How to redeclare package in a model before making an instance? - modelica

I would like to do
M_type(redeclare package L=L2) m2_instance;
but does not work. Instead I can write
model M2_type
extends M_type(redeclare package L=L2);
end M2_type;
M2_type m2_instance;
Is here not a shorter way to do this and avoid declaring M2_type?

The redeclare modifier must be moved to the instance name.
M_type(redeclare package L=L2) m2_instance; // wrong syntax
M_type m2_instance(redeclare package L=L2); // correct
Below is a small package, which demonstrates everything and simulates perfectly fine in Dymola 2021x and OpenModelica 1.16.2.
package Redeclaration
package L1
constant Real x = 1;
end L1;
package L2
constant Real x = 2;
end L2;
model M_type
replaceable package L = L1;
Real x = L.x;
end M_type;
model Example
M_type m_instance(redeclare package L=L2);
end Example;
end Redeclaration;

Related

Why can't I import a let definition from a package, in a SystemVerilog module?

I would like to put the following definitions in a default package, which I include in all my other SystemVerilog modules:
let max(a,b) = a > b ? a : b;
But, when I try to use the imported let definition in a module, I'm told that I'm attempting to use a non-local function definition and VCS errors out.
Why?
The simple example works with no issues. Make sure that the package is always compiled before it is imported. Do correct import from the package either as pkg::* or pkg::max. Or use it as pkg::max(a,b) directly without import. And yes, use the compiler which supports this syntax.
package pkg;
let max(a,b) = a > b ? a : b;
endpackage:pkg
module top();
import pkg::*;
int a = 1,b = 2;
initial begin
$display("max of %d and %d is %d", a, b, max(a,b));
end
endmodule

Can multiple modules have the same module type? How do I organize them and their interface files?

Currently, I have within the same OCaml file,
blah.ml:
module type blah =
sig
val a : some-type
end
module type X =
sig
val x : some-type
end
module Y : X =
struct
let x = some-def
end
module Z : X =
struct
let x = some-other-def
end
blah.mli looks like this:
module type blah =
sig
val a
end
module type X =
sig
val x : some-type
end
module Y : X
module Z : X
I want X, Y, and Z to be in separate files with separate interfaces. How do I tell in Y.mli and Z.mli that Y and Z have type X?
Any readings for this would also be appreciated. There are a lot of resources talking about modules, interfaces, and functors, but they don't mention interface files for modules that have other modules as types.
You can create x.ml containing the sig, y.ml containing the module, and z.ml containing that module. You don't need to do anything special to tell the compiler that Y : X and Z : X. The compiler infers the module type automatically from the fact that the module conforms to the type i.e. it implements every binding that the module type needs. If Y or Z don't conform, the type error will be shown at the point of use.
If you want to restrict the module type at the point of definition that's also doable, by giving each module an interface file and includeing the required signature there. For example:
(* x.ml *)
module type S = sig
val x : some-type
end
(* y.mli *)
include X.S
(* y.ml *)
let x = some-def
...and so on.
However this often becomes too restrictive as the signature hides too much detail about the types. So in reality you may actually need to add type equality sharing constraints to avoid compile errors where you want to expose more type info. E.g.:
(* y.mli *)
include X.S with type t = int
Often it is easier to not have the explicit interface file at all unless you really need to make some parts of the module private.

How to use "connect" statements to automatically derive sum of specific "Real" declared across set of components in modelica?

I was thinking about a feature that would nice to have in Modelica language (I am using OpenModelica 1.14.1).
The feature would automatically add an equation representing a sum of desired values.
The value representing the sum would be declared in the global component instantiated on the top level of a model.
Each contribution of a lower level (perhaps nested) component would be represented by a connect statement.
For this, a connector class with a flow variable could be used since it generates the right equations. inner and outer keywords could make this possible. I tried to code an example of this in the following way:
package global_sum_test
connector X_sum
flow Real x;
end X_sum;
model Global
X_sum x_sum;
Real x = x_sum.x "Variable representing the sum";
end Global;
model Local
parameter Real x=1 "Local contribution to the sum";
outer Global global "Reference to the Global instance";
X_sum x_sum;
equation
x_sum.x = -x "negative sign makes x flowing flom local into global";
connect(x_sum, global.x_sum) "Pushing local x into global sum";
end Local;
model Local_nested
parameter Real x=1 "Local contribution to the sum";
outer Global global "Reference to the global";
X_sum x_sum;
Local local "Component within another component to test nesting";
equation
x_sum.x = -x "Negative sign makes x flowing flom local into global";
connect(global.x_sum, x_sum) "Pushing local x into global sum";
end Local_nested;
model test_model
inner Global global "Instance of Global that is available to lower-level components";
Local local1 "Instance of Local";
Local_nested local2 "Instance of Local_nested with one more Local in it";
end test_model;
end global_sum_test;
This, unfortunately, does not work.
When I instantiate the test_model it gives the following output (which I have appropriately commented):
class global_sum_test.test_model
Real global.x_sum.x;
Real global.x = global.x_sum.x "Variable representing the sum";
parameter Real local1.x = 1.0 "Local contribution to the sum";
Real local1.x_sum.x;
parameter Real local2.x = 1.0 "Local contribution to the sum";
Real local2.x_sum.x;
parameter Real local2.local.x = 1.0 "Local contribution to the sum";
Real local2.local.x_sum.x;
equation
local1.x_sum.x = -local1.x "negative sign makes x flowing flom local into global";
local2.local.x_sum.x = -local2.local.x "negative sign makes x flowing flom local into global";
local2.x_sum.x = -local2.x "Negative sign makes x flowing flom local into global";
global.x_sum.x + (-local1.x_sum.x) + (-local2.x_sum.x) + (-local2.local.x_sum.x) = 0.0; // <- this is correct
local1.x_sum.x = 0.0; // <- this line should not be generated and makes system over-determined.
local2.x_sum.x = 0.0; // <- this line should not be generated and makes system over-determined.
local2.local.x_sum.x = 0.0; // <- this line should not be generated and makes system over-determined.
end global_sum_test.test_model;
The three lines generated at the end cause the system to be over-determined. If it would not be for those three lines it would work exaclly as I need.
Questions:
Is this expected behavior? Are the additional lines caused by using open Modelica compiler?
Is there a way to improve my code in such a way that the three additional lines do not get generated?
Can anyone please test this global_sum_test.test_model in Dymola to make sure that this issue is not specific to OpenModelica only?
Is there some other way to get the sum automatically?
Let me answer my own question by posting an altered version of the code:
package global_sum_test
connector X_sum
flow Real x;
end X_sum;
model Global
X_sum x_sum;
Real x = x_sum.x;
end Global;
model Local
parameter Real x = 1;
outer Global global;
outer X_sum x_sum "Added outer key word here";
equation
x_sum.x = x "Removed the negative sign from here";
connect(x_sum, global.x_sum);
end Local;
model Local_nested
parameter Real x = 1;
outer Global global;
outer X_sum x_sum "Added outer key word here";
Local local;
equation
x_sum.x = x "Removed the negative sign from here";
connect(global.x_sum, x_sum) ;
end Local_nested;
model test_model
inner Global global;
Local local1;
Local_nested local2;
end test_model;
end global_sum_test;
This instantiates correctly:
class global_sum_test.test_model
Real global.x_sum.x;
Real global.x = global.x_sum.x;
parameter Real local1.x = 1.0;
Real local1.x_sum.x;
parameter Real local2.x = 1.0;
Real local2.x_sum.x;
parameter Real local2.local.x = 1.0;
Real local2.local.x_sum.x;
equation
local1.x_sum.x = local1.x "Removed the negative sign from here";
local2.local.x_sum.x = local2.local.x "Removed the negative sign from here";
local2.x_sum.x = local2.x "Removed the negative sign from here";
global.x_sum.x + (-local1.x_sum.x) + (-local2.local.x_sum.x) + (-local2.x_sum.x) = 0.0;
end global_sum_test.test_model;
It now works as expected and gives answer global.x = 3.0.
So I have posted a ticket to https://trac.openmodelica.org/OpenModelica/ticket/5834 and got a great reply.
There is a very good explanation of what is happening and how to do these sums very neatly (and correctly) with a minimal working example.

Problems with record call in Dymola

The following package 'RecordTest' (example to reproduce an error of a bigger model) contains a Record to define the structure of some data. Further in package 'DataDefintion' two sets of data are defined. Finally this data should be used in package 'UseOfData'. Herein the data sets are read and the sum of all arrays A is evaluated in the function 'FunctionWithData'.
The simulation of model 'FunctionCall' works fine in OpenModelica. In Dymola I get the error: 'For variable package constant RecordTest.UseOfData.ReadData[1].A the subscript RecordTest.UseOfData.ReadData.Index of an array variable is not an integer.'
Do I miss anything? The constant 'Index' is defined as an integer in record 'DataStructure'. Further the model runs in OpenModelica. I don't understand the error of Dymola.
Thanks in advance.
package RecordTest
record DataStructure
constant Integer Index;
Real A[Index];
end DataStructure;
package DataDefinition
constant DataStructure Set1(Index=2, A={1,2});
constant DataStructure Set2(Index=2, A={3,4});
end DataDefinition;
package UseOfData
constant Integer N=2;
constant DataStructure ReadData[N]={DataDefinition.Set1, DataDefinition.Set2};
function FunctionWithData
input Real b;
output Real Result;
protected
Real Array[2];
algorithm
Array := {sum(ReadData[1].A), sum(ReadData[2].A)};
Result := b*sum(Array);
end FunctionWithData;
model FunctionCall
parameter Real b=2;
Real FunctionResult;
equation
FunctionResult = FunctionWithData(b);
end FunctionCall;
end UseOfData;
end RecordTest;
A work-around is to rewrite the package as follows:
package RecordTest
record DataStructure
constant Integer Index;
Real A[:];
end DataStructure;
package DataDefinition
constant DataStructure Set1=DataStructure(Index=2, A={1.0,2.0});
constant DataStructure Set2=DataStructure(Index=2, A={3.0,4.0});
end DataDefinition;
package UseOfData
constant Integer N=2;
constant DataStructure ReadData[N]={DataDefinition.Set1, DataDefinition.Set2};
function FunctionWithData
input Real b;
output Real Result;
protected
Real Array[2];
algorithm
Array := {sum(ReadData[1].A), sum(ReadData[2].A)};
Result := b*sum(Array);
end FunctionWithData;
model FunctionCall
parameter Real b=2;
Real FunctionResult;
equation
FunctionResult = FunctionWithData(b);
end FunctionCall;
end UseOfData;
end RecordTest;
The issues are the "Index" used in A inside a package-constant array of records, and the modifiers instead of binding equation for the package-constant records Set1 and Set2.
(It will also be handled in a future version of Dymola, and I understand the answer is a bit late.)

Using a Class/record in an other class (subtype mark required in this context)

I want to learn ADA and have a problem with the 'class'
I have 2 classes A and B and want that class A can use class B.
Class A
with B;
package A is
type A is tagged
record
varA : INTEGER := 0;
varB : INTEGER := 0;
end record;
procedure DOSMTH(A_In : in out A; B_IN: in out B);
end A;
and Class B
package B is
type B is tagged
record
var1 : INTEGER;
var2 : INTEGER;
end record;
procedure DoSMTH2(B_IN: in out B; var : INTEGER);
end B;
If I want to compile A I get following error message:
subtype mark required in this context
found 'B' declared at b.ads:1
Another problem is my 'Main' File which can't use A and B (declaration)
with Ada.Text_IO, A, B;
procedure Main is
a : A;
b : B;
begin
null;
end Main;
I get following Errors:
object "A" cannot be used before end of its declaration
object "B" cannot be used before end of its declaration
I can't find any solution for that. I have read the ADA 2005 Reference Manual but can't find anything.
OK thx for the help,
finaly it works now.
Solution:
Modify Class A to
with B;
package A is
type A is tagged
record
-- u can use a object VAR with
-- objB : B.B
varA : INTEGER := 0;
varB : INTEGER := 0;
end record;
procedure DOSMTH(A_In : in out A; B_IN: in out B.B);
end A
Modify Main to:
with Ada.Text_IO, A, B;
procedure Main is
myA : A.A; --the old one was stupid ...
myB : B.B; --same here
begin
null;
end Main;
The problem with the main program is that Ada isn’t case-sensitive, so when you say
a : A.A;
the compiler sees as far as a : A and thinks that the second A is the same thing as the first, hence the complaint that object "A" cannot be used before end of its declaration.
You can tell the compiler where to look for the package A by qualifying it. Package A is declared at library level, and there’s a notional package Standard you can use to indicate this:
a : Standard.A.A;
However, it’s much better, if you can, to avoid using the same name for different things in the first place.
You only withed package B in package A - in order to use anything form it you have to use qualified name (that is: for record B you should use B.B). Like:
with B;
package A is
type A is tagged
record
varA : INTEGER := 0;
varB : INTEGER := 0;
end record;
procedure DOSMTH(A_In : in out A; B_IN: in out B.B);
end A;
If you want to use things declared in package B without fully qualifying name you should put use B; right after withing it.
As to whether one should use or only with package is hard question - most of the time most Ada programmers that I know (including myself) prefer to with packages only, rarely using them - for example when working with Lumen library (OpenGL binding with glut-like functionality) I usually use Lumen because then I can type GL.Whatever_GL_Function instead of Lumen.GL.Whatever_GL_Function (but I do not "use" Lumen.GL). If package name is long I prefer to rename it inside procedure and in case of types (for operators if defined) one can use type B.B;
PS: I can elaborate more if some parts of it are unclear.
My guess would be that the compiler sees "B" as the name of the package and not the record. Try naming your package or records differently.
Also, if you want to learn Ada, the reference manual is the last place you want to start at. Get the book by Barnes or get one of the older books used at Amazon. You get good books about Ada 95 for 5$ in the used section.