```/* nag_pde_parab_1d_cd_ode (d03plc) Example Program.
*
* NAGPRODCODE Version.
*
* Copyright 2016 Numerical Algorithms Group.
*
* Mark 26, 2016.
*/

#include <stdio.h>
#include <nag.h>
#include <nag_stdlib.h>
#include <nagd03.h>
#include <nagx01.h>
#include <math.h>

/* Structure to communicate with user-supplied function arguments */

struct user
{
double elo, ero, gamma, rlo, rro;
};

#ifdef __cplusplus
extern "C"
{
#endif
static void NAG_CALL pdedef(Integer, double, double, const double[],
const double[], Integer, const double[],
const double[], double[], double[], double[],
double[], Integer *, Nag_Comm *);

static void NAG_CALL bndry1(Integer, Integer, double, const double[],
const double[], Integer, const double[],
const double[], Integer, double[], Integer *,
Nag_Comm *);

static void NAG_CALL bndry2(Integer, Integer, double, const double[],
const double[], Integer, const double[],
const double[], Integer, double[], Integer *,
Nag_Comm *);

static void NAG_CALL nmflx1(Integer, double, double, Integer,
const double[], const double[], const double[],
double[], Integer *, Nag_Comm *,
Nag_D03_Save *);

static void NAG_CALL nmflx2(Integer, double, double, Integer,
const double[], const double[], const double[],
double[], Integer *, Nag_Comm *,
Nag_D03_Save *);

static void NAG_CALL odedef(Integer, double, Integer, const double[],
const double[], Integer, const double[],
const double[], const double[], const double[],
double[], Integer *, Nag_Comm *);
#ifdef __cplusplus
}
#endif

static void init1(double, double *, Integer, double *, Integer, Integer);
static void init2(Integer, Integer, double *, double *, Nag_Comm *);
static void exact(double, double *, Integer, const double *, Integer);
static int ex1(void);
static int ex2(void);

#define P(I, J)    p[npde*((J) -1)+(I) -1]
#define UCP(I, J)  ucp[npde*((J) -1)+(I) -1]
#define U(I, J)    u[npde*((J) -1)+(I) -1]
#define UE(I, J)    ue[npde*((J) -1)+(I) -1]

int main(void)
{
Integer exit_status_ex1 = 0;
Integer exit_status_ex2 = 0;

printf("nag_pde_parab_1d_cd_ode (d03plc) Example Program Results\n");
exit_status_ex1 = ex1();
exit_status_ex2 = ex2();

return (exit_status_ex1 == 0 && exit_status_ex2 == 0) ? 0 : 1;
}

int ex1(void)
{
/* Constants */
const Integer npde = 2, npts = 201, ncode = 2, nxi = 2;
const Integer neqn = npde*npts + ncode, lrsave = 100000;
const Integer lisave = 100000;
static double ruser1[4] = { -1.0, -1.0, -1.0, -1.0 };

/* Scalars */
double        tout, ts, errmax, lerr, lwgt;
Integer       exit_status = 0, i, ind, itask, itol, itrace, j;

/* Arrays */
double        *algopt = 0, *atol = 0, *rsave = 0, *rtol = 0, *u = 0, *ue = 0;
double        *x = 0, *xi = 0;
Integer       *isave = 0;

/* Nag Types */
NagError      fail;
Nag_Comm      comm;
Nag_D03_Save  saved;

INIT_FAIL(fail);

/* For communication with user-supplied functions: */
comm.user = ruser1;

printf("\n\nExample 1\n\n");

/* Allocate memory */

if (!(algopt = NAG_ALLOC(30, double)) ||
!(atol = NAG_ALLOC(1, double)) ||
!(rsave = NAG_ALLOC(lrsave, double)) ||
!(rtol = NAG_ALLOC(1, double)) ||
!(u = NAG_ALLOC(neqn, double)) ||
!(ue = NAG_ALLOC(npde * npts, double)) ||
!(x = NAG_ALLOC(npts, double)) ||
!(xi = NAG_ALLOC(nxi, double)) ||
!(isave = NAG_ALLOC(lisave, Integer)))
{
printf("Allocation failure\n");
exit_status = 1;
goto END;
}

itrace = 0;
itol = 1;
atol[0] = 1e-5;
rtol[0] = 2.5e-4;

printf(" Method parameters:\n");
printf("  Number of mesh points used = %4" NAG_IFMT "\n", npts);
printf("  Relative tolerance used    = %12.3e\n", rtol[0]);
printf("  Absolute tolerance used    = %12.3e\n\n", atol[0]);

/* Initialize mesh */

for (i = 0; i < npts; ++i)
x[i] = i / (npts - 1.0);
xi[0] = 0.0;
xi[1] = 1.0;

/* Set initial values */

ts = 0.0;
init1(ts, u, npde, x, npts, ncode);

ind = 0;

for (i = 0; i < 30; ++i)
algopt[i] = 0.0;

/* BDF integration */

algopt[0] = 1.0;

/* Sparse matrix algebra parameters */

algopt[28] = 0.1;
algopt[29] = 1.1;

tout = 0.5;
/* nag_pde_parab_1d_cd_ode (d03plc).
* General system of convection-diffusion PDEs with source
* terms in conservative form, coupled DAEs, method of
* lines, upwind scheme using numerical flux function based
* on Riemann solver, one space variable
*/
nag_pde_parab_1d_cd_ode(npde, &ts, tout, pdedef, nmflx1, bndry1, u, npts, x,
ncode, odedef, nxi, xi, neqn, rtol, atol, itol,
Nag_OneNorm, Nag_LinAlgSparse, algopt, rsave,
lrsave, isave, lisave, itask, itrace, 0, &ind,
&comm, &saved, &fail);
if (fail.code != NE_NOERROR) {
printf("Error from nag_pde_parab_1d_cd_ode (d03plc).\n%s\n",
fail.message);
exit_status = 1;
goto END;
}

/* Check against exact solution */
exact(tout, ue, npde, &x[0], npts);
errmax = 0.0;
for (i=1; i<npts; i++) {
lerr = 0.0;
for (j=0; j<npde; j++) {
lwgt = rtol[0]*fabs(ue[i*npde+j]) + atol[0];
lerr += fabs(u[i*npde+j]-ue[i*npde+j])/lwgt;
}
lerr = lerr/(double) npde;
errmax = MAX(errmax,lerr);
}
errmax = MAX(100.0*round(errmax/100.0),50.0);
printf("\n Integration Results:\n");
printf("  Global error is less than %4" NAG_IFMT ""
" times the local error tolerance.\n", (Integer)(errmax));

/* Print integration statistics (reasonably rounded) */
printf("\n Integration Statistics:\n");
printf("  %-30s (nearest %3d) = %6" NAG_IFMT "\n",
"Number of time steps", 50, 50*((isave[0]+25)/50));
printf("  %-30s (nearest %3d) = %6" NAG_IFMT "\n",
"Number of function evaluations", 100, 100*((isave[1]+50)/100));
printf("  %-30s (nearest %3d) = %6" NAG_IFMT "\n",
"Number of Jacobian evaluations", 20, 20*((isave[2]+10)/20));
printf("  %-30s (nearest %3d) = %6" NAG_IFMT "\n",
"Number of iterations", 100, 100*((isave[4]+50)/100));
END:
NAG_FREE(algopt);
NAG_FREE(atol);
NAG_FREE(rsave);
NAG_FREE(rtol);
NAG_FREE(u);
NAG_FREE(ue);
NAG_FREE(x);
NAG_FREE(xi);
NAG_FREE(isave);

return exit_status;
}

static void NAG_CALL pdedef(Integer npde, double t, double x,
const double u[], const double ux[],
Integer ncode, const double v[],
const double vdot[], double p[], double c[],
double d[], double s[], Integer *ires,
Nag_Comm *comm)
{
Integer i, j;

if (comm->user[2] == -1.0) {
/* printf("(User-supplied callback pdedef, first invocation.)\n"); */
comm->user[2] = 0.0;
}
for (i = 1; i <= npde; ++i) {
c[i - 1] = 1.0;
d[i - 1] = 0.0;
s[i - 1] = 0.0;
for (j = 1; j <= npde; ++j) {
if (i == j) {
P(i, j) = 1.0;
}
else {
P(i, j) = 0.0;
}
}
}
return;
}

static void NAG_CALL bndry1(Integer npde, Integer npts, double t,
const double x[], const double u[], Integer ncode,
const double v[], const double vdot[],
Integer ibnd, double g[], Integer *ires,
Nag_Comm *comm)
{
double dudx;
double *ue = 0;

if (comm->user[0] == -1.0) {
/* printf("(User-supplied callback bndry1, first invocation.)\n"); */
comm->user[0] = 0.0;
}

/* Allocate memory */

if (!(ue = NAG_ALLOC(npde, double)))
{
printf("Allocation failure\n");
goto END;
}

if (ibnd == 0) {
exact(t, ue, npde, &x[0], 1);
g[0] = U(1, 1) + U(2, 1) - UE(1, 1) - UE(2, 1);
dudx = (U(1, 2) - U(2, 2) - U(1, 1) + U(2, 1)) / (x[1] - x[0]);
g[1] = vdot[0] - dudx;
}
else {
exact(t, ue, npde, &x[npts - 1], 1);
g[0] = U(1, npts) - U(2, npts) - UE(1, 1) + UE(2, 1);
dudx = (U(1, npts) + U(2, npts) - U(1, npts - 1) - U(2, npts - 1)) /
(x[npts - 1] - x[npts - 2]);
g[1] = vdot[1] + 3.0 * dudx;
}
END:
NAG_FREE(ue);

return;
}

static void NAG_CALL nmflx1(Integer npde, double t, double x, Integer ncode,
const double v[], const double uleft[],
const double uright[], double flux[],
Integer *ires, Nag_Comm *comm,
Nag_D03_Save *saved)
{
if (comm->user[1] == -1.0) {
/* printf("(User-supplied callback nmflx1, first invocation.)\n"); */
comm->user[1] = 0.0;
}
flux[0] = 0.5 * (3.0 * uleft[0] - uright[0] + 3.0 * uleft[1] + uright[1]);
flux[1] = 0.5 * (3.0 * uleft[0] + uright[0] + 3.0 * uleft[1] - uright[1]);
return;
}

static void NAG_CALL odedef(Integer npde, double t, Integer ncode,
const double v[], const double vdot[],
Integer nxi, const double xi[],
const double ucp[], const double ucpx[],
const double ucpt[], double r[], Integer *ires,
Nag_Comm *comm)
{
if (comm->user[3] == -1.0) {
/* printf("(User-supplied callback odedef, first invocation.)\n"); */
comm->user[3] = 0.0;
}
if (*ires == -1) {
r[0] = 0.0;
r[1] = 0.0;
}
else {
r[0] = v[0] - UCP(1, 1) + UCP(2, 1);
r[1] = v[1] - UCP(1, 2) - UCP(2, 2);
}
return;
}

static void exact(double t, double *u, Integer npde, const double *x,
Integer npts)
{
/* Exact solution (for comparison and b.c. purposes) */

double f, g, x1, x2;
Integer i;

for (i = 0; i < npts; ++i) {
x1 = x[i] - 3.0 * t;
x2 = x[i] + t;
f = exp(nag_pi * x1) * sin(2.0 * nag_pi * x1);
g = exp(-2.0 * nag_pi * x2) * cos(2.0 * nag_pi * x2);
u[npde*i]   = f + g;
u[npde*i+1] = f - g;
}
return;
}

static void init1(double t, double *u, Integer npde, double *x, Integer npts,
Integer ncode)
{
/* Initial solution */

double f, g, x1, x2;
Integer i, neqn;

neqn = npde * npts + ncode;
for (i = 0; i < npts; ++i) {
x1 = x[i] - 3.0 * t;
x2 = x[i] + t;
f = exp(nag_pi * x1) * sin(2.0 * nag_pi * x1);
g = exp(-2.0 * nag_pi * x2) * cos(2.0 * nag_pi * x2);
u[npde*i]   = f + g;
u[npde*i+1] = f - g;
}
u[neqn - 2] = u[0] - u[1];
u[neqn - 1] = u[neqn - 3] + u[neqn - 4];

return;
}

int ex2(void)
{
const Integer npde = 3, npts = 141, ncode = 0, nxi = 0;
const Integer neqn = npde * npts + ncode, lisave = neqn + 24;
const Integer lrsave = 16392;
static double ruser[2] = { -1.0, -1.0 };
double d, p, tout, ts, v;
Integer exit_status = 0, i, ind, it, itask, itol, itrace;
double *algopt = 0, *atol = 0, *rsave = 0, *rtol = 0, *u = 0;
double *x = 0, *xi = 0;
Integer *isave = 0;
NagError fail;
Nag_Comm comm;
Nag_D03_Save saved;
struct user data;

INIT_FAIL(fail);

/* For communication with user-supplied functions: */
comm.user = ruser;

printf("\n\nExample 2\n\n");

/* Allocate memory */

if (!(algopt = NAG_ALLOC(30, double)) ||
!(atol = NAG_ALLOC(1, double)) ||
!(rsave = NAG_ALLOC(lrsave, double)) ||
!(rtol = NAG_ALLOC(1, double)) ||
!(u = NAG_ALLOC(npde * npts, double)) ||
!(x = NAG_ALLOC(npts, double)) ||
!(xi = NAG_ALLOC(1, double)) || !(isave = NAG_ALLOC(447, Integer)))
{
printf("Allocation failure\n");
exit_status = -1;
goto END;
}

/* Problem parameters */

data.elo = 2.5;
data.ero = 0.25;
data.gamma = 1.4;
data.rlo = 1.0;
data.rro = 0.125;
comm.p = (Pointer) &data;

itrace = 0;
itol = 1;
atol[0] = 0.005;
rtol[0] = 5e-4;

printf(" Problem parameters and initial conditions:\n");
printf("  gamma          = %5.3f\n", data.gamma);
printf("      e(x<0.5,0) = %5.3f", data.elo);
printf("      e(x>0.5,0) = %5.3f\n", data.ero);
printf("    rho(x<0.5,0) = %5.3f", data.rlo);
printf("    rho(x>0.5,0) = %5.3f\n\n", data.rro);
printf(" Method parameters:\n");
printf("  Number of mesh points used = %4" NAG_IFMT "\n", npts);
printf("  Relative tolerance used    = %12.3e\n", rtol[0]);
printf("  Absolute tolerance used    = %12.3e\n\n", atol[0]);

/* Initialize mesh */

for (i = 0; i < npts; ++i)
x[i] = i / (npts - 1.0);

/* Initial values of variables */

init2(npde, npts, x, u, &comm);

xi[0] = 0.0;
ind = 0;
for (i = 0; i < 30; ++i)
algopt[i] = 0.0;

/* Theta integration */

algopt[0] = 2.0;
algopt[5] = 2.0;
algopt[6] = 2.0;

/* Max. time step */

algopt[12] = 0.005;
ts = 0.0;

printf(" Solution\n%4s%9s%9s%9s%9s\n", "t", "x", "d", "v", "p");
for (it = 0; it < 2; ++it) {
tout = 0.1 * (it + 1);

/* nag_pde_parab_1d_cd_ode (d03plc), see above. */
nag_pde_parab_1d_cd_ode(npde, &ts, tout, NULLFN, nmflx2, bndry2, u, npts,
x, ncode, NULLFN, nxi, xi, neqn, rtol, atol,
itol, Nag_TwoNorm, Nag_LinAlgBand, algopt, rsave,
lrsave, isave, lisave, itask, itrace, 0,
&ind, &comm, &saved, &fail);

if (fail.code != NE_NOERROR) {
printf("Error from nag_pde_parab_1d_cd_ode (d03plc).\n%s\n",
fail.message);
exit_status = 1;
goto END;
}

/* Calculate density, velocity and pressure */

for (i = 1; i <= npts; i += 14) {
d = U(1, i);
v = U(2, i) / d;
p = d*(data.gamma - 1.0)*(U(3, i)/d - 0.5*v*v);
if (i==1) {
printf("%6.3f  %7.4f  %7.4f  %7.4f  %7.4f\n",
ts, x[i-1], d, v, p);
} else {
printf("%6s  %7.4f  %7.4f  %7.4f  %7.4f\n",
"", x[i-1], d, v, p);
}
}
printf("\n");
}

/* Print integration statistics (reasonably rounded) */
printf("\n Integration Statistics:\n");
printf("  %-30s (nearest %3" NAG_IFMT ") = %6" NAG_IFMT "\n",
"Number of time steps", 50, 50*((isave[0]+25)/50));
printf("  %-30s (nearest %3" NAG_IFMT ") = %6" NAG_IFMT "\n",
"Number of function evaluations", 50, 50*((isave[1]+25)/50));
printf("  %-30s (nearest %3" NAG_IFMT ") = %6" NAG_IFMT "\n",
"Number of Jacobian evaluations", 1, isave[2]);
printf("  %-30s (nearest %3" NAG_IFMT ") = %6" NAG_IFMT "\n",
"Number of iterations", 1, isave[4]);

END:
NAG_FREE(algopt);
NAG_FREE(atol);
NAG_FREE(rsave);
NAG_FREE(rtol);
NAG_FREE(u);
NAG_FREE(x);
NAG_FREE(xi);
NAG_FREE(isave);

return exit_status;
}

static void init2(Integer npde, Integer npts, double *x, double *u,
Nag_Comm *comm)
{
Integer i, j;
struct user *data = (struct user *) comm->p;

j = 0;
for (i = 0; i < npts; ++i) {
if (x[i] < 0.5) {
u[j] = data->rlo;
u[j + 1] = 0.0;
u[j + 2] = data->elo;
}
else if (x[i] == 0.5) {
u[j] = 0.5 * (data->rlo + data->rro);
u[j + 1] = 0.0;
u[j + 2] = 0.5 * (data->elo + data->ero);
}
else {
u[j] = data->rro;
u[j + 1] = 0.0;
u[j + 2] = data->ero;
}
j += 3;
}
return;
}

static void NAG_CALL bndry2(Integer npde, Integer npts, double t,
const double x[], const double u[], Integer ncode,
const double v[], const double vdot[],
Integer ibnd, double g[], Integer *ires,
Nag_Comm *comm)
{
struct user *data = (struct user *) comm->p;

if (comm->user[0] == -1.0) {
/* printf("(User-supplied callback bndry2, first invocation.)\n"); */
comm->user[0] = 0.0;
}
if (ibnd == 0) {
g[0] = U(1, 1) - data->rlo;
g[1] = U(2, 1);
g[2] = U(3, 1) - data->elo;
}
else {
g[0] = U(1, npts) - data->rro;
g[1] = U(2, npts);
g[2] = U(3, npts) - data->ero;
}
return;
}

static void NAG_CALL nmflx2(Integer npde, double t, double x, Integer ncode,
const double v[], const double uleft[],
const double uright[], double flux[],
Integer *ires, Nag_Comm *comm,
Nag_D03_Save *saved)
{
char solver;
NagError fail;
struct user *data = (struct user *) comm->p;

if (comm->user[1] == -1.0) {
/* printf("(User-supplied callback nmflx2, first invocation.)\n"); */
comm->user[1] = 0.0;
}

INIT_FAIL(fail);

solver = 'R';
if (solver == 'R') {
/* ROE SCHEME */

/* nag_pde_parab_1d_euler_roe (d03puc).
* Roe's approximate Riemann solver for Euler equations in
* conservative form, for use with nag_pde_parab_1d_cd
* (d03pfc), nag_pde_parab_1d_cd_ode (d03plc) and
* nag_pde_parab_1d_cd_ode_remesh (d03psc)
*/
nag_pde_parab_1d_euler_roe(uleft, uright, data->gamma, flux, saved,
&fail);
}
else {
/* OSHER SCHEME */

/* nag_pde_parab_1d_euler_osher (d03pvc).
* Osher's approximate Riemann solver for Euler equations in
* conservative form, for use with nag_pde_parab_1d_cd
* (d03pfc), nag_pde_parab_1d_cd_ode (d03plc) and
* nag_pde_parab_1d_cd_ode_remesh (d03psc)
*/
nag_pde_parab_1d_euler_osher(uleft, uright, data->gamma,
Nag_OsherPhysical, flux, saved, &fail);
}

if (fail.code != NE_NOERROR) {
printf("Error from nag_pde_parab_1d_euler_osher (d03pvc).\n%s\n",
fail.message);
}

return;
}
```