Mixture gas in modelica - modelica

I use OpenModelica and I have some model gas mixture
package ExhaustGas
import Modelica.Media.IdealGases.Common;
extends Modelica.Media.IdealGases.Common.MixtureGasNasa(mediumName = "ExhaustGas", data = {Common.SingleGasesData.O2, Common.SingleGasesData.CO2, Common.SingleGasesData.H2O, Common.SingleGasesData.N2, Common.SingleGasesData.Ar, Common.SingleGasesData.SO2}, fluidConstants = {Common.FluidData.O2, Common.FluidData.CO2, Common.FluidData.H2O, Common.FluidData.N2, Common.FluidData.Ar, Common.FluidData.SO2}, substanceNames = {"Oxygen", "Carbondioxide", "Water", "Nitrogen", "Argon", "Sulfurdioxide"}, reference_X = {0.1383, 0.032, 0.0688, 1 - 0.1383 - 0.032 - 0.0688 - 0.0000000001 - 0.0000000001, 0.0000000001, 0.0000000001});
end ExhaustGas;
I run the code:
algorithm
for i in 1:6 loop
etaX[i] := ExhaustGas.fluidConstants[i].criticalTemperature;
end for;
and I get
{154.58, 154.58, 154.58, 154.58, 154.58, 154.58}
That is, only oxygen values are written to the array.
The same loop is used in the function Modelica.Media.IdealGases.Common.MixtureGasNasa.dynamicViscosity.
Can this function be considered to work correctly? What am I doing wrong?

I could not see any similar issue in Dymola (used Dymola 2018 for no obvious reason), so that seems like an issue in OpenModelica.
To get the example to run I used:
model ExhaustGas
import Modelica.Media.IdealGases.Common;
package P=Modelica.Media.IdealGases.Common.MixtureGasNasa (
mediumName="ExhaustGas",
data={Common.SingleGasesData.O2,Common.SingleGasesData.CO2,Common.SingleGasesData.H2O,
Common.SingleGasesData.N2,Common.SingleGasesData.Ar,Common.SingleGasesData.SO2},
fluidConstants={Common.FluidData.O2,Common.FluidData.CO2,Common.FluidData.H2O,
Common.FluidData.N2,Common.FluidData.Ar,Common.FluidData.SO2},
substanceNames={"Oxygen","Carbondioxide","Water","Nitrogen","Argon","Sulfurdioxide"},
reference_X={0.1383,0.032,0.0688,1 - 0.1383 - 0.032 - 0.0688 - 0.0000000001 -
0.0000000001,0.0000000001,0.0000000001});
Real etaX[6];
algorithm
for i in 1:6 loop
etaX[i] = P.fluidConstants[i].criticalTemperature;
end for;
end ExhaustGas;
Since a model inheriting from a package isn't legal. I noticed two warnings for the normalBoilingPoint being out of range.
Changed: I changed it to use algorithm instead of equation, it doesn't make a difference in Dymola, and I don't see any reason why it should matter.

Related

Is it possible to use callbacks to access a single trajectory in Julia's DifferentialEquations Ensemble Problems?

I am new to Julia and trying to use the Julia package DifferentialEquations to simultaneously solve for several conditions of the same set of coupled ODEs. My system is a model of an experiment and in one of the conditions, I increase the amount of one of the dependent variables at mid-way through the process.
I would like to be able to adjust the condition of this single trajectory, however so far I am only able to adjust all the trajectories at once. Is it possible to access a single one using callbacks? If not, is there a better way to do this?
Here is a simplified example using the lorentz equations for what I want to be doing:
#Differential Equations setup
function lorentz!(du,u,p,t)
a,r,b=p
du[1]= a*(u[2]-u[1])
du[2]=u[1]*(r-u[3])-u[2]
du[3]=u[1]*u[2]-b*u[3];
end
#function to cycle through inital conditions
function prob_func(prob,i,repeat)
remake(prob; u0 = u0_arr[i]);
end
#inputs
t_span=[(0.0,100.0),(0.0,100.0)];
u01=[0.0;1.0;0.0];
u02=[0.0;1.0;0.0];
u0_arr = [u01,u02];
p=[10.,28.,8/3];
#initialising the Ensemble Problem
prob = ODEProblem(lorentz!,u0_arr[1],t_span[1],p);
CombinedProblem = EnsembleProblem(prob,
prob_func = prob_func, #-> (prob),#repeat is a count for how many times the trajectories had been repeated
safetycopy = true # determines whether a safetly deepcopy is called on the prob before the prob_func (sounds best to leave as true for user-given prob_func)
);
#introducing callback
function condition(u,t,repeat)
return 50 .-t
end
function affect!(repeat)
repeat.u[1]=repeat.u[1] +50
end
callback = DifferentialEquations.ContinuousCallback(condition, affect!)
#solving
sim=solve(CombinedProblem,Rosenbrock23(),EnsembleSerial(),trajectories=2,callback=callback);
# Plotting for ease of understanding example
plot(sim[1].t,sim[1][1,:])
plot!(sim[2].t,sim[2][1,:])
I want to produce something like this:
Example_desired_outcome
But this code produces:
Example_current_outcome
Thank you for your help!
You can make that callback dependent on a parameter and make the parameter different between problems. For example:
function f(du,u,p,t)
if p == 0
du[1] = 2u[1]
else
du[1] = -2u[1]
end
du[2] = -u[2]
end
condition(t,u,integrator) = u[2] - 0.5
affect!(integrator) = integrator.prob.p = 1
For more information, check out the FAQ on this topic: https://diffeq.sciml.ai/stable/basics/faq/#Switching-ODE-functions-in-the-middle-of-integration

Please help debug my call scipy library for Kolmogorov-Smirnov Test

I am completing an assignment but can not get the right results from a kolmogorov smirnov test for a small sample of observations against a 'norm' distribution.
I have setup a minimal sample in a jupyter notebook with expected kstest results and tried running this in several environment and reviewed the call for hours. Answer key says my ks_value and p_value are wildly wrong.
But, I cannot see my error.
the sample I have is from the test run in the answer key. it is a 1d array, a valid input option.
sample mean and standard deviation I compute look right
if I change ddof it makes a small difference (hint is to use ddof=0)
norm is a valid distribution for the kstest
library documentation is at
https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.stats.kstest.html#scipy-stats-kstest
Any ideas or comments?
Would you expect a sample = [0.37, 0.27, 0.69, 0.56, 0.26] compared to a normal distribution to have
'KS test statistic' of 0.64 or 0.24
and
'p-value' of 0.02 or 0.94
TIA
import pandas as pd
import numpy as np
from scipy.stats import kstest
sample = [0.37, 0.27, 0.69, 0.56, 0.26]
normal_args = (np.mean(sample), np.std(sample, ddof=0))
print('mean', normal_args[0])
print('std', normal_args[1])
ks_value, p_value = kstest(sample, 'norm', normal_args )
print('ks_value', ks_value)
print('p_value', p_value)
print('')
print('#####posted solution')
print('expected ks_value = 0.63919407')
print('expected p_value = 0.01650327')
mean 0.43000000000000005
std 0.1688786546606764
ks_value 0.23881183701141995
p_value 0.9379686201081335
####posted solution
expected ks_value = 0.63919407
expected p_value = 0.01650327
My bad. A new guy mistake.
The function calls defines the 3rd argument as "args=()". I had put the 3rd argument in treating the input as a positional. Changing the call to
ks_value, p_value = kstest(sample, 'norm', args=(normal_args) )
yields the correct response.

What is the purpose of the StateSet variables seen in OpenModelica's result variable browser

When I simulate the model below, I get additional variables labelled $STATESET1, which are obviously auto-generated.
What is the purpose of these variables from the perspective of the user? Generally I am only interested in the solution, not in the specific strategies a specific solver achieved it with, right? So isn't this more like something that should be output only if one turns on model debugging of some kind rather than being something the average OpenModelica user can take advantage of? What if there is more than one "state set" (say $STATESET1 and $STATESET2): how am I supposed to know how these variables relate to my model, given their generic names? More specifically, what is $STATESET1.x[:]? Nothing in the original or flattened model gives a hint on this...
model StateSetTest
import SI = Modelica.SIunits;
Real[3] q(start = zeros(3), each fixed = true);
Real q4(start = 1);
Real[3] w(start = zeros(3), each fixed = true);
SI.Torque[3] TResult;
equation
q * q + q4 * q4 = 1;
w = 2.0 * (q4 * der(q) - der(q4) * q - cross(der(q), q));
der(w) = TResult;
TResult = zeros(3);
end StateSetTest;
They are used for dynamic state selection, i.e. changing the state during the simulation. And yes, they are not really needed for the user. I guess we could filter them out from OMEdit. I'll open a ticket about this.

Start values as results of previous simulation

Is it possible to use the result of a simulation Sim 1 at time t as start value of simulation Sim 2? The use of extend doesn't work for start values.
Example:
model Sim 1
Real a;
equation
a=2*time;
end Sim 1;
for model Sim 2, I need
Real b (start=a at time t)
to use in several other set of equations.
You have to differ between the modeling and the simulation process:
With the language Modelica you define your models
With the simulation tool (like Dymola) you perform the simulation.
The keyword extends is part of the Modelica language. So it cannot be of any use in this context, as you use it to define models, not to describe how a simulation should be performed.
The solution for your problem must be searched in the simulation tool and Dymola offers a simulator function, which does exactly what you want: simulateExtendedModel. It allows to read the final value of a variable and you can initialize parameters and state variables with it. You can use it in a .mos script or within a Modelica function.
So if we rename your models Sim1 and Sim2 to Model1 and Model2 (because they are really models, not simulations) the function below would do what you want:
function sim
import DymolaCommands.SimulatorAPI.simulateExtendedModel;
protected
Boolean ok;
Real a;
Real[1] finalValues;
algorithm
(ok, finalValues) :=simulateExtendedModel("Model1", 0, 5, finalNames={"a"});
a :=finalValues[1];
simulateExtendedModel("Model2", 5, 10, initialNames={"b"}, initialValues={a});
end sim;
If you want to set multiple variables, you can use this code:
function sim2
import DymolaCommands.SimulatorAPI.simulateExtendedModel;
protected
Boolean ok;
Real[:] finalValues_sim1;
String[:] finalNames_sim1 = {"a1", "a2", "a3"};
String[:] initialNames_sim2 = {"b1", "b2", "b3"};
algorithm
(ok, finalValues_sim1) :=simulateExtendedModel("SO.Model1", 0, 5, finalNames=finalNames_sim1);
simulateExtendedModel("SO.Model2", 5, 10, initialNames=initialNames_sim2, initialValues=finalValues_sim1);
end sim2;

limit random complex number to a given range

I can get the real part of a random number to stay withing a given range but the complex part of the number doesn't stay within the range I set. see matlab / octave code below.
xmin=-.5
xmax=1
n=3
x=xmin+rand(1,n)*(xmax-xmin)+(rand(1,n)-(xmax-xmin))*1i
x=x(:)
The real part works but the complex part isn't limited to -0.5 to 1
0.2419028288441536 - 0.6579427654754871i
0.2712527227134944 - 1.451964497492678i
0.3245051849394858 - 1.107556052779179i
You have two mistakes:
x=xmin+rand(1,n)*(xmax-xmin)+(xmin + rand(1,n)*(xmax-xmin))*1i
You should add xmin to the sum and change - to * in the second part.
I've added some spaces to your code so the difference more obvious:
x = xmin+rand(1,n)*(xmax-xmin) + ( rand(1,n)-(xmax-xmin) )*1i
^^^ correct ^^^ not correct: missing `xmin+`
(and as OmG noted, also a `-` instead of a `*`)
One good way to reduce the number of bugs is by avoiding code duplication. You could for example write:
rand_sequence = #(m,xmin,xmax) xmin+rand(1,n)*(xmax-xmin);
x = rand_sequence(n,xmin,xmax) + 1i*rand_sequence(n,xmin,xmax)
(This looks like more code, but the more complicated code logic is not duplicated.)
Or like this:
x = xmin + (rand(1,n)+1i*rand(1,n)) * (xmax-xmin);