I work with finding a good way to divide code in two parts: a general library and and application code, The examples I work with usually contain liquids and I want to make the general library independent of the number of components in the liquid. The idea is that the application code set the liquid medium used and then import equipment from the general library and adapt these equipment to the actual medium.
The example below is a very concise example that illustrate one way to do this division of code. Here I let value nc of number of components be undefined in the partial package MediumBase. Later when the EquipmentLib is adapted to the actual Medium then nc get a value. This is what I mean with “delay” setting of structural parameter. The code works well in both JModelica and OpenModelica.
package DEMO_v30
// Author: Jan Peter Axelsson
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
partial package MediumBase
constant Integer nc "Number of components";
replaceable type Concentration = Real[nc] "Component conc";
end MediumBase;
package Medium3
extends MediumBase (nc=3);
end Medium3;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package EquipmentLib
replaceable package Medium = MediumBase // formal parameter - EquipmentLib
constrainedby MediumBase;
model ReactorType
parameter Medium.Concentration c_0 = ones(Medium.nc) "Initial component conc";
Medium.Concentration c (start=c_0, each fixed=true) "Component conc";
equation
for i in 1:Medium.nc loop
der(c[i]) = -c[i];
end for;
end ReactorType;
end EquipmentLib;
// ---------------------------------------------------------------------------------------------
// Adaptation of package Equipment to Medium3
// ---------------------------------------------------------------------------------------------
package Equipment
import DEMO_v30.EquipmentLib;
extends EquipmentLib(redeclare package Medium=Medium3);
end Equipment;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
Equipment.ReactorType reactor;
end Test;
end DEMO_v30;
In slightly larger examples with the same code structure I get some problems though:
- In JModelica I get a warning that “The constant nc does not have a binding expression"
- In OpenModelica I get an error that “Could not evaluate structural parameter (or constant) .. nc which gives dimensions of array c[MediumBase.nc]. Array dimension must be know at compile time'
The message does not make sense to me since nc is known at compile time, at the level of where EquipmentLib is adapted. This problem can actually be resolved by givning nc in MediumBase a “dummy” value nc=1 in Medium Base, and then that nc get changed during compilation to the value provided when EquipmentLib is adapted.
So my questions are:
- To me it looks better to keep nc undefined and then make sure value is set during compilation, while changing a constant during compilation looks questionable, but perhaps (still) allowed in Modelica. IN the Modelica language specification I can see in Appendix A that the requirement of a constant is (only) that it is constant during simulation, i.e. not during compilation. In appendix E8.2 I see that perhaps an initial assignment of nc should be done, but not sure. Would appreciate some comment on this though.
- How could it be that with a somewhat larger example compilers of JModelica and OpenModelica give warning and error, respectively?
- What the Modelica specification say about what is right here?
If needed I can provide the larger example, but I think that here might be a more general answer.