Skip to content

Instantly share code, notes, and snippets.

@agarny
Created January 23, 2020 02:03
Show Gist options
  • Save agarny/5986e9ca05c6bb7158017770fb92e22d to your computer and use it in GitHub Desktop.
Save agarny/5986e9ca05c6bb7158017770fb92e22d to your computer and use it in GitHub Desktop.
idaRoberts_dns without yp0 values and without a Jacobian approximation
/* -----------------------------------------------------------------
* Programmer(s): Allan Taylor, Alan Hindmarsh and
* Radu Serban @ LLNL
* -----------------------------------------------------------------
* SUNDIALS Copyright Start
* Copyright (c) 2002-2020, Lawrence Livermore National Security
* and Southern Methodist University.
* All rights reserved.
*
* See the top-level LICENSE and NOTICE files for details.
*
* SPDX-License-Identifier: BSD-3-Clause
* SUNDIALS Copyright End
* -----------------------------------------------------------------
* This simple example problem for IDA, due to Robertson,
* is from chemical kinetics, and consists of the following three
* equations:
*
* dy1/dt = -.04*y1 + 1.e4*y2*y3
* dy2/dt = .04*y1 - 1.e4*y2*y3 - 3.e7*y2**2
* 0 = y1 + y2 + y3 - 1
*
* on the interval from t = 0.0 to t = 4.e10, with initial
* conditions: y1 = 1, y2 = y3 = 0.
*
* While integrating the system, we also use the rootfinding
* feature to find the points at which y1 = 1e-4 or at which
* y3 = 0.01.
*
* The problem is solved with IDA using the DENSE linear
* solver, with a user-supplied Jacobian. Output is printed at
* t = .4, 4, 40, ..., 4e10.
* -----------------------------------------------------------------*/
#include <stdio.h>
#include <math.h>
#include <ida/ida.h> /* prototypes for IDA fcts., consts. */
#include <nvector/nvector_serial.h> /* access to serial N_Vector */
#include <sunmatrix/sunmatrix_dense.h> /* access to dense SUNMatrix */
#include <sunlinsol/sunlinsol_dense.h> /* access to dense SUNLinearSolver */
#include <sunnonlinsol/sunnonlinsol_newton.h> /* access to Newton SUNNonlinearSolver */
#include <sundials/sundials_types.h> /* defs. of realtype, sunindextype */
#include <sundials/sundials_math.h> /* defs. of SUNRabs, SUNRexp, etc. */
#if defined(SUNDIALS_EXTENDED_PRECISION)
#define GSYM "Lg"
#define ESYM "Le"
#define FSYM "Lf"
#else
#define GSYM "g"
#define ESYM "e"
#define FSYM "f"
#endif
/* Problem Constants */
#define NEQ 3
#define NOUT 12
#define ZERO RCONST(0.0)
#define ONE RCONST(1.0)
/* Prototypes of functions called by IDA */
int resrob(realtype tres, N_Vector yy, N_Vector yp,
N_Vector resval, void *user_data);
/* Prototypes of private functions */
static void PrintHeader(realtype rtol, N_Vector avtol, N_Vector y);
static void PrintOutput(void *mem, realtype t, N_Vector y);
static void PrintFinalStats(void *mem);
static int check_retval(void *returnvalue, const char *funcname, int opt);
static int check_ans(N_Vector y, realtype t, realtype rtol, N_Vector atol);
/*
*--------------------------------------------------------------------
* Main Program
*--------------------------------------------------------------------
*/
int main(void)
{
void *mem;
N_Vector yy, yp, id, avtol;
realtype rtol, *yval, *ypval, *idval, *atval;
realtype t0, tout1, tout, tret;
int iout, retval;
SUNMatrix A;
SUNLinearSolver LS;
SUNNonlinearSolver NLS;
mem = NULL;
yy = yp = id = avtol = NULL;
yval = ypval = idval = atval = NULL;
A = NULL;
LS = NULL;
NLS = NULL;
/* Allocate N-vectors. */
yy = N_VNew_Serial(NEQ);
if(check_retval((void *)yy, "N_VNew_Serial", 0)) return(1);
yp = N_VNew_Serial(NEQ);
if(check_retval((void *)yp, "N_VNew_Serial", 0)) return(1);
id = N_VNew_Serial(NEQ);
if(check_retval((void *)yp, "N_VNew_Serial", 0)) return(1);
avtol = N_VNew_Serial(NEQ);
if(check_retval((void *)avtol, "N_VNew_Serial", 0)) return(1);
/* Create and initialize y, y', id and absolute tolerance vectors. */
yval = N_VGetArrayPointer(yy);
yval[0] = ONE;
yval[1] = ZERO;
yval[2] = ZERO;
ypval = N_VGetArrayPointer(yp);
ypval[0] = ZERO;
ypval[1] = ZERO;
ypval[2] = ZERO;
idval = N_VGetArrayPointer(id);
idval[0] = ONE;
idval[1] = ONE;
idval[2] = ONE;
rtol = RCONST(1.0e-4);
atval = N_VGetArrayPointer(avtol);
atval[0] = RCONST(1.0e-8);
atval[1] = RCONST(1.0e-6);
atval[2] = RCONST(1.0e-6);
/* Integration limits */
t0 = ZERO;
tout1 = RCONST(0.4);
PrintHeader(rtol, avtol, yy);
/* Call IDACreate and IDAInit to initialize IDA memory */
mem = IDACreate();
if(check_retval((void *)mem, "IDACreate", 0)) return(1);
retval = IDASetId(mem, id);
if(check_retval(&retval, "IDASetId", 1)) return(1);
retval = IDAInit(mem, resrob, t0, yy, yp);
if(check_retval(&retval, "IDAInit", 1)) return(1);
retval = IDASetMaxNumSteps(mem, 50000);
if(check_retval(&retval, "IDASetMaxNumSteps", 1)) return(1);
/* Call IDASVtolerances to set tolerances */
retval = IDASVtolerances(mem, rtol, avtol);
if(check_retval(&retval, "IDASVtolerances", 1)) return(1);
/* Create dense SUNMatrix for use in linear solves */
A = SUNDenseMatrix(NEQ, NEQ);
if(check_retval((void *)A, "SUNDenseMatrix", 0)) return(1);
/* Create dense SUNLinearSolver object */
LS = SUNLinSol_Dense(yy, A);
if(check_retval((void *)LS, "SUNLinSol_Dense", 0)) return(1);
/* Attach the matrix and linear solver */
retval = IDASetLinearSolver(mem, LS, A);
if(check_retval(&retval, "IDASetLinearSolver", 1)) return(1);
/* Create Newton SUNNonlinearSolver object. IDA uses a
* Newton SUNNonlinearSolver by default, so it is unecessary
* to create it and attach it. It is done in this example code
* solely for demonstration purposes. */
NLS = SUNNonlinSol_Newton(yy);
if(check_retval((void *)NLS, "SUNNonlinSol_Newton", 0)) return(1);
/* Attach the nonlinear solver */
retval = IDASetNonlinearSolver(mem, NLS);
if(check_retval(&retval, "IDASetNonlinearSolver", 1)) return(1);
/* Call IDACalcIC (with default options) to correct the initial values. */
retval = IDACalcIC(mem, IDA_YA_YDP_INIT, tout1);
if(check_retval(&retval, "IDACalcIC", 1)) return(1);
/* In loop, call IDASolve, print results, and test for error.
Break out of loop when NOUT preset output times have been reached. */
iout = 0; tout = tout1;
while(1) {
retval = IDASolve(mem, tout, &tret, yy, yp, IDA_NORMAL);
PrintOutput(mem,tret,yy);
if(check_retval(&retval, "IDASolve", 1)) return(1);
if (retval == IDA_SUCCESS) {
iout++;
tout *= RCONST(10.0);
}
if (iout == NOUT) break;
}
PrintFinalStats(mem);
/* check the solution error */
retval = check_ans(yy, tret, rtol, avtol);
/* Free memory */
IDAFree(&mem);
SUNNonlinSolFree(NLS);
SUNLinSolFree(LS);
SUNMatDestroy(A);
N_VDestroy(avtol);
N_VDestroy(yy);
N_VDestroy(yp);
N_VDestroy(id);
return(retval);
}
/*
*--------------------------------------------------------------------
* Functions called by IDA
*--------------------------------------------------------------------
*/
/*
* Define the system residual function.
*/
int resrob(realtype tres, N_Vector yy, N_Vector yp, N_Vector rr, void *user_data)
{
realtype *yval, *ypval, *rval;
yval = N_VGetArrayPointer(yy);
ypval = N_VGetArrayPointer(yp);
rval = N_VGetArrayPointer(rr);
rval[0] = RCONST(-0.04)*yval[0] + RCONST(1.0e4)*yval[1]*yval[2];
rval[1] = -rval[0] - RCONST(3.0e7)*yval[1]*yval[1] - ypval[1];
rval[0] -= ypval[0];
rval[2] = yval[0] + yval[1] + yval[2] - ONE;
return(0);
}
/*
*--------------------------------------------------------------------
* Private functions
*--------------------------------------------------------------------
*/
/*
* Print first lines of output (problem description)
*/
static void PrintHeader(realtype rtol, N_Vector avtol, N_Vector y)
{
realtype *atval, *yval;
atval = N_VGetArrayPointer(avtol);
yval = N_VGetArrayPointer(y);
printf("\nidaRoberts_dns: Robertson kinetics DAE serial example problem for IDA\n");
printf(" Three equation chemical kinetics problem.\n\n");
printf("Linear solver: DENSE, with user-supplied Jacobian.\n");
#if defined(SUNDIALS_EXTENDED_PRECISION)
printf("Tolerance parameters: rtol = %Lg atol = %Lg %Lg %Lg \n",
rtol, atval[0],atval[1],atval[2]);
printf("Initial conditions y0 = (%Lg %Lg %Lg)\n",
yval[0], yval[1], yval[2]);
#elif defined(SUNDIALS_DOUBLE_PRECISION)
printf("Tolerance parameters: rtol = %g atol = %g %g %g \n",
rtol, atval[0],atval[1],atval[2]);
printf("Initial conditions y0 = (%g %g %g)\n",
yval[0], yval[1], yval[2]);
#else
printf("Tolerance parameters: rtol = %g atol = %g %g %g \n",
rtol, atval[0],atval[1],atval[2]);
printf("Initial conditions y0 = (%g %g %g)\n",
yval[0], yval[1], yval[2]);
#endif
printf("Constraints and id not used.\n\n");
printf("-----------------------------------------------------------------------\n");
printf(" t y1 y2 y3");
printf(" | nst k h\n");
printf("-----------------------------------------------------------------------\n");
}
/*
* Print Output
*/
static void PrintOutput(void *mem, realtype t, N_Vector y)
{
realtype *yval;
int retval, kused;
long int nst;
realtype hused;
yval = N_VGetArrayPointer(y);
retval = IDAGetLastOrder(mem, &kused);
check_retval(&retval, "IDAGetLastOrder", 1);
retval = IDAGetNumSteps(mem, &nst);
check_retval(&retval, "IDAGetNumSteps", 1);
retval = IDAGetLastStep(mem, &hused);
check_retval(&retval, "IDAGetLastStep", 1);
#if defined(SUNDIALS_EXTENDED_PRECISION)
printf("%10.4Le %12.4Le %12.4Le %12.4Le | %3ld %1d %12.4Le\n",
t, yval[0], yval[1], yval[2], nst, kused, hused);
#elif defined(SUNDIALS_DOUBLE_PRECISION)
printf("%10.4e %12.4e %12.4e %12.4e | %3ld %1d %12.4e\n",
t, yval[0], yval[1], yval[2], nst, kused, hused);
#else
printf("%10.4e %12.4e %12.4e %12.4e | %3ld %1d %12.4e\n",
t, yval[0], yval[1], yval[2], nst, kused, hused);
#endif
}
/*
* Print final integrator statistics
*/
static void PrintFinalStats(void *mem)
{
int retval;
long int nst, nni, nje, nre, nreLS, netf, ncfn, nge;
retval = IDAGetNumSteps(mem, &nst);
check_retval(&retval, "IDAGetNumSteps", 1);
retval = IDAGetNumResEvals(mem, &nre);
check_retval(&retval, "IDAGetNumResEvals", 1);
retval = IDAGetNumJacEvals(mem, &nje);
check_retval(&retval, "IDAGetNumJacEvals", 1);
retval = IDAGetNumNonlinSolvIters(mem, &nni);
check_retval(&retval, "IDAGetNumNonlinSolvIters", 1);
retval = IDAGetNumErrTestFails(mem, &netf);
check_retval(&retval, "IDAGetNumErrTestFails", 1);
retval = IDAGetNumNonlinSolvConvFails(mem, &ncfn);
check_retval(&retval, "IDAGetNumNonlinSolvConvFails", 1);
retval = IDAGetNumLinResEvals(mem, &nreLS);
check_retval(&retval, "IDAGetNumLinResEvals", 1);
retval = IDAGetNumGEvals(mem, &nge);
check_retval(&retval, "IDAGetNumGEvals", 1);
printf("\nFinal Run Statistics: \n\n");
printf("Number of steps = %ld\n", nst);
printf("Number of residual evaluations = %ld\n", nre+nreLS);
printf("Number of Jacobian evaluations = %ld\n", nje);
printf("Number of nonlinear iterations = %ld\n", nni);
printf("Number of error test failures = %ld\n", netf);
printf("Number of nonlinear conv. failures = %ld\n", ncfn);
printf("Number of root fn. evaluations = %ld\n", nge);
}
/*
* Check function return value...
* opt == 0 means SUNDIALS function allocates memory so check if
* returned NULL pointer
* opt == 1 means SUNDIALS function returns an integer value so check if
* retval < 0
* opt == 2 means function allocates memory so check if returned
* NULL pointer
*/
static int check_retval(void *returnvalue, const char *funcname, int opt)
{
int *retval;
/* Check if SUNDIALS function returned NULL pointer - no memory allocated */
if (opt == 0 && returnvalue == NULL) {
fprintf(stderr,
"\nSUNDIALS_ERROR: %s() failed - returned NULL pointer\n\n",
funcname);
return(1);
} else if (opt == 1) {
/* Check if retval < 0 */
retval = (int *) returnvalue;
if (*retval < 0) {
fprintf(stderr,
"\nSUNDIALS_ERROR: %s() failed with retval = %d\n\n",
funcname, *retval);
return(1);
}
} else if (opt == 2 && returnvalue == NULL) {
/* Check if function returned NULL pointer - no memory allocated */
fprintf(stderr,
"\nMEMORY_ERROR: %s() failed - returned NULL pointer\n\n",
funcname);
return(1);
}
return(0);
}
/* compare the solution at the final time 4e10s to a reference solution computed
using a relative tolerance of 1e-8 and absoltue tolerance of 1e-14 */
static int check_ans(N_Vector y, realtype t, realtype rtol, N_Vector atol)
{
int passfail=0; /* answer pass (0) or fail (1) retval */
N_Vector ref; /* reference solution vector */
N_Vector ewt; /* error weight vector */
realtype err; /* wrms error */
/* create reference solution and error weight vectors */
ref = N_VClone(y);
ewt = N_VClone(y);
/* set the reference solution data */
NV_Ith_S(ref,0) = RCONST(5.2083474251394888e-08);
NV_Ith_S(ref,1) = RCONST(2.0833390772616859e-13);
NV_Ith_S(ref,2) = RCONST(9.9999994791631752e-01);
/* compute the error weight vector, loosen atol */
N_VAbs(ref, ewt);
N_VLinearSum(rtol, ewt, RCONST(10.0), atol, ewt);
if (N_VMin(ewt) <= ZERO) {
fprintf(stderr, "\nSUNDIALS_ERROR: check_ans failed - ewt <= 0\n\n");
return(-1);
}
N_VInv(ewt, ewt);
/* compute the solution error */
N_VLinearSum(ONE, y, -ONE, ref, ref);
err = N_VWrmsNorm(ref, ewt);
/* is the solution within the tolerances? */
passfail = (err < ONE) ? 0 : 1;
if (passfail) {
fprintf(stdout, "\nSUNDIALS_WARNING: check_ans error=%"GSYM"\n\n", err);
}
/* Free vectors */
N_VDestroy(ref);
N_VDestroy(ewt);
return(passfail);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment