NAG Library Manual, Mark 30.3
Interfaces:  FL   CL   CPP   AD 

NAG CL Interface Introduction
Example description
/* nag_ode_ivp_rkts_interp (d02psc) Example Program.
 *
 * Copyright 2024 Numerical Algorithms Group.
 *
 * Mark 30.3, 2024.
 */
#include <math.h>
#include <nag.h>

#ifdef __cplusplus
extern "C" {
#endif
static void NAG_CALL f(double t, Integer n, const double *y, double *yp,
                       Nag_Comm *comm);
#ifdef __cplusplus
}
#endif

#define N 2

int main(void) {
  /* Scalars */
  double tol0 = 1.0e-3;
  Integer npts = 16, exit_status = 0;
  Integer liwsav, lrwsav, lwcomm, n;
  double hnext, hstart, tend, tgot, tinc, tol, tstart, twant, waste;
  Integer fevals, i, j, k, stepcost, stepsok;
  /* Arrays */
  static double ruser[1] = {-1.0};
  double *rwsav = 0, *thresh = 0, *ygot = 0, *yinit = 0, *ypgot = 0;
  double *ywant = 0, *ypwant = 0, *wcomm = 0;
  Integer *iwsav = 0;
  char nag_enum_arg[40];
  /* NAG types */
  NagError fail;
  Nag_RK_method method;
  Nag_ErrorAssess errass;
  Nag_SolDeriv reqest = Nag_SolDer;
  Nag_Comm comm;

  INIT_FAIL(fail);

  n = N;
  liwsav = 130;
  lrwsav = 350 + 32 * n;
  lwcomm = 6 * n;
  printf("nag_ode_ivp_rkts_interp (d02psc) Example Program Results\n\n");

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

  if (!(thresh = NAG_ALLOC(n, double)) || !(ygot = NAG_ALLOC(n, double)) ||
      !(yinit = NAG_ALLOC(n, double)) || !(ypgot = NAG_ALLOC(n, double)) ||
      !(ywant = NAG_ALLOC(n, double)) || !(ypwant = NAG_ALLOC(n, double)) ||
      !(iwsav = NAG_ALLOC(liwsav, Integer)) ||
      !(rwsav = NAG_ALLOC(lrwsav, double)) ||
      !(wcomm = NAG_ALLOC((lwcomm), double))) {
    printf("Allocation failure\n");
    exit_status = -1;
    goto END;
  }

  /* Skip heading in data file */
  scanf("%*[^\n] ");

  /* Set initial conditions for ODE and parameters for the integrator. */
  scanf(" %39s%*[^\n] ", nag_enum_arg);
  /* nag_enum_name_to_value (x04nac) Converts NAG enum member name to value. */
  method = (Nag_RK_method)nag_enum_name_to_value(nag_enum_arg);
  scanf(" %39s%*[^\n] ", nag_enum_arg);
  errass = (Nag_ErrorAssess)nag_enum_name_to_value(nag_enum_arg);
  scanf("%lf%lf%*[^\n] ", &tstart, &tend);

  for (j = 0; j < n; j++)
    scanf("%lf", &yinit[j]);
  scanf("%*[^\n] ");
  scanf("%lf%*[^\n] ", &hstart);
  for (j = 0; j < n; j++)
    scanf("%lf", &thresh[j]);
  scanf("%*[^\n] ");

  tinc = (tend - tstart) / (double)(npts);
  tol = tol0;
  for (i = 1; i <= 2; i++) {
    tol = tol * 0.1;
    /* Initialize Runge-Kutta method for integrating ODE using
     * nag_ode_ivp_rkts_setup (d02pqc).
     */
    nag_ode_ivp_rkts_setup(n, tstart, tend, yinit, tol, thresh, method, errass,
                           hstart, iwsav, rwsav, &fail);
    if (fail.code != NE_NOERROR) {
      printf("Error from nag_ode_ivp_rkts_setup (d02pqc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

    printf(" Calculation with tol = %8.1e\n", tol);
    printf("    t          y1        y1'\n");
    printf("%6.3f", tstart);
    for (k = 0; k < n; k++)
      printf("   %8.4f", yinit[k]);
    printf("\n");

    /* Set up first point at which solution is desired. */
    twant = tstart + tinc;
    tgot = tstart;
    /* Integrate by by single steps until tend is reached or error is
     * encountered. Solution is required at regular increments, requiring
     * interpolation on those steps that pass over the regulat grid values
     * of t.
     */
    while (tgot < tend) {
      /* Solve ODE by Runge-Kutta method by a sequence of single steps using
       * nag_ode_ivp_rkts_onestep (d02pfc).
       */
      nag_ode_ivp_rkts_onestep(f, n, &tgot, ygot, ypgot, &comm, iwsav, rwsav,
                               &fail);
      if (fail.code != NE_NOERROR) {
        printf("Error from nag_ode_ivp_rkts_onestep (d02pfc).\n%s\n",
               fail.message);
        exit_status = 2;
        goto END;
      }

      /* Interpolate onto those grid values passed over in by last step. */
      while (twant <= tgot) {
        /* Interpolate at t = twant, given solution by
         * nag_ode_ivp_rkts_onestep (d02pfc), using
         * nag_ode_ivp_rkts_interp (d02psc).
         */
        nag_ode_ivp_rkts_interp(n, twant, reqest, n, ywant, ypwant, f, wcomm,
                                lwcomm, &comm, iwsav, rwsav, &fail);
        if (fail.code != NE_NOERROR) {
          printf("Error from nag_ode_ivp_rkts_interp (d02psc).\n%s\n",
                 fail.message);
          exit_status = 3;
          goto END;
        }
        printf("%6.3f   %8.4f   %8.4f\n", twant, ywant[0], ypwant[0]);
        /* Set next required solution point. */
        twant = twant + tinc;
      }
    }
    /* Get diagnostics on whole integration using
     * nag_ode_ivp_rkts_diag (d02ptc).
     */
    nag_ode_ivp_rkts_diag(&fevals, &stepcost, &waste, &stepsok, &hnext, iwsav,
                          rwsav, &fail);
    if (fail.code != NE_NOERROR) {
      printf("Error from nag_ode_ivp_rkts_diag (d02ptc).\n%s\n", fail.message);
      exit_status = 4;
      goto END;
    }
    printf("Cost of the integration in evaluations of f is %6" NAG_IFMT "\n\n",
           fevals);
  }
END:
  NAG_FREE(thresh);
  NAG_FREE(yinit);
  NAG_FREE(ygot);
  NAG_FREE(ypgot);
  NAG_FREE(ywant);
  NAG_FREE(ypwant);
  NAG_FREE(rwsav);
  NAG_FREE(iwsav);
  NAG_FREE(wcomm);
  return exit_status;
}

static void NAG_CALL f(double t, Integer n, const double *y, double *yp,
                       Nag_Comm *comm) {
  if (comm->user[0] == -1.0) {
    printf("(User-supplied callback f, first invocation.)\n");
    comm->user[0] = 0.0;
  }
  yp[0] = y[1];
  yp[1] = -y[0];
}