Is there a way to pass parameter to a replaceable/redeclared component? - modelica

This question is related to this previous question.
I have some submodels that are interchangeable and I use the replaceable/redeclare mechanism to include them in a model (e.g. submodels of different type of heat-exchangers in a cooling loop model).
I would like to "link" some parameters of the main model (let's say the pipes' length and diameter) to the corresponding parameters of the submodule. This is usually done when defining a model instance (i.e. in the replaceable line), but how can this link be applied also when the componenet is redeclared? Expecially if choicesAllMatching is used?
Here is "my" model (thanks to helpers in the previous question):
package Test
// Original definition of Component 1 and 2 in the external library
// COMP1 (COMP2) has a parameter p1 (p2) defined with a default value
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
parameter Real pp = 10; // New parameter definition to have the same name for all variants
Real v "";
end Call_Interface;
// Both Call1 and Call2 parameters (p1 and p2) are linked to pp
model Call1 "Default"
extends Call_Interface;
extends ReadOnlyLibrary.COMP1(p1=pp);
end Call1;
model Call2 "Variant"
extends Call_Interface;
extends ReadOnlyLibrary.COMP2(p2=pp);
end Call2;
// Main module (system)
model Main
parameter Real pm=100 "";
parameter Real pp0=1 ""; //Actual parameter value to be used by submodules for this application -> pp
Real vm "";
replaceable Test.Call1 OBJ(pp=pp0) constrainedby Test.Call_Interface annotation (choicesAllMatching); //For default definition, pp, and finally p1, are linked to pp0. But when OBJ is redeclarated, the link is lost and p1/p2 gets its default value.
equation
vm = OBJ.v+pm;
end Main;
// Application model, using the main model
model App
Main main;
end App;
end Test;
I could add all possible redeclarations in the annotation by writing for example choice(redeclare Test.Call2 OBJ(pp=pp0)) instead of using choiceAllMatching but that may become tedius and error prone when many submodules are interchangeables (it would be easier and safer to write the "link" just once).
I tried by adding a generic OBJ.pp = pp0 in Main model parameter section, but this is not accepted. What is the proper way of doing that?

You simply have to write the modifiers to the constraining class:
replaceable Test.Call1 OBJ constrainedby Test.Call_Interface(pp=pp0)
annotation (choicesAllMatching);

Related

Inheriting from Sealed classes in MATLAB

In MATLAB, one of the attributes of a class (defined after classdef) is Sealed, which means that no class can use it as a superclass (or to be more precise, "to indicate that these classes have not been designed to support subclasses."1).
For example, if I try to instantiate a class that's defined as below (considering table is Sealed):
classdef SomeLie < table
end
I would get the 'MATLAB:class:sealed' error:
>> A = SomeLie;
Error using SomeLie
Class 'table' is Sealed and may not be used as a superclass.
As I refuse to be told by a machine what I may or may not do, I would like to subclass a Sealed class, regardless. How can I do that in MATLAB R2017a?
I'm having a hard time believing that this system is completely airtight, so I'm looking for a solution that would cause the Sealed attribute to be silently ignored (or something of that sort). The desired solution should work without modifying any "library class definitions" to remove Sealed from them.
I tried playing around with "reflection", but arrived at a dead end...
classdef SomeLie % < table
properties (Access = private)
innerTable table;
end
properties (GetAccess = public)
methodHandles struct = struct();
end
methods
function slObj = SomeLie(varargin)
slObj.innerTable = table(varargin{:});
% methodHandles = methods(slObj.innerTable);
ml = ?table; ml = {ml.MethodList.Name}.';
ml = setdiff(ml,'end');
tmpStruct = struct;
for indM = 1:numel(ml)
tmpStruct.(ml{indM}) = str2func([...
'#(varargin)' ml{indM} '(slObj.innerTable,varargin{:})']);
end
slObj.methodHandles = tmpStruct;
end
function varargout = subsref(slObj,varargin)
S = struct(slObj);
varargout{:} = S.methodHandles.(varargin{1}.subs)(varargin{:});
end
end
end
(There's no need to fix the above code, I was just sharing)
I do not think the machine is the problem, but the class designer and he certainly has good motivations to seal the class. "Philosophy" of coding, a part, you could 'own' the class in a wrapper class without defining it sealed.
For example, supposer the class Hello is sealed and has a method (or function, if you wish) sayHello which you would like to use in inherited classes you could define a class FreeHello (public) which contains an instance of Hello. At the constructor you build the corresponding Hello and then you define a sayHello method whose body simply calls your Hello instance and makes it execute the sayHello method (and returns the output, accordingly).
In order to 'open' the sealed class, you need to do these for all properties and public methods; of course you are still not capable of accessing private methods, but now you can subclass your wrapper class, as you wish.

Avoid repeating a superclass' package name in Matlab

How can I avoid repeating a long tedious package name in matlab classes in the following cases:
When specifying the Superclass, e.g. classdef Class < tediouspkgname.Superclass
When calling the superclass constructor, e.g. obj = obj#tediouspkgname.Superclass(...).
When calling superclass methods, e.g. val = somefunc#tediouspkgname.Superclas(...).
I'm looking for an equivalent of matlabs import statement, which is not usable in these cases unfortunately.
MWE:
Lets have a folder called +tediouspkgname/ in our Matlab path. So Matlab recognizes there's a package called tediouspkgname.
Lets have a Class ExampleClass which is saved in the file +tediouspkgname/ExampleClass.m:
classdef ExampleClass
properties
p
end
methods
function obj = ExampleClass(p)
obj.p = p;
end
function print(obj)
fprintf('p=%s\n',obj.p);
end
end
end
Let there be another Class, derived from ExampleClass, living in the file
+tediouspkgname/DerivedClass.m:
classdef DerivedClass < tediouspkgname.ExampleClass
methods
function obj = DerivedClass(p)
obj = obj#tediouspkgname.ExampleClass(p);
end
function print(obj)
print#tediouspkgname.ExampleClass(obj);
fprintf('--Derived.\n');
end
end
end
I want the following commands to work without errors while mentioning tediouspkgname. as little as possible:
e = tediouspkgname.ExampleClass('Hello');
e.print();
o = tediouspkgname.DerivedClass('World');
o.print();
In particular, this definition of DerivedClass gives me the error ExampleClass is not a valid base class:
classdef DerivedClass < tediouspkgname.ExampleClass
methods
function obj = DerivedClass(p)
obj = obj#tediouspkgname.ExampleClass(p);
end
function print(obj)
import tediouspkgname.ExampleClass
print#ExampleClass(obj);
fprintf('--Derived.\n');
end
end
end
You have two examples at the command line:
e = tediouspkgname.ExampleClass('Hello');
e.print();
o = tediouspkgname.DerivedClass('World');
o.print();
For these cases, you can use import at the command line:
import tediouspkgname.*
e = ExampleClass('Hello');
e.print();
o = DerivedClass('World');
o.print();
and it should work fine.
For the other cases you have (in the class definition line, and when calling a superclass method), you need to use the fully qualified name including the package.
I dislike this aspect of the MATLAB OO system. It's not just that it's tedious to write out the fully qualified name; it means that if you change the name of your package, or move a class from one package to another, you have to manually go through your whole codebase in order to find-and-replace one package name for another.

Switch type based on boolean parameter (without inheriting)?

I have a model representing some chemical process, and I want the reaction model to be switchable between an absorption and a desorption class (which define the respective model), based on a boolean parameter.
I tried to do it like this:
model Sorption
boolean parameter absorbing;
AbsorptionModel if absorbing else Desorptionmodel reaction;
equation
reaction.T = T; //dummy usage
...
Use it like:
Sorption TestAbsorption(absorbing=true); // uses the absorption model
Sorption TestDesorption(absorbing=false); // uses the desorption model
Of course, this way does not work. absorbing is known at compile time, so I have a feeling it should be ok to achieve this somehow.
I tried to use replaceable, but I don't want to (unnecessarily) make two separate subclasses of Sorption just to switch the type of reaction model. It seems replaceable/redeclare is only useable when inheriting, but I may be wrong? Is there a way to do what I want?
AbsorptionModel and DesorptionModel both inherit from the same base class, and have identical interfaces, if that is relevant.
No if is needed and you cannot use if with component declaration, except for conditional components (but that will only remove the component declaration and its connection equations).
model Sorption
boolean parameter absorbing;
replaceable model RModel = AbsorptionModel;
RModel reaction;
equation
reaction.T = T; //dummy usage
...
Use it like:
Sorption TestAbsorption(redeclare model RModel = AbsorptionModel); // uses the absorption model
Sorption TestDesorption(redeclare model RModel = Desorptionmodel); // uses the desorption model

Classname in static methods of abstract classes

I would like to access the class name of the concrete class that's invoking a static method implemented in an abstract superclass.
This is the code (part of) of the abstract superclasss:
classdef (Abstract) AbstractJobProcessor < handle
properties (Abstract, Constant)
VERSION_MAJOR;
VERSION_MINOR;
LAST_MODIFIED;
end
...
methods (Static)
function res = getVersionMajor;
res = AbstractJobProcessor.VERSION_MAJOR;
end
function res = getVersionMinor
res = AbstractJobProcessor.VERSION_MINOR;
end
function res = getVersionInfo
res = sprintf('**CLASSNAME**: v%d.%02d (last modified: %s)',...
AbstractJobProcessor.VERSION_MAJOR,...
AbstractJobProcessor.VERSION_MINOR,...
AbstractJobProcessor.LAST_MODIFIED);
end
end
...
Basically, I would like to access the classname of the concrete subclass and use it in the method getVersionInfo in place of the string **CLASSNAME**.
All the methods returning meta information about a class (that I have found in the documentation) require a reference to an instance of the class (like, for example, mc = metaclass(object)).
The below function will give you what you want - subclass name, that was used when invoking an (inherited) static superclass method. Just call it inside your superclass method like you would any normal function:
className = getStaticCallingClassName();
What it does handle:
Both the case when method was invoked programmatically (i.e. by a running script / function), as well as when it was invoked from the command window.
Arbitrarily nested package names (i.e. classes located inside directories prefixed with +).
What it does not handle:
Does not work if the static method is called in a non-static context, i.e. on an object instance. But you should not be using such syntax anyway. This would've been possible if we were able to use evalin with 'caller' workspace recursively, but it does not work this way.
A brief explanation behind the idea: second entry in the stack trace, produced by dbstack, would correspond to the superclass, which we can use to extract the static method name. The next steps depend on:
If the method is invoked programmatically, third stack entry would point us to a line in the the parent script/function which we need to read, e.g. using dbtype. All that's left to do is extract the subclass name using regexp based on the method name.
If the method is invoked from command window, we query the last command and use that as the input for our regular expression.
Note that even if stack has 3 entries or more, it doesn't mean that the method was invoked programmatically. For example, if we've stopped on a breakpoint somewhere and invoke the method from command window, stack trace would be long, but regexp based on the line from the third stack trace entry will not give us the answer. In this case we fall back to the command window approach.
Warning: it heavily relies on undocumented features and may break in any feature release. Tested on Matlab 2015b, but should work on most previous releases as well. Some may say it is quite dirty, but it works very well, and it's the only method that I'm aware of to achieve such a behavior.
function [className, fullPath] = getStaticCallingClassName()
ST = dbstack('-completenames');
% First one is getStaticCallingClassName, second one is the superclass
methodName = char(regexp(ST(2).name, '[^\.]([^.]*)$', 'match'));
% matches string (combination of alphanumeric/underscore/dot characters) preceeding the given method call.
pattern = sprintf('[\\w.-]*(?=.%s)', methodName);
% If the parent called static method programmatically, we should be able to find it via the next (third) stack trace
if length(ST) > 2
command = evalc('dbtype(ST(3).file, num2str(ST(3).line))');
className = char(regexp(command, pattern, 'match'));
else % was likely called from command window. Long stack trace means that we're simply waiting in a breakpoint somewhere
className = []; % go straight to command window approach
end
if isempty(className) % means that static method was called directly from command window
javaHistory = com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory();
command = char(javaHistory(end));
className = char(regexp(command, pattern, 'match'));
end
fullPath = which(className);
end
Here's a workaround. According to the MATLAB documentation:
'Ordinary methods define functions that operate on objects of the class',
'Static methods are (1) associated with a class, but (2) not with specific instances of that class'.
You can have both aspects of static methods if you call an ordinary method with an empty object array.
For example, suppose we have a base class:
classdef base
methods
function obj = base()
disp('constructor called')
end
function dispClassName(obj)
disp(['class name = ', class(obj)]);
end
end
end
and a subclass
classdef sub < base
end
Now call the methods as follows (this will not invoke any constructor):
>> base.empty.dispClassName
class name = base
>> sub.empty.dispClassName
class name = sub
A real solution (for which I did an enhancement request 03315500 to MathWorks) would be to extend the MATLAB language with a method attribute 'Class' to define methods that are associated with the invoking class (similar to the Python #classmethod decorator). Methods of this class would automatically receive the metaclass of the invoking function as a first argument. With such an extension we could define a base class:
% Future MATLAB syntax extension
classdef base
methods(Class) % New method attribute ‘Class’
function dispClassName(cls) % implicit argument (meta.class)
disp(['class name = ' cls.Name ]);
end
end
end
and a subclass
classdef sub < base
end
and call
>> base.dispClassName
class name = base
>> sub.dispClassName
class name = sub

Is there any method to know whether a member is declared random or not in a class in SV

// Current Class
class x;
rand int a;
int b; // b is nonrandom as of now
function new();
endfunction
function abc;
// if a != ref.a, where ref is reference object of class x, declared somewhere else
a.rand_mode(0);
endfunciton
// Future Possible Class
class x;
rand int a;
rand int b; // b is also a random variable now
function new();
endfunction
function abc;
// if a != ref.a, where ref is reference object of class x, declared somewhere else
a.rand_mode(0);
// if b != ref.b, where ref is reference object of class x, declared somewhere else
b.rand_mode(0);
endfunciton
So in function abc, depending upon whether a rand member value matches or doesn't match with the value of that member in reference class, that rand declared members of class x, should be active or inactive accordinly.
Purpose - I need to check if a rand variable matches with reference class value then only it should be randomized, otherwise not.
I want to generalize method abc, for all possible future variations (So I don't need to modify it, as done in the above example), and as I don't know, when a class member may become rand or nonrand member, Is there any inbuilt method to know, whether a member of a class is declared as rand or not in that class?
You could change your perspective on the problem slightly. Instead of trying to disable randomization for fields that are declared rand, why not say that when they get randomized, they should keep their value?
According to this nice post, there's a new construct in SV 2012, const'(...) that would work in this case. Unfortunately I don't think many vendors support it. Your randomize() call would look like this:
if (!rand_obj.randomize() with {
const'(a) != ref_obj.a -> a == const'(a);
})
$fatal(0, "rand error");
Let's dissect this code. const(a) will sample the value of a prior to doing any sort of randomization. If the value of a before randomization is not equal to the reference value, then we have the second part of the constraint that says a should keep its value. I've tried this code on two simulators but it wasn't supported by either (though it should be legal SV 2012 syntax). Maybe you're lucky enough to have a vendor that supports it.
You can write such constraints even for state variables, as they will still hold.
If you can't get the const syntax to work in your simulator, then the same post shows how you could work around the issue. You could store the values prior to randomization inside the object and use those in the constraint:
class some_class;
rand bit [2:0] a;
bit [2:0] b;
bit [2:0] pre_rand_a;
bit [2:0] pre_rand_b;
function void pre_randomize();
pre_rand_a = a;
pre_rand_b = b;
endfunction
endclass
When you want to randomize, you'd add the following constraints:
if (!rand_obj.randomize() with {
pre_rand_a != ref_obj.a -> a == pre_rand_a;
pre_rand_b != ref_obj.b -> b == pre_rand_b;
})
$fatal(0, "rand error");
You can find a full example on EDAPlayground.
You mention that your function that does randomization is defined outside of the object. Because of that, the pre_rand_* fields can't be local/protected, which isn't very nice. You should consider making the function a class member and pass the reference object to it, so that you can enforce proper encapsulation.
This isn't possible as SystemVerilog doesn't provide any reflection capabilities. You could probably figure this out using the VPI, but I'm not sure how complete the implementation of the VPI is for classes.
Based on what you want to do, I'd say it anyway doesn't make sense to implement such a query just to future proof your code in case some fields will one day become rand. Just as how you add the rand modifier to the field, you can also add it to the list of fields for which randomization should be disabled. Both code locations reside in the same file, so it's difficult to miss.
One certain simulator will return -1 when interrogating a state variable's rand_mode(), but this is non-standard. The LRM explicitly states that it's a compile error to call rand_mode() on non-random fields.