Opened 8 years ago

Closed 7 years ago

Last modified 7 years ago

#4237 closed defect (fixed)

Bad treatment of algebraic loops in synchronous models

Reported by: rfranke Owned by: wbraun
Priority: high Milestone: 1.13.0
Component: Backend Version: v1.12.0
Keywords: Cc: wbraun, bthiele, ptaeuber

Description (last modified by rfranke)

PR1391 along with commit d32ecb make ControlledMixingUnit work by applying index reduction and appropriately implementing ExplicitEuler, respectively.

Some more issues show up when replacing ExplicitEuler with ImplicitEuler, introducing algebraic loops. See the following example:

model ControlledMixingUnit2
  extends Modelica_Synchronous.Examples.Systems.ControlledMixingUnit(
    periodicClock1(solverMethod="ImplicitEuler"));
end ControlledMixingUnit2;

No Jacobians and no ModelStructure are generated!

Moreover, there is a linear torn system of dimension 1 -- shouldn't this be solved analytically?

Last but not least, the C runtime does not generate code for algebraic loops in clocked partitions.

Change History (20)

comment:1 Changed 8 years ago by rfranke

  • Description modified (diff)

comment:2 Changed 8 years ago by lochel

  • Cc bthiele ptaeuber added

Patrick, can you please have a look at the torn system?

comment:3 Changed 8 years ago by wbraun

  • Owner changed from lochel to wbraun
  • Status changed from new to accepted

Actually they are generated, but currently not processed by SimCodeUtil.

comment:4 in reply to: ↑ description Changed 8 years ago by wbraun

Replying to rfranke:

PR1391 along with commit d32ecb make ControlledMixingUnit work by applying index reduction and appropriately implementing ExplicitEuler, respectively.

Some more issues show up when replacing ExplicitEuler with ImplicitEuler, introducing algebraic loops. See the following example:

model ControlledMixingUnit2
  extends Modelica_Synchronous.Examples.Systems.ControlledMixingUnit(
    periodicClock1(solverMethod="ImplicitEuler"));
end ControlledMixingUnit2;

No Jacobians and no ModelStructure are generated!

Moreover, there is a linear torn system of dimension 1 -- shouldn't this be solved analytically?

Last but not least, the C runtime does not generate code for algebraic loops in clocked partitions.

The Jacobians are now also generated at SimCode phase see commit 07d95e.

Now the generated code fails, because of unknown identifier:
error: use of undeclared identifier 'clockIndex'

How it is set in the clock partition equations?
Where is this value stored currently?

comment:5 follow-up: Changed 8 years ago by rfranke

clockIndex is generated during code generation -- the index of the clocked partition / equation system. It is used to generate code for operators like interval(), looking up the interval of a given clock.

comment:6 follow-up: Changed 8 years ago by rfranke

Btw. you will also need to merge PR1391 to treat the high-index problem in the clocked partition.

comment:7 in reply to: ↑ 6 Changed 8 years ago by wbraun

Replying to rfranke:

Btw. you will also need to merge PR1391 to treat the high-index problem in the clocked partition.

My commit is based on that PR.

comment:8 in reply to: ↑ 5 Changed 8 years ago by wbraun

Replying to rfranke:

clockIndex is generated during code generation -- the index of the clocked partition / equation system. It is used to generate code for operators like interval(), looking up the interval of a given clock.

Okay, is it possible to evaluate this index while compile time?

comment:9 Changed 8 years ago by rfranke

So far things like interval are treated during code generation, along with event processing. The Cpp runtime generates a variable

  const int clockIndex = <%index%>;

into each function that contains code for a clocked partition -- not yet in the Jacobian code.

Your new commit 07d95e loops through the clocked partitions. Would it be possible to store the iteration counter as one based clockIndex in the Jacobian?

Last edited 8 years ago by rfranke (previous) (diff)

comment:10 follow-up: Changed 8 years ago by rfranke

It appears painful to add something to a Jacobian, because it is defined as tuple, i.e. would require changes at many places. Alternatively the Jacobian vars can be added to the already existing SimCode.crefToClockIndexHT -- e.g. used for clockIndex to modelDescription.xml.

This patch extends your commit 07d95e.
It works with an addition to the code generation like: Generate Jacobians for clocked partitions in Cpp runtime

  • SimCodeUtil.mo

    old new  
    187187  SimCode.HashTableCrefToSimVar crefToSimVarHT;
    188188  SimCodeFunction.MakefileParams makefileParams;
    189189  SimCode.ModelInfo modelInfo;
    190   HashTable.HashTable crefToClockIndexHT;
     190  HashTable.HashTable crefToClockIndexHT = HashTable.emptyHashTable();
    191191  array<Integer> systemIndexMap;
    192192  list<BackendDAE.EqSystem> clockedSysts, contSysts;
    193193  //list<BackendDAE.Equation> paramAsserts, remEqLst;
     
    384384    SymbolicJacsNLS := listAppend(SymbolicJacsTemp, SymbolicJacsNLS);
    385385    (allEquations, numberofLinearSys, numberofNonLinearSys, numberofMixedSys, numberOfJacobians, SymbolicJacsTemp) := countandIndexAlgebraicLoops(allEquations, numberofLinearSys, numberofNonLinearSys, numberofMixedSys, numberOfJacobians, {});
    386386    SymbolicJacsNLS := listAppend(SymbolicJacsTemp, SymbolicJacsNLS);
    387     (clockedPartitions, numberofLinearSys, numberofNonLinearSys, numberofMixedSys, numberOfJacobians, SymbolicJacsTemp) := countandIndexAlgebraicLoopsClockPartitions(clockedPartitions, numberofLinearSys, numberofNonLinearSys, numberofMixedSys, numberOfJacobians, {});
     387    (clockedPartitions, numberofLinearSys, numberofNonLinearSys, numberofMixedSys, numberOfJacobians, SymbolicJacsTemp, crefToClockIndexHT) := countandIndexAlgebraicLoopsClockPartitions(clockedPartitions, numberofLinearSys, numberofNonLinearSys, numberofMixedSys, numberOfJacobians, {}, crefToClockIndexHT);
    388388    SymbolicJacsNLS := listAppend(SymbolicJacsTemp, SymbolicJacsNLS);
    389389
    390390    // collect symbolic jacobians from state selection
     
    472472    //BaseHashTable.dumpHashTable(varToArrayIndexMapping);
    473473    //print("END MAPPING\n\n");
    474474
    475     (crefToClockIndexHT, _) := List.fold(inBackendDAE.eqs, collectClockedVars, (HashTable.emptyHashTable(), 1));
     475    (crefToClockIndexHT, _) := List.fold(inBackendDAE.eqs, collectClockedVars, (crefToClockIndexHT, 1));
    476476
    477477    simCode := SimCode.SIMCODE(modelInfo,
    478478                              {}, // Set by the traversal below...
     
    12001200  input Integer inMixedSysIndex;
    12011201  input Integer inJacobianIndex;
    12021202  input list<SimCode.JacobianMatrix> inSymJacs;
     1203  input HashTable.HashTable inClkHT;
    12031204  output list<SimCode.ClockedPartition> outColockPartition = {};
    12041205  output Integer outLinearSysIndex = inLinearSysIndex;
    12051206  output Integer outNonLinSysIndex = inNonLinSysIndex;
    12061207  output Integer outMixedSysIndex = inMixedSysIndex;
    12071208  output Integer outJacobianIndex = inJacobianIndex;
    12081209  output list<SimCode.JacobianMatrix> outSymJacs = inSymJacs;
     1210  output HashTable.HashTable outClkHT = inClkHT;
    12091211protected
    12101212  SimCode.SubPartition subPartitionTmp;
    12111213  SimCode.ClockedPartition clockPartitionTmp;
    12121214  list<SimCode.SubPartition> subPartitionsTmp;
    12131215  list<SimCode.SimEqSystem> equations;
     1216  SimCode.JacobianMatrix symJac;
     1217  list<SimCode.JacobianColumn> columns;
     1218  list<SimCodeVar.SimVar> simVars;
     1219  Integer firstJacIdx, clockIndex = 0;
    12141220algorithm
    12151221  for clockPartion in inColockPartition loop
    12161222    subPartitionsTmp := {};
    12171223    for subPartion in clockPartion.subPartitions loop
     1224      clockIndex := clockIndex + 1;
     1225      firstJacIdx := listLength(outSymJacs) + 1;
    12181226      (equations, outLinearSysIndex, outNonLinSysIndex, outMixedSysIndex, outJacobianIndex, outSymJacs) :=
    12191227       countandIndexAlgebraicLoops(subPartion.equations, outLinearSysIndex, outNonLinSysIndex, outMixedSysIndex, outJacobianIndex, outSymJacs);
     1228      // add jac vars with clockIndex to outClkHT
     1229      for i in firstJacIdx:listLength(outSymJacs) loop
     1230        symJac := listGet(outSymJacs, i);
     1231        (columns, simVars, _, _, _, _, _) := symJac;
     1232        for simVar in simVars loop
     1233          outClkHT := BaseHashTable.add((simVar.name, clockIndex), outClkHT);
     1234        end for;
     1235        for column in columns loop
     1236          (_, simVars, _) := column;
     1237          for simVar in simVars loop
     1238            outClkHT := BaseHashTable.add((simVar.name, clockIndex), outClkHT);
     1239          end for;
     1240        end for;
     1241      end for;
    12201242      subPartitionTmp := SimCode.SUBPARTITION(
    12211243        subPartion.vars,
    12221244        equations,
Last edited 8 years ago by rfranke (previous) (diff)

comment:11 in reply to: ↑ 10 Changed 8 years ago by wbraun

Replying to rfranke:

It appears painful to add something to a Jacobian, because it is defined as tuple, i.e. would require changes at many places. Alternatively the Jacobian vars can be added to the already existing SimCode.crefToClockIndexHT -- e.g. used for clockIndex to modelDescription.xml.

True, therefor I started on Friday to rewrite them into records and add the clockIndex to the jacobian record, I'll add this later the day.
Since the clockIndex is a partition index, it's better to store it once in the jacobian, are you prefer your solution with the variables?

comment:12 Changed 8 years ago by rfranke

A Jacobian record with member clockIndex would of course be preferred. The variables need the clockIndex if they appear in modelDescription.xml. Once the clockIndex is available in the Jacobian, a separate function could transfer that info to crefToClockIndexHT on demand.

comment:13 follow-up: Changed 8 years ago by wbraun

In PR1439 the jacobian got partition index support.

In the c-runtime we the function "firstTick()" is not found in the jacobians.
@lochel Where is this defined?

comment:14 in reply to: ↑ 13 Changed 8 years ago by lochel

Replying to wbraun:

In the c-runtime we the function "firstTick()" is not found in the jacobians.
@lochel Where is this defined?

MCP-0024

comment:15 follow-up: Changed 8 years ago by rfranke

With fixing ticket:4237: Support of clockPartitions in jacobians the example ControlledMixingUnit2 gets clock indices 1, 2 and 3. It should only be 1. Moreover, continuous-time models get a clockIndex 3, which is wrong -- it should be 0 if appearing at all in non-synchronous model code.

comment:16 in reply to: ↑ 15 Changed 8 years ago by wbraun

Replying to rfranke:

With fixing ticket:4237: Support of clockPartitions in jacobians the example ControlledMixingUnit2 gets clock indices 1, 2 and 3. It should only be 1. Moreover, continuous-time models get a clockIndex 3, which is wrong -- it should be 0 if appearing at all in non-synchronous model code.

Okay, should be fixed with PR1442.

comment:17 Changed 7 years ago by casella

  • Milestone changed from 1.12.0 to 1.13.0

Milestone moved to 1.13.0 due to 1.12.0 already being released.

comment:18 Changed 7 years ago by wbraun

@rfranke Can mark this as fixed?

comment:19 Changed 7 years ago by rfranke

  • Resolution set to fixed
  • Status changed from accepted to closed

Yes, this ticket can be closed.

Just opened the new ticket #4783 about a new issue.

Moreover, the FMI ModelStructure is still missing for clocked partitions. Will open a new ticket as well -- don't we already have another ticket for this?

comment:20 Changed 7 years ago by wbraun

Ah, yes Regarding the discrete structure I've opened #4424 again.

Note: See TracTickets for help on using tickets.