I work with understanding how parametrized packages in a library can be adapted to external application code, i.e. I like to keep library code and application code very separate.
In my example here I have two parameters of my package Equipment, a connector LCon and also a model CType. The connector affect all models in the Equipment package. The model CType only affects one model RType in the Equipment (and have a closer inner-outer relation) to that model.
When I adapt the package Equipment to the application requirement of LCon2 and CTyp2 I can do that in one sweep as below.
code1
package Equipment2
import BR5i.Equipment;
extends Equipment(redeclare connector LCon=LCon2,
redeclare model CType=CType2);
end Equipment2;
However, I think the code (in the long run) is more readable if I divide these two adaptations to two different parts. I try the code below, but does not work. Error text: Cannot find class declaration for RType - when I run it in JModelica.
code2
package Equipment2
import BR5i.Equipment;
extends Equipment(redeclare connector LCon=LCon2);
end Equipment2;
model BRType2
import BR5i.Equipment2.RType;
extends RType(redeclare model CType=CType2);
end BRType2;
(And for code 2 the library was modified so the parameter CType was moved Equipment level down to the individual model RType where CType should serve as a parameter. And in the end I want BRType2 for code 2 correspond to Equipment2.RType from code 1).
I wonder if it is at all possible to make changes in several steps like this, i.e. first RType get a new connector LCon2 and then in the next step RType now imported from Equipment2 shall get CType replaced to CType2?
I understand that the code should not be seen as a sequence of "assignment statements", but rather parallel. In my eyes the logic of the "equations" in code 2 should make it possible to get a correct BRType2.
I have recently got some help on the subject from both people related to Modelon and to OpenModelica and I am grateful for that. Below updated files of the library and the application. The presented code does work in JModelica and OpenModelica and now also in Dymola.
A couple of comments to the code errors that are corrected.
In the model Test I have the habit to make an instance of the Medium of interest. It is actually not allowed (and not very meaningful either) to make an instance of a package like this in Modelica, although current versions of JModelica and OpenModelica support it. The reason I do this instance of the package Medium is two-fold:
I need generally in Test (but not in this example) have access to information in the medium package to make the configuration. For example if I connect a sensor to the harvest tank and that sensor is of gernal type then I need to specify what substance I want to measure and that is best done using the mnemonics for substance position in the state vector store in the package medium. I can of course import the mnemonics I need for the configuration, one by one, but shorter and even more readable to just use the medium package.
From the FMU it is good to be able to access the information in the medium package. This package may contain not only mnemonics but also various facts about the medium that we want to make use of when designing a tailer-made user interface for the FMU and interactive simulation. This is what I do in Python using JModelica. This works actually fine as it is now with JModelica and PyFMI but what I have learned is forbidden in Modelica.
In several places I transmit the number of components in the medium nc to the different equipment models. And I do this transmission of nc somewhat in-directly using the connector and “measure" the size of the vector. This is not OK to do like this in Modelica at compilation time.Also this works in both JModelica and OpenModelica currently, but not in Dymola. I resolve this by introducing a local constant in the general package Equipment that is unspecified, but given the appropriate number later when the package is adapted to the medium that should be used. Then it get the value medium.nc
These modification make the code more generally accepted I hope, and at least works for JModelica, OpenModelica and Dymola. However, I am not too happy with the solutions since it do not address the my uderlying user-requirements as described above.
Also, with this “solution”, the “alternative 2” - adaptation of the library in two (or more steps) is not relevant - which after all was the key question in the post. I will try to re-formulate this question with a smaller example in a new post later on.
Below the library DEMO_v18_alt1 and then after that the application d18_alt1_app7
package DEMO_v18_alt1
// Here I have put together a small demo-library to illustrate questions
// around structuring handling of medium. The key structures are taken
// from MSL fluid, I think it is fair to say.
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
package Medium2
replaceable constant String name = "Two components" "Medium name";
replaceable constant Integer nc = 2 "Number of substances";
replaceable type Concentration = Real[nc] "Substance conc";
replaceable constant Real[nc] mw = {10, 20} "Substance weight";
constant Integer A = 1 "Substance index";
constant Integer B = 2 "Substance index";
end Medium2;
package Medium3
import M2 = DEMO_v18_alt1.Medium2;
extends M2
(name="Three components" "Medium name",
nc=3 "Number of substances",
mw = cat(1,M2.mw,{30}) "Substance weight",
redeclare type Concentration = Real[nc] "Substance conc");
constant Integer C = 3 "Substance index";
end Medium3;
model Reaction3
constant Integer nc = 3;
outer Real[nc] c;
outer Real[nc] q;
equation
q[1] = 0;
q[2] = 0;
q[3] =-c[3];
end Reaction3;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package Equipment
constant Integer nc;
connector LiquidCon
Real[nc] c "Substance conc";
flow Real F (unit="m3/s") "Flow rate";
end LiquidCon;
replaceable model ReactionType = NoReaction // Alternative 1
constrainedby ReactionTypeInterface;
partial model ReactionTypeInterface // Alternative 1
outer Real[nc] c, q;
end ReactionTypeInterface;
model NoReaction // Alternative 1
extends ReactionTypeInterface;
equation
for i in 1:nc loop
q[i] = 0;
end for;
end NoReaction;
model PumpType
LiquidCon inlet, outlet;
RealInput Fsp;
equation
inlet.F = Fsp;
connect(outlet, inlet);
end PumpType;
model FeedtankType
LiquidCon outlet;
parameter Real[nc] c_in (each unit="kg/m3")
= {1.0*k for k in 1:nc} "Feed inlet conc";
parameter Real V_0 (unit="m3") = 100 "Initial feed volume";
Real V(start=V_0, fixed=true, unit="m3") "Feed volume";
equation
for i in 1:nc loop
outlet.c[i] = c_in[i];
end for;
der(V) = outlet.F;
end FeedtankType;
model HarvesttankType
// Connection to reaction
// replaceable model ReactionType = NoReaction constrainedby ReactionTypeInterface; // Alternative 2
ReactionType reaction;
inner Real[nc] c "Substance conc";
inner Real[nc] q "Reaction rate";
LiquidCon inlet, port;
parameter Real V_0 (unit="m3") = 1.0 "Initial harvest liquid volume";
parameter Real[nc] m_0
(each unit="kg/m3") = zeros(nc) "Initial substance mass";
Real[nc] m
(start=m_0, each fixed=true) "Substance mass";
Real V(start=V_0, fixed=true, unit="m3") "Harvest liquid volume";
equation
for i in 1:nc loop
der(m[i]) = inlet.c[i]*inlet.F + q[i];
c[i] = m[i]/V;
port.c[i] = c[i];
end for;
der(V) = inlet.F;
end HarvesttankType;
end Equipment;
// ---------------------------------------------------------------------------------------------
// Control
// ---------------------------------------------------------------------------------------------
package Control
block FixValueType
RealOutput out;
parameter Real val=0;
equation
out = val;
end FixValueType;
end Control;
// ---------------------------------------------------------------------------------------------
// Adaptation of library for the actual culture and media
// ---------------------------------------------------------------------------------------------
package Equipment3 // Alternative 1
import DEMO_v18_alt1.Equipment;
extends Equipment(nc=Medium3.nc,
redeclare model ReactionType=Reaction3);
end Equipment3;
// package Equipment3 // Alternative 2
// import DEMO_v18_alt2.Equipment;
// extends Equipment(nc=Medium3.nc);
// end Equipment3;
// model HarvesttankType3
// import DEMO_v18_alt2.Equipment3.HarvesttankType;
// extends HarvesttankType(redeclare model ReactionType=Reaction3);
// end HarvesttankType3;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
package medium = DEMO_v18_alt1.Medium3; // Not accessible in FMU though
Equipment3.FeedtankType feedtank;
Equipment3.HarvesttankType harvesttank; // Alternative 1
// HarvesttankType3 harvesttank; // Alternative 2
Equipment3.PumpType pump;
Control.FixValueType Fsp(val=0.2);
equation
connect(feedtank.outlet, pump.inlet);
connect(pump.outlet, harvesttank.inlet);
connect(Fsp.out, pump.Fsp);
end Test;
end DEMO_v18_alt1;
and here the application code
encapsulated package d18_alt1_app7
// Here I put together an application for 7 substances - print 8 pt
// and import code from the library DEMO.
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
package Medium7
import M2 = DEMO_v18_alt1.Medium2;
extends M2
(name = "Seven components" "Medium name",
nc = 7 "Number of substances",
mw = cat(1,M2.mw,{30,40,50,60,70}) "Substance weight",
redeclare type Concentration = Real[nc] "Substance conc");
constant Integer C = 3 "Substance index";
constant Integer D = 4 "Substance index";
constant Integer E = 5 "Substance index";
constant Integer F = 6 "Substance index";
constant Integer G = 7 "Substance index";
end Medium7;
model Reaction7
constant Integer nc = 7;
outer Real[nc] c;
outer Real[nc] q;
equation
q[1] = 0;
q[2] = 0;
q[3] = 0;
q[4] = 0;
q[5] = 0;
q[6] = 0;
q[7] =-c[7];
end Reaction7;
// ---------------------------------------------------------------------------------------------
// Adaptation of library DEMO_v18_alt1 to Medium7 and Reaction7
// ---------------------------------------------------------------------------------------------
package Equipment7
import DEMO_v18_alt1.Equipment;
extends Equipment(nc=Medium7.nc,
redeclare model ReactionType=Reaction7);
end Equipment7;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
import DEMO_v18_alt1.Control;
model Test
package medium = d18_alt1_app7.Medium7; // Not accessible in FMU though
Equipment7.PumpType pump;
Equipment7.FeedtankType feedtank;
Equipment7.HarvesttankType harvesttank;
Control.FixValueType Fsp(val=0.2);
equation
connect(feedtank.outlet, pump.inlet);
connect(pump.outlet, harvesttank.inlet);
connect(Fsp.out, pump.Fsp);
end Test;
end d18_alt1_app7;