pde1dMg¶
Solves a system of one-dimensional time-dependent partial differential equations using a moving-grid interface.
Synopsis¶
pde1dMgMgr (task, state)
pde1dMg (t, tend u, xl, xr, state, pdeSystems, boundaryConditions)
The function pde1dMgMgr
is used to initialize and reset the problem, and
the function pde1dMg
is the integrator. The descriptions of both
functions are provided below.
Required Arguments for pde1dMgMgr¶
- int
task
(Input) - This function must be called with task set to
PDE_INITIALIZE
to set up for solving a system and withtask
equal toPDE_RESET
to clean up after it has been solved. These values fortask
are defined in the include file,imsl.h
. - void
state
(Input/Output) - The current state of the PDE solution is held in a structure pointed to
by
state
. It cannot be directly manipulated.
Required Arguments for pde1dMg¶
- float
t
(Input/Output) - On input,
t
is the initial independent variable value. On output,t
is replaced bytend
, unless error conditions arise. This is first set to the value of the independent variable \(t_0\) where the integration of \(u_t\) begins. It is set to the valuetend
on return. - float
tend
(Input) - Mathematical value of \(t\) where the integration of \(u_t\)
ends. Note: Starting values of
t
<
tend
imply integration in the forward direction, while values oft >
tend
imply integration in the backward direction. Either direction is permitted. - float
u[]
(Input/Output) - Array of size
npdes+
1 byngrids
. On input, the firstnpdes
rows contain initial values for all components of the system at the equally spaced grid of values. It is not required to define the grid values in the last row ofu
. On outputu[]
contains the approximate solution value \(U _i(x_j(tend), tend)\) at array locationu[
i×ngrids+
j]
. The grid value \(x _j(tend)\) is in locationu
[(npdes\*ngrids
)+
j]. Normally the grid values are equally spaced as the integration starts. Variable grid values can be provided by defining them as output frompde1dMgMgr
’sinitialConditions
. - float
xl
(Input) - Lower grid boundary, \(x_L\) .
- float
xr
(Input) - Upper grid boundary, \(x_R\) .
- void
state
(Input/Output) - The current state of the solution is held in a structure pointed to by
state
. It must be initialized by a call topde1dMgMgr
. It cannot be directly manipulated. - void
pdeSystems
(t
,x
,npdes
,ngrids
,full_u
,grid_u
,dudx
,c
,q
,r
,ires
) (Input) A user-supplied function to evaluate the differential equation, as expressed in Equation 2. Each application requires a function specifically designed for the task, and this function is normally written by the user of the integrator.
Evaluate the terms of the system of Equation 2. A default value of \(m = 0\) is assumed, but this can be changed to one of the choices, \(m = 1, 2\). Use the optional arguments
cartCoordinates
,cylCoordinates
,sphCoordinates
for the respective values \(m = 0, 1, 2\). Return the values in the arrays as indicated:\[\begin{split}\begin{array}{l} u^j = \mathtt{grid\_u}[j] \\ U = \mathtt{full\_u} \\ \frac{{\partial}u^j}{{\partial}x} = u_x^j = \mathtt{dudx}[j] \\ \text{c}[l][k] = C_{j,k}\left(x, t, u, u_x\right) \\ \text{r}[j] = r_j\left(x, t, u, u_x\right) \\ \text{q}[j] = q_j\left(x, t, u, u_x\right) \\ j, k = 0, \ldots, \mathit{NPDE} - 1 \\ \end{array}\end{split}\]If any of the functions cannot be evaluated, set
ires=3
. Otherwise, do not change the value ofires
.- void
boundaryConditions
(t
,beta
,gamma
,full_u
,grid_u
,dudx
,npdes
,grids
,left
,ires
) (Input) User-supplied function to supply the boundary conditions, as expressed in Equation 2.
\[\begin{split}\begin{array}{l} u^j = \mathtt{grid\_u}[j] \\ U = \mathtt{full\_u} \\ \frac{\partial u^j}{\partial x} = u_x^j = \mathtt{dudx}[j] \\ \mathit{beta}[j] = \beta_j\left(x,t,u,u_x\right) \\ \mathtt{gamma}[j] = \gamma_j\left(x,t,u,u_x\right) \\ j = 0, \ldots \mathit{NPDE} - 1 \\ \end{array}\end{split}\]The value \(x \in \left\{ x_L, x_R \right\}\), and the flag
left=
1 for \(x = x_L\). The flag has the valueleft=
0 for \(x = x_R\). If any of the functions cannot be evaluated, setires=3
. Otherwise, do not change the value ofires
.
Optional Arguments¶
cartCoordinates
, orcylCoordinates
, orsphCoordinates
cartCoordinates
specifies cartesian coordinates, where \(m = 0\) in Equation 2.cylCoordinates
specifies cylindrical or polar coordinates, where \(m = 1\) in Equation 2.sphCoordinates
specifies spherical coordinates, where \(m = 2\) in Equation 2.Default:
cartCoordinates
timeSmoothing
, float (Input)Resets the value of the parameter \(\tau \geq 0\), described above.
Default: \(\tau = 0\).
spatialSmoothing
, float (Input)Resets the value of the parameter \(\kappa \geq 0\), described above.
Default: \(\kappa = 2\).
monitorRegularizing
, float (Input)Resets the value of the parameter \(\alpha \geq 0\), described above.
Default: \(\alpha = 0.01\).
maxBdfOrder
, intmaxBdfOrder
, (Input)Resets the maximum order for the bdf formulas used in
differentialAlgebraicEqs
. The new value can be any integer between 1 and 5. Some problems benefit by making this change. The default value ofmaxBdfOrder
was chosen becausedifferentialAlgebraicEqs
may cycle on its selection of order and step-size withmaxBdfOrder
higher than value 2.Default:
maxBdfOrder
=2.userFactorSolve
, intfac
(neq
,iband
,a
), voidsol
(neq
,iband
,g
,y
) (Input)- User-supplied functions to factor A, and solve the system AΔy =
Δg. Use of this optional argument allows for handling the
factorization and solution steps in a problem‑specific manner. If
successful
fac
should return 0, if unsuccessful,fac
should return a non-zero value. initialConditions
, voidinitialConditions
(npdes
,ngrids
,u)
(Input)- User-supplied function to supply the initial values for the system at the
starting independent variable value
t
. This function can also provide a non-uniform grid at the initial value. Herenpdes
is the number of differential equations,ngrids
is the number of grid points, andu
is an array of sizenpdes+
1 byngrids
, containing the approximate solution value \(U_i \left( x_j(\mathit{tend}), \mathit{tend} \right)\) in locationu[
i×ngrids+
j]
. The grid values are equally spaced on input, but can be updated as desired, provided the values are increasing. Update the grid values in array locationsu
[(npdes
×ngrids
) +j], where 0 ≤ j ≤ngrids
.
Optional Arguments¶
relativeTolerance
, float (Input)This option resets the value of the relative accuracy parameter used in
differentialAlgebraicEqs
.Default:
relativeTolerance=1.0E-
2 for single precision,relativeTolerance=1.0E-
4 for double precision.absoluteTolerance
, float (Input)This option resets the value of the absolute accuracy parameter used in
differentialAlgebraicEqs
.Default:
absoluteTolerance=1E-
2 for single precision,absoluteTolerance=1E-
4 for double precision.
Examples¶
Remarks on the Examples¶
Due to its importance and the complexity of its interface, function
pde1dMg
is presented with several examples. Many of the program features
are exercised. The problems complete without any change to the optional
arguments, except where these changes are required to describe or to solve
the problem.
Example 1 - Electrodynamics Model¶
This example is from Blom and Zegeling (1994). The system is
We make the connection between the model problem statement and the example:
The boundary conditions are
This is a non-linear problem with sharply changing conditions near
\(t = 0\). The default settings of integration parameters allow the
problem to be solved. The use of pde1dMg
requires two subroutines
provided by the user to describe the differential equations, and boundary
conditions.
from numpy import *
from pyimsl.math.pde1dMg import pde1dMg
from pyimsl.math.pde1dMgMgr import pde1dMgMgr, PDE_INITIALIZE, PDE_RESET
def initial_conditions(npdes, ngrids, u):
for i in range(0, ngrids):
u[0, i] = 1.0
u[1, i] = 0.0
def pde_systems(t, x, npdes, ngrids, full_u, grid_u, dudx,
c, q, r, ires):
def setC(i, j, npdes, value):
c[i * npdes + j] = value
eps = 0.143
eta = 17.19
pp = 0.1743
setC(0, 0, npdes, 1.0)
setC(0, 1, npdes, 0.0)
setC(1, 0, npdes, 0.0)
setC(1, 1, npdes, 1.0)
r[0] = pp * dudx[0] * eps
r[1] = pp * dudx[1]
z = eta * (grid_u[0] - grid_u[1]) / 3.0
q[0] = exp(z) - exp(-2.0 * z)
q[1] = -q[0]
def boundary_conditions(t, beta, gamma, full_u, grid_u, dudx,
ngrids, npdes, left, ires):
if (left):
beta[0] = 1.0
beta[1] = 0.0
gamma[0] = 0.0
gamma[1] = grid_u[1]
else:
beta[0] = 0.0
beta[1] = 1.0
gamma[0] = grid_u[0] - 1.0
gamma[1] = 0.0
npde = 2
nframes = 5
n = 51
u = zeros((npde + 1, n), dtype='double')
t0 = [0.0]
tout = 0.0
delta_t = 10.0
tend = 4.0
npdes = npde
ngrids = n
xl = 0.0
xr = 1.0
file1 = open("pde_ex01.out", mode="w")
file1.write(" %d\t%d\t%d" % (npdes, ngrids, nframes))
file1.write("\t%f\t%f\t%f\t%f\n" % (xl, xr, t0[0], tend))
# Initialize u
initial_conditions(npdes, ngrids, u)
state = []
pde1dMgMgr(PDE_INITIALIZE, state)
tout = 1.0e-3
while (True):
pde1dMg(t0, tout, u, xl, xr, state,
pde_systems, boundary_conditions)
file1.write("%f\n" % (tout))
for i in range(0, (npdes + 1)):
for j in range(0, ngrids):
file1.write("%16.10f " % (u[i][j]))
if (((j + 1) % 4) == 0):
file1.write("\n")
file1.write("\n")
t0[0] = tout
tout = tout * delta_t
if (tend < tout):
tout = tend
if (t0[0] >= tend):
break
file1.close()
pde1dMgMgr(PDE_RESET, state)
Example 2 - Inviscid Flow on a Plate¶
This example is a first order system from Pennington and Berzins, (1994). The equations are
Following elimination of w, there remain \(\mathit{NPDE} = 2\) differential equations. The variable \(t\) is not time, but a second space variable. The integration goes from \(t = 0\) to \(t = 5\) . It is necessary to truncate the variable \(x\) at a finite value, say \(x_{\max} = x_R = 25\). In terms of the integrator, the system is defined by letting \(m = 0\) and
The boundary conditions are satisfied by
We use \(N = 10 + 51 = 61\) grid points and output the solution at steps of \(\mathit{\Delta}t = 0.1\).
This is a non-linear boundary layer problem with sharply changing conditions near \(t = 0\). The problem statement was modified so that boundary conditions are continuous near \(t = 0\). Without this change the underlying integration software, differentialAlgebraicEqs, cannot solve the problem. The continuous blending function \(u - \exp(-20t)\) is arbitrary and artfully chosen. This is a mathematical change to the problem, required because of the stated discontinuity at \(t = 0\). Reverse communication is used for the problem data. No additional user-written subroutines are required when using reverse communication. We also have chosen 10 of the initial grid points to be concentrated near \(X_L = 0\), anticipating rapid change in the solution near that point. Optional changes are made to use a pure absolute error tolerance and non-zero time-smoothing.
from numpy import *
from pyimsl.math.pde1dMg import pde1dMg
from pyimsl.math.pde1dMgMgr import pde1dMgMgr, PDE_INITIALIZE, PDE_RESET
n1 = 10
n2 = 51
file1 = open("pde_ex02.out", mode="w")
def initial_conditions(npdes, ngrids, u):
global n1, n2
def setU(i, j, ngrids, value):
u[i * ngrids + j] = value
xl = 0.0
xr = 25.0
for i in range(0, ngrids):
setU(0, i, ngrids, 1.0)
setU(1, i, ngrids, 0.0)
setU(2, i, ngrids, 0.0)
dx1 = xr / n2
dx2 = dx1 / n1
# Grid
for i in range(1, n1 + 1):
i_ = i - 1
setU(2, i_, ngrids, (i - 1) * dx2)
for i in range(n1 + 1, n + 1):
i_ = i - 1
setU(2, i_, ngrids, (i - n1) * dx1)
for i in range(0, npdes + 1):
for j in range(0, ngrids):
file1.write("%16.10f " % (u[i * ngrids + j]))
if (((j + 1) % 4) == 0):
file1.write("\n")
file1.write("\n")
def pde_systems(t, x, npdes, ngrids, full_u, grid_u,
dudx, c, q, r, ires):
def setC(i, j, npdes, value):
c[i * npdes + j] = value
setC(0, 0, npdes, 1.0)
setC(1, 0, npdes, 0.0)
setC(0, 1, npdes, grid_u[0])
setC(1, 1, npdes, 0.0)
r[0] = -grid_u[1]
r[1] = dudx[0]
q[0] = 0.0
q[1] = grid_u[1] * dudx[0]
def boundary_conditions(t, beta, gamma, full_u, grid_u,
dudx, npdes, ngrids, left, ires):
beta[0] = 0.0
beta[1] = 0.0
if (left):
dif = exp(-20.0 * t)
gamma[0] = grid_u[0] - dif
gamma[1] = grid_u[1]
else:
gamma[0] = grid_u[0] - 1.0
gamma[1] = dudx[1]
npde = 2
n = n1 + n2
u = empty((npde + 1, n), dtype=double)
t0 = 0.0
delta_t = 1e-1
tend = 5.0
npdes = npde
ngrids = n
xl = 0.0
xr = 25.0
tau = 1.0e-3
atol = 1e-2
rtol = 0.0
nframes = int((tend + delta_t) / delta_t)
file1.write(" %d\t%d\t%d" % (npdes, ngrids, nframes))
file1.write("\t%f\t%f\t%f\t%f\n" % (xl, xr, t0, tend))
state = []
pde1dMgMgr(PDE_INITIALIZE, state,
timeSmoothing=tau,
initialConditions=initial_conditions)
t0 = [0.0]
tout = delta_t
while (True):
pde1dMg(t0, tout, u, xl, xr, state,
pde_systems, boundary_conditions,
relativeTolerance=rtol,
absoluteTolerance=atol)
t0[0] = tout
file1.write("%f\n" % (tout))
for i in range(0, npdes + 1):
for j in range(0, ngrids):
file1.write("%16.10f " % u[i][j])
if (((j + 1) % 4) == 0):
file1.write("\n")
file1.write("\n")
tout = tout + delta_t
if (tend < tout):
tout = tend
if (t0[0] >= tend):
break
file1.close()
pde1dMgMgr(PDE_RESET, state)
Example 3 - Population Dynamics¶
This example is from Pennington and Berzins (1994). The system is
This is a notable problem because it involves the unknown
across the entire domain. The software can solve the problem by introducing two dependent algebraic equations:
This leads to the modified system
In the interface to the evaluation of the differential equation and boundary conditions, it is necessary to evaluate the integrals, which are computed with the values of \(u(x,t)\) on the grid. The integrals are approximated using the trapezoid rule, commensurate with the truncation error in the integrator.
from numpy import *
from pyimsl.math.pde1dMg import pde1dMg
from pyimsl.math.pde1dMgMgr import pde1dMgMgr, PDE_INITIALIZE, PDE_RESET
file1 = open("pde_ex03.out", mode="w")
def initial_conditions(npdes, ngrids, u):
def setU(i, j, ngrids, value):
u[i * ngrids + j] = value
global file1
xl = 0.0
xr = 5.0
dx = (xr - xl) / (ngrids - 1)
for i in range(0, ngrids):
setU(0, i, ngrids, exp(-u[1 * ngrids + i]) / (2.0 - exp(-xr)))
for i in range(0, npdes + 1):
for j in range(0, ngrids):
file1.write("%16.10f " % (u[i * ngrids + j]))
if (((j + 1) % 4) == 0):
file1.write("\n")
file1.write("\n")
def pde_systems(t, x, npdes, ngrids, full_u, grid_u,
dudx, c, q, r, ires):
sum = 0.0
c[0] = 1.0
r[0] = -1 * grid_u[0]
for i in range(0, ngrids - 1):
sum += (full_u[0 * ngrids + i] + full_u[0 * ngrids + (i + 1)]) * \
(full_u[1 * ngrids + (i + 1)] - full_u[1 * ngrids + i])
v1 = 0.5 * sum
q[0] = v1 * grid_u[0]
def fcn_g(z, t):
a = 5.0
g = 4.0 * z * (2.0 - 2.0 * exp(-a) + exp(-t)) * \
(2.0 - 2.0 * exp(-a) + exp(-t))
g = g / ((1.0 - exp(-a)) * (1.0 - (1.0 + 2.0 * a)
* exp(-2.0 * a)) * (1.0 - exp(-a) + exp(-t)))
return g
def boundary_conditions(t, beta, gamma, full_u, grid_u, dudx,
npdes, ngrids, left, ires):
sum = 0.0
sum1 = 0.0
sum2 = 0.0
sum3 = 0.0
sum4 = 0.0
for i in range(0, ngrids - 1):
sum += (full_u[0 * ngrids + i]
+ full_u[0 * ngrids + (i + 1)]) * \
(full_u[1 * ngrids + (i + 1)]
- full_u[1 * ngrids + i])
mid = 0.5 * (full_u[1 * ngrids + i] + full_u[1 * ngrids + (i + 1)])
sum1 += mid * exp(-mid) * \
((full_u[0 * ngrids + i] + full_u[0 * ngrids + (i + 1)])
* (full_u[1 * ngrids + (i + 1)] - full_u[1 * ngrids + i]))
if (left):
v1 = 0.5 * sum
v2 = 0.5 * sum1
beta[0] = 0.0
gamma[0] = fcn_g(1.0, t) * v1 * v2 / \
((v1 + 1.0) * (v1 + 1.0)) - grid_u[0]
else:
beta[0] = 0.0
gamma[0] = dudx[0]
npde = 1
n = 101
u = empty((npde + 1, n), dtype=double)
mid = array((n - 1), dtype=double)
npdes = npde
ngrids = n
t0 = [0.0]
tout = 0.0
delta_t = 1e-1
tend = 5.0
a = 5.0
state = []
xl = 0.0
xr = 5.0
tau = 1.0
atol = 1e-2
rtol = 0.0
nframes = (int)(tend + delta_t) / delta_t
file1.write(" %d\t%d\t%d" % (npdes, ngrids, nframes))
file1.write("\t%f\t%f\t%f\t%f\n" % (xl, xr, t0[0], tend))
pde1dMgMgr(PDE_INITIALIZE, state,
timeSmoothing=tau,
initialConditions=initial_conditions)
tout = delta_t
file1.write("%f\n" % (t0[0]))
while (True):
pde1dMg(t0, tout, u, xl, xr, state,
pde_systems, boundary_conditions,
relativeTolerance=rtol,
absoluteTolerance=atol)
t0[0] = tout
if (t0[0] <= tend):
file1.write("%f\n" % (tout))
for i in range(0, npdes + 1):
for j in range(0, ngrids):
file1.write("%16.10f " % (u[i][j]))
if (((j + 1) % 4) == 0):
file1.write("\n")
file1.write("\n")
if ((tout + delta_t) < tend):
tout = tout + delta_t
else:
tout = tend
if (t0[0] >= tend):
break
file1.close()
pde1dMgMgr(PDE_RESET, state)
Example 4 - A Model in Cylindrical Coordinates¶
This example is from Blom and Zegeling (1994). The system models a reactor-diffusion problem:
The axial direction \(z\) is treated as a time coordinate. The radius \(r\) is treated as the single space variable.
This is a non-linear problem in cylindrical coordinates. Our example
illustrates assigning \(m = 1\) in
Equation 2. We provide the optional argument
cylCoordinates
that resets this value from its default, \(m = 0\).
from numpy import *
from pyimsl.math.pde1dMg import pde1dMg
from pyimsl.math.pde1dMgMgr import pde1dMgMgr, PDE_INITIALIZE, PDE_RESET
def initial_conditions(npdes, ngrids, t):
for i in range(0, ngrids):
t[0][i] = 0.0
def pde_systems(t, x, npdes, ngrids, u, grid_u, dudx,
c, q, r, ires):
beta = 01e-4
gamma = 1.0
eps = 1e-1
c[0] = 1.0
r[0] = beta * dudx[0]
q[0] = -1.0 * gamma * exp(grid_u[0] / (1.0 + eps * grid_u[0]))
def boundary_conditions(t, beta, gamma, u, grid_u, dudx,
npdes, ngrids, left, ires):
if (left):
beta[0] = 1.0
gamma[0] = 0.0
else:
beta[0] = 0.0
gamma[0] = grid_u[0]
npde = 1
n = 41
t = empty((npde + 1, n), dtype=double)
z0 = [0.0]
delta_z = 1e-1
zend = 1.0
zmax = 1.0
beta = 1e-4
gamma = 1.0
eps = 1e-1
npdes = npde
ngrids = n
xl = 0.0
xr = 1.0
m = 1
file1 = open("pde_ex04.out", mode="w")
nframes = (int)((zend + delta_z) / delta_z) - 1
file1.write(" %d\t%d\t%d" % (npdes, n, nframes))
file1.write("\t%f\t%f\t%f\t%f\n" % (xl, xr, z0[0], zend))
state = []
pde1dMgMgr(PDE_INITIALIZE, state, cylCoordinates=True)
initial_conditions(npdes, ngrids, t)
zout = delta_z
while (True):
pde1dMg(z0, zout, t, xl, xr, state,
pde_systems, boundary_conditions)
z0[0] = zout
if (z0[0] <= zend):
file1.write("%f\n" % (zout))
for i in range(0, npdes + 1):
for j in range(0, ngrids):
file1.write("%16.10f " % (t[i, j]))
if (((j + 1) % 4) == 0):
file1.write("\n")
file1.write("\n")
if ((zout + delta_z) < zend):
zout = zout + delta_z
else:
zout = zend
if (z0[0] >= zend):
break
file1.close()
pde1dMgMgr(PDE_RESET, state)
Example 5 - A ‘Hot Spot’ Model¶
This example is presented more fully in Verwer, et al., (1989). The system is a normalized problem relating the temperature \(u(x,t)\), of a reactant in a chemical system. The formula for \(h(z)\) is equivalent to their example.
This is a non-linear problem. The output shows a case where a rapidly changing front, or hot-spot, develops after a considerable way into the integration. This causes rapid change to the grid. An option sets the maximum order BDF formula from its default value of 2 to the theoretical stable maximum value of 5.
from numpy import *
from pyimsl.math.pde1dMg import pde1dMg
from pyimsl.math.pde1dMgMgr import pde1dMgMgr, PDE_INITIALIZE, PDE_RESET
def initial_conditions(npdes, ngrids, u):
for i in range(0, ngrids):
u[0][i] = 1.0
def pde_systems(t, x, npdes, ngrids, full_u, grid_u, dudx,
c, q, r, ires):
c[0] = 1.0
r[0] = dudx[0]
q[0] = -fcn_h(grid_u[0])
def boundary_conditions(t, beta, gamma, full_u, grid_u, dudx,
npdes, ngrids, left, ires):
if (left):
beta[0] = 0.0
gamma[0] = dudx[0]
else:
beta[0] = 0.0
gamma[0] = grid_u[0] - 1.0
def fcn_h(z):
a = 1.0
delta = 2e1
r = 5.0
return (r / (a * delta)) * (1.0 + a - z) * \
exp(-delta * (1.0 / z - 1.0))
npde = 1
n = 80
u = empty((npde + 1, n), dtype=double)
t0 = [0.0]
tout = 0.0
delta_t = 1e-2
tend = 29e-2
u0 = 1.0
u1 = 0.0
tdelta = 1e-1
tol = 29e-2
a = 1.0
delta = 20.0
r = 5.0
state = []
npdes = npde
ngrids = n
xl = 0.0
xr = 1.0
max_bdf_order = 5
file1 = open("pde_ex05.out", mode="w")
nframes = int((tend + delta_t) / delta_t) - 1
file1.write(" %d\t%d\t%d" % (npdes, ngrids, nframes))
file1.write("\t%f\t%f\t%f\t%f\n" % (xl, xr, t0[0], tend))
initial_conditions(npdes, ngrids, u)
pde1dMgMgr(PDE_INITIALIZE, state, maxBdfOrder=max_bdf_order)
tout = delta_t
while (True):
pde1dMg(t0, tout, u, xl, xr, state,
pde_systems, boundary_conditions)
t0[0] = tout
if (t0[0] <= tend):
file1.write("%f\n" % (tout))
for i in range(0, npdes + 1):
for j in range(0, ngrids):
file1.write("%16.10f " % (u[i][j]))
if (((j + 1) % 4) == 0):
file1.write("\n")
if ((tout + delta_t) < tend):
tout = tout + delta_t
else:
tout = tend
if (t0[0] >= tend):
break
file1.close()
pde1dMgMgr(PDE_RESET, state)
Example 6 - Traveling Waves¶
This example is presented more fully in Verwer, et al., (1989). The system is a normalized problem relating the interaction of two waves, \(u(x,t)\) and \(v(x,t)\) moving in opposite directions. The waves meet and reduce in amplitude, due to the non-linear terms in the equation. Then they separate and travel onward, with reduced amplitude.
This is a non-linear system of first order equations.
from numpy import *
from pyimsl.math.pde1dMg import pde1dMg
from pyimsl.math.pde1dMgMgr import pde1dMgMgr, PDE_INITIALIZE, PDE_RESET
file1 = open("pde_ex06.out", mode="w")
def initial_conditions(npdes, ngrids, u):
def setU(ngrids_, i_, j_, value_):
u[i_ * ngrids_ + j_] = value_
def getU(ngrids_, i_, j_):
return u[i_ * ngrids_ + j_]
for i in range(0, ngrids):
pulse = (0.5 * (1.0 + cos(10.0 * pi * getU(ngrids, npdes, i))))
setU(ngrids, 0, i, pulse)
setU(ngrids, 1, i, pulse)
for i in range(0, ngrids):
utmp = getU(ngrids, npdes, i)
if ((utmp < -3e-1) or (utmp > -1e-1)):
setU(ngrids, 0, i, 0.0)
if ((utmp < 1e-1) or (utmp > 3e-1)):
setU(ngrids, 1, i, 0.0)
for i in range(0, npdes + 1):
for j in range(0, ngrids):
utmp = getU(ngrids, i, j)
file1.write("%16.10f " % (utmp))
if (((j + 1) % 4) == 0):
file1.write("\n")
file1.write("\n")
def pde_systems(t, x, npdes, ngrids, full_u, grid_u, dudx,
c, q, r, ires):
def setC(npdes_, i_, j_, value_):
c[i_ * npdes_ + j_] = value_
setC(npdes, 0, 0, 1.0)
setC(npdes, 0, 1, 0.0)
setC(npdes, 1, 0, 0.0)
setC(npdes, 1, 1, 1.0)
r[0] = -1.0 * grid_u[0]
r[1] = grid_u[1]
q[0] = 100.0 * grid_u[0] * grid_u[1]
q[1] = q[0]
def boundary_conditions(t, beta, gamma, full_u, grid_u, dudx,
npdes, ngrids, left, ires):
beta[0] = 0.0
beta[1] = 0.0
gamma[0] = grid_u[0]
gamma[1] = grid_u[1]
npde = 2
n = 50
npdes = npde
ngrids = n
xl = -0.5
xr = 0.5
u = empty((npde + 1, n), dtype=double)
t0 = [0.0]
tout = 0.0
delta_t = 5e-2
tend = 5e-1
state = []
tau = 1e-3
atol = 1e-3
rtol = 0.0
max_bdf_order = 3
nframes = int((tend + delta_t) / delta_t)
file1.write(" %d\t%d\t%d" % (npdes, ngrids, nframes))
file1.write("\t%f\t%f\t%f\t%f\n" % (xl, xr, t0[0], tend))
pde1dMgMgr(PDE_INITIALIZE, state,
timeSmoothing=tau,
maxBdfOrder=max_bdf_order,
initialConditions=initial_conditions)
file1.write("%f\n" % (t0[0]))
tout = delta_t
while (True):
pde1dMg(t0, tout, u, xl, xr, state,
pde_systems, boundary_conditions,
relativeTolerance=rtol,
absoluteTolerance=atol)
t0[0] = tout
if (t0[0] <= tend):
file1.write("%f\n" % (tout))
for i in range(0, npdes + 1):
for j in range(0, ngrids):
file1.write("%16.10f " % (u[i, j]))
if (((j + 1) % 4) == 0):
file1.write("\n")
file1.write("\n")
if ((tout + delta_t) < tend):
tout = tout + delta_t
else:
tout = tend
if (t0[0] >= tend):
break
file1.close()
pde1dMgMgr(PDE_RESET, state)
Example 7 - Black-Scholes¶
The value of a European “call option,” \(c(s,t)\), with exercise price
\(e\) and expiration date \(T\), satisfies the “asset-or-nothing
payoff ” \(c(s,T) = s, s \geq e; = 0, s < e\). Prior to expiration
\(c(s,t)\) is estimated by the Black-Scholes differential equation
\(c_t + \tfrac{\sigma^2}{2} s^2 c_{ss} + rsc_s - rc \equiv c_t + \tfrac{\sigma^2}{2} \left( s^2 c_s \right)_s + \left( r - \sigma^2 \right) sc_s - rc = 0\)
. The parameters in the model are the risk-free interest rate, \(r\),
and the stock volatility, \(\sigma\). The boundary conditions are
\(c(0,t) = 0\) and \(c_s(s,t) \approx 1,s \rightarrow \infty\).
This development is described in Wilmott, et al. (1995), pages 41-57.
There are explicit solutions for this equation based on the Normal Curve of
Probability. The normal curve, and the solution itself, can be efficiently
computed with the PyIMSL function normalCdf
, see Chapter 9, “Special
Functions.” With numerical integration the equation itself or the payoff can
be readily changed to include other formulas, \(c(s, T)\) , and
corresponding boundary conditions. We use
\(e = 100, r = 0.08, T -t = 0.25, \sigma^2 = 0.04, s_L = 0 \text{ and } s_R = 150\)
.
This is a linear problem but with initial conditions that are discontinuous. It is necessary to use a positive time-smoothing value to prevent grid lines from crossing. We have used an absolute tolerance of \(10^{-3}\). In $US, this is one-tenth of a cent.
from numpy import *
from pyimsl.math.pde1dMg import pde1dMg
from pyimsl.math.pde1dMgMgr import pde1dMgMgr, PDE_INITIALIZE, PDE_RESET
def initial_conditions(npdes, ngrids, u):
xl = 0.0
xr = 150.0
e = 100.0
dx = (xr - xl) / (ngrids - 1)
for i in range(0, ngrids):
xi = xl + i * dx
if (xi <= e):
u[0][i] = 0.0
else:
u[0][i] = xi
def pde_systems(t, x, npdes, ngrids, full_u, grid_u, dudx, c,
q, r, ires):
sigma = 2e-1
rr = 8e-2
sigsq = sigma * sigma
c[0] = 1.0
r[0] = dudx[0] * x * x * sigsq * 0.5
q[0] = -(rr - sigsq) * x * dudx[0] + rr * grid_u[0]
def boundary_conditions(t, beta, gamma, full_u, grid_u, dudx,
npdes, ngrids, left, ires):
if (left):
beta[0] = 0.0
gamma[0] = grid_u[0]
else:
beta[0] = 0.0
gamma[0] = dudx[0] - 1.0
npde = 1
n = 100
xl = 0.0
xr = 150.0
u = empty((npde + 1, n), dtype=double)
t0 = [0.0]
delta_t = 25e-3
tend = 25e-2
xmax = 150.0
state = []
npdes = npde
ngrids = n
tau = 5e-3
atol = 1e-2
rtol = 0.0
max_bdf_order = 5
file1 = open("pde_ex07.out", mode="w")
nframes = int((tend + delta_t) / delta_t)
file1.write(" %d\t%d\t%d" % (npdes, ngrids, nframes))
file1.write("\t%f\t%f\t%f\t%f\n" % (xl, xr, t0[0], tend))
initial_conditions(npdes, ngrids, u)
pde1dMgMgr(PDE_INITIALIZE, state,
timeSmoothing=tau,
maxBdfOrder=max_bdf_order)
tout = delta_t
while (True):
pde1dMg(t0, tout, u, xl, xr, state,
pde_systems, boundary_conditions,
relativeTolerance=rtol,
absoluteTolerance=atol)
t0[0] = tout
if (t0[0] <= tend):
file1.write("%f\n" % (tout))
for i in range(0, npdes + 1):
for j in range(0, ngrids):
file1.write("%16.10f " % (u[i][j]))
if (((j + 1) % 4) == 0):
file1.write("\n")
if ((tout + delta_t) < tend):
tout = tout + delta_t
else:
tout = tend
if (t0[0] >= tend):
break
file1.close()
pde1dMgMgr(PDE_RESET, state)
Fatal Errors¶
IMSL_STOP_USER_FCN |
Request from user supplied function to stop algorithm. User flag = “#”. |