Carl Love

Carl Love

28075 Reputation

25 Badges

13 years, 59 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are Posts that have been published by Carl Love

The attached worksheet shows how to evaluate and graphically analyze an autonomous first-order nonlinear recurrence with two dependent variables and multiple symbolic parameters. 

This worksheet shows how a small module that simply encapsulates the given information of a problem combined with some use statements can greatly facilitate the organization of one's work, can encapsulate the setting of parameter values, and can allow one to work with symbolic parameters.

Edit: In the first version of this Post, I forgot to include the qualifier "autonomous".  The system being autonomous substantially simplifies its treatment.
 

Autonomous first-order nonlinear recurrences with parameters and multiple dependent variables

Author: Carl Love <carl.j.love@gmail.com> 20-Oct-2018

 

The techniques used in this worksheet can be applied to most autonomous first-order nonlinear recurrences with multiple dependent variables and parameters.

 

This worksheet shows how a small module that simply encapsulates the given information of a problem combined with some use statements

• 

can greatly facilitate the organization of one's work,

• 

can encapsulate the setting of parameter values,

• 

can allow one to work with symbolic parameters.

 

A Problem from MaplePrimes: A discrete Lottka-Volterra population model is applied to an isolated island with a population of predators (foxes), R, and prey (rabbits), K. [Note that R is the foxes, not the rabbits! Perhaps this problem statement originated in another language.] The change over one time period is given by

K[n+1]:= K[n]*(-b*R[n]+a+1);  R[n+1]:= R[n]*(b*e*K[n]-c+1),

where a, b, c, e are parameters of the model. In this problem we will use a= 0.15, b= 0.01, c= 0.02, e= 0.01, when numeric values are needed.

 

a) Show that there exists an equilibrium (values of K[n] and R[n] such that K[n+1] = K[n] and R[n+1] = R[n]).

 

b) Write Maple code that solves the recurrence numerically. Assume that if any population is less than 0.5 then it has gone extinct and set the value to 0. Check that your program is idempotent at the equilibrium.

 

restart:

We begin by collecting all the given information (except for specific numeric values) into a module. The ModuleApply lets the user set the numeric values later.

 

For all two-element vectors used in this worksheet, K is the first value and R is the second value.

KandR:= module()
local
   a, b, c, e, #parameters

   #procedure that lets user set parameter values:
   ModuleApply:= proc({
       a::algebraic:= KandR:-a, b::algebraic:= KandR:-b,
       c::algebraic:= KandR:-c, e::algebraic:= KandR:-e
   })
   local k;
      for k to _noptions do thismodule[lhs(_options[k])]:= rhs(_options[k]) od;
      return
   end proc,

   Extinct:= (x::realcons)-> `if`(x < 0.5, 0, x) #force small, insignificant values to 0
;
export
   #Procedure that does one symbolic iteration
   #(Note that this procedure uses Vector input and output.)
   iter_symb:= KR-> KR *~ <-b*KR[2]+a+1, b*e*KR[1]-c+1>, 

   #Such simple treatment as above is only possible for autonomous
   #recurrences.

  
   iter_num:= Extinct~@iter_symb #one numeric iteration
;
end module:

#The following expression is the discrete equivalent of the derivative (or gradient).
#It represents the change over one time period.
P:= <K,R>:  
OneStep:= KandR:-iter_symb(P) - P

Vector(2, {(1) = K*(-R*b+a+1)-K, (2) = R*(K*b*e-c+1)-R})

#An equilibrium occurs when the gradient is 0.
Eq:= <K__e, R__e>:
Eqs:= solve({seq(eval(OneStep=~ 0, [seq(P=~ Eq)]))}, [seq(Eq)]);

[[K__e = 0, R__e = 0], [K__e = c/(b*e), R__e = a/b]]

#We're only interested here in nonzero solutions.
EqSol:= remove(S-> 0 in rhs~(S), Eqs)[];

[K__e = c/(b*e), R__e = a/b]

#Set parameters:
KandR(a= 0.15, b= 0.01, c= 0.02, e= 0.01);

#Show idempotency at equilibrium:
use KandR in Eq0:= eval(Eq, EqSol); print(Eq0 = iter_num(Eq0)) end use:

(Vector(2, {(1) = 200.0000000, (2) = 15.00000000})) = (Vector(2, {(1) = 200.0000000, (2) = 15.00000000}))

#procedure that fills a Matrix with computed values of a 1st-order recurrence.
#(A more-efficient method than this can be used for linear recurrences.)
#This procedure has no dependence on the module.
Iterate:= proc(n::nonnegint, iter, init::Vector[column])
local M:= Matrix((n+1, numelems(init)), init^+, datatype= hfloat), i;
   for i to n do M[i+1,..]:= iter(M[i,..]) od;
   M
end proc:

We want to see what happens if the initial conditions deviate slightly from the equilibrium. It turns out that any deviation (as long as the
initial values are still nonnegative!) will cause the same effect. I simply chose the deviation <7,2> because it was the smallest for which

the plot clearly showed what happens using the scale that I wanted to show the plot at. By using a finer scale, it is possible to see the

"outward spiral" efffect from even the tiniest deviation.

dev:= <7,2>:
use KandR in KR:= Iterate(1000, iter_num, Eq0 + dev) end use:

plot(
   [
       KR, #trajectory of population
       KR[[1,1],..], #1st point
       KR[-[1,1],..], #last point,
       <Eq0|Eq0>^+, #equilibrium
       #every 100th point (helps show time scale):
       KR[100*[$1..iquo(numelems(KR[..,1]), 100)-1], ..]
   ],
   #This group of options are all lists, each element of which corresponds
   #to one of the above components of the plot:
   style= [line, point$4],
   symbol= [solidcircle$4, soliddiamond],
   symbolsize= [18$4, 12],
   color= [black, green, red, brown, blue],
   thickness= [0$5],
   legend= [`pop.`, init, final, equilibrium, `100 periods`],

   #This group of options are lists, each element of which corresponds to one
   #coordinate axis (horizontal, then vertical).
   view= [0..max(KR[..,1]), 0..max(KR(..,2))],
   labels= [rabbits, foxes],
   labeldirections= [horizontal,vertical],
   size= [700,700], #measured in pixels

   #options applied to whole plot:
   labelfont= [TIMES, BOLDITALIC, 14],
   title= "Population of foxes and rabbits over time" "\n", titlefont= [TIMES,16],
   caption=
      "\n" "Choosing an initial point near the equilibrium causes"
      "\n" "outward spiraling divergence." "\n",
   gridlines= false
);
 

A fieldplot helps show what happens for any starting values. An arrow is drawn from each of a 2-D grid of point. The magnitude and direction of the arrow show the gradient (as a vector) in this case.

plots:-fieldplot(
   rtable_eval(OneStep),
   K= 0..max(KR[..,1]),  R= 0..max(KR[..,2]), grid= [16,16],

   #arrow-specific options:
   anchor= tail, fieldstrength= log, arrows= slim, color= "DarkGreen",

   #other options (same as any 2D plot):
   labels= [rabbits, foxes], labeldirections= [horizontal,vertical],
   labelfont= [TIMES, BOLDITALIC, 14],
   title= "One-step population changes from any point" "\n", titlefont= [TIMES,16],
   caption= "\n" "All trajectories spiral outward from the equilibrium." "\n",
   size= [700,700],
   gridlines= false
);

The above plot is computed only from the symbolic discrete gradient expression OneStep; it does not use the computed population values from the first plot. It only uses the maxima of those computed values to determine the length of the axes.

 

Conclusion: While this is interesting stuff mathematically, and makes for great plots, divergence from the equilibrium doesn't seem realistic to me.

 


 

Download FoxesAndRabbits.mw

The numeric solution of ODE BVPs related to nanofluids is one of the most-common sources of Questions on MaplePrimes; perhaps the most-common source, with about 3 or 4 Questions per week over the last several years. The papers in this field are often shoddy, and they often use ad hoc methods for numeric solution of the BVPs. These methods usually have no error control. I have not seen any that come close to Maple's ability with BVPs. I have not analyzed any papers in this field that did not have either significant computational errors or significant omissions that make reproducing the entirety of the numeric computations impossible.

These systems often have many parameters, both as input and output. Maple's dsolve(..., numeric) allows symbolic input parameters for IVPs but not BVPs. On the other hand, it allows symbolic output parameters for BVPs but not IVPs. By using the technique that I show in the attached worksheet, these distinctions in the way that parameters are handled can be made mostly transparent to the end user so that all parameters can be treated as symbolic. Once this has been done, it is easy to make plots (both 2-D and 3-D) whose independent variables are the input parameters themselves, and whose dependent variables are the output parameters.

Other techniques covered in this worksheet are

  • how to make a 3D surface plot combined with a dropped-shadow view of the associated contour plot;
  • how to make 3D plots with boxed axes but with the three annoying foreground lines removed;
  • how to do a statisical fit to express an output parameter as a function of the input parameters using only data that's been collected during the production of the plots.


 

Numeric solution of ODE BVPs with many parameters

 

Author of this Maple worksheet: Carl Love <mailto:carl.j.love@gmail.com>, 14-Oct-2018

 

 

This worksheet is a critique of and an attempt to reproduce all numeric computations in the paper:

 

M. Sheikholeslami, D.D. Ganji, M.M. Rashidi, "Magnetic field effect on unsteady flow and heat transfer using Buongiorno model", Journal of Magnetism and Magnetic Materials, 416 (2016) 164-173, Elsevier, 11-May-2016, http://dx.doi.org/10.1016/j.jmmm.2016.05.026

 

That paper's authors' affiliations and email addresses:

M. Sheikholeslami: Department of Mechanical Engineering, Babol Univeristy of Technology, Babol, Islamic Republic of Iran <mohsen.sheikholeslami@yahoo.com>, <m.sheikholeslmai@stu.nit.ac.ir>,

D.D. Ganji: Department of Mechanical Engineering, Babol Univeristy of Technology, Babol, Islamic Republic of Iran <mirgang@nit.ac.ir>,

M.M. Rashidi: Shanghai Key Lab of Vehicle Aerodynamics and Vehicle Thermal Management Systems, Tongji Univeristy, 4800 Cao An Road, Shanghai 201804, China (no email address given).

 

All references to Equation numbers, Figure numbers, and Table numbers in this worksheet are from that paper.

 

restart:

Digits:= trunc(evalhf(Digits)); #generally a very efficient setting

15

Setup of BVP system:

#ordinary differential equations:
ODEs:= [
   #Eq 8:
   diff(f(eta),eta$4)
   - S*(diff(f(eta),eta$3)*(eta-f(eta)) + diff(f(eta),eta$2)*(3+diff(f(eta),eta)))
   - Ha^2*diff(f(eta),eta$2),

   #Eq 9:
   (1+4/3*Rd)*diff(theta(eta),eta$2)
   + Pr*(S*diff(theta(eta),eta)*(f(eta)-eta) + Ec*diff(f(eta),eta$2)^2)
   + Nb*diff(phi(eta),eta)*diff(theta(eta),eta) + Nt*diff(theta(eta),eta)^2,

   #Eq 10:
   diff(phi(eta),eta$2) + S*Sc*diff(phi(eta),eta)*(f(eta)-eta)
   + Nt/Nb*diff(theta(eta),eta$2)

   #All these ODEs are implicitly equated to 0.
]:

<ODEs[]>; #Display the ODEs.
   

Vector(3, {(1) = diff(diff(diff(diff(f(eta), eta), eta), eta), eta)-S*((diff(diff(diff(f(eta), eta), eta), eta))*(eta-f(eta))+(diff(diff(f(eta), eta), eta))*(3+diff(f(eta), eta)))-Ha^2*(diff(diff(f(eta), eta), eta)), (2) = (1+(4/3)*Rd)*(diff(diff(theta(eta), eta), eta))+Pr*(S*(diff(theta(eta), eta))*(f(eta)-eta)+Ec*(diff(diff(f(eta), eta), eta))^2)+Nb*(diff(phi(eta), eta))*(diff(theta(eta), eta))+Nt*(diff(theta(eta), eta))^2, (3) = diff(diff(phi(eta), eta), eta)+S*Sc*(diff(phi(eta), eta))*(f(eta)-eta)+Nt*(diff(diff(theta(eta), eta), eta))/Nb})

#lower and upper boundary values of the independent variable:
(LB,UB):= (0,1): #Eq 11

#boundary conditions:
BCs:= [
   #Eq 11:
   ([f, (D@@2)(f), D(theta), D(phi)](LB) =~ [0, 0, 0, 0])[],
   ([f, D(f), theta, phi](UB) =~ [1, 0, 1, 1])[]
];

[f(0) = 0, ((D@@2)(f))(0) = 0, (D(theta))(0) = 0, (D(phi))(0) = 0, f(1) = 1, (D(f))(1) = 0, theta(1) = 1, phi(1) = 1]

#parameters (input values to BVP system) and their default values:
Params:= Record(
   #Eq 12:
   S=  0.5,  #Squeeze number
   Pr= 10.,  #Prandtl number
   Ec= 0.1,  #Eckert number
   Sc= 0.5,  #Schmidt number
   Ha= 2.,   #Hartman number
   Nb= 0.15, #Brownian motion parameter
   Nt= 0.15, #thermophoretic parameter
   Rd= 4.5   #radiation parameter
):
   

#Named special computed boundary values (output values of the system): Note that each adds
#exactly one parameter and one boundary condition to the system.

NBVs:= [   
   -(D@@2)(f)(1) = `C*__f`,  #Eq 13: Skin friction coefficient
   -D(theta)(1) = `Nu*`      #Eq 14: Nusselt number
]:

#just rewriting the above names in a more-convenient form:
Nu:= `Nu*`:
Cf:= `C*__f`:

#Appliable module that calls dsolve for each
#particular configuration of parameter values. (Maple's numeric BVPs require a separate
#dsolve invocation for each specific set of parameter values (unlike IVPs, which can be
#parameterized into a single dsolve invocation).)
#
#For every dsolve call through this module, the NBVs are evaluated and saved.

Solve:= module()
local
   nbvs_rhs:= rhs~(:-NBVs), #just the names
   Sol, #numeric dsolve BVP solution of any 'output' form
   ModuleApply:= subs(
      _Sys= {:-ODEs[], :-BCs[], :-NBVs[]},
      proc({
         #These are just default parameter values: They can be changed when the
         #procedure is called.
         S::realcons:=  Params:-S,
         Pr::realcons:= Params:-Pr,
         Ec::realcons:= Params:-Ec,
         Sc::realcons:= Params:-Sc,
         Ha::realcons:= Params:-Ha,
         Nb::realcons:= Params:-Nb,
         Nt::realcons:= Params:-Nt,
         Rd::realcons:= Params:-Rd
         #By extracting the default values from record Params, it is possible to change
         #them by changing the record.
      })
         Sol:= dsolve(_Sys, _rest, numeric);
         AccumData(Sol, {_options});
         Sol
      end proc
   ),
   AccumData:= proc(
      Sol::{Matrix, procedure, list({name, function}= procedure)},
      params::set(name= realcons)
   )
   local n, nbvs;
      if Sol::Matrix then
         nbvs:= seq(n = Sol[2,1][1,Pos(n)], n= nbvs_rhs)
      else
         nbvs:= (nbvs_rhs =~ eval(nbvs_rhs, Sol(:-LB)))[]
      fi;
      SavedData[params]:= Record[packed](params[], nbvs)
   end proc,
   ModuleLoad:= eval(Init)
;
export
   SavedData, #table of Records
   Pos, #Matrix column indices of nbvs
   Init:= proc()
      Pos:= proc(n::name) option remember; local p; member(n, Sol[1,1], 'p'); p end proc;
      SavedData:= table();
      return
   end proc   
;
   ModuleLoad()
end module:
 

Now we attempt to recreate all the numeric computations of the paper.

 

Figure 1 is conceptual, not computational, so there's no point in trying to reproduce it here.

 

I can't attempt to reproduce Table 1 or Figure 2 because the paper doesn't specify the values of all the parameters used for those.

 

Recreate Figure 3:

colseq:= [red, green, blue, brown]:

#parameter values that remain fixed for the entire set of plots:
Pc:= Sc= 0.5, Nb= 0.1, Ec= 0.1, Pr= 10:
 

#parameter values that remain fixed with each of the four plots::
Ps:= [
   [S= 0.5, Ha= 2, Nt= 0.1],
   [Ha= 2, Rd= 0.5, Nt= 0.1],
   [S= 0.5, Rd= 0.5, Nt= 0.1],
   [S= 0.5, Ha= 2, Rd= 0.5]
]:

#parameter value for each curve
Pv:= [
   Rd= [0.5, 2, 4, 8],
   S=  [2, 4, 8, 12],
   Ha= [2, 4, 8, 12],
   Nt= [0.01, 0.05, 0.1, 0.2]
]:
      

for i to nops(Ps) do
   plots:-display(
      [seq(
         plots:-odeplot(
            Solve(lhs(Pv[i])= rhs(Pv[i])[j], Ps[i][], Pc),
            [eta, theta(eta)], 'color'= colseq[j], 'legend'= [lhs(Pv[i])= rhs(Pv[i])[j]]
         ),
         j= 1..nops(rhs(Pv[i]))
      )],
      'axes'= 'boxed', 'gridlines'= false,
      'labelfont'= ['TIMES', 'BOLDOBLIQUE', 16],
      'caption'= nprintf(
         cat("\n%a = %4.2f, "$nops(Ps[i])-1, "%a = %4.2f\n\n"), (lhs,rhs)~(Ps[i])[]
      ),
      'captionfont'= ['TIMES', 16]
   )
od;

The 4 plots agree with those in Fig. 3 in  the paper.

 

Recreate Fig. 4.

 

#procedure that generates a 2-D plot of an expression versus a varied parameter:
ParamPlot2d:= proc(
   Y::{procedure, `module`}, #procedure that extracts y-value from Solve's dsolve solution
   X::name= range(realcons), #x-axis-parameter range
   FP::list(name= realcons), #fixed values of other parameters
   {
      eta::realcons:= :-LB, #independent variable value
      dsolveopts::list({name, name= anything}):= []  
   }
)
   plot(
      x-> Y(
         Solve(
            lhs(X)= x, FP[],
            #Default dsolve options can be changed by setting 'dsolveopts':
            'abserr'= 0.5e-7, 'interpolant'= false, 'output'= Array([eta]), dsolveopts[]
         )
      ),
      rhs(X),
      #Default plot options can be changed by putting the option in the ParamPlot2d call:
      'numpoints'= 25, 'axes'= 'boxed', 'gridlines'= false,
      'labelfont'= ['TIMES', 'BOLDOBLIQUE', 16],
      'caption'= nprintf(cat("%a = %4.2f, "$nops(FP)-1, "%a = %4.2f"), (lhs,rhs)~(FP)[]),
      'captionfont'= ['TIMES', 16],
      _rest
   )
end proc:

#procedure that extracts Nusselt number from dsolve solution:
GetNu:= (Sol::Matrix)-> Sol[2,1][1, Solve:-Pos(:-Nu)]:

RD:= [0.5, 2, 4]:
plots:-display(
   [seq(
      ParamPlot2d(
         GetNu, Ha= 2..8, [S= 0.5],
         dsolveopts= [Rd= RD[k], Sc= 0.5, Nb= 0.1, Ec= 0.1, Nt= 0.1, Pr= 10],
         'legend'= [Rd= RD[k]], 'color'= colseq[k], 'labels'= [Ha, Nu]
      ),
      k= 1..nops(RD)
   )]
);

SV:= [0.5, 2, 4]:
plots:-display(
   [seq(
      ParamPlot2d(
         GetNu, Ha= 2..8, [Rd= 0.5],
         dsolveopts= [S= SV[k], Sc= 0.5, Nb= 0.1, Ec= 0.1, Nt= 0.1, Pr= 10],
         'legend'= [S= SV[k]], 'color'= colseq[k], 'labels'= [Ha, Nu]
      ),
      k= 1..nops(SV)
   )]
)

The above two plots match those of Fig. 4 in the paper.

 

#procedure that generates 3-D plots (dropped-shadow contour + surface) of an expression
#versus two varied parameters:

ParamPlot3d:= proc(
   Z::{procedure, `module`}, #procedure that extracts z-value from Solve's dsolve solution
   X::name= range(realcons), #x-axis-parameter range
   Y::name= range(realcons), #y-axis-parameter range
   FP::list(name= realcons), #fixed values of other parameters
   {
      #fraction of empty space above and below plot (larger "below"
      #value improves view of dropped-shadow contourplot):
      zmargin::[realcons,realcons]:= [.05,0.15],
      eta::realcons:= :-LB, #independent variable value
      dsolveopts::list({name, name= anything}):= [],
      contouropts::list({name, name= anything}):= [],
      surfaceopts::list({name, name= anything}):=[]    
   }
)
local
   LX:= lhs(X), RX:= rhs(X), LY:= lhs(Y), RY:= rhs(Y),
   Zremember:= proc(x,y)
   option remember; #Used because 'grid' should be the same for both plots.
      Z(
         Solve(
            LX= x, LY= y, FP[],
            #Default dsolve options can be changed by setting 'dsolveopts':
            'abserr'= 0.5e-7, 'interpolant'= false, 'output'= Array([eta]),  
            dsolveopts[]
         )
      )
   end proc,
   plotspec:= (Zremember, RX, RY),
   C:= plots:-contourplot(
      plotspec,
      #These default plot options can be changed by setting 'contouropts':
      'grid'= [25,25], 'contours'= 5, 'filled',
      'coloring'= ['yellow', 'orange'], 'color'= 'green',
      contouropts[]
   ),
   P:= plot3d(
      plotspec,
      #These default plot options can be changed by setting 'surfaceopts':
      'grid'= [25,25], 'style'= 'surfacecontour', 'contours'= 6,
      surfaceopts[]
   ),
   U, L #z-axis endpoints after margin adjustment
;
   #Stretch z-axis to include margins:
   (U,L):= ((Um,Lm,M,m)-> (M*(Lm-1)+m*Um, M*Lm+m*(Um-1)) /~ (Um+Lm-1))(
      zmargin[],
      (max,min)(op(3, indets(P, 'specfunc'('GRID'))[])) #actual z-axis range
   );
   plots:-display(  #final plot to display/return
      [
         plots:-spacecurve(
            {
               [[lhs(RX),rhs(RY),U],[rhs(RX),rhs(RY),U],[rhs(RX),rhs(RY),L]], #yz backwall
               [[rhs(RX),rhs(RY),U],[rhs(RX),lhs(RY),U],[rhs(RX),lhs(RY),L]]  #xz backwall
            },
            'color'= 'grey', 'thickness'= 0
         ),
         plottools:-transform((x,y)-> [x,y,L])(C), #dropped-shadow contours
         P
      ],
      #These default plot options can be changed simply by putting the option in the
      #ParamPlot3d call:
      'view'= ['DEFAULT', 'DEFAULT', L..U], 'orientation'= [-135, 75], 'axes'= 'frame',
      'labels'= [lhs(X), lhs(Y), Z], 'labelfont'= ['TIMES', 'BOLDOBLIQUE', 16],
      'caption'= nprintf(cat("%a = %4.2f, "$nops(FP)-1, "%a = %4.2f"), (lhs,rhs)~(FP)[]),
      'captionfont'= ['TIMES', 14],
      'projection'= 2/3,   
      _rest
   )
end proc:

Reproduce the twelve 3-D plots of Figure 5. Note that every plot uses a default grid of 25x25, so requires 625 complete solutions of the BVP. So, this might be slower than you expect.

ParamPlot3d(
   GetNu, S= 0..12, Ha= 0..12, [Rd= 4.5, Ec= 0.06, Nb= 0.15, Nt= 0.15, Sc= 0.5],
   labels= [S, Ha, Nu]
);

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, S= 0..12, Rd= 1..8, [Ha= 6, Ec= 0.06, Nb= 0.15, Nt= 0.15, Sc= 0.5],
   labels= [S, Rd, Nu]
);

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, S= 0..12, Ec= 0.01..0.10, [Ha= 6, Rd= 4.5, Nb= 0.15, Nt= 0.15, Sc= 0.5],
   labels= [S, Ec, Nu]
);

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, S= 0..12, Nt= 0.1..0.2, [Ha= 6, Rd= 4.5, Ec= 0.06, Nb= 0.15, Sc= 0.5],
   labels= [S, Nt, Nu]
);

The above plot doesn't match the corresponding one in the paper!

 

ParamPlot3d(
   GetNu, Ha= 0..12, Rd= 1.0..8.0, [S= 6, Ec= 0.06, Nb= 0.15, Nt= 0.15, Sc= 0.5],
   labels= [Ha, Rd, Nu]
);

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, Ha= 0..12, Ec= 0.01..0.1, [S= 6, Rd= 4.5, Nb= 0.15, Nt= 0.15, Sc= 0.5],
   labels= [Ha, Ec, Nu]
);
   

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, Ha= 0..12, Nt= 0.1..0.2, [S= 6, Rd= 4.5, Ec= 0.06, Nb= 0.15, Sc= 0.5],
   labels= [Ha, Nt, Nu]
);

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, Ha= 0..12, Nb= 0.1..0.2, [S= 6, Rd= 4.5, Ec= 0.06, Nt= 0.15, Sc= 0.5],
   labels= [Ha, Nb, Nu]
);

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, Rd= 1.0..8.0, Nt= 0.1..0.2, [S= 6, Ha= 6, Ec= 0.06, Nb= 0.15, Sc= 0.5],
   labels= [Rd, Nt, Nu]
);

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, Rd= 1.0..8., Nb= 0.1..0.2, [S= 6, Ha= 6, Ec= 0.06, Nt= 0.15, Sc= 0.5],
   labels= [Rd, Nb, Nu]
);

The above plot matches the paper.

 

ParamPlot3d(
   GetNu, Ec= 0.01..0.1, Nt= 0.1..0.2, [S= 6, Ha= 6, Rd= 4.5, Nb= 0.15, Sc= 0.5],
   labels= [Ec, Nt, Nu]
);

ParamPlot3d(
   GetNu, Ec= 0.01..0.1, Nb= 0.1..0.2, [S= 6, Ha= 6, Rd= 4.5, Nt= 0.15, Sc= 0.5],
   labels= [Ec, Nb, Nu]
);

The above plot does not match the corresponding one in the paper!

 

Recreate Fig. 6:

#parameter values that remain fixed for the entire set of plots:
Pc:= Sc= 0.5, Ec= 0.1, Pr= 10:
 

#parameter values that remain fixed within each plot:
Ps:= [
   [S= 0.5, Ha= 2, Nt= 0.1, Nb= 0.1],
   [Ha= 2, Rd= 0.5, Nt= 0.1, Nb= 0.1],
   [S= 0.5, Rd= 0.5, Nt= 0.1, Nb= 0.1],
   [S= 0.5, Ha= 2, Rd= 0.5, Nb= 0.1],
   [S= 0.5, Ha= 2, Rd= 0.5, Nt= 0.1]
]:

#parameter value for each curve in each plot
Pv:= [
   Rd = [0.5, 2, 4, 8],
   S= [2, 4, 8, 12],
   Ha= [2, 4, 8, 12],
   Nt= [0.01, 0.05, 0.1, 0.2],
   Nb= [0.1, 0.2, 0.4, 0.6]
]:
      

for i to nops(Ps) do
   plots:-display(
      [seq(
         plots:-odeplot(
            Solve(lhs(Pv[i])= rhs(Pv[i])[j], Ps[i][], Pc),
            [eta, phi(eta)], 'color'= colseq[j], 'legend'= [lhs(Pv[i])= rhs(Pv[i])[j]]
         ),
         j= 1..nops(rhs(Pv[i]))
      )],
      'axes'= 'boxed', 'gridlines'= false,
      'labelfont'= ['TIMES', 'BOLDOBLIQUE', 16],
      'caption'= nprintf(
         cat("\n%a = %4.2f, "$nops(Ps[i])-1, "%a = %4.2f\n\n"), (lhs,rhs)~(Ps[i])[]
       ),
       'captionfont'= ['TIMES', 16]
   )
od;

The five plots above match Fig. 6 from the paper.

 

Generate Eq. 31: At this point, we have a huge database of Nusselt numbers (15,186 records to be exact) computed at various parameter values.

NusseltList:= [entries(Solve:-SavedData, nolist)]:

nops(NusseltList);

15136

Sheikholeslami, et al, call these the "active parameters" (because they're the ones that have varied in the above computations):

V:= [S, Ha, Rd, Ec, Nt, Nb]:

NusseltData:= Matrix(map(R-> [map(v-> R[v], V)[], R[Nu]], NusseltList));