Skip to content

Support of Modelica_StateGraph2 Connections.uniqueRoot#3701

Open
HansOlsson wants to merge 4 commits intomodelica:masterfrom
HansOlsson:ProposeStateGraph2
Open

Support of Modelica_StateGraph2 Connections.uniqueRoot#3701
HansOlsson wants to merge 4 commits intomodelica:masterfrom
HansOlsson:ProposeStateGraph2

Conversation

@HansOlsson
Copy link
Copy Markdown
Collaborator

In progress.
The operator definitions need more work.

@HansOlsson HansOlsson marked this pull request as ready for review June 5, 2025 15:51
@HansOlsson
Copy link
Copy Markdown
Collaborator Author

HansOlsson commented Jun 5, 2025

This is now more or less the text from Modelica_StateGraph2; except that in case someone connects two unique roots tools are not restricted to using one message in the diagnostics. (The messages will normally be the same, but given that it is even an error to connect two roots with the same message it doesn't make sense to require an additional diagnostics in case they are different.)

@HansOlsson HansOlsson changed the title Adding draft variant of Connections.uniqueRoot Support of Modelica_StateGraph2 Connections.uniqueRoot Jun 9, 2025
@adrpo
Copy link
Copy Markdown
Collaborator

adrpo commented Nov 16, 2025

Looks good to me.

@HansOlsson HansOlsson added this to the ModelicaSpec3.7 milestone Apr 16, 2026
@HansOlsson
Copy link
Copy Markdown
Collaborator Author

UniqueRoot seems ok, need more motivation for uniqueRootIndices (why it is useful to return them and not only have it as a check). One use is for restart where one part is an infinite loop (need example).

@HansOlsson
Copy link
Copy Markdown
Collaborator Author

From the meeting I had an assignment to check whether uniqueRootIndices is fully needed, and as far as I can see the full complexity is used for two cases - ensuring that there are delayed transitions and something for starting.

Thus, one use-case for uniqueRootIndices is to check that there are delayed transitions. This is done by weaving around the entry/exit points, creating boolean equations that form a loop if there are no delayed transitions. I don't see how it would be possible without this more advanced function .

The relevant code is the following in Modelica_StateGraph2:

    local_entry[entryIndices[1]].checkOneDelayedTransitionPerLoop =
      checkOneDelayedTransitionPerLoopIn;

    // During initialization it is checked whether entry and exit port connections
    // are fine. The for-statements are made in such a form, that no translation
    // error occurs, if this case is present. Instead, during initialization
    // a meaningful error message is printed
    for i in 2:nMinBranches loop
      local_entry[entryIndices[i]].checkOneDelayedTransitionPerLoop = local_exit[i - 1].checkOneDelayedTransitionPerLoop;
    end for;
    for i in nMinBranches + 1:nEntry loop
      local_entry[entryIndices[i]].checkOneDelayedTransitionPerLoop = true;
    end for;
    local_outPort.checkOneDelayedTransitionPerLoop = fill(local_exit[nMinBranches].checkOneDelayedTransitionPerLoop, nOut);

For the example given below the connections for the checkOneDelayedTransitionPerLoop follow the red line below, so first down one path, and then down another path, and then through the exit and other components.
ParallelWithInfiniteLoop

The key is that the parallel block is part of a loop there has to be a delayed transition in one of the branches connecting the entry-points to the exit-points (they must all reach the exit for the parallel block to exit - that's why having just one unavoidable delayed transition suffices), or in the loop outside of the parallel block.

Whether the parallel branch (in general branches) not connected to any exit-point has a delayed transition or not doesn't matter for this (it obviously needs to have its own delayed transition if there's a loop or there would be a local infinite loop).

model ParallelWithInfiniteLoop 
  "A wrong Modelica_StateGraph2 to demonstrate parallel execution paths with infinite looping ((translates with an error))"
  extends Modelica.Icons.Example;

  Modelica_StateGraph2.Step step1(
    nOut=1,
    initialStep=true,
    nIn=1) annotation (Placement(transformation(extent={{-4,68},{4,76}})));
  Modelica_StateGraph2.Parallel parallel(
    use_inPort=true,
    use_outPort=true,
    nIn=1,
    nEntry=3,
    nOut=1,
    nExit=2) annotation (Placement(transformation(extent={{-38,-46},{38,44}})));
  Modelica_StateGraph2.Transition T1(waitTime=1, delayedTransition=false)
    annotation (Placement(transformation(extent={{-4,54},{4,62}})));
  Modelica_StateGraph2.Step step2(nIn=1, nOut=1)
    annotation (Placement(transformation(extent={{-8,-4},{0,4}})));
  Modelica_StateGraph2.Step step3(nOut=1, nIn=1)
    annotation (Placement(transformation(extent={{12,16},{20,24}})));
  Modelica_StateGraph2.Transition T2(waitTime=1, delayedTransition=false)
    annotation (Placement(transformation(extent={{12,-4},{20,4}})));
  Modelica_StateGraph2.Step step4(nOut=1, nIn=1)
    annotation (Placement(transformation(extent={{12,-24},{20,-16}})));
  Modelica_StateGraph2.Transition T3(
    waitTime=1,
    use_conditionPort=false,
    delayedTransition=false)
    annotation (Placement(transformation(extent={{52,6},{60,-2}})));
  Modelica_StateGraph2.Step step5(nIn=2, nOut=1)
    annotation (Placement(transformation(extent={{-28,-4},{-20,4}})));
  Modelica_StateGraph2.Transition T4(waitTime=1, delayedTransition=true)
    annotation (Placement(transformation(extent={{-26,-22},{-18,-14}})));
equation 
  connect(step1.outPort[1], T1.inPort) annotation (Line(
      points={{0,67.4},{0,62}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(T1.outPort, parallel.inPort[1]) annotation (Line(
      points={{0,53},{0,44}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(step3.outPort[1], T2.inPort) annotation (Line(
      points={{16,15.4},{16,4}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(parallel.entry[1], step2.inPort[1]) annotation (Line(
      points={{-1.26667,39.5},{-1.26667,20},{-2,20},{-2,4},{-4,4}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(parallel.entry[2], step3.inPort[1]) annotation (Line(
      points={{0,39.5},{0,34},{9.10146,34},{16,34},{16,24}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(T2.outPort, step4.inPort[1]) annotation (Line(
      points={{16,-5},{16,-16}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(parallel.outPort[1], T3.inPort) annotation (Line(
      points={{0,-47.125},{0,-54},{9.7754,-54},{39.1016,-54},{56,-54},{56,-38.918},
          {56,-2}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(T3.outPort, step1.inPort[1]) annotation (Line(
      points={{56,7},{56,73.502},{56,86},{41.1434,86},{12.0313,86},{0,86},{
          0,76}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(step2.outPort[1], parallel.exit[1]) annotation (Line(
      points={{-4,-4.6},{-2,-4.6},{-2,-20},{-2,-50},{-0.95,-50},{-0.95,-42.0625}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(step4.outPort[1], parallel.exit[2]) annotation (Line(
      points={{16,-24.6},{16,-32},{10.2306,-32},{0.95,-32},{0.95,-42.0625}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(parallel.entry[3], step5.inPort[1]) annotation (Line(
      points={{1.26667,39.5},{1.26667,26},{-22,26},{-22,4},{-24.5,4}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  connect(step5.outPort[1], T4.inPort) annotation (Line(points={{-24,-4.6},{-24,
          -10},{-22,-10},{-22,-14}}, color={0,0,0}));
  connect(T4.outPort, step5.inPort[2]) annotation (Line(
      points={{-22,-23},{-28,-23},{-28,-24},{-32,-24},{-32,12},{-30,12},{-23.5,12},
          {-23.5,8},{-23.5,4}},
      color={0,0,0},
      smooth=Smooth.Bezier));
  annotation (Diagram(coordinateSystem(preserveAspectRatio=true, extent={{-100,
            -100},{100,100}}), graphics={Line(
          points={{-10,62},{-6,-36},{-2,-44},{16,48},{18,34},{20,-40},{8,-60},{70,
              -58},{68,66},{68,80},{66,90},{10,94},{-10,80},{-10,66}},
          color={238,46,47},
          smooth=Smooth.Bezier,
          arrow={Arrow.None,Arrow.Open})}), uses(Modelica(version="4.1.0"),
        Modelica_StateGraph2(version="2.1.1")));
end ParallelWithInfiniteLoop;

I could not yet find a good demonstration of the starting-part.

Since one of the main benefits of Modelica_StateGraph2 is being able to detect loops, and most of the loop-detection is done just using equations I don't see that we can simplify this proposal.

(I didn't yet figure out how this primitive is used for (re-)starting the parallel part.)

Comment thread chapters/connectors.tex Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants