OpenModelica - Estou tentando executar um exemplo de livro, mas estou tendo problemas internos e externos

StackOverflow https://stackoverflow.com/questions/19841314

  •  29-07-2022
  •  | 
  •  

Pergunta

Estou executando o OpenModelica e tentando executar um exemplo de Introdução à Modelagem Física com Modelica.Copiei os exemplos 9.1 - 9.4 em um pacote.O arquivo agora fica assim:

    package gravityPackage
  //Test of gravity taken from Intro to Physical modeling with Modelica
  //
  //
  //
  //
  //
  model ParticleField
    inner function gravity = TwoBodyField;
    Particle p1(x_init = {2,-2,0}, v_init = {0.7,0,0});
    Particle p2(x_init = {0,0.5,0}, v_init = {-1,-1,0});
    Particle p3(x_init = {0.5,2,0}, v_init = {-1,-0.5,0});
  end ParticleField;
  function TwoBodyField
    extends GravityField;
  protected
    Modelica.SIunits.Position b1[3],b2[3];
    Modelica.SIunits.Velocity n1[3],n2[3];
  algorithm
    b1:={0,0,0};
    b2:={0,1,0};
    n1:=-(x - b1) / sqrt((x - b1) * (x - b1));
    n2:=-(x - b2) / sqrt((x - b2) * (x - b2));
    g:=n1 / ((x - b1) * (x - b1)) + n2 / ((x - b2) * (x - b2));
  end TwoBodyField;
  partial function GravityField
    input Modelica.SIunits.Position x[3];
    output Modelica.SIunits.Acceleration g[3];
  end GravityField;
  model Particle
    parameter Modelica.SIunits.Position x_init[3];
    parameter Modelica.SIunits.Velocity v_init[3];
  protected
    outer function gravity = GravityField;
    //outer function gravity=ParticleField;
    //outer function gravity=TwoBodyField;
    Modelica.SIunits.Position x[3](start = x_init);
    Modelica.SIunits.Velocity v[3](start = v_init);
    Modelica.SIunits.Acceleration a[3];
  equation
    v = der(x);
    a = der(v);
    a = gravity(x);
  end Particle;
end gravityPackage;

Mas, se eu for ao OMShell e tentar executá-lo, recebo o seguinte:

    >> loadFile("gravityPackage.mo")
true


>> simulate(gravityPackage.ParticleField) 
record SimulationResult
    resultFile = "",
    simulationOptions = "startTime = 0.0, stopTime = 1.0, numberOfIntervals = 500, tolerance = 0.000001, method = 'dassl', fileNamePrefix = 'gravityPackage.ParticleField', options = '', outputFormat = 'mat', variableFilter = '.*', measureTime = false, cflags = '', simflags = ''",
    messages = "Simulation failed for model: gravityPackage.ParticleField
[gravityPackage.mo:34:11-34:42:writable] Warning: No corresponding 'inner' declaration found for class gravity declared as 'outer '.
 Continuing flattening by only considering the 'outer' class declaration.
[gravityPackage.mo:43:5-43:19:writable] Error: Failed to instantiate equation 
a = gravity(x);.
Error: Error occurred while flattening model gravityPackage.ParticleField
",
    timeFrontend = 0.0,
    timeBackend = 0.0,
    timeSimCode = 0.0,
    timeTemplates = 0.0,
    timeCompile = 0.0,
    timeSimulation = 0.0,
    timeTotal = 0.0
end SimulationResult;

>> 

Então, claramente há algo relacionado ao escopo que não estou acertando.Todo o código, exceto o pacote, é copiado diretamente do livro.Acredito que o pacote seja necessário para colocá-lo em um único arquivo (embora eu tenha tentado algumas outras maneiras de fazer isso sem sucesso).Qualquer sugestão será apreciada.

Obrigado,

Foi útil?

Solução

Este é um bug no OpenModelica. Deve funcionar bem se for um componente ou classe interna, mas não para funções.

Eu adicionei um relatório de bug sobre isso e vamos consertar:https://trac.openmodelica.org/openmodelica/ticket/2467

Por enquanto, você pode usar um pacote interno/externo, que deve funcionar bem.

package gravityPackage

package Functions
  function TwoBodyField
    extends GravityField;
  protected
    Modelica.SIunits.Position b1[3],b2[3];
    Modelica.SIunits.Velocity n1[3],n2[3];
  algorithm
    b1:={0,0,0};
    b2:={0,1,0};
    n1:=-(x - b1) / sqrt((x - b1) * (x - b1));
    n2:=-(x - b2) / sqrt((x - b2) * (x - b2));
    g:=n1 / ((x - b1) * (x - b1)) + n2 / ((x - b2) * (x - b2));
  end TwoBodyField;

  partial function GravityField
    input Modelica.SIunits.Position x[3];
    output Modelica.SIunits.Acceleration g[3];
  end GravityField;

end Functions;

model ParticleField
    inner package funcs = Functions;
    Particle p1(x_init = {2,-2,0}, v_init = {0.7,0,0});
    Particle p2(x_init = {0,0.5,0}, v_init = {-1,-1,0});
    Particle p3(x_init = {0.5,2,0}, v_init = {-1,-0.5,0});
  end ParticleField;

  model Particle
    parameter Modelica.SIunits.Position x_init[3];
    parameter Modelica.SIunits.Velocity v_init[3];
  protected
    outer package funcs = Functions;
    function gravity = funcs.TwoBodyField;
    //outer function gravity=ParticleField;
    //outer function gravity=TwoBodyField;
    Modelica.SIunits.Position x[3](start = x_init);
    Modelica.SIunits.Velocity v[3](start = v_init);
    Modelica.SIunits.Acceleration a[3];
  equation
    v = der(x);
    a = der(v);
    a = gravity(x);
  end Particle;

end gravityPackage;

Outras dicas

OK, acho que o problema aqui é que você está tentando "passar" uma função pela árvore de instâncias usando escopo dinâmico (ou seja, inner e outer).Não li a especificação sobre esse ponto específico, mas não acho que isso funcione.A razão é que normalmente inner e outer são usados ​​em conjunto com coisas que são instanciadas (variáveis, modelos, etc.).

Portanto, a coisa a entender é que conceitualmente ambos constant variáveis ​​e function definições não são instanciadas.Ser capaz de tratar um function como instância (um valor de primeira classe) tem várias consequências úteis, mas também introduz algumas complicações semânticas.Tem havido trabalho em versões recentes da linguagem para tentar tratar as funções como cidadãs de primeira classe.O principal caso de uso era passar funções como argumentos para outras funções.Mas acho que essa nova semântica não chega a tornar as funções valores verdadeiramente de primeira classe (como seu exemplo demonstraria).No entanto, isso pode ser um problema com o OpenModelica.Não posso dizer definitivamente.

Uma maneira de lidar com isso seria usar substituível e declarar novamente.Então no seu Particle modelo, definir gravity assim:

public
  replaceable function gravity = GravityField;

Em seguida, instancie-o da seguinte maneira:

model ParticleField
  Particle p1(x_init = {2,-2,0}, v_init = {0.7,0,0}, redeclare function gravity = TwoBodyField);
  Particle p2(x_init = {0,0.5,0}, v_init = {-1,-1,0}, redeclare function gravity = TwoBodyField);
  Particle p3(x_init = {0.5,2,0}, v_init = {-1,-0.5,0}, redeclare function gravity = TwoBodyField);
end ParticleField;

Observe que não testei esta solução.Por exemplo, seu Particle modelo pode exigir o partial qualificador (já que você teria que substituir gravity para um não-partial implementação).

Espero que isso ajude.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top