Modelica: how to use replaceable components? - modelica

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.

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)
Alternative approach: MSL-Style with interfaces
I suggest to create an interface model like the Modelica library usually does (e.g. with Modelica.Electrical.Analog.Interfaces.OnePort):
You create a partial base model, which contains everything that is common for all variants, called the interface
The variants extend the interface and one of the models of the the existing library
The class using the variants instantiates one of the variants and constrains the redeclaration to the interface using constrainedby
Instead of creating the choices annotations manually you can now create it automatically with the annotation choicesAllMatching
This 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;

Related

How to inherit a standard Fluid component and override and replace some equations of the base model?

I want to customize a standard Fluid Library component in Modelica using OpenModelica. 
I want to create a customized version of a new Pump where several equations will be changed.
I inherited Fluid.Machines.BaseClasses.PartialPump as a base model by "extends" keyword. When I tried to change and redefine an equation, it gave an overdetermined system error. 
I put redeclare or redifine in front of the equation, and it still gives an error.
What is the best way to create a customised component model without copying everything into a new model? 
Thanks
Unfortunately, you cannot change existing code* — you can only add new code.
In your case, you will have to make a copy of Fluid.Machines.BaseClasses.PartialPump and modify the equation in question. However, you don't necessarily need to copy its base class (Modelica.Fluid.Interfaces.PartialTwoPort).
The PartialPump model is quite versatile. If you need different pump curves (pressure, efficiency or power) you can write additional functions based on the base classes in Fluid.Machines.BaseClasses.PumpCharacteristics.
*) One exception to my initial statement is the inheritance of graphical annotations: if you extend a model and add the annotation primitivesVisible=false the graphical annotations (icon) will not be inherited, for example:
model myModel
extends baseModel annotation(IconMap(primitivesVisible=false));
<new icon annotations>
end myModel;
The usage of extends suggests one wants to inherit all the behaviours of the extended class. You can change those behaviours unless they are redeclarable. The best is to create a new class by duplicating the base model and then change the behaviours as you want. Hope this works!

What causes 'interface resolution' compilation error when working with classes and virtual interfaces

I have declared in a design file following interfaces:
interface t_clocks;
ckrs_t ClkRs125MHz_ix;
ckrs_t ClkRs160MHz_ix;
ckrs_t [3:0] ClkRsLink_ixb;
ckrs_t ClkRsLinkx2_ixb;
logic tdclk_sampling;
modport producer(output ClkRs125MHz_ix,
output ClkRs160MHz_ix,
output ClkRsLink_ixb,
output tdclk_sampling);
modport consumer(input ClkRs125MHz_ix,
input ClkRs160MHz_ix,
input ClkRsLink_ixb,
input tdclk_sampling);
endinterface // clocks
interface t_bst(input ckrs_t ClkRs_ix);
tb_t mark;
modport consumer(input ClkRs_ix, input mark);
modport producer(output ClkRs_ix, output mark);
endinterface // t_bst
and in a package classes working with those interfaces:
package clspkg;
import DefinitionsPkg::*;
class bst_generator;
virtual t_bst.producer bst_master;
....
endclass // bst_generator
class clock_generator;
virtual t_clocks.producer clk_tree;
....
endclass // clock_generator
endpackage // clspkg
I have glued all together in the testbench, using only clock_generator class from the package:
module tb_turn_emulator;
import clspkg::*;
t_clocks clk_tree();
clock_generator cgen;
// ???????????????
//t_bst blast_radius(clk_tree.ClkRs160MHz_ix);
default clocking cb #(posedge clk_tree.ClkRs160MHz_ix.clk); endclocking
`TEST_SUITE begin
`TEST_SUITE_SETUP begin
cgen = new;
cgen.clk_tree = clk_tree;
cgen.run();
##10;
end
....
endmodule
Now, when I try to compile such example, it FAILS with Virtual interface resolution cannot find a matching instance for 'virtual t_bst.producer'
It took me quite some time to find out, that if I instantiate as well the t_bst interface in the testbench module (uncommenting the t_bst line in the code above), everything goes smoothly, no compilation error and the testbench passes as usual.
I don't understand why the t_bst interface has to be instantiated as it is not at all used in code. It is true that I am importing the entire clspkg package, but nothing changes when I cherry pick by importing only the clock_generator by import clspkg::clock_generator.
What is wrong? I'm using Mentor Modelsim
First about using packages:
Once you import one identifier or every identifier from a package in a design, the entire package exists in your design. That means all the static variables get allocated and initialized, as well as all the code for tasks and functions get generated. If static variable initializations call functions like class constructors, that implies executing procedural code without ever referencing it directly. (For those of you familiar with the factory design pattern and UVM, this is exactly how factory registration works.)
Next about using interfaces:
Like a module, an interface is a design element containing definitions of lots of different things. They can define variables, routines, import other packages, and have port connections. But nothing inside an interface exists or generates any code in a design until other design unit instantiates it, or in the case of a module, gets established as a top-level instance.
Now about using virtual interfaces:
Virtual interface are the primary method used to bridge the two kingdoms of the dynamic class based testbench world with the static instance based design world. Virtual interfaces behave much like a class type, except that there is no rule to have seen a definition of the interface before using it in your code. Hierarchical reference also have this capability of referencing something that does not exist at the point of compilation, but must be resolved later in the elaboration phase of compilation.
To summarize, the compiler generates code for a virtual interface once it sees a reference to it whether you actually think you are using it or not. I would try to align packages with specific interfaces they are associated with.
From SV LRM (25.9 Virtual interfaces):
A virtual interface is a variable that represents an interface instance.
A virtual interface shall be initialized before referencing a component of the virtual interface; it has the value null before it is initialized. Attempting to use a null virtual interface shall result in a fatal run-time error.
I hope it answers to your question.

Share the same parameter from model in the toplevel with all components in dymola

i tried to use something like this:
Toplevel with Model1 and the Model with the Parameter in it.
Parametermodel:
Parameter heat_coeffi = 50;
Model1:
outer [Path:Parametermodel] name;
Parameter heat_coeffi = name.heatcoeffi;
The Error message is : "Found non-inner parametermodel for inner model
Failed to find matching inner ....
I tried to use it just like they use System from the original Modelica Lib.
If I understand your question correctly, you instantiate the Parametermodel (similar to the Modelica.Fluid.System) in the top-level model. When you do so you must instantiate it as an inner model. In that way the other instantiated models (model1 etc.) know where to find the global parameters.
In Modelica.Fluid.System there is an annotation defaultComponentPrefixes="inner" that ensures that it is automatically instantiated as an inner model.

Error in instantiating an object - Too many input arguments

I created a class with the name Player. This is the code of the class
classdef Player
properties
Name
Score
end
methods
end
end
Now I use the following code to create an instance of the class. In the final line I attempt to print the value of properties
Player evergreen = new Player();
evergreen.Name = "Roger Federer" ;
evergreen
An error is thrown up while I run the script. This is the error - Error using Player
Too many input arguments.
Error in Team (line 1) Player evergreen = new Player();
Team is the name of the file containing script.
Compared to Java, things in Matlab work a little bit differently. When working with classes, you don't need to specify the type when declaring variables and constructors must be called without the new keyword. While your code run perfectly under Java, in order to make it work under Matlab you have to rewrite it as follows:
p = Player();
p.Name = 'Roger Federer';
For a brief introduction to object oriented programming in Matlab, read this.

Extending matlab classes: new methods for built-in classes

I inherited a complete toolbox, last revised in 2006, and I must update it to the latest version of Matlab. This toolbox defines some classes and defines methods for built in classes. More specifically, it creates some extra methods for objects of the control systems toolbox classes lti, ss, zpk and tf.
The first part, rebuilding the new classes, is already done. I am having troubles with the new methods for existing classes.
Since the code was written in an older version of Matlab, it uses class folders like #lti, #ss, #zpk to define the new methods. Now I need to keep the functionality, but using the new OOP model, in which not all #-folders are visible.
Does anybody know how to do that?
Since I had no luck trying to find a solution, I had to find one on my own. This is the method I came up with.
The toolbox had three new method for the zpk class. I created a new class, called sdzpk, and declared it to be a subclass of the built in zpk class. Then, wherever any of the new methods were used, I first converted the object to the new class before passing it to the method.
The following code may ilustrate that better:
Class definition file:
classdef sdzpk < zpk & sdlti
methods (Access = public)
function obj = sdzpk(varargin)
% Constructor method. Long code here to perform data validation
% and pass information to the zpk constructor
obj = obj#zpk(args{:});
end
% Existing methods
% This are the old files I inherited. No need to edit them.
tsys = ctranspose(sys);
sys = delay2z(sys);
sysr = minreal(sys,tol);
F = minreals(F,tol);
FP = setpoles(F,p);
F = symmetr(F,type,tol);
F = z2zeta(F,tol);
end
end
At several locations within the toolbox, the function minreals is called. All those calls were replaced with:
minreals(sdzpk(obj))
In that way, I make sure the new class is used and the correct method is applied.
I hope this helps somebody.