institutionen för datavetenskap - diva...
TRANSCRIPT
Institutionen för datavetenskap
Department of Computer and Information Science
Master Thesis
A Template-Based Java Code Generator
for OpenModelica and MetaModelica
By
Manokar Munisamy
LIU-IDA/LITH-EX-A--14/022—SE
2014-09-01
Linköping University Department of Computer and Information Science
Master Thesis
A Template-Based Java Code Generator for
OpenModelica and MetaModelica
By
Manokar Munisamy
LIU-IDA/LITH-EX-A--14/022—SE
2014-09-01
Supervisor: Lena Buffoni (fd Olena Rogovchenko) Department of Computer and Information Science
Examiner: Peter Fritzson Department of Computer and Information Science
Abstract The current OpenModelica Complier (OMC) translates Modelica models into executable C-
code through several stages. The Code Generator is the final stage of the compiler which
generates target C-code from the optimized sorted equations. Recently, the Code Generator in
OMC has been rewritten using the OpenModelica text template language. This gives a more
concise and easier to understand code generator. Modeling and simulation is becoming
increasingly used in several application areas. There is demand for the OpenModelica
Complier (OMC) to generate code in languages like C#, CSharp, XML, JAVA and so on. In
this thesis work, we implement a Java code generator to translate the internal equation-based
models in OpenModelica and its extension MetaModelica into a Java code representation. To
create the Java code generator we used the OpenModelica text template language, also called
Susan. This work is an important step on the way to finalize a full version of a Java Code
Generator for the OpenModelica Complier (OMC).
4
Acknowledgments I take this opportunity to thank my examiner Prof. Peter Fritzson and my supervisor Dr. Olena
Rogovchenko for this thesis opportunity, and for guidance. I also thank my technical
supervisor Martin Sjölund and give special thanks to Prof. Hans Georg Schaathun from
høgskolen i Ålesund (Aalesund University College) for his continuous support through skype
meetings. Finally I thank my friends and family for their support.
5
Contents Contents ................................................................................................................................................... 5
Chapter 1 .................................................................................................................................................. 7
Introduction .............................................................................................................................................. 7
1.1 Motivation ...................................................................................................................................... 7
1.2 Problem Statement ........................................................................................................................ 7
1.3 Goals ............................................................................................................................................... 8
1.4 Methodology .................................................................................................................................. 8
1.5 Intended Readers ........................................................................................................................... 8
1.6 Thesis Outline ................................................................................................................................. 9
Chapter 2 ................................................................................................................................................ 11
Background ............................................................................................................................................. 11
2.1 Modelica and OpenModelica ....................................................................................................... 11
2.2 OpenModelica Compiler Phases and Modules ............................................................................ 12
2.2.1. The OpenModelica Compiler Phases ................................................................................... 12
2.1.2 The OpenModelica Compiler Modules ................................................................................. 14
2.3 MetaModelica .............................................................................................................................. 15
2.4 Numerical Integration .................................................................................................................. 16
2.4.1 Introduction to Numerical Integration .................................................................................. 16
2.4.2 Euler Integration .................................................................................................................... 17
2.5 Event Handling ............................................................................................................................. 18
2.5.1 Events .................................................................................................................................... 18
2.5.2 Run-time Algorithm ............................................................................................................... 19
2.6 The Susan Template Language ..................................................................................................... 21
Chapter 3 ................................................................................................................................................ 23
Design and Implementation ................................................................................................................... 23
3.1 Java Code Generation ................................................................................................................... 23
3.1.1 Root Template ....................................................................................................................... 24
3.1.2 Java Specific File Template .................................................................................................... 24
3.1.3 simulationFileHeader Template ............................................................................................ 25
3.1.4 modelClassName Template ................................................................................................... 25
3.1.5 addGlobalInitialization Template .......................................................................................... 26
6
3.1.6 modelClassConstructorTemplate ........................................................................................ 26
3.1.7 functionBoundParameters Template .................................................................................... 27
3.1.8 functionODE Template .......................................................................................................... 28
3.1.9 functionDAE Template .......................................................................................................... 29
3.1.10 functions Template ............................................................................................................. 30
3.1.11 mainFunction Template ...................................................................................................... 31
3.1.12 daeExp Template ................................................................................................................. 32
3.2 Java runtime system ..................................................................................................................... 33
3.2.1 SimModel .............................................................................................................................. 34
3.2.2 SimData ................................................................................................................................. 34
3.2.3 EulerSolver ............................................................................................................................ 35
Chapter 4 ................................................................................................................................................ 37
Testing .................................................................................................................................................... 37
4.1 Modelica Test Models .................................................................................................................. 37
4.1.1 Verification Test .................................................................................................................... 38
4.1.2 Performance Test .................................................................................................................. 38
4.2 Improvements from previous version .......................................................................................... 42
Chapter 5 ................................................................................................................................................ 45
Conclusion and Future Work .................................................................................................................. 45
5.1 Conclusion .................................................................................................................................... 45
5.2 Future Work ................................................................................................................................. 45
User Guide .......................................................................................................................................... 47
References .............................................................................................................................................. 49
Appendix ................................................................................................................................................ 51
A Sample Results ................................................................................................................................ 51
B Simulation Time ............................................................................................................................... 55
C Implementation code ...................................................................................................................... 59
7
Chapter 1
Introduction
In this chapter, we provide an overview and motivation for this thesis work. We also explain
the methodology which we use to achieve our goals. In the next section, we have stated the
goals and problem statement in this chapter. Finally, we present the outline of this thesis
work.
1.1 Motivation In modern technology, modeling and simulation plays a vital role in many industries.
Industries need a multi domain modeling and simulation language and tool for their
application development such as: mechanical, robotics, automotive, aerospace, electrical,
hydraulic, control subsystems, process oriented applications and many more. Modelica is a
non-proprietary, object oriented, mathematical and equation based language. The Modelica
language is used for modeling and simulating the above mentioned applications/models.
OpenModelica is an open-source Modelica-based modeling and simulation environment
intended for industrial and academic usage. OpenModelica is growing fast and contains
different subsystems such as OMC, OMShell, OMNotebook, OMEdit, OMWeb, OMOptim,
MDT, ModelicaML, and OMPython.
The idea of creating this thesis work came from some users of OpenModelica, including
University of Ålesund, who are using the Java platform for software development and
simulation. They have a need for a simulator which is running as a Java application. Therefore
there is a need for OpenModelica to be able to generate Java code as an alternative to C code.
1.2 Problem Statement The OpenModelica Compiler, code generator has recently (two years ago) been rewritten
using the OpenModelica text template based language, Susan [2.6]. A previous master thesis
project developed a subset text template based code generator. This work extends that to cover
a larger part of the language, to create a Java Run-time that supports event handling, and to
also support code generation for MetaModelica to Java. Thus the first problem is that,
8
Problem 1: How to implement a template based Java code generator for
OpenModelica and MetaModelica? After Java code is generated, we need a runtime system to simulate the model. Currently there
exists a C runtime system but now we also need a Java runtime system to simulate. Thus the
second problem is that,
Problem 2: How to implement a Java runtime system to simulate Java coded
models?
1.3 Goals The main goals of this thesis work are the following: To further develop a template based Java code generator for OpenModelica Complier
OMC.
o further develop a Java Runtime System to simulate the models.
To perform the example test cases that demonstrate the possibility of OMC to generate
Java code for Modelica models, and track the performance with other the
programming language.
1.4 Methodology The methodology used for the development of theTemplate Based Java code generator and
Java runtime system for OpenModelica is based upon:
Literature Study – A literature study is the basic for the initiation of this thesis work. The
OpenModelica project was studied as along with already existing code generation thesis
works made for different languages such as C, C++, C# and XML code generation, as well as
previous master thesis with limited code generation from Modelica to Java in OpenModelica.
Also, some publications and documentations on OpenModelica were studied which are
related to this thesis work. Taking part in Intense Modelica Course and OpenModelica
workshop helped to a large extent to learn more about the Modelica language.
Implementation – The implementation leads to obtain a deeper understanding about the
problems and its proposed solutions. The Java code generator and Java runtime system were
developed using Susan template language and Java respectively.
1.5 Intended Readers The intended readers of this thesis work are people with general idea in Modelica language,
Susan template language, OpenModelica modeling and simulation environment. However,
interested readers with basic knowledge of compiler construction and programming can
understand as well.
9
1.6 Thesis Outline The rest of this thesis is organized as follows. Chapter 2: Background studies on the Modelica, OpenModelica, MetaModelica, complier
phases and modules, numerical integration for solver and Susan template
language. Chapter 3: Explains the design and implementation of Template Based Java Code
Generator and Java Runtime System for OpenModelica/MetaModelica. Chapter 4: Demonstrates the different test case and simulation to show the performance of
the implementation. Chapter 5: Concludes the thesis work and discussion of possible future work.
10
11
Chapter 2
Background
In this chapter, some theoretical background and technology needed for the implementation is
described. Initially, an overview of Modelica and OpenModelica for modeling and simulation
environment is given. In the section 2.2, an introduction to compiler construction and its
phases is described along with the modules of OMC. In the next section, the Run-time
algorithms for numerical integration and event handling are discussed. Finally, the Susan
template language is described which is used for the implementation of this thesis work.
2.1 Modelica and OpenModelica Modeling and simulation plays a vital role in many industries, because modeling and
simulation gives an overview of the actual system before it is implemented in the real world.
There are many modeling and simulation tools are available. In this thesis work, we focus in
OpenModelica and its extension MetaModelica.
Modelica is an object oriented and equation based language for modeling and simulation of
multi domain such as mechanical, electrical, hydraulic, control subsystems etc. The Modelica
Association is a non-profit organization which supports the development of the open standard
Modelica and the open source Modelica Standard Library.
The OpenModelica is an open source project for Modelica based modeling, compilation and
simulation environment. The major development of OpenModelica is done in Linköping
University, PELAB. OpenModelica is supported by non-profit organization, Open Source
Modelica Consortium (OSMC). There are many development is in under construction,
recently new version of OpenModelica1.9.0 beta 4 has been released including the different
tools as shown below in the figure 2.1.
12
Figure 2.1: The overall architecture of the OpenModelica environment
An OpenModelica Compiler (OMC) –The OMC translates Modelica source code to an
executable C code for simulation. An interactive session handler (OMShell) – An OMShell provides a command
interface to OMC. The OpenModelica Notebook (OMNotebook) – OMNotebook gives a tutorial for
Modelica. In addition, Modelica models can be written and simulated on it. The OpenModelica Development Environment (OMDev) – The OMDev is a tool for
building OMC. A Modelica eclipse plugin (MDT-Modelica Development Tooling) – MDT is used for
Modelica development, code browsing, and simulation. Modelica Debugger – The Modelica debugger used for debugging an extended
algorithm subset of Modelica by using eclipse for displaying and positioning. Graphical model editor – The OpenModelica Connection Editor (OMEdit) is used for
graphical model editing, plotting and browsing of the Modelica standard library.
2.2 OpenModelica Compiler Phases and Modules
2.2.1. The OpenModelica Compiler Phases A Modelica Compiler - The OMC translates Modelica source code to executable C code for
simulation by several phases. In this section, we give a short description for every phase with
the help of OpenModelica compiler phases shown in figure 2.2.1 below.
13
Figure 2.2.1: The OpenModelica compiler translation phases
Phases of compiler are as follows:
1. The first phase of the compiler is Scanner (input: symbols, output: tokens), which
produce tokens from the Modelica model symbols.
2. The second phase of the compiler is Parser (input: tokens, output: abstract syntax tree),
which translates the tokens to flattened model with list of variables, equation, function.
3. The Analyzer (input: abstract syntax tree, output: error messages, abstract syntax tree),
which is used for type checking, import statements, handling of inheritance,
modifications and all other object oriented operations are also performed in this
phase.
4. Optimization (input: abstract syntax tree, output: (optimized) abstract syntax tree),
which gives the Optimized sorted equation.
5. Code Generator is an important phase of the compiler (input: abstract syntax tree,
output: executable code). Code generation generates the final code (this is typically
architecture specific, one has to consider memory issues, etc.)
6. In the last phase of OMC, the code generator generates C code which is then pass to a
C compiler to produce executable code for simulation.
14
Interested readers to know the detailed compiler phases are encouraged to go through the
“Compliers Principles, Techniques, & Tools” book[3].
2.1.2 The OpenModelica Compiler Modules The OMC has around 40 modules. The brief descriptions of each module can be found in the
OpenModelica system documentation and figure2.2.2a shown below for a quick reference.
Figure 2.2.2a: Module connections and data flows in the OMC
In this section, we will describe only the most important modules of OMC and its short
description, see also figure 2.2.2b below.
1. The parser generates Abstract Syntax (Absyn) which is then converted into a
simplified intermediate form (SCode).
2. The code instantiation module (Inst) calls Lookup to find a name in an environment. It
also generates the Differential Algebraic Equation (DAE) representation which is
simplified by DAELow.
3. The Ceval module performs compile time or interactive expression evaluation and
returns values.
4. The static module performs static semantic and type checking.
5. SimCode is the data structure for representing solved equation code which then can be
used to generate different target code in code generation phase.
15
Figure 2.2.2b: The OpenModelica compiler most important modules
2.3 MetaModelica MetaModelica is a unified equation-based modeling language specifically designed for OMC
development. MetaModelica is an extended subset of Modelica used for the development of
OMC. There are some extended features such as local equations, pattern equations, match
expressions and high level data structures are matchcontinue, uniontype, list and the option
type.
The MetaModelica uniontype construct used to specify the type of each node in the AST. It
declares one or more record members. The structure of uniontype may be recursive (i.e., the
records are allowed to contain uniontype members). See the listing 2.3 for an example on how
to declare an expression uniontype of six record types.
uniontype Exp
record INT Integer value; end INT;
record ADD Exp lhs; Exp rhs; end ADD;
record SUB Exp lhs; Exp rhs; end SUB;
record MUL Exp lhs; Exp rhs; end MUL;
record DIV Exp lhs; Exp rhs; end DIV;
record NEG Exp exp1; end NEG;
end Exp;
Listing 2.3: Exp Abstract syntax definition using MetaModelica Uniontype constructs The AST representation of the expression 10+3*8 by using the Exp abstract syntax definition
is shown below in the Figure 2.3.
16
ADD
INT MUL
10
INT INT
3 8
Figure 2.3: AST of 10+8*3 in the language Exp
See the listing 2.3.b for an example on how to declare a match constructs in MetaModelica.
function eval
input Exp in_exp;
output Real out_real;
algorithm
out_real := match in_exp
local Real v1,v2,v3; Exp e1,e2;
case RCONST(v1) then v1;
case ADD(e1,e2) equation
v1 = eval(e1); v2 = eval(e2); v3 = v1 + v2; then v3;
case SUB(e1,e2) equation
v1 = eval(e1); v2 = eval(e2); v3 = v1 - v2; then v3;
case MUL(e1,e2) equation
v1 = eval(e1); v2 = eval(e2); v3 = v1 * v2;then v3;
case DIV(e1,e2) equation
v1 = eval(e1); v2 = eval(e2); v3 = v1 / v2; then v3;
case NEG(e1) equation
v1 = eval(e1); v2 = -v1; then v2;
end match;
end eval;
Listing 2.3.b: MetaModelica match constructs
2.4 Numerical Integration
In this section, we explain the numerical integration procedure and methods used in this thesis
work to solve the ODE equations in solver.
2.4.1 Introduction to Numerical Integration
One of the inputs to the final code generation step, with the limited set of models used in this
thesis, is a set of explicit ODEs on the form:
x ' ( t )= f ( x( t ) , u( t ) ,t ) …. (2.1)
with initial conditions:
x ( t= t0)= x0 ….. (2.2)
17
In equation (2.1) x is the state vector, u is the input vector, and t represents time. We are not
considering any input to our Modelica model while simulation so we may skip the u(t) part
from equation (2.2) and thus form a new equation (2.3). The new equation can be written as:
x ' ( t )= f ( x( t ) , t ) ….. (2.3)
Our task is to calculate the state vector x and derivative x' of these states of the specified time
t. We can get the value of state vector x by analytically calculating them one by one but is not
possible in all cases specially if there are many time stamps and multiple state variables. The
alternative is to use the numerical integration methods. By using the numerical integration
methods, we can get the approximated values. Although it is not always possible to get the
accurate results but approximated values very close to the accurate ones. The approximated
values can be calculated at any given point using Taylor-Series expansion for every element
of xi:
xi( t∗ +h )= x
i( t∗ )+
dxi ( t∗ )
dt.h+
d2xi( t∗ )
dt2
.h2
2 !+. .. …. (2.4)
By plugging in equation (2.3) we get:
xi( t∗ +h )= x
i( t∗ )+ f
i( t∗ ) .h+
df i( t∗ )
dt.h2
2 !+.. . …. (2.5)
2.4.2 Euler Integration
Euler integration is the first-order numerical procedure for solving ODEs. The Euler
integration algorithm is formed by taking only the linear part from the Taylor Series equation
(2.5), such as:
xi(t*+ h) ¿ xi(t*) + x'i(t*) . h ….(2.6)
We use the approximation sign here instead of the equal sign, this is because we are just
taking the linear part and ignoring the rest of the Taylor equation of (2.5). Now the above
equation (2.6) scheme is very simple comparatively to Taylor series equation (2.5) because it
doesn't hold any higher-order derivatives. We call this integration scheme Forward Euler
algorithm since this numerical integration algorithm depends only on the past values of states
and state derivatives unlike Backward Euler 3 [3].
Recall equation (2.2), with initial conditions, x(t = t0) = x0, we can write the rest of steps as
follows:
step 1a: x'(t0) = f(x(t0); t0)
step 1b: x(t0 + h) = x(t0) + h . x'(t0)
step 2a: x' (t0 + h) = f(x(t0 + h); t0 + h)
step 2b: x(t0 + 2h) = x(t0 + h) + h . x'(t0 + h)
18
step 3a: x' (t0+ 2h) = f(x(t0 + 2h); t0 + 2h)
step 3b: x(t0 + 3h) = x(t0 + 2h) + h . x'(t0 + 2h)
x(t)
x'
time
t t+h
Figure 2.4: Numerical integration using the Forward Euler method.
Backward Euler integration scheme depends on past as well as current values of variables.
*Note this integration is not discussed in this thesis.
2.5 Event Handling In this section, we address about events and how we handle events in run-time system.
2.5.1 Events
An event (or discrete changes) is simply something that happens. Events are associated with a
point in time, state and conditional equation. The An Event in Modelica is something that
happens and has the following four properties: taken from [2 ]
A point in time that is instantaneous, i.e., has zero duration.
An event condition that switches from false to true for the event to happen.
A set of variables that are associated with the event, i.e., are referenced or explicitly
changed by equations associated with the event.
Some behavior associated with the event, expressed as conditional equations that
become active or are deactivated at the event. Instantaneous equations are special case
of conditional equations that are active only at events.
The short definitions of different events are given below:
Timed event: An event is triggered by time and the corresponding event-action takes place.
An example is shown below, when time >=10.0 then
event-action1;
end when;
State event: An event takes place in a particular state that triggers an action.
Conditional Event: An event takes place after satisfying a condition which triggers an action.
An example is shown below, when event-conditions then
Actual Value
Approximated Value
19
event-action1;
event-action2;
…
end when;
2.5.2 Run-time Algorithm
The following flowchart is shown in the figure 2.5 gives an overview of how an event is
handled in the run time system. The each and every step of the flowchart is described below.
First of all the simulation must be initialized consistently. By use of the initial conditions the
initial values for the entire system can be determined. This will also execute all initial events
at time .
After the initialization the main simulation loop starts with the continuous integration step that
calculates the states and state derivatives with its size value. With the new values of states and
state derivatives, the functions “Solver and CSVBuilder” can be evaluated. Thus, the entire
continuous system is determined.
The continuous integration step is accepted if no event has occurred then the values can be
saved and the next step can be performed. If an event has occurred then the value of condition
changes, an event occurred within the interval and . Then the exact time has to be
detected.
The continuous part is evaluated at the time just before the event and all values are saved to
provide them to the pre() operator. Then the entire system is evaluated by the functions again.
At this point the event is handled and the further events are handling by loop.
The main simulation loop will repeat until it reaches the end time. This helps us to get the
simulation time for Run-time system.
20
Figure 2.5: Schematic Flowchart for Run-time System.
21
2.6 The Susan Template Language In this section, we explain the Susan template language which is used in implementation of
Java code generator. Susan is a functional, strongly typed, expression oriented template
language which is specifically designed for OMC with the following main advantages are: Increases readability
Compiled to reach maximum performance
Provides a full vehicle for different target code generation such as C++, Java, C# etc...
Susan template expressions can consists of conditional expressions, match-expressions,
function calls, iterator expressions, and etc. For more expressions and its complete description
refer the Susan template guide. The match expression in the template language is used for
distinction of AST structure nodes declared in MetaModelica union types. See the listing 2.6
for an example of how pattern matching against a tree structure of figure 2.6.
ADD
INT MUL
10
INT INT
3 8
Figure 2.6: AST of 10+8*3 in the language Exp template exp(Exp inExp) ::=
match inExp
case INT(__) then value
case ADD(__) then '<%exp(lhs)%> + <%exp(rhs)%>'
case SUB(__) then '<%exp(lhs)%> - <%exp(rhs)%>'
case MULT(__) then '<%exp(lhs)%> * <%exp(rhs)%>'
case DIV(__) then '<%exp(lhs)%> / <%exp(rhs)%>'
case NEG(__) then '- <%exp(exp1)%> '
end exp;
Listing 2.6: Template “exp” - Pattern matching example
The template function exp is recursive. The scope of the INT constructor is automatically
opened by using INT(__) pattern to make its field (i.e., value) available, and the ADD, SUB,
MUL, DIV and NEG constructors are opened automatically by using the ADD(__), SUB(__),
22
MUL(__), DIV(__) and NEG(__) pattern respectively.
23
Chapter 3
Design and Implementation
This chapter describes the design and implementation of this thesis work. Initially, we present
the process of Java code generator design and implementation in OMC. Secondly, we present
the process of Java runtime system design and implementation for simulation.
3.1 Java Code Generation To design a Java code generator with the basic block diagram as shown in Figure 3.1a. Java
code generator takes the input as Modelica model and process in the generator to produce an
output as Java code corresponding to the Modelica model.
Input Output
Figure 3.1a: Block diagram for Java code generator
Code generator generates the Java code from the modelica model though OMC. The block
diagram for OpenModelica Compiler for Java Code Generation is shown in the figure 3.1b.
below. Code generator is depends directly on the SimCode’s solved equations (SimCodeTV).
So, the SimCodeTV module is important to understand, SimCodeTV is data structure for
solved equations. SimCodeTV contains many data structure representation, but in this section
we describe only some data structure.
DAELow
Solved Equations
Java Code
Figure 3.1b: Block diagram for OpenModelica Compiler for Java Code Generation
Modelica Model
OMC Front End
SimCodeTV
Code Generator
Simulation
Modelica Model
(testmodel.mo)
Java Code
Generator
Java Coded Model
(testmodel.Java)
24
Java code generation is implemented by passing the correct data structure into SimCodeTV
data structure as function template in Susan template language. The main functions of Java
code generation templates are described in the following sections.
3.1.1 Root Template
Root template is top level of code generation, it generates java file which is also a target file
can be used for simulation in Java Runtime System. It also consists of main function which is
“simulationFile(simCode)” as shown below in the listing 3.1.1.
Listing 3.1.1: Root template for Java Code generation
3.1.2 Java Specific File Template
In this section, we are going to elaborate more on the main funtion
“simulationFile(simCode)”. This main template function consists of set of templates which is
used to generate a Java file as complete Java executable file. The file consists of necessary
packages, class declaration, variable declarations, constructor, functions, external functions
and main class declaration. The main template “simulationFile(simCode)” is defined as shown
below in the listing 3.1.2.
template translateModel(SimCode simCode)
"Generates Java code and Makefile for compiling and running a
simulation of a Modelica model."
::=
match simCode
case SIMCODE(modelInfo=modelInfo as MODELINFO(__)) then
let()= textFile(simulationFile(simCode),
'<%fileNamePrefix%>.java')
"" //empty result for true case
//this top-level template always returns an empty result
//since generated texts are written to files directly
end translateModel;
template simulationFile(SimCode simCode)
"Generates code for main Java file for simulation target."
::=
match simCode
case SIMCODE(modelInfo = MODELINFO(__)) then
<<
<%simulationFileHeader(simCode)%>
<%modelClassName(simCode)%>
<%addGlobalInitialization(modelInfo, simCode)%>
<%modelClassConstructor(simCode)%>
<%functionInput(modelInfo, simCode)%>
<%functionOutput(modelInfo, simCode)%>
<%functionBoundParameters(parameterEquations, simCode)%>
<%functionODE(odeEquations, simCode)%>
<%functionDAE(allEquations, whenClauses, relations, simCode)%>
<%functions(modelInfo.functions, recordDecls, simCode)%>
<%mainFunction(simCode)%>
>>
end simulationFile;
25
Listing 3.1.2: Main temaple for Java specific file in Java Code generation
3.1.3 simulationFileHeader Template
This Java code generation template is responsible for importing the necessary packages,
which are used in the Java file, as header for the Java file. The header template is shown
below in the listing 3.1.3., and an example is shown in the Listing 3.1.4a.
Listing 3.1.3: simulationFileHeader template for Java Code generation
3.1.4 modelClassName Template
This Java code generation template corresponds to the model class declaration and initializing
Data object with necessary parameters. In this model class declaration template, declares
class name as model name, number of states, output file name and initializing a new SimData
as data object. As shown below in the listing 3.1.4.
Listing 3.1.4: modelClassName template for Java Code generation
Example 1: Representation of simulationFileHeader and modelClassName declaration are
shown in the listing 3.1.4b., for the below model is shown in the listing 3.1.4a.
In the below model “AddReal.mo”, consists of two algebraic parameters and an algebraic
template simulationFileHeader(SimCode simCode)
"Generates header part of simulation file."
::=
match simCode
case SIMCODE(modelInfo=MODELINFO(__), extObjInfo=EXTOBJINFO(__)) then
<<
package CodegenJava; // solver package name
import java.io.IOException;
import java.math.*;
import java.lang.Thread.State;
import java.util.Vector;
>>
end simulationFileHeader;
template modelClassName(SimCode simCode)
"Generates model class name of simulation file."
::=
match simCode
case SIMCODE(modelInfo=MODELINFO(varInfo = vi as VARINFO(__)),
extObjInfo=EXTOBJINFO(__)) then
let noOfstates = if vi.numAlgVars then vi.numAlgVars else vi.numStateVars
<<
/* Simulation code for <%dotPath(modelInfo.name)%> generated by the
OpenModelica Compiler <%getVersionNr()%>.*/
@SuppressWarnings("unused")
public class <%dotPath(modelInfo.name)%> extends SuperModel // name of
the given model
{
static int n= <%noOfstates%>; // n --> number of states
static String filename = "<%dotPath(modelInfo.name)%>_result.txt";
/* Simulation output file */
public static SimData localData = new SimData(n, 0, 0); /*
Initializing a Data Object*/
>>
end modelClassName;
26
variables. It also consists of an ODEs equation with an external function called addReal1_.
Listing 3.1.4a. Model AddReal1.mo
Listing 3.1.4b:Example of simulationFileHeader and modelClassName declaration
3.1.5 addGlobalInitialization Template
This Java code generation template corresponds to the initialization of global variables and
parameters. In this template, we declare algebraic variable parameter lists such as variables,
parameters, integer variables, integer parameters, string variables, string parameters and
external objects under separate subsections in order to easy understand for the users. The
example is shown in the listing 3.1.6a.
3.1.6 modelClassConstructorTemplate
This Java code generation template corresponds to the declaration of a constructor. In this
template, the generation of class constructor with the state initialization as in model or set as
default for the equations. The example is shown in the listing 3.1.6a.
Example 2: Representation of global initialization and constructor as shown in the listing
3.1.6a. for the model “AddReal.mo” mentioned in listing 3.1.4a.
package CodegenJava; // solver package name
import java.io.IOException;
import java.math.*;
import java.lang.Thread.State;
import java.util.Vector;
/* Simulation code for AddReal1 generated by the OpenModelica Compiler
1.9.0 beta4+dev (r16707).*/
@SuppressWarnings("unused")
public class AddReal1 extends SuperModel /* name of the given model */
{
static int n= 1; // n --> number of states
static String filename = "AddReal1_result.txt"; /* Simulation output
file */
public static SimData localData = new SimData(n, 0, 0); /*
Initializing a Data Object */
model AddReal1
parameter Real a=2.3;
parameter Real b=4.5;
Real c;
equation
c = addReal1_(a, b);
end AddReal1;
/* Algebraic Vars */
double c[] = new double [1]; /* c */
/* Algebraic Parameter */
double a = 2.3; /* a */
double b = 4.5; /* b */
public AddReal1() // constructor
{
/* States Initialization Ordinary equations */
localData.x/*state*/.add(0,0.0); /* $dummy */
/* States Initialization algebraic equations */
localData.x/*state*/.add(0,0.0); /* c */
}
simulationFileHeader
GlobalInitialization
27
Listing 3.1.6a:Example of global initialization and constructor for AddReal1.mo
3.1.7 functionBoundParameters Template
In this function BoundParameters, the parameters for state algebraic equations are bounded
with corresponding state derivatives. This function is being called in functionODE,
functionDAE to update the algebraic equations. The parameter equations are either
“SES_SIMPLE_ASSIGN” or “SES_ALGORITHM” defined as shown below in the listing 3.1.7.
Listing 3.1.7: functionBoundParameters Template for Java code generation
Example 3: Representation of bound parameter is shown in the listing 3.1.7b. for the below
model “EquationFor6.mo”. In this model, there are three algebraic variables with three simple
algebraic equations respectively and shown in the listing 3.1.7a.
Listing 3.1.7a: EquationFor6.mo
template functionBoundParameters(list<SimEqSystem> parameterEquations,
SimCode simCode)
::=
let &tmp = buffer ""
<<
public void BoundParameters()
{
<% parameterEquations
|> saeq as SES_SIMPLE_ASSIGN(__) => equation_(saeq, contextOther,
simCode, &tmp) ;separator="\n"%>
<% parameterEquations
|> eq as SES_ALGORITHM(__) => equation_(eq, contextOther, simCode,
&tmp) ;separator="\n"%>
}
>>
end functionBoundParameters;
class EquationFor6
Real a[3];
equation
for i loop
a[i] = i;
end for;
end EquationFor6;
// Result:
// class EquationFor6
// Real a[1];
// Real a[2];
// Real a[3];
// equation
// a[1] = 1.0;
// a[2] = 2.0;
// a[3] = 3.0;
// end EquationFor6;
// endResult
Flattened Model
28
Listing 3.1.7b:Example of bound parameter function for EquationFor6.mo
3.1.8 functionODE Template
This Java code generation template is an important function for the simulation. In this
template, only the “statecontEquations” implemented. If the model consists of ordinary
differential equation then the corresponding “equation_” will be executed. The “equation_”
template is the root template for the entire equations such as SES_SIMPLE_ASSIGN,
SES_ARRAY_CALL_ASSIGN, SES_ALGORITHM, SES_WHEN. StatesAssign template is useful
for declaring the variables locally. Finally “BoundParameters” function will be called to
update the changes in stateDerivative if any. The functionODE template is defined as shown
in the listing 3.1.8 and its representation of functionODE is shown in the listing 3.1.9a. for
“BouncingBall.mo” model.
Listing 3.1.8: functionODE Template for Java code generation
public void BoundParameters()
{
localData.xdot /*stateDerivative*/.add(0,1.0); //a[1] = 1.0; localData.xdot /*stateDerivative*/.add(1,2.0); //a[2] = 2.0; localData.xdot /*stateDerivative*/.add(2,3.0); //a[3] = 3.0; }
template functionODE(list<list<SimEqSystem>> stateContEquations, SimCode
simCode)
::=
match simCode
case SIMCODE(modelInfo =
MODELINFO(varInfo=VARINFO(numStateVars=numStateVars), vars=SIMVARS(__)))
then
match modelInfo
case MODELINFO(varInfo=VARINFO(numStateVars=numStateVars),
vars=SIMVARS(__)) then
let &tmp = buffer ""
<<
public void functionODE()
{
<%StatesAssign("states", vars.stateVars, simCode)
;separator="\n"%>
<%StatesAssign("states", vars.algVars, simCode)
;separator="\n"%>
<%stateContEquations |> eqs =>
(eqs |> it => equation_(it, contextOther, simCode, &tmp)
;separator="\n")
;separator="\n"%>
BoundParameters();
}
>>
end functionODE;
29
3.1.9 functionDAE Template
In this template, all type of equations with when-clauses is implemented. For every equation,
the corresponding “equation_” will be executed. StatesAssign template is useful for
declaration of variables locally. The functionDAE template is defined as shown in the listing
3.1.9 and its representation of functionDAE is shown in the listing 3.1.9a. for
“BouncingBall.mo” model.
Listing 3.1.9: functionDAE Template for Java code generation
Example 4: Representation of functionODE and functionDAE are shown in the listing 3.1.9b.
for the “BouncingBall.mo” as shown in listing 3.1.9a. This model contains two basic
equations and when equation as discrete issues suitable for functionODE and functionDAE.
Listing 3.1.9a: BouncingBall.mo
model BouncingBall "The bouncing ball model"
constant Real g = 9.81; // Gravitational acceleration
parameter Real c = 0.9; // Elasticity constant of ball
parameter Real radius = 0.1; // Radius of the ball
Real height(start = 1); // height above ground of the ball center
Real velocity(start = 0); // Velocity of the ball
equation
der(height) = velocity;
der(velocity) = -g;
when height <= radius then
reinit(velocity, -c*pre(velocity));
end when;
end BouncingBall;
template functionDAE(list<SimEqSystem> allEquationsPlusWhen,
list<SimWhenClause> whenClauses, list<ZeroCrossing> relations,
SimCode simCode)
"Generates function in simulation file."
::=
match simCode
case SIMCODE(modelInfo =
MODELINFO(varInfo=VARINFO(numStateVars=numStateVars), vars=SIMVARS(__)))
then
match modelInfo
case MODELINFO(varInfo=VARINFO(numStateVars=numStateVars),
vars=SIMVARS(__)) then
let &varDecls = buffer "" /*BUFD*/
let &tmp = buffer ""
<<
public void functionDAE()
{
<%StatesAssign("states", vars.stateVars, simCode)
;separator="\n"%>
<%StatesAssign("states", vars.algVars, simCode) ;separator="\n"%>
<%allEquationsPlusWhen |> eq => equation_(eq,
contextSimulationDiscrete, simCode, &tmp)
;separator="\n"%>
<%whenClauses |> when hasindex i0 => genreinits(when, relations,
contextOther, &varDecls, simCode)
;separator="\n"
%>
}
>>
end functionDAE;
30
Listing 3.1.9b:Example of functionODE and functionDAE for BouncingBall.mo
3.1.10 functions Template
In this template, Java code generation for user defined functions and external functions. The
root template for this “functionJava” is “functions” template which contains the list of
functions “list<Function>”. This template is the root for the following templates such as
user defined functions, external functions and the record constructor. The “functionJava”
template is defined as shown in the listing 3.1.10.
Listing 3.1.10: Functions and external functions Template for Java code generation
Example 5: Representation of external function is shown in the listing 3.1.10a. for the
“AddReal.mo” model, which consists of a ODEs equation with an external function called
“addReal1_” in C language.
public void functionODE()
{
double velocity = localData.getState().elementAt(0);
double height = localData.getState().elementAt(1);
localData.xdot.add(0,-9.81);
localData.xdot.add(1,velocity);
BoundParameters();
}
public void functionDAE()
{
double velocity = localData.getState().elementAt(0);
double height = localData.getState().elementAt(1);
localData.xdot.add(0,-9.81);
localData.xdot.add(1,velocity);
//(height <= radius) "Condition Relation"
if (height <= radius)
{
velocity = ((-c) * velocity);
}
}
template functionJava(Function fn, list<RecordDeclaration> recordDecls,
SimCode simCode)
"Generates the body for a function."
::=
match fn
case fn as FUNCTION(__) then regularFunction(fn, simCode)
case fn as EXTERNAL_FUNCTION(__) then externalFunction(fn, simCode)
case fn as RECORD_CONSTRUCTOR(__) then recordsJava(recordDecls)
end functionJava;
31
AddReal1.mo
Listing 3.1.10a:Example of external functions for AddReal1.mo
3.1.11 mainFunction Template
This Java code generation template corresponds to the main class declaration and invokes the
EulerSolver with correct parameters. It is shown below in the listing 3.1.11.
Listing 3.1.11: mainfunction Template for Java code generation
Example 9: Representation of main function for the class model is shown in the listing
3.1.11a. for the AddReal1.mo.
template mainFunction(SimCode simCode)
::=
match simCode
case SIMCODE(modelInfo = MODELINFO(__)) then
<<
public static void main(String[] args) throws IOException
{
<%dotPath(modelInfo.name)%> temp = new
<%dotPath(modelInfo.name)%>();
temp.functionODE();
/* Invoke the Solver with correct parameters */
EulerSolver.main(localData.stepsize, localData, temp, filename);
}
}
>>
end mainFunction;
function addReal1_
input Real x;
input Real y;
output Real res;
external "C";
end addReal1_;
model AddReal1
parameter Real a=2.3;
parameter Real b=4.5;
Real c;
equation
c = addReal1_(a, b);
end AddReal1;
public void BoundParameters()
{
/*Function Call*/
localData.xdot/*stateDerivative*/.add(0, addReal1__(a,b));
}
public double addReal1__(double arg_x , double arg_y) /*Function*/
{
double res;
double x = arg_x;
double y = arg_y;
return res = addReal1_(x,y); /*externalFunction*/
}
32
Listing 3.1.11a:Example of global initialization and constructor for AddReal1.mo
3.1.12 daeExp Template
This Java code generation template is the root template for all the expressions. The
expressions which are used in models are flattened, and those expressions “exp” match the
corresponding case in this template in order to translate into a Java code. This template is
defined below in the listing 3.1.12.
Listing 3.1.12:daeExp template for Java code generation
public static void main(String[] args) throws IOException
{
AddReal1 temp = new AddReal1();
temp.functionODE();
/* Invoke the Solver with correct parameters */
EulerSolver.main(localData.stepsize, localData, temp, filename);
}
template daeExp(Exp exp, Context context, Text &preExp /*BUFP*/, SimCode
simCode)
"Generates code for an expression."
::=
match exp
case e as ICONST(__) then integer
case e as RCONST(__) then real
case e as SCONST(__) then daeExpSconst(string, context,
&preExp /*BUFC*/, simCode)
case e as BCONST(__) then if bool then "true" else "false"
case e as ENUM_LITERAL(__) then index
case e as CREF(__) then daeExpCrefRhs(e, context, &preExp,
simCode)
case e as BINARY(__) then daeExpBinary(e, context, &preExp
/*BUFC*/, simCode)
case e as UNARY(__) then daeExpUnary(e, context, &preExp
/*BUFC*/, simCode)
/**************************** Some code removed here ***************
*******************************************************************/
case e as CAST(__) then daeExpCast(e, context, &preExp
/*BUFC*/, simCode)
case e as ASUB(__) then daeExpAsub(e, context, &preExp
/*BUFC*/, simCode)
case e as TSUB(__) then '<%daeExp(exp, context, &preExp,
simCode)%>'
case e as SIZE(__) then daeExpSize(e, context, &preExp
/*BUFC*/, simCode)
case e as BOX(__) then daeExpBox(e, context, &preExp
/*BUFC*/, simCode)
case e as UNBOX(__) then daeExpUnbox(e, context, &preExp
/*BUFC*/, simCode)
case e as SHARED_LITERAL(__) then '_OMC_LIT<%index%>'
// META_TUPLE
// META_OPTION
// METARECORDCALL
else error(sourceInfo(), 'Unknown expression:
<%ExpressionDump.printExpStr(exp)%>')
end daeExp;
33
The interested readers who wants to know more about Java code generator implemention are
welcome to go though the full implemention code in the section “Appendix B Implementation
code”.
3.2 Java runtime system
Java Runtime System takes the java files as input and returns the simulation results to verify
the model. Runtime system is needed for every specific programming language. The block
diagram for Java Runtime System is shown below in the Figure 3.2a.
Input Output
Figure 3.2a: Block diagram for Java Runtime System
The class diagram for Java Runtime System is shown below in the Figure 3.2b, and consists
of
SimModel – Java coded model which is generated from Java code generator.
SimData – The dynamic data for a simulation at a given time.
Solver: Euler's method for numerical integration.
Super Model – This is the superclass for any model class generated from Modelica.
Static Model – A ModelicaModel with its static information.
Modelica Variable –Static information about a single variable in the model.
Modelica Equation: A single equation in the Modelica model.
Figure 3.2b: Class Diagram for Java Runtime System
Java coded model
(testmodel.Java)
Java Runtime
System
Simulation test
results
Super Model
SimModel
(testmodel.Java)
EulerSolver
Modelica Variable
SimData
Static Model Modelica Equation
testmodel_result.txt
Output
34
The description of the class diagram and its implementation is discussed in the following
sections.
3.2.1 SimModel
The SimModel is a Java coded model which is generated by using Java code generator for the
corresponding modelica model. The Java code model contains the packages, class declaration,
variable declaration, class constructor, functions, external functions and the main class
declaration.
The sample Java code for modelica models are given in the section “Appendix A” for some
test models.
3.2.2 SimData
SimData class is being initialized by the model class declaration object in SimModel. After
the initialization, this class is ready for simulation at a given time. This class contains the
values of state and state derivative in appropriate format for the solver. The state and state
derivatives are initialize as Vector type as Double for better efficiency for runtime system.
This class also contains default simulation settings. This SimData implementation is shown in
the listing 3.2.1.
package jrt;
import java.util.*;
import org.jscience.physics.amount.* ;
import javax.measure.quantity.* ;
/*** @author [email protected]***/
public class SimData {
double time ;
int size;
double start;
double stepsize;
double stop;
/* Initialize as Vector type as Double*/
Vector<Double> x = new Vector<Double>();
Vector<Double> xdot = new Vector<Double>() ;
public SimData( int xdim, int mdim, int zdim ) {
// simulation default settings
size = xdim;
start = 0.0;
stepsize = 0.002;
stop = 1.0;
}
/*** Advance to next time step, advancing time by dt.***/
public void advance( double dt )
{
time = time+dt;
}
/*** Get the continuous state vector ***/
public Vector<Double> getState()
{
return x ;
}
************************ to be continued
35
Listing 3.2.1:SimData for Java Runtime System
3.2.3 EulerSolver
Java runtime system uses Euler's numerical integration method. The EulerSolver main class is
invoked by SimModel’s main-function with necessary parameters. By using those parameters,
the solver main class initializes the output result file (testmodel_result.txt). And the values of
state and state derivative values by using SimData object.
In the main simulation loop, the solver function and CSVBuilder function is being called for
simulate the model. The function Solver() takes the appropriate parameters in order to do the
numerical integration. There are two main operations in the Solver function, one is the setting
of state values in the size loop. And the other is the function-call of functionODE ().
The state vectors are compute by using below equation:
states[i] = states[i] + statesDerivatives[i] * (step);
This method is implemented and shown in the listing 3.2.2. This function helps to get the state
and statesDerivatives values which is set for the operations and generates the output result file
by using CSVBuilder function.
Finally there is an small calculation for simulation time for the model. The outline of the code
for time stamp is given below.
// for time measurement
long startSimulationTime = System.currentTimeMillis();
// simulation loop
// end simulation time measurements
long endSimulationTime = System.currentTimeMillis();
// simulation time calculation
System.out.println("Simulation took: " + (endSimulationTime -
startSimulationTime)+ " milliseconds.\n");
/*** Get the continuous state derivative vector.***/
public Vector<Double> getDer()
{
return xdot ;
}
/*** Get current time.***/
public double getTime()
{
return time ;
}
/*** Set the continuous state vector and update time.***/
public void updateState( Vector<Double> x )
{
this.x = x ;
}
}
36
Listing 3.2.2: Solver Function of EulerSolver.Java for Java Runtime System
For EulerSolver, SuperModel, StaticModel and it’s ModelicaEquation, Modelica Variable.
The interested readers who wants to know more about Java Runtime System implemention are
welcome to go though the full implemention code in section “Appendix C Java Runtime
System”.
public static void Solver( SimData data ,SuperModel model, double dt )
throws IOException
{
Vector<Double> x = data.getState() ;
Vector<Double> xdot = data.getDer() ;
for(int i=0;i<x.size();i++)
{
x.set(i, x.get(i)+ xdot.get(i)*dt);
}
data.advance( dt ) ;
model.functionODE();
}
37
Chapter 4
Testing
In this chapter, we provide different test cases conducted to test the implementation of the
thesis work.
4.1 Modelica Test Models
We have tested around 250 test case models and all the models were successfully generated.
We have taken almost all the types of Modelica language constructs from the OpenModelica
test suite. The listing.4 shown below is the general description of subset from the
OpenModelica test suite. The detailed listing is shown in “Appendix B” with the model name
and its simulation time for both Java Runtime System and C Runtime System.
Test Cases Section Description
38 algorithms-
functions
In this section, we have tested all type of Algorithms and
functions such as inline function, function call, function
evaluations.
56 array In this section, we have tested for Arrays, array
declarations, array operations such as array addition,
division, multiplication, subtraction, xpowers, and etc,.
37 built-in-functions In this section, we have generated Java code for the built-
in-functions which are Acos, Asin, Atan, Cos, Cosh, Log,
Log10, Sqrt, Sin, Sinh, Sign, Tan, Tanh, Transpose, Ceil
and etc,.
9 declarations In this section, we perform to test the Constant
declarations, DeclarationEquations.
32 Equations In this section, we have tested all type of equations with
When, for, if condition equations and some hybrid
models which is taken from book [2].
23 extends In this section, Some extends models like Colors,
Moonlanding, Multiplex, StepAdvanced and some more
models are tested.
38
7 external-functions In this section, we have tested the different external
functions for instance AddReal1, ExternalFunctionArray,
ExternalFunctionBuiltin, etc.
13 records In this section, we have tested record construct of
Modelica language such as RecordAssignment,
RecordConstants, and RecordVariability.
30 MetaModelica
models
In this section, we have tested all type MetaModelica
such as List, match, partialfunction and uniontype.
Listing 4: Modelica Test Models
In this section, we have chosen one model from OpenModelica and another model from
MetaModelica to showcase the implementation of Java code generator and its Java Runtime
system works fine. The verification and performance test methods are used for testing the
generated models.
4.1.1 Verification Test
The following method is used to verify the test results:
Generate the simulation output for both C Runtime System (testmodel_res.csv)
and Java Runtime System (testmodel_resJava.csv).
By executing the file Script.mos, a graph is generated. We can verify the model using
this graph.
Script.mos
4.1.2 Performance Test
The following method is used for testing the performance of models:
By executing the file Script_table.mos, a table is generated. The table consists of
model name and its simulation time.
The flag “+s +simCodeTarget=Java” is used for Java Runtime System. The flag “+s
+simCodeTarget=C” is used for C Runtime System.
By using these tables, we can compare the simulation time of models for both C
Runtime System and Java Runtime System.
html := diffSimulationResultsHtml("/*any one attribute*/ ",
"testmodel_res.csv", "testmodel_resJava.csv");
writeFile("b.html",html);getErrorString();
system("cp " + getInstallationDirectoryPath() +
"/share/doc/omc/testmodels/dygraph-combined.js .");
system("chromium-browser b.html &");
39
Script_table.mos
Model 1: BouncingBall.mo:
The BouncingBall model contains the two basic equations of motion relating height and
velocity as well as the acceleration caused by the gravitational force. At the bounce instant the
velocity is suddenly reversed and slightly decreased, i.e.,veclocity(after bounce) = -
c*veclocity(before bounce), which is accomplished by the special reinit synatactic form.. This
model suitable for functionODE and functionDAE. This model is a good example of a hybrid
system for which the when-equation is appropriate when modeled. And this discrete model
handles the event handling. The full Java code generation of this model is given in section
“Appendix A”.
Verification Test:
Figure 4.1.1a: Graph for BouncingBall.mo
mofiles := {"testmodel1.mo", "testmodel2.mo"};
system("rm -f log.csv");
{writeFile(file + ".mos", "
loadFile(\""+file+"\");
names:=getClassNames();
name:=names[1];
res:=simulate(name);
t:=res.timeSimulation;
writeFile(\"log.txt\",typeNameString(name) + \",\"
+ String(t) + \"\\n\",append=true);
") for file in mofiles};
{runScript(file + ".mos") for file in mofiles};
40
From this graph, we can conclude that the projection of BouncingBall for both JCG and CCG
are almost same. Thus the model is successfully generated using JCG and simulated using
JRS.
Performance Test:
Simulation Time For: C Runtime System Java Runtime System
BouncingBall.mo 0.0156448 seconds 0.0209959 seconds
The following model is an example of MetaModelica.
Model 2: PartialFn12.mo
This model consists of an equation section with the function call of TestFn(x). This function
section has another function call. The full Java code generation of this model is given in the
section “Appendix A”. partial function PartFn
input Real x;
output Real y;
end PartFn;
function FullFn
extends PartFn;
input Real extraReal1;
input Real extraReal2;
algorithm
y := x * ((extraReal1 + extraReal2) / 2.0);
end FullFn;
function CallerFn
input Real inReal;
input PartFn inPartFn;
output Real outReal;
algorithm
outReal := inPartFn(inReal) * 2.0;
end CallerFn;
function TestFn
input Real inReal;
output Real outReal;
algorithm
outReal := 0;
for i in 1:10 loop
outReal := outReal + CallerFn(inReal, function FullFn(1.5,7.5));
end for;
end TestFn;
model PartialFn12
Real x;
Real y;
equation
x = 2.0;
y = TestFn(x);
end PartialFn12;
41
Verification Test:
Figure 4.1.1b: Graph for PartialFn12.mo
From this graph, we can conclude that the projection of PartialFn for both JCG and CCG are
almost same. Thus the model is successfully generated using JCG and simulated using JRS.
Performance Test:
Simulation Time For: C Runtime System Java Runtime System
PartialFn12.mo 0.0099915 seconds 0.00943867 seconds
The following bar chart shows the performance of models in JRS and CRS. The performance
of Java Runtime System varies from C Runtime System, because C code executes more
directly on the hardware platform whereas Java runs on a JVM. Thus the C compiler compiles
the code directly into the machine code while the Java compiler compiles into the byte code
which is understandable by JVM. Due to this, Java Runtime System takes more time to
execute than C Runtime System. In contrast for some models, Java Runtime System executes
in lesser time than C Run time System.
42
Figure 4.1: Bar Chart Graph for Equations Subset
4.2 Improvements from previous version
When we started this thesis work, we used the thesis report of “Template-Based Java Code
Generator and Java Runtime System for OpenModelica” by Inam Ul Haq. A. As the
development of “Template-Based Java Code Generator” began from his thesis work and listed
below the improvements made in this thesis work.
Design:
We started the design of Java Code Generator and Java Runtime System in order to get better
efficiency, and to handle hybrid models such as event handling, external functions, records
and MetaModelica constructs. With the help of Prof. Hans Georg Schaathun, the new design
of Java Runtime System is created and the detailed class diagram is given in the chapter 3.
Implementation: Java Code Generator
We have implemented the Java Code Generator for the whole Openmodelica and
Metamodelica constructs. The previous version of the Java Code Generator did not cover the
following features:
Algebraic loops
Hybrid Models (Event Handling)
Algebraic Arrays
External functions
Records
MetaModelica constructs such as match, List and PartialFunctions.
43
But, we have implemented the complete Java Code Generator for the entire Modelica
constructs, which are not supported in the previous version.
Java Runtime System:
The OpenModelica has changed a lot during the period of two years and this leads to some
changes in simCodeTv. As we mentioned before, simCodeTv contains all the data structures
which are required for the code generation. So the previous version of Java Code Generator
and Java Runtime System does not support the latest version of Openmodelica. Therefore we
couldn’t use the previous version of Java Runtime System anymore. This leads to the new
design of Java Runtime System based on the previous version. We have implemented the
complete Java Runtime System which supports the latest version of Java Code Generator.
Testing:
We have used the script files for verification testing and performance testing, which were not
used in the previous version. It is used to test the group of models which makes the testing
process easier and efficient. The produced results are very accurate and clear, which is used to
compare the simulation time of Java Runtime System with C Runtime System. We have used
a total of 250 test cases which are passed successfully, from which we can conclude that the
entire Modelica constructs are covered. The previous version does not cover the entire
Modelica constructs.
44
45
Chapter 5
Conclusion and Future Work
This chapter concludes the work conducted in this thesis work and discussion the possible
directions for future work.
5.1 Conclusion
In this thesis work, we have implemented an extended version of the previous subset Java
Code Generator by using Susan template based language. We have tested around 250 test
cases which cover almost all types of Modelica language constructs. This code generation will
be helpful to open the OpenModelica Java code generator to a wide range of users both
academic and commercial.
5.2 Future Work
The current version of SimCodeTv is unstable and the Java Code Generation is fully
dependent on the SimCodeTv. If the SimCodeTv is modified in future then the Java Code
Generation will be interrupted. Thus in order to support the Java Code Generation, a stable
SimCodeTv can be implemented.
Another task for future work is to implement a Click-on button in OMEdit which makes
exporting models to an Java format from OpenModelica straightforward for users. To
implement a click-on button in OMEdit.
46
47
User Guide 1. Install OpenModelica Compiler. Follow the instructions found in
https://www.openmodelica.org/index.php/developer/source-code
2. Compiling a model and generate Java code
The following step compiles a model to a Java code generation.
- Open the mingw terminal if you are a windows user and normal terminal for linux user
- In the terminal window go to the path where your model file found(C:/<%path to .mo
file%>).
- Go to omc path (<%path to omc%>/omc) and write the flag +s +simCodeTarget=Java
<%your.mo file%>.mo>
This is demonstrated in the following example, where +s +simCodeTarget=Java is the flag
specific for Java code generation and Circle.mo is the model name.
Once compilation has completed successfully a Java file will have been generated and can be
found in the same directory as your model found.
48
49
References
[1] OpenModelica project. https://www.openmodelica.org/
[2] TDDB44 Compiler Construction course http://www.ida.liu.se/~TDDB44/index.en.shtml.
[3] The OpenModelica source code. Available from
https://openmodelica.org/svn/OpenModelica/trunk/Compiler/Template/ User name:
anonymous, Password: none
Books:
[4] Peter Fritzson. Principles of Object-Oriented Modeling and Simulation with Modelica,
Wiley-IEEE Press, 2003.
[5] Alfred V.Aho, Monica S.Lam, Ravi Sethi, Jeffrey D.Ullman. Compilers Principles,
Techniques, & Tools, Second Edition, Addison Wesley, 2006.
[6] David J. Barnes, Michael Kölling. Objects First with Java, third edition, Pearson
Education Limited, 2006.
Technical reports:
[7] Peter Fritzson, Pavol Privitzer Adrian Pop, and Martin Sjölund. Towards a Text
Generation Template Language for Modelica. Technical report in Computer and
Information Science, Linköping University Electronic Press, September 2009.
[8] Peter Fritzson, Adrian Pop, and Martin Sjölund. Towards Modelica 4 Meta-
Programming and Language Modeling with MetaModelica 2.0, Technical report in
Computer and Information Science, Linköping University Electronic Press, May 2011.
[9] Peter Fritzson, Adrian Pop, and Martin Sjölund. Meta-Programming and Language
Modeling with MetaModelica 1.0, Technical report in Computer and Information
Science, Linköping University Electronic Press, March 2011.
[10] Peter Fritzson. Modelica Text Template Language Susan Users Guide v0.2,
Technical report in Linköping University, PELAB - Programming Environment
Laboratory, April 2010.
Thesis:
[11] Inam Ul Haq. A Template-Based Java Code Generator and Java Runtime System
for OpenModelica. Master's thesis, PELAB, Linköping University, Department of
Computer and Information Science, August 2011.
[12] Rickard Lindberg. A Template-Based Code Generator for the OpenModelica
Compiler. Master's thesis, PELAB, Linköping University, Department of Computer
and Information Science, March 2010.
[13] Martin Sjölund. Bidirectional external function interface between
Modelica/MetaModelica and Java. Master's thesis, PELAB, Linköping University,
Department of Computer and Information Science, August 2009.
50
51
Appendix
A Sample Results
Model 1: BouncingBall.Java
package CodegenJava; // solver package name
import java.io.IOException;
import java.math.*;
import java.lang.Thread.State;
import java.util.Vector;
// Simulation code for BouncingBall generated by the OpenModelica Compiler 1.9.1+dev
(RML version).
@SuppressWarnings("unused")
public class BouncingBall extends SuperModel // name of the given model
{
static int n= 2; // n --> number of states
static String filename = "BouncingBall_result.txt"; // Simulation output file
public static SimData localData = new SimData(n, 0, 0); // Initializing a Data Object
/* Algebraic Vars */
/* Algebraic Parameter */
double c = 0.9; /* c */
double radius = 0.1; /* radius */
/* External Objects */
/* Algebraic Integer Vars */
/* Algebraic Integer Parameter */
/* Algebraic String Variables */
/* Algebraic String Parameter */
public BouncingBall() // constructor
{
/* States */
/* States Initialization Ordinary equations */
localData.x/*state*/.add(0,0.0); /* velocity */
localData.x/*state*/.add(1,1.0); /* height */
/* States Initialization algebraic equations */
}
public void InputFun()
{
}
public void OutputFun()
{
}
52
public void BoundParameters()
{
}
public void functionODE()
{
double velocity = localData.getState().elementAt(0);
double height = localData.getState().elementAt(1);
localData.xdot/*stateDerivative*/.add(0,-9.81);
localData.xdot/*stateDerivative*/.add(1,velocity);
BoundParameters();
}
public void functionDAE()
{
double velocity = localData.getState().elementAt(0);
double height = localData.getState().elementAt(1);
localData.xdot/*stateDerivative*/.add(0,-9.81);
localData.xdot/*stateDerivative*/.add(1,velocity);
//(height <= radius) "Condition Relation"
if (height <= radius) {
velocity = ((-c) * velocity);
}
}
public static void main(String[] args) throws IOException
{
BouncingBall temp = new BouncingBall();
temp.functionODE();
/* Invoke the Solver with correct parameters */
EulerSolver.main(localData.stepsize, localData, temp, filename);
}
}
Model 2: PartialFn12.Java
package jrt; // solver package name
import java.io.IOException;
import java.math.*;
import java.lang.Thread.State;
import java.util.Vector;
// Simulation code for PartialFn12 generated by the OpenModelica Compiler 1.9.1+dev (RML
version).
@SuppressWarnings("unused")
public class PartialFn12 extends SuperModel // name of the given model
{
53
static int n= 2; // n --> number of states
static String filename = "PartialFn12_result.txt"; // Simulation output file
public static SimData localData = new SimData(n, 0, 0); // Initializing a Data Object
/* Algebraic Vars */
double y[] = new double [2]; /* y */
double x[] = new double [2]; /* x */
/* Algebraic Parameter */
/* External Objects */
/* Algebraic Integer Vars */
/* Algebraic Integer Parameter */
/* Algebraic String Variables */
/* Algebraic String Parameter */
public PartialFn12() // constructor
{
/* States */
/* States Initialization Ordinary equations */
localData.x/*state*/.add(0,0.0); /* $dummy */
/* States Initialization algebraic equations */
localData.x/*state*/.add(0,0.0); /* y */
localData.x/*state*/.add(1,0.0); /* x */
}
public void InputFun()
{
}
public void OutputFun()
{
}
public void BoundParameters()
{
localData.xdot/*stateDerivative*/.add(0, TestFn(2.0));
localData.xdot/*stateDerivative*/.add(1,2.0);
}
public void functionODE()
{
double $dummy = localData.getState().elementAt(0);
double y = localData.getState().elementAt(0);
double x = localData.getState().elementAt(1);
localData.xdot/*stateDerivative*/.add(0,0.0);
BoundParameters();
}
public void functionDAE()
{
double $dummy = localData.getState().elementAt(0);
54
double y = localData.getState().elementAt(0);
double x = localData.getState().elementAt(1);
localData.xdot/*stateDerivative*/.add(0,0.0);
BoundParameters();
}
public double CallerFn__FullFn(double arg_inReal , double arg_FullFn_extraReal1 ,
double arg_FullFn_extraReal2)
{
double outReal;
double inReal = arg_inReal;
double FullFn_extraReal1 = arg_FullFn_extraReal1;
double FullFn_extraReal2 = arg_FullFn_extraReal2;
return outReal = (2.0 * FullFn(inReal,FullFn_extraReal1,FullFn_extraReal2));
}
public double TestFn(double arg_inReal)
{
double outReal;
double inReal = arg_inReal;
outReal = 0.0;
/*algStmtForRange_impl*/
for ( int i = 1; i<=10; i++) {
outReal = (outReal + CallerFn__FullFn(inReal,1.5,7.5));
}
return outReal;
}
public double FullFn(double arg_x , double arg_extraReal1 , double arg_extraReal2)
{
double y;
double x = arg_x;
double extraReal1 = arg_extraReal1;
double extraReal2 = arg_extraReal2;
return y = (0.5 * (x * (extraReal1 + extraReal2)));
}
public static void main(String[] args) throws IOException
{
PartialFn12 temp = new PartialFn12();
temp.functionODE();
/* Invoke the Solver with correct parameters */
EulerSolver.main(localData.stepsize, localData, temp, filename);
}
}
55
B Simulation Time Number
of Model
Model Name Simulation Time in Seconds
C Runtime Java Runtime
1 Modelica.Electrical.Analog.Examples. HeatingRectifier
0.043 0.066
2 Modelica.Mechanics.MultiBody.Examples. Loops.Engine1b
1. .305 1.440
3 Modelica.Mechanics.MultiBody.Examples. Elementary.DoublePendulum
0.458 0.476
4 While 0.000913 0.001231
5 WhenPriority 0.000744 0.000697
6 Vectorizable 0.000684 0.001647
7 Inline5 0.000774 0.000999
8 Inline1 0.000685 0.001759
9 FunctionMultiReturn 0.000623 0.002259
10 FunctionEvalBuiltin 0.001012 0.001245
11 FunctionEval12 0.00069 0.000886
12 FunctionEval11 0.000672 0.002041
13 FunctionEval8 0.000724 0.001088
14 FunctionEval7 0.00072 0.001785
15 FunctionEval6 0.000721 0.001488
16 FunctionEval4 0.000851 0.001054
17 FunctionEval3 0.001149 0.001078
18 FunctionEval2 0.000673 0.001425
19 FunctionEval1 0.000807 0.00105
20 FunctionDefaultArgs 0.000671 0.001474
21 FunctionCall 0.000669 0.001073
22 FunctionBreak 0.001807 0.002823
23 ForSimple 0.000902 0.001026
24 ForNested 0.001667 0.001824
25 AssignmentSimple 0.000799 0.000864
26 AssignmentFunctionMultiple1 0.001236 0.001008
27 AssignmentFunction 0.000705 0.001258
28 AlgorithmSection 0.00076 0.001488
29 AlgorithmFor6 0.002617 0.003154
30 AlgorithmFor5 0.001025 0.001147
31 AlgorithmFor4 0.000868 0.001043
32 AlgorithmFor3 0.000894 0.001179
33 AlgorithmFor2 0.000899 0.002716
34 AlgorithmFor1 0.001115 0.001598
35 AlgorithmElseOpt 0.00074 0.001271
36 Algorithm3 0.000932 0.001674
37 RangeVector 0.001737 0.003289
56
38 Range2 0.001852 0.002721
39 Range1 0.001714 0.002401
40 MatrixPow 0.001471 0.002456
41 MatrixMulVector 0.003418 0.002966
42 Matrix 0.001984 0.003071
43 MatrixBrackets 0.001499 0.002849
44 Matrix2 0.001545 0.003127
45 DoubleWhenSequential 0.001629 0.002651
46 DimSize 0.001747 0.002353
47 ConcatArr2 0.001444 0.003627
48 ConcatArr1 0.00156 0.002214
49 Concat3 0.00167 0.003687
50 ArraySubtraction 0.001425 0.003377
51 ArrayRemoveIndex1 0.006831 0.007187
52 ArrayReduce 0.001483 0.00226
53 ArrayRange 0.001846 0.002216
54 ArrayOperators 0.001357 0.002122
55 ArrayMult 0.001831 0.002142
56 ArrayMultiplication 0.002168 0.00285
57 ArrayIndex2 0.003867 0.005009
58 ArrayEWOpsCEval5 0.002086 0.0022
59 ArrayEWOpsCEval3 0.001619 0.002309
60 ArrayEWOpsCEval2 0.001557 0.002164
61 ArrayEWOpsCEval1 0.002038 0.002416
62 ArrayDiv 0.001476 0.002279
63 ArrayDivision 0.001671 0.002481
64 ArrayDeclaration5 0.001747 0.002857
65 ArrayDeclaration3 0.001599 0.002976
66 ArrayDeclaration2 0.002314 0.003164
67 ArrayDeclaration1 0.001601 0.002998
68 ArrayCurlyBrackets 0.001612 0.001962
69 ArrayCall 0.002993 0.003126
70 ArrayBrackets 0.001435 0.002717
71 ArrayAlgebraFunc 0.002027 0.002299
72 ArrayAddition2 0.0014 0.002495
73 ArrayAddition 0.001577 0.002162
74 ArrayAccess 0.002277 0.001788
75 Array15 0.001368 0.002331
76 Array14 0.001464 0.003175
77 Array13 0.001621 0.002115
78 Array12 0.001533 0.002288
79 Array11 0.001647 0.002135
80 Array10 0.001493 0.002073
81 Array7 0.001338 0.002123
57
82 Array4 0.001407 0.002087
83 Array2 0.001486 0.002566
84 Array1 0.001384 0.002231
85 AppendElement 0.001911 0.002455
86 VectorTest 0.001372 0.002313
87 Vectorizable4 0.000776 0.001493
88 VectorDimension 0.00105 0.001064
89 VectorBuiltin 0.000847 0.001103
90 TrigIdentity 0.000941 0.000926
91 Transpose 0.000747 0.000814
92 Tanh 0.000919 0.001522
93 Tan 0.001441 0.002182
94 Sqrt 0.000706 0.000812
95 Skew 0.001304 0.001585
96 Sinh 0.001204 0.001623
97 Sin 0.000725 0.001887
98 Sign 0.000703 0.000984
99 Scalar 0.001143 0.001301
100 Rem 0.000667 0.001051
101 NumericFunctions 0.000625 0.000997
102 Mod 0.000776 0.00089
103 MathematicalFunctions 0.001145 0.00119
104 Log10 0.001052 0.002078
105 Log 0.00066 0.001557
106 Integer2Real 0.000979 0.002087
107 Floor 0.001059 0.001394
108 Exp 0.001282 0.001528
109 EventFunctions 0.000753 0.001594
110 Div 0.00074 0.001099
111 DerConstant2 0.001247 0.002308
112 DerConstant1 0.000808 0.001011
113 Cosh 0.000734 0.001175
114 Cos 0.0008 0.000873
115 Ceil 0.000762 0.001774
116 Atan2 0.000893 0.001587
117 Atan 0.000688 0.002341
118 Asin 0.000995 0.001963
119 Acos 0.000846 0.001355
120 Abs 0.001115 0.00224
121 ScopeModification1 0.001688 0.002314
122 ScopeDeclaration1 0.001863 0.002317
123 SimpleIntegrator2 0.001126 0.001186
124 SimpleIntegrator1 0.001013 0.000851
125 ScalarizeBindings 0.000767 0.001005
58
126 ParameterDeclType 0.000856 0.001922
127 OutputDeclType 0.000704 0.000884
128 MyPointsInst1 0.000638 0.001436
129 InvalidReplaceableExtends1 0.001327 0.002327
130 Extends10 0.002555 0.002764
131 Extends1 0.001456 0.003532
132 AccessDemo 0.001901 0.003175
133 ExternalFunctionExtends 0.000518 0.001275
134 ExternalFunctionBuiltin 0.002863 0.004088
135 ExternalFunctionArray 0.001985 0.002829
136 ExternalFunction7 0.001359 0.0036
137 ExternalFunction6 0.002475 0.002124
138 ExternalFunction4 0.001578 0.003376
139 RecordAssignment 0.000681 0.000889
140 RecordPrefixes 0.000677 0.002173
141 RecordConnections 0.000746 0.002114
142 RecordConstructors2 0.000681 0.001402
143 RecordConstructors 0.000856 0.00218
144 RecordConstant3 0.000947 0.002262
145 RecordConstant1 0.012791 0.013145
146 Derived1 0.000658 0.001871
147 PartialFn12 0.000554 0.000895
148 PartialFn11 0.000469 0.001492
149 WhenSet 0.00052 0.0012
150 WhenSemantics1 0.00058 0.00148
151 WhenValidResult 0.00046 0.00244
152 WhenEquation 0.00056 0.00268
153 WaveEquationSample 0.00096 0.00555
154 VanDerPol 0.00044 0.001
155 TwoRateSampler 0.00102 0.00217
156 Sampler 0.00051 0.00117
157 LotkaVolterra 0.00045 0.00191
158 InitialReduction 0.00058 0.00104
159 IfEquation 0.00106 0.00148
160 HideVariableForEquations 0.00063 0.00084
161 HelloWorld 0.00041 0.00107
162 FiveForEquations 0.0004 0.00088
163 Equations 0.00046 0.00309
164 EquationIf4 0.00042 0.00386
165 EquationIf3 0.00056 0.00145
166 EquationIf2 0.00062 0.00093
167 EquationIf1 0.00043 0.00134
168 EquationFor7 0.00042 0.00258
169 EquationFor6 0.00047 0.00088
59
170 EquationFor3 0.00097 0.00088
171 EquationFor2 0.00086 0.00089
172 EquationFor1 0.00043 0.00087
173 EqualityEquationsCorrect 0.00052 0.00152
174 Epidemics1 0.00059 0.00127
175 DAEexample 0.00604 0.00408
176 ConditionalArrayExpression2 0.00094 0.00173
177 Circle 0.00046 0.00115
178 BouncingBall 0.00093 0.00154
179 Activate 0.00051 0.00106
C Implementation code
Java Code Generation
CodegenJava.tpl
package CodegenJava
import interface SimCodeTV;
import CodegenUtil.*;
/********************* SECTION:
SIMULATION TARGET: ROOT
TEMLPATE
**********************************
******/
template translateModel(SimCode
simCode)
"Generates Java code and Makefile for
compiling and running a simulation of a
Modelica model."
::=
match simCode
case SIMCODE(modelInfo=modelInfo as
MODELINFO(__)) then
let()= textFile(simulationFile(simCode),
'<%fileNamePrefix%>.java')
"" //empty result for true case
//this top-level template always returns
an empty result
//since generated texts are written to files
directly
end translateModel;
/************************ SECTION:
SIMULATION TARGET, Java FILE
SPECIFIC TEMPLATES
************************/
template simulationFile(SimCode
simCode)
"Generates code for main Java file for
simulation target."
::=
match simCode
case SIMCODE(modelInfo =
MODELINFO(__)) then
<<
<%simulationFileHeader(simCode)%>
<%modelClassName(simCode)%>
<%addGlobalInitialization(modelInfo,
simCode)%>
<%modelClassConstructor(simCode)%>
<%functionInput(modelInfo,
simCode)%>
<%functionOutput(modelInfo,
simCode)%>
<%functionBoundParameters(parameterEq
uations, simCode)%>
<%functionODE(odeEquations,
simCode)%>
<%functionDAE(allEquations,
whenClauses, relations, simCode)%>
<%functions(modelInfo.functions,
recordDecls, simCode)%>
<%mainFunction(simCode)%>
>>
60
end simulationFile;
/************************ SECTION:
SIMULATION TARGET, JAVA FILE
SPECIFIC FUNCTION TEMPLATES
************************/
template simulationFileHeader(SimCode
simCode)
"Generates header part of simulation file."
::=
match simCode
case
SIMCODE(modelInfo=MODELINFO(__),
extObjInfo=EXTOBJINFO(__)) then
<<
package CodegenJava; // solver package
name
import java.io.IOException;
import java.math.*;
import java.lang.Thread.State;
import java.util.Vector;
>>
end simulationFileHeader;
template modelClassName(SimCode
simCode)
"Generates model class name of
simulation file."
::=
match simCode
case
SIMCODE(modelInfo=MODELINFO(varI
nfo = vi as VARINFO(__)),
extObjInfo=EXTOBJINFO(__)) then
let noOfstates = if vi.numAlgVars then
vi.numAlgVars else vi.numStateVars
<<
// Simulation code for
<%dotPath(modelInfo.name)%> generated
by the OpenModelica Compiler
<%getVersionNr()%>.
@SuppressWarnings("unused")
public class
<%dotPath(modelInfo.name)%> extends
SuperModel // name of the given model
{
static int n= <%noOfstates%>; // n
--> number of states
static String filename =
"<%dotPath(modelInfo.name)%>_result.tx
t"; // Simulation output file
public static SimData localData =
new SimData(n, 0, 0); // Initializing a Data
Object
>>
end modelClassName;
// SECTION: GENERAL TEMPLATES,
PATHS
template dotPath(Path path)
"Generates paths with components
separated by dots."
::=
match path
case QUALIFIED(__) then
'<%name%>.<%dotPath(path)%>'
case IDENT(__) then name
case FULLYQUALIFIED(__) then
dotPath(path)
end dotPath;
template
addGlobalInitialization(ModelInfo
modelInfo, SimCode simCode)
"Generates global data in simulation file."
::=
match modelInfo
case MODELINFO(varInfo= vi as
VARINFO(numAlgVars=numAlgVars,
numStringAlgVars=numStringAlgVars ),
vars=SIMVARS(__)) then
<<
/* Algebraic Vars */
<%vars.algVars |> var =>
globalDataVarDefine(var, "realVars",
numAlgVars, simCode)
;separator="\n"%>
/* Algebraic Parameter */
<%vars.paramVars |> var =>
globalDataParDefine(var,
"realParameter", simCode)
;separator="\n"%>
/* External Objects */
<%vars.extObjVars |> var =>
61
globalDataParDefine(var, "extObjs",
simCode)
;separator="\n"%>
/* Algebraic Integer Vars */
<%vars.intAlgVars |> var =>
globalDataDefineInt(var,
"integerVars",numAlgVars, simCode)
;separator="\n"%>
/* Algebraic Integer Parameter */
<%vars.intParamVars |> var =>
globalDataDefineInt(var,
"integerParameter",numAlgVars,
simCode)
;separator="\n"%>
/* Algebraic String Variables */
<%vars.stringAlgVars |> var =>
globalDataVarDefine(var,
"stringVars",numStringAlgVars, simCode)
;separator="\n"%>
/* Algebraic String Parameter */
<%vars.stringParamVars |> var =>
globalDataParDefine(var,
"stringParameter", simCode)
;separator="\n"%>
>>
end addGlobalInitialization;
template globalDataVarDefine(SimVar
simVar, String arrayName, Integer offset,
SimCode simCode)
"Generates a define statement for a
variable in the global data section."
//if varsLst then
//we need all of them to initialize also
empty arrays
::=
match simVar
case SIMVAR(__) then
<<
<%\t%> <%VariableType (type_)%>
<%qualifiedNamePart(name)%>[] = new
<%VariableType (type_)%>
[<%offset%>]; /* <%cref(name)%> */
>>
end match
end globalDataVarDefine;
template
qualifiedNamePart(ComponentRef cr)
"Generates Qualified name of a variable .
"
::=
match cr
case CREF_IDENT(__) then
<<
<%ident%>
>>
else "CREF_NOT_IDENT_OR_QUAL"
end qualifiedNamePart;
template globalDataParDefine(SimVar
simVar, String arrayName, SimCode
simCode)
"Generates a define statement for a
parameter."
::=
match simVar
case SIMVAR(__) then
<<
<%\t%><%VariableType (type_)%>
<%cref(name)%>
<%initialEquation(simVar, simCode)%>;
/* <%cref(name)%> */
>>
end match
end globalDataParDefine;
template globalDataDefineInt(SimVar
simVar, String arrayName, Integer offset,
SimCode simCode)
"Generates a define statement for a
variable in the global data section."
::=
match simVar
case SIMVAR(__) then
<<
<%\t%>int <%cref(name)%>
<%initialEquation(simVar, simCode)%>;
/* <%cref(name)%> */
>>
end match
end globalDataDefineInt;
template initVals(Option<DAE.Exp>
initialValue)
::=
match initialValue
case SOME(v) then
62
<<
initVal(v)
else " "
>>
end initVals;
template initVal(Exp initialValue)
::=
match initialValue
case ICONST(__) then integer
case RCONST(__) then real
case SCONST(__) then
'<%Util.escapeModelicaStringToCString(s
tring)%>'
case BCONST(__) then if bool then
"true" else "false"
case ENUM_LITERAL(__) then
'<%index%>
/*ENUM:<%dotPath(name)%>*/'
else "error(sourceInfo(), 'initial value of
unknown type:
<%printExpStr(initialValue)%>')"
end initVal;
template VariableType(DAE.Type type_)
"Generates Java code for ScalarVariable
Type file."
::=
match type_
case T_INTEGER(__) then 'double'
/*need to cast int to double to support
SimData*/
case T_REAL(__) then 'double'
case T_BOOL(__) then 'boolean'
case T_STRING(__) then 'String'
case T_ENUMERATION(__) then
'double'
else 'UNKOWN_TYPE'
end VariableType;
template initialEquation(SimVar var,
SimCode simCode)
"Generates Java code for Inititial
Equations."
::=
match var
case SIMVAR(__) then
let identName = '<%cref(name)%>'
match initialValue
case SOME(exp) then
let &varDecls = buffer "" /*BUFD*/
let &preExp = buffer "" /*BUFD*/
<<
= <%daeExp(exp, contextOther,
&preExp, simCode)%>
>>
else " "
end initialEquation;
/************************ Class
constructor for the model
*****************/
template modelClassConstructor(SimCode
simCode)
::=
match simCode
case SIMCODE(modelInfo =
MODELINFO(__)) then
<<
public <%dotPath(modelInfo.name)%>() //
constructor
{
<%assignGlobalData(modelInfo,
simCode)%>
}
>>
end modelClassConstructor;
template assignGlobalData(ModelInfo
modelInfo, SimCode simCode)
"Generates global data in simulation file."
::=
match modelInfo
case
MODELINFO(varInfo=VARINFO(numSt
ateVars=numStateVars, numAlgVars=
numAlgVars), vars=SIMVARS(__)) then
<<
/* States */
/* States Initialization Ordinary
equations */
<%VarsAssign("state", vars.stateVars,
simCode)
;separator="\n"%>
63
/* States Initialization algebraic
equations */
<%VarsAssign("state", vars.algVars,
simCode)
;separator="\n"%>
>>
end assignGlobalData;
template VarsAssign(String arrName,
list<SimVar> varsLst, SimCode simCode)
::=
<<
<%varsLst |> sv as SIMVAR(__) =>
<<
localData.x/*<%arrName%>*/.add
(<%sv.index%>,<%initialEquationStates(s
v, simCode)%>); /* <%cref(name)%> */
>>
;separator="\n"
%>
>>
end VarsAssign;
template initialEquationStates(SimVar var,
SimCode simCode)
"Generates Java code for Inititial
Equations."
::=
match var
case SIMVAR(__) then
let identName = '<%cref(name)%>'
match initialValue
case SOME(exp) then
let &varDecls = buffer "" /*BUFD*/
let &preExp = buffer "" /*BUFD*/
<<
<%daeExp(exp, contextOther,
&preExp, simCode)%>
>>
else "0.0"
end initialEquationStates;
/******************************
Template for Functions starts
****************************/
template functionInput(ModelInfo
modelInfo, SimCode simCode) ::=
match modelInfo
case MODELINFO(varInfo =
VARINFO(__), vars = SIMVARS(__))
then
<<
public void InputFun()
{
<%vars.inputVars |> SIMVAR(__)
hasindex i0 =>
<<
<%cref(name)%> =
inputVars[<%i0%>];
>> ;separator="\n"%>
}
>>
end functionInput;
template functionOutput(ModelInfo
modelInfo, SimCode simCode) ::=
match modelInfo
case MODELINFO(varInfo =
VARINFO(__), vars = SIMVARS(__))
then
<<
public void OutputFun()
{
<%vars.outputVars |>
SIMVAR(__) hasindex i0 =>
<<
outputVars[<%i0%>] =
<%cref(name)%>;
>> ;separator="\n"%>
}
>>
end functionOutput;
template
functionBoundParameters(list<SimEqSyst
em> parameterEquations, SimCode
simCode)
::=
let &tmp = buffer ""
<<
public void BoundParameters()
{
<% parameterEquations
64
|> saeq as SES_SIMPLE_ASSIGN(__)
=> equation_(saeq, contextOther,
simCode, &tmp) ;separator="\n"%>
<% parameterEquations
|> eq as SES_ALGORITHM(__) =>
equation_(eq, contextOther, simCode,
&tmp) ;separator="\n"%>
}
>>
end functionBoundParameters;
template
functionODE(list<list<SimEqSystem>>
stateContEquations, SimCode simCode)
::=
match simCode
case SIMCODE(modelInfo =
MODELINFO(varInfo=VARINFO(numSt
ateVars=numStateVars),
vars=SIMVARS(__))) then
match modelInfo
case
MODELINFO(varInfo=VARINFO(numSt
ateVars=numStateVars),
vars=SIMVARS(__)) then
let &tmp = buffer ""
<<
public void functionODE()
{
<%StatesAssign("states",
vars.stateVars, simCode)
;separator="\n"%>
<%StatesAssign("states",
vars.algVars, simCode)
;separator="\n"%>
<%stateContEquations |> eqs =>
(eqs |> it => equation_(it, contextOther,
simCode, &tmp) ;separator="\n")
;separator="\n"%>
BoundParameters();
}
>>
end functionODE;
template
functionDAE(list<SimEqSystem>
allEquationsPlusWhen,
list<SimWhenClause> whenClauses,
list<ZeroCrossing> relations,
SimCode simCode)
"Generates function in simulation file."
::=
match simCode
case SIMCODE(modelInfo =
MODELINFO(varInfo=VARINFO(numSt
ateVars=numStateVars),
vars=SIMVARS(__))) then
match modelInfo
case
MODELINFO(varInfo=VARINFO(numSt
ateVars=numStateVars),
vars=SIMVARS(__)) then
let &varDecls = buffer "" /*BUFD*/
let &tmp = buffer ""
<<
public void functionDAE()
{
<%StatesAssign("states",
vars.stateVars, simCode)
;separator="\n"%>
<%StatesAssign("states",
vars.algVars, simCode) ;separator="\n"%>
<%allEquationsPlusWhen |> eq =>
equation_(eq, contextSimulationDiscrete,
simCode, &tmp)
;separator="\n"%>
<%whenClauses |> when hasindex
i0 => genreinits(when, relations,
contextOther, &varDecls, simCode)
;separator="\n"
%>
}
>>
end functionDAE;
template StatesAssign(String arrName,
list<SimVar> varsLst, SimCode simCode)
"Helper template for assigning states in
functionODE and functionDAE"
::=
<<
<%varsLst |> sv as SIMVAR(__) =>
<<
<%VariableType (type_)%>
<%cref(name)%> =
localData.getState().elementAt(<%sv.inde
x%>);
>>
65
;separator="\n"
%>
>>
end StatesAssign;
template mainFunction(SimCode
simCode)
::=
match simCode
case SIMCODE(modelInfo =
MODELINFO(__)) then
<<
public static void main(String[] args)
throws IOException
{
<%dotPath(modelInfo.name)%>
temp = new
<%dotPath(modelInfo.name)%>();
temp.functionODE();
/* Invoke the Solver with correct
parameters */
EulerSolver.main(localData.stepsiz
e, localData, temp, filename);
}
}
>>
end mainFunction;
/********************* SECTION:
TEMPLATES WHICH SUPPORT Java
FILE SPECIFIC FUNCTION
TEMPLATES
**********************************/
template functions(list<Function>
functions, list<RecordDeclaration>
recordDecls, SimCode simCode)
"Generates the body for a function."
::=
<<
<%functions |> fn =>
functionJava(fn, recordDecls, simCode)
;separator="\n"%>
>>
end functions;
template functionJava(Function fn,
list<RecordDeclaration> recordDecls,
SimCode simCode)
"Generates the body for a function."
::=
match fn
case fn as FUNCTION(__) then
regularFunction(fn, simCode)
case fn as EXTERNAL_FUNCTION(__)
then externalFunction(fn, simCode)
case fn as
RECORD_CONSTRUCTOR(__) then
recordsJava(recordDecls)
end functionJava;
template regularFunction(Function fn,
SimCode simCode)
"Generates JAVA code for a Modelica
function."
::=
match fn
case FUNCTION(__) then
let fname = underscorePath(name)
let &varDecls = buffer "" /*BUFD*/
let extFunCall = (body |> stmt =>
funStatement(stmt, simCode)
;separator="\n")
<<
public <%outVars |> var =>
funArgDefinitiontype(var)%>
<%fname%>(<%functionArguments |> var
=> funArgDefinitionarg(var) ;separator=" ,
"%>)
{
<%outVars |> var =>
funOutputVariable(var) ;separator="\n"%>
<%functionArguments |> var =>
funArgDefinition(var) ;separator="\n"%>
return <%extFunCall%>
}
>>
end regularFunction;
template externalFunction(Function fn,
SimCode simCode)
"Generates the body for an external
function (just a wrapper)."
::=
match fn
66
case EXTERNAL_FUNCTION(__) then
let &preExp = buffer "" /*BUFD*/
let fname = underscorePath(name)
let &varDecls = buffer "" /*BUFD*/
let callPart = extFunCall(fn, &preExp
/*BUFC*/, simCode)
<<
public <%outVars |> var =>
funArgDefinitiontype(var)%>
<%fname%>(<%funArgs |> var =>
funArgDefinitionarg(var) ;separator=" ,
"%>)
{
<%outVars |> var =>
funOutputVariable(var) ;separator="\n"%>
<%funArgs |> var =>
funArgDefinition(var) ;separator="\n"%>
<%callPart%>
}
>>
end externalFunction;
template funStatement(Statement stmt,
SimCode simCode)
"Generates function statements."
::=
match stmt
case ALGORITHM(__) then
(statementLst |> stmt =>
algStatement(stmt, contextFunction,
simCode) ;separator="\n")
else "NOT IMPLEMENTED FUN
STATEMENT"
end funStatement;
template funArgDefinitiontype(Variable
var)
::=
match var
case VARIABLE(__) then
<<
<%VariableType(ty)%>
>>
end funArgDefinitiontype;
template funArgDefinitionarg(Variable
var)
::=
match var
case
VARIABLE(ty=T_COMPLEX(complexCl
assType=RECORD(__))) then
<<
<%varType(var)%>
arg_<%contextCref(name,contextFunction
)%>
>>
case VARIABLE(__) then
<<
<%varType(var)%>
arg_<%contextCref(name,contextFunction
)%>
>>
end funArgDefinitionarg;
template funArgDefinition(Variable var)
::=
match var
case
VARIABLE(ty=T_COMPLEX(complexCl
assType=RECORD(__))) then
<<
<%varType(var)%>
<%contextCref(name,contextFunction)%>
=
arg_<%contextCref(name,contextFunction
)%>;
>>
case VARIABLE(__) then
<<
<%varType(var)%>
<%contextCref(name,contextFunction)%>
=
arg_<%contextCref(name,contextFunction
)%>;
>>
end funArgDefinition;
template funOutputVariable(Variable var)
::=
match var
case
VARIABLE(ty=T_COMPLEX(complexCl
assType=RECORD(__))) then
<<
<%VariableType(ty)%>
<%contextCref(name,contextFunction)%>;
>>
67
case VARIABLE(__) then
<<
<%VariableType(ty)%>
<%contextCref(name,contextFunction)%>;
>>
end funOutputVariable;
template extFunCall(Function fun, Text
&preExp /*BUFP*/, SimCode simCode)
"Generates the call to an external
function."
::=
match fun
case EXTERNAL_FUNCTION(__) then
match language
case "C" then extFunCallC(fun, &preExp
/*BUFC*/, simCode)
case "FORTRAN 77" then
extFunCallF77(fun, &preExp /*BUFC*/,
simCode)
end extFunCall;
template extFunCallC(Function fun, Text
&preExp /*BUFP*/, SimCode simCode)
"Generates the call to an external C
function."
::=
match fun
case EXTERNAL_FUNCTION(__) then
let args = (extArgs |> arg =>
extArgC(arg, &preExp /*BUFC*/,
simCode)
;separator=",")
let returnAssign = match extReturn case
SIMEXTARG(cref=c) then
'<%extVarName(c)%> = '
else
""
<<
return <%returnAssign%>
<%extName%>(<%args%>);
>>
end extFunCallC;
template extFunCallF77(Function fun,
Text &preExp /*BUFP*/, SimCode
simCode)
"Generates the call to an external Fortran
77 function."
::=
match fun
case EXTERNAL_FUNCTION(__) then
let args = (extArgs |> arg =>
extArgF77(arg, &preExp, simCode)
;separator=", ")
let returnAssign = match extReturn case
SIMEXTARG(cref=c) then
'<%extVarName(c)%> = '
else
""
<<
return <%returnAssign%>
<%extName%>(<%args%>);
>>
end extFunCallF77;
template extArgC(SimExtArg extArg, Text
&preExp /*BUFP*/, SimCode simCode)
"Helper to extFunCall."
::=
match extArg
case SIMEXTARG(cref=c,
outputIndex=oi, isArray=true, type_=t)
then
<<
<%extVarName(c)%>
>>
case SIMEXTARG(cref=c, isInput=ii,
outputIndex=0, type_=t) then
<<
<%extVarName(c)%>
>>
case SIMEXTARG(cref=c, isInput=ii,
outputIndex=oi, type_=t) then
<<
<%extVarName(c)%>
>>
case SIMEXTARGEXP(__) then
daeExternalExp(exp, contextFunction,
&preExp /*BUFC*/, simCode) +'test
daeexternal'
case SIMEXTARGSIZE(cref=c) then
let name = extVarName(c)
let dim = daeExp(exp, contextFunction,
&preExp /*BUFC*/, simCode)
<<
<%name%> = <%dim%>
>>
68
end extArgC;
template daeExternalExp(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Like daeExp, "
::=
match typeof(exp)
case T_ARRAY(__) then // Array-
expressions
<<
<%daeExp(exp, context, &preExp,
simCode)%>
>>
end daeExternalExp;
template extArgF77(SimExtArg extArg,
Text &preExp, SimCode simCode)
::=
match extArg
case SIMEXTARG(cref=c, isArray=true,
type_=t) then
<<
<%extVarName(c)%>
>>
case SIMEXTARG(cref=c,
outputIndex=oi, type_=T_INTEGER(__))
then
<<
<%extVarName(c)%>
>>
case SIMEXTARG(cref=c,
outputIndex=oi, type_ = T_STRING(__))
then
<<
<%extVarName(c)%>
>>
case SIMEXTARG(cref=c,
outputIndex=oi, type_=t) then
<<
<%extVarName(c)%>
>>
case SIMEXTARGEXP(exp=exp, type_
= T_STRING(__)) then
let texp = daeExp(exp, contextFunction,
&preExp /*BUFC*/, simCode)
<<
<%texp%>
>>
case SIMEXTARGSIZE(cref=c) then
let dim = daeExp(exp, contextFunction,
&preExp, simCode)
let name = extVarName(c)
<<
<%name%> = <%dim%>
>>
end extArgF77;
template extVarName(ComponentRef cr)
::=
<<
<%cref(cr)%>
>>
end extVarName;
/*********************SECTION:
GENERATE ALL RECORDS ( RECORD
LIST) IN SIMULATION
FILE************************/
template
recordsJava(list<RecordDeclaration>
recordDecls)
"Generates Java code for all records."
::=
<<
<%recordDecls |> rd =>
recordDeclaration(rd) ;separator="\n"%>
>>
end recordsJava;
template
recordDeclaration(RecordDeclaration
recDecl)
"Generates Java structs for a record
declaration."
::=
match recDecl
case RECORD_DECL_FULL(__) then
<<
public void <%name%>()
{
<%variables |> var =>
recordBody(var) ;separator="\n"%>
return;
}
>>
case RECORD_DECL_DEF(__) then
69
<<
Record Declaration definition is not yet
implemented
>>
end recordDeclaration;
template recordBody(Variable var)
::=
match var
case VARIABLE(__) then
<<
<%varType(var)%>
<%crefStr(var.name)%>;
>>
case FUNCTION_PTR(__) then
'modelica_fnptr <%name%>'
end recordBody;
/*****************************SECT
ION: GENERATE All EQUATIONS IN
SIMULATION
FILE******************************
***********/
template equationIndex(SimEqSystem eq)
"Generates an equation."
::=
match eq
case SES_RESIDUAL(__) then
'<%index%>'
case SES_SIMPLE_ASSIGN(__) then
'<%index%>'
case SES_ARRAY_CALL_ASSIGN(__)
then '<%index%>'
case SES_ALGORITHM(__) then
'<%index%>'
case SES_LINEAR(__) then
'<%index%>'
case SES_NONLINEAR(__) then
'<%index%>'
case SES_MIXED(__) then '<%index%>'
case SES_WHEN(__) then '<%index%>'
end equationIndex;
template equation_(SimEqSystem eq,
Context context, SimCode simCode, Text
&eqs)
"Generates an equation.
This template should not be used for a
SES_RESIDUAL.
Residual equations are handled
differently."
::=
match simCode
case SIMCODE(modelInfo =
MODELINFO(__)) then
let &varDecls = buffer "" /*BUFD*/
match eq
case eq as
SES_SIMPLE_ASSIGN(__) then
let &preExp = buffer "" /*BUFD*/
let expPart =daeExp(exp, context,
&preExp, simCode) //was daeExpToReal
let codetxt =
<<
localData.xdot/*stateDerivative*/.add(<%c
refindex(cref,simCode)%>,<%expPart%>)
;
>>
match exp
case RELATION(__) then
<<
//<%expPart%> "Condition
Relation"
>>
case ARRAY(__) then
<<
ty[] temp = new ty[];
{
temp[<%crefindex(cref,simCode)%
>]=<%expPart%>; /*array*/
}
>>
else
codetxt
case eq as
SES_ARRAY_CALL_ASSIGN(__)
then equationArrayCallAssign(eq,
context, &varDecls /*BUFP*/, simCode)
case eq as SES_ALGORITHM(__)
then
70
(statements |> stmt =>
algStatement(stmt, context, simCode)
;separator="\n")
case eq as SES_LINEAR(__) then
" "
case eq as SES_NONLINEAR(__)
then " "
case eq as SES_MIXED(__) then "
"
case eq as SES_WHEN(__)
then equationWhen(eq, context,
&varDecls /*BUFD*/, simCode)
else "NOT IMPLEMENTED
EQUATION"
end equation_;
template
equationArrayCallAssign(SimEqSystem
eq, Context context, Text &varDecls
/*BUFP*/, SimCode simCode)
"Generates a when equation."
::=
<<
<%match eq
case eq as
SES_ARRAY_CALL_ASSIGN(__) then
let &preExp = buffer "" /*BUFD*/
let expPart = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
match expTypeFromExpShort(eq.exp)
case "boolean" then
<<
<%cref(eq.componentRef)%> =
<%expPart%>
>>
case "integer" then
<<
<%cref(eq.componentRef)%> =
<%expPart%>
>>
case "double" then
<<
<%cref(eq.componentRef)%> =
<%expPart%>
>>
case "real" then
<<
<%cref(eq.componentRef)%> =
<%expPart%>
>>
else "error:No runtime support for this
sort of array call"
%>
>>
end equationArrayCallAssign;
template equationWhen(SimEqSystem eq,
Context context, Text &varDecls
/*BUFP*/, SimCode simCode)
"Generates a when equation."
::=
match eq
case SES_WHEN(__) then
let &preExp = buffer ""
let helpIf = (conditions |> cr =>
'<%cref(cr)%>'
;separator=" || ")
let rightExp = daeExp(right, context,
&preExp, simCode)
let elseWhenConds = match elseWhen
case SOME(ew) then
equationElseWhen(ew, context, simCode)
if initialCall then
<<
if(Initial<%helpIf%>) {
<%preExp%>
<%cref(left)%> = <%rightExp%>;
}
<%elseWhenConds%>
>>
else
<<
if( ! Initial) {
if(<%helpIf%>) {
<%preExp%>
<%cref(left)%> = <%rightExp%>;
}
<%elseWhenConds%>
}
>>
end equationWhen;
template equationElseWhen(SimEqSystem
eq, Context context, SimCode simCode)
"Generates a else when equation."
71
::=
match eq
case SES_WHEN(left=left,
right=right,conditions=conditions,elseWhe
n = NONE()) then
let helpIf = (conditions |> cr =>
'<%cref(cr)%>'
;separator=" || ")
let &preExp2 = buffer "" /*BUFD*/
let exp = daeExp(right, context,
&preExp2 /*BUFC*/, simCode)
<<
else if (<%helpIf%>) {
<%preExp2%>
<%cref(left)%> = <%exp%>;
}
>>
case SES_WHEN(left=left,
right=right,conditions=conditions,elseWhe
n = SOME(elseWhenEq)) then
let helpIf = (conditions |> cr =>
'<%cref(cr)%>'
;separator=" || ")
let &preExp2 = buffer "" /*BUFD*/
let exp = daeExp(right, context,
&preExp2 /*BUFC*/, simCode)
let elseWhen =
equationElseWhen(elseWhenEq,context,si
mCode)
<<
else if (<%helpIf%>) {
<%preExp2%>
<%cref(left)%> = <%exp%>;
}
<%elseWhen%>
>>
end equationElseWhen;
template relationsTpl(list<ZeroCrossing>
relations, Context context, SimCode
simCode)
"Generates code for zero crossings."
::=
(relations |> ZERO_CROSSING(__)
hasindex i0 =>
relationTpl(i0, relation_, context,
simCode)
;separator="\n";empty)
end relationsTpl;
template relationTpl(Integer index1, Exp
relationExp, Context context, SimCode
simCode)
"Generates code for a zero crossing."
::=
match relationExp
case RELATION(__) then
let &preExp = buffer ""
let e1 = daeExp(exp1, context, &preExp,
simCode)
let e2 = daeExp(exp2, context, &preExp,
simCode)
<<
<%ExpressionDump.printExpStr(relationE
xp)%>
>>
end relationTpl;
template genreinits(SimWhenClause
whenClauses, list<ZeroCrossing>
relations, Context context, Text
&varDecls, SimCode simCode)
"Generates reinit statemeant"
::=
match whenClauses
case SIM_WHEN_CLAUSE(__)then
let CondExp = relationsTpl(relations,
contextOther, simCode)
if reinits then
<<
if (<%CondExp%>) {
<%functionWhenReinitStatementThen(rei
nits, &varDecls /*BUFP*/, simCode)%>
}
>>
end genreinits;
template
functionWhenReinitStatementThen(list<W
henOperator> reinits, Text &varDecls
/*BUFP*/, SimCode simCode)
"Generates re-init statement for when
equation."
::=
reinits |> reinit =>
match reinit
72
case REINIT(__) then
let &preExp = buffer "" /*BUFD*/
let val = daeExp(value,
contextSimulationDiscrete, &preExp
/*BUFC*/, simCode)
<<
<%preExp%>
<%cref(stateVar)%> = <%val%>;
>>
case TERMINATE(__) then
let &preExp = buffer ""
let msgVar = daeExp(message,
contextSimulationDiscrete, &preExp,
simCode)
<<
<%preExp%>
MODELICA_TERMINATE(<%msgVar%
>);
>>
case
ASSERT(source=SOURCE(info=info))
then
assertCommon(condition, message,
contextSimulationDiscrete, simCode, info)
;separator="\n"
end functionWhenReinitStatementThen;
/***************************SECTIO
N: GENERATE All DAE Expression IN
SIMULATION
FILE******************************/
template daeExp(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for an expression."
::=
match exp
case e as ICONST(__) then integer
/* need to cast int into real to support
SimData */
case e as RCONST(__) then real
case e as SCONST(__) then
daeExpSconst(string, context, &preExp
/*BUFC*/, simCode)
case e as BCONST(__) then if bool
then "true" else "false"
case e as ENUM_LITERAL(__) then
index
case e as CREF(__) then
daeExpCrefRhs(e, context, &preExp,
simCode)
case e as BINARY(__) then
daeExpBinary(e, context, &preExp
/*BUFC*/, simCode)
case e as UNARY(__) then
daeExpUnary(e, context, &preExp
/*BUFC*/, simCode)
case e as LBINARY(__) then
daeExpLbinary(e, context, &preExp
/*BUFC*/, simCode)
case e as LUNARY(__) then
daeExpLunary(e, context, &preExp
/*BUFC*/, simCode)
case e as RELATION(__) then
daeExpRelation(e, context, &preExp
/*BUFC*/, simCode)
case e as CALL(__) then
daeExpCall(e, context, &preExp
/*BUFC*/, simCode)
case e as ARRAY(__) then
daeExpArray(e, context, &preExp
/*BUFC*/, simCode)
case e as IFEXP(__) then
daeExpIf(e, context, &preExp /*BUFC*/,
simCode)
case e as MATRIX(__) then
daeExpMatrix(e, context, &preExp
/*BUFC*/, simCode)
case e as RANGE(__) then
daeExpRange(e, context, &preExp
/*BUFC*/, simCode)
case e as CAST(__) then
daeExpCast(e, context, &preExp
/*BUFC*/, simCode)
case e as ASUB(__) then
daeExpAsub(e, context, &preExp
/*BUFC*/, simCode)
case e as TSUB(__) then
'<%daeExp(exp, context, &preExp,
simCode)%>'
case e as SIZE(__) then
daeExpSize(e, context, &preExp
/*BUFC*/, simCode)
73
case e as BOX(__) then
daeExpBox(e, context, &preExp
/*BUFC*/, simCode)
case e as UNBOX(__) then
daeExpUnbox(e, context, &preExp
/*BUFC*/, simCode)
case e as SHARED_LITERAL(__) then
'_OMC_LIT<%index%>'
// META_TUPLE
// META_OPTION
// METARECORDCALL
else error(sourceInfo(), 'Unknown
expression:
<%ExpressionDump.printExpStr(exp)%>')
end daeExp;
template daeExpSconst(String string,
Context context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a string constant."
::=
<<
"<%Util.escapeModelicaStringToCString(
string)%>"
>>
end daeExpSconst;
template daeExpCrefRhs(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a component
reference."
::=
match exp
/*case CREF(componentRef=cr,
ty=T_ENUMERATION(__)) then
getEnumIndexfromCref(cr)*/
case cref as CREF(componentRef=cr,
ty=ty) then
let cast = match ty case
T_INTEGER(__) then "(int)" //else ""
'<%cast%><%cref(cr)%>'
end daeExpCrefRhs;
template daeExpBinary(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a binary expression."
::=
match exp
case BINARY(__) then
let e1 = daeExp(exp1, context, &preExp
/*BUFC*/, simCode)
let e2 = daeExp(exp2, context, &preExp
/*BUFC*/, simCode)
match operator
case ADD(__) then '(<%e1%> +
<%e2%>)'
case SUB(__) then '(<%e1%> -
<%e2%>)'
case MUL(__) then '(<%e1%> *
<%e2%>)'
case DIV(__) then '(<%e1%> / <%e2%>)'
case POW(__) then 'Math.pow(<%e1%>,
<%e2%>)'
case UMINUS(__) then
daeExpUnary(exp, context, &preExp
/*BUFC*/, simCode)
else "daeExpBinary:ERR"
end daeExpBinary;
template daeExpUnary(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a unary expression."
::=
match exp
case UNARY(__) then
let e = daeExp(exp, context, &preExp
/*BUFC*/, simCode)
match operator
case UMINUS(__) then '(-<%e%>)'
case NOT(__) then '(!<%e%>)'
case UMINUS_ARR(__) then
"UMINUS_ARR_NOT_IMPLEMENTED
"
else "daeExpUnary:ERR"
end daeExpUnary;
template daeExpLbinary(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a logical binary
expression."
::=
match exp
74
case LBINARY(__) then
let e1 = daeExp(exp1, context, &preExp
/*BUFC*/, simCode)
let e2 = daeExp(exp2, context, &preExp
/*BUFC*/, simCode)
match operator
case AND(__) then '(<%e1%> &&
<%e2%>)'
case OR(__) then '(<%e1%> || <%e2%>)'
else "daeExpLbinary:ERR"
end daeExpLbinary;
template daeExpLunary(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a logical unary
expression."
::=
match exp
case LUNARY(__) then
let e = daeExp(exp, context, &preExp
/*BUFC*/, simCode)
match operator
case NOT(__) then '(!<%e%>)'
end daeExpLunary;
template daeExpRelation(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a relation expression."
::=
match exp
case rel as RELATION(__) then /* to get
output BouncingBall --mano */
let e1 = daeExp(rel.exp1, context,
&preExp /*BUFC*/, simCode)
let e2 = daeExp(rel.exp2, context,
&preExp /*BUFC*/, simCode)
match rel.operator
case LESS(ty = T_BOOL(__)) then
'(!<%e1%> && <%e2%>)'
case LESS(ty = T_STRING(__)) then
'(<%e1%>.compareTo(<%e2%>) < 0)'
case LESS(ty = T_INTEGER(__))
then '(<%e1%> < <%e2%>)'
case LESS(ty = T_REAL(__)) then
'(<%e1%> < <%e2%>)'
case GREATER(ty = T_BOOL(__))
then '(<%e1%> && !<%e2%>)'
case GREATER(ty = T_STRING(__))
then '(<%e1%>.compareTo(<%e2%>) >
0)'
case GREATER(ty = T_INTEGER(__))
then '(<%e1%> > <%e2%>)'
case GREATER(ty = T_REAL(__))
then '(<%e1%> > <%e2%>)'
case LESSEQ(ty = T_BOOL(__))
then '(!<%e1%> || <%e2%>)'
case LESSEQ(ty = T_STRING(__))
then '(<%e1%>.compareTo(<%e2%>) <=
0)'
case LESSEQ(ty = T_INTEGER(__))
then '(<%e1%> <= <%e2%>)'
case LESSEQ(ty = T_REAL(__))
then '(<%e1%> <= <%e2%>)'
case GREATEREQ(ty = T_BOOL(__))
then '(<%e1%> || !<%e2%>)'
case GREATEREQ(ty =
T_STRING(__)) then
'(<%e1%>.compareTo(<%e2%>) >= 0)'
case GREATEREQ(ty =
T_INTEGER(__))then '(<%e1%> >=
<%e2%>)'
case GREATEREQ(ty = T_REAL(__))
then '(<%e1%> >= <%e2%>)'
case EQUAL(ty = T_BOOL(__))
then '((!<%e1%> && !<%e2%>) ||
(<%e1%> && <%e2%>))'
case EQUAL(ty = T_STRING(__))
then '(<%e1%>.equals(<%e2%>))'
case EQUAL(ty = T_INTEGER(__))
then '(<%e1%> == <%e2%>)'
case EQUAL(ty = T_REAL(__))
then '(<%e1%> == <%e2%>)'
case EQUAL(ty =
T_ENUMERATION(__))then '(<%e1%>
== <%e2%>)'
case NEQUAL(ty = T_BOOL(__))
then '((!<%e1%> && <%e2%>) ||
(<%e1%> && !<%e2%>))'
case NEQUAL(ty = T_STRING(__))
then '(!<%e1%>.equals(<%e2%>))'
case NEQUAL(ty = T_INTEGER(__))
then '(<%e1%> != <%e2%>)'
case NEQUAL(ty = T_REAL(__))
then '(<%e1%> != <%e2%>)'
75
else
let simRel = daeExpRelationSim(rel,
context, &preExp /*BUFC*/, simCode)
if simRel then
simRel
else "daeExpRelation:ERR"
end daeExpRelation;
template daeExpRelationSim(Exp exp,
Context context, Text &preExp /*BUFP*/,
SimCode simCode)
"Helper to daeExpRelation."
::=
match exp
case rel as RELATION(__) then
match context
case SIMULATION(genDiscrete=false)
then
match rel.optionExpisASUB
case NONE() then
let &varDecls = buffer "" /*BUFD*/
let e1 = daeExp(rel.exp1, context,
&preExp /*BUFC*/, simCode)
let e2 = daeExp(rel.exp2, context,
&preExp /*BUFC*/, simCode)
let res =
tempDecl("modelica_boolean", &varDecls
/*BUFC*/)
match rel.operator
case LESS(__) then
let &preExp +=
<<
(<%res%> < <%e2%>)
>>
res
case LESSEQ(__) then
let &preExp +=
<<
(<%res%> <= <%e2%>)
>>
res
case GREATER(__) then
let &preExp +=
<<
(<%res%> > <%e2%>)
>>
res
case GREATEREQ(__) then
let &preExp +=
<<
(<%res%> >= <%e2%>)
>>
res
end match
case SOME((exp,i,j)) then
let &varDecls = buffer "" /*BUFD*/
let e1 = daeExp(rel.exp1, context,
&preExp /*BUFC*/, simCode)
let e2 = daeExp(rel.exp2, context,
&preExp /*BUFC*/, simCode)
let iterator = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
let res =
tempDecl("modelica_boolean", &varDecls
/*BUFC*/)
match rel.operator
case LESS(__) then
let &preExp +=
<<
(<%res%> < <%e2%>)
>>
res
case LESSEQ(__) then
let &preExp +=
<<
(<%res%> <= <%e2%>)
>>
res
case GREATER(__) then
let &preExp +=
<<
(<%res%> > <%e2%>)
>>
res
case GREATEREQ(__) then
let &preExp +=
<<
(<%res%> >= <%e2%>)
>>
res
end match
end match
case SIMULATION(genDiscrete=true)
then
match rel.optionExpisASUB
case NONE() then
76
let &varDecls = buffer "" /*BUFD*/
let e1 = daeExp(rel.exp1, context,
&preExp /*BUFC*/, simCode)
let e2 = daeExp(rel.exp2, context,
&preExp /*BUFC*/, simCode)
let res =
tempDecl("modelica_boolean", &varDecls
/*BUFC*/)
match rel.operator
case LESS(__) then
let &preExp +=
<<
(<%res%> < <%e2%>)
>>
res
case LESSEQ(__) then
let &preExp +=
<<
(<%res%> <= <%e2%>)
>>
res
case GREATER(__) then
let &preExp +=
<<
(<%res%> > <%e2%>)
>>
res
case GREATEREQ(__) then
let &preExp +=
<<
(<%res%> >= <%e2%>)
>>
res
end match
case SOME((exp,i,j)) then
let &varDecls = buffer "" /*BUFD*/
let e1 = daeExp(rel.exp1, context,
&preExp /*BUFC*/, simCode)
let e2 = daeExp(rel.exp2, context,
&preExp /*BUFC*/, simCode)
let iterator = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
let res =
tempDecl("modelica_boolean", &varDecls
/*BUFC*/)
match rel.operator
case LESS(__) then
let &preExp +=
<<
(<%res%> < <%e2%>)
>>
res
case LESSEQ(__) then
let &preExp +=
<<
(<%res%> <= <%e2%>)
>>
res
case GREATER(__) then
let &preExp +=
<<
(<%res%> > <%e2%>)
>>
res
case GREATEREQ(__) then
let &preExp +=
<<
(<%res%> >= <%e2%>)
>>
res
end match
end match
end match
end match
end daeExpRelationSim;
template daeExpCall(Exp call, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a function call."
::=
match call
// special builtins
case
CALL(path=IDENT(name="DIVISION"),
expLst={e1, e2,
DAE.SCONST(string=string)}) then
let var1 = daeExp(e1, context, &preExp,
simCode)
let var2 = daeExp(e2, context, &preExp,
simCode)
let var3 =
Util.escapeModelicaStringToCString(strin
g)
<<
<%var1%>/<%var2%> /*Division
Call*/
>>
77
case CALL(attr=CALL_ATTR(ty=ty),
path=IDENT(name="DIVISION_ARRAY
_SCALAR"),
expLst={e1, e2, e3 as
SHARED_LITERAL(__)}) then
let type = match ty case
T_ARRAY(ty=T_INTEGER(__)) then
"integer_array"
case
T_ARRAY(ty=T_ENUMERATION(__))
then "integer_array"
else "real_array"
let &varDecls = buffer "" /*BUFD*/
let var = tempDecl(type, &varDecls)
let var1 = daeExp(e1, context, &preExp,
simCode)
let var2 = daeExp(e2, context, &preExp,
simCode)
let var3 = daeExp(e3, context, &preExp,
simCode)
let &preExp +=
'division_alloc_<%type%>_scalar(&<%va
r1%>, <%var2%>, &<%var%>,
<%var3%>);<%\n%>'
'<%var%>'
case exp as
CALL(path=IDENT(name="DIVISION_A
RRAY_SCALAR")) then
error(sourceInfo(), 'Code generation
does not support <%printExpStr(exp)%>')
case CALL(path=IDENT(name="der"),
expLst={arg as CREF(__)}) then
<<
<%cref(arg.componentRef)%>
>>
case CALL(path=IDENT(name="der"),
expLst={exp}) then
error(sourceInfo(), 'Code generation
does not support
der(<%printExpStr(exp)%>)')
case CALL(path=IDENT(name="pre"),
expLst={arg}) then
daeExpCallPre(arg, context, preExp,
simCode)
case
CALL(path=IDENT(name="$_start"),
expLst={arg}) then
daeExpCallPre(arg, context, preExp,
simCode)
case CALL(path=IDENT(name="edge"),
expLst={arg as CREF(__)}) then
<<
<%cref(arg.componentRef)%> /*edge*/
>>
case CALL(path=IDENT(name="edge"),
expLst={exp}) then
error(sourceInfo(), 'Code generation
does not support
edge(<%printExpStr(exp)%>)')
case
CALL(path=IDENT(name="change"),
expLst={arg as CREF(__)}) then
<<
<%cref(arg.componentRef)%>
/*change*/
>>
case
CALL(path=IDENT(name="change"),
expLst={exp}) then
error(sourceInfo(), 'Code generation
does not support
change(<%printExpStr(exp)%>)')
case CALL(path=IDENT(name="print"),
expLst={e1}) then
let var1 = daeExp(e1, context, &preExp,
simCode)
if acceptMetaModelicaGrammar() then
'System.out.println(<%var1%>)' else
'put(<%var1%>)'
case CALL(path=IDENT(name="max"),
attr=CALL_ATTR(ty = T_REAL(__)),
expLst={e1,e2}) then
let var1 = daeExp(e1, context, &preExp,
simCode)
let var2 = daeExp(e2, context, &preExp,
simCode)
<<
'Math.Max (<%var1%>,<%var2%>)'
>>
78
case CALL(path=IDENT(name="max"),
expLst={e1,e2}) then
let var1 = daeExp(e1, context, &preExp,
simCode)
let var2 = daeExp(e2, context, &preExp,
simCode)
<<
'Math.max (<%var1%>,<%var2%>)'
>>
case CALL(path=IDENT(name="sum"),
attr=CALL_ATTR(ty = ty), expLst={e})
then
let arr = daeExp(e, context, &preExp,
simCode)
let ty_str = '<%expTypeArray(ty)%>'
'sum_<%ty_str%>(&<%arr%>)'
case CALL(path=IDENT(name="min"),
attr=CALL_ATTR(ty = T_REAL(__)),
expLst={e1,e2}) then
let var1 = daeExp(e1, context, &preExp,
simCode)
let var2 = daeExp(e2, context, &preExp,
simCode)
<<
'Math.min (<%var1%>,<%var2%>)'
>>
case CALL(path=IDENT(name="min"),
expLst={e1,e2}) then
let var1 = daeExp(e1, context, &preExp,
simCode)
let var2 = daeExp(e2, context, &preExp,
simCode)
<<
'Math.min (<%var1%>,<%var2%>)'
>>
case CALL(path=IDENT(name="abs"),
expLst={e1}, attr=CALL_ATTR(ty =
T_INTEGER(__))) then
let var1 = daeExp(e1, context, &preExp,
simCode)
<<
'Math.abs (<%var1%>)'
>>
case CALL(path=IDENT(name="abs"),
expLst={e1}) then
let var1 = daeExp(e1, context, &preExp,
simCode)
<<
'Math.abs (<%var1%>)'
>>
case CALL(path=IDENT(name="sqrt"),
expLst={e1}, attr=attr as
CALL_ATTR(__)) then
let retPre =
assertCommon(createAssertforSqrt(e1),cre
ateDAEString("Model error: Argument of
sqrt should be >= 0"), context, simCode,
dummyInfo)
let argStr = daeExp(e1, context,
&preExp /*BUFC*/, simCode)
let &preExp += '<%retPre%>'
<<
'Math.sqrt (<%argStr%>)'
>>
case CALL(path=IDENT(name="mod"),
expLst={e1,e2}, attr=CALL_ATTR(ty =
ty)) then
let var1 = daeExp(e1, context, &preExp,
simCode)
let var2 = daeExp(e2, context, &preExp,
simCode)
'<%var1%>.mod(<%var2%>)'
case CALL(path=IDENT(name="log"),
expLst={s1}) then
'Math.log(<%daeExp(s1, context,
&preExp, simCode)%>)'
case
CALL(path=IDENT(name="log10"),
expLst={s1}) then
'Math.log10(<%daeExp(s1, context,
&preExp, simCode)%>)'
case CALL(path=IDENT(name="exp"),
expLst={s1}) then
'Math.exp(<%daeExp(s1, context,
&preExp, simCode)%>)'
79
case CALL(path=IDENT(name="sin"),
expLst={s1}) then
'Math.Sin(<%daeExp(s1, context,
&preExp, simCode)%>)'
case CALL(path=IDENT(name="cos"),
expLst={s1}) then
'Math.cos(<%daeExp(s1, context,
&preExp, simCode)%>)'
case CALL(path=IDENT(name="tanh"),
expLst={s1}) then
'Math.tanh(<%daeExp(s1, context,
&preExp, simCode)%>)'
case
CALL(path=IDENT(name="noEvent"),
expLst={s1}) then
'(/*noEvent*/<%daeExp(s1, /*context*/
contextOther, &preExp, simCode)%>)'
case
CALL(path=IDENT(name="initial"),
expLst={}) then
'Initial'
/* Begin code generation of event
triggering math functions */
case
CALL(path=IDENT(name="integer"),
expLst={valExp,index}) then
let &preExp += '//event trigger function:
<%ExpressionDump.printExpStr(call)%><
%\n%>'
let constIndex = daeExp(index, context,
&preExp, simCode)
match context
case SIMULATION(genDiscrete=true)
case
ALGLOOP_CONTEXT(genInitialisation=
true)
case
ZEROCROSSINGS_CONTEXT(__)
then
let val = daeExp(valExp, context,
&preExp, simCode)
'((int) (mathEVPre[<%constIndex%>]
= Math.floor(<%val%>)))'
case SIMULATION(genDiscrete=false)
then
'(int) mathEVPre[<%constIndex%>]'
case
ALGLOOP_CONTEXT(genInitialisation=
false) then
let &res = buffer ""
let &preExp +=
let &preExpVal = buffer ""
let val = daeExp(valExp, context,
&preExpVal, simCode)
<<
<%tempDecl("int", &res)%>;
if(IsDiscreteEvaluation &&
!IsContinuousEvaluation) {
<%preExpVal%>
<%res%> = (int)
(mathEVPre[<%constIndex%>] =
Math.floor(<%val%>));
} else {
<%res%> = (int)
mathEVPre[<%constIndex%>];
}<%\n%>
>>
res
else error(sourceInfo(), 'Unexpected
context for:
<%ExpressionDump.printExpStr(call)%>')
case CALL(path=IDENT(name="floor"),
expLst={valExp,index},
attr=CALL_ATTR(__)) then
let &preExp += '//event trigger function:
<%ExpressionDump.printExpStr(call)%><
%\n%>'
let constIndex = daeExp(index, context,
&preExp, simCode)
let retType =
match attr.ty
case T_REAL(__) then ""
case T_INTEGER(__) then "(int)"
else error(sourceInfo(), 'Unexpected
return type "<%expTypeShort(attr.ty)%>"
for floor().')
retType
+ ( match context
case
SIMULATION(genDiscrete=true)
80
case
ALGLOOP_CONTEXT(genInitialisation=
true)
case
ZEROCROSSINGS_CONTEXT(__)
then
let val = daeExp(valExp, context,
&preExp, simCode)
'(mathEVPre[<%constIndex%>] =
Math.floor(<%val%>))'
case
SIMULATION(genDiscrete=false) then
'mathEVPre[<%constIndex%>]'
case
ALGLOOP_CONTEXT(genInitialisation=
false) then
let &res = buffer ""
let &preExp +=
let &preExpVal = buffer ""
let val = daeExp(valExp, context,
&preExpVal, simCode)
<<
<%tempDecl("double", &res)%>;
if(IsDiscreteEvaluation &&
!IsContinuousEvaluation) {
<%preExpVal%>
<%res%> =
(mathEVPre[<%constIndex%>] =
Math.floor(<%val%>));
} else {
<%res%> =
mathEVPre[<%constIndex%>];
}<%\n%>
>>
res
else error(sourceInfo(), 'Unexpected
context for:
<%ExpressionDump.printExpStr(call)%>')
)
case CALL(path=IDENT(name="ceil"),
expLst={valExp,index},
attr=CALL_ATTR(__)) then
let &preExp += '//event trigger function:
<%ExpressionDump.printExpStr(call)%><
%\n%>'
let constIndex = daeExp(index, context,
&preExp, simCode)
let retType =
match attr.ty
case T_REAL(__) then ""
case T_INTEGER(__) then "(int)"
else error(sourceInfo(), 'Unexpected
return type "<%expTypeShort(attr.ty)%>"
for ceil().')
retType
+ ( match context
case
SIMULATION(genDiscrete=true)
case
ALGLOOP_CONTEXT(genInitialisation=
true)
case
ZEROCROSSINGS_CONTEXT(__)
then
let val = daeExp(valExp, context,
&preExp, simCode)
'(mathEVPre[<%constIndex%>] =
Math.ceil(<%val%>))'
case
SIMULATION(genDiscrete=false) then
'mathEVPre[<%constIndex%>]'
case
ALGLOOP_CONTEXT(genInitialisation=
false) then
let &res = buffer ""
let &preExp +=
let &preExpVal = buffer ""
let val = daeExp(valExp, context,
&preExpVal, simCode)
<<
<%tempDecl("double", &res)%>;
if(IsDiscreteEvaluation &&
!IsContinuousEvaluation) {
<%preExpVal%>
<%res%> =
(mathEVPre[<%constIndex%>] =
Math.ceil(<%val%>));
} else {
<%res%> =
mathEVPre[<%constIndex%>];
}<%\n%>
>>
res
else error(sourceInfo(), 'Unexpected
context for:
<%ExpressionDump.printExpStr(call)%>')
)
81
case CALL(path=IDENT(name="div"),
expLst={e1,e2, index},
attr=CALL_ATTR(__)) then
let &preExp += '//event trigger function:
<%ExpressionDump.printExpStr(call)%><
%\n%>'
let constIndex = daeExp(index, context,
&preExp, simCode)
let stype = expTypeShort(attr.ty)
match context
case SIMULATION(genDiscrete=true)
case
ALGLOOP_CONTEXT(genInitialisation=
true)
case
ZEROCROSSINGS_CONTEXT(__)
then
let val1 = daeExp(e1, context,
&preExp, simCode)
let val2 = daeExp(e2, context,
&preExp, simCode)
let &res = buffer ""
let &preExp +=
<<
<%tempDecl(stype, &res)%>
{ var d = <%val2%>;
if (d = 0) throw new
DivideByZeroException("event_div()
failed at time " + Time + " because
denominator is zero!");
<%res%> = (int) (<%val1%> / d);
mathEVPre[<%constIndex%>] =
<%res%>;
}
>>
res
case SIMULATION(genDiscrete=false)
then
'(<%stype%>)
mathEVPre[<%constIndex%>]'
case
ALGLOOP_CONTEXT(genInitialisation=
false) then
let &res = buffer ""
let &preExp +=
let &preExpVal = buffer ""
let val1 = daeExp(e1, context,
&preExpVal, simCode)
let val2 = daeExp(e2, context,
&preExpVal, simCode)
<<
<%tempDecl(stype, &res)%>;
if(IsDiscreteEvaluation &&
!IsContinuousEvaluation) {
<%preExpVal%>
var d = <%val2%>;
if (d = 0) {
throw new
DivideByZeroException("event_div()
failed at time " + Time + " because
denominator is zero!");
<%res%> = (int) (<%val1%> / d);
mathEVPre[<%constIndex%>] =
<%res%>;
}
} else {
<%res%> = (<%stype%>)
mathEVPre[<%constIndex%>];
}<%\n%>
>>
res
else error(sourceInfo(), 'Unexpected
context for:
<%ExpressionDump.printExpStr(call)%>')
/* end codegeneration of event triggering
math functions */
case exp as CALL(attr=attr as
CALL_ATTR(__)) then
let argStr = (expLst |> exp =>
'<%daeExp(exp, context, &preExp
/*BUFC*/, simCode)%>' ;separator=",")
let builtinName ='<%dotPath(path)%>'
let builtinFunctionName
='<%builtinFunctionName(path)%>'
let funName =
'<%underscorePath(path)%>'
let retType = if attr.builtin then (match
attr.ty case T_NORETCALL(__) then ""
else expTypeModelica(attr.ty))
else '<%funName%>'
let retVar = match attr.ty
case T_NORETCALL(__) then ""
else ""/*tempDecl(retType, &varDecls)
*/
match exp
82
// no return calls
case
CALL(attr=CALL_ATTR(ty=T_NORETC
ALL(__))) then '/* NORETURNCALL */'
// non tuple calls (single return value)
case
CALL(attr=CALL_ATTR(tuple_=false))
then
if attr.builtin then
<<
<%builtinFunctionName%>(<%argStr%>)
/*<%builtinName%>(<%argStr%>);
*/
>>
else
<<
<%funName%>(<%argStr%>)
>>
// tuple calls (multiple return values)
else
<<
<%funName%>(<%argStr%>)
>>
end daeExpCall;
template builtinFunctionName(Path path)
::=
match path
case IDENT(name="DIVISION") then
'divide'
case IDENT(name="ADDITION") then
'add'
case IDENT(name="SUBTRACTION")
then 'sub'
case IDENT(name="POWER") then
'Math.pow'
case IDENT(name="sin") then 'Math.sin'
case IDENT(name="cos") then 'Math.cos'
case IDENT(name="exp") then
'Math.exp'
case IDENT(name="sample") then
'Sample'
else "Builtin Function is not yet
implemented "
end builtinFunctionName;
template daeExpCallPre(Exp exp, Context
context, Text &preExp, SimCode
simCode)
"Generates code for an asub of a cref,
which becomes cref + offset."
::=
match exp
case cr as CREF(__) then
'<%cref(cr.componentRef)%>'
else
error(sourceInfo(), 'Code generation
does not support
pre(<%printExpStr(exp)%>)')
end daeExpCallPre;
template expTypeModelica(DAE.Type ty)
"Generate type helper."
::=
expTypeFlag(ty, 2)
end expTypeModelica;
template expTypeArray(DAE.Type ty)
"Generate type helper."
::=
expTypeFlag(ty, 3)
end expTypeArray;
template expTypeArrayIf(DAE.Type ty)
"Generate type helper."
::=
expTypeFlag(ty, 4)
end expTypeArrayIf;
template daeExpArray(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for an array expression."
::=
match exp
case cr as CREF(__) then
daeExpCrefRhs(cr, context, &preExp,
simCode)
case a as ARRAY(__) then
if scalar then
let &arrayVar = buffer ""
let params = a.array |> e =>
'(<%expTypeFromExpFlag(e,1)%>)<%dae
Exp(e, context, &preExp, simCode)%>'
;separator=", "
83
let &preExp +=
'<%tempDecl("var",&arrayVar)%> = new
<%expTypeArray(a.ty)%>(<%listLength(a
.array)%>,-
1,new[]{<%params%>});<%\n%>'
arrayVar
else
"NON_SCALAR_ARRAY_notYetImplem
eted"
end daeExpArray;
template daeExpIf(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for an if expression."
::=
match exp
case IFEXP(__) then
let condExp = daeExp(expCond, context,
&preExp /*BUFC*/, simCode)
let &preExpThen = buffer "" /*BUFD*/
let eThen = daeExp(expThen, context,
&preExpThen /*BUFC*/, simCode)
let &preExpElse = buffer "" /*BUFD*/
let eElse = daeExp(expElse, context,
&preExpElse /*BUFC*/, simCode)
let shortIfExp = if preExpThen then ""
else if preExpElse then "" else "x"
(if shortIfExp
then
// Safe to do if eThen and eElse don't
emit pre-expressions
'(<%condExp%>?<%eThen%>:<%eElse%
>)'
else
let &varDecls = buffer "" /*BUFD*/
let condVar = tempDecl("boolean",
&varDecls /*BUFD*/)
let resVarType =
expTypeFromExpArrayIf(expThen)
let resVar = tempDecl(resVarType,
&varDecls /*BUFD*/)
let &preExp +=
<<
<%condVar%> =
(boolean)<%condExp%>;
if (<%condVar%>) {
<%preExpThen%>
<%resVar%> =
(<%resVarType%>)<%eThen%>;
} else {
<%preExpElse%>
<%resVar%> =
(<%resVarType%>)<%eElse%>;
}<%\n%>
>>
resVar)
end daeExpIf;
template daeExpMatrix(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a matrix expression."
::=
match exp
case cr as CREF(__) then
daeExpCrefRhs(cr, context, &preExp,
simCode)
case MATRIX(matrix={{}}) // special
case for empty matrix: create dimensional
array Real[0,1]
case MATRIX(matrix={}) // special
case for empty array: create dimensional
array Real[0,1]
then
let &tmp = buffer ""
let &preExp +=
'<%tempDecl("var",&tmp)%> = new
<%expTypeArray(ty)%>(0,1);<%\n%>'
tmp
//only scalar orthogonal matrix for now
case m as MATRIX(matrix=(row1::_))
then
let &tmp = buffer ""
let matArr = m.matrix |> row =>
(row |> elem =>
daeExp(elem, context,
&preExp, simCode)
;separator=", ")
;separator=",\n"
let &preExp +=
<<
<%tempDecl("var",&tmp)%> = new
<%expTypeArray(m.ty)%>(<%listLength(
m.matrix)%>,<%listLength(row1)%>,-1,
new[]{
84
<%matArr ;anchor%>
});<%\n%>
>>
tmp
end daeExpMatrix;
template daeExpRange(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a range expression."
::=
match exp
case RANGE(__) then
let ty_str = expTypeArray(ty)
let start_exp = daeExp(start, context,
&preExp, simCode)
let stop_exp = daeExp(stop, context,
&preExp, simCode)
let &varDecls = buffer "" /*BUFD*/
let tmp = tempDecl(ty_str, &varDecls)
let step_exp = match step case
SOME(stepExp) then daeExp(stepExp,
context, &preExp, simCode) else "1"
let &preExp +=
<<
'range(<%start_exp%>,<%stop_exp%>,<
%step_exp%>);<%\n%>'
>>
'<%tmp%>'
end daeExpRange;
template daeExpCast(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a cast expression."
::=
match exp
case CAST(__) then
let expVar = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
match ty
case T_INTEGER(__) then
'((int)<%expVar%>)'
case T_REAL(__) then
'((double)<%expVar%>)'
else "NOT_IMPLEMENTED_CAST"
end daeExpCast;
template daeExpAsub(Exp inExp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for an asub expression."
::=
match inExp
case ASUB(exp=RANGE(ty=t),
sub={idx}) then
'ASUB_EASY_CASE'
case ASUB(exp=ASUB(
exp=ASUB(
exp=ASUB(exp=e,
sub={ICONST(integer=i)}),
sub={ICONST(integer=j)}),
sub={ICONST(integer=k)}),
sub={ICONST(integer=l)}) then
'ASUB_4D'
case ASUB(exp=ASUB(
exp=ASUB(exp=e,
sub={ICONST(integer=i)}),
sub={ICONST(integer=j)}),
sub={ICONST(integer=k)}) then
'ASUB_3D'
case ASUB(exp=ASUB(exp=e,
sub={ICONST(integer=i)}),
sub={ICONST(integer=j)}) then
'<%daeExp(e, context, &preExp,
simCode)%>[<%i%>,<%j%>]'
case ASUB(exp=e,
sub={ICONST(integer=i)}) then
'ASUB_ARRAY'
case ASUB(exp=ecr as
CREF(componentRef = cr), sub = subs)
then
match context case
FUNCTION_CONTEXT(__) then
daeExpCrefRhs(buildCrefExpFromAsub(e
cr, subs), context, &preExp, simCode)
else //SIMULATION or OTHER
contexts
match ecr.ty
case T_ARRAY(ty = T_REAL(__),
dims = dims) then
//daeExpCrefRhsArrayBox
let &constSum = buffer ""
let arrayRepr =
crefRepresentationArrayAndIndex(cr,
&constSum, simCode)
85
let baseSub = asubSubsripts(dims,
subs, &constSum, context, &preExp,
simCode)
'/*<%crefStr(cr)%>[]*/<%arrayRepr%>[<
%constSum%><%baseSub%>]'
else
"ASUB_SIMULATION_OTHER_ERRO
R"
case ASUB(exp=exp as
ARRAY(scalar=true), sub={idx}) then
"ASUB_FAST_ONE"
case ASUB(exp=e, sub=indexes) then
<<
<%daeExp(e, context, &preExp,
simCode)
%>[<%indexes |> index =>
'<%daeExp(index, context, &preExp,
simCode)%>' ;separator=", "%>]
>>
else
'OTHER_ASUB__ERROR'
end daeExpAsub;
template asubSubsripts(list<Dimension>
dims, list<Exp> subs, Text &constSum,
Context context, Text
&preExp, SimCode simCode)
"Helper to daeExpAsub."
::=
match subs case s :: subsRest then
match dims case _ :: dimsRest then
let subStr = daeExp(s, context,
&preExp, simCode)
if dimsRest then //not last
let ds = dimsRest |> dim =>
dimension(dim) ;separator="*"
//if ds then //TODO: assuming
every dimension is SOME, is it true ??
let &constSum += '-(<%ds%>)' //-
1 * ds
'+<%subStr%>*(<%ds%>)<%
asubSubsripts(dimsRest, subsRest,
&constSum, context, &preExp, simCode)
%>'
else //the last sub, add it to constSum
(better optimization on compilation)
let &constSum += '-1 + <% subStr
%>'
""
else
"ERROR_asubSubsripts_not_enough_dim
s"
end asubSubsripts;
template dimension(Dimension d)
::=
match d
case DAE.DIM_INTEGER(__) then
integer
case DAE.DIM_UNKNOWN(__) then
":"
else "INVALID_DIMENSION"
end dimension;
template daeExpSize(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a size expression."
::=
match exp
case SIZE(exp=CREF(__),
sz=SOME(dim)) then
let expPart = daeExp(exp, context,
&preExp, simCode)
match dim
case ICONST(__) then
'<%expPart%>.size<%integer%>'
else
'<%expPart%>.size(<%daeExp(dim,
context, &preExp, simCode)%>)'
else "size_X_NOT_IMPLEMENTED"
end daeExpSize;
template daeExpBox(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a match expression
box."
::=
match exp
case exp as BOX(__) then
let ty = expTypeFromExpShort(exp.exp)
let res =
daeExp(exp.exp,context,&preExp,simCode
)
86
<<
box_<%ty%><%res%>
>>
end daeExpBox;
template daeExpUnbox(Exp exp, Context
context, Text &preExp /*BUFP*/,
SimCode simCode)
"Generates code for a match expression
unbox."
::=
match exp
case exp as UNBOX(__) then
let ty = expTypeShort(exp.ty)
let res =
daeExp(exp.exp,context,&preExp,simCode
)
'unbox_<%ty%>(<%res%>) /*
DAE.UNBOX <%unparseType(exp.ty)
%> */'
end daeExpUnbox;
template daeExpCallBuiltinPrefix(Boolean
builtin)
"Helper to daeExpCall."
::=
match builtin
case true then ""
case false then "_"
end daeExpCallBuiltinPrefix;
/**********************************
****SECTION: GENERATE All
Algorithm IN SIMULATION
FILE******************************
****/
template algStatement(DAE.Statement
stmt, Context context, SimCode simCode)
"Generates an algorithm statement."
::=
match stmt
case s as STMT_ASSIGN(__) then
algStmtAssign(s, context, simCode)
case s as STMT_ASSIGN_ARR(__)
then algStmtAssignArr(s, context,
simCode)
case s as STMT_TUPLE_ASSIGN(__)
then algStmtTupleAssign(s, context,
simCode)
case s as STMT_IF(__) then
algStmtIf(s, context, simCode)
case s as STMT_FOR(__) then
algStmtFor(s, context, simCode)
case s as STMT_WHILE(__) then
algStmtWhile(s, context, simCode)
case s as STMT_ASSERT(__) then
algStmtAssert(s, context, simCode)
case s as STMT_TERMINATE(__)
then algStmtTerminate(s, context,
simCode)
case s as STMT_WHEN(__) then
algStmtWhen(s, context, simCode)
case s as STMT_BREAK(__) then
'Break;<%\n%>'
case s as STMT_RETURN(__) then
'Return;<%\n%>'
case s as STMT_NORETCALL(__)
then algStmtNoretcall(s, context, simCode)
case s as STMT_REINIT(__) then
algStmtReinit(s, context, simCode)
else "NEW ALG STATEMENT"
end algStatement;
template algStmtAssign(DAE.Statement
stmt, Context context, SimCode simCode)
"Generates an assigment algorithm
statement."
::=
match stmt
case
STMT_ASSIGN(exp1=CREF(component
Ref=WILD(__)), exp=e) then
let &preExp = buffer "" /*BUFD*/
let expPart = daeExp(e, context,
&preExp /*BUFC*/, simCode)
<<
<%preExp%>
>>
case STMT_ASSIGN(exp1=CREF(ty =
T_FUNCTION_REFERENCE_VAR(__)))
case STMT_ASSIGN(exp1=CREF(ty =
T_FUNCTION_REFERENCE_FUNC(__)
)) then
let &preExp = buffer "" /*BUFD*/
87
let varPart = scalarLhsCref(exp1,
context, &preExp /*BUFC*/, simCode)
let expPart = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
<<
<%preExp%>
<%varPart%> = <%expPart%>;
>>
case STMT_ASSIGN(exp1=CREF(__))
then
let &preExp = buffer "" /*BUFD*/
let varPart = scalarLhsCref(exp1,
context, &preExp /*BUFC*/, simCode)
let expPart = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
<<
<%preExp%>
<%varPart%> = <%expPart%>;
>>
case STMT_ASSIGN(__) then
let &preExp = buffer "" /*BUFD*/
let varPart = scalarLhsCref(exp1,
context, &preExp /*BUFC*/, simCode)
let expPart = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
<<
<%preExp%>
<%varPart%> = <%expPart%>;
>>
case
STMT_ASSIGN(exp1=CALL(path=path,e
xpLst=expLst,attr=CALL_ATTR(ty=
T_COMPLEX(varLst = varLst,
complexClassType=RECORD(__))))) then
let &preExp = buffer ""
let rec = daeExp(exp, context, &preExp,
simCode)
<<
<%preExp%>
<% varLst |> var as TYPES_VAR(__)
hasindex i1 fromindex 0 =>
let re = daeExp(listNth(expLst,i1),
context, &preExp, simCode)
'<%re%> =
<%rec%>.<%var.name%>;'
; separator="\n"
%>
>>
case STMT_ASSIGN(exp1=exp1 as
ASUB(__),exp=val) then
let &preExp = buffer "" /*BUFD*/
let varPart = daeExpAsub(exp1, context,
&preExp /*BUFC*/, simCode)
let expPart = daeExp(val, context,
&preExp /*BUFC*/, simCode)
<<
<%preExp%>
<%varPart%> = <%expPart%>;
>>
end algStmtAssign;
template
algStmtAssignArr(DAE.Statement stmt,
Context context, SimCode simCode)
"Generates an array assigment algorithm
statement."
::=
match stmt
case STMT_ASSIGN_ARR(exp=e,
componentRef=cr, type_=t) then
let &preExp = buffer "" /*BUFD*/
let expPart = daeExp(e, context, &preExp
/*BUFC*/, simCode)
let ispec = indexSpecFromCref(cr,
context, &preExp /*BUFC*/, simCode)
if ispec then
<<
<%preExp%>
<%indexedAssign(t, expPart, cr, ispec,
context, simCode)%>
>>
else
<<
<%copyArrayData(t, expPart, cr,
context, simCode)%>
<%preExp%>
>>
end algStmtAssignArr;
template
indexSpecFromCref(ComponentRef cr,
Context context, Text &preExp /*BUFP*/,
SimCode
simCode)
88
"Helper to algStmtAssignArr.
Currently works only for CREF_IDENT."
::=
match cr
case CREF_IDENT(subscriptLst=subs as
(_ :: _)) then
daeExpCrefRhsIndexSpec(subs, context,
&preExp /*BUFC*/, simCode)
end indexSpecFromCref;
template
daeExpCrefRhsIndexSpec(list<Subscript>
subs, Context context,
Text &preExp
/*BUFP*/, SimCode simCode)
"Helper to daeExpCrefRhs."
::=
let nridx_str = listLength(subs)
let &varDecls = buffer "" /*BUFD*/
let idx_str = (subs |> sub =>
match sub
case INDEX(__) then
let expPart = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
let str =
<<
<%expPart%>
>>
str
case WHOLEDIM(__) then
let str = <<(1), (int*)0, 'W'>>
str
case SLICE(__) then
let expPart = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
let tmp =
tempDecl("modelica_integer", &varDecls
/*BUFD*/)
let &preExp += '<%tmp%> =
size_of_dimension_integer_array(<%expP
art%>, 1);<%\n%>'
let str = <<(int) <%tmp%>,
integer_array_make_index_array(&<%exp
Part%>), 'A'>>
str
;separator=", ")
let tmp = tempDecl("index_spec_t",
&varDecls /*BUFD*/)
let &preExp +=
'create_index_spec(&<%tmp%>,
<%nridx_str%>, <%idx_str%>);<%\n%>'
tmp
end daeExpCrefRhsIndexSpec;
template indexedAssign(DAE.Type ty,
String exp, DAE.ComponentRef cr,
String ispec, Context
context, SimCode simCode)
::=
let type = expTypeArray(ty)
let cref = contextArrayCref(cr, context)
match context
case FUNCTION_CONTEXT(__) then
<<
<%type%> <%cref%>
>>
else
<<
<%type%>
<%exp%>
<%ispec%>
<%cref%>
>>
end indexedAssign;
template copyArrayData(DAE.Type ty,
String exp, DAE.ComponentRef cr,
Context context, SimCode simCode)
::=
let type = expTypeArray(ty)
let cref = contextArrayCref(cr, context)
match context
case FUNCTION_CONTEXT(__) then
'<%cref%>'
else
<<
<%type%> <%cref%>
>>
end copyArrayData;
template
algStmtTupleAssign(DAE.Statement stmt,
Context context, SimCode simCode)
"Generates Java for a tuple assigment
algorithm statement."
::=
89
match stmt
case
STMT_TUPLE_ASSIGN(exp=CALL(__))
then
let &preExp = buffer "" /*BUFD*/
let &afterExp = buffer "" /*BUFD*/
let crefs = (expExpLst |> e =>
ExpressionDump.printExpStr(e)
;separator=", ")
let marker = '(<%crefs%>) =
<%ExpressionDump.printExpStr(exp)%>'
let &preExp += '/* algStmtTupleAssign:
preExp buffer created for <%marker%>
*/<%\n%>'
let &afterExp += '/* algStmtTupleAssign:
afterExp buffer created for <%marker%>
*/<%\n%>'
let retStruct = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
let lhsCrefs = (expExpLst |> cr hasindex
i1 fromindex 1 =>
let rhsStr =
'<%retStruct%>.targ<%i1%>'
writeLhsCref(cr, rhsStr,
context, &afterExp /*BUFC*/, simCode)
;separator="\n")
<<
return <%lhsCrefs%> = <%retStruct%>;
>>
case
STMT_TUPLE_ASSIGN(exp=MATCHE
XPRESSION(__)) then
let &preExp = buffer "" /*BUFD*/
let &afterExp = buffer "" /*BUFD*/
let prefix = 'tmp<%System.tmpTick()%>'
//let _ = daeExpMatch2(exp, expExpLst,
prefix, context, &preExp, simCode)
let lhsCrefs = (expExpLst |> cr hasindex
i1 fromindex 1 =>
let rhsStr =
'<%prefix%>_targ<%i1%>'
writeLhsCref(cr, rhsStr,
context, &afterExp /*BUFC*/, simCode)
;separator="\n")
<<
<%expExpLst |> cr hasindex i1
fromindex 1 =>
let rhsStr = '<%prefix%>_targ<%i1%>'
let typ =
'<%expTypeFromExpModelica(cr)%>'
let &varDecls = buffer "" /*BUFD*/
let initVar = match typ case
"modelica_metatype" then ' = NULL' else ''
let addRoot = match typ case
"modelica_metatype" then '
mmc_GC_add_root(&<%rhsStr%>,
mmc_GC_local_state, "<%rhsStr%>");'
else ''
let &varDecls += '<%typ%>
<%rhsStr%><%initVar%>;<%addRoot%>
<%\n%>'
""
;separator="\n";empty%>
<%preExp%>
<%lhsCrefs%>
<%afterExp%>
>>
else error(sourceInfo(),
'algStmtTupleAssign failed')
end algStmtTupleAssign;
template writeLhsCref(Exp exp, String
rhsStr, Context context, Text &preExp
/*BUFP*/, SimCode simCode)
"Generates Java code for writing a
returnStructur to var."
::=
match exp
case ecr as
CREF(componentRef=WILD(__)) then
<<
"EmptyOutputArgument"
>>
case CREF(ty= t as DAE.T_ARRAY(__))
then
let lhsStr = scalarLhsCref(exp, context,
&preExp /*BUFC*/, simCode)
match context
case SIMULATION(__) then
<<
<%lhsStr%>
>>
else
<<
<%lhsStr%>
>>
90
case UNARY(exp = e as CREF(ty= t as
DAE.T_ARRAY(__))) then
let lhsStr = scalarLhsCref(e, context,
&preExp /*BUFC*/, simCode)
match context
case SIMULATION(__) then
<<
<%rhsStr%>
<%lhsStr%>
>>
else
<<
<%lhsStr%>
>>
case CREF(__) then
let lhsStr = scalarLhsCref(exp, context,
&preExp /*BUFC*/, simCode)
<<
<%lhsStr%>
>>
case UNARY(exp = e as CREF(__)) then
let lhsStr = scalarLhsCref(e, context,
&preExp /*BUFC*/, simCode)
<<
<%lhsStr%>
>>
case _ then
<<
/* CodegenJava.tpl template:
writeLhsCref: UNHANDLED LHS
*
<%ExpressionDump.printExpStr(exp)%>
= <%rhsStr%>
*/
>>
end writeLhsCref;
template algStmtIf(DAE.Statement stmt,
Context context, SimCode simCode)
"Generates an if algorithm statement."
::=
match stmt
case STMT_IF(__) then
let &preExp = buffer "" /*BUFD*/
let condExp = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
<<
<%preExp%>
if (<%condExp%>) {
<%statementLst |> stmt =>
algStatement(stmt, context, simCode)
;separator="\n"%>
}
<%elseExpr(else_, context, simCode)%>
>>
end algStmtIf;
template elseExpr(DAE.Else else_,
Context context, SimCode simCode)
"Helper to algStmtIf."
::=
match else_
case NOELSE(__) then
""
case ELSEIF(__) then
let &preExp = buffer "" /*BUFD*/
let condExp = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
<<
else {
<%preExp%>
if (<%condExp%>) {
<%statementLst |> stmt =>
algStatement(stmt, context,
simCode)
;separator="\n"%>
}
<%elseExpr(else_, context,
simCode)%>
}
>>
case ELSE(__) then
<<
else {
<%statementLst |> stmt =>
algStatement(stmt, context, simCode)
;separator="\n"%>
}
>>
end elseExpr;
template algStmtFor(DAE.Statement stmt,
Context context, SimCode simCode)
"Generates a while algorithm statement."
::=
/*algStmtFor */
match stmt
91
case s as STMT_FOR(range=rng as
RANGE(__)) then
algStmtForRange(s, context, simCode)
case s as STMT_FOR(__) then
algStmtForGeneric(s, context,
simCode)
end algStmtFor;
template algStmtForRange(DAE.Statement
stmt, Context context, SimCode simCode)
"Generates a for algorithm statement
where range is RANGE."
::=
match stmt
case STMT_FOR(range=rng as
RANGE(__)) then
let identType = expType(type_,
iterIsArray)
let identTypeShort =
expTypeShort(type_)
let stmtStr = (statementLst |> stmt =>
algStatement(stmt, context, simCode)
;separator="\n")
algStmtForRange_impl(rng, iter,
identType, identTypeShort, stmtStr,
context, simCode)
end algStmtForRange;
template contextIteratorName(Ident name,
Context context)
"Generates code for an iterator variable."
::=
match context
case FUNCTION_CONTEXT(__) then
"_" + name
case
PARALLEL_FUNCTION_CONTEXT(__
) then "_" + name
else "$P" + name
end contextIteratorName;
template algStmtForRange_impl(Exp
range, Ident iterator, String type, String
shortType, Text body, Context context,
SimCode simCode)
"The implementation of algStmtForRange,
which is also used by daeExpReduction."
::=
match range
case RANGE(__) then
let &varDecls = buffer "" /*BUFD*/
let iterName =
contextIteratorName(iterator, context)
let stateVar = if not
acceptMetaModelicaGrammar() then
tempDecl("state", &varDecls)
let startVar = tempDecl(type, &varDecls)
let stepVar = tempDecl(type, &varDecls)
let stopVar = tempDecl(type, &varDecls)
let &preExp = buffer ""
let startValue = daeExp(start, context,
&preExp, simCode)
let stepValue = match step case
SOME(eo) then
daeExp(eo, context, &preExp,
simCode)
else
"(1)"
let stopValue = daeExp(stop, context,
&preExp, simCode)
<<
/*algStmtForRange_impl*/
<%preExp%>
<%startVar%> = <%startValue%>;
<%stepVar%> = <%stepValue%>;
<%stopVar%> = <%stopValue%>;
if (!<%stepVar%>) {
FILE_INFO info =
omc_dummyFileInfo;
omc_assert("assertion range step != 0
failed", info);
} else if (!(((<%stepVar%> > 0) &&
(<%startVar%> > <%stopVar%>)) ||
((<%stepVar%> < 0) && (<%startVar%>
< <%stopVar%>)))) {
<%type%> <%iterName%>;
for (<%iterName%> =
<%startValue%>;
in_range_<%shortType%>(<%iterName%
>, <%startVar%>, <%stopVar%>);
<%iterName%> += <%stepVar%>) {
<%if not
acceptMetaModelicaGrammar() then
'<%stateVar%> = get_memory_state();'%>
<%body%>
<%if not
acceptMetaModelicaGrammar() then
92
'restore_memory_state(<%stateVar%>);'%
>
}
}
>> /* else we're looping over a zero-
length range */
end algStmtForRange_impl;
template
algStmtForGeneric(DAE.Statement stmt,
Context context, SimCode simCode)
"Generates a for algorithm statement
where range is not RANGE."
::=
match stmt
case STMT_FOR(__) then
let iterType = expType(type_,
iterIsArray)
let arrayType = expTypeArray(type_)
let stmtStr = (statementLst |> stmt =>
algStatement(stmt, context, simCode)
;separator="\n")
algStmtForGeneric_impl(range, iter,
iterType, arrayType, iterIsArray, stmtStr,
context, simCode)
end algStmtForGeneric;
template algStmtForGeneric_impl(Exp
exp, Ident iterator, String type,
String arrayType, Boolean iterIsArray,
Text &body, Context context, SimCode
simCode)
"The implementation of
algStmtForGeneric, which is also used by
daeExpReduction."
::=
let &varDecls = buffer "" /*BUFD*/
let iterName =
contextIteratorName(iterator, context)
let stateVar = if not
acceptMetaModelicaGrammar() then
tempDecl("state", &varDecls)
let tvar = tempDecl("int", &varDecls)
let ivar = tempDecl(type, &varDecls)
let &preExp = buffer ""
let evar = daeExp(exp, context, &preExp,
simCode)
let stmtStuff = if iterIsArray then
'simple_index_alloc_<%type%>1(&<%eva
r%>, <%tvar%>, &<%ivar%>);'
else
'<%iterName%> =
*(<%arrayType%>_element_addr1(&<%e
var%>, 1, <%tvar%>));'
<<
/* algStmtForGeneric_impl;*/
<%preExp%>
{
<%type%> <%iterName%>;
for(<%tvar%> = 1; <%tvar%> <=
size_of_dimension_<%arrayType%>(<%e
var%>, 1); ++<%tvar%>) {
<%if not
acceptMetaModelicaGrammar() then
'<%stateVar%> = get_memory_state();'%>
<%stmtStuff%>
<%body%>
<%if not
acceptMetaModelicaGrammar() then
'restore_memory_state(<%stateVar%>);'%
>
}
}
}
>>
end algStmtForGeneric_impl;
template algStmtWhile(DAE.Statement
stmt, Context context, SimCode simCode)
"Generates a while algorithm statement."
::=
match stmt
case STMT_WHILE(__) then
let &preExp = buffer "" /*BUFD*/
let var = daeExp(exp, context, &preExp
/*BUFC*/, simCode)
<<
while (<%var%>) {
<%statementLst |> stmt =>
algStatement(stmt, context, simCode)
;separator="\n"%>
}
>>
end algStmtWhile;
93
template algStmtAssert(DAE.Statement
stmt, Context context, SimCode simCode)
"Generates an assert algorithm statement."
::=
match stmt
case
STMT_ASSERT(source=SOURCE(info=i
nfo)) then
assertCommon(cond, msg, context,
simCode, info)
end algStmtAssert;
template
algStmtTerminate(DAE.Statement stmt,
Context context, SimCode simCode)
"Generates an assert algorithm statement."
::=
match stmt
case STMT_TERMINATE(__) then
let &preExp = buffer "" /*BUFD*/
let msgVar = daeExp(msg, context,
&preExp /*BUFC*/, simCode)
<<
<%preExp%>
<%msgVar%>
>>
end algStmtTerminate;
template algStmtWhen(DAE.Statement
when, Context context, SimCode simCode)
"Generates a when algorithm statement."
::=
match context
case SIMULATION(__) then
match when
case STMT_WHEN(__) then
let preIf = algStatementWhenPre(when,
simCode)
let statements = (statementLst |> stmt =>
algStatement(stmt, context, simCode)
;separator="\n")
let else =
algStatementWhenElse(elseWhen,
simCode)
<<
/*algStmtWhen*/
<%/*preIf*/%>
if <%preIf%> {
<%statements%>
}
<%else%>
}
>>
end match
end match
end algStmtWhen;
template
algStatementWhenPre(DAE.Statement
stmt, SimCode simCode)
"Helper to algStmtWhen."
::=
match stmt
case
STMT_WHEN(exp=ARRAY(array=el))
then
let restPre = match elseWhen case
SOME(ew) then
algStatementWhenPre(ew, simCode)
else
""
let &preExp = buffer "" /*BUFD*/
/*let assignments =
algStatementWhenPreAssigns(el,
helpVarIndices,
&preExp
/*BUFC*/,
simCode)*/
<<
/*algStatementWhenPre case1*/
<%preExp%>
</*%assignments%>
<%restPre%>
>>
case when as STMT_WHEN(__) then
match statementLst
// match helpVarIndices
case {i} then
let restPre = match when.elseWhen
case SOME(ew) then
algStatementWhenPre(ew, simCode)
else
""
let &preExp = buffer "" /*BUFD*/
let res = daeExp(when.exp,
contextSimulationDiscrete,
94
&preExp /*BUFC*/,
simCode)
<<
/*algStatementWhenPre case 2 */
<%preExp%>
<%res%>
<%restPre%>
>>
end algStatementWhenPre;
template
algStatementWhenElse(Option<DAE.State
ment> stmt, SimCode simCode)
"Helper to algStmtWhen."
::=
match stmt
case SOME(when as STMT_WHEN(__))
then
let statements = (when.statementLst |>
stmt =>
algStatement(stmt,
contextSimulationDiscrete, simCode)
;separator="\n")
let else =
algStatementWhenElse(when.elseWhen,
simCode)
/*let elseCondStr = (when.helpVarIndices
|> hidx =>
'data-
>simulationInfo.helpVars[<%hidx%>] &&
!data-
>simulationInfo.helpVarsPre[<%hidx%>]
/* edge */'
;separator=" || ")*/
<<
else if (</*%elseCondStr%>) {
<%statements%>
}
<%else%>
>>
end algStatementWhenElse;
template
algStatementWhenPreAssigns(list<Exp>
exps, list<Integer> ints,
Text &preExp /*BUFP*/,
SimCode simCode)
"Helper to algStatementWhenPre.
The lists exps and ints should be of the
same length. Iterating over two
lists like this is not so well supported in
Susan, so it looks a bit ugly."
::=
match exps
case {} then ""
case (firstExp :: restExps) then
match ints
case (firstInt :: restInts) then
let rest =
algStatementWhenPreAssigns(restExps,
restInts, &preExp /*BUFC*/, simCode)
let firstExpPart = daeExp(firstExp,
contextSimulationDiscrete,
&preExp /*BUFC*/,
simCode)
<<
<%firstExpPart%>;
<%rest%>
>>
end algStatementWhenPreAssigns;
template algStmtNoretcall(DAE.Statement
stmt, Context context, SimCode simCode)
"Generates a no return call algorithm
statement."
::=
match stmt
case STMT_NORETCALL(__) then
let &preExp = buffer "" /*BUFD*/
let expPart = daeExp(exp, context,
&preExp /*BUFC*/, simCode)
<<
<%preExp%>
<%expPart%>
>>
end algStmtNoretcall;
template algStmtReinit(DAE.Statement
stmt, Context context, SimCode simCode)
"Generates an assigment algorithm
statement."
::=
match stmt
case STMT_REINIT(__) then
let &preExp = buffer "" /*BUFD*/
let expPart1 = daeExp(var, context,
&preExp /*BUFC*/, simCode)
95
let expPart2 = daeExp(value, context,
&preExp /*BUFC*/, simCode)
<<
<%expPart1%> = <%expPart2%>;
>>
end algStmtReinit;
/**********************************
**componentreference****************
**********************************
***/
template scalarLhsCref(Exp ecr, Context
context, Text &preExp, SimCode
simCode)
"Generates the left hand side (for use on
left hand side) of a component
reference."
::=
match ecr
case CREF(componentRef = cr, ty =
T_FUNCTION_REFERENCE_VAR(__))
then
<<
<%crefStr(cr)%>
>>
case ecr as
CREF(componentRef=CREF_IDENT(__))
then
if crefNoSub(ecr.componentRef) then
contextCref(ecr.componentRef,
context)
else
daeExpCrefRhs(ecr, context, &preExp,
simCode)
case ecr as
CREF(componentRef=CREF_QUAL(__))
then
contextCref(ecr.componentRef, context)
else
"ONLY_IDENT_OR_QUAL_CREF_SUP
PORTED_SLHS"
end scalarLhsCref;
template functionName(ComponentRef cr)
::=
match cr
case CREF_IDENT(__) then
System.stringReplace(ident, "_", "__")
case CREF_QUAL(__) then
'<%System.stringReplace(ident, "_",
"__")%>_<%functionName(componentRef
)%>'
end functionName;
template contextCref(ComponentRef cr,
Context context)
"Generates code for a component
reference depending on which context
we're in."
::=
match context
case FUNCTION_CONTEXT(__) then
cref(cr)
else cref(cr)
end contextCref;
template cref(ComponentRef cr)
"Generates Java equivalent name for
component reference."
::=
match cr
case CREF_IDENT(ident = "xloc") then
crefStr(cr)
case CREF_IDENT(ident = "time") then
"time"
case CREF_IDENT(ident = " ") then
crefToCStr(cr)
else crefToCStr(cr)
end cref;
template expCref(DAE.Exp ecr)
::=
match ecr
case CREF(__) then cref(componentRef)
case CALL(path = IDENT(name =
"der"), expLst = {arg as CREF(__)}) then
'der<%cref(arg.componentRef)%>'
else "ERROR_NOT_A_CREF"
end expCref;
template contextArrayCref(ComponentRef
cr, Context context)
"Generates Java code for an array
component reference depending on the
context."
96
::=
match context
case FUNCTION_CONTEXT(__) then
arrayCrefStr(cr)
else arrayCrefStrname(cr)
end contextArrayCref;
template arrayCrefStrname(ComponentRef
cr)
::= '<%arrayCrefStrName1(cr)%>'
end arrayCrefStrname;
template
arrayCrefStrName1(ComponentRef cr)
::=
match cr
case CREF_IDENT(__) then
<<
<exp:QualifiedName>
<exp:QualifiedNamePart
name="<%unquoteIdentifier(ident)%>">
>>
case CREF_QUAL(__) then
'<%unquoteIdentifier(ident)%><%subscrip
tsStr(subscriptLst)%>$P<%arrayCrefStrNa
me1(componentRef)%>testing array'
else "CREF_NOT_IDENT_OR_QUAL"
end arrayCrefStrName1;
template arrayCrefStr(ComponentRef cr)
::=
match cr
case CREF_IDENT(__) then
<<
"<%ident%>"
>>
case CREF_QUAL(__) then
'<%ident%>.<%arrayCrefStr(componentR
ef)%>'
else "CREF_NOT_IDENT_OR_QUAL"
end arrayCrefStr;
template
crefRepresentationArrayAndIndex(Compo
nentRef cr, Text &indexTxt, SimCode
simCode)
::=
match cr
//deprecated: case CREF_IDENT(ident =
"xloc") then crefStr(cr, simCode) //TODO:
??xloc
case CREF_IDENT(ident = "time") then
"Time" //no index
case CREF_IDENT(ident = "$_lambda")
then "_lambda" //no index
//??is this a HACK (on the SimCode
level) ??
case CREF_QUAL(ident = "$PRE") then
'pre<%crefRepresentationArrayAndIndex(
componentRef, &indexTxt, simCode)%>'
else
(cref2simvar(cr, simCode) |>
SIMVAR(__) =>
let &indexTxt += index
representationArrayName(varKind,
type_))
end crefRepresentationArrayAndIndex;
template
representationArrayName(VarKind
varKind, Type type_)
::=
match varKind
case VARIABLE(__) then "Y"
case STATE(__) then "X"
case STATE_DER(__) then "Xd"
case DUMMY_DER(__) then "Y" // =>
algebraics
case DUMMY_STATE(__) then "Y" //
=> algebraics
case EXTOBJ(__) then "EO"
case CONST(__) then
"CONST_VAR_KIND"
else "BAD_VARKIND"
end representationArrayName;
template
representationCref(ComponentRef inCref,
SimCode simCode)
::=
let &indexTxt = buffer ""
let arrAndIdx =
crefRepresentationArrayAndIndex(inCref,
&indexTxt, simCode)
if indexTxt then
'<% indexTxt %>'
97
else
arrAndIdx
end representationCref;
template crefindex(ComponentRef cref,
SimCode simCode)
::=
'<% representationCref(cref, simCode)
%>'
end crefindex;
template crefStr(ComponentRef cr)
"Generates the name of a variable for
variable name array."
::=
match cr
case CREF_IDENT(__) then
'<%ident%><%subscriptsStr(subscriptLst)
%>'
case CREF_QUAL(ident = "der") then
'der(<%crefStr(componentRef)%>)'
case CREF_QUAL(__) then
'<%ident%><%subscriptsStr(subscriptLst)
%>.<%crefStr(componentRef)%>'
else "CREF_NOT_IDENT_OR_QUAL"
end crefStr;
template subscriptsStr(list<Subscript>
subscripts)
"Generares subscript part of the name."
::=
if subscripts then
'[<%subscripts |> s => subscriptStr(s)
;separator=","%>]'
end subscriptsStr;
template subscriptStr(Subscript subscript)
"Generates a single subscript.
Only works for constant integer indicies."
::=
match subscript
case
INDEX(exp=ICONST(integer=i)) then i
case
SLICE(exp=ICONST(integer=i)) then i
case WHOLEDIM(__) then
"WHOLEDIM"
else "UNKNOWN_SUBSCRIPT"
end subscriptStr;
template crefToCStr(ComponentRef cr)
"Helper function to cref."
::=
match cr
case CREF_IDENT(__) then
'<%ident%><%subscriptsToCStr(subscript
Lst)%>'
case CREF_QUAL(__) then
'<%ident%><%subscriptsToCStr(subscript
Lst)%><%crefToCStr(componentRef)%>'
else "CREF_NOT_IDENT_OR_QUAL"
end crefToCStr;
template subscriptsToCStr(list<Subscript>
subscripts)
::=
if subscripts then
'[<%subscripts |> s =>
subscriptToCStr(s) ;separator=","%>]'
end subscriptsToCStr;
template subscriptToCStr(Subscript
subscript)
::=
match subscript
case INDEX(exp=ICONST(integer=i))
then i
case SLICE(exp=ICONST(integer=i))
then i
case WHOLEDIM(__) then
"WHOLEDIM"
else "UNKNOWN_SUBSCRIPT"
end subscriptToCStr;
template expType(DAE.Type ty, Boolean
array)
"Generate type helper."
::=
match array
case true then expTypeArray(ty)
case false then expTypeModelica(ty)
end expType;
template expTypeFromExpArrayIf(Exp
exp)
"Generate type helper."
::=
expTypeFromExpFlag(exp, 4)
98
end expTypeFromExpArrayIf;
template expTypeFlag(DAE.Type ty,
Integer flag)
"Generate type helper."
::=
match flag
case 1 then
// we want the short type
expTypeShort(ty)
case 2 then
// we want the "modelica type"
match ty case
T_COMPLEX(complexClassType=EXTE
RNAL_OBJ(__)) then
'<%expTypeShort(ty)%>'
else match ty case T_COMPLEX(__)
then
'struct
<%underscorePath(ClassInf.getStateName(
complexClassType))%>' // alachew 'struct
<%underscorePath(name)%>' //
else
'<%expTypeShort(ty)%>'
case 3 then
// we want the "array type"
'<%expTypeShort(ty)%>'
case 4 then
// we want the "array type" only if type
is array, otherwise "modelica type"
match ty
case T_ARRAY(__) then
'<%expTypeShort(ty)%>'
else expTypeFlag(ty, 2)
end expTypeFlag;
template tempDecl(String ty, Text
&varDecls /*BUFP*/)
"Declares a temporary variable in
varDecls and returns the name."
::=
let newVar
=
match ty /* TODO! FIXME! UGLY!
UGLY! hack! */
case "modelica_metatype"
case "metamodelica_string"
case "metamodelica_string_const"
then
'tmpMeta[<%System.tmpTickIndex(1)%>]
'
else
let newVarIx =
'tmp<%System.tmpTick()%>'
let &varDecls += '<%ty%>
<%newVarIx%>;<%\n%>'
newVarIx
newVar
end tempDecl;
template expTypeFromExpFlag(Exp exp,
Integer flag)
"Generate type helper."
::=
/*replaced "modelica_integer" type to
normal type "int" and real to double for
header porblem --mano*/
match exp
case ICONST(__) then match flag
case 8 then "int" case 1 then "int" else "int"
case RCONST(__) then match flag
case 1 then "double" else "double"
case SCONST(__) then if
acceptMetaModelicaGrammar() then
(match flag case 1 then
"metatype" else "modelica_metatype")
else
(match flag case 1 then
"string" else "string")
case BCONST(__) then match flag
case 1 then "boolean" else "boolean"
case ENUM_LITERAL(__) then match
flag case 8 then "int" case 1 then "int" else
"int"
case e as BINARY(__)
case e as UNARY(__)
case e as LBINARY(__)
case e as LUNARY(__)
case e as RELATION(__) then
expTypeFromOpFlag(e.operator, flag)
case IFEXP(__) then
expTypeFromExpFlag(expThen, flag)
case CALL(attr=CALL_ATTR(__)) then
expTypeFlag(attr.ty, flag) // alachew case
CALL(__) then expTypeFlag(ty,
flag)
99
else '#error
"expTypeFromExpFlag:<%printExpStr(ex
p)%>"'
end expTypeFromExpFlag;
template varType(Variable var)
"Generates type for a variable."
::=
match var
case VARIABLE(__) then
if instDims then
expTypeArray(ty)
else
expTypeArrayIf(ty)
end varType;
template expTypeShort(DAE.Type type)
"Generate type helper."
::=
match type
case T_INTEGER(__) then "int"
case T_REAL(__) then "double"
case T_STRING(__) then if
acceptMetaModelicaGrammar() then
"metatype" else "string"
case T_BOOL(__) then "boolean" /*
need to cross check --mano*/
case T_ENUMERATION(__) then "int"
case T_ARRAY(__) then
expTypeShort(ty)
case
T_COMPLEX(complexClassType=EXTE
RNAL_OBJ(__))
then "complex"
case T_COMPLEX(__) then '/*struct*/
<%underscorePath(ClassInf.getStateName(
complexClassType))%>'
case T_METATYPE(__) case
T_METABOXED(__) then
"META_TYPE_NOT_SUPPORTED"
case
T_FUNCTION_REFERENCE_VAR(__)
then "fnptr"
case T_UNKNOWN(__) then
"UNKNOWN_TYPE_NOT_SUPPORTE
D"
case T_ANYTYPE(__) then
"ANYTYPE_TYPE_NOT_SUPPORTED"
else "expTypeShort:ERROR"
end expTypeShort;
template replaceDotAndUnderscore(String
str)
"Replace _ with __ and dot in identifiers
with _"
::=
match str
case name then
let str_dots =
System.stringReplace(name,".", "_")
let str_underscores =
System.stringReplace(str_dots, "_", "__")
'<%str_underscores%>'
end replaceDotAndUnderscore;
template underscorePath(Path path)
"Generate paths with components
separated by underscores.
Replaces also the . in identifiers with _.
The dot might happen for
world.gravityAccleration"
::=
match path
case QUALIFIED(__) then
'<%replaceDotAndUnderscore(name)%>_
<%underscorePath(path)%>'
case IDENT(__) then
replaceDotAndUnderscore(name)
case FULLYQUALIFIED(__) then
underscorePath(path)
end underscorePath;
template expTypeFromOpFlag(Operator
op, Integer flag)
"Generate type helper."
::=
match op
case o as ADD(__)
case o as SUB(__)
case o as MUL(__)
case o as DIV(__)
case o as POW(__)
case o as UMINUS(__)
// alachew case o as UPLUS(__)
case o as LESS(__)
case o as LESSEQ(__)
100
case o as GREATER(__)
case o as GREATEREQ(__)
case o as EQUAL(__)
case o as NEQUAL(__) then
expTypeFlag(o.ty, flag)
case o as AND(__)
case o as OR(__)
case o as NOT(__) then
match flag case 1 then "boolean" else
"boolean"
else "expTypeFromOpFlag:ERROR"
end expTypeFromOpFlag;
template infoArgs(Info info)
::=
match info
case INFO(__) then
'"<%fileName%>",<%lineNumberStart%>
,<%columnNumberStart%>,<%lineNumbe
rEnd%>,<%columnNumberEnd%>,<%isR
eadOnly%>'
end infoArgs;
template assertCommon(Exp condition,
Exp message, Context context, SimCode
simCode, Info info)
::=
let &preExpCond = buffer ""
let &preExpMsg = buffer ""
let condVar = daeExp(condition, context,
&preExpCond, simCode)
let msgVar = daeExp(message, context,
&preExpMsg, simCode)
<<
<%preExpCond%>
if (!<%condVar%>) {
<%preExpMsg%>
// <%infoArgs(info)%>
throw new Exception(<%msgVar%>);
}
>>
end assertCommon;
template expTypeFromExpShort(Exp exp)
"Generate type helper."
::=
expTypeFromExpFlag(exp, 1)
end expTypeFromExpShort;
template expTypeFromExpModelica(Exp
exp)
"Generate type helper."
::=
expTypeFromExpFlag(exp, 2)
end expTypeFromExpModelica;
template unboxVariable(String varName,
Type varType, Text &preExp, Text
&varDecls)
::=
match varType
case T_STRING(__) case
T_METATYPE(__) case
T_METABOXED(__) then varName
case T_COMPLEX(complexClassType =
RECORD(__)) then
unboxRecord(varName, varType,
&preExp, &varDecls)
else
let shortType =
mmcExpTypeShort(varType)
let ty = '<%shortType%>'
let tmpVar = tempDecl(ty, &varDecls)
let &preExp += '<%tmpVar%> =
mmc_unbox_<%shortType%>(<%varNam
e%>);<%\n%>'
tmpVar
end unboxVariable;
template unboxRecord(String recordVar,
Type ty, Text &preExp, Text &varDecls)
::=
match ty
case T_COMPLEX(complexClassType =
RECORD(path = path), varLst = vars) then
let tmpVar = tempDecl('struct
<%underscorePath(path)%>', &varDecls)
let &preExp += (vars |>
TYPES_VAR(name = compname)
hasindex offset fromindex 2 =>
let varType = mmcExpTypeShort(ty)
let untagTmp =
tempDecl('modelica_metatype',
&varDecls)
//let offsetStr = incrementInt(i1, 1)
let &unboxBuf = buffer ""
101
let unboxStr =
unboxVariable(untagTmp, ty, &unboxBuf,
&varDecls)
<<
<%untagTmp%> =
(MMC_FETCH(MMC_OFFSET(MMC_U
NTAGPTR(<%recordVar%>),
<%offset%>)));
<%unboxBuf%>
<%tmpVar%>.<%compname%> =
<%unboxStr%>;
>>
;separator="\n")
tmpVar
end unboxRecord;
template mmcExpTypeShort(DAE.Type
type)
::=
match type
case T_INTEGER(__) then
"int"
case T_REAL(__) then
"double"
case T_STRING(__) then
"string"
case T_BOOL(__) then
"boolean"
case T_ENUMERATION(__)
then "int"
case T_ARRAY(__) then
"type[]"
case T_METATYPE(__) case
T_METABOXED(__) then
"metatype"
case
T_FUNCTION_REFERENCE_VAR(__)
then "fnptr"
else "mmcExpTypeShort:ERROR"
end mmcExpTypeShort;
template xsdateTime(DateTime dt)
"YYYY-MM-DDThh:mm:ssZ"
::=
match dt
case DATETIME(__) then '<%year%>-
<%twodigit(mon)%>-
<%twodigit(mday)%>T<%twodigit(hour)
%>:<%twodigit(min)%>:<%twodigit(sec)
%>Z'
end xsdateTime;
end CodegenJava;
102
Java Runtime System
SimData.Java
package jrt;
import java.util.*;
import org.jscience.physics.amount.* ;
import javax.measure.quantity.* ;
/**
* The dynamic data for a simulation at a
given time.
*
* This includes the values of every state
variable at a given time.
* The values are stored in a format
appropriate for the solvers.
*
* DISCUSS: Constituent type for
variables; either
* 1. Amount<?> which is consistent
with the external packages interfaces
* providing domain specific typing.
* 2. Float64 which will give more
efficient calculations and storage.
*
* @author [email protected]
*
*/
public class SimData {
double time ;
int size;
double start;
double stepsize;
double stop;
/*
* Initialize as Vector type as Double
* To avoid NullPointerException error
*/
Vector<Double> x = new
Vector<Double>();
Vector<Double> xdot = new
Vector<Double>() ;
Vector<Double> m ;
Vector<Double> z ;
public SimData( int xdim, int mdim, int
zdim )
{
// simulation default settings
size = xdim;
start = 0.0;
stepsize = 0.002;
stop = 1.0;
// this.x = new Float64Vector( xdim
) ;
// this.xdot = new Float64Vector(
xdim ) ;
// this.m = new Float64Vector( mdim
) ;
// this.z = new Float64Vector( zdim ) ;
}
/**
* Advance to next time step, advancing
time by dt.
*
* @param dt
* @return
*
*/
public void advance( double dt ) {
time = time+dt;
}
/**
* Get the continuous state vector.
*
* The state is returned as a Float64
vector for efficiency.
*/
public Vector<Double> getState() {
return x ;
}
/**
* Get the discrete state vector.
*
* The state is returned as a Float64
vector for efficiency.
*/
public Vector<Double> getDiscrete() {
return m ;
103
}
/**
* Get the event indicators.
*
* The state is returned as a Float64
vector for efficiency.
*/
public Vector<Double>
getEventIndicators() {
return z ;
}
/**
* Get the continuous state derivative
vector.
*
* The state is returned as a Float64
vector for efficiency.
*/
public Vector<Double> getDer() {
return xdot ;
}
/**
* Get current time.
*/
public double getTime() {
return time ;
}
/**
* Set the continuous state vector and
update time.
*
* @param x
* @param dt
*/
public void updateState(
Vector<Double> x ) {
this.x = x ;
}
}
EulerSolver.Java
package jrt;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Vector;
import org.jscience.mathematics.vector.* ;
import org.jscience.physics.amount.* ;
import javax.measure.quantity.* ;
/**
* Euler's method for numerical
integration.
*
* @author [email protected]
*
*/
public class EulerSolver {
static BufferedWriter bw ;
/**
* Solve the system using Euler's
method.
*
* @param dt
* @param data
* @param model
* @throws IOException
*/
public static void main (double dt,
SimData data, SuperModel model, String
filename) throws IOException
{
FileWriter fw = new
FileWriter( filename );
bw = new BufferedWriter(fw);
long startSimulationTime =
System.currentTimeMillis();
Vector<Double> x =
data.getState() ;
Vector<Double> xdot =
data.getDer() ;
bw.write(data.start+ ",");
for (int i =0;i<x.size();i++)
bw.write(data.getState().elementAt(i).toStr
ing()+",");
for (int i =0;i<xdot.size();i++)
{
104
bw.write(data.getDer().elementAt(i).toStri
ng());
if ( i != (xdot.size())-1)
bw.write( "," ) ;
}
bw.newLine() ;
while(data.time < data.stop){
Solver(data,model,dt);
CSVBuilder(data);
}
long endSimulationTime =
System.currentTimeMillis(); // end
simulation time measurements
System.out.println("starttime:"+
startSimulationTime + "endtime:" +
endSimulationTime );
System.out.println("Simulation
took: " + (endSimulationTime -
startSimulationTime)+ " milliseconds.\n");
bw.close() ;
}
public static void Solver( SimData
data ,SuperModel model, double dt )
throws IOException {
Vector<Double> x =
data.getState() ;
Vector<Double> xdot =
data.getDer() ;
for(int i=0;i<x.size();i++)
{
x.set(i, x.get(i)+
xdot.get(i)*dt);
}
data.advance( dt ) ;
model.functionODE();
}
public static void
CSVBuilder(SimData data) throws
IOException {
bw.write(data.time + ",");
int n = data.size;
for( int i=0 ; i < n ; i++ ) {
bw.write(data.getState().elementAt(i).toStr
ing()+",");
//
bw.write(data.getState().toString()+",");
bw.write(data.getDer().elementAt(i
).toString());
if ( i != n-1 )
bw.write( ", " ) ;
}
bw.newLine() ;
}
}
SuperModel.Java
package jrt;
import java.io.IOException;
import org.jscience.physics.amount.* ;
import javax.measure.quantity.* ;
/**
* A Modelica Model for simulation.
*
* This is the superclass for any model
class generated from modelica.
* As the core of the Modelica model, this
class needs properties similar
* to those of FMI for model exchange.
* Other features can be wrapped around
SuperModel objects, such as the
* SimModel class which provides features
comparable to FMI for cosimulation.
*
* A SuperClass object has two major
components, namely a StaticModel
* object for static information about the
model and a SimData object
* for the dynamic variable values.
*
* Comparing to the C code generation,
* SIMULATION_INFO is covered by
this class.
* SIMULATION_DATA is covered by
the SimData class.
105
* MODEL_DATA is covered by the
StaticModel class.
*
* @author [email protected]
*
*/
public abstract class SuperModel {
private StaticModel model ;
private SimData data ;
private Amount<Duration> time ;
private Boolean initialised=false ;
/* MAIN INTERFACE METHODS */
/**
* Constructor.
*
* @param m The static model to be
simulated
*/
SuperModel( ) {
}
/**
* Initialise the object.
* This should always be called once
before any other method.
*/
public void init() {
if ( this.initialised ) return ;
this.data = new SimData(
model.xdim(), model.mdim(),
model.zdim() ) ;
}
/** Getter for the SimData object.
*/
public SimData getData() {
return this.data ;
}
/**
* Generic getter, taking the identifier of
a variable as argument.
*
* The result is returned as a JScience
Amount object, making sure
* that it has a defined quantity and is
unit independent.
*
* @param s
* @return
*/
public Amount<?> getValue( String s )
{
throw new RuntimeException(
"Not implemented yet" ) ;
}
/**
* Generic setter, using the variable
identifier as a String.
*
* The value is given as a JScience
Amount object, making sure
* it has a defined quantity and is
independent of unit.
*
* @param s
* @param a
*/
public void setValue( String s,
Amount<?> a ) {
throw new RuntimeException(
"Not implemented yet" ) ;
}
/**
* Solve the model for the next time
step, advancing time by dt.
*
* @param dt
*
*/
public void advance(
Amount<Duration> dt ) {
time = time.plus(dt) ;
}
/**
* This corresponds to the functionODE
function which is
* code generated in the case of C.
Investigate.
*
106
* Should this be protected?
*/
public abstract void functionODE() ;
/* public Amount<Duration> getTime()
{
return data.getTime() ;
}*/
}
StaticModel.Java
package jrt;
import java.util.ArrayList;
/**
* A ModelicaModel with its static
information.
*
* The static model includes comments and
descriptions of the
* variables as well as range, initialisation
values, etc.
* It does not include any information
about simulation of the
* model.
*
* Essentially, the StaticModel is a
collection of ModelicaVariabel
* and ModelicaEquation objects.
*
* @author [email protected]
*
*/
public class StaticModel {
private ArrayList<ModelicaVariable>
variables ;
private ArrayList<ModelicaEquation>
equations ;
StaticModel() {
variables = new
ArrayList<ModelicaVariable>() ;
equations = new
ArrayList<ModelicaEquation>() ;
}
/**
* Add the given variable to the model.
*
* @param v
*/
public void addVariable(
ModelicaVariable v ) {
variables.add(v) ;
}
/**
* Add the given equation to the model.
* @param e
*/
public void addEquation(
ModelicaEquation e ) {
equations.add(e) ;
}
public int mdim() {
throw new RuntimeException() ;
}
public int xdim() {
throw new RuntimeException() ;
}
public int zdim() {
throw new RuntimeException() ;
}
ModelicaVariable.Java
package jrt;
/**
* Static information about a single
variable in the model.
*
* This represents a single variable in the
model and records
* static information.
*
* @author georg
*
*/
public abstract class ModelicaVariable {
// The following three come from
VAR_INFO in the C code.
private int id ;
private String name ;
107
private String comment ;
// We should also have a file info
field for diagnostics.
/**
* Return the ID of the variable.
*
* @return
*/
public int get_id() {
return id ;
}
/**
* Return the name of the variable.
*
* @return
*/
public String get_name() {
return name ;
}
/**
* Return the descriptive comment.
*
* @return
*/
public String get_comment() {
return comment ;
}
}
ModelicaVariable.Java
package jrt;
/**
* A single equation in the modelica
model.
*
* @author georg
*
*/
public class ModelicaEquation {
}
Linköping University Electronic Press
Upphovsrätt
Detta dokument hålls tillgängligt på Internet – eller dess framtida ersättare –från
publiceringsdatum under förutsättning att inga extraordinära omständigheter
uppstår.
Tillgång till dokumentet innebär tillstånd för var och en att läsa, ladda ner,
skriva ut enstaka kopior för enskilt bruk och att använda det oförändrat för icke-
kommersiell forskning och för undervisning. Överföring av upphovsrätten vid
en senare tidpunkt kan inte upphäva detta tillstånd. All annan användning av
dokumentet kräver upphovsmannens medgivande. För att garantera äktheten,
säkerheten och tillgängligheten finns lösningar av teknisk och administrativ art.
Upphovsmannens ideella rätt innefattar rätt att bli nämnd som upphovsman i
den omfattning som god sed kräver vid användning av dokumentet på ovan be-
skrivna sätt samt skydd mot att dokumentet ändras eller presenteras i sådan form
eller i sådant sammanhang som är kränkande för upphovsmannens litterära eller
konstnärliga anseende eller egenart.
För ytterligare information om Linköping University Electronic Press se för-
lagets hemsida http://www.ep.liu.se/
Copyright
The publishers will keep this document online on the Internet – or its possible
replacement –from the date of publication barring exceptional circumstances.
The online availability of the document implies permanent permission for
anyone to read, to download, or to print out single copies for his/hers own use
and to use it unchanged for non-commercial research and educational purpose.
Subsequent transfers of copyright cannot revoke this permission. All other uses
of the document are conditional upon the consent of the copyright owner. The
publisher has taken technical and administrative measures to assure authenticity,
security and accessibility.
According to intellectual property law the author has the right to be
mentioned when his/her work is accessed as described above and to be protected
against infringement.
For additional information about the Linköping University Electronic Press
and its procedures for publication and for assurance of document integrity,
please refer to its www home page: http://www.ep.liu.se/.
© MANOKAR MUNISAMY