# The DSblock model interface

Version 4.0a

**Incomplete Draft**

Martin Otter

Pieter Mosterman

January 12, 1998

History:

Nov. 19., 1996: | Initial version. | |

Nov. 27., 1996: | Mathematical description forms, example for hierarchical DSblock with separatly compiled components. | |

Jan. 12., 1998: | Re-designed and adapted to Modelica version 1.0. Implemented in C++ and tested with Dymola. |

Note: this document is best printed on a laser printer by using a font size of 10pt.

## 1. Introduction

The DSblock model interface definition is a neutral, low-level description for complex dynamic systems. It is developed since 1990 from Martin Otter and is used for the mathematical description of parameterized, event-driven, explizit ordinary differential equations or differential algebraic equations in form of input-output "blocks". Upto version 3.3, the DSblock definition consists of upto 11 Fortran77 subroutines with defined interfaces.

Below, a draft of DSblock version 4.0 is given, which is a major
redefinition. Most importantly, the underlying target language, i.e., Fortran,
is changed. The new target language is C++. Interfaces for Java and Fortran90
will be added in the future. The reason for this change is that Fortran77 is
too limited in scope and that C++ leads to a considerably **simplified**
interface, due to the better available datastructures.
Other changes include:

- The new DSblock definition is closely related to the
**Modelica**language. Especially, all attributes of a Modelica model can be stored and the DSblock datastructure is a direct map of the Modelica datastructures. Of course, it will still be possible and useful to generate DSblock code for other model description forms.

- DSblock models can be built up
**hierarchically**, i.e., subcomponents of a DSblock model may consist of other,**precompiled**DSblock models. This allows e.g., to generate a subcomponent from a Modelica model, compile it and use this precompiled DSblock as submodel in another Modelica model.

- DSblock models are no longer be limited to input/output blocks. Every
**non-causal**component, like a Resistor or a Capacitor, can be described.

- There are now two interfaces. One interface describes the model and
is e.g. used to connect a DSblock with other DSblocks to built up hierarchical
structures. Every such model contains a description of the
**model**which is close to the**Modelica**description.

The second interface is used for the**communication**with the**integrators**. Depending on the integrator, several interfaces are provided (presently for hybrid differential equations in space form and for hybrid differential algebraic equation systems).

The DSblock interface version 4.0 is realized in form of C++ classes.
The **interface** definition and the software is **free**, and
can be used without any restrictions. Below, pointers to the software
are given. In order to get a quick feeling how models are defined,
see the first two examples. The whole available software can also
be downloaded as zip-file dsblock.zip.

circuit.mo | Simple electrical circuit as a Modelica model. |

circuit.cpp | "circuit.mo" as a DSblock model. It is demonstrated how physical models can be built up hierarchically. |

hybrid.mo | Modelica model to demonstrate the hybrid language elements of Modelica. |

hybrid.cpp | "hybrid.mo" in form of a DSblock model. It is demonstrated
how hybrid proporties are described. |

dsmodel.h | Header-file containing classes to implement Modelica models in an easy way. |

dsblock.h | Header-file containing classes to interface a DSblock model to ODE and DAE integrators. |

dsblock.cpp | Source-file of all DSblock classes of "dsmodel.h" and "dsblock.h"".; |

In the following sections, examples for the new DSblock definition are given in C++. All models are first given as a Modelica model before the corresponding DSblock description is discussed. At the end, a more detailed overall description is given.

## 2. DSblock Interface to Modelica Models

Several utility classes are provided to build up a DSblock model which originates from a Modelica model. The classes are structured in such a way that a Modelica compiler can generate C++ DSblock code easily. At hand of three examples, the most important features are explained.

### 2.1 Simple DSblock: Van der Pol equation

In the most simpliest case, a DSblock is a "flat" respresentation of a corresponding Modelica model. E.g. the Van der Pol equation, a second order ODE, can be described by the following Modelica model:

modelVanDerPolparameterReal lambda=0.5; Real y;equationder(der(y)) + lambda*(1-y^2)*der(y) + y = 0end VanDerPol;

This model can be easily solved for its highest derivative. A corresponding C++ DSblock has the following structure:

#include"dsmodel.h"using namespacedsblock;classVanDerPol :publicModel {public: // Variables of model Real lambda; Real y, der_y, der_der_y; // Functions of DSblock VanDerPol(); // initialize DSblockvoidequation(DynamicSystem& sys); // sorted equations }; Model& dsblock::newModel() { // make model available Model *model =newVanDerPol;return*model; }

Class **VanDerPol** is a subclass of the predefined
class **Model** in namespace **dsblock**, in which the common
properties of Modelica model classes are defined. For every type
of Modelica class, a corresponding DSblock class is provided.
In particular, the following mappings are used:

Modelica class |
DSblock C++ class |

class |
class ModelicaClass {...} |

connector |
class Connector : public ModelicaClass {...} |

record |
class Record : public ModelicaClass {...} |

package |
class Package : public ModelicaClass {...} |

model |
class Model
: public ModelicaClass {...} |

block |
class Block
: public Model {...} |

function |
class Function : public Block {...} |

- | class Variable
: public ModelicaClass {...} |

Real |
class Real
: public Variable {...} |

Integer |
class Integer
: public Variable {...} |

Boolean |
class Boolean
: public Variable {...} |

- | class Crossing
: public ModelicaClass {...} |

The variables of a DSblock are declared in a similiar way as the corresponding Modelica model by statements:

Real lambda; Real y, der_y, der_der_y;

Furthermore the constructor of the class (here: ": VanDerPol()")
and the virtual function **equations** have to be provided.
The former function is used to initialize the DSblock and to provide
all the attributes of a variable. The latter function is used to
provided the sorted equations of the model. For the VanDerPol class
the constructor can be defined in the following way:

VanDerPol::VanDerPol() { // register all components insert(lambda ,"lambda"); insert(y ,"y"); insert(der_y ,"der_y"); insert(der_der_y,"der_der_y"); // define other component attributes name("VanDerPol"); lambda.parameter(0.5); der_y.der(y); der_der_y.der(der_y); };

Utility function **insert** is a member of class **ModelicaClass**
and is used to register all components together with the component
name as character string. When a model is hierarchically structured,
all components together form a **tree** and the insert function
is used to introduce new nodes in this tree.
All other classes have class-dependent member functions to define
**all** Modelica attributes. E.g. the attributes of a Real variable could
be set in the following way:

Real var; ... var.parameter(2.0).start(3.0).min(0.0).quantity("xx").unit("yy");

Additionally, proporties of variables can also be defined, especially

der_y.der(y);

defines that variable **der_y** is the derivative
of variable **y**. Finally, the sorted model equations
have to be provided in
function **equation** which is a member of class **Model**:

voidVanDerPol::equation(DynamicSystem& sys) { // Equations of Van-Der-Pol system der_der_y._ = -lambda._ * (1 - y._*y._) * der_y._ - y._; }

The actual value of a variable is stored in the public member variable
"_". This means e.g. that "y._" is the value of Modelica
variable **y**. All the other attributes of a Modelica variable
are stored in the private field and can be inquired via utility
functions (e.g., the full name of the variable).
An object of class **DynamicSystem** is provided in the interface
of member function **equation**.
This object contains utility functions needed by the model,
e.g., the actual time instant can be inquired or the task to be
carried out. This will be discussed in more detail below.

The equations have to be solved for the highest derivatives or for the residues of implicit algebraic equations containing these derivatives as unknowns, or a mixture of the two. In the latter two cases, only implicit solvers can be used, whereas for the form above explicit integration methods can be utilitzed as well. Rewritting the Van der Pol system into residue form results in:

VanDerPol::VanDerPol() { // register all components ... insert(resvdp,"resvdp"); // define other component attributes lambda.parameter(0.5); der_y.der(y); der_der_y.der(der_y); resvdp.residue(der_der_y); // residue used to compute der_der_y };voidVanDerPol::equation(DynamicSystem& sys) { // Equations of Van-Der-Pol system resvdp = -lambda._ * (1 - y._*y._) * der_y._ - y._ - der_der_y._; }

The only differences to the previous formulation is that an additional
Real variable **resvdp** is introduced with property = **residue**,
and that this residue is computed instead of the highest derivative.
The property of a residue variable contains a reference to another
variable. Informally this means, that a residue is primarily used to
compute the refered variable in the solver. To be more specific, this
information is used for the **ordering** of the **equations**
in the solver. In the solver, the unknown variables are ordered according
to the order in which the corresponding
constructors are called. Then, the equations are ordered in the same
way utilizing the variable refered to in the property attribute of the
residue. Of course, this is just the initial ordering of the systems of
equations; the solver may changed this ordering afterwards.

### 2.2 Hierarchical DSblock: A simple electrical circuit

In principal, every model could be built up with the described scheme. However, one of the disadvantages is that for a hierarchical Modelica model all the attribute definitions (e.g. the instance names) are repeated all the time. At hand of an example from Modelicas language description it is show, in which way hierarchical models can be build up without unnecessarily repeating information. The complete Modelica model is given in circuit.mo. The most important parts are:

modelCircuit "Simple circuit as demonstration example" Resistor R1 (R= 10); Resistor R2 (R=100); Capacitor C (C=0.01); Inductor L (L=0.1); VsourceAC AC; Ground G;equationconnect(AC.p, R1.p);connect(R1.n, C.p);connect(C.n, AC.n);connect(R1.p, R2.p);connect(R2.n, L.p);connect(L.n, C.n);connect(AC.n, G.p);endCircuit;modelResistor // component used in CircuitextendsTwoPin;parameterResistance R;equationv = R*p.i;endResistor;partial modelTwoPin // superclass of Resistor Pin p "Positive pin"; Pin n "Negative pin"; Voltage v "Voltage drop between the two pins";equationv = p.v - n.v;endTwoPin;connectorPin // connector used in TwoPin Voltage v "Potential at the pin";flowCurrent i "Current flowing into the pin";endPin; // Type definitionstypeVoltage = Real(quantity="Voltage", unit="V");typeCurrent = Real(quantity="Current", unit="A");

In the corresponding DSblock, the same hierarchy as in the Modelica
model is used for the **datastructures**. To enhance efficiency, this
is usually not done for the model equations. By **symbolic processing**
of the models all the equations are "flattened" and sorted
together, i.e., the hierarchy of the original model is lost.
The complete C++ DSblock model is given in
circuit.cpp.
The most important parts are:

classCircuit :publicModel {public: Resistor R1; Resistor R2; Capacitor C; Inductor L; VsourceAC AC; Ground G; Circuit(); void equation(DynamicSystem& sys); }; Circuit::Circuit() { // register all components insert(R1,"R1"); insert(R2,"R2"); insert(C ,"C" ); insert(L ,"L" ); insert(AC,"AC"); insert(G ,"G" ); // define other component attributes R1.R.parameter(10.0); R2.R.parameter(100.0); C.C.parameter (0.01); L.L.parameter (0.1); name("Circuit"); description("Simple circuit as demonstration example"); // define alias and constant variables G.p.v.constant(0.0); R1.p.v.alias(AC.v); // R1.p.v = AC.v R2.p.v.alias(AC.v); };classResistor :publicTwoPin {public: Resistance R; Resistor() { insert(R,"R"); R.parameter(); } };classTwoPin :publicModel {public: Pin p; Pin n; Voltage v; TwoPin() { // register all components insert(p,"p"); insert(n,"n"); insert(v,"v"); // define other component attributes p.description("Positive pin"); n.description("Negative pin"); v.description("Voltage drop between the two pins"); } };classPin :publicConnector {public: Voltage v; Current i; Pin() { // register all components insert(v,"v"); insert(i,"i"); // define other component attributes v.description("Potential at the pin"); i.description("Current flowing into the pin").flow(); } };classVoltage :publicReal {public: Voltage() { quantity("Voltage"); unit("V"); }};classCurrent :publicReal {public: Current() { quantity("Current"); unit("A"); }};

The hierarchical ordering of the C++ classes is done exactly as for the Modelica model. When connecting components together, a lot of equations of the form "a = b" are generated, because connector variables in different components are identical. It would be a vaste of space if the time series of the result is stored for both variables. Therefore, in the initialization part of the model it is e.g. defined:

R1.p.v.alias(AC.v); // R1.p.v = AC.v

which means that only the results for **AV.v** are stored and
the information that **R1.p.v** is identical to **AV.v**.
Additional the utility member function **v2.negAlias(v1)** is provided
to state that **v2 = -v1**.

As already noted, only on the highest level the flattened model
equations are provided:

voidCircuit::equation(DynamicSystem& sys) { // Equations of simple circuitint equationStructure[5] = {0, // ComputeCrossings 0, // ComputeOutputs 1, // ComputeDerivatives 2, // ComputeAll 0}; // ComputeJacobianintstopLabel = equationStructure[sys.demand()];doubleQw101;doubletime = sys.time(); // Compute only the minimum needed part of the equationsif( computeLabel >= stopLabel )return;switch( ++computeLabel ) {case1: Qw101 = sin(2.0*AC.PI._*AC.f._*time); AC.p.v._ = AC.VA._*Qw101; R1.p.i._ = (AC.p.v._ - C.v._)/R1.R._; AC.p.i._ = - (R1.p.i._ + L.p.i._); AC.v._ = AC.p.v._; R1.v._ = AC.p.v._ - C.v._; R2.n.v._ = AC.p.v._ - R2.R._*L.p.i._; R2.v._ = AC.p.v._ - R2.n.v._; C.der_v._ = R1.p.i._ / C.C._; L.der_i._ = R2.n.v._ / L.L._; if ( stopLabel <= 1 ) break;case2: G.p.i._ = R1.p.i._ + L.p.i._ + AC.p.i._; if ( stopLabel <= 2 ) break; } computeLabel = stopLabel; }

Via member function **demand()** the variables to be computed can
be inquired in order that only the minimum amount of equations are
evaluated during simulation. In this case this saves not much.
But for more realistic models, this enhances efficiency considerably.
The public variable **computeLabel** is set to zero from the calling
environment, whenever one of the input variables has been changed.
Together with the scheme above this allows the desired computation
of the minimum amount of evaluation at the current time instant.

### 2.3 Hybrid DSblock

Modelica has several powerful features for hybrid systems. Most of the hybrid language elements are mapped quite directly on the corresponding C++ DSblock. This is demonstrated at hand of a Modelica model containing most of the hybrid features:

modelhybrid "Test hybrid features of Modelica and DSblock" // DeclarationsparameterReal g=9.81;parameterReal hStart = 1; Real h, v, a; Real u;outputReal y1;outputReal y2; Boolean yL(start=false); Boolean trigger;equation// Test event operator and crossing functions u = time - 2; y1 =if event(u > 1 )then1elseif event(u < -1 )then-1elseu; // Test when operator and crossing functionswheny1 > 0.5doyL :=true;end when; // Test when, initial and new operator on Real (jumping ball)der(h) = v;der(v) = a; a = -g;when Initial(time)donew(h) := hStart;end when;whenh < 0donew(v) := -0.9*v;end when; // Test when, sample and new (generate triangle signal) der(y2) = 1.0;when Sample(0.0, 0.5)donewy2) := 0.0;end when; // Test new operator on Booleanwhen Sample(0.0, 0.5)donew(trigger) :=nottrigger;end when;endhybrid;

The **event** operator signals a state event. A **when** clause
is only evaluated when the corresponding expression **becomes**
true. The **new** operator is used to characterize a new value of
the variable, after the corresponding event is processed.
The mapping of these language elements into C++ DSblock code
is summarized in the following table under the assumption that
**sys** is the instance of class **DynamicSystem**
provided as single argument to function **equations**:

Modelica |
DSblock C++ code |

time |
sys.time() |

initial |
sys.initial() |

terminal |
sys.terminal() |

sample(v1,v2) |
sys.sample(v1,v2) |

if event (u > 1) then
... |
Crossing z;... z = u - 1; if ( sys.sign(z) > 0 ) {
... |

when bvar do ... end when; |
Boolean bvar;... if ( sys.edge(bvar) ) { ... } |

Control c (enable=bvar); |
Control c; ... sys.enable(c, bvar); |

The operators **time, initial, terminal, sample** are directly
mapped into appropriate C++ operators. An expression, such as
"u > 1", has to be first transformed into a zero
crossing function **z** which has to be declared as an instance
of the predefined class **Crossing**. Afterwards, the sign
of the crossing function can be inquired and used whenever
the Modelica **event** operator signals a state event.
The **Crossing** class is realized with an overloaded
"=" operator:

voidoperator= (doublev) {if(sys->Event) sys->zSignUpdate(*this, v); zPos = v + Eps; zNeg = v - Eps;}

which computes the correct sign of the crossing function at event
instants, stores this sign in the crossing function datastructure and
keeps it constant during continuous integration.

The expression of a **when** clause has to be assigned to a Boolean
variable. Afterwards, with operator **edge** it can be tested
when this Boolean **becomes** true, i.e., the when semantic
applies.

Finally, a block component can be enabled or disabled by just calling
function **enable** on the desired component. This function
enables or disables automatically all sub-components and variables
which are contained in the block, even if the block has a deep hierarchy
of components.

Using the mentioned hybrid language construct, the previous Modelica model can be transformed into C++ DSblock code in the following way:

classHybrid :publicModel {public: // variables of model Real g; Real hStart; Real h, v, a, der_h, der_v, new_h, new_v; Real u; Real y1; Real y2, der_y2, new_y2; Boolean yL; Boolean trigger, new_trigger; // auxiliary variables for crossing functions and when clauses Crossing z1, z2, z3, z4; Boolean b1, b2, b3, b4, b5; Hybrid();voidequation(DynamicSystem& sys); }; Hybrid::Hybrid() { // register all components insert(g ,"g"); insert(hStart ,"hStart"); insert(h ,"h"); insert(v ,"v"); insert(a ,"a"); insert(der_h ,"der_h"); insert(der_v ,"der_v"); insert(new_h ,"new_h"); insert(new_v ,"new_v"); insert(u ,"u"); insert(y1 ,"y1"); insert(y2 ,"y2"); insert(der_y2 ,"der_y2"); insert(new_y2 ,"new_y2"); insert(yL ,"yL"); insert(trigger ,"trigger"); insert(new_trigger,"new_trigger"); insert(z1,"z1"); insert(z2,"z2"); insert(z3,"z3"); insert(z4,"z4"); insert(b1,"b1"); insert(b2,"b2"); insert(b3,"b3"); insert(b4,"b4"); insert(b5,"b5"); // define other component attributes g.parameter(9.81); hStart.parameter(1.0); der_h.der(h); der_v.der(v); new_h.newv(h); new_v.newv(v); u.output(); y1.output(); y2.output(); der_y2.der(y2); new_y2.newv(y2); yL.start(False); new_trigger.newv(trigger); z1.description("u - 1"); z2.description("u + 1"); z3.description("y1 - 0.5"); z4.description("h"); b1.description("y - 0.5"); b2.description("initial()"); b3.description("h"); b4.description("sample(0.0, 0.5)"); b5.description("sample(0.0, 0.5)"); name("Hybrid"); description("Test hybrid features of Modelica and DSblock"); };voidHybrid::equation(DynamicSystem& sys) { // Equations of simple circuitdoubletime = sys.time(); // Compute only the minimum needed part of the equationsif( computeLabel > 0 )return; // Test event operator and crossing functions u = time - 2.0; z1 = u._ - 1.0; z2 = u._ + 1.0;if( sys.sign(z1) > 0 ) { y1 = 1.0; } else if ( sys.sign(z2) < 0 ) { y1 = -1.0; } else { y1 = u._; } // Test when operator and crossing functions z3 = y1._ - 0.5; b1 = sys.sign(z3) > 0.0;if( sys.edge(b1) ) { yL = True; } // Test when, initial and new operator on Real (jumping ball) a = -g._; der_h = v._; der_v = a._; b2 = sys.initial();if( sys.edge(b2) ) { new_h = hStart._; } z4 = h._; b3 = sys.sign(z4) < 0;if( sys.edge(b3) ) { new_v = -0.9*v._; } // Test when, sample and new (generate triangle signal) der_y2 = 1.0; b4 = sys.sample(0.0, 0.5);if( sys.edge(b4) ) { new_y2 = 0.0; } // Test new operator on Boolean b5 = sys.sample(0.0, 0.5);if( sys.edge(b5) ) { new_trigger = !trigger._; } computeLabel = 1; }

## 3. DSblock Interface to Integrator

The DSblock provides a layer between a representation of the model
close to the Modelica model and between a representation which is
close to the requirements of a numerical integrator.
For the latter case, several C++ classes are provided, depending on the
underlying mathematical description form of the integrator.
Presently, two description forms - hybrid ODEs and hybrid DAEs -
are supported. These classes are subclasses of class
**FullDynamicSystem** which in turn is a subclass of class
**DynamicSystem** which is used for the input argument of the
**equation** function.

### 3.1 Hybrid ODEs (class HybridODE)

A hybrid ODE (Ordinary Differential Equation in state space form) is described by the following equations:

(1a) Derivative Equations : dx/dt :=f(x, u, p,t,m) (1b) Output Equations :y:=f(x, u, p,t,m) (1c) Crossing Functions :z:=g(x, u, p, t,m) (1d) Update Functions : [m,x] :=h(x, u, p, t,m,x^{post})

where the variables have the following meaning:

t | time, the independent (real) variable. |

x(t) |
(real) state variables. |

u(t) |
known (real) functions of time. |

p |
known (constant) parameters of type Real, Integer, Boolean. |

m |
discrete variables of any type (real, integer, string, ...) defining
the current mode. |

y(t) |
(real) output variables. |

z(t) |
(real) crossing variables where the zero crossings trigger state events. |

The *derivative equations* (1a) and the *output equations*
(1b) are used for continuous integration.
During integration, the discrete variables **m** are not changed. The
*crossing functions* (1c) are also evaluated during continuous integration.
If one of the signals **z** crosses zero, the integration is halted
and an event occurs. The special case of a time event, "z = t - te",
is also included. For efficiency reasons, time events are usually treated
in a special way, since the time instant of such an event is known in advance.
At every event instant, the *update functions* (1e) are used to determine
new values of the discrete variables and of new initial values for the
states **x**. The change of discrete variables may characterize a new
structure of a DAE where elements of the state vector **x** are *disabled*.
In other words, the number of state variables may change at event instants
by disabling the appropriate part of the equations.
For clarity of the equations, this is not
explicitly shown by an additional index in (1).

In (Mosterman and Biswas 1996) it is shown that for the update functions
**h** it is necessary to distinguish the usage of **x** in equations
and assignment statements from the usage in Boolean expressions, such as
"**if** x > 0 **then** ...". Changes of discrete variables
may cause jumps in state variables, and Boolean expressions may have to
utilize the values immediately after the jump occurred. In (1) these state
variables are supplied as additional function argument **x**^{post},
where the index "post" stands for "posterior" value.

The update functions are used in the following iteration procedure to determine
new *consistent *initial conditions:

x^{new}:=xloop[m^{new},x^{new}]:=h(x, u, p, t,m,x^{new})ifm^{new}==mthen breakrepeatm:=m^{new }[m^{new},x^{new}]:=h(x, u, p, t,m,x^{new})untilm^{new}==mx:=x^{new}end loop

If, for example, several ideal Coulomb friction elements are used in
a model, it is not possible to decide in advance the mode of each friction
element (whether it is stuck or it slides) when the relative velocity is
zero. An iteration is needed to determine the modes which are compatible
with the forces and torques acting on the mechanical device. According
to (Mosterman and Biswas 1996) an inner loop is needed in order not to
converge to a physically wrong solution. The equations of the inner loop
are always evaluated with the state vector **x** of the last consistent
mode **m**. The inner loop is iterated until the next consistent mode
**m** is found. The start of an integration is treated as an event instant,
i.e., an iteration also takes place at the initial time.
Note, that the feature with the posterior values is not yet implemented
in the DSblock C++ classes described below.

The DSblock C++ interface for the integrators is a straightforward
map of the discussed functions. In particular, the following member
functions are provided in class **HybridODE** (all the details
can be found in the header file dsblock.h
and its implementation dsblock.cpp):

classHybridODE :publicFullDynamicSystem {public: // Evaluation functionsvoidsetArg (doublex [],doubleu[],doubletime);voidgetArg (doublex []); // get arguments after eventvoidderivatives (doublexDot[]); // compute derivatives (1a)voidoutputs (doubley[]); // compute output variables (1b)voidcrossings (doublez[]); // compute crossing variables (1c)voidperformInitial (); // perform initial event (1d)voidperformEvent (); // perform event (1d)voidperformTerminal(); // perform terminal event (1d) // Inquiry functionsdoublenextTimeEvent(); // return next time event Bool dimChanged(); // true, if number of dimensions changedintnxMax(); // maximum number of statesintnx (); // actual number of stateintnu (); // number of Real input variablesintny (); // number of Real Output variablesintnzMax(); // maximum number of crossing variablesintnz (); // actual number of crossing variables ... };

The **setArg** function is used to copy the input arguments
from the vectors provided by the integrator into the model
datastructure discussed in the previous chapter. This function has to
be called, before a calculation is performed. Afterwards, different
computations can be done, according to the situation at hand, e.g.,
computation of derivatives or of crossing functions (this is often
done at different time instants). Depending on the implementation
of the model, the complete model is evaluated once and the evaluation
calls such as **outputs** copy the result back without newly
evaluating the model equations or alternativly, only the minimum needed
part of the model is computed, depending on the required action.

The update functions (1d) are split into three functions, since at the
initial and terminal time of the integration some different actions
have to be performed. After an event is processed, modified state
variables can be inquired via the standard computational procedures
(such as **derivatives**).

Furthermore, a lot of inquiry functions are provided, especially to inquire the number of dimensions. For present Modelica models it is possible to determine the maximum dimensions of all vectors even for variable structure models, because all components have to be provided and during simulation sub-components can be disabled but no new sub-components can be added dynamically. Both the maximum dimensions, as well as the dimensions of the actual configuration can be inquired at event instants.

### 3.2 Hybrid DAEs (class HybridDAE)

...

## 4. Discussion

...

**Acknowledgement:**

This work was supported in part by
SiE (Simulation in Europe),
the European COSY program
and the "Schwerpunktprogramm KONDISK der Deutschen Forschungsgemeinschaft".