Skip to main content

numerical integration - Tips for efficiently solving large system coupled (nonlinear) ODEs


I'm trying to solve a system of nonlinear, coupled ODEs, where the governing equation for the n-th ODE is of the form:



M∑kQnk¨ak−M∑ℓM∑kSn(ℓ,k)˙aℓ˙ak+12Un=0


where


Qnk=12M∑j=1PjnPjk,


with


Pjn=1√mn(an−j+aj+n−ajan),andan−j=0forj>n,


Sn(ℓ,k)=−12(∂Qkℓ∂an−∂Qnℓ∂ak−∂Qnk∂aℓ),


and


Un=∂∂an12π∫2π0{(−M∑j=1(a2j2j−ajjcosjθ))2(1+M∑j=1ajcosjθ)}dθ.


Note, (Qkℓ,SN(k,ℓ),Un) are all polynomials (of maximum order 4) in the dependent variables ai(t) and M is the total number of dependent variables under consideration (i.e. aj≡0 for j>M). I have been able to solve for low M cases (i.e. M less than 10) using NDSolve. For fixed initial conditions, I have been increasing M and finding a significant increase in computation time. I'm wondering if there are any obvious ways to decrease computation time that I have overlooked. (Ideally, for the system I'm trying to model, I'd like to increase the number of dependent variables to around 200.)


I'm new to Mathematica, and I'm sure I'm making some 'rookie mistakes' that are costing me in computation time. Also, if I'm barking up the wrong tree, that is I should be using a different platform, I'd like to find out before I invest too much effort into this project.



Some questions I have on basic problem set-up:




  1. Is it more efficient to isolate the dependent variables in question. That is, have equations of the form ¨ai=… versus ∑MkQnk¨ak=…?




  2. Is it worth fully simplifying the governing equations (i.e. using FullSimplify) before executing the NDSolve command?




  3. Should I rewrite each second order ODEs as a pair of first order ODEs?





Any advice on this would be greatly appreciated.


Here is the code:


M = 10; (*Number of modes*)
f[r_, s_] := If[r > s, 0, 1]; (*Will ensure we have no negative modes*)
α[i_, t_] := If[i <= M, A[i, t], 0]; (*Truncate series at Mth mode*)
A[0, t_] := 1; (*By definition*)

P[m_, n_, t_] :=

1/Sqrt[m*n^2]*(f[m, n]*α[n - m, t] + α[n + m,
t] - α[m, t]*α[n, t]) ;

Q[n_, l_, t_] := 1/2 Sum[P[m, n, t]* P[m, l, t], {m,1,M}] ;

S[n_, k_, l_, t_] :=
1/2 (D[Q[k, l, t], A[n, t]] - D[Q[n, l, t], A[k, t]] -
D[Q[n, k, t], A[l, t]]);

F[t_] := 1/(2 π) Integrate[

Sum[((A[j, t]*Cos[j*ξ])/j -
A[j, t]^2/(2j)),{j,1,M}]^2*
(1+Sum[1+A[j, t]*
Cos[j*ξ],{j,1,M}]), {ξ, 0, 2π}];
U[n_, t_] := D[F[t], A[n, t]];
Table[A[j, t_] = B[j][t], {j, 1, M}]; (*Redefine dep variables so that independent variable is distinguished from dep var index*)
Gov[n_, t_] := Sum[B[l]''[t]*Q[n,l,t],{l,1,M}]-Sum[Sum[S[n,k,l,t]B[k]'[t]B[l]'[t], {k,1,M}],{l,1,M}]+1/2U[n,t];

eqns = {Table[Gov[j, t] == 0, {j, 1, M}], B[1][0] == 0.3, B[2][0] == 0.1, Table[B[j][0] == 0, {j, 3, M}], Table[B[j]'[0] == 0, {j, 1, M}]};


TenMode = NDSolve[eqns, Table[B[n][t], {n, 1, M}], {t, 0, 10}]

I apologize for any errors in the code since I had some issues parsing from the symbolic notation present in my editor to a code that would be easily copied into this forum.



Answer



The bottleneck in this example is not NDSolve but the fact that for every time you call F a symbolic integration needs to be done. F is defined via SetDelayed (:=) and that function has Attributes HoldAll. What you can do is to force a symbolic (!) evaluation of the integral and use that evaluated integral in stead.


showStatus[status_] := 
LinkWrite[$ParentLink,
SetNotebookStatusLine[FrontEnd`EvaluationNotebook[],
ToString[status]]];
clearStatus[] := showStatus[""];

clearStatus[]

M = 10;(*Number of modes*)

f[r_, s_] :=
If[r > s, 0, 1];(*Will ensure we have no negative modes*)α[i_,
t_] := If[i <= M, A[i, t], 0];(*Truncate series at Mth mode*)

A[0, t_] := 1;(*By definition*)
P[m_, n_, t_] :=

1/Sqrt[m*n^2]*(f[m, n]*α[n - m, t] + α[n + m,
t] - α[m, t]*α[n, t]);
Q[n_, l_, t_] := 1/2 Sum[P[m, n, t]*P[m, l, t], {m, 1, M}];
S[n_, k_, l_, t_] :=
1/2 (D[Q[k, l, t], A[n, t]] - D[Q[n, l, t], A[k, t]] -
D[Q[n, k, t], A[l, t]]);

(* pre-evaluate the integral and define F to be that *)
F[t_] := Evaluate[
1/(2 π) Integrate[

Sum[((A[j, t]*Cos[j*ξ])/j - A[j, t]^2/(2 j)), {j, 1, M}]^2*
Sum[1 + A[j, t]*Cos[j*ξ]/j, {j, 1, M}], {ξ, 0,
2 π}] // Simplify];

U[n_, t_] := D[F[t], A[n, t]];
Table[A[j, t_] = B[j][t], {j, 1, M}];

Gov[n_, t_] :=
Evaluate[Sum[B[l]''[t]*Q[n, l, t], {l, 1, M}] -
Sum[Sum[S[n, k, l, t] B[k]'[t] B[l]'[t], {k, 1, M}], {l, 1, M}] +

1/2 U[n, t]];
eqns = {Table[Gov[j, t] == 0, {j, 1, M}], B[1][0] == 0.3,
B[2][0] == 0.1, Table[B[j][0] == 0, {j, 3, M}],
Table[B[j]'[0] == 0, {j, 1, M}]};
TenMode =
NDSolve[eqns, Table[B[n][t], {n, 1, M}], {t, 0, 10},
EvaluationMonitor :> showStatus["t = " <> ToString[CForm[t]]]
(*,Method->{"EquationSimplification"->"Residual"}*)
]


This gives a message (NDSolve::ndsdtc). If you comment in the (*Method->..*) this will go away. Also have a look at the documentation.


Concerning your questions:



  1. Not really, NDSolve does that for you.

  2. Not really, the overhead in this example is not the numerical function evaluation. In some cases using e.g. Simplify will make the equations smaller and thus less function evaluations are necessary.

  3. No, NDSolve does that for you.


Hope this helps.


Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

mathematical optimization - Minimizing using indices, error: Part::pkspec1: The expression cannot be used as a part specification

I want to use Minimize where the variables to minimize are indices pointing into an array. Here a MWE that hopefully shows what my problem is. vars = u@# & /@ Range[3]; cons = Flatten@ { Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; Minimize[{Total@((vec1[[#]] - vec2[[u[#]]])^2 & /@ Range[1, 3]), cons}, vars, Integers] The error I get: Part::pkspec1: The expression u[1] cannot be used as a part specification. >> Answer Ok, it seems that one can get around Mathematica trying to evaluate vec2[[u[1]]] too early by using the function Indexed[vec2,u[1]] . The working MWE would then look like the following: vars = u@# & /@ Range[3]; cons = Flatten@{ Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; NMinimize[ {Total@((vec1[[#]] - Indexed[vec2, u[#]])^2 & /@ R...

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]