#5114 closed defect (fixed)
Issue with MultiBody models of ScalableTestSuite with the NF
| Reported by: | Francesco Casella | Owned by: | Per Östlund | 
|---|---|---|---|
| Priority: | high | Milestone: | 2.0.0 | 
| Component: | New Instantiation | Version: | |
| Keywords: | Cc: | Bernhard Bachmann, Willi Braun, Per Östlund | 
Description
The last remaining models of ScalableTestSuite which are not handled by the NF are the FlexibleBeamModelica and StringModelica models. The issue is quite intricate but I think I understood what happens. 
For example, you can check ScalableTestSuite.Mechanical.Strings.ScaledExperiments.StringModelica_N_2, which reports this error:
ScalableTestSuite_noopt_ScalableTestSuite.Mechanical.Strings.ScaledExperiments.StringModelica_N_2_06inz.c:4331:38: error: use of undeclared identifier '$Pbodybox$lB1$rB$Pbody$PR_start$PT' copy_real_array_data_mem(tmp2._T, &$Pbodybox$lB1$rB$Pbody$PR_start$PT);
The issue is with the parameter-binding equation
  final parameter Frames.Orientation R_start=
      Modelica.Mechanics.MultiBody.Frames.axesRotations(
        sequence_start,
        angles_start,
        zeros(3));
of the Modelica.Mechanics.MultiBody.Parts.Body model, which is moved as a whole by the new front end into the initial equation section as 
  bodybox[1].body.R_start = Modelica.Mechanics.MultiBody.Frames.axesRotations(
  {1, 2, 3}, bodybox[1].body.angles_start, {0.0, 0.0, 0.0});
which the back-end cannot handle. The old-front end constant-evaluates the binding equation and expands it to its scalar components
final parameter Real bodybox[1].body.R_start.T[1,1] = 1.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.T[1,2] = 0.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.T[1,3] = 0.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.T[2,1] = 0.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.T[2,2] = 1.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.T[2,3] = 0.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.T[3,1] = 0.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.T[3,2] = 0.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.T[3,3] = 1.0 "Transformation matrix from world frame to local frame"; final parameter Real bodybox[1].body.R_start.w[1](quantity = "AngularVelocity", unit = "rad/s") = 0.0 "Absolute angular velocity of local frame, resolved in local frame"; final parameter Real bodybox[1].body.R_start.w[2](quantity = "AngularVelocity", unit = "rad/s") = 0.0 "Absolute angular velocity of local frame, resolved in local frame"; final parameter Real bodybox[1].body.R_start.w[3](quantity = "AngularVelocity", unit = "rad/s") = 0.0 "Absolute angular velocity of local frame, resolved in local frame";
which is trivial for the back-end to handle.
However, looking at the axesRotation() function call, the parameter R_start is final, sequence_start has Evaluate = true and zeros(3) is a literal constant, but angles_start doesn't have Evaluate = true, so I'm not sure why the old front-end constant-evaluates the right-hand-side of the binding equation. Maybe just the fact of being final was used to trigger that, though it needs not necessarily be the case: a final parameter may depend on another parameter that is not evaluated and that should be changeable at runtime. 
axesRotation has Inline = true, but I understand this is only relevant for the back-end, the front-end never inlines anything.
So, I don't think we should try to reproduce the old front-end behaviour here, because it performs an unnecessary evaluation. On the other hand, we need a viable solution to get ScalableTestSuite to run ASAP.
I checked Modelica.Mechanics.MultiBody.Examples.Elementary.DoublePendulum, which runs fine with the NF, and produces the initial equation
  boxBody1.body.R_start = Modelica.Mechanics.MultiBody.Frames.axesRotations(
  {1, 2, 3}, boxBody1.body.angles_start, {0.0, 0.0, 0.0});
which is handled correctly. So, I understand there is some problem with code generation of
  bodybox[1].body.R_start = Modelica.Mechanics.MultiBody.Frames.axesRotations(
  {1, 2, 3}, bodybox[1].body.angles_start, {0.0, 0.0, 0.0});
because in the latter case the left-hand-side has some indexing, while the former case doesn't.
I'm not sure whether this is because the new front-end creates a somewhat invalid data structure in this case, or rather that the back-end or simcode should be amended by adding the case of array element on the left-hand-side, maybe that's just a trivial fix.
@perost, @lochel, @adrpo, @wbraun can you agree on a solution for this case?
Change History (8)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
| Cc: | added; removed | 
|---|---|
| Owner: | changed from to | 
| Status: | new → assigned | 
As discussed at the devmeeting on Sep 17, @karim.abdelhak will have a look at this issue ASAP.
comment:4 by , 7 years ago
| Resolution: | → fixed | 
|---|---|
| Status: | assigned → closed | 
follow-up: 7 comment:5 by , 7 years ago
| Cc: | added | 
|---|---|
| Resolution: | fixed | 
| Status: | closed → reopened | 
Unfortunately there are still issue with this model, as demonstrated e.g. by this report.
I made some further analysis on the optdaedump output. The flattened model contains the equation
revolute[2].frame_a.f = -Modelica.Mechanics.MultiBody.Frames.resolve1(revolute[2].R_rel, revolute[2].frame_b.f)
which is then inlined and aliased by the back-end into
-bodybox[1].frame_b.f[1] = (-transpose(revolute[2].R_rel.T) * 
  {-bodyboxN.frame_a.f[1], -bodyboxN.frame_a.f[2], -bodyboxN.frame_a.f[3]})[1]
-bodybox[1].frame_b.f[2] = (-transpose(revolute[2].R_rel.T) *
  {-bodyboxN.frame_a.f[1], -bodyboxN.frame_a.f[2], -bodyboxN.frame_a.f[3]})[2]
-bodybox[1].frame_b.f[3] = (-transpose(revolute[2].R_rel.T) * 
  {-bodyboxN.frame_a.f[1], -bodyboxN.frame_a.f[2], -bodyboxN.frame_a.f[3]})[3] 
In the simulation results, bodyboxN.frame_a.f is nonzero due to the force applied on the beam tip, while bodybox[1].frame_b.f turns out to be zero, which is wrong, since the numerical value of revolute[2].R_rel.T turns out to be (correctly) close to the unit matrix.
I compared this with the result of optdaedump when using the old front-end, which is
-bodybox[1].frame_b.f[1] = (-revolute[2].R_rel.T[2,1]) * revolute[2].frame_b.f[2] - revolute[2].R_rel.T[3,1] * revolute[2].frame_b.f[3] - revolute[2].R_rel.T[1,1] * revolute[2].frame_b.f[1] -bodybox[1].frame_b.f[2] = (-revolute[2].R_rel.T[2,2]) * revolute[2].frame_b.f[2] - revolute[2].R_rel.T[3,2] * revolute[2].frame_b.f[3] - revolute[2].R_rel.T[1,2] * revolute[2].frame_b.f[1] -bodybox[1].frame_b.f[3] = (-revolute[2].R_rel.T[2,3]) * revolute[2].frame_b.f[2] - revolute[2].R_rel.T[3,3] * revolute[2].frame_b.f[3] - revolute[2].R_rel.T[1,3] * revolute[2].frame_b.f[1]
I don't know why the back-end expands the transpose operator after inlining the resolve1 function when using the OF, but it doesn't when using the NF. I guess this causes some issues with the generated code, which is not broken but gives wrong results. I flattened the model with both front-ends, and the two function printouts seem identical, so I don't really know where to look at.
@wbraun, @perost, any idea?
comment:6 by , 7 years ago
| Owner: | changed from to | 
|---|---|
| Status: | reopened → assigned | 
follow-up: 8 comment:7 by , 7 years ago
| Resolution: | → fixed | 
|---|---|
| Status: | assigned → closed | 
Replying to casella:
I don't know why the back-end expands the
transposeoperator after inlining theresolve1function when using the OF, but it doesn't when using the NF. I guess this causes some issues with the generated code, which is not broken but gives wrong results. I flattened the model with both front-ends, and the two function printouts seem identical, so I don't really know where to look at.
When using the OF it wasn't the backend that evaluated transpose, but the frontend. Or rather that the frontend expanded the argument to transpose and had a simplification rule for transpose of an array. 
I tried to do the same in the NF, i.e. expand all function arguments, mostly to see what the impact would be. But the results were a bit mixed and on the whole didn't make much difference, so I disabled it. But I disabled it by just changing the default value of the debug flag I'd introduced, so -d=nfExpandFuncArgs can still be used to turn on expansion of all function arguments.
Instead I chose the more targeted approach of expanding the argument of only transpose in 5bbac02, which fixed the simulation of the FlexibleBeamModelica models as well as some of the MultiBody models in the MSL.


Here's a small test model that gives the same issue when compiled using the old frontend:
So it seems like this is something that should at least be fixed in the code generation.