Skip to content

Commit

Permalink
[codegen/simcode] Improve code generation for assignment of records i…
Browse files Browse the repository at this point in the history
…n simulation context. (#546)

- We now split up the record memebers and then create assignments for each member.
    We used to textually generate '=' assignments for the memebers.
    This does not work if the member is a record or an array.
    Instead we now actually create assignment expressions and then send them back to the template
    functions.

Fix generation of auxiliary, residual and algebraicstate vars for daeMode

  - setVariableIndexHelper does not update the index so it is not the one that
    should be used.
    It also seems uneccsary to add the algebraicstateVars to the hastable manually.
    They are already there.

  - disable the creation of a new hastable after we had added the
    auxiliary vars to the old one. Otherwise we will discard them.

  - Since it was discarding some of the variables added to the hastable
    daemode used #defines to access these vars instead of actaully fixing the
    problem. The defines are disabled now.

Fix creation of an array expression from a list of crefs.

  - Expanded crefs can be multidimensional. Therefore we should
    create multidimensional ARRAY expression in such cases.

  - Sometimes we get unevaluated dimensions in a simulation variable cref.
    In this case we might not be able to correctly exapnd the cref to an ARRAY exp
    if it is multidimensional. Since we do not know where to break up the list of exps.
    However there is now a workaround to let this happen if the cref was a one dimensional
    array. We jsut create an array with the unevaluated dim exp and hope it is correct.
    The proper way to fix this is to fix the FrontEnd to use evaluated dims for all crefs.
    But I am not going to try and do that now.
  • Loading branch information
mahge committed Nov 22, 2019
1 parent 58b266e commit 6192db4
Show file tree
Hide file tree
Showing 6 changed files with 295 additions and 191 deletions.
82 changes: 50 additions & 32 deletions OMCompiler/Compiler/FrontEnd/Expression.mo
Expand Up @@ -2186,6 +2186,10 @@ algorithm
case DAE.DIM_BOOLEAN() then 2;
case DAE.DIM_EXP(exp = DAE.ICONST(integer = i)) then i;
case DAE.DIM_EXP(exp = DAE.ENUM_LITERAL(index = i)) then i;
// else algorithm
// Error.addInternalError("Function dimensionSize failed to extract size from dimension. Make sure
// you have dimension that is evaluated if you want to use this function.", sourceInfo());
// then fail();
end match;
end dimensionSize;

Expand Down Expand Up @@ -4704,66 +4708,74 @@ protected function listToArray2
input DAE.Type inType;
output DAE.Exp oExp;
algorithm
oExp := matchcontinue(inList, iDims, inType)
() := match(inList, iDims, inType)
local
Integer i;
DAE.Dimension d;
list<DAE.Exp> explst;
DAE.Exp arrexp;
DAE.Dimensions dims;
Boolean is_scalar;
DAE.Type ty;

case(_, {d}, _)
equation
i = dimensionSize(d);
true = i == listLength(inList);
then makeArrayFromList(inList);

case(_, {d}, _)
equation
i = dimensionSize(d);
true = i > listLength(inList);
Error.addMessage(Error.INTERNAL_ERROR, {"Expression.listToArray2: Not enough elements left in list to fit dimension."});
then
fail();
algorithm
is_scalar := not Types.isArray(inType);
if dimensionKnown(d) then
i := dimensionSize(d);
if i <> listLength(inList) then
Error.addMessage(Error.INTERNAL_ERROR, {"Expression.listToArray2: Number of elements in the list does not match the dimension size."});
fail();
else
ty := liftArrayR(inType, DAE.DIM_INTEGER(listLength(inList)));
oExp := DAE.ARRAY(ty, is_scalar, inList);
end if;
// We do not know the dimension size but we have only one dimension.
// WE just create a one dimensional array and hope for the best. This is needed for
// codegen when we have to expand an array crefexp to an array expression. Sometimes
// we get an unevaluated dimension for a model variable all the way down in codegen :(
else
ty := liftArrayR(inType, d);
oExp := DAE.ARRAY(ty, is_scalar, inList);
end if;
then ();

case(_, _ :: _ , _)
equation
(d, dims) = List.splitLast(iDims);
explst = listToArray3(inList,d,inType);
arrexp = listToArray2(explst,dims,inType);
algorithm
(d, dims) := List.splitLast(iDims);
explst := listToArray3(inList,d);
ty := liftArrayR(inType, DAE.DIM_INTEGER(listLength(explst)));
oExp := listToArray2(explst,dims,ty);
then
arrexp;
();

end matchcontinue;
end match;
end listToArray2;


protected function listToArray3
input list<DAE.Exp> inList;
input DAE.Dimension iDim;
input DAE.Type inType;
output list<DAE.Exp> oExps;
algorithm
oExps := match(inList, iDim, inType)
oExps := match(inList, iDim)
local
Integer i;
DAE.Dimension d;
list<DAE.Exp> explst, restexps, restarr;
DAE.Exp arrexp;

case({}, _, _) then {};
case({}, _) then {};

case(_, d, _)
case(_, d)
equation
i = dimensionSize(d);
if (i > listLength(inList))
then
if (i > listLength(inList)) then
Error.addMessage(Error.INTERNAL_ERROR, {"Expression.listToArray3: Not enough elements left in list to fit dimension."});
fail();
else
(explst, restexps) = List.split(inList,i);
arrexp = makeArrayFromList(explst);
restarr = listToArray3(restexps,d,inType);
restarr = listToArray3(restexps,d);
end if;
then
arrexp::restarr;
Expand Down Expand Up @@ -12129,14 +12141,20 @@ end makeVectorCall;


public function expandCrefs
input output DAE.Exp exp;
input DAE.Exp inExp;
output DAE.Exp outExp;
input output Integer dummy=0 "For traversal";
algorithm
exp := match exp
outExp := match inExp
local
DAE.Type ty;
case DAE.CREF(ty=DAE.T_ARRAY(ty=ty)) then makeArray(list(makeCrefExp(cr, ty) for cr in ComponentReference.expandCref(exp.componentRef, true)), exp.ty, not Types.isArray(ty));
else exp;
DAE.Type elem_ty, arr_ty;
list<DAE.Exp> exp_lst;
DAE.Exp exp;
case DAE.CREF(ty=arr_ty as DAE.T_ARRAY()) algorithm
exp_lst := list(makeCrefExp(cr, arr_ty.ty) for cr in ComponentReference.expandCref(inExp.componentRef, true));
exp := listToArray(exp_lst, arr_ty.dims);
then exp;
else inExp;
end match;
end expandCrefs;

Expand Down
52 changes: 52 additions & 0 deletions OMCompiler/Compiler/SimCode/SimCodeFunctionUtil.mo
Expand Up @@ -220,6 +220,58 @@ algorithm
end match;
end makeCrefRecordExp;

public function splitRecordAssignmentToMemberAssignments
"This function is used by the templates to split up a record assignment to
assignments of each of the members. This is needed in simulation context
since there is no 'record' per se. Instead the elements(locations) of the record are
scattered through the SIMVAR structure.

Note that this does not recurse to check if a member itself is a record as well i.e.
we generate an assignment of records. But since these assignments are sent the codegen
template we will indirectly come back here and resolve them."
input DAE.ComponentRef lhs_cref;
input DAE.Type lhs_type;
input String rhs_cref_str;
output list<DAE.Statement> outAssigns;
protected
DAE.ComponentRef rhs_cref;
algorithm

outAssigns := {};
rhs_cref := DAE.CREF_IDENT(rhs_cref_str, lhs_type, {});

_ := match lhs_type
local
DAE.ComponentRef l_v_cref,r_v_cref;
DAE.Exp l_v_exp, r_v_exp;
DAE.Statement stmt;

case DAE.T_COMPLEX() algorithm
for v in lhs_type.varLst loop
// l_v_cref := ComponentReference.crefPrependIdent(lhs_cref, v.name, {}, v.ty);
// r_v_cref := ComponentReference.crefPrependIdent(rhs_cref, v.name, {}, v.ty);

// l_v_exp := Expression.makeCrefExp(l_v_cref, v.ty);
// r_v_exp := Expression.makeCrefExp(r_v_cref, v.ty);

l_v_exp := makeCrefRecordExp(lhs_cref, v);
r_v_exp := makeCrefRecordExp(rhs_cref, v);

if Types.isArray(v.ty) then
stmt := DAE.STMT_ASSIGN_ARR(v.ty, l_v_exp, r_v_exp, DAE.emptyElementSource);
else
stmt := DAE.STMT_ASSIGN(v.ty, l_v_exp, r_v_exp, DAE.emptyElementSource);
end if;

outAssigns := stmt::outAssigns;
end for;

outAssigns := listReverse(outAssigns);
then ();

end match;
end splitRecordAssignmentToMemberAssignments;

public function derComponentRef
"Used by templates to derrive a cref in a der(cref) expression.
Particularly, this function is called for the C# code generator,
Expand Down
18 changes: 14 additions & 4 deletions OMCompiler/Compiler/SimCode/SimCodeMain.mo
Expand Up @@ -1305,11 +1305,19 @@ algorithm
// create SimCodeVars for algebraic states
algStateVars := BackendVariable.listVar(inBackendDAE.shared.daeModeData.algStateVars);
((algebraicStateVars, _)) := BackendVariable.traverseBackendDAEVars(algStateVars, SimCodeUtil.traversingdlowvarToSimvar, ({}, BackendVariable.emptyVars()));
SimCode.VARINFO(numStateVars=nStates) := modelInfo.varInfo;

algebraicStateVars := SimCodeUtil.sortSimVarsAndWriteIndex(algebraicStateVars, crefToSimVarHT);
(algebraicStateVars, _) := SimCodeUtil.setVariableIndexHelper(algebraicStateVars, 2*nStates);
crefToSimVarHT:= List.fold(algebraicStateVars,HashTableCrefSimVar.addSimVarToHashTable,crefToSimVarHT);

/* This lines seem to be not neccsary and actually problematic.
The algebraicStateVars are already in the simvars. Which means they are already addded
to the hastable somewhere above. Here we try to add them again but with wrong indexs because
setVariableIndexHelper does not actually update the indices we want. If you want to enable this
for some reason use rewriteIndex.
*/
// SimCode.VARINFO(numStateVars=nStates) := modelInfo.varInfo;
// // (algebraicStateVars, _) := SimCodeUtil.setVariableIndexHelper(algebraicStateVars, 2*nStates);
// (algebraicStateVars, _) := SimCodeUtil.rewriteIndex(algebraicStateVars, 2*nStates);
// crefToSimVarHT:= List.fold(algebraicStateVars,HashTableCrefSimVar.addSimVarToHashTable,crefToSimVarHT);

// create DAE mode Sparse pattern and TODO: Jacobians
// sparsity pattern generation
Expand All @@ -1323,7 +1331,9 @@ algorithm
modelInfo := SimCodeUtil.addNumEqns(modelInfo, uniqueEqIndex-listLength(jacobianEquations));

// update hash table
crefToSimVarHT := SimCodeUtil.createCrefToSimVarHT(modelInfo);
// mahge: This creates a new crefToSimVarHT discarding everything added upto here
// The updated variable 'numEquations' (by SimCodeUtil.addNumEqns) is not even used in createCrefToSimVarHT :/
// crefToSimVarHT := SimCodeUtil.createCrefToSimVarHT(modelInfo);

simCode := SimCode.SIMCODE(modelInfo,
{}, // Set by the traversal below...
Expand Down
41 changes: 22 additions & 19 deletions OMCompiler/Compiler/Template/CodegenC.tpl
Expand Up @@ -858,21 +858,23 @@ template defineSimVarArray(SimVar simVar, String arrayName)
case SIMVAR(arrayCref=SOME(c),aliasvar=NOALIAS()) then
<<
/* <%crefStrNoUnderscore(c)%> */
#define <%cref(c)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]
// #define <%cref(c)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]

/* <%crefStrNoUnderscore(name)%> */
#define <%cref(name)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]
// #define <%cref(name)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]

>>
case SIMVAR(aliasvar=NOALIAS()) then
<<
/* <%crefStrNoUnderscore(name)%> */
#define <%cref(name)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]
// #define <%cref(name)%> data->simulationInfo->daeModeData-><%arrayName%>[<%index%>]

>>
end match
end defineSimVarArray;

// TODO: This is probably not relevant anymore can be removed. We access residual and auxialry
// variables of daemode using cref2simvar now. No need to define them.
template simulationFile_dae_header(SimCode simCode)
"DAEmode header generation"
::=
Expand Down Expand Up @@ -5939,22 +5941,23 @@ match ty
error(sourceInfo(), 'No runtime support for this sort of array call: <%cref(left)%> = <%dumpExp(right,"\"")%>')
end match
case T_COMPLEX(varLst = varLst, complexClassType=RECORD(__)) then
let &preExp = buffer ""
let exp = daeExp(right, context, &preExp, &varDecls, &auxFunction)
let tmp = tempDecl(expTypeModelica(ty),&varDecls)
<<
<%preExp%>
<%tmp%> = <%exp%>;
<% varLst |> var as TYPES_VAR(__) =>
match var.ty
case T_ARRAY(__) then
copyArrayData(var.ty, '<%tmp%>._<%var.name%>', appendStringCref(var.name,left), context, &preExp, &varDecls, &auxFunction)
else
let varPart = contextCref(appendStringCref(var.name,left),context, &auxFunction)
'<%varPart%> = <%tmp%>._<%var.name%>;'
; separator="\n"
%>
>>
error(sourceInfo(), 'No runtime support for this record assignment: <%cref(left)%> = <%dumpExp(right,"\"")%>')
// let &preExp = buffer ""
// let exp = daeExp(right, context, &preExp, &varDecls, &auxFunction)
// let tmp = tempDecl(expTypeModelica(ty),&varDecls)
// <<
// <%preExp%>
// <%tmp%> = <%exp%>;
// <% varLst |> var as TYPES_VAR(__) =>
// match var.ty
// case T_ARRAY(__) then
// copyArrayData(var.ty, '<%tmp%>._<%var.name%>', appendStringCref(var.name,left), context, &preExp, &varDecls, &auxFunction)
// else
// let varPart = contextCref(appendStringCref(var.name,left),context, &auxFunction)
// '<%varPart%> = <%tmp%>._<%var.name%>;'
// ; separator="\n"
// %>
// >>
else
let &preExp = buffer ""
let exp = daeExp(right, context, &preExp, &varDecls, &auxFunction)
Expand Down

0 comments on commit 6192db4

Please sign in to comment.