modified_method_of_lines

Solves a system of partial differential equations of the form ut = f(x, t, u, ux, uxx) using the method of lines. The solution is represented with cubic Hermite polynomials.

Note: imsl_f_modified_method_of_lines replaces deprecated function imsl_pde_method_of_lines.

Synopsis

#include <imsl.h>

void imsl_f_modified_method_of_lines_mgr (int task, void **state, , 0)

void imsl_f_modified_method_of_lines (int npdes, float *t, float tend, int nx,float xbreak[], float y[], void *state, void fcn_ut(), void fcn_bc())

The type double functions are imsl_d_modified_method_of_lines_mgr and imsl_d_modified_method_of_lines.

Required Arguments for imsl_f_modified_method_of_lines_mgr

int task (Input)
This function must be called with task set to IMSL_PDE_INITIALIZE to set up memory and default values prior to solving a problem and with task equal to IMSL_PDE_RESET to clean up after it has solved.

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 imsl_f_modified_method_of_lines

int npdes (Input)
Number of differential equations.

float *t (Input/Output)
Independent variable. On input, t supplies the initial time, t0. On output, t is set to the value to which the integration has been updated. Normally, this new value is tend.

float tend (Input)
Value of t = tend at which the solution is desired.

int nx (Input)
Number of mesh points or lines.

float xbreak[] (Input)
Array of length nx containing the breakpoints for the cubic Hermite splines used in the x discretization. The points in xbreak must be strictly increasing. The values xbreak[0] and xbreak[nx - 1] are the endpoints of the interval.

float y[] (Input/Output)
Array of length npdes by nx containing the solution. The array y contains the solution as y[k,i] = uk(xtend) at x = xbreak[i]. On input, y contains the initial values. It must satisfy the boundary conditions. On output, y contains the computed solution.

void *state (Input/Output)
The current state of the PDE solution is held in a structure pointed to by state. It must be initialized by a call to imsl_f_modified_method_of_lines_mgr. It cannot be directly manipulated.

void fcn_ut(int npdes, float x, float t, float u[], float ux[], float uxx[], float ut[])
User-supplied function to evaluate ut.

int npdes (Input)
Number of equations.

float x (Input)
Space variable, x.

float t (Input)
Time variable, t.

float u[] (Input)
Array of length npdes containing the dependent values, u.

float ux[] (Input)
Array of length npdes containing the first derivatives, ux.

float uxx[] (Input)
Array of length npdes containing the second derivative, uxx.

float ut[] (Output)
Array of length npdes containing the computed derivatives ut.

void fcn_bc(int npdes, float x, float t, float alpha[], float beta[], float gamma[])
User-supplied function to evaluate the boundary conditions. The boundary conditions accepted by imsl_f_modified_method_of_lines are

 

 

NOTE: Users must supply the values αk, βk, and yk.

int npdes (Input)
Number of equations.

float x (Input)
Space variable, x.

float t (Input)
Time variable, t.

float alpha[] (Output)
Array of length npdes containing the αk values.

float beta[] (Output)
Array of length npdes containing the βk values.

float gamma[] (Output)
Array of length npdes containing the values of yk.

Synopsis with Optional Arguments

#include <imsl.h>

void imsl_f_modified_method_of_lines_mgr (int task, void **state,

IMSL_TOL, float tol,

IMSL_HINIT, float hinit,

IMSL_INITIAL_VALUE_DERIVATIVE, float initial_deriv[],

IMSL_HTRIAL, float *htrial,

IMSL_FCN_UT_W_DATA, void fcn_ut(), void *data,

IMSL_FCN_BC_W_DATA, void fcn_bc(), void *data,

0)

Optional Arguments

IMSL_TOL, float tol (Input)
Differential equation error tolerance. An attempt is made to control the local error in such a way that the global relative error is proportional to tol.
Default: tol = 100.0*imsl_f_machine(4)

IMSL_HINIT, float hinit (Input)
Initial step size in the t integration. This value must be nonnegative. If hinit is zero, an initial step size of 0.001|tend - t0| will be arbitrarily used. The step will be applied in the direction of integration.
Default: hinit = 0.0

IMSL_INITIAL_VALUE_DERIVATIVE, float initial_deriv[] (Input/Output)
Supply the derivative values ux(x, t0) in initial_deriv, an array of length npdes by nx. This derivative information is input as

 

The array initial_deriv contains the derivative values as output:

 

Default: Derivatives are computed using cubic spline interpolation.

IMSL_HTRIAL, float *htrial (Output)
Return the current trial step size.

IMSL_FCN_UT_W_DATA, void fcn_ut(int npdes, float x, float t, float u[], float ux[], float uxx[], float ut[], void *data), void *data (Input)
User-supplied function to evaluate ut, which also accepts a pointer to data that is supplied by the user. data is a pointer to the data to be passed to the usersupplied function. See Passing Data to User-Supplied Functions in the introduction to this manual for more details.

IMSL_FCN_BC_W_DATA, void fcn_bc(int npdes, float x, float t, float alpha[], float beta[], float gamma[], void *data), void *data (Input)
User-supplied function to evaluate the boundary conditions, which also accepts a pointer to data that is supplied by the user. data is a pointer to the data to be passed to the user-supplied function. See Passing Data to User-Supplied Functions in the introduction to this manual for more details.

Description

Let M = npdes, N = nx and xi = xbreak(I). The function imsl_f_modified_method_of_lines uses the method of lines to solve the partial differential equation system

 

 

 

with the initial conditions

 

and the boundary conditions

for k = 1, M.

Cubic Hermite polynomials are used in the x variable approximation so that the trial solution is expanded in the series

 

 

where φi(x) and ψi(x) are the standard basis functions for the cubic Hermite polynomials with the knots x1 < x2 <  < xN. These are piecewise cubic polynomials with continuous first derivatives. At the breakpoints, they satisfy

 

According to the collocation method, the coefficients of the approximation are obtained so that the trial solution satisfies the differential equation at the two Gaussian points in each subinterval,

 

for j = 1, N. The collocation approximation to the differential equation is

 

for k = 1, M and j = 1, , 2(N - 1).

This is a system of 2M(N - 1) ordinary differential equations in 2M N unknown coefficient functions, ak,i and bk,i. This system can be written in the matrixvector form as A dc/dt = F (tc) with c(t0) = c0 where c is a vector of coefficients of length 2M N and c0 holds the initial values of the coefficients. The last 2M equations are obtained from the boundary conditions.

If αk = βk = 0, it is assumed that no boundary condition is desired for the kth unknown at the left endpoint. A similar comment holds for the right endpoint. Thus, collocation is done at the endpoint. This is generally a useful feature for systems of first-order partial differential equations.

The input/output array Y contains the values of the ak,i. The initial values of the bk,i are obtained by using the IMSL cubic spline function imsl_f_cub_spline_interp_e_cnd (Interpolation and Approximation) to construct functions

 

such that

 

The IMSL function imsl_f_cub_spline_value (Interpolation and Approximation) is used to approximate the values

 

 

Optional argument IMSL_INITIAL_VALUE_DERIVATIVE allows the user to provide the initial values of bk,i.

The order of matrix A is 2M N and its maximum bandwidth is 6M  1. The band structure of the Jacobian of F with respect to c is the same as the band structure of A. This system is solved using a modified version of imsl_f_ode_adams_krogh. Numerical Jacobians are used exclusively. Gear’s BDF method is used as the default because the system is typically stiff. For more details, see Sewell (1982).

Four examples of PDEs are now presented that illustrate how users can interface their problems with IMSL PDE solving software. The examples are small and not indicative of the complexities that most practitioners will face in their applications. A set of seven sample application problems, some of them with more than one equation, is given in Sincovec and Madsen (1975). Two further examples are given in Madsen and Sincovec (1979).

Examples

 

Example 1

The normalized linear diffusion PDE, ut = uxx, 0  x  1, t > t0, is solved. The initial values are t0 = 0, u(x, t0) = u0 = 1. There is a “zero-flux” boundary condition at x = 1, namely ux(1, t) = 0, (t > t0). The boundary value of u(0, t) is abruptly changed from u0 to the value 0, for t >0.

When the boundary conditions are discontinuous, or incompatible with the initial conditions such as in this example, it may be important to use double precision.

 

#include <imsl.h>

#include <stdio.h>

 

void fcnut(int, float, float, float *, float *, float *, float *);

void fcnbc(int, float, float, float *, float *, float *);

 

int main() {

 

int npdes = 1, nx = 8, i, j, nstep = 10;

float hinit, tol, t = 0.0, tend, xbreak[8], y[8];

char title[50];

void *state;

 

/* Set breakpoints and initial conditions */

 

for (i = 0; i < nx; i++) {

xbreak[i] = (float) i / (float) (nx - 1);

y[i] = 1.0;

}

 

/* Initialize the solver */

 

tol = 10.e-4;

hinit = 0.01 * tol;

imsl_f_modified_method_of_lines_mgr(IMSL_PDE_INITIALIZE, &state,

IMSL_TOL, tol,

IMSL_HINIT, hinit,

0);

for (j = 1; j <= nstep; j++) {

tend = (float) j / (float) nstep;

tend *= tend;

 

/* Solve the problem */

 

imsl_f_modified_method_of_lines(npdes, &t, tend, nx, xbreak, y,

state, fcnut, fcnbc);

 

/* Print results at current t=tend */

 

sprintf(title, "solution at t = %4.2f", t);

imsl_f_write_matrix(title, npdes, nx, y, 0);

}

}

 

 

void fcnut(int npdes, float x, float t, float *u, float *ux,

float *uxx, float *ut) {

/* Define the PDE */

*ut = *uxx;

}

 

 

void fcnbc(int npdes, float x, float t, float *alpha, float *beta,

float *gam) {

float delta = 0.09, u0 = 1.0, u1 = 0.1;

 

/* Define boundary conditions */

 

if (x == 0.0) {

 

/* These are for x = 0 */

 

*alpha = 1.0;

*beta = 0.0;

*gam = u1;

 

/* If in the boundary layer, compute

 

nonzero gamma */

if (t <= delta)

*gam = u0 +(u1 - u0)* t/delta;

} else {

 

/* These are for x = 1 */

 

*alpha = 0.0;

*beta = 1.0;

*gam = 0.0;

}

}

Output

 

solution at t = 0.01

1 2 3 4 5 6

0.900 0.985 0.999 1.000 1.000 1.000

 

7 8

1.000 1.000

 

solution at t = 0.04

1 2 3 4 5 6

0.600 0.834 0.941 0.982 0.996 0.999

 

7 8

1.000 1.000

 

solution at t = 0.09

1 2 3 4 5 6

0.1003 0.4906 0.7304 0.8673 0.9395 0.9743

 

7 8

0.9891 0.9931

 

solution at t = 0.16

1 2 3 4 5 6

0.1000 0.3145 0.5094 0.6702 0.7905 0.8709

 

7 8

0.9159 0.9303

 

solution at t = 0.25

1 2 3 4 5 6

0.1000 0.2571 0.4052 0.5361 0.6434 0.7228

 

7 8

0.7713 0.7876

 

solution at t = 0.36

1 2 3 4 5 6

0.1000 0.2178 0.3295 0.4296 0.5129 0.5754

 

7 8

0.6142 0.6273

 

solution at t = 0.49

1 2 3 4 5 6

0.1000 0.1852 0.2661 0.3387 0.3993 0.4449

 

7 8

0.4732 0.4827

 

solution at t = 0.64

1 2 3 4 5 6

0.1000 0.1587 0.2144 0.2644 0.3061 0.3375

 

7 8

0.3570 0.3636

 

solution at t = 0.81

1 2 3 4 5 6

0.1000 0.1385 0.1752 0.2080 0.2354 0.2561

 

7 8

0.2689 0.2732

 

solution at t = 1.00

1 2 3 4 5 6

0.1000 0.1243 0.1475 0.1682 0.1855 0.1985

 

7 8

0.2066 0.2093

 

Example 2

Here, Problem C is solved from Sincovec and Madsen (1975). The equation is of diffusion-convection type with discontinuous coefficients. This problem illustrates a simple method for programming the evaluation routine for the derivative, ut. Note that the weak discontinuities at x = 0.5 are not evaluated in the expression for ut. The problem is defined as

 

 

 

 

#include <imsl.h>

#include <math.h>

#include <stdio.h>

 

void fcnut(int, float, float, float *, float *, float *, float *);

void fcnbc(int, float, float, float *, float *, float *);

 

int main()

{

int i, j, npdes = 1, nstep = 10, nx = 100;

float hinit, t = 0.0, tend, tol, xbreak[100], y[100];

char title[50];

void *state;

 

/* Set breakpoints and initial conditions */

 

for (i = 0; i < nx; i++) {

xbreak[i] = (float) i / (float) (nx - 1);

y[i] = 0.0;

}

y[0] = 1.0;

 

/* Initialize the solver */

 

tol = sqrt(imsl_f_machine(4));

hinit = 0.01*tol;

imsl_f_modified_method_of_lines_mgr(IMSL_PDE_INITIALIZE, &state,

IMSL_TOL, tol,

IMSL_HINIT, hinit,

0);

 

for (j = 1; j <= nstep; j++) {

tend = (float) j / (float) nstep;

 

/* Solve the problem */

 

imsl_f_modified_method_of_lines(npdes, &t, tend, nx, xbreak, y,

state, fcnut, fcnbc);

}

 

/* Print results at t=tend */

 

sprintf(title, "solution at t = %4.2f", t);

imsl_f_write_matrix(title, npdes, nx, y, 0);

}

 

void fcnut(int npdes, float x, float t, float *u, float *ux, float *uxx,

float *ut)

{

/* Define the PDE */

 

float d = 1.0, v = 1.0;

 

if (x <= 0.5) {

d = 5.0;

v = 1000.0;

}

ut[0] = d*uxx[0] - v*ux[0];

}

 

void fcnbc(int npdes, float x, float t, float *alpha, float *beta,

float *gam)

{

if (x == 0.0) {

*alpha = 1.0;

*beta = 0.0;

*gam = 1.0;

} else {

*alpha = 1.0;

*beta = 0.0;

*gam = 0.0;

}

}

Output

 

solution at t = 1.00

1 2 3 4 5 6

1.000 1.000 1.000 1.000 1.000 1.000

 

7 8 9 10 11 12

1.000 1.000 1.000 1.000 1.000 1.000

 

13 14 15 16 17 18

1.000 1.000 1.000 1.000 1.000 1.000

 

19 20 21 22 23 24

1.000 1.000 1.000 1.000 1.000 1.000

 

25 26 27 28 29 30

1.000 1.000 1.000 1.000 1.000 1.000

 

31 32 33 34 35 36

1.000 1.000 1.000 1.000 1.000 1.000

 

37 38 39 40 41 42

1.000 1.000 1.000 1.000 1.000 1.000

 

43 44 45 46 47 48

1.000 1.000 1.000 1.000 1.000 1.000

 

49 50 51 52 53 54

1.000 0.997 0.984 0.969 0.953 0.937

 

55 56 57 58 59 60

0.921 0.905 0.888 0.872 0.855 0.838

 

61 62 63 64 65 66

0.821 0.804 0.786 0.769 0.751 0.733

 

67 68 69 70 71 72

0.715 0.696 0.678 0.659 0.640 0.621

 

73 74 75 76 77 78

0.602 0.582 0.563 0.543 0.523 0.502

 

79 80 81 82 83 84

0.482 0.461 0.440 0.419 0.398 0.376

 

85 86 87 88 89 90

0.354 0.332 0.310 0.288 0.265 0.242

 

91 92 93 94 95 96

0.219 0.196 0.172 0.148 0.124 0.100

 

97 98 99 100

0.075 0.050 0.025 0.000

 

Example 3

In this example, using imsl_f_modified_method_of_lines, the linear normalized diffusion PDE ut = uxx is solved but with an optional use that provides values of the derivatives, ux, of the initial data. Due to errors in the numerical derivatives computed by spline interpolation, more precise derivative values are required when the initial data is u(x, 0) = 1 + cos[(2n - 1)πx], n > 1. The boundary conditions are “zero flux” conditions ux(0, t) = ux(1, t) = 0 for t > 0.

This optional usage signals that the derivative of the initial data is passed by the user. The values u(xtend) and ux(xtend) are output at the breakpoints with the optional usage.

 

#include <imsl.h>

#include <math.h>

#include <stdio.h>

 

void fcnut(int, float, float, float *, float *, float *, float *);

void fcnbc(int, float, float, float *, float *, float *);

 

int main()

{

int i, j, npdes = 1, nstep = 10, nx = 10;

float arg, hinit, tol, pi, t = 0.0, tend = 0.0;

float deriv[10], xbreak[10], y[10];

char title[50];

void *state;

 

pi = imsl_f_constant("pi", 0);

arg = 9.0 * pi;

 

/* Set breakpoints and initial conditions */

 

for (i = 0; i < nx; i++) {

xbreak[i] = (float) i / (float) (nx - 1);

y[i] = 1.0 + cos(arg * xbreak[i]);

deriv[i] = -arg * sin(arg * xbreak[i]);

}

 

/* Initialize the solver */

 

tol = sqrt(imsl_f_machine(4));

imsl_f_modified_method_of_lines_mgr(IMSL_PDE_INITIALIZE, &state,

IMSL_TOL, tol,

IMSL_INITIAL_VALUE_DERIVATIVE, deriv,

0);

 

for (j = 1; j <= nstep; j++) {

tend += 0.001;

 

/* Solve the problem */

 

imsl_f_modified_method_of_lines(npdes, &t, tend, nx, xbreak, y,

state, fcnut, fcnbc);

 

/* Print results at every other t=tend */

 

if (!(j % 2)) {

sprintf(title, "\nsolution at t = %5.3f", t);

imsl_f_write_matrix(title, npdes, nx, y, 0);

sprintf(title, "\nderivative at t = %5.3f", t);

imsl_f_write_matrix(title, npdes, nx, deriv, 0);

}

}

}

 

void fcnut(int npdes, float x, float t, float *u, float *ux, float *uxx,

float *ut)

{

/* Define the PDE */

 

*ut = *uxx;

}

 

void fcnbc(int npdes, float x, float t, float *alpha, float *beta,

float *gam)

{

/* Define the boundary conditions */

 

alpha[0] = 0.0;

beta[0] = 1.0;

gam[0] = 0.0;

}

Output

 

solution at t = 0.002

1 2 3 4 5 6

1.234 0.766 1.234 0.766 1.234 0.766

 

7 8 9 10

1.234 0.766 1.234 0.766

 

 

derivative at t = 0.002

1 2 3 4 5 6

0.000e+000 8.983e-007 -3.682e-008 1.772e-006 4.368e-008 2.619e-006

 

7 8 9 10

-1.527e-006 4.956e-006 -3.003e-006 -3.009e-011

 

 

solution at t = 0.004

1 2 3 4 5 6

1.054 0.946 1.054 0.946 1.054 0.946

 

7 8 9 10

1.054 0.946 1.054 0.946

 

 

derivative at t = 0.004

1 2 3 4 5 6

0.000e+000 2.646e-007 4.763e-007 1.009e-006 -5.439e-007 -8.247e-007

 

7 8 9 10

3.142e-007 1.750e-006 -1.019e-006 4.300e-012

 

 

solution at t = 0.006

1 2 3 4 5 6

1.012 0.988 1.012 0.988 1.012 0.988

 

7 8 9 10

1.012 0.988 1.012 0.988

 

 

derivative at t = 0.006

1 2 3 4 5 6

0.000e+000 4.923e-007 4.082e-008 6.763e-007 -3.347e-007 -7.026e-007

 

7 8 9 10

4.525e-007 3.456e-007 -5.008e-007 1.327e-012

 

 

solution at t = 0.008

1 2 3 4 5 6

1.003 0.997 1.003 0.997 1.003 0.997

 

7 8 9 10

1.003 0.997 1.003 0.997

 

 

derivative at t = 0.008

1 2 3 4 5 6

0.000e+000 -1.323e-007 1.079e-006 2.271e-007 -7.651e-007 4.554e-007

 

7 8 9 10

7.479e-007 -5.015e-009 -3.918e-007 2.261e-013

 

 

solution at t = 0.010

1 2 3 4 5 6

1.001 0.999 1.001 0.999 1.001 0.999

 

7 8 9 10

1.001 0.999 1.001 0.999

 

 

derivative at t = 0.010

1 2 3 4 5 6

0.000e+000 9.523e-008 1.043e-006 3.912e-007 -6.791e-007 2.734e-008

 

7 8 9 10

4.506e-007 2.447e-007 -2.414e-008 -1.161e-015

Example 4

In this example, consider the linear normalized hyperbolic PDE, utt = uxx, the “vibrating string” equation. This naturally leads to a system of first order PDEs. Define a new dependent variable ut = v. Then, vt = uxx is the second equation in the system. Take as initial data u(x, 0) = sin(πx) and ut(x, 0) = v(x, 0) = 0. The ends of the string are fixed so u(0, t) = u(1, t) = v(0, t) = v(1, t) = 0. The exact solution to this problem is u(xt) = sin(πx) cos(πt). Residuals are computed at the output values of t for 0 < t  2. Output is obtained at 200 steps in increments of 0.01.

Even though the sample code imsl_f_modified_method_of_lines gives satisfactory results for this PDE, users should be aware that for nonlinear problems, “shocks” can develop in the solution. The appearance of shocks may cause the code to fail in unpredictable ways. See Courant and Hilbert (1962), pp 488-490, for an introductory discussion of shocks in hyperbolic systems.

 

#include <imsl.h>

#include <math.h>

#include <stdio.h>

 

void fcnut(int, float, float, float *, float *, float *, float *);

void fcnbc(int, float, float, float *, float *, float *);

 

int main()

{

int i, j, npdes = 2, nstep = 200, nx = 10;

float error[10], erru = 0.0, err, hinit, pi, t = 0.0, tend = 0.0;

float deriv[20], tol, y[20], xbreak[10];

void *state;

 

pi = imsl_f_constant("pi", 0);

 

/* Set breakpoints and initial conditions */

 

for (i = 0; i < nx; i++) {

xbreak[i] = (float) i / (float) (nx - 1);

y[i] = sin(pi * xbreak[i]);

y[nx + i] = 0.0;

deriv[i] = pi * cos(pi * xbreak[i]);

deriv[nx + i] = 0.0;

}

 

/* Initialize the solver */

 

tol = sqrt(imsl_f_machine(4));

imsl_f_modified_method_of_lines_mgr(IMSL_PDE_INITIALIZE, &state,

IMSL_TOL, tol,

IMSL_INITIAL_VALUE_DERIVATIVE, deriv,

0);

 

for ( j=1; j <= nstep; j++) {

tend += 0.01;

 

/* Solve the problem */

 

imsl_f_modified_method_of_lines(npdes, &t, tend, nx, xbreak, y,

state, fcnut, fcnbc);

 

 

/* Look at output at steps of 0.01 and compute errors */

 

 

for (i = 0; i < nx; i++) {

error[i] = y[i] - sin(pi * xbreak[i]) * cos(pi *tend);

err = fabs(error[i]);

if (err > erru) erru = err;

}

}

printf("Maximum error in u(x,t) = %e\n", erru);

}

 

void fcnut(int npdes, float x, float t, float *u, float *ux, float *uxx,

float *ut)

{

/* Define the PDE */

 

ut[0] = u[1];

ut[1] = uxx[0];

}

 

void fcnbc(int npdes, float x, float t, float *alpha, float *beta,

float *gam)

{

/* Define the boundary conditions */

 

alpha[0] = 1.0;

beta[0] = 0.0;

gam[0] = 0.0;

alpha[1] = 1.0;

beta[1] = 0.0;

gam[1] = 0.0;

}

Output

 

Maximum error in u(x,t) = 5.757928e-003

Fatal Errors

IMSL_REPEATED_ERR_TEST_FAILURE

After some initial success, the integration was halted by repeated error test failures.

IMSL_INTEGRATION_HALTED_1

Integration halted after failing to pass the error test, even after reducing the stepsize by a factor of 1.0E+10 to H = #. TOL = # may be too small.

IMSL_INTEGRATION_HALTED_2

Integration halted after failing to achieve corrector convergence, even after reducing the stepsize by a factor of 1.0E+10 to H = #. TOL = # may be too small.

IMSL_INTEGRATION_HALTED_3

After some initial success, the integration was halted by a test on TOL = #.

IMSL_TOL_TOO_SMALL_OR_STIFF

On the next step X+H will equal X, with X = # and H = #. Either TOL = # is too small or the problem is stiff.

IMSL_STOP_USER_FCN

Request from user supplied function to stop algorithm.
User flag = "#".