Skip to content

Commit

Permalink
Adding spatialDistribution to Backend and C runtime (#7299)
Browse files Browse the repository at this point in the history
* Adding spatialDistribution to Backend and C runtime

  - Backend generates evaluate and store equation for each spatialDistribution operator.
  - New C code generated for spatialDistribution equations.
  - Added zero-crossing function for spatialDistribution.
  - C Runtime handling spatialDistribution evaluation.
  - Testcases in testsuite/simulation/modelica/spatialDistribution

Co-authored-by: kabdelhak <38032125+kabdelhak@users.noreply.github.com>
  • Loading branch information
AnHeuermann and kabdelhak committed Mar 16, 2021
1 parent a7d4363 commit e2823a8
Show file tree
Hide file tree
Showing 45 changed files with 2,144 additions and 28 deletions.
51 changes: 29 additions & 22 deletions OMCompiler/Compiler/BackEnd/BackendDAECreate.mo
Expand Up @@ -631,51 +631,58 @@ protected
HashTableExpToIndex.HashTable ht;
algorithm
ht := HashTableExpToIndex.emptyHashTable();
(outDAE, outTree, (_, (_, _, _, outTimeEvents))) := DAEUtil.traverseDAE(inDAE, functionTree, Expression.traverseSubexpressionsHelper, (transformBuiltinExpression, (ht, 0, 0, {})));
(outDAE, outTree, (_, (_, _, _, _, outTimeEvents))) := DAEUtil.traverseDAE(inDAE, functionTree, Expression.traverseSubexpressionsHelper, (transformBuiltinExpression, (ht, 0, 0, 0, {})));
end processBuiltinExpressions;

protected function transformBuiltinExpression "author: lochel
Helper for transformBuiltinExpressions"
input DAE.Exp inExp;
input tuple<HashTableExpToIndex.HashTable, Integer /*iDelay*/, Integer /*iSample*/, list<BackendDAE.TimeEvent>> inTuple;
input tuple<HashTableExpToIndex.HashTable, Integer /*iDelay*/, Integer /*iSample*/, Integer /*iSpatial*/, list<BackendDAE.TimeEvent>> inTuple;
output DAE.Exp outExp;
output tuple<HashTableExpToIndex.HashTable, Integer /*iDelay*/, Integer /*iSample*/, list<BackendDAE.TimeEvent>> outTuple;
output tuple<HashTableExpToIndex.HashTable, Integer /*iDelay*/, Integer /*iSample*/, Integer /*iSpatial*/, list<BackendDAE.TimeEvent>> outTuple;
algorithm
(outExp,outTuple) := matchcontinue (inExp, inTuple)
(outExp,outTuple) := match (inExp, inTuple)
local
DAE.Exp start, interval;
list<DAE.Exp> es;
HashTableExpToIndex.HashTable ht;
Integer iDelay, iSample, i;
Integer iDelay, iSample, iSpatial, i;
list<BackendDAE.TimeEvent> timeEvents;
DAE.CallAttributes attr;

// delay [already in ht]
case (DAE.CALL(Absyn.IDENT("delay"), es, attr), (ht, _, _, _)) equation
i = BaseHashTable.get(inExp, ht);
then (DAE.CALL(Absyn.IDENT("delay"), DAE.ICONST(i)::es, attr), inTuple);
case (DAE.CALL(Absyn.IDENT("delay"), es, attr), (ht, _, _, _, _)) guard(BaseHashTable.hasKey(inExp, ht))
then (DAE.CALL(Absyn.IDENT("delay"), DAE.ICONST(BaseHashTable.get(inExp, ht))::es, attr), inTuple);

// delay [not yet in ht]
case (DAE.CALL(Absyn.IDENT("delay"), es, attr), (ht, iDelay, iSample, timeEvents)) equation
ht = BaseHashTable.add((inExp, iDelay+1), ht);
then (DAE.CALL(Absyn.IDENT("delay"), DAE.ICONST(iDelay)::es, attr), (ht, iDelay+1, iSample, timeEvents));
case (DAE.CALL(Absyn.IDENT("delay"), es, attr), (ht, iDelay, iSample, iSpatial, timeEvents)) algorithm
ht := BaseHashTable.add((inExp, iDelay+1), ht);
then (DAE.CALL(Absyn.IDENT("delay"), DAE.ICONST(iDelay)::es, attr), (ht, iDelay+1, iSample, iSpatial, timeEvents));

// spatialDistribution [already in ht]
case (DAE.CALL(Absyn.IDENT("spatialDistribution"), es, attr), (ht, _, _, _, _)) guard(BaseHashTable.hasKey(inExp, ht))
then (DAE.CALL(Absyn.IDENT("spatialDistribution"), DAE.ICONST(BaseHashTable.get(inExp, ht))::es, attr), inTuple);

// spatialDistribution [not yet in ht]
case (DAE.CALL(Absyn.IDENT("spatialDistribution"), es, attr), (ht, iDelay, iSample, iSpatial, timeEvents)) algorithm
ht := BaseHashTable.add((inExp, iSpatial+1), ht);
then (DAE.CALL(Absyn.IDENT("spatialDistribution"), DAE.ICONST(iSpatial)::es, attr), (ht, iDelay, iSample, iSpatial+1, timeEvents));

// sample [already in ht]
case (DAE.CALL(Absyn.IDENT("sample"), es as {_, interval}, attr), (ht, _, _, _))
guard (not Types.isClockOrSubTypeClock(Expression.typeof(interval))) equation
i = BaseHashTable.get(inExp, ht);
then (DAE.CALL(Absyn.IDENT("sample"), DAE.ICONST(i)::es, attr), inTuple);
case (DAE.CALL(Absyn.IDENT("sample"), es as {_, interval}, attr), (ht, _, _, _, _))
guard (not Types.isClockOrSubTypeClock(Expression.typeof(interval)) and BaseHashTable.hasKey(inExp, ht)) equation
then (DAE.CALL(Absyn.IDENT("sample"), DAE.ICONST(BaseHashTable.get(inExp, ht))::es, attr), inTuple);

// sample [not yet in ht]
case (DAE.CALL(Absyn.IDENT("sample"), es as {start, interval}, attr), (ht, iDelay, iSample, timeEvents))
guard (not Types.isClockOrSubTypeClock(Expression.typeof(interval))) equation
iSample = iSample+1;
timeEvents = List.appendElt(BackendDAE.SAMPLE_TIME_EVENT(iSample, start, interval), timeEvents);
ht = BaseHashTable.add((inExp, iSample), ht);
then (DAE.CALL(Absyn.IDENT("sample"), DAE.ICONST(iSample)::es, attr), (ht, iDelay, iSample, timeEvents));
case (DAE.CALL(Absyn.IDENT("sample"), es as {start, interval}, attr), (ht, iDelay, iSample, iSpatial, timeEvents))
guard (not Types.isClockOrSubTypeClock(Expression.typeof(interval))) algorithm
iSample := iSample+1;
timeEvents := List.appendElt(BackendDAE.SAMPLE_TIME_EVENT(iSample, start, interval), timeEvents);
ht := BaseHashTable.add((inExp, iSample), ht);
then (DAE.CALL(Absyn.IDENT("sample"), DAE.ICONST(iSample)::es, attr), (ht, iDelay, iSample, iSpatial, timeEvents));

else (inExp,inTuple);
end matchcontinue;
end match;
end transformBuiltinExpression;

/*
Expand Down
24 changes: 24 additions & 0 deletions OMCompiler/Compiler/BackEnd/BackendDAEUtil.mo
Expand Up @@ -3138,6 +3138,12 @@ algorithm
(_, _, tpl) := traversingadjacencyRowExpSolvableFinder(e2, inTpl);
then traversingadjacencyRowExpSolvableFinder(e1, tpl);

// only traverse position and direction for spatialDistribution, not the inputs!
case (DAE.CALL(path=Absyn.IDENT(name="spatialDistribution"), expLst = {_, _, _, e1, e2, _, _}), _)
algorithm
(_, _, tpl) := traversingadjacencyRowExpSolvableFinder(e2, inTpl);
then traversingadjacencyRowExpSolvableFinder(e1, tpl);

// use the inlined function to analyze the ocuring variables
case (DAE.CALL(path=Absyn.IDENT()), (vars, pa, visitedPaths, isInitial, ofunctionTree as SOME(functionTree))) guard not AvlSetPath.hasKey(visitedPaths, inExp.path)
algorithm
Expand Down Expand Up @@ -3526,6 +3532,12 @@ algorithm
(_, _, tpl) := traversingadjacencyRowExpFinder(e2, inTpl);
then traversingadjacencyRowExpFinder(e1, tpl);

// only traverse position and direction for spatialDistribution, not the inputs!
case (DAE.CALL(path=Absyn.IDENT(name="spatialDistribution"), expLst = {_, _, _, e1, e2, _, _}), _)
algorithm
(_, _, tpl) := traversingadjacencyRowExpFinder(e2, inTpl);
then traversingadjacencyRowExpFinder(e1, tpl);

case (DAE.ASUB(exp=DAE.CREF(componentRef=cr), sub={DAE.ICONST(i)}), (vars, pa, isInitial))
equation
cr = ComponentReference.subscriptCrefWithInt(cr, i);
Expand Down Expand Up @@ -3678,6 +3690,12 @@ algorithm
(_, _, tpl) := traversingadjacencyRowExpFinderwithInput(e2, inTpl);
then traversingadjacencyRowExpFinderwithInput(e1, tpl);

// only traverse position and direction for spatialDistribution, not the inputs!
case (DAE.CALL(path=Absyn.IDENT(name="spatialDistribution"), expLst = {_, _, _, e1, e2, _, _}), _)
algorithm
(_, _, tpl) := traversingadjacencyRowExpFinderwithInput(e2, inTpl);
then traversingadjacencyRowExpFinderwithInput(e1, tpl);

/* pre(v) is considered a known variable */
case (DAE.CALL(path = Absyn.IDENT(name = "pre"),expLst = {DAE.CREF()}),_) then (inExp,false,inTpl);

Expand Down Expand Up @@ -5983,6 +6001,12 @@ algorithm
(_, _, tpl) := traversingAdjacencyRowExpSolvableEnhancedFinder(e2, inTpl);
then traversingAdjacencyRowExpSolvableEnhancedFinder(e1, tpl);

// only traverse position and direction for spatialDistribution, not the inputs!
case (DAE.CALL(path=Absyn.IDENT(name="spatialDistribution"), expLst = {_, _, _, e1, e2, _, _}), _)
algorithm
(_, _, tpl) := traversingAdjacencyRowExpSolvableEnhancedFinder(e2, inTpl);
then traversingAdjacencyRowExpSolvableEnhancedFinder(e1, tpl);

else (inExp, true, inTpl);
end matchcontinue;
end traversingAdjacencyRowExpSolvableEnhancedFinder;
Expand Down
24 changes: 24 additions & 0 deletions OMCompiler/Compiler/BackEnd/FindZeroCrossings.mo
Expand Up @@ -968,6 +968,7 @@ algorithm
(outExp,cont,outTpl) := match (inExp, inTpl)
local
DAE.Exp e, e1, e2, e_1, e_2, eres, eres1;
DAE.Exp index, in0, in1, x, dir, initPnts, initVals;
BackendDAE.Variables vars, globalKnownVars;
BackendDAE.ZeroCrossingSet zeroCrossings, zc_lst, samples;
DoubleEnded.MutableList<BackendDAE.ZeroCrossing> relations;
Expand Down Expand Up @@ -996,6 +997,29 @@ algorithm
end if;
then (inExp, true, inTpl);

// spatialDistribution() can trigger events which are handled individually via the function spatialDistributionZeroCrossing() > 0
case (DAE.CALL(path=Absyn.IDENT(name="spatialDistribution"), expLst = {index, in0, in1, x, dir, initPnts, initVals}, attr = attr), ((zeroCrossings, relations, samples, numMathFunctions), tp1 as (eq_count, _, _)))
algorithm
// traverse relevant arguments
(in0, ((_, relations, samples, numMathFunctions), tp1)) := Expression.traverseExpTopDown(in0, collectZC, ((ZeroCrossings.new(), relations, samples, numMathFunctions), tp1));
(in1, ((_, relations, samples, numMathFunctions), tp1)) := Expression.traverseExpTopDown(in1, collectZC, ((ZeroCrossings.new(), relations, samples, numMathFunctions), tp1));
(x, ((_, relations, samples, numMathFunctions), tp1)) := Expression.traverseExpTopDown(x, collectZC, ((ZeroCrossings.new(), relations, samples, numMathFunctions), tp1));
(dir, ((_, relations, samples, numMathFunctions), tp1 as (eq_count, _, _))) := Expression.traverseExpTopDown(dir, collectZC, ((ZeroCrossings.new(), relations, samples, numMathFunctions), tp1));

// create zero crossing function
eres1 := DAE.CALL(Absyn.IDENT("spatialDistributionZeroCrossing"), {index, DAE.ICONST(DoubleEnded.length(relations)), x, dir}, attr);
e_1 := DAE.RELATION(eres1, DAE.GREATER(DAE.T_REAL_DEFAULT) ,DAE.RCONST(0.0), DoubleEnded.length(relations), NONE());
zc := createZeroCrossing(eres1, {eq_count});
(eres, relations) := zcIndexRelation(e_1, relations, DoubleEnded.length(relations), zc);
zc := createZeroCrossing(eres, {eq_count});
(DAE.RELATION(index=itmp), zeroCrossings, _) := zcIndex(eres, zeroCrossings, DoubleEnded.length(relations), zc);

if Flags.isSet(Flags.RELIDX) then
print("collectZC result zc: " + ExpressionDump.printExpStr(eres) + " index: " + intString(itmp) + "\n");
end if;

then (DAE.CALL(Absyn.IDENT(name="spatialDistribution"), {index, in0, in1, x, dir, initPnts, initVals}, attr), true, ((zeroCrossings, relations, samples, numMathFunctions), tp1));

// function with discrete expressions generate no zerocrossing
case (DAE.LUNARY(exp=e1), ((_, relations, _, _), (_, vars, globalKnownVars)))
guard not BackendDAEUtil.hasExpContinuousParts(e1, vars, globalKnownVars)
Expand Down
22 changes: 22 additions & 0 deletions OMCompiler/Compiler/SimCode/SimCode.mo
Expand Up @@ -134,6 +134,7 @@ uniontype SimCode
ExtObjInfo extObjInfo;
SimCodeFunction.MakefileParams makefileParams;
DelayedExpression delayedExps;
SpatialDistributionInfo spatialInfo;
list<JacobianMatrix> jacobianMatrixes;
Option<SimulationSettings> simulationSettingsOpt;
String fileNamePrefix, fullPathPrefix "Used in FMI where files are generated in a special directory";
Expand Down Expand Up @@ -208,6 +209,26 @@ uniontype DelayedExpression
end DELAYED_EXPRESSIONS;
end DelayedExpression;

uniontype SpatialDistributionInfo
record SPATIAL_DISTRIBUTION_INFO
list<SpatialDistribution> spatialDistributions;
Integer maxIndex;
end SPATIAL_DISTRIBUTION_INFO;
end SpatialDistributionInfo;

uniontype SpatialDistribution
record SPATIAL_DISTRIBUTION
Integer index "uniqueIndex";
DAE.Exp in0 "input 0";
DAE.Exp in1 "input 1";
DAE.Exp pos "current pos";
DAE.Exp dir "flow direction";
DAE.Exp initPnts "initial grid points";
DAE.Exp initVals "initial grid values";
Integer initSize "number of initial points";
end SPATIAL_DISTRIBUTION;
end SpatialDistribution;

uniontype UnitDefinition "unitDefinitions for fmi modelDescription.xml"
record UNITDEFINITION
String name;
Expand Down Expand Up @@ -247,6 +268,7 @@ uniontype ModelInfo "Container for metadata about a Modelica model."
//Files files "all the files from SourceInfo and DAE.ElementSource";
Integer nClocks;
Integer nSubClocks;
Integer nSpatialDistributions;
Boolean hasLargeLinearEquationSystems; // True if model has large linear eq. systems that are crucial for performance.
list<SimEqSystem> linearSystems;
list<SimEqSystem> nonLinearSystems;
Expand Down
6 changes: 5 additions & 1 deletion OMCompiler/Compiler/SimCode/SimCodeMain.mo
Expand Up @@ -543,6 +543,7 @@ algorithm
(CodegenC.simulationFile_dae, "_16dae.c"),
(CodegenC.simulationFile_dae_header, "_16dae.h"),
(CodegenC.simulationFile_inl, "_17inl.c"),
(CodegenC.simulationFile_spd, "_18spd.c"),
(CodegenC.simulationHeaderFile, "_model.h")
} loop
(func,str) := f;
Expand Down Expand Up @@ -1229,6 +1230,7 @@ protected
SimCode.ExtObjInfo extObjInfo;
SimCode.HashTableCrefToSimVar crefToSimVarHT;
SimCodeFunction.MakefileParams makefileParams;
SimCode.SpatialDistributionInfo spatialInfo;
list<tuple<Integer, tuple<DAE.Exp, DAE.Exp, DAE.Exp>>> delayedExps;
Integer maxDelayedExpIndex;
Integer uniqueEqIndex = 1;
Expand Down Expand Up @@ -1285,6 +1287,7 @@ algorithm
makefileParams := SimCodeFunctionUtil.createMakefileParams(includeDirs, libs, libPaths, false, false);
//create delay exps
(delayedExps, maxDelayedExpIndex) := SimCodeUtil.extractDelayedExpressions(inBackendDAE);
spatialInfo := SimCodeUtil.extractSpatialDistributionInfo(inBackendDAE);

// created event suff e.g. zeroCrossings, samples, ...
timeEvents := inBackendDAE.shared.eventInfo.timeEvents;
Expand Down Expand Up @@ -1340,7 +1343,7 @@ algorithm
// disable start value calculation, it's only helpful in case of algebraic loops
// and they are not present in DAEmode
tmpB := FlagsUtil.set(Flags.NO_START_CALC, true);
modelInfo := SimCodeUtil.createModelInfo(className, p, emptyBDAE, inInitDAE, functions, {}, 0, fileDir, 0, tempVars);
modelInfo := SimCodeUtil.createModelInfo(className, p, emptyBDAE, inInitDAE, functions, {}, 0, spatialInfo.maxIndex, fileDir, 0, tempVars);
FlagsUtil.set(Flags.NO_START_CALC, tmpB);

//create hash table
Expand Down Expand Up @@ -1457,6 +1460,7 @@ algorithm
extObjInfo = extObjInfo,
makefileParams = makefileParams,
delayedExps = SimCode.DELAYED_EXPRESSIONS(delayedExps, maxDelayedExpIndex),
spatialInfo = spatialInfo,
jacobianMatrixes = SymbolicJacs,
simulationSettingsOpt = simSettingsOpt,
fileNamePrefix = filenamePrefix,
Expand Down
42 changes: 41 additions & 1 deletion OMCompiler/Compiler/SimCode/SimCodeUtil.mo
Expand Up @@ -274,6 +274,7 @@ protected
Integer countSenParams;
list<tuple<Integer, Integer>> equationSccMapping, eqBackendSimCodeMapping;
list<tuple<Integer, tuple<DAE.Exp, DAE.Exp, DAE.Exp>>> delayedExps;
SimCode.SpatialDistributionInfo spatialInfo;
BackendDAE.InlineData inlineData;
list<SimCodeVar.SimVar> inlineSimKnVars;
BackendDAE.Variables emptyVars;
Expand Down Expand Up @@ -448,6 +449,7 @@ algorithm
if debug then execStat("simCode: extractDiscreteModelVars"); end if;
makefileParams := SimCodeFunctionUtil.createMakefileParams(includeDirs, libs, libPaths, false, isFMU);
(delayedExps, maxDelayedExpIndex) := extractDelayedExpressions(dlow);
spatialInfo := extractSpatialDistributionInfo(dlow);
execStat("simCode: created of all other equations (e.g. parameter, nominal, assert, etc)");

// append removed equation to all equations, since these are actually
Expand All @@ -472,7 +474,7 @@ algorithm
if debug then execStat("simCode: createStateSets"); end if;

// create model info
modelInfo := createModelInfo(inClassName, program, dlow, inInitDAE, functions, {}, numStateSets, inFileDir, listLength(clockedSysts), tempvars);
modelInfo := createModelInfo(inClassName, program, dlow, inInitDAE, functions, {}, numStateSets, spatialInfo.maxIndex, inFileDir, listLength(clockedSysts), tempvars);
if debug then execStat("simCode: createModelInfo and variables"); end if;

//build labels
Expand Down Expand Up @@ -710,6 +712,7 @@ algorithm
extObjInfo = extObjInfo,
makefileParams = makefileParams,
delayedExps = SimCode.DELAYED_EXPRESSIONS(delayedExps, maxDelayedExpIndex),
spatialInfo = spatialInfo,
jacobianMatrixes = SymbolicJacs,
simulationSettingsOpt = simSettingsOpt,
fileNamePrefix = filenamePrefix,
Expand Down Expand Up @@ -5584,6 +5587,41 @@ algorithm
end match;
end extractIdAndExpFromDelayExp;

function extractSpatialDistributionInfo
"Create spatialDistribution simCode from backend DAE."
input BackendDAE.BackendDAE dlow;
output SimCode.SpatialDistributionInfo spatialInfo;
protected
list<SimCode.SpatialDistribution> spatial_lst;
Mutable<Integer> maxIndex_ptr = Mutable.create(-1);
algorithm
((_,spatial_lst)) := BackendDAEUtil.traverseBackendDAEExps(dlow, Expression.traverseSubexpressionsHelper, (function extractSpatialDistributionInfoExp(maxIndex_ptr = maxIndex_ptr), {}));
spatialInfo := SimCode.SPATIAL_DISTRIBUTION_INFO(spatial_lst, Mutable.access(maxIndex_ptr));
end extractSpatialDistributionInfo;

function extractSpatialDistributionInfoExp
input output DAE.Exp callExp;
input output list<SimCode.SpatialDistribution> spatialInfo;
input Mutable<Integer> maxIndex_ptr;
algorithm
spatialInfo := match callExp
local
Integer i, initSize;
DAE.Exp in0, in1, pos, dir, initPnts, initVals;
case DAE.CALL(path = Absyn.IDENT("spatialDistribution"), expLst={DAE.ICONST(i), in0, in1, pos, dir, initPnts, initVals})
algorithm
if i > Mutable.access(maxIndex_ptr) then
Mutable.update(maxIndex_ptr, i);
end if;
if not Expression.sizeOf(Expression.typeof(initPnts)) == Expression.sizeOf(Expression.typeof(initVals)) then
Error.addInternalError("function extractDelayedExpressions failed: initialPoints and initialValues of spatialDistribution are not of the same size.", sourceInfo());
end if;
initSize := Expression.sizeOf(Expression.typeof(initPnts));
then SimCode.SPATIAL_DISTRIBUTION(i, in0, in1, pos, dir, initPnts, initVals, initSize) :: spatialInfo;
else spatialInfo;
end match;
end extractSpatialDistributionInfoExp;

public function createExtObjInfo
input BackendDAE.Shared shared;
output SimCode.ExtObjInfo extObjInfo;
Expand Down Expand Up @@ -7238,6 +7276,7 @@ public function createModelInfo
input list<SimCodeFunction.Function> functions;
input list<String> labels;
input Integer numStateSets;
input Integer numSpatialDistributions;
input String fileDir;
input Integer nSubClock;
input list<SimCodeVar.SimVar> tempVars;
Expand Down Expand Up @@ -7293,6 +7332,7 @@ algorithm
List.sort(program.classes, AbsynUtil.classNameGreater),
arrayLength(dlow.shared.partitionsInfo.basePartitions),
arrayLength(dlow.shared.partitionsInfo.subPartitions),
numSpatialDistributions + 1,
hasLargeEqSystems, {}, {}, unitDefinitions);
else
Error.addInternalError("createModelInfo failed", sourceInfo());
Expand Down

0 comments on commit e2823a8

Please sign in to comment.