how to declare floating numbers as being float128 with numba - numba

I am concerned about numerical error n my simulation and want numba to use float128 variables. When I specify nb.jit('f8()') on func_nb, I tell numba that the function takes no arguments and returns a float128 number, right? How can I tell numba to make all the floating point numbers float128?
#nb.jit()
def f_big_nb(A, k, std_A, std_k, mean_A=10, mean_k=0.2, hh=100):
return ( 1 / (std_A * std_k * 2 * np.pi) ) * A * (hh/50) ** k * np.exp( -1*(k - mean_k)**2 / (2 * std_k **2 ) - (A - mean_A)**2 / (2 * std_A**2))
#nb.jit('f8()')
def func_nb():
outer_sum = 0
dk = 0.01 #0.000001
X = np.arange(dk, 0.4, dk)
Y = np.arange(dk, 20, dk)
for i in xrange(X.shape[0]):
k = X[i] # faster to do lookup than iterate over an array directly
inner_sum = 0
for j in xrange(Y.shape[0]):
A = Y[j]
inner_sum += dk * f_big_nb(A, k, 1e-5, 1e-5)
outer_sum += inner_sum * dk
return outer_sum

Related

Extract intermediate parameter values from an ODE function?

I want to get extract intermediate parameter values from below ODE function. Can someone figure out how to extract those values from the ode solver.
I want to get values of "a, b,s,& w" apart from the main outputs of the ode solver. I tried to modify return option in the function, but that doesn't work.
Be kind to explain by providing sample codes as I am bit new to python.
from scipy.integrate import odeint
import numpy as np
import matplotlib.pyplot as plt
# parameters
S = 0.0001
M = 30.03
K = 113.6561
Vr = 58
R = 8.3145
T = 298.15
Q = 0.000133
Vp = 0.000022
Mr = 36
Pvap = 1400
wf = 0.001
tr = 1200
mass = 40000
# define t
time = 14400
t = np.arange(0, time + 1, 1)
# define initial state
Cv0 = (mass / Vp) * wf # Cv(0)
Cr0 = (mass / Vp) * (1 - wf)
Cair0 = 0 # Cair(0)
# define function and solve ode
def model(x, t):
C = x[0] # C is Cair(t)
c = x[1] # c is Cv(t)
a = Q + (K * S / Vr)
b = (K * S * M) / (Vr * R * T)
s = (K * S * M) / (Vp * R * T)
w = (1 - wf) * 1000
Peq = (c * Pvap) / (c + w * c * M / Mr)
Pair = (C * R * T) / M
dcdt = -s * (Peq - Pair)
if t <= tr:
dCdt = -a * C + b * Peq
else:
dCdt = -a * C
return [dCdt, dcdt]
x = odeint(model, [Cair0, Cv0], t)
C = x[:, 0]
c = x[:, 1]

How to compute the derivatives automatically within for-loop in Matlab?

For the purpose of generalization, I hope Matlab can automatically compute the 1st & 2nd derivatives of the associated function f(x). (in case I change f(x) = sin(6x) to f(x) = sin(8x))
I know there exists built-in commands called diff() and syms, but I cannot figure out how to deal with them with the index i in the for-loop. This is the key problem I am struggling with.
How do I make changes to the following set of codes? I am using MATLAB R2019b.
n = 10;
h = (2.0 * pi) / (n - 1);
for i = 1 : n
x(i) = 0.0 + (i - 1) * h;
f(i) = sin(6 * x(i));
dfe(i) = 6 * cos(6 * x(i)); % first derivative
ddfe(i) = -36 * sin(6 * x(i)); % second derivative
end
You can simply use subs and double to do that. For your case:
% x is given here
n = 10;
h = (2.0 * pi) / (n - 1);
syms 'y';
g = sin(6 * y);
for i = 1 : n
x(i) = 0.0 + (i - 1) * h;
f(i) = double(subs(g,y,x(i)));
dfe(i) = double(subs(diff(g),y,x(i))); % first derivative
ddfe(i) = double(subs(diff(g,2),y,x(i))); % second derivative
end
By #Daivd comment, you can vectorize the loop as well:
% x is given here
n = 10;
h = (2.0 * pi) / (n - 1);
syms 'y';
g = sin(6 * y);
x = 0.0 + ((1:n) - 1) * h;
f = double(subs(g,y,x));
dfe = double(subs(diff(g),y,x)); % first derivative
ddfe = double(subs(diff(g,2),y,x)); % second derivative

matrix singular under determined linear system not solvable

Following this question, I modified my code to:
model test
// types
type Mass = Real(unit = "Kg", min = 0);
type Length = Real(unit = "m");
type Area = Real(unit = "m2", min = 0);
type Force = Real(unit = "Kg.m/s2");
type Pressure = Real(unit = "Kg/m/s2");
type Torque = Real(unit = "Kg.m2/s2");
type Velocity = Real(unit = "m/s");
type Time = Real(unit = "s");
// constants
constant Real pi = 2 * Modelica.Math.asin(1.0);
parameter Mass Mp = 0.01;
parameter Length r1 = 0.010;
parameter Length r3 = 0.004;
parameter Integer n = 3;
parameter Area A = 0.020 * 0.015;
parameter Time Stepping = 1.0;
parameter Real DutyCycle = 1.0;
parameter Pressure Pin = 500000;
parameter Real Js = 1;
//parameter Real Muk = 0.0;
parameter Real Muk = 0.158;
// variables
Length x[n];
Velocity vx[n];
Real theta;
Real vt;
Pressure P[n];
Force Fnsp[n];
Torque Tfsc;
initial equation
theta = 0;
vt = 0;
algorithm
for i in 1:n loop
if noEvent((i - 1) * Stepping < mod(time, n * Stepping)) and noEvent(mod(time, n * Stepping) < Stepping * ((i - 1) + DutyCycle)) then
P[i] := Pin;
else
P[i] := 0;
end if;
end for;
Tfsc := -r3 * Muk * sign(vt) * abs(sum(Fnsp));
equation
vx = der(x);
vt = der(theta);
x = r1 * {sin(theta + (i - 1) * 2 * pi / n) for i in 1:n};
Mp * der(vx) + P * A = Fnsp;
Js * der(theta) = Tfsc - r1 * Fnsp * {cos(theta + (i - 1) * 2 * pi / n) for i in 1:n};
// Js * der(theta) = - r1 * Fnsp * {cos(theta + (i - 1) * 2 * pi / n) for i in 1:n};
annotation(
experiment(StartTime = 0, StopTime = 30, Tolerance = 1e-06, Interval = 0.03),
__OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "dassl"));
end test;
However, I get the preprocessing warning of
[1] .... Translation Warning
Iteration variables with default zero start attribute in torn nonlinear equation system:
Fnsp[3]:VARIABLE(unit = "Kg.m/s2" ) type: Real [3]
Fnsp[2]:VARIABLE(unit = "Kg.m/s2" ) type: Real [3]
Fnsp[1]:VARIABLE(unit = "Kg.m/s2" ) type: Real [3]
$DER.vt:VARIABLE() type: Real
which doesn't make sense but I assume I can safely ignore, and the compiling error of:
Matrix singular!
under-determined linear system not solvable
which had also been previously reported here. if I remove the lines
Torque Tfsc;
and
Tfsc := -r3 * Muk * sign(vt) * abs(sum(Fnsp));
and changing
Js * der(theta) = - r1 * Fnsp * {cos(theta + (i - 1) * 2 * pi / n) for i in 1:n};
works perfectly fine. However, setting Muk to zero, which theoretically the same thing leads to the same error as above! I would appreciate if you could help me know what is the problem and how I can resolve it.
P.S.1. On the demo version of Dymola the simulation test finishes with no errors, only the warning:
Some variables are iteration variables of the initialization problem:
but they are not given any explicit start values. Zero will be used.
Iteration variables:
der(theta, 2)
P[1]
P[2]
P[3]
P.S.2. Using JModelica, removing the noEvent and using the python code:
model_name = 'test'
mo_file = 'test.mo'
from pymodelica import compile_fmu
from pyfmi import load_fmu
my_fmu = compile_fmu(model_name, mo_file)
myModel = load_fmu('test.fmu')
res = myModel.simulate(final_time=30)
theta = res['theta']
t = res['time']
import matplotlib.pyplot as plt
plt.plot(t, theta)
plt.show()
it solves the model blazingly fast for small values (e.g. 0.1) of Muk. But again it gets stuck for bigger values. The only warnings are:
Warning at line 30, column 3, in file 'test.mo':
Iteration variable "Fnsp[2]" is missing start value!
Warning at line 30, column 3, in file 'test.mo':
Iteration variable "Fnsp[3]" is missing start value!
Warning in flattened model:
Iteration variable "der(_der_theta)" is missing start value!
You do not need to use algorithm for the assignments of equations (even if they are in a for-loop and an if). I moved them to the equation section and removed your algorithm section completely:
model test
// types
type Mass = Real(unit = "Kg", min = 0);
type Length = Real(unit = "m");
type Area = Real(unit = "m2", min = 0);
type Force = Real(unit = "Kg.m/s2");
type Pressure = Real(unit = "Kg/m/s2");
type Torque = Real(unit = "Kg.m2/s2");
type Velocity = Real(unit = "m/s");
type Time = Real(unit = "s");
// constants
constant Real pi = 2 * Modelica.Math.asin(1.0);
parameter Mass Mp = 0.01;
parameter Length r1 = 0.010;
parameter Length r3 = 0.004;
parameter Integer n = 3;
parameter Area A = 0.020 * 0.015;
parameter Time Stepping = 1.0;
parameter Real DutyCycle = 1.0;
parameter Pressure Pin = 500000;
parameter Real Js = 1;
//parameter Real Muk = 0.0;
parameter Real Muk = 0.158;
// variables
Length x[n];
Velocity vx[n];
Real theta;
Real vt;
Pressure P[n];
Force Fnsp[n];
Torque Tfsc;
initial equation
theta = 0;
vt = 0;
equation
for i in 1:n loop
if noEvent((i - 1) * Stepping < mod(time, n * Stepping)) and noEvent(mod(time, n * Stepping) < Stepping * ((i - 1) + DutyCycle)) then
P[i] = Pin;
else
P[i] = 0;
end if;
end for;
Tfsc = -r3 * Muk * sign(vt) * abs(sum(Fnsp));
vx = der(x);
vt = der(theta);
x = r1 * {sin(theta + (i - 1) * 2 * pi / n) for i in 1:n};
Mp * der(vx) + P * A = Fnsp;
Js * der(theta) = Tfsc - r1 * Fnsp * {cos(theta + (i - 1) * 2 * pi / n) for i in 1:n};
// Js * der(theta) = - r1 * Fnsp * {cos(theta + (i - 1) * 2 * pi / n) for i in 1:n};
end test;
This makes it far easier for the compiler to find a sensible sorting and tearing for the strong components. This still breaks at 19s but before that it may just be what you are looking for. The newton solver diverges after that threshold, since i don't really know what you are doing here i unfortunately cannot provide any analysis of the results.
Also it seems like your event triggered by your if-equation could be cleanly replaced by a Sample operator. You might want to have a look at that.

Matlab - Plotting with for loop

I am new to matlab and am trying to loop through an equation from 1 to 1000 and plot the result, but every value is turning out the same and the plot is incrorrect.
Here is my current attempt, but the variable Rm is giving only one results (instead of 1000 separate ones):
Ds = 1.04e-10;
Gamma = 1.9;
Omega = 1.09e-29;
Deltas = 2.5e-10;
Boltzmann = 1.3806e-23;
T = 1123.15;
Beta = 0.83;
Zo = 6.7;
EtaNi = 0.39;
EtaYSZ = 0.61;
Rm0 = 0.29;
RmYSZ0 = 0.265;
lambda = 4.70e-3;
C = Ds * ((Gamma * Omega * Deltas) / (2 * Boltzmann * T)) * (Beta / ((1 - Beta^2) * ((1 + Beta^2)^0.5) * ((1 + Beta)^3))) * Zo * (EtaNi/((EtaNi/Rm0) + (EtaYSZ/RmYSZ0)));
tinit=1; % Initial time value (h)
tend=1000; % End time value (h)
tinc=1; % Increment in time value (h)
t= [tinit:tinc:tend]; % Time vector
n = 1000;
for i=1:n
Rm(i) = (((5*C)/lambda) * (1 - exp(-lambda*i)) + (Rm0)^5)^(1/5);
end
plot(t,Rm);
Expected result is an exponential curve, any help would be appreciated
Your term before R0 is an exponential that ranges from 0 to 4.5e-27. R0^5 is 0.0021. Floating point precision is not enough to preserve the first term when it is added to the second. So (5C/L*(...) + Rm0^5) == Rm0^5, so it is constant.

Solution of transcendental equation in with Matlab

I have an equation which goes like this:
Here, I_L(lambdap) is the modified bessel function. This and product with exponential function can be written in matlab as besseli(L,lambdap,1). "i" stands for square root of -1. I want to solve:
1+pt+it=0
where I have to vary 'k' and find values of 'w'. I had posted similar problem at mathematica stack exchange, but I couldn't solve the problem fully, though i have got a clue (please go through the comments at mathematica stack exchange site). I could not convert my equation to the code that has been posted in clue. Any help in this regards will be highly appreciated.
Thanks in advance...
I never attempted this before, but... is this returning a suitable result?
syms w k;
fun = 1 + pt(w,k) + it(w,k);
sol = vpasolve(fun == 0,w,k);
disp(sol.w);
disp(sol.k);
function res = pt(w,k)
eps_l0 = w / (1.22 * k);
lam_k = 0.25 * k^2;
res = sym('res',[5 1]);
res_off = 1;
for L = -2:2
gam = besseli(L,lam_k) * exp(-lam_k);
eps_z = (w - L) / (1.22 * k);
zeta = 1i * sqrt(pi()) * exp(-eps_z^2) * (1 + erfc(1i * eps_z));
res(res_off,:) = ((25000 * gam) / k^2) * (1 + (eps_l0 * zeta));
res_off = res_off + 1;
end
res = sum(res);
end
function res = it(w,k)
eps_l0 = (w - (0.86 * k)) / (3.46 * k);
lam_k = 0.03 * k^2;
res = sym('res',[5 1]);
res_off = 1;
for L = -2:2
gam = besseli(L,lam_k) * exp(-lam_k);
eps_z = (w - (8 * L) - (0.86 * k)) / (3.46 * k);
zeta = 1i * sqrt(pi()) * exp(-eps_z^2) * (1 + erfc(1i * eps_z));
res(res_off,:) = ((2000000 * gam) / k^2) * (1 + (eps_l0 * zeta));
res_off = res_off + 1;
end
res = sum(res);
end
EDIT
For numeric k and symbolic w:
syms w;
for k = -3:3
fun = 1 + pt(w,k) + it(w,k);
sol = vpasolve(fun == 0,w);
disp(sol.w);
end