This is a good question and it comes up a lot. But first, let's step back for a second.
The idea of debugging "line by line" is something comes from imperative programming languages. By "imperative" I mean that a program is simply a sequence of instructions to be carried out in the specified order.
When someone debugs Java or Python, this "line by line" approach makes sense because the statements are the fundamental way behavior is represented. This "line by line" approach could also be extended to modeling formalisms like block diagrams (e.g. Simulink) because, while graphical, they are also imperative (i.e. they constitute steps to be carried out in a specified order).
But Modelica is not an imperative language. There is no notion of steps, statements or instructions. Instead, we have omnipresent equations. So thinking linearly about debugging doesn't work in Modelica. It is true that you could think about debugging the C code generated from Modelica, but that is typically not very useful because it bears only a partial resemblance to the equations.
So how do you debug Modelica code? Well, debugging Modelica code is really debugging Modelica equations. Normally, Modelica models are composed of components. The equations that are generated when components are connected are automatically generated so lets stipulate that the Modelica compiler generates those correctly. So what's left is the equations in the component models.
The simplest way to approach this is to test each component individually (or at least in the smallest possible models). I often say that trying to debug Modelica components by throwing them all together in a big model is like listening to an orchestra and trying to figure out the one instrument that is out of tune. The fact that these equations in Modelica tend to form simultaneous systems of equations means that errors, when they occur, can propagate immediately to a number of variables.
So your best bet is to go through and create tests for each individual component and verify the behavior of the component. My experience is that when you do this, you can track down and eliminate bugs pretty easily.
Update: You shouldn't need to add outputs to other people's component models to debug them. An output can be created at any level, e.g.
model SystemModel
SomeoneElsesComponent a;
SomeOtherGuysComponent b;
end SystemModel;
model SystemModel_Debug
extends SystemModel;
output Real someNestedSignalFromA = a.someSubsystem.someSubcomponent.someSignal;
output Real someOtherNestedSignalFromB = b.anotherSubsystem.anotherSignal;
end SystemModel_Debug;
Of course, this becomes impractical if you have multiple instantiations of a signal component. In those cases, I admit that it is easier to modify the underlying model. But if they make their models replaceable
, you can use the same trick as above (extends their model, add a bunch of custom outputs and then redeclare
your model in place of the original).