Skip to content

Commit

Permalink
Added support for event generating functions to the adevs backend
Browse files Browse the repository at this point in the history
git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@14423 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
  • Loading branch information
smiz committed Dec 17, 2012
1 parent 9e84fa4 commit 1fde75c
Showing 1 changed file with 183 additions and 28 deletions.
211 changes: 183 additions & 28 deletions Compiler/Template/CodegenAdevs.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ case SIMCODE(modelInfo = MODELINFO(varInfo = vi as VARINFO(__))) then
/// Destructor
~<%lastIdentOfPath(modelInfo.name)%>();
/// Index of the first extra state event
int numStateEvents() const { return <%vi.numRelations%>; }
int numStateEvents() const { return numZeroCrossings(); }
/**
* These methods are generated by the OpenModelica compiler.
*/
Expand Down Expand Up @@ -145,7 +145,11 @@ case SIMCODE(modelInfo = MODELINFO(varInfo = vi as VARINFO(__))) then

// Zero crossing variables
int *zc;
int numZeroCrossings() const { return <%vi.numRelations%>; }
int numZeroCrossings() const {
return numRelations()+2*numMathEvents();
}
int numRelations() const { return <%vi.numRelations%>; }
int numMathEvents() const { return <%vi.numMathEventFunctions%>; }

// Initial unknowns via solution to least squares
void solve_for_initial_unknowns();
Expand All @@ -168,6 +172,12 @@ case SIMCODE(modelInfo = MODELINFO(varInfo = vi as VARINFO(__))) then
double calcDelay(int index, double expr, double t, double delay);
void saveDelay(int index, double expr, double t, double maxdelay);

AdevsMathEventFunc** eventFuncs;
double floor(double expr, int index);
double div(double x, double y, int index);
int integer(double expr, int index);
double ceil(double expr, int index);

protected:
/**
* Calculate the values of the state and algebraic variables.
Expand Down Expand Up @@ -272,23 +282,24 @@ case SIMCODE(modelInfo = MODELINFO(varInfo = vi as VARINFO(__))) then
int extra_state_events, double eventHys):
ode_system<OMC_ADEVS_IO_TYPE>(
<%vi.numStateVars%>+1, // Number of state variables plus one for the clock
<%vi.numRelations%>+extra_state_events // Number of state event functions
<%vi.numRelations%>+2*<%vi.numMathEventFunctions%>+extra_state_events // Number of state event functions
),
epsilon(eventHys),
helpVars(NULL),
helpVars_saved(NULL),
zc(NULL),
samples(NULL),
delays(NULL)
delays(NULL),
eventFuncs(NULL)
{
timeValue = 0.0;
if (numHelpVars() > 0)
{
helpVars = new bool[numHelpVars()];
helpVars_saved = new bool[numHelpVars()];
}
if (numZeroCrossings() > 0)
zc = new int[numZeroCrossings()];
if (numRelations() > 0)
zc = new int[numRelations()];
if (numTimeEvents() > 0)
{
samples = new AdevsSampleData*[numTimeEvents()];
Expand All @@ -301,6 +312,12 @@ case SIMCODE(modelInfo = MODELINFO(varInfo = vi as VARINFO(__))) then
for (int i = 0; i < numDelays(); i++)
delays[i] = NULL;
}
if (numMathEvents() > 0)
{
eventFuncs = new AdevsMathEventFunc*[numMathEvents()];
for (int i = 0; i < numMathEvents(); i++)
eventFuncs[i] = NULL;
}
}

<%lastIdentOfPath(modelInfo.name)%>::~<%lastIdentOfPath(modelInfo.name)%>()
Expand All @@ -320,6 +337,12 @@ case SIMCODE(modelInfo = MODELINFO(varInfo = vi as VARINFO(__))) then
if (delays[i] != NULL) delete delays[i];
delete [] delays;
}
if (eventFuncs != NULL)
{
for (int i = 0; i < numMathEvents(); i++)
if (eventFuncs[i] != NULL) delete eventFuncs[i];
delete [] eventFuncs;
}
}

<%makeExtraResiduals(allEquations,lastIdentOfPath(modelInfo.name))%>
Expand Down Expand Up @@ -462,8 +485,8 @@ case SIMCODE(modelInfo = MODELINFO(vars = vars as SIMVARS(__))) then
{
bool result = false;
double* z = new double[numZeroCrossings()];
<%zeroCrossingEqns(relations)%>
for (int i = 0; i < numZeroCrossings(); i++)
<%zeroCrossingEqns(zeroCrossings,relations)%>
for (int i = 0; i < numRelations(); i++)
{
if (z[i] < -epsilon && zc[i] == 1)
{
Expand All @@ -476,14 +499,18 @@ case SIMCODE(modelInfo = MODELINFO(vars = vars as SIMVARS(__))) then
zc[i] = 1;
}
}
for (int i = numRelations(); i < numZeroCrossings() && !result; i += 2)
{
if (z[i] < -epsilon || z[i+1] < -epsilon) result = true;
}
delete [] z;
return result;
}

void <%lastIdentOfPath(modelInfo.name)%>::state_event_func(const double* q, double* z)
{
calc_vars(q);
<%zeroCrossingEqns(relations)%>
<%zeroCrossingEqns(zeroCrossings,relations)%>
extra_state_event_funcs(&(z[numStateEvents()]));
restore_vars();
}
Expand Down Expand Up @@ -515,8 +542,14 @@ case SIMCODE(modelInfo = MODELINFO(vars = vars as SIMVARS(__))) then
{
atEvent = true;
// Switch the state event variables
for (int i = 0; i < numZeroCrossings(); i++)
for (int i = 0; i < numRelations(); i++)
if (state_event[i]) zc[i] = !zc[i];
for (int i = numRelations(); i < numZeroCrossings(); i += 2)
{
int which = (i-numRelations())/2;
if (state_event[i]) eventFuncs[which]->goUp();
else if (state_event[i+1]) eventFuncs[which]->goDown();
}
for (int i = 0; i < numTimeEvents(); i++)
{
assert(samples[i] != NULL);
Expand All @@ -531,20 +564,51 @@ case SIMCODE(modelInfo = MODELINFO(vars = vars as SIMVARS(__))) then
save_vars(); // save the new state of the model
// Reinitialize state variables that need to be reinitialized
<%(vars.stateVars |> SIMVAR(__) => 'q[<%index%>]=<%cref(name)%>;') ;separator="\n"%>
for (int i = 0; i < numMathEvents(); i++)
if (eventFuncs[i] != NULL) eventFuncs[i]->setInit(false);
atEvent = false;
}

double <%lastIdentOfPath(modelInfo.name)%>::floor(double expr, int index)
{
if (eventFuncs[index] == NULL)
eventFuncs[index] = new AdevsFloorFunc(epsilon);
return eventFuncs[index]->calcValue(expr);
}

double <%lastIdentOfPath(modelInfo.name)%>::div(double x, double y, int index)
{
if (eventFuncs[index] == NULL)
eventFuncs[index] = new AdevsDivFunc(epsilon);
return eventFuncs[index]->calcValue(x/y);
}

int <%lastIdentOfPath(modelInfo.name)%>::integer(double expr, int index)
{
if (eventFuncs[index] == NULL)
eventFuncs[index] = new AdevsFloorFunc(epsilon);
return int(eventFuncs[index]->calcValue(expr));
}

double <%lastIdentOfPath(modelInfo.name)%>::ceil(double expr, int index)
{
if (eventFuncs[index] == NULL)
eventFuncs[index] = new AdevsCeilFunc(epsilon);
return eventFuncs[index]->calcValue(expr);
}
>>
end makeEventFunc;

template zeroCrossingEqns(list<ZeroCrossing> zeroCrossings)
template zeroCrossingEqns(list<ZeroCrossing> zeroCrossings, list<ZeroCrossing> relations)
"Generates function in simulation file."
::=
let &varDecls = buffer "" /*BUFD*/
let zeroCrossingsCode = zeroCrossingsTpl2(zeroCrossings, &varDecls /*BUFD*/)
let RelationsCode = zeroCrossingsRelationsTpl(relations, &varDecls /*BUFD*/)
let EventFuncCode = zeroCrossingsEventFunctionsTpl(zeroCrossings, &varDecls /*BUFD*/)
<<
<%varDecls%>
<%zeroCrossingsCode%>
<%RelationsCode%>
<%EventFuncCode%>
>>
end zeroCrossingEqns;

Expand Down Expand Up @@ -615,7 +679,9 @@ case SIMCODE(modelInfo = MODELINFO(vars = vars as SIMVARS(__))) then
<<
void <%lastIdentOfPath(modelInfo.name)%>::clear_event_flags()
{
for (int i = 0; i < numZeroCrossings(); i++) zc[i] = -1;
for (int i = 0; i < numRelations(); i++) zc[i] = -1;
for (int i = 0; i < numMathEvents(); i++)
if (eventFuncs[i] != NULL) eventFuncs[i]->setInit(true);
}

void <%lastIdentOfPath(modelInfo.name)%>::init(double* q)
Expand Down Expand Up @@ -649,6 +715,8 @@ case SIMCODE(modelInfo = MODELINFO(vars = vars as SIMVARS(__))) then
save_vars();
<%(vars.stateVars |> SIMVAR(__) => 'q[<%index%>]=<%cref(name)%>;') ;separator="\n"%>
atInit = false;
for (int i = 0; i < numMathEvents(); i++)
if (eventFuncs[i] != NULL) eventFuncs[i]->setInit(false);
}
>>
end makeInit;
Expand Down Expand Up @@ -724,7 +792,7 @@ case SIMCODE(modelInfo = MODELINFO(vars = vars as SIMVARS(__))) then
<<
void <%lastIdentOfPath(modelInfo.name)%>::calc_vars(const double* q, bool doReinit)
{
bool reInit = false, newEvents = false;
bool reInit = false;
active_model = this;
if (doReinit) clear_event_flags();
// Copy state variable arrays to values used in the odes
Expand All @@ -735,8 +803,8 @@ case SIMCODE(modelInfo = MODELINFO(vars = vars as SIMVARS(__))) then
}
// Calculate the odes
<%allEqns(allEquations,whenClauses)%>
if (atEvent) newEvents = check_for_new_events();
if (reInit || newEvents)
if (atEvent && !reInit) reInit = check_for_new_events();
if (reInit)
{
save_vars();
calc_vars(NULL,reInit);
Expand Down Expand Up @@ -959,18 +1027,54 @@ template functionWhenReinitStatementThen(list<WhenOperator> reinits, Text &varDe
>>
end functionWhenReinitStatementThen;

template zeroCrossingsTpl2(list<ZeroCrossing> zeroCrossings, Text &varDecls /*BUFP*/)
template zeroCrossingsRelationsTpl(list<ZeroCrossing> relations, Text &varDecls /*BUFP*/)
"Generates code for zero crossings."
::=
(relations |> ZERO_CROSSING(__) hasindex i0 =>
zeroCrossingRelation(i0, relation_, &varDecls /*BUFD*/)
;separator="\n")
end zeroCrossingsRelationsTpl;

template zeroCrossingsEventFunctionsTpl(list<ZeroCrossing> zeroCrossings, Text &varDecls /*BUFP*/)
"Generates code for zero crossings."
::=
(zeroCrossings |> ZERO_CROSSING(__) hasindex i0 =>
zeroCrossingTpl2(i0, relation_, &varDecls /*BUFD*/)
zeroCrossingFunction(i0, relation_, &varDecls /*BUFD*/)
;separator="\n")
end zeroCrossingsTpl2;
end zeroCrossingsEventFunctionsTpl;

template makeEventFuncCallForDiv(Exp exp1, Exp exp2, Exp idx, Text& varDecls)
"Generate code for a call to an event generating function"
::=
let &preExp = buffer "" /*BUFD*/
let e1 = daeExp(exp1, contextOther, &preExp /*BUFC*/, &varDecls /*BUFD*/)
let e2 = daeExp(exp2, contextOther, &preExp /*BUFC*/, &varDecls /*BUFD*/)
let indx = daeExp(idx, contextOther, &preExp /*BUFC*/, &varDecls /*BUFD*/)
<<
<%preExp%>
z[numRelations()+2*<%indx%>] = eventFuncs[<%indx%>]->getZUp((<%e1%>)/(<%e2%>));
z[numRelations()+2*<%indx%>+1] = eventFuncs[<%indx%>]->getZDown((<%e1%>)/(<%e2%>));
// Div generates extra two extra state event functions
z[numRelations()+2*(<%indx%>+1)] = 1.0;
z[numRelations()+2*(<%indx%>+1)+1] = 1.0;
>>
end makeEventFuncCallForDiv;

template zeroCrossingTpl2(Integer index1, Exp relation, Text &varDecls /*BUFP*/)
"Generates code for a zero crossing."
template makeEventFuncCall(Exp exp1, Exp idx, Text& varDecls)
"Generate code for a call to an event generating function"
::=
let &preExp = buffer "" /*BUFD*/
let e1 = daeExp(exp1, contextOther, &preExp /*BUFC*/, &varDecls /*BUFD*/)
let indx = daeExp(idx, contextOther, &preExp /*BUFC*/, &varDecls /*BUFD*/)
<<
<%preExp%>
z[numRelations()+2*<%indx%>] = eventFuncs[<%indx%>]->getZUp(<%e1%>);
z[numRelations()+2*<%indx%>+1] = eventFuncs[<%indx%>]->getZDown(<%e1%>);
>>
end makeEventFuncCall;

template zeroCrossingRelation(Integer index1, Exp relation, Text &varDecls /*BUFP*/)
"Generates code for a zero crossing relations."
::=
match relation
case RELATION(__) then
Expand All @@ -982,13 +1086,56 @@ template zeroCrossingTpl2(Integer index1, Exp relation, Text &varDecls /*BUFP*/)
<%preExp%>
ADEVS_ZEROCROSSING(<%index1%>, <%op%>(<%e1%>, <%e2%>));
>>
case CALL(path=IDENT(name="sample"), expLst={start, interval}) then
<< >>
case CALL(path=IDENT(name="floor"), expLst={exp1, idx}) then
<<
>>
case CALL(path=IDENT(name="integer"), expLst={exp1, idx}) then
<<
>>
case CALL(path=IDENT(name="ceil"), expLst={exp1, idx}) then
<<
>>
case CALL(path=IDENT(name="div"), expLst={exp1, exp2, idx}) then
<<
>>
else
<<
// UNKNOWN ZERO CROSSING for <%index1%>
// IN RELATION: UNKNOWN ZERO CROSSING for <%index1%>
assert(false);
>>
end zeroCrossingTpl2;
end zeroCrossingRelation;

template zeroCrossingFunction(Integer index1, Exp relation, Text &varDecls /*BUFP*/)
"Generates code for a zero crossing function."
::=
match relation
case CALL(path=IDENT(name="floor"), expLst={exp1, idx}) then
<<
<%makeEventFuncCall(exp1,idx,&varDecls)%>
>>
case CALL(path=IDENT(name="integer"), expLst={exp1, idx}) then
<<
<%makeEventFuncCall(exp1,idx,&varDecls)%>
>>
case CALL(path=IDENT(name="ceil"), expLst={exp1, idx}) then
<<
<%makeEventFuncCall(exp1,idx,&varDecls)%>
>>
case CALL(path=IDENT(name="div"), expLst={exp1, exp2, idx}) then
<<
<%makeEventFuncCallForDiv(exp1,exp2,idx,&varDecls)%>
>>
case RELATION(__) then
<<
>>
else
let preExp = ""
let e1 = daeExp(relation, contextOther, &preExp /*BUFC*/, &varDecls /*BUFD*/)
<<
// IN EVENT FUNCTION: UNKNOWN ZERO CROSSING for <%index1%>
// <%e1%>
>>
end zeroCrossingFunction;

template zeroCrossingOpFunc(Operator op)
"Generates zero crossing function name for operator."
Expand Down Expand Up @@ -3919,7 +4066,15 @@ template daeExpCall(Exp call, Context context, Text &preExp /*BUFP*/,
let var1 = daeExp(e1, context, &preExp, &varDecls)
let var2 = daeExp(e2, context, &preExp, &varDecls)
'trunc(<%var1%>/<%var2%>)'


case CALL(path=IDENT(name="floor"), expLst={e1}) then
let var1 = daeExp(e1, context, &preExp, &varDecls)
'::floor(<%var1%>)'

case CALL(path=IDENT(name="ceil"), expLst={e1}) then
let var1 = daeExp(e1, context, &preExp, &varDecls)
'::ceil(<%var1%>)'

case CALL(path=IDENT(name="mod"), expLst={e1,e2}, attr=CALL_ATTR(__)) then
let var1 = daeExp(e1, context, &preExp, &varDecls)
let var2 = daeExp(e2, context, &preExp, &varDecls)
Expand Down Expand Up @@ -4035,7 +4190,7 @@ template daeExpCall(Exp call, Context context, Text &preExp /*BUFP*/,
case CALL(path=IDENT(name="integer"),
expLst={toBeCasted}) then
let castedVar = daeExp(toBeCasted, context, &preExp /*BUFC*/, &varDecls /*BUFD*/)
'((modelica_integer)<%castedVar%>)'
'((modelica_integer)(::floor(<%castedVar%>)))'

case CALL(path=IDENT(name="Integer"),
expLst={toBeCasted}) then
Expand Down

0 comments on commit 1fde75c

Please sign in to comment.