Extending packages and access to the content - modelica
I continue work on understanding how to best divide code in library and application. In a few previous posts I have worked with a toy example DEMO_xx library with application dxx_app7. Below is a slightly updated version to cover the question here. I have included the possibility to add a sensor to the harvest tank.
Now I want to understand how to in application code bring in information from the application Medium7 that is extended from the library Medium2 and use that fully in a new component model in the application.
What I understand is that if you import a package that is extended from another package you only get what is the “latest” package and NOT what is built up from through extensions and what is aggregated total Medium7 information.
This fact is illustrated in the example by changing the constant SensorX.component from C that works to A or B that does not work.
However, if I make a local instance of Medium7 THEN I get the complete information of Medium7. I can do that in SensorX as marked Question 1 - alt 2.
I can also do this choice of substrate to measure out in the configuration of the system and marked Question 1 alt 3. This is more readable code I think.
But how do I make all of the content of Medium7 available locally? Must I define locally a new constant for every constant I need as I show here with sensorX.component? Generally you may want to in a model have access to various properties of the medium and that is convenient to put in the package Medium
Also I wish I could import a connector LiquidCon adapted for Medium7 instead of writing that code once again in package Sensor7. Import as suggested does not work. Is there another way? I have only tested the code in JModelica 2.4 and it might be a bug?
Would appreciate some input on these two questions. / Jan Peter
Below the application code d12_app7 that is of interest for the questions and then the associated library DEMO_v12. I have marked up with comments changes of code for the two questions and as the code stands it is for question 1 alt 1.
encapsulated package d12_app7
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
package Medium7
import M2 = DEMO_v12.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;
// ---------------------------------------------------------------------------------------------
// New sensor introduced in this application for measurement of substance A
// ---------------------------------------------------------------------------------------------
package Sensor7
connector LiquidCon
Medium7.Concentration c "Substance conc";
flow Real F (unit="m3/s") "Flow rate";
end LiquidCon;
model SensorX
// import d12_app7.Equipment7.LiquidCon; // Question 2
import d12_app7.Medium7.*; // Question 1 - alt 1
constant Integer component = C; // Question 1 - alt 1
// constant Integer component = d12_app7.Medium7.A; // Question 1 - alt 2
LiquidCon probe;
RealOutput out;
equation
probe.F = 0;
out = probe.c[component];
end SensorX;
end Sensor7;
// ---------------------------------------------------------------------------------------------
// Adaptation of library DEMO_v12 to Medium7
// ---------------------------------------------------------------------------------------------
package Equipment7
import DEMO_v12.Equipment;
extends Equipment(redeclare package Medium=Medium7);
end Equipment7;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
import DEMO_v12.Control;
model Test
Equipment7.Medium medium; // Instance not necessary but helpful for user interface
Equipment7.PumpType pump;
Equipment7.FeedtankType feedtank;
Equipment7.HarvesttankType harvesttank;
Sensor7.SensorX sensor; // Question 1 alt 1 and 2
// Sensor7.SensorX sensor(component = medium.A); // Question 1 alt 3
Control.FixValueType Fsp(val=0.2);
equation
connect(feedtank.outlet, pump.inlet);
connect(pump.outlet, harvesttank.inlet);
connect(Fsp.out, pump.Fsp);
connect(sensor.probe, harvesttank.port);
end Test;
end d12_app7;
And finally the library code DEMO_v12
package DEMO_v12
// ---------------------------------------------------------------------------------------------
// 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_v12.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;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package Equipment
replaceable package Medium
end Medium;
connector LiquidCon
Medium.Concentration c "Substance conc";
flow Real F (unit="m3/s") "Flow rate";
end LiquidCon;
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
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] c "Substance conc";
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;
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;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
// package Equipment3 = Equipment(redeclare package Medium=Medium3); // Just shorter version
package Equipment3
import DEMO_v12.Equipment;
extends Equipment(redeclare package Medium=Medium3);
end Equipment3;
model Test
Equipment3.Medium medium;
Equipment3.FeedtankType feedtank;
Equipment3.HarvesttankType harvesttank;
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_v12;
I have also on this post recently got some help from people related to Modelon-JModelica and to OpenModelica - thank you! Below answers and comments as well as updated code.
To make content of Medium7 available we can (likely) do as in the presented code. In my new code I decide what substance to measure not until configuration of the Test model. Therefore I in the model SensorX make a declaration constant Integer component without any value. Note a constant can only be given a value once.
To avoid writing the code of LiquidCon a second time it is better to put the code of the sensor model in the extension of package Equipment where adaptation is made to Medium7.
In the model Test we need to have access to the mnemonics of components. The construction in the code with an instance of a package is not allowed in Modelica (but still works in JModelica and OpenModelica). A generally accepted way to do is given in the new code. Note that this solution makes the content of the actual Medium not accessible through FMU. To get that accessibility local instances need to be made of various medium constants in the model, as done with name.
I have in DEMO_v20.Medium2 taken away “replaceable” in front of constants, and the technique to just give these Medium constants different values in Medium3 is allowed since Modelica 3.2 (but not in 3.1) according to Hans Olsson in a previous post response.
I have in DEMO_v20 introduced a partial MediumBase and then Medium2 extends from that and MeiumBase also is constraining type for the formal parameter Medium for package Equipment.
The code works for JModelica both running DEMO_v20 alone with the Test example for three substances and together with the application code for seven substances. In OpenModelica only the Test example for three substances work, however.
Would appreciate help to get the code working in OpenModelica and to check it in Dymolas as well.
Library code DEMO_v20
package DEMO_v20
// 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;
partial package MediumBase
constant String name "Medium name";
constant Integer nc "Number of substances";
replaceable type Concentration = Real[nc] "Substance conc";
end MediumBase;
package Medium2
extends MediumBase
(name="Two components",
nc=2);
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_v20.Medium2;
extends M2
(name="Three components" "Medium name",
nc=3 "Number of substances",
mw = cat(1,M2.mw,{30}) "Substance weight");
constant Integer C = 3 "Substance index";
end Medium3;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package Equipment
replaceable package Medium = MediumBase
constrainedby MediumBase;
connector LiquidCon
Medium.Concentration c "Substance conc";
flow Real F (unit="m3/s") "Flow rate";
end LiquidCon;
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
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] c "Substance conc";
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;
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 package Equipment to Medium3
// ---------------------------------------------------------------------------------------------
package Equipment3
extends DEMO_v20.Equipment(redeclare package Medium=Medium3);
end Equipment3;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
package medium = DEMO_v20.Medium3; // Not accessible in FMU though
constant String name = medium.name; // But name here is accessible
Equipment3.FeedtankType feedtank;
Equipment3.HarvesttankType harvesttank;
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_v20;
And the corresponding application code d20_app7.mo
encapsulated package d20_app7
// ---------------------------------------------------------------------------------------------
// Interfaces
// ---------------------------------------------------------------------------------------------
import Modelica.Blocks.Interfaces.RealInput;
import Modelica.Blocks.Interfaces.RealOutput;
package Medium7
import M2 = DEMO_v20.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");
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;
// ---------------------------------------------------------------------------------------------
// Adaptation of library DEMO_v20 to Medium7 and including a new model SensorX
// ---------------------------------------------------------------------------------------------
package Equipment7
extends DEMO_v20.Equipment(redeclare package Medium=Medium7);
model SensorX
LiquidCon probe;
RealOutput out;
constant Integer component "Component measured";
equation
probe.F = 0;
out = probe.c[component];
end SensorX;
end Equipment7;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
import DEMO_v20.Control;
model Test
package medium = Medium7; // Not accessible in FMU though
constant String name = medium.name; // But name here is accessible
Equipment7.PumpType pump;
Equipment7.FeedtankType feedtank;
Equipment7.HarvesttankType harvesttank;
Equipment7.SensorX sensor(component = medium.G);
Control.FixValueType Fsp(val=0.2);
equation
connect(feedtank.outlet, pump.inlet);
connect(pump.outlet, harvesttank.inlet);
connect(Fsp.out, pump.Fsp);
connect(sensor.probe, harvesttank.port);
end Test;
end d20_app7;
Tested both DEMO_v20.mo and d20_app7.mo in Dymola Version 2018 (64-bit), 2017-04-10.
Loading the file DEMO_v20.mo gives the error,
<medium declaration> (line 137, column 27: C:/Users/adeas31/Desktop/DEMO_v20.mo)
medium already declared on line 135.
And running DEMO_v20.Test gives,
Translation of DEMO_v20.Test:
For variable feedtank.medium_nc
declared in class DEMO_v20.Equipment.FeedtankType, C:/Users/adeas31/Desktop/DEMO_v20.mo at line 77, and used in component feedtank.
The variability of the definition equation:
feedtank.medium_nc = size(feedtank.outlet.c, 1);
is higher than the declared variability of the variables.
For variable harvesttank.medium_nc
declared in class DEMO_v20.Equipment.HarvesttankType, C:/Users/adeas31/Desktop/DEMO_v20.mo at line 91, and used in component harvesttank.
The variability of the definition equation:
harvesttank.medium_nc = size(harvesttank.inlet.c, 1);
is higher than the declared variability of the variables.
Basic type inconsistencies detected.
Translation aborted.
ERRORS have been issued.
Running d20_app7.Test gives,
Translation of d20_app7.Test:
Encapsulation of d20_app7
prevented us from finding DEMO_v20 in global scope.
Missing base class DEMO_v20.Equipment
the class DEMO_v20.Equipment exists, but Modelica is case-sensitive and uses scoping
File: C:/Users/adeas31/Desktop/d20_app7.mo, line 46
Context: d20_app7.Equipment7
Component type specifier Equipment7.PumpType not found
File: C:/Users/adeas31/Desktop/d20_app7.mo, line 67
Component context: pump
Component declared as Equipment7.PumpType pump in d20_app7.Test
Component type specifier Equipment7.FeedtankType not found
File: C:/Users/adeas31/Desktop/d20_app7.mo, line 68
Component context: feedtank
Component declared as Equipment7.FeedtankType feedtank in d20_app7.Test
Component type specifier Equipment7.HarvesttankType not found
File: C:/Users/adeas31/Desktop/d20_app7.mo, line 69
Component context: harvesttank
Component declared as Equipment7.HarvesttankType harvesttank in d20_app7.Test
Component type specifier LiquidCon not found
File: C:/Users/adeas31/Desktop/d20_app7.mo, line 49
Component context: sensor.probe
Component declared as LiquidCon probe in d20_app7.Equipment7.SensorX
WARNINGS have been issued.
ERRORS have been issued.
Hope that helps.
Thank you Adeel!
The Dymola error log made me do the following changes to the code:
DEMO_v20 here I eliminated the instantiation of medium - forgot it see 3) above
DEMO_v20 here I now get the size of the models from Medium.nc instead of through the connector and size of c.
D20_app7 here I now in the procedure of adaptation of package Equipment, first import, and then extend and adapt to Medium7.
The updated code DEMO_v22 and d22_app7 now works with both JModelica and OpenModelica. Would be good to have it tested in Dymola too 🙂
Updated code DEMO_v22.mo
package DEMO_v22
// 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;
partial package MediumBase
constant String name "Medium name";
constant Integer nc "Number of substances";
replaceable type Concentration = Real[nc] "Substance conc";
end MediumBase;
package Medium2
extends MediumBase
(name="Two components",
nc=2);
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_v22.Medium2;
extends M2
(name="Three components" "Medium name",
nc=3 "Number of substances",
mw = cat(1,M2.mw,{30}) "Substance weight");
constant Integer C = 3 "Substance index";
end Medium3;
// ---------------------------------------------------------------------------------------------
// Equipment dependent on the medium
// ---------------------------------------------------------------------------------------------
package Equipment
replaceable package Medium = MediumBase
constrainedby MediumBase;
connector LiquidCon
Medium.Concentration c "Substance conc";
flow Real F (unit="m3/s") "Flow rate";
end LiquidCon;
model PumpType
LiquidCon inlet, outlet;
RealInput Fsp;
equation
inlet.F = Fsp;
connect(outlet, inlet);
end PumpType;
model FeedtankType
LiquidCon outlet;
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
LiquidCon inlet, port;
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] c "Substance conc";
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;
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 package Equipment to Medium3
// ---------------------------------------------------------------------------------------------
package Equipment3
extends DEMO_v22.Equipment(redeclare package Medium=Medium3);
end Equipment3;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
model Test
package medium = DEMO_v22.Medium3; // Not accessible in FMU though
constant String name = medium.name; // But name here is now accessible
Equipment3.FeedtankType feedtank;
Equipment3.HarvesttankType harvesttank;
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_v22;
and updated application code d22_app7.mo
encapsulated package d22_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_v22.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");
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;
// ---------------------------------------------------------------------------------------------
// Adaptation of library DEMO_v22 to Medium7 and including a new model SensorX
// ---------------------------------------------------------------------------------------------
package Equipment7
import DEMO_v22.Equipment;
extends Equipment(redeclare package Medium=Medium7);
model SensorX
LiquidCon probe;
RealOutput out;
constant Integer component "Component measured";
equation
probe.F = 0;
out = probe.c[component];
end SensorX;
end Equipment7;
// ---------------------------------------------------------------------------------------------
// Examples of systems
// ---------------------------------------------------------------------------------------------
import DEMO_v22.Control;
model Test
package medium = Medium7; // Not accessible in FMU though
constant String name = medium.name; // But name here is accessible
Equipment7.PumpType pump;
Equipment7.FeedtankType feedtank;
Equipment7.HarvesttankType harvesttank;
Equipment7.SensorX sensor(component = medium.G);
Control.FixValueType Fsp(val=0.2);
equation
connect(feedtank.outlet, pump.inlet);
connect(pump.outlet, harvesttank.inlet);
connect(Fsp.out, pump.Fsp);
connect(sensor.probe, harvesttank.port);
end Test;
end d22_app7;
Related
OpenModelica Building Libary, using PlugFlowPipe component
This question is a continuation to the question: OpenModelica: How to model plug flow for multi substance fluid medium? The modelica does not include by default a medium model supporting multiple substances and trace substances. Therefore, I was putting together a medium model that works fine with basic Modelica fluid components (sources, open tanks, static pipe). However, Buildings library's component Buildings.Fluid.FixedResistances.PlugFlowPipe seems to be problematic and I could not figure out why? I have a very limited experience on OpenModelica and would appreciate if someone could help and point out the reasoning. I have ended up to the Building library since I haven't found any other component in other libraries that would model the plug flow and transfer delays in pipe lines. Below are the medium model and Simulation model that has been used for testing. Medium model used: // file: SimpleMachineStockMedium_400_v1.mo package SimpleMachineStockMedium_400_v1 import Modelica = Modelica; // EXTENDING FROM A CLASS // ************************** extends Modelica.Media.Interfaces.PartialMedium( final ThermoStates = Modelica.Media.Interfaces.Choices.IndependentVariables.pTX, final singleState = true, final reducedX = true, final fixedX = false, reference_X=fill(1/nX,nX), mediumName="SimpleMachineStockMedium_400_v1", substanceNames={"water","fiber","filler"}, extraPropertiesNames=fill("", 0) //extraPropertiesNames={"reta"} ); // SPECIFY CONSTANTS // ********************************* constant SpecificHeatCapacity cp_const=4184 "Constant specific heat capacity at constant pressure"; constant SpecificHeatCapacity cv_const=4184 "Constant specific heat capacity at constant volume"; constant Density d_const=995.586 "Constant density"; constant DynamicViscosity eta_const=1.e-3 "Constant dynamic viscosity"; constant ThermalConductivity lambda_const=0.598 "Constant thermal conductivity"; constant VelocityOfSound a_const=1484 "Constant velocity of sound"; constant Temperature T_min=273 "Minimum temperature valid for medium model"; constant Temperature T_max=373 "Maximum temperature valid for medium model"; constant Temperature T0=273.15 "Zero enthalpy temperature"; // defining fluid constants for substances import Modelica.Media.Water.ConstantPropertyLiquidWater.simpleWaterConstants; constant Modelica.Media.Interfaces.Types.Basic.FluidConstants[3] simpleWaterConstants( each chemicalFormula="H2O", each structureFormula="H2O", each casRegistryNumber="7732-18-5", each iupacName="oxidane", each molarMass=0.018015268); //constant MolarMass MM_const "Molar mass"; // Molarmasses are defined for substances, just giving same values for all constant Real MM_const_fiber = 0.018015268; constant Real MM_const_filler = 0.018015268; constant Real MM_const_water = 0.018015268; constant MolarMass[nX] MMX ={MM_const_fiber, MM_const_filler, MM_const_water} "Molar mass"; // THERMODYNAMIC STATE // ********************** redeclare record extends ThermodynamicState "Thermodynamic state" AbsolutePressure p "Absolute pressure of medium"; Temperature T "Temperature of medium"; // bring in the substances MassFraction[nX] X(start=reference_X) "Mass fractions (= (component mass)/total mass m_i/m)"; end ThermodynamicState; // MODEL BaseProperties // ******************** redeclare replaceable model extends BaseProperties( T(stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default), p(stateSelect=if preferredMediumStates then StateSelect.prefer else StateSelect.default), Xi(each stateSelect = if preferredMediumStates then StateSelect.prefer else StateSelect.default), final standardOrderComponents = true) "Base properties" equation assert(T >= T_min and T <= T_max, " Temperature T (= " + String(T) + " K) is not in the allowed range (" + String(T_min) + " K <= T <= " + String(T_max) + " K) required from medium model \"" + mediumName + "\". "); // h = cp_const*(T-T0); h = specificEnthalpy_pTX( p, T, X); u = cv_const*(T - T0); d = d_const; R_s = 0; //MM = MM_const; MM = molarMass(state); state.T = T; state.p = p; state.X = if fixedX then reference_X else X; annotation (Documentation(info="<html> <p> This is the most simple incompressible medium model, where specific enthalpy h and specific internal energy u are only a function of temperature T and all other provided medium quantities are assumed to be constant. Note that the (small) influence of the pressure term p/d is neglected. </p> </html>")); end BaseProperties; // DECLARE FUNCTIONS // ******************* //------------------- redeclare function setState_pTX "Return thermodynamic state from p, T, and X or Xi" extends Modelica.Icons.Function; input AbsolutePressure p "Pressure"; input Temperature T "Temperature"; input MassFraction X[:]=reference_X "Mass fractions"; output ThermodynamicState state "Thermodynamic state record"; algorithm //state := ThermodynamicState(p=p, T=T); // take into account substances state := if size(X,1) == 0 then ThermodynamicState(p=p,T=T,X=reference_X) else if size(X,1) == nX then ThermodynamicState(p=p,T=T, X=X) else ThermodynamicState(p=p,T=T, X=cat(1,X,{1-sum(X)})); // when reduceX = true end setState_pTX; //------------------- redeclare function setState_phX "Return thermodynamic state from p, h, and X or Xi" extends Modelica.Icons.Function; input AbsolutePressure p "Pressure"; input SpecificEnthalpy h "Specific enthalpy"; input MassFraction X[:]=reference_X "Mass fractions"; output ThermodynamicState state "Thermodynamic state record"; algorithm state := if size(X,1) == 0 then ThermodynamicState(p = p, T = T0 + h / cp_const, X=X) else if size(X,1) == nX then ThermodynamicState(p = p, T = T0 + h / cp_const, X=X) else ThermodynamicState(p = p, T = T0 + h / cp_const, X=cat(1,X,{1-sum(X)})); end setState_phX; //------------------- redeclare replaceable function setState_psX "Return thermodynamic state from p, s, and X or Xi" extends Modelica.Icons.Function; input AbsolutePressure p "Pressure"; input SpecificEntropy s "Specific entropy"; input MassFraction X[:]=reference_X "Mass fractions"; output ThermodynamicState state "Thermodynamic state record"; algorithm //state := ThermodynamicState(p=p, T=Modelica.Math.exp(s/cp_const + // Modelica.Math.log(reference_T))) // "Here the incompressible limit is used, with cp as heat capacity"; // take into account substances state := if size(X,1) == 0 then ThermodynamicState(p = p, T = Modelica.Math.exp(s / cp_const + Modelica.Math.log(reference_T)), X=X) else if size(X,1) == nX then ThermodynamicState(p = p, T = Modelica.Math.exp(s / cp_const + Modelica.Math.log(reference_T)), X=X) else ThermodynamicState(p = p, T = Modelica.Math.exp(s / cp_const + Modelica.Math.log(reference_T)), X=cat(1,X,{1-sum(X)})); end setState_psX; //------------------- redeclare function setState_dTX "Return thermodynamic state from d, T, and X or Xi" extends Modelica.Icons.Function; input Density d "Density"; input Temperature T "Temperature"; input MassFraction X[:]=reference_X "Mass fractions"; output ThermodynamicState state "Thermodynamic state record"; algorithm assert(false, "Pressure can not be computed from temperature and density for an incompressible fluid!"); end setState_dTX; //------------------- redeclare function extends setSmoothState "Return thermodynamic state so that it smoothly approximates: if x > 0 then state_a else state_b" algorithm state := ThermodynamicState(p=Media.Common.smoothStep( x, state_a.p, state_b.p, x_small), T=Media.Common.smoothStep( x, state_a.T, state_b.T, x_small)); end setSmoothState; //------------------- redeclare function extends dynamicViscosity "Return dynamic viscosity" algorithm eta := eta_const; end dynamicViscosity; //------------------- redeclare function extends thermalConductivity "Return thermal conductivity" algorithm lambda := lambda_const; end thermalConductivity; //------------------- redeclare function extends pressure "Return pressure" algorithm p := state.p; end pressure; //------------------- redeclare function extends temperature "Return temperature" algorithm T := state.T; end temperature; //------------------- redeclare function extends density "Return density" algorithm d := d_const; end density; //------------------- redeclare function extends specificEnthalpy "Return specific enthalpy" algorithm h := cp_const*(state.T - T0); end specificEnthalpy; //------------------- redeclare function extends specificHeatCapacityCp "Return specific heat capacity at constant pressure" algorithm cp := cp_const; end specificHeatCapacityCp; //------------------- redeclare function extends specificHeatCapacityCv "Return specific heat capacity at constant volume" algorithm cv := cv_const; end specificHeatCapacityCv; //------------------- redeclare function extends isentropicExponent "Return isentropic exponent" algorithm gamma := cp_const/cv_const; end isentropicExponent; //------------------- redeclare function extends velocityOfSound "Return velocity of sound" algorithm a := a_const; end velocityOfSound; //------------------- redeclare function specificEnthalpy_pTX "Return specific enthalpy from p, T, and X or Xi" extends Modelica.Icons.Function; input AbsolutePressure p "Pressure"; input Temperature T "Temperature"; input MassFraction X[nX] "Mass fractions"; output SpecificEnthalpy h "Specific enthalpy"; algorithm h := cp_const*(T - T0); annotation (Documentation(info="<html> <p> This function computes the specific enthalpy of the fluid, but neglects the (small) influence of the pressure term p/d. </p> </html>")); end specificEnthalpy_pTX; //------------------- redeclare function temperature_phX "Return temperature from p, h, and X or Xi" extends Modelica.Icons.Function; input AbsolutePressure p "Pressure"; input SpecificEnthalpy h "Specific enthalpy"; input MassFraction X[nX] "Mass fractions"; output Temperature T "Temperature"; algorithm T := T0 + h/cp_const; end temperature_phX; //------------------- redeclare function density_phX "Return density from p, h, and X or Xi" extends Modelica.Icons.Function; input AbsolutePressure p "Pressure"; input SpecificEnthalpy h "Specific enthalpy"; input MassFraction X[nX] "Mass fractions"; output Density d "Density"; algorithm d := density(setState_phX( p, h, X)); end density_phX; //------------------- redeclare function extends specificInternalEnergy "Return specific internal energy" extends Modelica.Icons.Function; algorithm // u := cv_const*(state.T - T0) - reference_p/d_const; u := cv_const*(state.T - T0); annotation (Documentation(info="<html> <p> This function computes the specific internal energy of the fluid, but neglects the (small) influence of the pressure term p/d. </p> </html>")); end specificInternalEnergy; //------------------- redeclare function extends specificEntropy "Return specific entropy" extends Modelica.Icons.Function; algorithm s := cv_const*Modelica.Math.log(state.T/T0); end specificEntropy; //------------------- redeclare function extends specificGibbsEnergy "Return specific Gibbs energy" extends Modelica.Icons.Function; algorithm g := specificEnthalpy(state) - state.T*specificEntropy(state); end specificGibbsEnergy; //------------------- redeclare function extends specificHelmholtzEnergy "Return specific Helmholtz energy" extends Modelica.Icons.Function; algorithm f := specificInternalEnergy(state) - state.T*specificEntropy(state); end specificHelmholtzEnergy; //------------------- redeclare function extends isentropicEnthalpy "Return isentropic enthalpy" algorithm h_is := cp_const*(temperature(refState) - T0); end isentropicEnthalpy; //------------------- redeclare function extends isobaricExpansionCoefficient "Returns overall the isobaric expansion coefficient beta" algorithm beta := 0.0; end isobaricExpansionCoefficient; //------------------- redeclare function extends isothermalCompressibility "Returns overall the isothermal compressibility factor" algorithm kappa := 0; end isothermalCompressibility; //------------------- redeclare function extends density_derp_T "Returns the partial derivative of density with respect to pressure at constant temperature" algorithm ddpT := 0; end density_derp_T; //------------------- redeclare function extends density_derT_p "Returns the partial derivative of density with respect to temperature at constant pressure" algorithm ddTp := 0; end density_derT_p; //------------------- redeclare function extends density_derX "Returns the partial derivative of density with respect to mass fractions at constant pressure and temperature" algorithm dddX := fill(0, nX); end density_derX; //------------------- redeclare function extends molarMass "Return the molar mass of the medium" algorithm //MM := MM_const; MM := 1/sum(state.X[j]/MMX[j] for j in 1:size(state.X,1)); end molarMass; // functions that have been adopted from class PARTIALMIXTUREMEDIUM // ----------------- replaceable function gasConstant "Return the gas constant of the mixture (also for liquids)" extends Modelica.Icons.Function; input ThermodynamicState state "Thermodynamic state"; output SI.SpecificHeatCapacity R_s "Mixture gas constant"; algorithm R_s := 0; end gasConstant; // ----------------- function moleToMassFractions "Return mass fractions X from mole fractions" extends Modelica.Icons.Function; input SI.MoleFraction moleFractions[:] "Mole fractions of mixture"; input MolarMass[:] MMX "Molar masses of components"; output SI.MassFraction X[size(moleFractions, 1)] "Mass fractions of gas mixture"; protected MolarMass Mmix=moleFractions*MMX "Molar mass of mixture"; algorithm for i in 1:size(moleFractions, 1) loop X[i] := moleFractions[i]*MMX[i]/Mmix; end for; annotation (smoothOrder=5); end moleToMassFractions; // ----------------- function massToMoleFractions "Return mole fractions from mass fractions X" extends Modelica.Icons.Function; input SI.MassFraction X[:] "Mass fractions of mixture"; input SI.MolarMass[:] MMX "Molar masses of components"; output SI.MoleFraction moleFractions[size(X, 1)] "Mole fractions of gas mixture"; protected Real invMMX[size(X, 1)] "Inverses of molar weights"; SI.MolarMass Mmix "Molar mass of mixture"; algorithm for i in 1:size(X, 1) loop invMMX[i] := 1/MMX[i]; end for; Mmix := 1/(X*invMMX); for i in 1:size(X, 1) loop moleFractions[i] := Mmix*X[i]/MMX[i]; end for; annotation (smoothOrder=5); end massToMoleFractions; end SimpleMachineStockMedium_400_v1; PlugFlowPipe model derived from the example : model testing_PlugFlowPipe_example_ver01 "Simple example of plug flow pipe" // Modifications to the example import Buildings = Buildings; import Sources = Buildings.Fluid.Sources; import Sensors = Buildings.Fluid.Sensors; //replaceable package Medium = Buildings.Media.Water; replaceable package Medium = SimpleMachineStockMedium_400_v1; // End of modifications final parameter Modelica.Units.SI.MassFlowRate m_flow_nominal = 3 "Mass flow rate"; Modelica.Blocks.Sources.Ramp Tin(height = 20, duration = 0, offset = 273.15 + 50, startTime = 100) "Ramp pressure signal" annotation( Placement(transformation(extent = {{-100, -10}, {-80, 10}}))); Sources.Boundary_pT sin(redeclare package Medium = Medium, T = 273.15 + 10, nPorts = 2, p(displayUnit = "Pa") = 101325) "Pressure boundary condition" annotation( Placement(transformation(extent = {{100, -10}, {80, 10}}))); Buildings.Fluid.FixedResistances.PlugFlowPipe pip(redeclare package Medium = Medium, dh = 0.1, length = 100, dIns = 0.05, kIns = 0.028, m_flow_nominal = m_flow_nominal, cPip = 500, thickness = 0.0032, initDelay = true, m_flow_start = m_flow_nominal, rhoPip = 8000, T_start_in = 323.15, T_start_out = 323.15) "Pipe" annotation( Placement(transformation(extent = {{0, 10}, {20, 30}}))); Buildings.HeatTransfer.Sources.FixedTemperature bou[2](each T = 283.15) "Boundary temperature" annotation( Placement(transformation(extent = {{-40, 60}, {-20, 80}}))); Buildings.Fluid.Sources.MassFlowSource_T sou(redeclare package Medium = Medium, use_T_in = true, m_flow = m_flow_nominal, nPorts = 1) "Flow source" annotation( Placement(transformation(extent = {{-60, 10}, {-40, 30}}))); Buildings.Fluid.Sensors.TemperatureTwoPort senTemOut(redeclare package Medium = Medium, m_flow_nominal = m_flow_nominal, tau = 0, T_start = 323.15) "Temperature sensor" annotation( Placement(transformation(extent = {{40, 10}, {60, 30}}))); Buildings.Fluid.Sensors.TemperatureTwoPort senTemIn(redeclare package Medium = Medium, m_flow_nominal = m_flow_nominal, tau = 0, T_start = 323.15) "Temperature sensor" annotation( Placement(transformation(extent = {{-30, 10}, {-10, 30}}))); Sensors.TemperatureTwoPort senTemInNoMix(redeclare package Medium = Medium, m_flow_nominal = m_flow_nominal, tau = 0, T_start = 323.15) "Temperature sensor" annotation( Placement(transformation(extent = {{-30, -30}, {-10, -10}}))); Buildings.Fluid.FixedResistances.PlugFlowPipe pipNoMix(have_pipCap = false, redeclare package Medium = Medium, dh = 0.1, length = 100, dIns = 0.05, kIns = 0.028, m_flow_nominal = m_flow_nominal, cPip = 500, thickness = 0.0032, initDelay = true, m_flow_start = m_flow_nominal, rhoPip = 8000, T_start_in = 323.15, T_start_out = 323.15) "Pipe" annotation( Placement(transformation(extent = {{0, -30}, {20, -10}}))); Sensors.TemperatureTwoPort senTemOutNoMix(redeclare package Medium = Medium, m_flow_nominal = m_flow_nominal, tau = 0, T_start = 323.15) "Temperature sensor" annotation( Placement(transformation(extent = {{40, -30}, {60, -10}}))); Sources.MassFlowSource_T souNoMix(redeclare package Medium = Medium, use_T_in = true, m_flow = m_flow_nominal, nPorts = 1) "Flow source" annotation( Placement(transformation(extent = {{-60, -30}, {-40, -10}}))); equation connect(Tin.y, sou.T_in) annotation( Line(points = {{-79, 0}, {-68, 0}, {-68, 24}, {-62, 24}}, color = {0, 0, 127})); connect(pip.port_b, senTemOut.port_a) annotation( Line(points = {{20, 20}, {40, 20}}, color = {0, 127, 255})); connect(senTemOut.port_b, sin.ports[1]) annotation( Line(points = {{60, 20}, {76, 20}, {76, -1}, {80, -1}}, color = {0, 127, 255})); connect(senTemIn.port_b, pip.port_a) annotation( Line(points = {{-10, 20}, {0, 20}}, color = {0, 127, 255})); connect(senTemInNoMix.port_b, pipNoMix.port_a) annotation( Line(points = {{-10, -20}, {0, -20}}, color = {0, 127, 255})); connect(pipNoMix.port_b, senTemOutNoMix.port_a) annotation( Line(points = {{20, -20}, {40, -20}}, color = {0, 127, 255})); connect(senTemOutNoMix.port_b, sin.ports[2]) annotation( Line(points = {{60, -20}, {76, -20}, {76, 1}, {80, 1}}, color = {0, 127, 255})); connect(bou[1].port, pip.heatPort) annotation( Line(points = {{-20, 70}, {-4, 70}, {-4, 40}, {10, 40}, {10, 30}}, color = {191, 0, 0})); connect(bou[2].port, pipNoMix.heatPort) annotation( Line(points = {{-20, 70}, {-4, 70}, {-4, 0}, {10, 0}, {10, -10}}, color = {191, 0, 0})); connect(sou.ports[1], senTemIn.port_a) annotation( Line(points = {{-40, 20}, {-30, 20}}, color = {0, 127, 255})); connect(souNoMix.ports[1], senTemInNoMix.port_a) annotation( Line(points = {{-40, -20}, {-30, -20}}, color = {0, 127, 255})); connect(Tin.y, souNoMix.T_in) annotation( Line(points = {{-79, 0}, {-68, 0}, {-68, -16}, {-62, -16}}, color = {0, 0, 127})); annotation( __Dymola_Commands(file = "modelica://Buildings/Resources/Scripts/Dymola/Fluid/FixedResistances/Examples/PlugFlowPipe.mos" "Simulate and Plot"), experiment(StopTime = 1000, Tolerance = 1e-006), Documentation(info = "<html> <p>Basic test of model <a href=\"modelica://Buildings.Fluid.FixedResistances.PlugFlowPipe\"> Buildings.Fluid.FixedResistances.PlugFlowPipe</a> with and without outlet mixing volume. This test includes an inlet temperature step under a constant mass flow rate. </p> </html>", revisions = "<html> <ul> <li>July 27, 2021 by Baptiste Ravache<br/>Add case without mixing volume</li> </ul> <ul> <li>September 8, 2017 by Bram van der Heijde<br/>First implementation</li> </ul> </html>"), Diagram(coordinateSystem(extent = {{-120, -100}, {120, 100}})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}))); end testing_PlugFlowPipe_example_ver01; EDIT: Version information: MSL 4.0.0 Buildings library: I was told to use version 9.0.0. The repository https://github.com/lbl-srg/modelica-buildings did not have any specific label for that. I was using the master branch of the repository and the file "modelica-buildings/Buildings/package.mo" gives the version information 9.0.0 (cloned 27.1.2022). Information obtained from the Buildings library through OMEdit Error Message (Intergrator method dassl): Latest Debug message from Transformational debugger Error Message when using rungekutta integrator:
You need the latest development version of Buildings (the master branch; not any released version) because have_pipCap was only introduced in https://github.com/lbl-srg/modelica-buildings/commit/89bf74035bdea926701edef2c3dbf35f48b32680 Without this Buildings version, you will get the message: Error: Modified element have_pipCap not found in class PlugFlowPipe. It is recommended to let the Modelica tool put the annotation uses on the code so the same version can be used for testing. I am assuming this is the problem because the questions did not list the version of Buildings used or the error-message you got.
Redeclare model with "outer" parameters
I tried redeclare model that contain global (outer) parameter. Here simple example of my code: package tests model M0 inner parameter Real a = 1; end M0; model M1 extends tests.M0; replaceable tests.M3 c; end M1; model M2 outer constant Real a; end M2; model M3 extends tests.M2; Real b; equation b = a; end M3; model M4 extends tests.M2; Real b2; equation b2 = a; end M4; model test1 tests.M1 X; end test1; model test2 tests.M1 X(redeclare each tests.M4 c); end test2; end tests; Test1 works fine, but with test2 I have warning An inner declaration for outer component a could not be found and was automatically generated. Without "inner/outer" all works fine. The warning occurs even if M3 and model M4 have identically code model M3 // and M4 outer constant Real a; Real b; equation b = a; end M3; or if redeclare the same model model test3 tests.M1 X(redeclare tests.M3 c); end test3; I am using OM 1.18
The issue seems to be that b is defined in M3 but not in M4. Modifying M4 to model M4 extends tests.M2; Real b, b2; equation b = a; b2 = a; end M4; or model M4 extends tests.M2; Real b; equation b = a; end M4; removes the respective warnings in Dymola. This comes down to plug-compatibility, which in this example means, that every public variable in M3 must be present in M4 as well. As plug-compatibility only refers to public variables, defining b to be protected in M3 should also resolve the issue: model M3 extends tests.M2; protected Real b; equation b = a; end M3; Note: I didn't test it with OpenModelica...
Your code works in Dymola, even though there is one issue: In M0 you declared a as a parameter inner parameter Real a = 1; But in M2 you are looking for a constant outer constant Real a; Both tools don't care much about that fact, which seems strange. In OpenModelica I guess you have hit a bug. You are using inner/outer in an uncommon way. Changing your setup to a more common style with the inner variable defined in a top-level-component (now named World) works: package tests model World inner parameter Real a = 1; end World; model M1 replaceable tests.M3 c; end M1; model M2 outer World w; parameter Real a = w.a; end M2; model M3 extends tests.M2; Real b; equation b = a; end M3; model M4 extends tests.M2; Real b2; equation b2 = a; end M4; model test1 inner World w; tests.M1 X; end test1; model test2 inner World w; tests.M1 X(redeclare each tests.M4 c); end test2; end tests;
Modelica coding standards / new OpenModelica compiler frontend
looks like a issue with new OpenModelica compiler frontend. I am using official release version of openmodelica 1.14 on windows-7 64bit OS. package Test1_14 model M1 parameter Integer size = 2 "matrix size"; parameter Real A[size] = {1.0, 1.0}; Real B[size]; Real T = 1; Real P = 2; equation B = A * (T/P); end M1; model M1_Extn Real C[size]; Real D[size]; equation for J in 1:size loop C[J] = Func1(T); D[J] = C[J] / P; end for; end M1_Extn; function Func1 input Real a; output Real b; algorithm b := a*a; end Func1; model M1_Combined parameter Integer size = 2 "matrix size"; Real B[size]; Real T = 1; Real P = 2; extends M1_Extn; equation B = D; end M1_Combined; end Test1_14; When I compile the model ‘M1_Combined’, the code generation fails with new OpenModelica compiler frontend. Export FMU also fails with the same error. Is my code as per Modelica programing standards? How do I declare variables - size, T, P in the model M1_Extn and still use keyword ‘extends’ in ‘M1_Combined’ ?
This is because the old frontend did not handle the "extends" correctly, according to the Modelica Specification. The new frontend does it correctly. To be clear, you cannot define a variable in this class and then use it in the extends any other way than via a modification (and via inner/outer, via redeclare as element). An example is below, you cannot use a inside M1. package TestExtends model M1 parameter Real b = a; end M1; model M2 parameter Real a = 1; extends M1; end M2; end TestExtends; To fix your model so that is according to Modelica standards, you can do: package Test1_14 model M1 parameter Integer size = 2 "matrix size"; parameter Real A[size] = {1.0, 1.0}; Real B[size]; Real T = 1; Real P = 2; equation B = A * (T/P); end M1; model M1_Extn parameter Integer size = 2; Real T = 1; Real P = 2; Real C[size]; Real D[size]; equation for J in 1:size loop C[J] = Func1(T); D[J] = C[J] / P; end for; end M1_Extn; function Func1 input Real a; output Real b; algorithm b := a*a; end Func1; model M1_Combined extends M1_Extn(size=2, T = 1, P = 2); Real B[size]; // this one works as you can use things defined in extends. equation B = D; end M1_Combined; end Test1_14;
Parametrised Modelica library and possibility to use models as parameters - part 2
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.
Your "code2" would result in BRType2 not having CType modified. A redeclare does not mean "change package A to look like this", but rather "this should be like package A, but with these changes". So to get the result you want, you should do something like: package Equipment2 import BR5i.Equipment; extends Equipment(redeclare connector LCon=LCon2); end Equipment2; model BRType2 // Equipment2 has the change in LCon, so extend RType from there instead import Equipment2.RType; extends RType(redeclare model CType=CType2); end BRType2; Also note that this approach will not give the expected results if Equipment contains any instances of or other references to Rtype, as they would refer to the unchanged RType, not to BRType2. Why you get the error about not finding RType, I can't say. It could plausibly be a bug, but I'd first check to see if you have written the path to it correctly.
On request I here supply a small self-contained example, about 150 lines. I decided to re-use my toy-example used in a couple of other posts recently and now add on what is needed to exemplify the problem discussed here. It means I use different names of things compared to what is written above, but the structure of the problem is exactly the same. The toy-example describe pumping of a medium from one vessel to another and is made general so that we can easily change medium and the equipment of pumps and tanks are automatically updated. Originally the medium contain two substances. With a separate short application code we define a medium with more components and update the package Equipment by redeclaring the connector LiquidCon and then system setup is simply re-used. Now I add on an inner model to the harvest that describe some reaction between the substances. Originally we have a reaction model NoReaction that leave the substances in the harvest tank without any reaction. Another reaction model is Reaction 3 that shows degradation of substance 3. The problem I want to highlight is that if we first adapt the equipment with a connector for say three substances. And then in a second round change the reaction model of the adapted equipment3 to a reaction model Reaction3, then JModelica compiler gives error message, while OpenModelica does not and produce simulation resultat that are ok. This is marked Alternative 2 in the code. Alternative 1. On other hand if the two very different re-declrations are done at the same time, i.e. both changed connector LiquidCon and model ReactionType then it works in both JModelica and OpenModelica. Below self-contained code and the example Test now is Alternative 2 and generates error in JModelica 2.4 but works in OpenModelica. Not clear to me what to expect from the Modelica def itself. package DEMO_v14 // 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. // Author: Jan Peter Axelsson // --------------------------------------------------------------------------------------------- // 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_v14.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; connector LiquidCon3 Medium3.Concentration c "Substance conc"; flow Real F (unit="m3/s") "Flow rate"; end LiquidCon3; 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 replaceable connector LiquidCon end LiquidCon; // replaceable model ReactionType // Alternative 1 // end ReactionType; 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 // Alternative 2 end ReactionType; 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; model NoReaction constant Integer nc = Medium.nc; outer Real[nc] c; outer Real[nc] q; equation for i in 1:nc loop q[i] = 0; end for; end NoReaction; 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_v14.Equipment; // extends Equipment(redeclare connector LiquidCon=LiquidCon3, // redeclare model ReactionType=Reaction3); // end Equipment3; package Equipment3 // Alternative 2 import DEMO_v14.Equipment; extends Equipment(redeclare connector LiquidCon=LiquidCon3); end Equipment3; model HarvesttankType3 import DEMO_v14.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_v14;
I have not had time to analyze your problem in Detail, but I would like to point out here that if some code is accepted in one tool, but not accepted in the other, it does not necessarily mean the bug is in the tool that does not accept the code. Modelica semantics got quite a bit stricter over time to make Modelica safer to use, and easier to be portable across tools. Since the OpenModelica kernel is one of the oldest ones around, it is known to accept a lot of code that is actually not (anymore in many cases) legal Modelica in the latest versions. Sorry, I don't have the time to analyze this in depth from the Modelica semantics legality point of view. I am in any case convinced that you can achieve what you want to achieve with certainly legal Modelica. Two remarks on modeling practices: It is unsafe, and should be avoided, to have an empty class (connector in your case) as a replaceable class since it can be replaced with anything, which is inherently unsafe. I also think that you can achieve what you want to achieve with a variable length vector in the connector, the connector itself does not need to be replaceable. All the best, /Hubertus
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;
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;
Balancing local models Modelica
I have a local model, which when I check in Dymola claims to have 35 variables and 34 unknowns, while when I check exactly the same model in OMEdit it is balanced at 34/34. In determining what counts as a variable, do all inputs and outputs get included? Below is my model: model HeatStorage extends PentakomoPlant.Interfaces.StorageFluidHeat; parameter SI.Diameter D = 18.667 "Diameter"; parameter SI.Height H = 20 "Height"; parameter Boolean enable_losses = false "= true enable thermal losses with environment" parameter SI.CoefficientOfHeatTransfer alpha = 1 "Constant heat transfer coefficient with the ambient" parameter Boolean use_L = false "= true to display level as output variable" parameter Real L_start = 0 "Start value of level in %" parameter SI.Temperature T_start = from_degC(300) "Start value of temperature" parameter SI.Temperature T_max = from_degC(550) "Maximum tank temperature" parameter SI.Temperature T_set = from_degC(300) "Tank Heater Temperature Set-Point" parameter SI.Power W_max = 30e8 "Hot Tank Heater Capacity" parameter SI.Efficiency e_ht = 0.99 "Tank Heater Efficiency" SI.Volume V; SI.Mass m; Medium.BaseProperties medium; SI.Area A; SI.HeatFlowRate Q_losses; Medium.ThermodynamicState state_i = Medium.setState_pTX(medium.p, T_start); SI.Power W_net; SI.Power W_loss; Modelica.Blocks.Interfaces.RealOutput L if use_L "Tank level in %" Modelica.Blocks.Interfaces.RealInput T_amb if enable_losses Modelica.Blocks.Interfaces.RealInput Q_heater SI.HeatFlowRate Q_PB "Heat Flow to PowerBlock"; SI.HeatFlowRate Q_desal "Heat Flow to Desalination"; protected parameter SI.Volume V_t = H * pi * D ^ 2 / 4; Modelica.Blocks.Interfaces.RealOutput L_internal; initial equation medium.h = Medium.specificEnthalpy(state_i); m = Medium.density(state_i) * V_t; equation if use_L then connect(L_internal, L); end if; if enable_losses then connect(T_amb_internal, T_amb); Q_losses = -0.939 * exp(to_degC(medium.T) * 0.005111) * 1000;//*5/7; else T_amb_internal = Medium.T_default; Q_losses = 0; end if; fluid_a.p = medium.p; fluid_b.p = medium.p; fluid_a.h_outflow = medium.h; fluid_b.h_outflow = medium.h; der(m) = fluid_a.m_flow + fluid_b.m_flow; m * der(medium.h) + der(m) * medium.h = Q_losses + Q_PB + Q_desal + W_net + fluid_a.m_flow * inStream(fluid_a.h_outflow) + fluid_b.m_flow * medium.h; V = m / medium.d; L_internal = 100 * (max(medium.T, T_set) - T_set) / (T_max - T_set); A = 2 * pi * (D / 2) * H; W_net = Q_heater; W_loss = W_net / e_ht; //PowerBlock heat_PB.Q_flow = Q_PB; heat_DS.Q_flow = Q_desal; heat_PB.T = medium.T; heat_DS.T = medium.T; end HeatStorage; With: partial model StorageFluidHeat extends SolarTherm.Icons.StorageModel; Modelica.Fluid.Interfaces.FluidPort_a fluid_a(redeclare package Medium = Medium) Modelica.Fluid.Interfaces.FluidPort_b fluid_b(redeclare package Medium = Medium) replaceable package Medium = SolarTherm.Media.MoltenSalt.MoltenSalt_base constrainedby Modelica.Media.Interfaces.PartialMedium "Medium in the component" Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b heat_PB Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b heat_DS end StorageFluidHeat; And (for the base properties of the medium): redeclare model extends BaseProperties(final standardOrderComponents=true) "Base properties of medium" equation d = rho_T(T); h = state.h; u = h - p/d; MM = 0.091438; R = 8.3144/MM; state.p = p; T = T_h(h); end BaseProperties; I am struggling to find where the extra variable may be, or why it might be different when using Dymola/OMEdit. I have tried following the advice from ELmqvist about balancing models, so in counting variables would I be right in assuming (For this model): 8 x Specialised class variables 3 x Inputs 2 x Output 7 x Medium Base Property Variables 2 x 5 x Fluid port Variables 2 x 2 x Heat port Variables = 34 variables Am I missing something?
The model is not complete with all libraries to enable testing (assumedly there are similar issues with other media), so this will be an incomplete answer. In addition it seems likely that some equations and variables could be removed to simplify the model. But there are some concerns with the model: T_amb_internal is unused and undeclared; that looks odd. You normally need equations for two intensive properties for simple medium: e.g. p, h or p, T. Here medium.h is determined due to the differential equations, but not medium.p. (The mass also has a differential equation and can vary.) Note that testing of a local model can be tricky - and you should preferably include it in a test-circuit as well.