Maple. Dsolve and functions - maple

I have a differential equation that my program solves:
p := dsolve({ic, sys}, numeric, method = rosenbrock);
After solving we have the following:
print(p(10));
[t = 10., alpha(t) = HFloat(0.031724302221312055), beta(t) = HFloat(0.00223975915581258)]
I need use this alpha(t) and beta(t) as follows:
a := t->exp( int(alpha(t)),x=0..t) );
b := t->exp( int(beta(t)),x=0..t) )
And draw a plot:
odeplot(p, [[t, a(t)], [t, b(t)]], 0 .. 20, thickness = 2, numpoints = 500, color = [red, blue])
The first thing that occurred to do so:
p := dsolve({sys, ic}, numeric, method=rosenbrock);
alpha := t->rhs(p(t)[2] );
beta := t->rhs(p(t)[3;
a := t->exp( int(alphat)),x=0..t) );
b := t->exp( int(betat)),x=0..t) );
odeplot(p, [[t, a(t)], [t, b(t)]], 0 .. 20, thickness = 2, numpoints = 500, color = [red, blue])
But the code does not work, and Yes, obviously, should act differently.

First, let's try to get your approach to work, with a few syntax and usage changes.
You didn't supply the example's details, so I make up a system of differential equations sys and initial conditions ic so that your computational commands can be performed.
restart:
sys := diff(alpha(t),t) = -1/200*beta(t),
diff(beta(t),t) = -1/200*alpha(t) - 1/Pi^2:
ic := alpha(0)=0, beta(0)=-1:
p := dsolve({ic, sys}, numeric, method = rosenbrock, output=listprocedure):
alphat := eval(alpha(t),p):
betat := eval(beta(t),p):
a := unapply( exp( Int(alphat , 0..t) ), t, numeric):
b := unapply( exp( Int(betat , 0..t) ), t, numeric):
evalf(a(20.0)), evalf(b(20.0));
-18
5.347592595, 3.102016550 10
st := time():
P := plots:-odeplot(p, [[t, a(t)], [t, b(t)]], 0 .. 20,
thickness = 2, numpoints = 50, color = [red, blue]):
( time() - st )*`seconds`;
16.770 seconds
P;
I used output=listprocedure so that I could assign the right procedures from solution p to alphat and betat. Those are more efficient to call many times, as opposed to your original which formed a sequence of values for each numeric t value and then had to pick off a certain operand. It's also more robust since its not sensitive to positions (which could change due to a new lexicographic ordering if you altered the names of your variables).
The above took about 16 seconds on an Intel i7. That's not fast. One reason is that the numeric integrals are being computed to higher accuracy than is necessary for the plotting. So let's restart (to ensure fair timing) and recompute with relaxed tolerances on the numeric integrations done for a and b.
restart:
sys := diff(alpha(t),t) = -1/200*beta(t),
diff(beta(t),t) = -1/200*alpha(t) - 1/Pi^2:
ic := alpha(0)=0, beta(0)=-1:
p := dsolve({ic, sys}, numeric, method = rosenbrock, output=listprocedure):
alphat := eval(alpha(t),p):
betat := eval(beta(t),p):
a := unapply( exp( Int(alphat , 0..t, epsilon=1e-5) ), t, numeric):
b := unapply( exp( Int(betat , 0..t, epsilon=1e-5) ), t, numeric):
evalf(a(20.0)), evalf(b(20.0));
-18
5.347592681, 3.102018090 10
st := time():
P := plots:-odeplot(p, [[t, a(t)], [t, b(t)]], 0 .. 20,
thickness = 2, numpoints = 50, color = [red, blue]):
( time() - st )*`seconds`;
0.921 seconds
You can check that this gives a plot that appears the same.
Now lets augment the example so that the numeric integrals are computed by dsolve,numeric itself. We can do that by using Calculus. In this way we are leaving it to the numeric ode solver to do its own error estimation, stepsize control, stiffness or singularity detection, etc.
Note that the integrands alphat and betat are not functions for which we have explicit functions -- their accuracy is intimately tied to the numerical ode solving. This is not quite the same as simplistically using a numerical ode routine to replace a numeric quadrature routine for a problem with an integrand which we expect to be computed directly to any desired accuracy (including on either side of any singularity).
restart:
sys := diff(alpha(t),t) = -1/200*beta(t),
diff(beta(t),t) = -1/200*alpha(t) - 1/Pi^2,
diff(g(t),t) = alpha(t), diff(h(t),t) = beta(t):
ic := alpha(0)=0, beta(0)=-1,
g(0)=0, h(0)=0:
p := dsolve({ic, sys}, numeric, method = rosenbrock, output=listprocedure):
alphat := eval(alpha(t),p):
betat := eval(beta(t),p):
gt := eval(g(t),p):
ht := eval(h(t),p):
exp(gt(20.0)), exp(ht(20.0));
-18
5.34759070530497, 3.10201330730572 10
st := time():
P := plots:-odeplot(p, [[t, exp(g(t))], [t, exp(h(t))]], 0 .. 20,
thickness = 2, numpoints = 50, color = [red, blue]):
( time() - st )*`seconds`;
0.031 seconds
P;

Related

Maple procedure and function

I don't understand how to use a mathematical function in a maple procedure.
For example in this procedure I try to compute the arc length of a function :
proc(f,a,b);
local f,a,b;
L=int(sqrt(1+f'(x)^2),x=a..b);
end proc;
But is doesn't work.
It is my first question here if there is a problem
Firstly, the syntax f'(x) is only valid in Maple's marked up 2S Math, not in plaintext Maple code. So it does not make sense to show us that syntax as code on this site.
Moving on, and using only 1D plaintext code (which makes sense for this site and is, in my opinion, a better choice for learning Maple), you need to understand the difference between procedures and expresssions.
An expressiom and differentiating it:
Fexpr := x^2 + sin(x);
2
Fexpr := x + sin(x)
diff(Fexpr, x);
2 x + cos(x)
An operator, and differentiating it (and applying it, or applying it after differentiating):
F := t -> t^2 + sin(t);
F := t -> t^2 + sin(t)
D(F);
t -> 2*t + cos(t)
D(F)(x);
2 x + cos(x)
F(x);
2
x + sin(x)
diff(F(x), x);
2 x + cos(x)
Here are some examples:
Your task, done with argument f as an expression, and supplying the variable name as an argument:
restart;
myproc := proc(fexpr,a,b,var)
local L;
L:=int(sqrt(1+diff(fexpr,var)^2),var=a..b);
end proc:
myproc(sin(x), 0, Pi, x);
myproc(sin(x), 0.0, evalf(Pi), x);
myproc(sin(t), 0.0, evalf(Pi), t);
myproc(t^2, 0, Pi, t);
A modification of the above, where it figures out the variable name from the expression passed as argument:
restart;
myproc := proc(fexpr,a,b)
local deps,L,x;
deps := indets(fexpr,
And(name,Not(constant),
satisfies(u->depends(fexpr,u))));
x := deps[1];
L:=int(sqrt(1+diff(fexpr,x)^2),x=a..b);
end proc:
myproc(sin(x), 0, Pi);
myproc(sin(x), 0.0, evalf(Pi));
myproc(sin(t), 0.0, evalf(Pi));
myproc(t^2, 0, Pi);
Now, significantly different, passing an procedure (operator) instead of an expression:
restart;
myproc := proc(f,a,b)
local L,x;
L:=int(sqrt(1+D(f)(x)^2),x=a..b);
end proc:
myproc(sin, 0, Pi);
myproc(sin, 0.0, evalf(Pi));
myproc(s -> s^2, 0, Pi);
Lastly (and I do not recommend this way, since the procedure f may not function properly when called with an unassigned name, etc):
restart;
myproc := proc(f,a,b)
local L,x;
L:=int(sqrt(1+diff(f(x),x)^2),x=a..b);
end proc:
myproc(sin, 0, Pi);
myproc(sin, 0.0, evalf(Pi));
myproc(s -> s^2, 0, Pi);

Generating two random time depedant veariables with different sample periods

Following this question, I'm trying to generate two time-dependent random functions omega1 and tau using this example. The difference is that I need to have two different sample periods of 0.05 and 0.17 for omega1 and tau respectively. I just duplicated the parts I thought would do the job:
model testData
extends Modelica.Icons.Example;
import Modelica.Math.Random.Generators;
import Modelica.Math.Random.Utilities;
parameter Real k = 50.0;
parameter Real J = 0.001;
Real theta1;
Real theta2;
Real omega2;
parameter Modelica.SIunits.Period samplePeriod1 = 0.05;
parameter Integer globalSeed1 = 30020;
parameter Integer localSeed1 = 614657;
output Real omega1;
parameter Modelica.SIunits.Period samplePeriod2 = 0.17;
parameter Integer globalSeed2 = 30020;
parameter Integer localSeed2 = 614657;
output Real tau;
protected
discrete Integer state1024[33](each start=0, each fixed = true);
algorithm
when initial() then
state1024 := Generators.Xorshift1024star.initialState(localSeed1, globalSeed1);
omega1 := 0;
elsewhen sample(0, samplePeriod1) then
(omega1, state1024) := Generators.Xorshift1024star.random(pre(state1024));
omega1 := (omega1 - 0.5) * 13;
end when;
when initial() then
state1024 := Generators.Xorshift1024star.initialState(localSeed2, globalSeed2);
omega1 := 0;
elsewhen sample(0, samplePeriod2) then
(tau, state1024) := Generators.Xorshift1024star.random(pre(state1024));
tau := (tau - 0.5) * 3;
end when;
public
parameter Integer id1 = Utilities.initializeImpureRandom(globalSeed1);
discrete Real rImpure1;
Integer iImpure1;
parameter Integer id2 = Utilities.initializeImpureRandom(globalSeed2);
discrete Real rImpure2;
Integer iImpure2;
algorithm
when initial() then
rImpure1 := 0;
iImpure1 := 0;
elsewhen sample(0, samplePeriod1) then
rImpure1 := Utilities.impureRandom(id=id1);
iImpure1 := Utilities.impureRandomInteger(
id=id1,
imin=-1234,
imax=2345);
end when;
when initial() then
rImpure2 := 0;
iImpure2 := 0;
elsewhen sample(0, samplePeriod2) then
rImpure2 := Utilities.impureRandom(id=id2);
iImpure2 := Utilities.impureRandomInteger(
id=id2,
imin=-1234,
imax=2345);
end when;
initial equation
theta1 = 0;
theta2 = 0;
der(theta2) = 0;
equation
der(theta1) = omega1;
der(theta2) = omega2;
J * der(omega2) = tau + k * (theta1 - theta2);
annotation(experiment(StartTime = 0, StopTime = 10, Tolerance = 1e-6, Interval = 0.02));
end testData;
however I get the error messages:
Symbolic Error
The given system is mixed-determined. [index > 3]
Please checkout the option "--maxMixedDeterminedIndex".
Translation Error
No system for the symbolic initialization was generated
I would appreciate if you could help me know what is the problem and how I can solve it.
P.S. considering that this code is apparantly compiling fine on Dymola, this could be a problem with OpenModelica. So I'm adding th JModelica tag in the case those guys can help me know if this compiles over there or not.
You have omega1 := 0; in two when initial()statements. Replace it by tau := 0; in the second one and the example will work.
I recommend to cleanup your code a bit. I found various smaller issues and needless code lines.
everything related to the impure random numbers can be removed
localSeed2 and globalSeed2 are useless when they are initialized like the other seed variables
state1024 is initialized at 3 different places (even though it works with OpenModelica): with start values and fixed=true and in two different when initial() statements
omega2 and tau2 don't need to be outputs. The Tool determines by itself what it has to compute.
And finally: Modelica models are a lot easier to debug and understand if existing blocks and physical components are used instead of writing lengthy code in a single class. Your model can also be built graphically with blocks from Modelica.Blocks.Noise and components from Modelica.Mechanics.Rotational.
Below is an updated version of your code with units, only one section for initialization and removed algorithm section (not necessary anymore due to the additional variables rand_omega and rand_tau).
model testData2
extends Modelica.Icons.Example;
import Modelica.Math.Random.Generators;
import Modelica.Math.Random.Utilities;
import SI = Modelica.SIunits;
parameter SI.RotationalSpringConstant k = 50.0;
parameter SI.Inertia J = 0.001;
parameter SI.Period samplePeriod_tau = 0.17;
parameter SI.Period samplePeriod_omega = 0.05;
parameter Integer globalSeed = 30020;
parameter Integer localSeed_tau = 614657;
parameter Integer localSeed_omega = 45613;
SI.Angle theta1, theta2;
SI.AngularVelocity omega1, omega2, rand_omega;
SI.Torque tau, rand_tau;
protected
discrete Integer state1024_tau[33];
discrete Integer state1024_omega[33];
initial equation
state1024_omega = Generators.Xorshift1024star.initialState(localSeed_omega, globalSeed);
state1024_tau = Generators.Xorshift1024star.initialState(localSeed_tau, globalSeed);
theta1 = 0;
theta2 = 0;
der(theta2) = 0;
equation
when sample(0, samplePeriod_omega) then
(rand_omega, state1024_omega) = Generators.Xorshift1024star.random(pre(state1024_omega));
end when;
when sample(0, samplePeriod_tau) then
(rand_tau, state1024_tau) = Generators.Xorshift1024star.random(pre(state1024_tau));
end when;
der(theta1) = omega1;
der(theta2) = omega2;
omega1 = (rand_omega - 0.5) * 13;
tau = (rand_tau - 0.5) * 3;
J * der(omega2) = 0 + k * (theta1 - theta2);
annotation(experiment(StartTime = 0, StopTime = 10, Tolerance = 1e-6, Interval = 0.02));
end testData2;

OpenModelica complains about a negative value which can't be negative

Following this question I have modified the energy based controller which I have described here to avoid negative values inside the sqrt:
model Model
//constants
parameter Real m = 1;
parameter Real k = 2;
parameter Real Fmax = 3;
parameter Real x0 = 1;
parameter Real x1 = 2;
parameter Real t1 = 5;
parameter Real v0 = -2;
//variables
Real x, v, a, xy, F, vm, K;
initial equation
x = x0;
v = v0;
equation
v = der(x);
a = der(v);
m * a + k * x = F;
algorithm
if time < t1 then
xy := x0;
else
xy := x1;
end if;
K := Fmax * abs(xy - x) + k * (xy^2 - x^2) / 2;
if abs(xy - x) < 1e-6 then
F := k * x;
else
if K > 0 then
vm := sign(xy - x) * sqrt(2 * K / m);
F := Fmax * sign(vm - v);
else
F := Fmax * sign(x - xy);
end if;
end if;
annotation(
experiment(StartTime = 0, StopTime = 20, Tolerance = 1e-06, Interval = 0.001),
__OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "euler"));
end Model;
However, it keeps giving me the error:
The following assertion has been violated at time 7.170000
Model error: Argument of sqrt(K / m) was -1.77973e-005 should be >= 0
Integrator attempt to handle a problem with a called assert.
The following assertion has been violated at time 7.169500
Model error: Argument of sqrt(K / m) was -6.5459e-006 should be >= 0
model terminate | Simulation terminated by an assert at the time: 7.1695
STATISTICS 
Simulation process failed. Exited with code -1.
I would appreciate if you could help me know what is the problem and how I can solve it.
The code you created does event localization to find out when the condition in the if-statements becomes true and/or false. During this search it is possible that the expression in the square-root becomes negative although you 'avoided' it with the if-statement.
Try reading this and to apply the solution presented there. Spoiler: It basically comes down to adding a noEvent() statement for you Boolean condition...

Taylor series vs numeric solution of nonlinear DE in maple

I want to plot two graphs: numeric solution of DE and Taylor series approximation for DE given. I have
de := diff(y(x), x$2) = x+y(x)-y(x)^2;
cond := y(0) = -1, (D(y))(0) = 1;
stp := 0.1e-1;
a, b := -5, 30;
numpts := floor((b-a)/stp+1);
p := dsolve({cond, de}, y(x), numeric, stepsize = stp, output = listprocedure);
Plotting eval gives weird vertical line, while I expect to obtain plot that seems to oscillate as x -> ∞. For Taylor series, I've tried f:=[seq(taylor(y(x),x=i,n),i=-5..30 by stp)]; but seems like it won't work in such a way. What can I do with it? Why does my plot differ from expected?
restart;
kernelopts(version);
Maple 2018.0, X86 64 LINUX, Mar 9 2018, Build ID 1298750
de := diff(y(x), x$2) = x+y(x)-y(x)^2:
cond := y(0) = -1, (D(y))(0) = 1:
stp := 0.1e-1:
a, b := -5, 30:
numpts := floor((b-a)/stp+1):
p := dsolve({cond, de}, y(x), numeric, stepsize = stp,
output = listprocedure):
Y:=eval(y(x),p);
Y := proc(x) ... end;
plot(Y, 0..20);
Order:=10:
S := convert(rhs(dsolve({cond, de}, {y(x)}, series)),polynom);
plot([S, Y(x)], x=0..1.5);
Order:=40:
S := convert(rhs(dsolve({cond, de}, {y(x)}, series)),polynom):
plot([S, Y(x)], x=0..2.0);

How to plot experimental data at special points?

I have a set of experimental data (P), and I want to obtain plot "experimental vs predicted". In order to do so, I use another set of data which depend on P (Q), plot ScatterPlot, use appropriate fit, then obtain regression line, and use its coefficients in appropriate differential equation. Plot of P looks good, but I need to add there experimental data. For simplicity, I've used interval t=0..150.
How can I plot experimental data so that P(0) = Pvals[1], P(10)=Pvals[2], etc.? Besides, how can I distribute data (say, I have t=0..800 and want to plot Pvals so that P(0) = Pvals[1] and P(800) = Pvals[16])?
Pvals := [3.929, 5.308, 7.24, 9.638, 12.866, 17.069, 23.192, 31.433, 38.558, 50.156, 62.948,
75.996, 91.972, 105.711, 122.775, 131.669]:
for i to 15 do Qval[i] := .1*(Pvals[i+1]/Pvals[i]-1); end do:
Qvals := [seq(Qval[i], i = 1 .. 15), 0.144513895e-1]:
with(Statistics);
ScatterPlot(Pvals, Qvals, fit = [a*v^2+b*v+c, v], thickness = 3,
legend = [points = "Point data", fit = typeset("fit to a", 2^nd, "degree polynomial")]);
with(CurveFitting);
LeastSquares(Pvals, Qvals, v, curve = a*v^2+b*v+c);
de := diff(P(t), t) = (0.370152282598477e-1-0.272504103112702e-3*P(t))*P(t);
sol := dsolve({de, P(0) = 3.929}, P(t));
P := plot(rhs(sol), t = 0 .. 160);
I'm not sure that I entirely follow your methodology. But is this something like what you are trying to accomplish?
restart;
with(Statistics):
Pvals := [3.929, 5.308, 7.24, 9.638, 12.866, 17.069, 23.192, 31.433,
38.558, 50.156, 62.948, 75.996, 91.972, 105.711, 122.775, 131.669]:
for i to 15 do Qval[i] := .1*(Pvals[i+1]/Pvals[i]-1); end do:
Qvals := [seq(Qval[i], i = 1 .. 15), 0.144513895e-1]:
form := a*v^2+b*v+c:
CF := CurveFitting:-LeastSquares(Pvals, Qvals, v, curve = form);
CF := 0.0370152282598477 - 0.000272504103112702 v
-7 2
+ 5.60958249026713 10 v
Now I use CF in the DE (since I don't understand why you dropped the v^2 term),
#de := diff(P(t), t) = (0.370152282598477e-1-0.272504103112702e-3*P(t))*P(t);
de := diff(P(t), t) = eval(CF, v=P(t))*P(t);
d /
de := --- P(t) = \0.0370152282598477 - 0.000272504103112702 P(t)
dt
-7 2\
+ 5.60958249026713 10 P(t) / P(t)
I'll use the numeric option of the dsolve command, and obtain a procedure that computes P(t) for numeric t values.
sol := dsolve({de, P(0) = 3.929}, P(t), numeric, output=listprocedure ):
Pfunc := eval(P(t), sol);
Pfunc := proc(t) ... end;
Pfunc(0.0), Pvals[1];
3.92900000000000, 3.929
Now some rescaling (which, again, is my guess as to your goal),
endpt := fsolve(Pfunc(t)-Pvals[16]);
endpt := 135.2246055
Pfunc(endpt), Pvals[16];
131.669000003321, 131.669
plot(Pfunc(t), t=0 .. endpt, size=[500,200]);
a,b,N := 0.0, 800.0, nops(Pvals);
a, b, N := 0., 800.0, 16
Pfuncscaled := proc(t)
if not t::numeric then
return 'procname'(args);
end if;
Pfunc(t*endpt/b);
end proc:
Pfuncscaled(0), Pvals[1];
3.92900000000000, 3.929
Pfuncscaled(800), Pvals[N];
131.669000003321, 131.669
PLscaled := plot( Pfuncscaled(t), t=a .. b,
color=red, size=[500,200] );
Now to display the Pdata against 0 .. 800 as well,
V := Vector(N, (i)->a+(i-1)*(b-a)/(N-1)):
V[1], V[-1];
0., 800.0000000
Pdatascaled := plot( < V | Vector(Pvals) >,
color=blue, size=[500,200],
style=pointline, symbol=solidcircle );
And, displaying the rescaled data together with the rescaled procedure from dsolve,
plots:-display( PLscaled, Pdatascaled, size=[500,500] );