I buy the idea that to make a library package parametrized in a safe way you make the flexibility as “small” as you can. You can in the package have a constant integer nc that you give the number Medium3.nc at the time when you adapt the package. And then the connector LiquidCon is defined inside the package Equipment and have a declaration of concentration vector as Real [nc] c; Other information about the Medium than nc can be brought to the application Test on configuration level rather than as adaptation of the package Equipment, and not discussed in this example but in other related posts. In this way the package adaptation process would be as “safe” as you can.
The other adaptation that involves introducing a ReactionType to HarvesttankType (that is now adapted to the actual nc) needs to be very flexible for this library package to be of any interest. What we require from the ReactionType is to have the interface: outer Real(nc] c, q; and that we can describe in a partial model and use the constrainedby construction, to bring some safety.
See code DEMO_v17_alt1 and d17_alt1_app7 below.
However, I would prefer to write the code as alt2 and keep ReactionType etc defined for HarvesttankType only and not for the whole Equipment package. That would need to allow for a two-step procedure of adaptation of the library. First level adapt the Equipment to the number of medium components. Second level adapt the now adapted HarvesttankType to the ReactionType. This is not possible in JModelica, but actually in OpenModelica.
So only alt1 works in JModelica 2.4 while both alt1 and alt2 works in OpenModelica 1.13.2 (and 1.14 beta). What does the current Modelica definition say?
The library code DEMO_v17_alt1:
package DEMO_v17_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_v17_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;
constant Integer medium_nc = size(outlet.c,1);
parameter Real[medium_nc] c_in (each unit="kg/m3")
= {1.0*k for k in 1:medium_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:medium_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[medium_nc] c "Substance conc";
inner Real[medium_nc] q "Reaction rate";
LiquidCon inlet, port;
constant Integer medium_nc = size(inlet.c,1);
parameter Real V_0 (unit="m3") = 1.0 "Initial harvest liquid volume";
parameter Real[medium_nc] m_0
(each unit="kg/m3") = zeros(medium_nc) "Initial substance mass";
Real[medium_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:medium_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 DEMO_v17_alt1 to Medium3 and Reaction3
// ---------------------------------------------------------------------------------------------
package Equipment3 // Alternative 1
import DEMO_v17_alt1.Equipment;
extends Equipment(nc=Medium3.nc,
redeclare model ReactionType=Reaction3);
end Equipment3;
// package Equipment3 // Alternative 2
// import DEMO_v17_alt2.Equipment;
// extends Equipment(nc=3);
// end Equipment3;
// model HarvesttankType3
// import DEMO_v17_alt2.Equipment3.HarvesttankType;
// extends HarvesttankType(redeclare model ReactionType=Reaction3);
// end HarvesttankType3;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
Medium3 medium;
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_v17_alt1;
and the application code d17_alt1_app7
encapsulated package d17_alt1_app7
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
package Medium7
import M2 = DEMO_v17_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_v17_alt1 to Medium7 and Reaction7
// ---------------------------------------------------------------------------------------------
package Equipment7
import DEMO_v17_alt1.Equipment;
extends Equipment(nc=Medium7.nc,
redeclare model ReactionType=Reaction7);
end Equipment7;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
import DEMO_v17_alt1.Control;
model Test
Medium7 medium; // Instance not necessary but helpful for user interface
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 d17_alt1_app7;