Reputation: 347
I am trying to build a model that can use two different components (taken from an existing library) for the same scope: in particular a system with an heat exchanger; this heat exchanger can be based on different technologies, e.g. pipes or plates.
I want then define a model with a default replaceable exchanger and say which other technologies may be used.
This is a vey simple exemple of what I tried:
package Test
// Component 1 original definition in the library
model COMP1
parameter Real p1=1 "";
Real v "";
equation
v=p1*time;
end COMP1;
// Component 2 original definition in the library
model COMP2
parameter Real p2=1 "";
Real v "";
equation
v=p2*time;
end COMP2;
// Main module (system)
model MAIN
parameter Real pm=100 "";
Real vm "";
// Redefinition of the component modifing the default values
model call1 = COMP1(p1=10);
model call2 = COMP2(p2=20);
replaceable call1 OBJ
annotation(choices(
choice(redeclare call1 OBJ "Default"),
choice(redeclare call2 OBJ "Variant")));
equation
vm = OBJ.v+pm;
end MAIN;
// Application model, using the main model
model APP
MAIN mAIN;
end APP;
end Test;
The model APP run successfully. However, if I open the parameters of APP.mAIN and change OBJ (either selecting "Default" or "Variant"), which results in modifing the APP model as follows:
model APP
MAIN mAIN(redeclare call1 OBJ "Default");
end APP;
I get the following error:
Component type specifier call1 not found
I do not understand what I did wrong, please help.
Upvotes: 1
Views: 1660
Reputation: 6645
The problem related to the error occurs, because you did not use the correct class path in the choices annotations.
If you select "Default" in APP
, you get the following code:
model APP
MAIN mAIN(redeclare call1 OBJ "Default");
end APP;
Here we see that the class path call1
is not valid. APP can access call1
only by using the relative class path MAIN.call1
or the absolute class path Test.MAIN.call1
.
So you can fix this problem by using the following annotation:
replaceable call1 OBJ
annotation(choices(
choice(redeclare MAIN.call1 OBJ "Default"),
choice(redeclare MAIN.call2 OBJ "Variant")));
However, in Dymola the model still does not check, apparently due to the local class definitions in MAIN
, under Redefinition of the component modifying the default values.
Here you create the new classes call1
and call2
. This could be a Dymola bug, as it works in OpenModelica - but the new classes are not necessary. Instead, you can use the original classes and set the parameters with modifier equations in the redeclare
statement as follows:
model MAIN
parameter Real pm=100 "";
Real vm "";
replaceable COMP1 OBJ
annotation(choices(
choice(redeclare Test.COMP1 OBJ(p1=10) "Default"),
choice(redeclare Test.COMP2 OBJ(p2=10) "Variant")));
equation
vm = OBJ.v+pm;
end MAIN;
Now the model works for no selection and "Default", but when "Variant" is selected, Dymola complains that the redeclared class does not contain the same variables as the original one. This is one of the restrictions you have when you work with replaceable classes (again, OpenModelica has no problem with it, but Dymola warns you that this is not conform to the Modelica language specification)
I suggest to create an interface model like the Modelica library usually does (e.g. with Modelica.Electrical.Analog.Interfaces.OnePort
):
partial
base model, which contains everything that is common for all variants, called the interfaceThis is how your example could look like. The third-party-components COMP1
and COMP2
are moved to the package ReadOnlyLibrary
.
package Test
// Original definition of Component 1 and 2 in the external library
package ReadOnlyLibrary
model COMP1
parameter Real p1=1 "";
Real v "";
equation
v=p1*time;
end COMP1;
model COMP2
parameter Real p2=1 "";
Real v "";
equation
v=p2*time;
end COMP2;
end ReadOnlyLibrary;
// Interface and variants with modified default values
partial model Call_Interface
Real v "";
end Call_Interface;
model Call1 "Default"
extends Call_Interface;
extends ReadOnlyLibrary.COMP1(p1=10);
end Call1;
model Call2 "Variant"
extends Call_Interface;
extends ReadOnlyLibrary.COMP2(p2=20);
end Call2;
// Main module (system)
model Main
parameter Real pm=100 "";
Real vm "";
replaceable Test.Call1 OBJ constrainedby Test.Call_Interface annotation (choicesAllMatching);
equation
vm = OBJ.v+pm;
end Main;
// Application model, using the main model
model App
Main main annotation (Placement(transformation(extent={{-12,10},{8,30}})));
end App;
end Test;
Upvotes: 3