Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

1812 linhas
52KB

  1. /*
  2. sensBVP: A program that calculates the sensitivity of ignition delay time to
  3. kinetic rate parameters by using a boundary value problem formulation.
  4. Copyright (C) 2019 Vyaas Gururajan
  5. This program is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free Software
  7. Foundation; either version 2 of the License, or (at your option) any later
  8. version.
  9. This program is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
  11. PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along with
  13. this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
  14. Street, Fifth Floor, Boston, MA 02110-1301, USA.
  15. */
  16. #include <stdbool.h>
  17. #include <math.h>
  18. #include <stdio.h>
  19. #include <unistd.h>
  20. #include <string.h>
  21. #include <time.h>
  22. /*Cantera include files*/
  23. #include "IdealGasMix.h"
  24. /*Sundials include files*/
  25. #include <cvode/cvode.h> /* prototypes for CVODE fcts., consts. */
  26. #include <nvector/nvector_serial.h> /* access to serial N_Vector */
  27. #include <sunmatrix/sunmatrix_dense.h> /* access to dense SUNMatrix */
  28. #include <sunlinsol/sunlinsol_dense.h> /* access to dense SUNLinearSolver */
  29. #include <cvode/cvode_direct.h> /* access to CVDls interface */
  30. #include <sundials/sundials_types.h> /* defs. of realtype, sunindextype */
  31. #include <sundials/sundials_math.h>
  32. #include <kinsol/kinsol.h> /* access to KINSOL func., consts. */
  33. //#include <kinsol/kinsol_impl.h> /* access to KINSOL data structs */
  34. #include <sunmatrix/sunmatrix_band.h> /* access to band SUNMatrix */
  35. #include <kinsol/kinsol_direct.h> /* access to KINDls interface */
  36. #include <sunlinsol/sunlinsol_band.h> /* access to band SUNLinearSolver */
  37. //#include <sunlinsol/sunlinsol_lapackband.h> /* access to band SUNLinearSolver */
  38. #include <gsl/gsl_math.h>
  39. #include <gsl/gsl_spline.h>
  40. static int imaxarg1,imaxarg2;
  41. #define IMAX(a,b) (imaxarg1=(a),imaxarg2=(b),(imaxarg1) > (imaxarg2) ?\
  42. (imaxarg1) : (imaxarg2))
  43. static int iminarg1,iminarg2;
  44. #define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\
  45. (iminarg1) : (iminarg2))
  46. /*quick-sort related routines*/
  47. static unsigned long *lvector(long nl, long nh);
  48. static void free_lvector(unsigned long *v, long nl, long nh);
  49. static void sort(unsigned long n, double arr[], int ind[]);
  50. #define ZERO RCONST(0.0)
  51. #define HALF RCONST(0.5)
  52. #define ONE RCONST(1.0)
  53. #define TWO RCONST(2.0)
  54. #define THREE RCONST(3.0)
  55. #define TEN RCONST(10.0)
  56. #define BUFSIZE 1000
  57. /* In order to keep begin the index numbers from 1 instead of 0, we define
  58. * macros here. Also, we define macros to ease referencing various variables in
  59. * the sundials nvector.
  60. */
  61. #define Y0(k) NV_Ith_S(data->Y0,k-1)
  62. #define x(i) NV_Ith_S(data->x,i-1)
  63. #define t(i) NV_Ith_S(data->tArray,i)
  64. #define P(i) NV_Ith_S(data->PArray,i)
  65. #define dPdt(i) NV_Ith_S(data->dPdtArray,i)
  66. #define T(i) NV_Ith_S(y,((i-1)*data->nvar)+data->nt)
  67. #define Y(i,k) NV_Ith_S(y,((i-1)*data->nvar)+data->ny+k-1)
  68. #define Tdot(i) NV_Ith_S(ydot,((i-1)*data->nvar)+data->nt)
  69. #define Ydot(i,k) NV_Ith_S(ydot,((i-1)*data->nvar)+data->ny+k-1)
  70. #define Ttemp(i) NV_Ith_S(ytemp,((i-1)*(data->nvar+1))+data->nt)
  71. #define Ytemp(i,k) NV_Ith_S(ytemp,((i-1)*(data->nvar+1))+data->ny+k-1)
  72. #define tautemp(i) NV_Ith_S(ytemp,((i-1)*(data->nvar+1))+data->ntau)
  73. #define Tp(i) NV_Ith_S(yp,((i-1)*(data->nvar+1))+data->nt)
  74. #define Yp(i,k) NV_Ith_S(yp,((i-1)*(data->nvar+1))+data->ny+k-1)
  75. #define taup(i) NV_Ith_S(yp,((i-1)*(data->nvar+1))+data->ntau)
  76. #define Pp(i) NV_Ith_S(data->Pp,i-1)
  77. #define dPdtp(i) NV_Ith_S(data->dPdtp,i-1)
  78. #define Tres(i) NV_Ith_S(res,((i-1)*(data->nvar+1))+data->nt)
  79. #define Yres(i,k) NV_Ith_S(res,((i-1)*(data->nvar+1))+data->ny+k-1)
  80. #define taures(i) NV_Ith_S(res,((i-1)*(data->nvar+1))+data->ntau)
  81. #define tautmp1(i) NV_Ith_S(tmp1,((i-1)*(data->nvar+1))+data->ntau)
  82. #define tautmp2(i) NV_Ith_S(tmp2,((i-1)*(data->nvar+1))+data->ntau)
  83. #define wdot(i) wdot[i-1]
  84. #define enthalpy(i) enthalpy[i-1]
  85. typedef struct {
  86. /* This structure contains all information relevant to evaluating the
  87. * residue.
  88. */
  89. Cantera::IdealGasMix* gas;//Ideal gas object containing thermodynamic and
  90. //kinetic data
  91. realtype P; //Pressure (in Pascals)
  92. realtype T0; //Initial Temperature (in K)
  93. N_Vector Y0; //Initial Mass Fractions
  94. realtype rho0; //initial density
  95. realtype TIgnFac; //factor that determines the ignition
  96. //temperature: should be anywhere between 0 and 1 where 0 corresponds to the
  97. //initial temperature and 1 corresponds to adiabatic flame
  98. //temperature
  99. realtype TIgn; //Ignition Temperature (in K)
  100. realtype tauIgn; //Ignition delay time (in s)
  101. N_Vector x; //The grid
  102. N_Vector tArray;
  103. N_Vector PArray;
  104. N_Vector dPdtArray;
  105. N_Vector Pp;
  106. N_Vector dPdtp;
  107. realtype dPdt;
  108. int tArraySize;
  109. bool constantVolume; //boolean to enable/disable constant volume
  110. //version of the ignition delay problem
  111. bool imposedPdt; //boolean to enable/disable manual entry for P and dPdt
  112. int jguess; //saved index to accelerate lookup via "hunt"
  113. bool writeSpeciesSensitivities; //boolean to enable/disable writing
  114. //of species sensitivities
  115. bool IVPSuccess;
  116. bool BVPSuccess;
  117. bool sensSuccess;
  118. bool solveBVP; //The BVP does not HAVE to be solved: use this flag to skip solving it!
  119. int nsp,neq,npts,nvar; //key quantities required in for loops:
  120. //nsp-> no: of chemical species
  121. //neq-> number of governing equations
  122. //npts-> no: of grid points
  123. //nvar->no: of variables
  124. int nt,ny,ntau; //array indices for various variables:
  125. //nt-> temperature (0)
  126. //ny-> species mass fractions
  127. //ntau-> ignition delay time
  128. int KSneq; //No: of equations in the BVP formulation of
  129. //the ignition delay problem
  130. realtype rel; //the relative perturbation factor used in
  131. //computing difference quotients
  132. realtype atol;
  133. realtype rtol;
  134. realtype ftol;
  135. realtype t1; //Maximum time to run simulation
  136. int nreac;
  137. int pert_index; //index of reaction whose rate is perturbed
  138. bool sensitivityAnalysis;// boolean to activate perturbations for
  139. //sensitivity analysis
  140. bool sort; //boolean to activate sorting
  141. bool sens; //if true, perform sensitivity analysis
  142. FILE *output; //output file for temperature and species profiles
  143. FILE *ignSensOutput; //output file for ignition sensitivities
  144. FILE *speSensOutput; //output file for species sensitivities
  145. FILE *dPdtInput; //output file for species sensitivities
  146. gsl_interp_accel* acc;
  147. gsl_interp_accel* accdot;
  148. gsl_spline* spline;
  149. gsl_spline* splinedot;
  150. } *UserData;
  151. /* Set the initial conditions using this subroutine: */
  152. static int setInitialProfile(UserData data, N_Vector y);
  153. /* Evaluate the residue for the IVP using this subroutine: */
  154. static int residue(realtype t, N_Vector y, N_Vector ydot, void *user_data);
  155. /* Evaluate the residue for the BVP using this subroutine: */
  156. static int residueKS(N_Vector yp, N_Vector res, void *user_data);
  157. static int parseInput(UserData data, int argc, char *argv[]);
  158. static int hunt(realtype x, realtype xx[], int n, int jguess);
  159. static void polint(realtype *xdata, realtype *f, int n, realtype x,realtype *y, realtype *dy);
  160. static void lookupDpdt(UserData data, realtype t, realtype *P, realtype *dPdt);
  161. /* Subroutine to compute the Jacobian using numerical differencing: */
  162. static int kinDlsBandDQJac(N_Vector u, N_Vector fu, SUNMatrix Jac, UserData data, N_Vector scale, N_Vector tmp1, N_Vector tmp2);
  163. /* Subroutine that prints the column titles in the output file: */
  164. static void printInstructions();
  165. /* Subroutine that prints the column titles in the output file: */
  166. static void printHeader(UserData data);
  167. static void printSensitivitiesHeader(UserData data);
  168. /* Subroutine that prints the output of the IVP into the output file contained
  169. * in the UserData structure: */
  170. static void printOutput(realtype t, N_Vector y, UserData data);
  171. /* Subroutine that prints the output of the BVP into the output file contained
  172. * in the UserData structure: */
  173. //static void printOutputKS(N_Vector yp, UserData data);
  174. /* Subroutine that prints the residue of the BVP into the output file contained
  175. * in the UserData structure: */
  176. //static void printResidueKS(N_Vector res, UserData data);
  177. /* Subroutine that prints the species sensitivities into the output file
  178. * (speSensOutput) contained in the UserData structure: */
  179. static void printSpeciesSensitivities(int index, N_Vector yp, N_Vector res, UserData data);
  180. /* Subroutine that prints the sensitivities into the output file (ignSensOutput)
  181. * contained in the UserData structure: */
  182. static void printIgnSensitivities(realtype sensCoeffs[], int indices[], UserData data);
  183. static int parsedPdt(UserData data);
  184. /* Print solver statistics for the IVP: */
  185. static void PrintFinalStats(void *cvode_mem);
  186. /* Print solver statistics for the BVP: */
  187. static void PrintFinalStatsKS(void *kmem);
  188. /* Subroutine that reports failure if memory hasn't been successfully allocated
  189. * to various objects: */
  190. static int check_flag(void *flagvalue, const char *funcname, int opt);
  191. int main(int argc, char *argv[])
  192. {
  193. clock_t start, end;
  194. double cpu_time_used;
  195. start = clock();
  196. int ier; //error flag
  197. UserData data; //User defined data
  198. data = NULL;
  199. /* Create and load problem data block. */
  200. data = (UserData) malloc(sizeof *data);
  201. ier=parseInput(data,argc,argv);
  202. if(ier==-1)return(-1);
  203. /* Set the maximum number of time-steps that will be used in the BVP
  204. * formulation of the problem: */
  205. int nout=50000;
  206. /* Create a temporary solution array to save the results of the IVP for
  207. * use in the BVP:*/
  208. N_Vector ytemp;
  209. data->npts=nout;
  210. data->KSneq=(data->nvar+1)*data->npts;
  211. ytemp=N_VNew_Serial(data->KSneq);
  212. {
  213. /* Solver Memory:*/
  214. void *mem;
  215. mem=NULL;
  216. /* Save the initial mass fractions: */
  217. data->Y0=N_VNew_Serial(data->nsp);
  218. for(int k=1;k<=data->nsp;k++){
  219. Y0(k)=data->gas->massFraction(k-1);
  220. }
  221. /*Assign variable indices:*/
  222. data->nt=0;
  223. data->ny=data->nt+1;
  224. data->ntau=data->ny+data->nsp;
  225. /*Get and save the no: of reactions:*/
  226. data->nreac=data->gas->nReactions();
  227. /* Solution vector of the IVP: */
  228. N_Vector y;
  229. y = NULL;
  230. y = N_VNew_Serial(data->neq);
  231. ier=check_flag((void *)y, "N_VNew_Serial", 0);
  232. realtype t0, tret; //times
  233. t0=tret=ZERO;
  234. /*Set the initial values:*/
  235. setInitialProfile(data, y);
  236. /*Print out the column names and the initial values:*/
  237. printHeader(data);
  238. printOutput(0.0e0,y,data);
  239. /* Create a CVode solver object for solution of the IVP: */
  240. //mem = CVodeCreate(CV_BDF,CV_NEWTON);
  241. mem = CVodeCreate(CV_BDF);
  242. ier=check_flag((void *)mem, "CVodeCreate", 0);
  243. /*Associate the user data with the solver object: */
  244. ier = CVodeSetUserData(mem, data);
  245. ier=check_flag(&ier, "CVodeSetUserData", 1);
  246. /* Initialize the solver object by connecting it to the solution vector
  247. * y: */
  248. ier = CVodeInit(mem, residue, t0, y);
  249. ier=check_flag(&ier, "CVodeInit", 1);
  250. /*Set the tolerances: */
  251. ier = CVodeSStolerances(mem, data->rtol, data->atol);
  252. ier=check_flag(&ier, "IDASStolerances", 1);
  253. /* Create dense SUNMatrix for use in linear solves: */
  254. SUNMatrix A;
  255. A = SUNDenseMatrix(data->neq, data->neq);
  256. ier=check_flag((void *)A, "SUNDenseMatrix", 0);
  257. /* Create dense SUNLinearSolver object for use by CVode: */
  258. SUNLinearSolver LS;
  259. LS = SUNDenseLinearSolver(y, A);
  260. ier=check_flag((void *)LS, "SUNDenseLinearSolver", 0);
  261. /* Call CVDlsSetLinearSolver to attach the matrix and linear solver to
  262. * CVode: */
  263. ier = CVDlsSetLinearSolver(mem, LS, A);
  264. ier=check_flag(&ier, "CVDlsSetLinearSolver", 1);
  265. /* Use a difference quotient Jacobian: */
  266. ier = CVDlsSetJacFn(mem, NULL);
  267. ier=check_flag(&ier, "CVDlsSetJacFn", 1);
  268. /*Save the initial values in the temporary solution vector:*/
  269. Ttemp(1)=T(1);
  270. for(int k=1;k<=data->nsp;k++){
  271. Ytemp(1,k)=Y(1,k);
  272. }
  273. tautemp(1)=tret;
  274. /*Begin IVP solution; Save solutions in the temporary solution vector;
  275. * stop problem when the temperature reaches a certain value (like 400
  276. * K) corresponding to the time for ignition :*/
  277. int i=1;
  278. bool BVPCutOff=false;
  279. int skip=10;
  280. int count=0;
  281. while (tret<=data->t1) {
  282. if(i<data->npts){
  283. if(!BVPCutOff){
  284. Ttemp(i+1)=T(1);
  285. for(int k=1;k<=data->nsp;k++){
  286. Ytemp(i+1,k)=Y(1,k);
  287. }
  288. tautemp(i+1)=tret;
  289. }
  290. }
  291. else{
  292. printf("Need more points!\n");
  293. printf("Hard-coded npts=%d not enough!\n",data->npts);
  294. data->IVPSuccess=false;
  295. break;
  296. }
  297. if(T(1)>=data->TIgn && !BVPCutOff){
  298. printf("Ignition Delay: %15.6es\n", tret);
  299. BVPCutOff=true;
  300. }
  301. ier = CVode(mem, data->t1, y, &tret, CV_ONE_STEP);
  302. if(check_flag(&ier, "CVode", 1)) {
  303. data->IVPSuccess=false;
  304. break;
  305. }
  306. else{
  307. data->IVPSuccess=true;
  308. }
  309. printOutput(tret,y,data);
  310. count++;
  311. if(tret>1e-06 && !BVPCutOff && count%skip==0){
  312. i++;
  313. count=0;
  314. }
  315. }
  316. data->npts=i;
  317. data->KSneq=(data->nvar+1)*data->npts;
  318. /* Print remaining counters and free memory. */
  319. PrintFinalStats(mem);
  320. CVodeFree(&mem);
  321. N_VDestroy_Serial(y);
  322. }
  323. /*Create a solution vector yp, dimensioned such that the maximum no: of
  324. * grid points associated with it is the no: of time-steps (i) used
  325. * above. Fill in its values using the temporary solution vector. */
  326. N_Vector yp;
  327. if(data->IVPSuccess){
  328. yp=N_VNew_Serial(data->KSneq);
  329. for(int j=1;j<=data->npts;j++){
  330. Tp(j)=Ttemp(j);
  331. for(int k=1;k<=data->nsp;k++){
  332. if(fabs(Ytemp(j,k))>1e-16){
  333. Yp(j,k)=Ytemp(j,k);
  334. }
  335. else{
  336. Yp(j,k)=ZERO;
  337. }
  338. }
  339. taup(j)=tautemp(j);
  340. }
  341. data->tauIgn=taup(data->npts); //Save the ignition delay time
  342. data->TIgn=Tp(data->npts); //Save the temperature corresponding to
  343. //the ignition delay
  344. /* Create a grid (in time) to be used in the solution of the BVP: */
  345. data->x = N_VNew_Serial(data->npts);
  346. if(check_flag((void *)data->x, "N_VNew_Serial", 0)) return(1);
  347. if(data->imposedPdt){
  348. data->Pp = N_VNew_Serial(data->npts);
  349. if(check_flag((void *)data->Pp, "N_VNew_Serial", 0)) return(1);
  350. data->dPdtp = N_VNew_Serial(data->npts);
  351. if(check_flag((void *)data->dPdtp, "N_VNew_Serial", 0)) return(1);
  352. }
  353. realtype P,dPdt;
  354. for (int j = 1; j <=data->npts; j++) {
  355. if(data->imposedPdt){
  356. //P=dPdt=ZERO;
  357. lookupDpdt(data, taup(j), &P, &dPdt);
  358. Pp(j)=P*Cantera::OneAtm;
  359. dPdtp(j)=dPdt*Cantera::OneAtm;
  360. //printf("%15.6e\t%15.6e\n",Pp(j),dPdtp(j));
  361. }
  362. x(j)=taup(j)/data->tauIgn;
  363. taup(j)=data->tauIgn;
  364. }
  365. if(data->tArray!=NULL){
  366. N_VDestroy_Serial(data->tArray);
  367. }
  368. if(data->PArray!=NULL){
  369. N_VDestroy_Serial(data->PArray);
  370. }
  371. if(data->dPdtArray!=NULL){
  372. N_VDestroy_Serial(data->dPdtArray);
  373. }
  374. //printOutputKS(yp,data);
  375. }
  376. N_VDestroy_Serial(ytemp); //Destroy the temporary solution vector
  377. printf("No: of time-steps: %d\n",data->npts);
  378. /********************************************************/
  379. /*Begin solution of the BVP here:*/
  380. if(data->IVPSuccess && data->sens){
  381. /*Create a KINSOL solver object for the solution of the BVP:*/
  382. /* Solver Memory:*/
  383. void *mem; mem = NULL;
  384. mem = KINCreate();
  385. //if (check_flag((void *)mem, "KINCreate", 0)) return(1);
  386. /*Associate the user data with the solver object: */
  387. ier = KINSetUserData(mem, data);
  388. ier=check_flag(&ier, "KINSetUserData", 1);
  389. /* Initialize the solver object by connecting it to the solution vector
  390. * yp and the residue "residueKS": */
  391. ier = KINInit(mem, residueKS, yp);
  392. ier = check_flag(&ier, "KINInit", 1);
  393. /* Specify stopping tolerance based on residual: */
  394. ier = KINSetFuncNormTol(mem, data->ftol);
  395. ier = check_flag(&ier, "KINSetFuncNormTol", 1);
  396. /* Create banded SUNMatrix for use in linear solves; bandwidths are
  397. * dictated by the dependence of the solution at a given time on one
  398. * time-step ahead and one time-step behind:*/
  399. SUNMatrix J;
  400. int mu,ml;
  401. mu = data->nvar+2; ml = data->nvar+2;
  402. //J = SUNBandMatrix(data->KSneq, mu, ml, mu+ml);
  403. J = SUNBandMatrix(data->KSneq, mu, ml);
  404. ier = check_flag((void *)J, "SUNBandMatrix", 0);
  405. /* Create dense SUNLinearSolver object for use by KINSOL: */
  406. SUNLinearSolver LSK;
  407. LSK = SUNBandLinearSolver(yp, J);
  408. ier = check_flag((void *)LSK, "SUNBandLinearSolver", 0);
  409. /* Call KINDlsSetLinearSolver to attach the matrix and linear solver to
  410. * KINSOL: */
  411. ier = KINDlsSetLinearSolver(mem, LSK, J);
  412. ier = check_flag(&ier, "KINDlsSetLinearSolver", 1);
  413. /* No scaling used: */
  414. N_Vector scale;
  415. scale=NULL;
  416. scale = N_VNew_Serial(data->KSneq);
  417. //ier = check_flag((void *)scale, "N_VNew_Serial", 0);
  418. N_VConst_Serial(ONE,scale);
  419. /* Force a Jacobian re-evaluation every mset iterations: */
  420. int mset = 100;
  421. ier = KINSetMaxSetupCalls(mem, mset);
  422. //ier = check_flag(&ier, "KINSetMaxSetupCalls", 1);
  423. /* Every msubset iterations, test if a Jacobian evaluation
  424. is necessary: */
  425. int msubset = 1;
  426. ier = KINSetMaxSubSetupCalls(mem, msubset);
  427. //ier = check_flag(&ier, "KINSetMaxSubSetupCalls", 1);
  428. ier=KINSetPrintLevel(mem,2);
  429. /* Solve the BVP! */
  430. if(data->solveBVP){
  431. ier = KINSol(mem, /* KINSol memory block */
  432. yp, /* initial guess on input; solution vector */
  433. KIN_NONE,//KIN_LINESEARCH,/* global strategy choice */
  434. scale, /* scaling vector, for the variable cc */
  435. scale); /* scaling vector for function values fval */
  436. if (check_flag(&ier, "KINSol", 1)){
  437. data->BVPSuccess=false;
  438. }else{
  439. data->BVPSuccess=true;
  440. /* Get scaled norm of the system function */
  441. ier = KINGetFuncNorm(mem, &data->ftol);
  442. //ier = check_flag(&ier, "KINGetfuncNorm", 1);
  443. printf("\nComputed solution (||F|| = %g):\n\n",data->ftol);
  444. printf("KinSOL Ignition Delay: %15.6es\n", taup(1));
  445. }
  446. }
  447. //ier=check_flag(&ier, "KINSol", 1);
  448. //printOutputKS(yp,data);
  449. fclose(data->output);
  450. PrintFinalStatsKS(mem);
  451. KINFree(&mem);
  452. N_VDestroy_Serial(scale);
  453. }
  454. /********************************************************/
  455. /*Begin sensitivity analysis here:*/
  456. if(data->BVPSuccess || !data->solveBVP){
  457. /* Create banded SUNMatrix for use in linear solves; bandwidths
  458. * are dictated by the dependence of the solution at a given
  459. * time on one time-step ahead and one time-step behind:*/
  460. SUNMatrix J;
  461. int mu,ml;
  462. mu = data->nvar+1; ml = data->nvar+1;
  463. //J = SUNBandMatrix(data->KSneq, mu, ml, mu+ml);
  464. J = SUNBandMatrix(data->KSneq, mu, ml);
  465. ier = check_flag((void *)J, "SUNBandMatrix", 0);
  466. /*Create a residue vector and two temporary vectors:*/
  467. N_Vector res,tmp1,tmp2, scale;
  468. res=N_VNew_Serial(data->KSneq);
  469. tmp1=N_VNew_Serial(data->KSneq);
  470. tmp2=N_VNew_Serial(data->KSneq);
  471. scale = N_VNew_Serial(data->KSneq);
  472. N_VConst_Serial(ONE,scale);
  473. /*Evaluate the residue using the solution computed by solving
  474. * the BVP above:*/
  475. ier = residueKS(yp, res, data);
  476. ier = check_flag(&ier, "residueKS", 1);
  477. //printResidueKS(res,data);
  478. /*Compute the Jacobian and store it in J:*/
  479. kinDlsBandDQJac(yp, res, J, data, scale, tmp1, tmp2);
  480. /*Create a linear solver object for the banded system; in the
  481. * problem Ax=b, A is J and x is tmp2:*/
  482. SUNLinearSolver LS;
  483. LS = SUNBandLinearSolver(res, J);
  484. /*Initialize the solver and perform an LU factorization by
  485. * running SUNLinSolSetup:*/
  486. ier = SUNLinSolInitialize_Band(LS);
  487. ier = check_flag(&ier, "SUNLinSolInitialize", 1);
  488. ier = SUNLinSolSetup_Band(LS,J);
  489. ier = check_flag(&ier, "SUNLinSolSetup", 1);
  490. /*Create an array to store the logarithmic sensitivity
  491. * coefficients:*/
  492. realtype sensCoeffs[data->nreac];
  493. /*Create an array to store the indices of the reactions (needed
  494. * for sorting the sensitivity coefficients):*/
  495. int indices[data->nreac];
  496. /*The sensitivities are computed as follows:
  497. * For a system equations
  498. * F(y;α)=0
  499. * where F is the residue of the BVP
  500. * y is the solution of the BVP
  501. * α is a parameter
  502. * => (∂F/∂y)(∂y/∂α)+(∂F/∂α) = 0
  503. * => (∂F/∂y)(∂y/∂α)=-(∂F/∂α)
  504. * Therefore, the sensitivity coefficient (∂y/∂α) can be
  505. * computed by solving a system Ax=b, where A=(∂F/∂y),
  506. * x=(∂y/∂α), and b=-(∂F/∂α)!*/
  507. /*Run a loop over all the reactions: */
  508. printf("\nRunning Sensitivity Analysis...\n");
  509. /*Enable sensitivity analysis:*/
  510. data->sensitivityAnalysis=true;
  511. realtype oneOverRel=ONE/(data->rel);
  512. for(int j=0;j<data->nreac;j++){
  513. /*Save the index of the reaction whose collision
  514. * frequency (A in the Arrhenius law k=A*exp(-Eₐ/RT))
  515. * is to be perturbed:*/
  516. data->pert_index=j;
  517. /*Compute the perturbed residue and store it in tmp1:*/
  518. ier=residueKS(yp, tmp1, data);
  519. ier=check_flag(&ier, "residueKS", 1);
  520. //printResidueKS(tmp1,data);
  521. /*Compute the difference F(α+Δα)-F(α) and store it in
  522. * tmp2:*/
  523. N_VLinearSum(ONE,tmp1,-ONE,res,tmp2);
  524. /*Divide the difference quotient by -Δα and store the
  525. * result in tmp1. This is the numerical approximation
  526. * to -(∂F/∂α):*/
  527. N_VScale(-oneOverRel,tmp2,tmp1);
  528. /*Solve the linear system (thankfully the LU
  529. * factiorization has already been carried out once and
  530. * for all above!) and store the solution in tmp2:*/
  531. ier=SUNLinSolSolve_Band(LS,J,tmp2,tmp1,ZERO);
  532. ier=check_flag(&ier, "SUNLinSolSolve", 1);
  533. /*Divide the result by the ignition delay time to get
  534. * the logarithmic sensitivity coefficient and save it
  535. * in sensCoeffs:*/
  536. sensCoeffs[j]=tautmp2(1)/taup(1);
  537. if(sensCoeffs[j]!=sensCoeffs[j]){
  538. printf("\nNaN! Quitting Program! Try different tolerances!\n");
  539. data->sensSuccess=false;
  540. break;
  541. }else{
  542. data->sensSuccess=true;
  543. printf("Reaction %5d: %15.6e\n",j,sensCoeffs[j]);
  544. }
  545. /*Print out the temperature and species mass-fraction
  546. * sensitivities:*/
  547. if(data->writeSpeciesSensitivities){
  548. printSpeciesSensitivities(j, yp, tmp2, data);
  549. }
  550. /*Save the index of the reaction:*/
  551. indices[j]=j;
  552. }
  553. if(data->sensSuccess){
  554. /*Sort the sensitivities in ascending order. Note the advancing
  555. * of the beginning indices of the sensCoeffs and indices
  556. * arrays. This is due to the Numerical recipes convention for
  557. * array indexing used in sort subroutine:*/
  558. if(data->sort){
  559. sort(data->nreac,sensCoeffs-1,indices-1);
  560. }
  561. /*Print out the sensitivities:*/
  562. printIgnSensitivities(sensCoeffs,indices,data);
  563. }
  564. N_VDestroy_Serial(scale);
  565. N_VDestroy_Serial(res);
  566. N_VDestroy_Serial(tmp1);
  567. N_VDestroy_Serial(tmp2);
  568. fclose(data->ignSensOutput);
  569. fclose(data->speSensOutput);
  570. }
  571. /*Free memory and delete all the vectors and user data:*/
  572. if(yp!=NULL){
  573. N_VDestroy_Serial(yp);
  574. printf("BVP Solution Vector Deleted!\n");
  575. }
  576. if(data->Y0!=NULL){
  577. N_VDestroy_Serial(data->Y0);
  578. printf("Initial Mass fraction Vector Deleted!\n");
  579. }
  580. if(data->x!=NULL){
  581. N_VDestroy_Serial(data->x);
  582. printf("Grid for BVP deleted!\n");
  583. }
  584. if(data->Pp!=NULL){
  585. N_VDestroy_Serial(data->Pp);
  586. printf("P array deleted!\n");
  587. }
  588. if(data->dPdtp!=NULL){
  589. N_VDestroy_Serial(data->dPdtp);
  590. printf("dPdt array deleted!\n");
  591. }
  592. if(data->gas!=NULL){
  593. delete data->gas;
  594. printf("Gas Deleted!\n");
  595. }
  596. if(data->imposedPdt){
  597. if(data->acc!=NULL){
  598. gsl_interp_accel_free(data->acc);
  599. }
  600. if(data->accdot!=NULL){
  601. gsl_interp_accel_free(data->accdot);
  602. }
  603. if(data->spline!=NULL){
  604. gsl_spline_free(data->spline);
  605. }
  606. if(data->splinedot!=NULL){
  607. gsl_spline_free(data->splinedot);
  608. }
  609. }
  610. if(data!=NULL){
  611. /* Free the user data */
  612. free(data);
  613. printf("User data structure deleted!\n");
  614. }
  615. end = clock();
  616. cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
  617. printf("Elapsed cpu time: %15.6e s\n", cpu_time_used);
  618. return(0);
  619. }
  620. static int parseInput(UserData data, int argc, char *argv[]){
  621. /*Set defaults here:*/
  622. /*****************************************************/
  623. /*Relative tolerance for IVP:*/
  624. data->rtol = RCONST(1e-14);
  625. /*Absolute tolerance for IVP:*/
  626. data->atol = RCONST(1e-14);
  627. /*Residue tolerance for BVP:*/
  628. data->ftol = RCONST(1e-13);
  629. /*Final Time:*/
  630. data->t1 = RCONST(10.0);
  631. /*Solve constant pressure problem:*/
  632. data->constantVolume=false;
  633. /*Do not impose a P vs t curve:*/
  634. data->imposedPdt=false;
  635. /*Disable writing species sensitivities:*/
  636. data->writeSpeciesSensitivities=false;
  637. /*Enable sensitivity analysis:*/
  638. data->sens=false;
  639. /*Index to start with for pressure lookup (see hunt):*/
  640. data->jguess=0;
  641. /*Set rate of change of pressure to zero:*/
  642. data->dPdt=ZERO;
  643. /*Disable sensitivity analysis:*/
  644. data->sensitivityAnalysis=false;
  645. /*Find the relative perturbation constant:*/
  646. data->rel=SUNRsqrt(UNIT_ROUNDOFF);
  647. /*Set flags that indicate success of various stages:*/
  648. data->IVPSuccess=false;
  649. data->BVPSuccess=false;
  650. data->sensSuccess=false;
  651. /*TIgnFac:*/
  652. data->TIgnFac=0.20;
  653. /*Sorting*/
  654. data->sort=false;
  655. /* Solve two-point BVP: */
  656. data->solveBVP=true;
  657. /*****************************************************/
  658. int ier;
  659. int opt;
  660. char mech[BUFSIZE+1];
  661. char comp[BUFSIZE+1];
  662. bool enteredT0, enteredP, enteredMech, enteredComp;
  663. enteredT0=enteredP=enteredMech=enteredComp=false;
  664. while((opt=getopt(argc,argv,"a:r:f:T:P:m:c:t:q:vsodn")) != -1){
  665. switch(opt){
  666. case 'a':
  667. data->atol=RCONST(atof(optarg));
  668. break;
  669. case 'r':
  670. data->rtol=RCONST(atof(optarg));
  671. break;
  672. case 'f':
  673. data->ftol=RCONST(atof(optarg));
  674. break;
  675. case 'T':
  676. data->T0=RCONST(atof(optarg));
  677. enteredT0=true;
  678. break;
  679. case 'P':
  680. data->P=RCONST(atof(optarg))*Cantera::OneAtm;
  681. enteredP=true;
  682. break;
  683. case 'm':
  684. snprintf(mech,BUFSIZE,"%s",optarg);
  685. enteredMech=true;
  686. break;
  687. case 'c':
  688. snprintf(comp,BUFSIZE,"%s",optarg);
  689. enteredComp=true;
  690. break;
  691. case 't':
  692. data->t1=RCONST(atof(optarg));
  693. enteredT0=true;
  694. break;
  695. case 'v':
  696. data->constantVolume=true;
  697. break;
  698. case 'S':
  699. data->writeSpeciesSensitivities=true;
  700. break;
  701. case 's':
  702. data->sens=true;
  703. break;
  704. case 'o':
  705. data->sort=true;
  706. break;
  707. case 'd':
  708. data->imposedPdt=true;
  709. break;
  710. case 'q':
  711. data->TIgnFac=RCONST(atof(optarg));
  712. break;
  713. case 'n':
  714. data->solveBVP=false;
  715. break;
  716. default:
  717. printInstructions();
  718. return(-1);
  719. }
  720. }
  721. if(!enteredT0){
  722. printf("Not specified initial Temperature! Exiting...\n");
  723. printInstructions();
  724. return(-1);
  725. }
  726. else if(!enteredP){
  727. printf("Not specified Pressure! Exiting...\n");
  728. printInstructions();
  729. return(-1);
  730. }
  731. else if(!enteredMech){
  732. printf("Not specified Mechanism! Exiting...\n");
  733. printInstructions();
  734. return(-1);
  735. }
  736. else if(!enteredComp){
  737. printf("Not specified Composition! Exiting...\n");
  738. printInstructions();
  739. return(-1);
  740. }
  741. else{
  742. if(data->imposedPdt){
  743. ier=parsedPdt(data);
  744. if(ier==-1){
  745. return(-1);
  746. }
  747. }
  748. printf("Required inputs provided:\n");
  749. printf("\natol: %15.6e\n", data->atol);
  750. printf("\nrtol: %15.6e\n", data->rtol);
  751. printf("\nftol: %15.6e\n", data->ftol);
  752. printf("\nT0 : %15.6e K\n", data->T0);
  753. printf("\nP : %15.6e Pa\n", data->P);
  754. printf("\nmech: %s\n", mech);
  755. printf("\ncomp: %s\n", comp);
  756. printf("\nt1 : %15.6e s\n", data->t1);
  757. printf("\nconstantVolume : %d\n", data->constantVolume);
  758. printf("\nimposedPdt : %d\n", data->imposedPdt);
  759. printf("\nwriteSpeciesSensitivities : %d\n",
  760. data->writeSpeciesSensitivities);
  761. printf("Proceeding...\n\n");
  762. }
  763. /*Define Gas here:*/
  764. data->gas = new Cantera::IdealGasMix(mech);
  765. /* Set the initial state of the gas: */
  766. data->gas->setState_TPX(data->T0,
  767. data->P,
  768. comp);
  769. /* Create output file for the solution of the IVP: */
  770. data->output=fopen("output.dat","w");
  771. /* Create output file for the ignition sensitivities (post BVP): */
  772. data->ignSensOutput=fopen("ignitionSensitivities.dat","w");
  773. /* Create output file for the species sensitivities (post BVP): */
  774. data->speSensOutput=fopen("speciesSensitivities.dat","w");
  775. data->rho0=data->gas->density();
  776. if(data->constantVolume){
  777. data->gas->equilibrate("UV");
  778. }
  779. else{
  780. data->gas->equilibrate("HP");
  781. }
  782. data->TIgn=data->T0+(data->gas->temperature()
  783. -data->T0)*data->TIgnFac;
  784. printf("Ignition Temperature: %15.6e K\n",data->TIgn);
  785. data->gas->setState_TPX(data->T0,
  786. data->P,
  787. comp);
  788. /*Get and save the no: of species:*/
  789. data->nsp=data->gas->nSpecies();
  790. /*set the no: of variables for the IVP:*/
  791. data->nvar=data->nsp+1;
  792. /*set the no: of equations for the IVP:*/
  793. data->neq=data->nvar;
  794. return(0);
  795. }
  796. static int setInitialProfile(UserData data, N_Vector y)
  797. {
  798. /*This routine sets the initial temperature and mass fractions for the
  799. * solution of the initial value problem:*/
  800. N_VConst(ZERO, y);
  801. T(1)=data->gas->temperature();
  802. for (int k = 1; k <=data->nsp; k++) {
  803. Y(1,k)=Y0(k);
  804. }
  805. return(0);
  806. }
  807. static int residue(realtype t, N_Vector y, N_Vector ydot, void *user_data)
  808. {
  809. /*This is the sub-routine that computes the right hand side F(y) in the
  810. * problem ∂y/∂t = F(y).
  811. *
  812. * The energy conservation equation is
  813. * ∂T/∂t = (1/ρcₚ)(dP/dt -∑ ώᵢhᵢ)
  814. *
  815. * T has units of K
  816. * hᵢ has units J/kmol, so we must multiply the enthalpy
  817. * defined above (getEnthalpy_RT) by T (K) and the gas constant
  818. * (J/kmol/K) to get the right units.
  819. * ρ has units of kg/m³
  820. * cₚ has units J/kg/K
  821. * ώᵢ has units of kmol/m³/s
  822. * dP/dt has units of Pa/s
  823. *
  824. * In the case of a constant volume problem, the energy conservation
  825. * equation can be re-written as
  826. * ∂T/∂t = -(1/ρcᵥ)∑ ώᵢeᵢ
  827. * eᵢ has units J/kmol
  828. * cᵥ has units J/kg/K
  829. *
  830. *
  831. * The species conservation equation is
  832. * ∂Yᵢ/∂t = ώᵢWᵢ/ρ
  833. * Wᵢ has units of kg/kmol
  834. */
  835. /*Assign data structure type to user_data:*/
  836. UserData data;
  837. data=(UserData)user_data;
  838. /*Get no: of species:*/
  839. int nsp=data->nsp;
  840. /*Create temporary arrays to store enthalpy (non-dimensional) and ώᵢ:*/
  841. realtype wdot[nsp];
  842. realtype enthalpy[nsp];
  843. try {
  844. /*Set the gas conditions:*/
  845. if(data->constantVolume){
  846. data->gas->setMassFractions_NoNorm(&Y(1,1));
  847. data->gas->setTemperature(T(1));
  848. data->gas->setDensity(data->rho0);
  849. data->P=data->gas->pressure();
  850. }
  851. else if(data->imposedPdt){
  852. data->gas->setMassFractions_NoNorm(&Y(1,1));
  853. data->gas->setTemperature(T(1));
  854. realtype P,dPdt;
  855. P=dPdt=0.0e0;
  856. lookupDpdt(data, t, &P, &dPdt);
  857. data->P=P*Cantera::OneAtm;
  858. data->dPdt=dPdt*Cantera::OneAtm;
  859. data->gas->setPressure(data->P);
  860. }
  861. else{
  862. data->gas->setMassFractions_NoNorm(&Y(1,1));
  863. data->gas->setTemperature(T(1));
  864. data->gas->setPressure(data->P);
  865. }
  866. realtype rho=data->gas->density(); //get ρ
  867. realtype cp=data->gas->cp_mass(); //get cₚ
  868. data->gas->getNetProductionRates(wdot); //get ώᵢ
  869. data->gas->getEnthalpy_RT(enthalpy); //get hᵢ/RT
  870. if(data->constantVolume){
  871. for(int k=1;k<=nsp;k++){
  872. enthalpy(k)=enthalpy(k)-ONE;
  873. }
  874. cp=data->gas->cv_mass();
  875. }
  876. realtype sum=ZERO;
  877. for(int k=1;k<=nsp;k++){
  878. Ydot(1,k)=wdot(k)*(data->gas->molecularWeight(k-1))/rho;
  879. sum=sum+wdot(k)*enthalpy(k)*T(1);
  880. }
  881. sum=sum*Cantera::GasConstant;
  882. Tdot(1)=(data->dPdt-sum)/(rho*cp);
  883. } catch (Cantera::CanteraError& err) {
  884. printf("Error:\n");
  885. printf("%s\n",err.what());
  886. return(-1);
  887. }
  888. return(0);
  889. }
  890. static int residueKS(N_Vector yp, N_Vector res, void *user_data)
  891. {
  892. /*This is the sub-routine that computes the right hand side F(y) in the
  893. * problem F(y) = 0. Here the problem is specifically that of a
  894. * homogeneous isobaric batch reactor formulated as a boundary value
  895. * problem (BVP). The unknowns in this problem are T, Yᵢ, and τ.
  896. *
  897. * The energy conservation equation is
  898. * ∂T/∂x = (τ/ρcₚ)(dP/dt - ∑ ώᵢhᵢ)
  899. *
  900. * T has units of K
  901. * x is *unitless*
  902. * τ has units of time
  903. * hᵢ has units J/kmol, so we must multiply the enthalpy
  904. * defined above (getEnthalpy_RT) by T (K) and the gas constant
  905. * (J/kmol/K) to get the right units.
  906. * ρ has units of kg/m³
  907. * cₚ has units J/kg/K
  908. * ώᵢ has units of kmol/m³/s
  909. * dP/dt has units of Pa/s
  910. *
  911. * In the case of a constant volume problem, the energy conservation
  912. * equation can be re-written as
  913. * ∂T/∂x = -(τ/ρcᵥ)∑ ώᵢeᵢ
  914. * eᵢ has units J/kmol
  915. * cᵥ has units J/kg/K
  916. *
  917. * The species conservation equation is
  918. * ∂Yᵢ/∂x = τώᵢWᵢ/ρ
  919. *
  920. * Wᵢ has units of kg/kmol
  921. *
  922. * The equation (trivial) to maintain a banded structure in the linear
  923. * solver is
  924. * ∂τ/∂x = 0
  925. */
  926. /*Assign data structure type to user_data:*/
  927. UserData data;
  928. data=(UserData)user_data;
  929. /*Get no: of species:*/
  930. int nsp=data->nsp;
  931. /*Create temporary arrays to store enthalpy (non-dimensional) and ώᵢ:*/
  932. realtype wdot[nsp];
  933. realtype enthalpy[nsp];
  934. /*Create temperorary variables to store grid spacing and summation
  935. * terms:*/
  936. realtype dx;
  937. realtype sum=ZERO;
  938. data->dPdt=ZERO;
  939. try {
  940. /*If sensitivity analysis has been enabled, perturb the collision
  941. * frequency by using cantera's setMultiplier function:*/
  942. if(data->sensitivityAnalysis){
  943. data->gas->setMultiplier(data->pert_index,ONE+data->rel);
  944. //printf("%d\t%15.9e\n",data->pert_index,ONE+data->rel);
  945. }
  946. Tres(1)=Tp(1)-data->T0;
  947. for(int k=1;k<=nsp;k++){
  948. Yres(1,k)=Yp(1,k)-Y0(k);
  949. }
  950. taures(1)=taup(2)-taup(1);
  951. for(int i=2;i<=data->npts;i++){
  952. if(data->constantVolume){
  953. data->gas->setMassFractions_NoNorm(&Yp(i,1));
  954. data->gas->setTemperature(Tp(i));
  955. data->gas->setDensity(data->rho0);
  956. }
  957. else if(data->imposedPdt){
  958. //printf("%15.6e\t%15.6e\t%15.6e\n",x(i),Tp(i),Pp(i));
  959. data->gas->setMassFractions_NoNorm(&Yp(i,1));
  960. data->gas->setTemperature(Tp(i));
  961. data->gas->setPressure(Pp(i));
  962. data->dPdt=dPdtp(i);
  963. }
  964. else{
  965. data->gas->setMassFractions_NoNorm(&Yp(i,1));
  966. data->gas->setTemperature(Tp(i));
  967. data->gas->setPressure(data->P);
  968. }
  969. realtype rho=data->gas->density();
  970. realtype cp=data->gas->cp_mass();
  971. data->gas->getNetProductionRates(wdot);
  972. data->gas->getEnthalpy_RT(enthalpy);
  973. if(data->constantVolume){
  974. for(int k=1;k<=nsp;k++){
  975. enthalpy(k)=enthalpy(k)-ONE;
  976. }
  977. cp=data->gas->cv_mass();
  978. }
  979. dx=x(i)-x(i-1);
  980. sum=ZERO;
  981. for(int k=1;k<=nsp;k++){
  982. Yres(i,k)=(Yp(i,k)-Yp(i-1,k))/dx;
  983. Yres(i,k)+=-taup(i)*wdot(k)*(data->gas->molecularWeight(k-1))/rho;
  984. sum+=wdot(k)*enthalpy(k)*Tp(i);
  985. }
  986. sum=sum*Cantera::GasConstant;
  987. Tres(i)=(Tp(i)-Tp(i-1))/dx;
  988. Tres(i)+=taup(i)*(sum-data->dPdt)/(rho*cp);
  989. if(i==data->npts){
  990. taures(i)=Tp(i)-data->TIgn;
  991. }
  992. else{
  993. taures(i)=taup(i+1)-taup(i);
  994. }
  995. }
  996. /*If sensitivity analysis has been enabled, *un*perturb the collision
  997. * frequency:*/
  998. if(data->sensitivityAnalysis){
  999. data->gas->setMultiplier(data->pert_index,ONE);
  1000. }
  1001. } catch (Cantera::CanteraError& err) {
  1002. printf("Error:\n");
  1003. printf("%s\n",err.what());
  1004. return(-1);
  1005. }
  1006. return(0);
  1007. }
  1008. static void lookupDpdt(UserData data, realtype t, realtype *P, realtype *dPdt)
  1009. {
  1010. realtype *dPdtData;
  1011. dPdtData = N_VGetArrayPointer_Serial(data->dPdtArray);
  1012. int npts=data->tArraySize;
  1013. if(t<=data->t1){
  1014. *P=gsl_spline_eval(data->spline,t,data->acc);
  1015. *dPdt=gsl_spline_eval(data->splinedot,t,data->accdot);
  1016. }
  1017. else{
  1018. *P=P(npts-1);
  1019. *dPdt=dPdt(npts-1);
  1020. }
  1021. }
  1022. /*------------------------------------------------------------------
  1023. kinDlsBandDQJac
  1024. This routine generates a banded difference quotient approximation
  1025. to the Jacobian of F(u). It assumes a SUNBandMatrix input stored
  1026. column-wise, and that elements within each column are contiguous.
  1027. This makes it possible to get the address of a column of J via the
  1028. function SUNBandMatrix_Column() and to write a simple for loop to
  1029. set each of the elements of a column in succession.
  1030. NOTE: Any type of failure of the system function her leads to an
  1031. unrecoverable failure of the Jacobian function and thus of
  1032. the linear solver setup function, stopping KINSOL.
  1033. ------------------------------------------------------------------*/
  1034. static int kinDlsBandDQJac(N_Vector u, N_Vector fu, SUNMatrix Jac,
  1035. UserData data, N_Vector scale, N_Vector tmp1, N_Vector tmp2)
  1036. {
  1037. realtype inc, inc_inv;
  1038. N_Vector futemp, utemp;
  1039. sunindextype group, i, j, width, ngroups, i1, i2;
  1040. sunindextype N, mupper, mlower;
  1041. realtype *col_j, *fu_data, *futemp_data, *u_data, *utemp_data, *uscale_data;
  1042. int retval = 0;
  1043. //KINDlsMem kindls_mem;
  1044. //KINMem kin_mem;
  1045. //kin_mem = (KINMem) mem;
  1046. ///* access DlsMem interface structure */
  1047. //kindls_mem = (KINDlsMem) kin_mem->kin_lmem;
  1048. /* access matrix dimensions */
  1049. N = SUNBandMatrix_Columns(Jac);
  1050. mupper = SUNBandMatrix_UpperBandwidth(Jac);
  1051. mlower = SUNBandMatrix_LowerBandwidth(Jac);
  1052. /* Rename work vectors for use as temporary values of u and fu */
  1053. futemp = tmp1;
  1054. utemp = tmp2;
  1055. /* Obtain pointers to the data for ewt, fy, futemp, y, ytemp */
  1056. fu_data = N_VGetArrayPointer(fu);
  1057. futemp_data = N_VGetArrayPointer(futemp);
  1058. u_data = N_VGetArrayPointer(u);
  1059. //uscale_data = N_VGetArrayPointer(kin_mem->kin_uscale);
  1060. uscale_data = N_VGetArrayPointer(scale);
  1061. utemp_data = N_VGetArrayPointer(utemp);
  1062. /* Load utemp with u */
  1063. N_VScale(ONE, u, utemp);
  1064. /* Set bandwidth and number of column groups for band differencing */
  1065. width = mlower + mupper + 1;
  1066. ngroups = SUNMIN(width, N);
  1067. //UserData data;
  1068. //data=(UserData) kin_mem->kin_user_data;
  1069. for (group=1; group <= ngroups; group++) {
  1070. /* Increment all utemp components in group */
  1071. for(j=group-1; j < N; j+=width) {
  1072. //inc = kin_mem->kin_sqrt_relfunc*SUNMAX(SUNRabs(u_data[j]),
  1073. // ONE/SUNRabs(uscale_data[j]));
  1074. //inc = data->rel*SUNRabs(u_data[j]);
  1075. inc = data->rel*SUNMAX(SUNRabs(u_data[j]),
  1076. ONE/SUNRabs(uscale_data[j]));
  1077. utemp_data[j] += inc;
  1078. }
  1079. /* Evaluate f with incremented u */
  1080. //retval = kin_mem->kin_func(utemp, futemp, kin_mem->kin_user_data);
  1081. retval=residueKS(utemp, futemp, data);
  1082. if (retval != 0) return(retval);
  1083. /* Restore utemp components, then form and load difference quotients */
  1084. for (j=group-1; j < N; j+=width) {
  1085. utemp_data[j] = u_data[j];
  1086. col_j = SUNBandMatrix_Column(Jac, j);
  1087. //inc = kin_mem->kin_sqrt_relfunc*SUNMAX(SUNRabs(u_data[j]),
  1088. // ONE/SUNRabs(uscale_data[j]));
  1089. //inc = kin_mem->kin_sqrt_relfunc*SUNRabs(u_data[j]);
  1090. //inc = data->rel*SUNRabs(u_data[j]);
  1091. inc = data->rel*SUNMAX(SUNRabs(u_data[j]),
  1092. ONE/SUNRabs(uscale_data[j]));
  1093. inc_inv = ONE/inc;
  1094. i1 = SUNMAX(0, j-mupper);
  1095. i2 = SUNMIN(j+mlower, N-1);
  1096. for (i=i1; i <= i2; i++)
  1097. SM_COLUMN_ELEMENT_B(col_j,i,j) = inc_inv * (futemp_data[i] - fu_data[i]);
  1098. }
  1099. }
  1100. ///* Increment counter nfeDQ */
  1101. //kindls_mem->nfeDQ += ngroups;
  1102. return(0);
  1103. }
  1104. static int hunt(realtype x, realtype xx[], int n, int jguess)
  1105. {
  1106. int jlo=jguess;
  1107. int jm,jhi,inc;
  1108. int ascnd;
  1109. ascnd=(xx[n-1] >= xx[0]);
  1110. if (jlo <= 0 || jlo > n-1) {
  1111. jlo=0;
  1112. jhi=n;
  1113. } else {
  1114. inc=1;
  1115. if ((x >= xx[jlo]) == ascnd) {
  1116. if (jlo == n-1) return(jlo);
  1117. jhi=(jlo)+1;
  1118. while ((x >= xx[jhi]) == ascnd) {
  1119. jlo=jhi;
  1120. inc += inc;
  1121. jhi=(jlo)+inc;
  1122. if (jhi > n-1) {
  1123. jhi=n;
  1124. break;
  1125. }
  1126. }
  1127. } else {
  1128. if (jlo == 1) {
  1129. jlo=0;
  1130. return (jlo);
  1131. }
  1132. jhi=(jlo)--;
  1133. while ((x < xx[jlo]) == ascnd) {
  1134. jhi=(jlo);
  1135. inc <<= 1;
  1136. if (inc >= jhi) {
  1137. jlo=0;
  1138. break;
  1139. }
  1140. else jlo=jhi-inc;
  1141. }
  1142. }
  1143. }
  1144. while (jhi-(jlo) != 1) {
  1145. jm=(jhi+(jlo)) >> 1;
  1146. if ((x >= xx[jm]) == ascnd)
  1147. jlo=jm;
  1148. else
  1149. jhi=jm;
  1150. }
  1151. if (x == xx[n-1]) jlo=n-2;
  1152. if (x == xx[0]) jlo=1;
  1153. return(jlo);
  1154. }
  1155. static void polint(realtype *xdata, realtype *f, int n, realtype x, realtype *y, realtype *dy){
  1156. int i,m,ns=1;
  1157. realtype den,dif,dift,ho,hp,w;
  1158. realtype c[n+1],d[n+1];
  1159. dif=fabs(x-xdata[1]);
  1160. for (i=1;i<=n;i++) {
  1161. if ( (dift=fabs(x-xdata[i])) < dif) {
  1162. ns=i;
  1163. dif=dift;
  1164. }
  1165. c[i]=f[i];
  1166. d[i]=f[i];
  1167. }
  1168. *y=f[ns--];
  1169. for (m=1;m<n;m++) {
  1170. for (i=1;i<=n-m;i++) {
  1171. ho=xdata[i]-x;
  1172. hp=xdata[i+m]-x;
  1173. w=c[i+1]-d[i];
  1174. if ( (den=ho-hp) == 0.0) printf("Error in routine polint!\n");
  1175. den=w/den;
  1176. d[i]=hp*den;
  1177. c[i]=ho*den;
  1178. }
  1179. *y += (*dy=(2*ns < (n-m) ? c[ns+1] : d[ns--]));
  1180. }
  1181. }
  1182. #define SWAP(a,b) temp=(a);(a)=(b);(b)=temp;
  1183. #define M 7
  1184. #define NSTACK 50
  1185. #define NR_END 1
  1186. #define FREE_ARG char*
  1187. static unsigned long *lvector(long nl, long nh)
  1188. /* allocate an unsigned long vector with subscript range v[nl..nh] */
  1189. {
  1190. unsigned long *v;
  1191. v=(unsigned long *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(long)));
  1192. if (!v) printf("allocation failure in lvector()");
  1193. return v-nl+NR_END;
  1194. }
  1195. static void free_lvector(unsigned long *v, long nl, long nh)
  1196. /* free an unsigned long vector allocated with lvector() */
  1197. {
  1198. free((FREE_ARG) (v+nl-NR_END));
  1199. }
  1200. static void sort(unsigned long n, double arr[], int ind[])
  1201. {
  1202. unsigned long i,ir=n,j,k,l=1,*istack;
  1203. int jstack=0;
  1204. double a,temp;
  1205. int b;
  1206. istack=lvector(1,NSTACK);
  1207. for (;;) {
  1208. if (ir-l < M) {
  1209. for (j=l+1;j<=ir;j++) {
  1210. a=arr[j];
  1211. b=ind[j];
  1212. for (i=j-1;i>=l;i--) {
  1213. if (arr[i] <= a) break;
  1214. arr[i+1]=arr[i];
  1215. ind[i+1]=ind[i];
  1216. }
  1217. arr[i+1]=a;
  1218. ind[i+1]=b;
  1219. }
  1220. if (jstack == 0) break;
  1221. ir=istack[jstack--];
  1222. l=istack[jstack--];
  1223. } else {
  1224. k=(l+ir) >> 1;
  1225. SWAP(arr[k],arr[l+1])
  1226. SWAP(ind[k],ind[l+1])
  1227. if (arr[l] > arr[ir]) {
  1228. SWAP(arr[l],arr[ir])
  1229. SWAP(ind[l],ind[ir])
  1230. }
  1231. if (arr[l+1] > arr[ir]) {
  1232. SWAP(arr[l+1],arr[ir])
  1233. SWAP(ind[l+1],ind[ir])
  1234. }
  1235. if (arr[l] > arr[l+1]) {
  1236. SWAP(arr[l],arr[l+1])
  1237. SWAP(ind[l],ind[l+1])
  1238. }
  1239. i=l+1;
  1240. j=ir;
  1241. a=arr[l+1];
  1242. b=ind[l+1];
  1243. for (;;) {
  1244. do i++; while (arr[i] < a);
  1245. do j--; while (arr[j] > a);
  1246. if (j < i) break;
  1247. SWAP(arr[i],arr[j]);
  1248. SWAP(ind[i],ind[j]);
  1249. }
  1250. arr[l+1]=arr[j];
  1251. ind[l+1]=ind[j];
  1252. arr[j]=a;
  1253. ind[j]=b;
  1254. jstack += 2;
  1255. if (jstack > NSTACK) printf("NSTACK too small in sort.");
  1256. if (ir-i+1 >= j-l) {
  1257. istack[jstack]=ir;
  1258. istack[jstack-1]=i;
  1259. ir=j-1;
  1260. } else {
  1261. istack[jstack]=j-1;
  1262. istack[jstack-1]=l;
  1263. l=i;
  1264. }
  1265. }
  1266. }
  1267. free_lvector(istack,1,NSTACK);
  1268. }
  1269. #undef M
  1270. #undef NSTACK
  1271. #undef SWAP
  1272. static void printInstructions(){
  1273. printf("\nInputs either incomplete or wrong!\n");
  1274. printf("\n-a <absolute tolerance for IVP>\n");
  1275. printf("\n-r <relative tolerance for IVP>\n");
  1276. printf("\n-f <function tolerance for BVP>\n");
  1277. printf("\n-T <Initial Temperature in Kelvin>\n");
  1278. printf("\n-P <Initial Pressure in atm>\n");
  1279. printf("\n-m <mechanism file (cti or xml)>\n");
  1280. printf("\n-c <composition in mole fractions>\n");
  1281. printf("\n-t <Total simulation time in seconds>\n");
  1282. printf("\n-v :Enables constant volume simulation\n");
  1283. printf("\n-s :Enables ignition delay sensitivity output\n");
  1284. printf("\n-S :Enables species mass fraction sensitivity output (works only with -s)\n");
  1285. printf("\n-d :Enables manual dPdt entryspecies sensitivity output\n");
  1286. printf("\n-o :Enables sorting of ignition delay sensitivity output\n");
  1287. printf("\n-q :factor that determines ignition temperature (default: 0.2)\n");
  1288. printf("\n-n :Disables the boundary value problem solver\n");
  1289. printf("\nexample: <executable> ");
  1290. printf("-T 1200.0 -P 1.0 -m gri30.cti");
  1291. printf(" -c H2:1.0,N2:3.76,O2:1.0");
  1292. printf(" -t 1e-03\n");
  1293. }
  1294. static void printHeader(UserData data)
  1295. {
  1296. fprintf((data->output), "%15s\t","#1");
  1297. for (int k = 1; k <=data->nvar; k++) {
  1298. fprintf((data->output), "%15d\t",k+1);
  1299. }
  1300. fprintf((data->output), "\n");
  1301. fprintf((data->output), "%15s\t%15s\t%15s\t",
  1302. "#time(s)","Temp(K)","Pressure(Pa)");
  1303. for (int k = 1; k <=data->nsp; k++) {
  1304. fprintf((data->output), "%15s\t",
  1305. data->gas->speciesName(k-1).c_str());
  1306. }
  1307. fprintf((data->output), "\n");
  1308. }
  1309. static void printSensitivitiesHeader(UserData data)
  1310. {
  1311. fprintf((data->speSensOutput), "%15s\t","#1");
  1312. for (int k = 1; k <=data->nvar; k++) {
  1313. fprintf((data->speSensOutput), "%15d\t",k+1);
  1314. }
  1315. fprintf((data->speSensOutput), "\n");
  1316. fprintf((data->speSensOutput), "%15s\t%15s\t",
  1317. "#time(s)","Temp(K)");
  1318. for (int k = 1; k <=data->nsp; k++) {
  1319. fprintf((data->speSensOutput), "%15s\t",
  1320. data->gas->speciesName(k-1).c_str());
  1321. }
  1322. fprintf((data->speSensOutput), "\n");
  1323. }
  1324. static void printOutput(realtype t, N_Vector y, UserData data)
  1325. {
  1326. fprintf((data->output), "%15.6e\t%15.6e\t%15.6e\t",t,T(1),data->P);
  1327. for (int k = 1; k <=data->nsp; k++) {
  1328. fprintf((data->output), "%15.6e\t",Y(1,k));
  1329. }
  1330. fprintf((data->output), "\n");
  1331. }
  1332. //static void printOutputKS(N_Vector yp, UserData data)
  1333. //{
  1334. // //printf("%d\n",data->npts);
  1335. // fprintf(data->output, "\n\n");
  1336. // for(int i=1;i<=data->npts;i++){
  1337. // fprintf((data->output), "%15.6e\t%15.6e\t%15.6e\t",x(i)*data->tauIgn,Tp(i),data->P);
  1338. // //printf("%15.6e\t%15.6e\n",x(i),Tp(i));
  1339. // for (int k = 1; k <=data->nsp; k++) {
  1340. // fprintf((data->output), "%15.6e\t",Yp(i,k));
  1341. // }
  1342. // fprintf(data->output, "\n");
  1343. // }
  1344. //}
  1345. static void printSpeciesSensitivities(int index, N_Vector yp, N_Vector res, UserData data)
  1346. {
  1347. char buf[50];
  1348. std::string line;
  1349. line=data->gas->reactionString(index);
  1350. sprintf(buf,"%s",line.c_str());
  1351. fprintf((data->speSensOutput), "#%d: %38s\t\n", index, buf);
  1352. printSensitivitiesHeader(data);
  1353. for(int i=1;i<=data->npts;i++){
  1354. fprintf((data->speSensOutput), "%15.6e\t%15.6e\t",x(i)*taup(i),Tres(i)/Tp(i));
  1355. for (int k = 1; k <=data->nsp; k++) {
  1356. if(Yp(i,k)>=data->atol){
  1357. fprintf((data->speSensOutput), "%15.6e\t",Yres(i,k)/(Yp(i,k)+1e-31));
  1358. }
  1359. else{
  1360. fprintf((data->speSensOutput), "%15.6e\t",ZERO);
  1361. }
  1362. }
  1363. fprintf((data->speSensOutput), "\n");
  1364. }
  1365. fprintf((data->speSensOutput), "\n\n");
  1366. }
  1367. //static void printResidueKS(N_Vector res, UserData data)
  1368. //{
  1369. // fprintf((data->output), "\n\n");
  1370. // for(int i=1;i<=data->npts;i++){
  1371. // fprintf((data->output), "%15.6e\t%15.6e\t",x(i),Tres(i));
  1372. // for (int k = 1; k <=data->nsp; k++) {
  1373. // fprintf((data->output), "%15.6e\t",Yres(i,k));
  1374. // }
  1375. // fprintf((data->output), "\n");
  1376. // }
  1377. //}
  1378. static void printIgnSensitivities(realtype sensCoeffs[], int indices[], UserData data)
  1379. {
  1380. char buf[50];
  1381. std::string line;
  1382. for(int j=0;j<data->nreac;j++){
  1383. line=data->gas->reactionString(indices[j]);
  1384. sprintf(buf,"%s",line.c_str());
  1385. fprintf((data->ignSensOutput), "%d\t\"%35s\"\t%15.6e\n",indices[j],buf,sensCoeffs[j]);
  1386. }
  1387. }
  1388. static int parsedPdt(UserData data){
  1389. /* Open file containing P and dPdt as functions of time: */
  1390. data->dPdtInput=fopen("dPdt.dat","r");
  1391. if(data->dPdtInput==NULL){
  1392. printf("The dPdt.dat file wasn't found!\n");
  1393. return(-1);
  1394. }
  1395. char buf[1000];
  1396. char comment[1];
  1397. char *ret;
  1398. int i=0;
  1399. int j=0;
  1400. while (fgets(buf,100, data->dPdtInput)!=NULL){
  1401. comment[0]=buf[0];
  1402. if(strncmp(comment,"#",1)!=0 &&
  1403. strncmp(comment,"\n",1)!=0){
  1404. i++;
  1405. }
  1406. }
  1407. printf("No: of rows with numbers: %d\n",i);
  1408. rewind(data->dPdtInput);
  1409. int nPts=i;
  1410. data->tArraySize=nPts;
  1411. i=0;
  1412. data->tArray = N_VNew_Serial(nPts);
  1413. data->PArray = N_VNew_Serial(nPts);
  1414. data->dPdtArray = N_VNew_Serial(nPts);
  1415. while (fgets(buf,100, data->dPdtInput)!=NULL){
  1416. comment[0]=buf[0];
  1417. if(strncmp(comment,"#",1)==0 ||
  1418. strncmp(comment,"\n",1)==0){
  1419. printf("Comment! Skip Line!\n");
  1420. }
  1421. else{
  1422. j=0;
  1423. ret=strtok(buf,", \t");
  1424. t(i)=atof(ret);
  1425. j++;
  1426. while(ret!=NULL){
  1427. ret=strtok(NULL,", \t");
  1428. if(j==1){
  1429. P(i)=atof(ret);
  1430. }
  1431. else if(j==2){
  1432. dPdt(i)=atof(ret);
  1433. }
  1434. j++;
  1435. }
  1436. i++;
  1437. }
  1438. }
  1439. fclose(data->dPdtInput);
  1440. //for(int k=0;k<nPts;k++){
  1441. // printf("%15.6e\t%15.6e\t%15.6e\n",t(k),P(k),dPdt(k));
  1442. //}
  1443. data->t1=t(nPts-1);
  1444. data->P=P(0)*Cantera::OneAtm;
  1445. /*check the polynomial interpolation (testing only)*/
  1446. //realtype t,P,dPdt;
  1447. //t=1e-03;
  1448. //P=dPdt=0.0e0;
  1449. //lookupDpdt(data, t, &P, &dPdt);
  1450. //printf("Interpolated P value %15.6e. \n",P);
  1451. //printf("Interpolated dPdt value %15.6e. \n",dPdt);
  1452. //
  1453. //GSL additions here:
  1454. data->acc=gsl_interp_accel_alloc();
  1455. data->spline=gsl_spline_alloc(gsl_interp_steffen,data->tArraySize);
  1456. data->accdot=gsl_interp_accel_alloc();
  1457. data->splinedot=gsl_spline_alloc(gsl_interp_steffen,data->tArraySize);
  1458. double* Pdata;
  1459. double* dPdtdata;
  1460. double* tdata;
  1461. tdata=N_VGetArrayPointer_Serial(data->tArray);
  1462. Pdata=N_VGetArrayPointer_Serial(data->PArray);
  1463. dPdtdata=N_VGetArrayPointer_Serial(data->dPdtArray);
  1464. gsl_spline_init(data->spline,tdata,Pdata,data->tArraySize);
  1465. gsl_spline_init(data->splinedot,tdata,dPdtdata,data->tArraySize);
  1466. return(0);
  1467. }
  1468. static void PrintFinalStats(void *cvode_mem)
  1469. {
  1470. long int nst, nfe, nsetups, nje, nfeLS, nni, ncfn, netf, nge;
  1471. int flag;
  1472. flag = CVodeGetNumSteps(cvode_mem, &nst);
  1473. check_flag(&flag, "CVodeGetNumSteps", 1);
  1474. flag = CVodeGetNumRhsEvals(cvode_mem, &nfe);
  1475. check_flag(&flag, "CVodeGetNumRhsEvals", 1);
  1476. flag = CVodeGetNumLinSolvSetups(cvode_mem, &nsetups);
  1477. check_flag(&flag, "CVodeGetNumLinSolvSetups", 1);
  1478. flag = CVodeGetNumErrTestFails(cvode_mem, &netf);
  1479. check_flag(&flag, "CVodeGetNumErrTestFails", 1);
  1480. flag = CVodeGetNumNonlinSolvIters(cvode_mem, &nni);
  1481. check_flag(&flag, "CVodeGetNumNonlinSolvIters", 1);
  1482. flag = CVodeGetNumNonlinSolvConvFails(cvode_mem, &ncfn);
  1483. check_flag(&flag, "CVodeGetNumNonlinSolvConvFails", 1);
  1484. flag = CVDlsGetNumJacEvals(cvode_mem, &nje);
  1485. check_flag(&flag, "CVDlsGetNumJacEvals", 1);
  1486. flag = CVDlsGetNumRhsEvals(cvode_mem, &nfeLS);
  1487. check_flag(&flag, "CVDlsGetNumRhsEvals", 1);
  1488. flag = CVodeGetNumGEvals(cvode_mem, &nge);
  1489. check_flag(&flag, "CVodeGetNumGEvals", 1);
  1490. printf("\nFinal CVode Statistics:\n");
  1491. printf("nst = %-6ld nfe = %-6ld nsetups = %-6ld nfeLS = %-6ld nje = %ld\n",
  1492. nst, nfe, nsetups, nfeLS, nje);
  1493. printf("nni = %-6ld ncfn = %-6ld netf = %-6ld nge = %ld\n \n",
  1494. nni, ncfn, netf, nge);
  1495. }
  1496. static void PrintFinalStatsKS(void *kmem)
  1497. {
  1498. long int nni, nfe, nje, nfeD;
  1499. long int lenrw, leniw, lenrwB, leniwB;
  1500. long int nbcfails, nbacktr;
  1501. int flag;
  1502. /* Main solver statistics */
  1503. flag = KINGetNumNonlinSolvIters(kmem, &nni);
  1504. check_flag(&flag, "KINGetNumNonlinSolvIters", 1);
  1505. flag = KINGetNumFuncEvals(kmem, &nfe);
  1506. check_flag(&flag, "KINGetNumFuncEvals", 1);
  1507. /* Linesearch statistics */
  1508. flag = KINGetNumBetaCondFails(kmem, &nbcfails);
  1509. check_flag(&flag, "KINGetNumBetacondFails", 1);
  1510. flag = KINGetNumBacktrackOps(kmem, &nbacktr);
  1511. check_flag(&flag, "KINGetNumBacktrackOps", 1);
  1512. /* Main solver workspace size */
  1513. flag = KINGetWorkSpace(kmem, &lenrw, &leniw);
  1514. check_flag(&flag, "KINGetWorkSpace", 1);
  1515. /* Band linear solver statistics */
  1516. flag = KINDlsGetNumJacEvals(kmem, &nje);
  1517. check_flag(&flag, "KINDlsGetNumJacEvals", 1);
  1518. flag = KINDlsGetNumFuncEvals(kmem, &nfeD);
  1519. check_flag(&flag, "KINDlsGetNumFuncEvals", 1);
  1520. /* Band linear solver workspace size */
  1521. flag = KINDlsGetWorkSpace(kmem, &lenrwB, &leniwB);
  1522. check_flag(&flag, "KINDlsGetWorkSpace", 1);
  1523. printf("\nFinal KINSOL Statistics:\n");
  1524. printf("nni = %6ld nfe = %6ld \n", nni, nfe);
  1525. printf("nbcfails = %6ld nbacktr = %6ld \n", nbcfails, nbacktr);
  1526. printf("nje = %6ld nfeB = %6ld \n", nje, nfeD);
  1527. printf("\n");
  1528. printf("lenrw = %6ld leniw = %6ld \n", lenrw, leniw);
  1529. printf("lenrwB = %6ld leniwB = %6ld \n", lenrwB, leniwB);
  1530. }
  1531. static int check_flag(void *flagvalue, const char *funcname, int opt)
  1532. {
  1533. int *errflag;
  1534. /* Check if SUNDIALS function returned NULL pointer - no memory allocated */
  1535. if (opt == 0 && flagvalue == NULL) {
  1536. fprintf(stderr,
  1537. "\nSUNDIALS_ERROR: %s() failed - returned NULL pointer\n\n",
  1538. funcname);
  1539. return(1);
  1540. }
  1541. /* Check if flag < 0 */
  1542. else if (opt == 1) {
  1543. errflag = (int *) flagvalue;
  1544. if (*errflag < 0) {
  1545. fprintf(stderr,
  1546. "\nSUNDIALS_ERROR: %s() failed with flag = %d\n\n",
  1547. funcname, *errflag);
  1548. return(1);
  1549. }
  1550. }
  1551. /* Check if function returned NULL pointer - no memory allocated */
  1552. else if (opt == 2 && flagvalue == NULL) {
  1553. fprintf(stderr,
  1554. "\nMEMORY_ERROR: %s() failed - returned NULL pointer\n\n",
  1555. funcname);
  1556. return(1);
  1557. }
  1558. return(0);
  1559. }