ModiaSim / Modia.jl

Modeling and simulation of multidomain engineering systems
MIT License
321 stars 38 forks source link

Error: type Global has no field head #59

Open crlaugh opened 5 years ago

crlaugh commented 5 years ago

I am continuing to work on the example referred to in https://github.com/ModiaSim/Modia.jl/issues/58, and have run into a different problem. Rather than drive the system with a torque, I am trying to drive it with a position, and have Modia calculate the torque signal required to achieve the particular output. This is a classic InverseBlockConstraints problem from Modelica that I am trying to implement in Modia. I am not using an InverseBlockConstraints block, since Modia has no semantics for input/output (as far as I know), but have tried implementing the InverseBlockConstraints model anyways in Modia and it doesn't change the behavior of the model.

I can now simulate the system when I drive the torque with an input source, but I get an error type Global has no field head when I drive the position sensor with a desired angle. I enabled logging and looked at the flattened and structurally processed system, but can't find many clues to the source of this problem.

I have updated and cleaned up these models slightly from the previous issue, and am re-including them here.

using Modia, ModiaMath
using Modia.Blocks
using Modia.Rotational

@model Pulse begin
    height = Parameter(1.0, info="Height of pulse")
    duration = Parameter(1.0, info="Duration of pulse")
    @extends Modia.Blocks.SignalSource()
    @inherits y, offset, startTime
    @equations begin
        y = (time < startTime) ? 0.0 : (time < (startTime + duration)) ? height : 0.0
    end
end;

@model AngleSensor begin
    phi=Modia.Rotational.Angle()
    flange=Flange()
    @equations begin
        0=flange.tau
        phi=flange.phi
    end
end;

@model ExpSine begin
    amplitude = Parameter(1.0, info="Amplitude of sine wave")
    freqHz = Parameter(2.0, info="Frequency of sine wave")
    phase = Parameter(0.0, info="Phase of sine wave")
    damping = Parameter(start=1.0, info="Damping coefficient of sine wave")
    offset = Parameter(0.0, info="Offset of output signal")
    startTime = Parameter(0.0, info="Output = offset for time < startTime")
    @extends Modia.Blocks.SO()
    @inherits y
    @equations begin
        y = offset + (time < startTime ? 0 : amplitude*exp(-
            (time - startTime)*damping)*sin(2*pi*freqHz*(time -
            startTime) + phase));
    end
end;  

@model SysTest2a begin
    u = Float(info="input")
    torque = Torque()
    inertia1 = Inertia(J=0.1)
    springDamper = SpringDamper(c=10, d=0.1)
    inertia2 = Inertia(J=10)
    angleSensor = AngleSensor()
    expSine = ExpSine(freqHz=2, damping=0.5)
    @equations begin
        connect(u, torque.tau)
        connect(torque.flange, inertia1.flange_a)
        connect(inertia1.flange_b, springDamper.flange_a)
        connect(springDamper.flange_b, inertia2.flange_a)
        connect(inertia2.flange_b, angleSensor.flange)
        connect(angleSensor.phi, expSine.y)
    end    
end;

result2 = simulate(SysTest2a, 10, removeSingularities=false, logTranslation=true, logSimulation=true)

logTranslation = true
removeSingularities = false
Log file: C:\Users\laughman/C:\Users\laughman/ModiaResults/SysTest2a.txt

Simulating model: SysTest2a
Number of equations: 63
Number of variables: 64
Number of continuous states: 4
Number of non states: 1
type Global has no field head

Stacktrace:
 [1] getproperty(::Any, ::Symbol) at .\sysimg.jl:18
 [2] differentiate(::Modia.Instantiation.Global) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:610
 [3] differentiate(::Expr) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:660 (repeats 2 times)
 [4] differentiate(::Expr) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:689
 [5] differentiate(::Expr) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:758
 [6] differentiate(::Expr) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:689
 [7] differentiate(::Expr) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:632
 [8] differentiate(::Expr) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:660
 [9] differentiate(::Expr) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:611
 [10] differentiateEquations(::Array{Any,1}, ::Array{Any,1}, ::Array{Any,1}, ::Array{Int64,1}, ::Array{Int64,1}, ::Array{Int64,1}, ::Int64) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:877
 [11] differentiateSortedEquations(::Array{Any,1}, ::Array{Any,1}, ::Array{Any,1}, ::Array{Int64,1}, ::Array{Int64,1}, ::Array{Int64,1}) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\DAEquations\SymbolicTransform.jl:982
 [12] macro expansion at .\util.jl:154 [inlined]
 [13] elaborateModel(::Modia.Instantiation.Instance) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\ModelElaboration.jl:134
 [14] #simulateModelWithOptions#7(::Base.Iterators.Pairs{Symbol,Bool,Tuple{Symbol,Symbol,Symbol},NamedTuple{(:removeSingularities, :logTranslation, :logSimulation),Tuple{Bool,Bool,Bool}}}, ::Function, ::Modia.Instantiation.Model, ::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}) at C:\Users\laughman\.julia\packages\Modia\kJUT1\src\symbolic\ModelElaboration.jl:351
 [15] #simulate#9 at .\none:0 [inlined]
 [16] (::getfield(Modia.ModelElaboration, Symbol("#kw##simulate")))(::NamedTuple{(:removeSingularities, :logTranslation, :logSimulation),Tuple{Bool,Bool,Bool}}, ::typeof(simulate), ::Modia.Instantiation.Model, ::Int64) at .\none:0
 [17] top-level scope at In[77]:1
HildingElmqvist commented 5 years ago

I have not found the problem yet. Is there a corresponding Modelica model to compare with? As I understand, there should be 2 remaining states: inertia1.phi, inertia1.w, right?

crlaugh commented 5 years ago

I think that is correct. Here is the equivalent Modelica code for the Modia model that I am trying to create; it is a nice example of a use of acausal models that cannot be easily replicated using a block-based paradigm.

model InverseRotational
  Modelica.Mechanics.Rotational.Components.Inertia inertia1(J=0.1)
    annotation (Placement(transformation(extent={{-44,-2},{-24,18}})));
  Modelica.Mechanics.Rotational.Components.Inertia inertia2(J=10)
    annotation (Placement(transformation(extent={{22,-2},{42,18}})));
  Modelica.Blocks.Math.InverseBlockConstraints inverseBlockConstraints
    annotation (Placement(transformation(extent={{34,-50},{-6,-24}})));
  Modelica.Mechanics.Rotational.Components.SpringDamper springDamper(c=10, d=0.1)
    annotation (Placement(transformation(extent={{-8,-2},{12,18}})));
  Modelica.Blocks.Sources.ExpSine expSine(freqHz=2, damping=0.5)
    annotation (Placement(transformation(extent={{78,-48},{58,-28}})));
  Modelica.Mechanics.Rotational.Sensors.AngleSensor angleSensor
    annotation (Placement(transformation(extent={{52,-2},{72,18}})));
  Modelica.Mechanics.Rotational.Sources.Torque torque
    annotation (Placement(transformation(extent={{-76,-2},{-56,18}})));
equation 
  connect(inertia1.flange_b, springDamper.flange_a)
    annotation (Line(points={{-24,8},{-8,8}}, color={0,0,0}));
  connect(springDamper.flange_b, inertia2.flange_a)
    annotation (Line(points={{12,8},{22,8}}, color={0,0,0}));
  connect(inertia2.flange_b, angleSensor.flange)
    annotation (Line(points={{42,8},{52,8}}, color={0,0,0}));
  connect(angleSensor.phi, inverseBlockConstraints.u2) annotation (Line(points={
          {73,8},{86,8},{86,-12},{18,-12},{18,-37},{30,-37}}, color={0,0,127}));
  connect(inverseBlockConstraints.u1, expSine.y) annotation (Line(points={{36,-37},
          {48,-37},{48,-38},{57,-38}}, color={0,0,127}));
  connect(inertia1.flange_a, torque.flange)
    annotation (Line(points={{-44,8},{-56,8}}, color={0,0,0}));
  connect(torque.tau, inverseBlockConstraints.y2) annotation (Line(points={{-78,
          8},{-90,8},{-90,-12},{6,-12},{6,-37},{-3,-37}}, color={0,0,127}));
  annotation (
    Icon(coordinateSystem(preserveAspectRatio=false)),
    Diagram(coordinateSystem(preserveAspectRatio=false)),
    experiment(StopTime=10),
    __Dymola_experimentSetupOutput,
    __Dymola_experimentFlags(
      Advanced(GenerateVariableDependencies=false, OutputModelicaCode=false),
      Evaluate=false,
      OutputCPUtime=false,
      OutputFlatModelica=false));
end InverseRotational;
MartinOtter commented 5 years ago

Since it is an inverse model and no filter for the reference value is used (which is fine here, because the input expSine(..) can be analytically differentiated), the number of states are less as the original model. From the statistics:

Simulating model: SysTest2a
Number of equations: 63
Number of variables: 64
Number of continuous states: 4
Number of non states: 1

It can be seen that the number of states are not correct. In particular the following relation must hold (the Modia log should make this more explicit, by explicitly stating that states must be removed):

Number of equations + Number of variables - Number of continuous states = 0

This means that there are 3 states too much. Since Modia does not yet support automatic state selection, this means that 3 states have to be removed. I tried various versions, but all give a similar error. For example:

Angle(; args...) = Variable(; start = 0.0, size = (),
                              T = U"rad", info = "Rotational angle", args...)
AngularVelocity(; args...) = Variable(; start = 0.0, size = (),
                              T = U"rad/s", info = "Angular Velocity", args...)

@model SysTest2a begin
    u = Float(info="input")
    torque = Torque()
    inertia1 = Inertia(J=0.1,phi=Angle(state=false), w=AngularVelocity(state=false))
    springDamper = SpringDamper(c=10, d=0.1,phi_rel=Angle(state=true))
    inertia2 = Inertia(J=10,phi=Angle(state=false), w=AngularVelocity(state=false))
    angleSensor = AngleSensor()
    expSine = ExpSine(freqHz=2, damping=0.5)
    @equations begin
        connect(u, torque.tau)
        connect(torque.flange, inertia1.flange_a)
        connect(inertia1.flange_b, springDamper.flange_a)
        connect(springDamper.flange_b, inertia2.flange_a)
        connect(inertia2.flange_b, angleSensor.flange)
        connect(angleSensor.phi, expSine.y)
    end
end;

Simulating model: SysTest2a
Number of equations: 63
Number of variables: 64
Number of continuous states: 1
Number of non states: 4
ERROR: LoadError: type Global has no field head
Stacktrace:
 [1] getproperty(::Any, ::Symbol) at .\sysimg.jl:18
 [2] differentiate(::Modia.Instantiation.Global) at \src\symbolic\DAEquations\SymbolicTransform.jl:610

The equation/variable count is now correct, but still an error is present. I also checked the model and it looks good. One could simplify it a bit, by removing u = Float(info="input") and connect(u, torque.tau), but still the error occurs (since Modia does not yet support input/output attributes it is not checked whether signal connections respect block-diagram restrictions and therefore the "inverseBlockConstraint" block of Modelica is not needed here (yet)).

MartinOtter commented 5 years ago

So to summarize: The corrected model looks now good for me and it seems that this is a bug in Modia.