How to deal with derivatives of input variables in equations in OpenModelica when doing linearization? - modelica

I'm trying to linearize a very simple model using OpenModelica's linearize() function, however, a translation error is produced likely because the equation of motion includes derivatives of the input variable.
Currently, I really don't mind the value of the input variable as long as I can get the state space representation with the function linearize(), from which I can calculate the transfer function. Therefore, I explicitly wrote the value of the input variable to be zero, but it still produces the error.
The definition of the model and the output generated in OMShell are below.
Any help would be appreciated.
Regards,
Fabian
Model definition:
model IP_v0
// Input and output variables
output Real x_load (start = 100e-6) "Displacement of the load";
input Real x_ground = 0 " Displacement of the ground";
// Velocities
Real v_load (start = 0) "Velocity of the load";
Real v_ground (start = 0) "Velocity of the ground";
// Parameters of the equation of motion
parameter Real beta = -1e-4;
parameter Real omega = 2 * 3.141592653 * 0.100 "Frequency of 100 mHz" ;
equation
v_load = der(x_load);
v_ground = der(x_ground);
der(v_load) + beta * der(v_ground) = -omega ^ 2 * (x_load - x_ground);
end IP_v0;
OMShell session:
linearize(VIS.IP_v0)
record SimulationResult
resultFile = "",
simulationOptions = "startTime = 0.0, stopTime = 1.0, numberOfIntervals = 500, tolerance = 1e-06, method = 'dassl', fileNamePrefix = 'VIS.IP_v0', options = '', outputFormat = 'mat', variableFilter = '.*', cflags = '', simflags = ''",
messages = "Failed to run the linearize command: VIS.IP_v0",
timeFrontend = 0.0041959,
timeBackend = 0.0,
timeSimCode = 0.0,
timeTemplates = 0.0,
timeCompile = 0.0,
timeSimulation = 0.0,
timeTotal = 0.0042162
end SimulationResult;
getErrorString()
"Error: Internal error - IndexReduction.pantelidesIndexReductionMSS failed! Use -d=bltdump to get more information.
Error: Internal error - IndexReduction.pantelidesIndexReduction1 failed! Use -d=bltdump to get more information.
Error: Internal error - IndexReduction.pantelidesIndexReduction failed!
Error: Internal error Transformation Module PFPlusExt index Reduction Method Pantelides failed!

Related

Out of bound external function calls with nonlinear solvers in OpenModelica

I have a simple Modelica model calls an external function (C code via ExternalObject) that (nonlinearly) interpolates properties over the space s1, s2, s3 where s are all bound between 0 and 1. The model needs to invert/solve f1 = f1(s1,s2,s3), f2 = f2(s1,s2,s3), f3 = f3(s1,s2,s3) to find the initial s given known f. Unfortunately, the OpenModelica nonlinear solvers attempt to evaluate f using out of bounds s, despite defining s1,s2,s3 as:
Real s1(min = 0.0, max = 1.0, start = 0.5, nominal = 0.01);
Real s2(min = 0.0, max = 1.0, start = 0.5, nominal = 0.01);
Real s3(min = 0.0, max = 1.0, start = 0.5, nominal = 0.01);
As far as I can tell, there is no way of dealing with this other than to pull the inversion into the external C object. Have I missed something?

How to work with quantiz in matlab/octave?

I have a code which resizes an image and gets its entropy.
Resize works correctly, but I cannot do something with quantiz.
This function throws
Error using quantiz (line 31)
The input signal must be a real vector.
Error. How to fix it?(GrayImage is 2D array with values from 0 to 255)
normalImage = imread("porshe.bmp");
grayImage = rgb2gray(normalImage);
width = 750;
heigth = 500;
ebase = entropy(grayImage);
resizedImage2 = imresize(grayImage,0.5);
resizedImage4 = imresize(grayImage,0.25);
er2 = entropy(resizedImage2);
er4 = entropy(resizedImage4);
quantizImage8 = quantiz(grayImage,8);
quantizImage16 = quantiz(grayImage,16);
quantizImage64 = quantiz(grayImage,64);
imshow(quantizImage64)

Interpreting flat code and counting equations in Dymola

I am having trouble locating the source of an additional unknown in a modelling project I am working on. I am getting an error saying I have 34 unknowns and 33 equations. I decided to look at the flattened code in Dymola, and while I can count the correct number of variables, I cannot find a way to reach the 33 equations. Below is the flattened code:
model HeatStorage
parameter Modelica.SIunits.Diameter D = 18.667 "Diameter";
parameter Modelica.SIunits.Height H = 20 "Height";
parameter Boolean enable_losses = false "= true enable thermal losses with environment";
parameter Modelica.SIunits.CoefficientOfHeatTransfer alpha = 1
"Constant heat transfer coefficient with the ambient";
parameter Real L_start = 0 "Start value of level in %";
parameter Modelica.SIunits.Temperature T_start = Modelica.SIunits.Conversions.from_degC
(300) "Start value of temperature";
parameter Modelica.SIunits.Temperature T_max = Modelica.SIunits.Conversions.from_degC
(550) "Maximum tank temperature";
parameter Modelica.SIunits.Temperature T_set = Modelica.SIunits.Conversions.from_degC
(300) "Tank Heater Temperature Set-Point";
parameter Modelica.SIunits.Power W_max = 3000000000.0 "Hot Tank Heater Capacity";
parameter Modelica.SIunits.Efficiency e_ht = 0.99 "Tank Heater Efficiency";
parameter Boolean medium.preferredMediumStates = false "= true if StateSelect.prefer shall be used for the independent property variables of the medium";
parameter Boolean medium.standardOrderComponents = true "If true, and reducedX = true, the last element of X will be computed from the other ones";
input Modelica.Blocks.Interfaces.RealInput Q_heater;
parameter Modelica.SIunits.Volume V_t = H*3.141592653589793*D^2/4;
Modelica.Media.Interfaces.PartialMedium.MassFlowRate fluid_a.m_flow
"Mass flow rate from the connection point into the component";
Modelica.Media.Interfaces.Types.AbsolutePressure fluid_a.p "Thermodynamic pressure in the connection point";
Modelica.Media.Interfaces.Types.SpecificEnthalpy fluid_a.h_outflow
"Specific thermodynamic enthalpy close to the connection point if m_flow < 0";
Modelica.Media.Interfaces.Types.MassFraction fluid_a.Xi_outflow[0]
"Independent mixture mass fractions m_i/m close to the connection point if m_flow < 0";
Modelica.Media.Interfaces.Types.ExtraProperty fluid_a.C_outflow[0](start =
fill(1.0, size(fluid_a.C_outflow, 1))) "Properties c_i/m close to the connection point if m_flow < 0";
Modelica.Media.Interfaces.PartialMedium.MassFlowRate fluid_b.m_flow
"Mass flow rate from the connection point into the component";
Modelica.Media.Interfaces.Types.AbsolutePressure fluid_b.p "Thermodynamic pressure in the connection point";
Modelica.Media.Interfaces.Types.SpecificEnthalpy fluid_b.h_outflow
"Specific thermodynamic enthalpy close to the connection point if m_flow < 0";
Modelica.Media.Interfaces.Types.MassFraction fluid_b.Xi_outflow[0]
"Independent mixture mass fractions m_i/m close to the connection point if m_flow < 0";
Modelica.Media.Interfaces.Types.ExtraProperty fluid_b.C_outflow[0](start =
fill(1.0, size(fluid_b.C_outflow, 1))) "Properties c_i/m close to the connection point if m_flow < 0";
Modelica.SIunits.Temperature heat_PB.T "Port temperature";
Modelica.SIunits.HeatFlowRate heat_PB.Q_flow "Heat flow rate (positive if flowing from outside into the component)";
Modelica.SIunits.Temperature heat_DS.T "Port temperature";
Modelica.SIunits.HeatFlowRate heat_DS.Q_flow "Heat flow rate (positive if flowing from outside into the component)";
Modelica.SIunits.Volume V;
Modelica.SIunits.Mass m;
Modelica.Media.Interfaces.PartialMedium.BaseProperties_D1.InputAbsolutePressure
medium.p(nominal = 100000.0, unit = "Pa", displayUnit = "bar", min = 0.0)
"Absolute pressure of medium";
Modelica.Media.Interfaces.PartialMedium.BaseProperties_D1.InputMassFraction
medium.Xi[0](start = {}, unit = "1", min = 0.0, max = 1.0) "Structurally independent mass fractions";
Modelica.Media.Interfaces.PartialMedium.BaseProperties_D1.InputSpecificEnthalpy
medium.h(unit = "J/kg") "Specific enthalpy of medium";
Modelica.Media.Interfaces.Types.Density medium.d "Density of medium";
Modelica.Media.Interfaces.Types.Temperature medium.T(start = 800, min = 573.15,
max = 873.15) "Temperature of medium";
Modelica.Media.Interfaces.Types.MassFraction medium.X[2](start = {0.5, 0.5})
"Mass fractions (= (component mass)/total mass m_i/m)";
Modelica.Media.Interfaces.Types.SpecificInternalEnergy medium.u
"Specific internal energy of medium";
Modelica.Media.Interfaces.Types.SpecificHeatCapacity medium.R "Gas constant (of mixture if applicable)";
Modelica.Media.Interfaces.Types.MolarMass medium.MM "Molar mass (of mixture or single fluid)";
Modelica.Media.Interfaces.Types.AbsolutePressure medium.state.p
"Absolute pressure of medium";
Modelica.Media.Interfaces.Types.SpecificEnthalpy medium.state.h
"Specific enthalpy";
Modelica.SIunits.Conversions.NonSIunits.Temperature_degC medium.T_degC =
Modelica.SIunits.Conversions.to_degC(medium.T) "Temperature of medium in [degC]";
Modelica.SIunits.Conversions.NonSIunits.Pressure_bar medium.p_bar =
Modelica.SIunits.Conversions.to_bar(medium.p) "Absolute pressure of medium in [bar]";
Modelica.SIunits.Area A;
Modelica.SIunits.HeatFlowRate Q_losses;
Modelica.Media.Interfaces.Types.AbsolutePressure state_i.p "Absolute pressure of medium";
Modelica.Media.Interfaces.Types.SpecificEnthalpy state_i.h "Specific enthalpy";
Modelica.SIunits.Power W_net;
Modelica.SIunits.Power W_loss;
output Modelica.Blocks.Interfaces.RealOutput L "Tank level in %";
Modelica.SIunits.HeatFlowRate Q_PB "Heat Flow to PowerBlock";
Modelica.SIunits.HeatFlowRate Q_desal "Heat Flow to Desalination";
// Equations and algorithms
// Component medium
// class SolarTherm.Media.MoltenSalt.MoltenSalt_base.BaseProperties
// extends Modelica.Media.Interfaces.PartialMedium.BaseProperties_D1
equation
if (medium.standardOrderComponents) then
medium.Xi = medium.X[1:0];
medium.X = {0.5, 0.5};
for i in (1:2) loop
assert(medium.X[i] >= -1E-005 and medium.X[i] <= 1.00001,
"Mass fraction X["+ String(i, true, 0)+"] = "+ String(
medium.X[i], true, 0)+"of substance "+{"NaNO3", "KNO3"}[i]+
"\nof medium "+"MoltenSalt"+" is not in the range 0..1");
end for;
end if;
assert(medium.p >= 0.0, "Pressure (= "+ String(medium.p, true, 0)+
" Pa) of medium \""+"MoltenSalt"+"\" is negative\n(Temperature = "+
String(medium.T, true, 0)+" K)");
// end of extends
equation
medium.d = SolarTherm.Media.MoltenSalt.MoltenSalt_Utilities.rho_T(medium.T);
medium.h = medium.state.h;
medium.u = medium.h-medium.p/medium.d;
medium.MM = 0.091438;
medium.R = 8.3144/medium.MM;
medium.state.p = medium.p;
medium.T = SolarTherm.Media.MoltenSalt.MoltenSalt_Utilities.T_h(medium.h);
// This model
// class PentakomoPlant.Storage.HeatStorage
equation
Q_losses = -0.939*exp(Modelica.SIunits.Conversions.to_degC(medium.T)*
0.005111)*1000*5/7;
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 = 100*(max(medium.T, T_set)-T_set)/(T_max-T_set);
A = 6.283185307179586*(D/2)*H;
W_net = Q_heater;
W_loss = W_net/e_ht;
heat_PB.Q_flow = Q_PB;
heat_DS.Q_flow = Q_desal;
heat_PB.T = medium.T;
heat_DS.T = medium.T;
// Initial equations and algorithms
// This model
// class PentakomoPlant.Storage.HeatStorage
initial equation
medium.h = specificEnthalpy_Unique3(
state_i);
m = density_Unique4(
state_i)*V_t;
end HeatStorage;
If someone could shed some light on exactly how the equations are counted from the flat code so as to help me locate my missing variable, I would be most appreciative!!
Unfortunately the flattened code does not contain all the necessary information.
However, it is a good start and contains 27 equations:
2 binding equations
2 scalar equations in the extends Modelica.Media.Interfaces.PartialMedium.BaseProperties_D1
7 equations in SolarTherm.Media.MoltenSalt.MoltenSalt_base.BaseProperties outside the base-class
16 equations in PentakomoPlant.Storage.HeatStorage.
But in addition there can at least be:
Bindings of records (none in this case)
Flow-variables in top-level public connectors; in this case I would assume it 2+2+1+1 (fluid_a, fluid_b, heat_PB, heat_DS).
The top-level public input Q_heater can be handled in two ways, and as I recall Dymola has used both variants: either it does neither contribute to unknowns nor to equations (seen as a known variable), or it adds one to both.

How do I combine tf.absolute and tf.square to create the Huber loss function in Tensorflow?

To be precise, the loss function that I'm looking for is the squared error when the absolute error is lesser than 0.5, and it is the absolute error itself, when the absolute error is greater than 0.5. In this way, the gradient from the error function doesn't exceed 1 because once the gradient of the squared error function reaches 1, the absolute error function kicks in, and the gradient remains constant at 1. I've included my current implementation below. For some reason, it's giving me worse performance than just the squared error.
fn_choice_maker1 = (tf.to_int32(tf.sign(y - y_ + 0.5)) + 1)/2
fn_choice_maker2 = (tf.to_int32(tf.sign(y_ - y + 0.5)) + 1)/2
choice_maker_sqr = tf.to_float(tf.mul(fn_choice_maker1, fn_choice_maker2))
sqr_contrib = tf.mul(choice_maker_sqr, tf.square(y - y_))
abs_contrib = tf.abs(y - y_)-0.25 - tf.mul(choice_maker_sqr, tf.abs(y - y_)-0.25)
loss = tf.reduce_mean(sqr_contrib + abs_contrib)
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)
choice_maker_sqr is a column tensor that is one whenever the error is between 0.5 and -0.5. The names are pretty self explanatory.
Here is my implementation of the Huber loss function in python tensorflow:
def huber_loss(y_true, y_pred, max_grad=1.):
"""Calculates the huber loss.
Parameters
----------
y_true: np.array, tf.Tensor
Target value.
y_pred: np.array, tf.Tensor
Predicted value.
max_grad: float, optional
Positive floating point value. Represents the maximum possible
gradient magnitude.
Returns
-------
tf.Tensor
The huber loss.
"""
err = tf.abs(y_true - y_pred, name='abs')
mg = tf.constant(max_grad, name='max_grad')
lin = mg*(err-.5*mg)
quad=.5*err*err
return tf.where(err < mg, quad, lin)
You can use tf.select to implement it in a single call:
err = y - y_
huber_loss = tf.select(tf.abs(err) < 1.0,
0.5 * tf.square(err),
tf.abs(err) - 0.5) # if, then, else
err = tf.subtract(x,y)
huber_loss = tf.where(tf.less(x,y),
tf.sqrt(tf.square(err)),
tf.abs(err))
with tf.Session() as sess:
print(sess.run(tf.reduce_mean(huber_loss)))
Not sure if this is still relevant, but I would like to point it out to those seeking this in the future. The tensorflow research losses script has an implementation of the Huber loss for Object detection (like its implemented in the FasterRCNN paper)
Here's the link to the method

OpenModelica - I am trying to run a book example but having inner-outer issues

I am running OpenModelica and trying to run an example from Introduction to Physical Modeling with Modelica. I have copied examples 9.1 - 9.4 into a package. The file now looks like this:
package gravityPackage
//Test of gravity taken from Intro to Physical modeling with Modelica
//
//
//
//
//
model ParticleField
inner function gravity = TwoBodyField;
Particle p1(x_init = {2,-2,0}, v_init = {0.7,0,0});
Particle p2(x_init = {0,0.5,0}, v_init = {-1,-1,0});
Particle p3(x_init = {0.5,2,0}, v_init = {-1,-0.5,0});
end ParticleField;
function TwoBodyField
extends GravityField;
protected
Modelica.SIunits.Position b1[3],b2[3];
Modelica.SIunits.Velocity n1[3],n2[3];
algorithm
b1:={0,0,0};
b2:={0,1,0};
n1:=-(x - b1) / sqrt((x - b1) * (x - b1));
n2:=-(x - b2) / sqrt((x - b2) * (x - b2));
g:=n1 / ((x - b1) * (x - b1)) + n2 / ((x - b2) * (x - b2));
end TwoBodyField;
partial function GravityField
input Modelica.SIunits.Position x[3];
output Modelica.SIunits.Acceleration g[3];
end GravityField;
model Particle
parameter Modelica.SIunits.Position x_init[3];
parameter Modelica.SIunits.Velocity v_init[3];
protected
outer function gravity = GravityField;
//outer function gravity=ParticleField;
//outer function gravity=TwoBodyField;
Modelica.SIunits.Position x[3](start = x_init);
Modelica.SIunits.Velocity v[3](start = v_init);
Modelica.SIunits.Acceleration a[3];
equation
v = der(x);
a = der(v);
a = gravity(x);
end Particle;
end gravityPackage;
But, if I go to OMShell and try to run it, I get this:
>> loadFile("gravityPackage.mo")
true
>> simulate(gravityPackage.ParticleField)
record SimulationResult
resultFile = "",
simulationOptions = "startTime = 0.0, stopTime = 1.0, numberOfIntervals = 500, tolerance = 0.000001, method = 'dassl', fileNamePrefix = 'gravityPackage.ParticleField', options = '', outputFormat = 'mat', variableFilter = '.*', measureTime = false, cflags = '', simflags = ''",
messages = "Simulation failed for model: gravityPackage.ParticleField
[gravityPackage.mo:34:11-34:42:writable] Warning: No corresponding 'inner' declaration found for class gravity declared as 'outer '.
Continuing flattening by only considering the 'outer' class declaration.
[gravityPackage.mo:43:5-43:19:writable] Error: Failed to instantiate equation
a = gravity(x);.
Error: Error occurred while flattening model gravityPackage.ParticleField
",
timeFrontend = 0.0,
timeBackend = 0.0,
timeSimCode = 0.0,
timeTemplates = 0.0,
timeCompile = 0.0,
timeSimulation = 0.0,
timeTotal = 0.0
end SimulationResult;
>>
So, clearly there is something related to scope that I am not getting correct. All the code, except for the package, is just copied directly from the book. I believe that the package is necessary to get it into a single file (although I tried a few other ways to do that with no success).
Any suggestions are appreciated.
Thanks,
This is a bug in OpenModelica.
It should work fine if is a inner component or class but not for functions.
I added a bug report about it and we will fix it:
https://trac.openmodelica.org/OpenModelica/ticket/2467
For now you can use an inner/outer package, that should work fine.
package gravityPackage
package Functions
function TwoBodyField
extends GravityField;
protected
Modelica.SIunits.Position b1[3],b2[3];
Modelica.SIunits.Velocity n1[3],n2[3];
algorithm
b1:={0,0,0};
b2:={0,1,0};
n1:=-(x - b1) / sqrt((x - b1) * (x - b1));
n2:=-(x - b2) / sqrt((x - b2) * (x - b2));
g:=n1 / ((x - b1) * (x - b1)) + n2 / ((x - b2) * (x - b2));
end TwoBodyField;
partial function GravityField
input Modelica.SIunits.Position x[3];
output Modelica.SIunits.Acceleration g[3];
end GravityField;
end Functions;
model ParticleField
inner package funcs = Functions;
Particle p1(x_init = {2,-2,0}, v_init = {0.7,0,0});
Particle p2(x_init = {0,0.5,0}, v_init = {-1,-1,0});
Particle p3(x_init = {0.5,2,0}, v_init = {-1,-0.5,0});
end ParticleField;
model Particle
parameter Modelica.SIunits.Position x_init[3];
parameter Modelica.SIunits.Velocity v_init[3];
protected
outer package funcs = Functions;
function gravity = funcs.TwoBodyField;
//outer function gravity=ParticleField;
//outer function gravity=TwoBodyField;
Modelica.SIunits.Position x[3](start = x_init);
Modelica.SIunits.Velocity v[3](start = v_init);
Modelica.SIunits.Acceleration a[3];
equation
v = der(x);
a = der(v);
a = gravity(x);
end Particle;
end gravityPackage;
OK, so I think the issue here is that you are trying to "pass" a function up the instance tree using dynamic scoping (i.e. inner and outer). I haven't read the specification on this particular point, but I don't think this will work. The reason is that normally inner and outer are used in conjunction with things that are instantiated (variables, models, etc).
So the thing to understand is that conceptually both constant variables and function definitions are not instantiated. Being able to treat a function as an instance (a first-class value) has several useful consequences but it also introduces some semantic complications. There has been work done in recent versions of the language toward trying to treat functions as first class citizens. The main use case was to pass functions as arguments to other functions. But I think these new semantics stop short of making functions truly first class values (as your example would demonstrate). However, this may be in issue with OpenModelica. I can't say definitively.
One way you could deal with this would be to use replaceable and redeclare. So in your Particle model, define gravity like this:
public
replaceable function gravity = GravityField;
Then, instantiate it as follows:
model ParticleField
Particle p1(x_init = {2,-2,0}, v_init = {0.7,0,0}, redeclare function gravity = TwoBodyField);
Particle p2(x_init = {0,0.5,0}, v_init = {-1,-1,0}, redeclare function gravity = TwoBodyField);
Particle p3(x_init = {0.5,2,0}, v_init = {-1,-0.5,0}, redeclare function gravity = TwoBodyField);
end ParticleField;
Note, I haven't tested this solution. For example, your Particle model might require the partial qualifier (since you would have to override gravity to a non-partial implementation).
I hope that helps.