Droplet Lagrangian Transient One-dimensional Reacting Code Implementation of both liquid and gas phase governing equations.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1762 lines
52KB

  1. #ifndef GSL_DEF
  2. #define GSL_DEF
  3. #include <gsl/gsl_math.h>
  4. #include <gsl/gsl_spline.h>
  5. #endif
  6. #include "residue.h"
  7. #include "macros.h"
  8. #include <cmath>
  9. #include <stdio.h>
  10. #include "timing.hpp"
  11. double maxTemperaturePosition(const double* y,const size_t nt,const size_t nvar,const double *x ,size_t nPts){
  12. double maxT = 0.0e0;
  13. double TempT = 0.0e0;
  14. double pos = 0.0e0;
  15. for (size_t i=1;i<=nPts;i++){
  16. TempT = y[(i-1)*nvar+nt] ;
  17. if(TempT > maxT){
  18. maxT = TempT ;
  19. pos = x[i-1];
  20. }
  21. }
  22. return(pos);
  23. }
  24. double maxTemperature(const double* y,const size_t nt,const size_t nvar ,size_t nPts){
  25. double maxT = 0.0e0;
  26. double TempT = 0.0e0;
  27. //int index = 0 ;
  28. for (size_t i=1;i<=nPts;i++){
  29. TempT = y[(i-1)*nvar+nt] ;
  30. if(TempT > maxT){
  31. maxT = TempT ;
  32. }
  33. }
  34. return(maxT);
  35. }
  36. int maxTemperatureIndex(const double* y,const size_t nt,const size_t nvar ,size_t nPts){
  37. double maxT = 0.0e0;
  38. double TempT = 0.0e0;
  39. int index = 0 ;
  40. for (size_t i=1;i<=nPts;i++){
  41. TempT = y[(i-1)*nvar+nt] ;
  42. if(TempT > maxT){
  43. maxT = TempT ;
  44. index = i;
  45. }
  46. }
  47. return(index);
  48. }
  49. double maxCurvPositionR(const double* y, const size_t nt,
  50. const size_t nvar, const size_t nr, size_t nPts){
  51. double maxCurvT=0.0e0;
  52. double gradTp=0.0e0;
  53. double gradTm=0.0e0;
  54. double curvT=0.0e0;
  55. double dx=0.0e0;
  56. double dr=0.0e0;
  57. double pos=0.0e0;
  58. size_t j,jm,jp;
  59. size_t r,rp,rm;
  60. for (size_t i = 1; i <nPts-1; i++) {
  61. j=i*nvar+nt;
  62. jm=(i-1)*nvar+nt;
  63. jp=(i+1)*nvar+nt;
  64. r = i*nvar+nr;
  65. rm = (i-1)*nvar+nr;
  66. rp = (i+1)*nvar+nr;
  67. //gradTp=fabs((y[jp]-y[j])/(x[i+1]-x[i]));
  68. //gradTm=fabs((y[j]-y[jm])/(x[i]-x[i-1]));
  69. //dx=0.5e0*((x[i]+x[i+1])-(x[i-1]+x[i]));
  70. //curvT=(gradTp-gradTm)/dx;
  71. gradTp = fabs((y[jp]-y[j])/(y[rp]-y[r]));
  72. gradTp = fabs((y[j]-y[jm])/(y[r]-y[rm]));
  73. dr = 0.5e0*(y[rp]-y[rm]);
  74. curvT=(gradTp-gradTm)/dr;
  75. if (curvT>=maxCurvT) {
  76. maxCurvT=curvT;
  77. pos=y[r];
  78. }
  79. }
  80. return(pos);
  81. }
  82. int maxCurvIndexR(const double* y, const size_t nt,
  83. const size_t nvar, const size_t nr, size_t nPts){
  84. double maxCurvT=0.0e0;
  85. double gradTp=0.0e0;
  86. double gradTm=0.0e0;
  87. double curvT=0.0e0;
  88. double dx=0.0e0;
  89. double dr=0.0e0;
  90. int pos=0;
  91. size_t j,jm,jp;
  92. size_t r,rm,rp;
  93. for (size_t i = 1; i <nPts-1; i++) {
  94. j=i*nvar+nt;
  95. jm=(i-1)*nvar+nt;
  96. jp=(i+1)*nvar+nt;
  97. r = i*nvar+nr;
  98. rm = (i-1)*nvar+nr;
  99. rp = (i+1)*nvar+nr;
  100. //gradTp=fabs((y[jp]-y[j])/(x[i+1]-x[i]));
  101. //gradTm=fabs((y[j]-y[jm])/(x[i]-x[i-1]));
  102. //dx=0.5e0*((x[i]+x[i+1])-(x[i-1]+x[i]));
  103. //curvT=(gradTp-gradTm)/dx;
  104. gradTp = fabs((y[jp]-y[j])/(y[rp]-y[r]));
  105. gradTp = fabs((y[j]-y[jm])/(y[r]-y[rm]));
  106. dr = 0.5e0*(y[rp]-y[rm]);
  107. curvT=(gradTp-gradTm)/dr;
  108. if (curvT>=maxCurvT) {
  109. maxCurvT=curvT;
  110. pos=i;
  111. }
  112. }
  113. return(pos);
  114. }
  115. double maxGradPosition(const double* y, const size_t nt,
  116. const size_t nvar, const double* x, size_t nPts){
  117. double maxGradT=0.0e0;
  118. double gradT=0.0e0;
  119. double pos=0.0e0;
  120. size_t j,jm;
  121. for (size_t i = 1; i <nPts; i++) {
  122. j=i*nvar+nt;
  123. jm=(i-1)*nvar+nt;
  124. gradT=fabs((y[j]-y[jm])/(x[i]-x[i-1]));
  125. if (gradT>=maxGradT) {
  126. maxGradT=gradT;
  127. pos=x[i];
  128. }
  129. }
  130. return(pos);
  131. }
  132. int maxGradIndex(const double* y, const size_t nt,
  133. const size_t nvar, const double* x, size_t nPts){
  134. double maxGradT=0.0e0;
  135. double gradT=0.0e0;
  136. int pos=0;
  137. size_t j,jm;
  138. for (size_t i = 1; i <nPts; i++) {
  139. j=i*nvar+nt;
  140. jm=(i-1)*nvar+nt;
  141. gradT=fabs((y[j]-y[jm])/(x[i]-x[i-1]));
  142. if (gradT>=maxGradT) {
  143. maxGradT=gradT;
  144. pos=i;
  145. }
  146. }
  147. return(pos);
  148. }
  149. double maxCurvPosition(const double* y, const size_t nt,
  150. const size_t nvar, const double* x, size_t nPts){
  151. double maxCurvT=0.0e0;
  152. double gradTp=0.0e0;
  153. double gradTm=0.0e0;
  154. double curvT=0.0e0;
  155. double dx=0.0e0;
  156. double pos=0.0e0;
  157. size_t j,jm,jp;
  158. for (size_t i = 1; i <nPts-1; i++) {
  159. j=i*nvar+nt;
  160. jm=(i-1)*nvar+nt;
  161. jp=(i+1)*nvar+nt;
  162. gradTp=fabs((y[jp]-y[j])/(x[i+1]-x[i]));
  163. gradTm=fabs((y[j]-y[jm])/(x[i]-x[i-1]));
  164. dx=0.5e0*((x[i]+x[i+1])-(x[i-1]+x[i]));
  165. curvT=(gradTp-gradTm)/dx;
  166. if (curvT>=maxCurvT) {
  167. maxCurvT=curvT;
  168. pos=x[i];
  169. }
  170. }
  171. return(pos);
  172. }
  173. int maxCurvIndex(const double* y, const size_t nt,
  174. const size_t nvar, const double* x, size_t nPts){
  175. double maxCurvT=0.0e0;
  176. double gradTp=0.0e0;
  177. double gradTm=0.0e0;
  178. double curvT=0.0e0;
  179. double dx=0.0e0;
  180. int pos=0;
  181. size_t j,jm,jp;
  182. for (size_t i = 1; i <nPts-1; i++) {
  183. j=i*nvar+nt;
  184. jm=(i-1)*nvar+nt;
  185. jp=(i+1)*nvar+nt;
  186. gradTp=fabs((y[jp]-y[j])/(x[i+1]-x[i]));
  187. gradTm=fabs((y[j]-y[jm])/(x[i]-x[i-1]));
  188. dx=0.5e0*((x[i]+x[i+1])-(x[i-1]+x[i]));
  189. curvT=(gradTp-gradTm)/dx;
  190. if (curvT>=maxCurvT) {
  191. maxCurvT=curvT;
  192. pos=i;
  193. }
  194. }
  195. return(pos);
  196. }
  197. //double isothermPosition(const double* y, const double T, const size_t nt,
  198. // const size_t nvar, const double* x, const size_t nPts){
  199. // double pos=x[nPts-1];
  200. // size_t j;
  201. // for (size_t i = 1; i <nPts; i++) {
  202. // j=i*nvar+nt;
  203. // if (y[j]<=T) {
  204. // pos=x[i];
  205. // break;
  206. // }
  207. // }
  208. // return(pos);
  209. //}
  210. //******************* scan the temperature from left to right ******************//
  211. double isothermPosition(const double* y, const double T, const size_t nt,
  212. const size_t nvar, const double* x, const size_t nPts){
  213. double pos=x[0];
  214. size_t j;
  215. for (size_t i = 0; i <nPts; i++) {
  216. j=i*nvar+nt;
  217. if (y[j]>=T) {
  218. pos=x[i];
  219. break;
  220. }
  221. }
  222. return(pos);
  223. }
  224. void updateSolution(double* y, double* ydot, const size_t nvar,
  225. const double xOld[],const double xNew[],const size_t nPts){
  226. double ytemp[nPts],ydottemp[nPts];
  227. gsl_interp_accel* acc;
  228. gsl_spline* spline;
  229. acc = gsl_interp_accel_alloc();
  230. spline = gsl_spline_alloc(gsl_interp_steffen, nPts);
  231. gsl_interp_accel* accdot;
  232. gsl_spline* splinedot;
  233. accdot = gsl_interp_accel_alloc();
  234. splinedot = gsl_spline_alloc(gsl_interp_steffen, nPts);
  235. for (size_t j = 0; j < nvar; j++) {
  236. for (size_t i = 0; i < nPts; i++) {
  237. ytemp[i]=y[j+i*nvar];
  238. ydottemp[i]=ydot[j+i*nvar];
  239. }
  240. gsl_spline_init(spline,xOld,ytemp,nPts);
  241. gsl_spline_init(splinedot,xOld,ydottemp,nPts);
  242. for (size_t i = 0; i < nPts; i++) {
  243. y[j+i*nvar]=gsl_spline_eval(spline,xNew[i],acc);
  244. ydot[j+i*nvar]=gsl_spline_eval(splinedot,xNew[i],accdot);
  245. }
  246. }
  247. //Exploring "fixing" boundary conditions:
  248. //for (size_t j = 1; j < nvar; j++) {
  249. // //printf("%15.6e\t%15.6e\n", y[j],y[j+nvar]);
  250. // y[j]=y[j+nvar];
  251. // //y[j+(nPts-1)*nvar]=y[j+(nPts-2)*nvar];
  252. // //ydot[j+nvar]=ydot[j];
  253. //}
  254. //y[0]=0.0e0;
  255. gsl_interp_accel_free(acc);
  256. gsl_spline_free(spline);
  257. gsl_interp_accel_free(accdot);
  258. gsl_spline_free(splinedot);
  259. }
  260. //Locate bath gas:
  261. size_t BathGasIndex(UserData data){
  262. size_t index=0;
  263. double max1;
  264. double max=data->gas->massFraction(0);
  265. for(size_t k=1;k<data->nsp;k++){
  266. max1=data->gas->massFraction(k);
  267. if(max1>=max){
  268. max=max1;
  269. index=k;
  270. }
  271. }
  272. return(index+1);
  273. }
  274. //Locate Oxidizer:
  275. size_t oxidizerIndex(UserData data){
  276. size_t index=0;
  277. for(size_t k=1;k<data->nsp;k++){
  278. if(data->gas->speciesName(k-1)=="O2"){
  279. index=k;
  280. }
  281. }
  282. return(index);
  283. }
  284. //Locate OH:
  285. size_t OHIndex(UserData data){
  286. size_t index=0;
  287. for(size_t k=1;k<data->nsp;k++){
  288. if(data->gas->speciesName(k-1)=="OH"){
  289. index=k;
  290. }
  291. }
  292. return(index);
  293. }
  294. //Locate HO2:
  295. size_t HO2Index(UserData data){
  296. size_t index=0;
  297. for(size_t k=1;k<data->nsp;k++){
  298. if(data->gas->speciesName(k-1)=="HO2"){
  299. index=k;
  300. }
  301. }
  302. return(index);
  303. }
  304. //Locate species index:
  305. size_t specIndex(UserData data,char *specName){
  306. size_t index=0;
  307. for(size_t k=1;k<data->nsp;k++){
  308. if(data->gas->speciesName(k-1)==specName){
  309. index=k;
  310. }
  311. }
  312. return(index);
  313. }
  314. int setAlgebraicVariables(N_Vector* id, UserData data){
  315. double *iddata;
  316. N_VConst(ONE, *id);
  317. iddata = N_VGetArrayPointer_OpenMP(*id);
  318. data->k_bath=BathGasIndex(data);
  319. data->k_oxidizer=oxidizerIndex(data);
  320. data->k_OH=OHIndex(data);
  321. data->k_HO2=HO2Index(data);
  322. data->k_drop=specIndex(data,data->dropSpec);
  323. printf("Oxidizer index: %lu\n",data->k_oxidizer);
  324. printf("Bath gas index:%lu\n",data->k_bath);
  325. printf("Droplet species index:%lu\n",data->k_drop);
  326. for (size_t i = 1; i <=data->npts; i++) {
  327. /*Algebraic variables: indicated by ZERO.*/
  328. Rid(i)=ZERO;
  329. Pid(i)=ZERO;
  330. Yid(i,data->k_bath)=ZERO;
  331. Mdotid(i)=ZERO;
  332. }
  333. Mdotid(1)=ZERO;
  334. Rid(1)=ONE;
  335. Yid(1,data->k_drop)=ZERO;
  336. Tid(data->npts)=ZERO;
  337. if(data->constantPressure){
  338. Pid(data->npts)=ONE;
  339. }else{
  340. Pid(data->npts)=ZERO;
  341. Rid(data->npts)=ONE;
  342. }
  343. if(data->dirichletInner){
  344. Tid(1)=ZERO;
  345. }else{
  346. Tid(1)=ONE;
  347. }
  348. if(data->dirichletOuter){
  349. for (size_t k = 1; k <=data->nsp; k++) {
  350. if(k!=data->k_bath){
  351. Yid(data->npts,k)=ONE;
  352. }
  353. Yid(1,k)=ZERO;
  354. Tid(data->npts)=ONE;
  355. }
  356. }else{
  357. for (size_t k = 1; k <=data->nsp; k++){
  358. Yid(1,k)=ZERO;
  359. Yid(data->npts,k)=ZERO;
  360. Tid(data->npts)=ZERO;
  361. }
  362. }
  363. return(0);
  364. }
  365. inline double calc_area(double x,int* i){
  366. switch (*i) {
  367. case 0:
  368. return(ONE);
  369. case 1:
  370. return(x);
  371. case 2:
  372. return(x*x);
  373. default:
  374. return(ONE);
  375. }
  376. }
  377. void readInitialCondition(FILE* input, double* ydata, const size_t nvar, const size_t nr, const size_t nPts, double Rg){
  378. FILE* output;output=fopen("test.dat","w");
  379. size_t bufLen=10000;
  380. size_t nRows=0;
  381. size_t nColumns=nvar;
  382. char buf[bufLen];
  383. char buf1[bufLen];
  384. char comment[1];
  385. char *ret;
  386. while (fgets(buf,bufLen, input)!=NULL){
  387. comment[0]=buf[0];
  388. if(strncmp(comment,"#",1)!=0){
  389. nRows++;
  390. }
  391. }
  392. rewind(input);
  393. printf("nRows: %ld\n", nRows);
  394. double y[nRows*nColumns];
  395. size_t i=0;
  396. while (fgets(buf,bufLen, input)!=NULL){
  397. comment[0]=buf[0];
  398. if(strncmp(comment,"#",1)==0){
  399. }
  400. else{
  401. ret=strtok(buf,"\t");
  402. size_t j=0;
  403. y[i*nColumns+j]=(double)(atof(ret));
  404. j++;
  405. while(ret!=NULL){
  406. ret=strtok(NULL,"\t");
  407. if(j<nColumns){
  408. y[i*nColumns+j]=(double)(atof(ret));
  409. }
  410. j++;
  411. }
  412. i++;
  413. }
  414. }
  415. for (i = 0; i < nRows; i++) {
  416. for (size_t j = 0; j < nColumns; j++) {
  417. fprintf(output, "%15.6e\t",y[i*nColumns+j]);
  418. }
  419. fprintf(output, "\n");
  420. }
  421. fclose(output);
  422. //double xOld[nRows],xNew[nPts],ytemp[nPts];
  423. double xOld[nRows],xNew[nPts],ytemp[nRows];
  424. for (size_t j = 0; j < nRows; j++) {
  425. xOld[j]=y[j*nColumns+nr];
  426. }
  427. //double dx=(xOld[nRows-1] - xOld[0])/((double)(nPts)-1.0e0);
  428. //for (size_t j = 0; j < nPts-1; j++) {
  429. // xNew[j]=(double)j*dx + xOld[0];
  430. //}
  431. //xNew[nPts-1]=xOld[nRows-1];
  432. double dX0;
  433. int NN = nPts-2;
  434. dX0 = (xOld[nRows-1]-xOld[0])*(pow(Rg,1.0/NN) - 1.0)/(pow(Rg,(NN+1.0)/NN) - 1.0);
  435. xNew[0] = xOld[0];
  436. for (size_t i = 1; i < nPts-1; i++) {
  437. xNew[i]=xNew[i-1]+dX0*pow(Rg,(i-1.0)/NN);
  438. }
  439. xNew[nPts-1] = xOld[nRows-1];
  440. gsl_interp_accel* acc;
  441. gsl_spline* spline;
  442. acc = gsl_interp_accel_alloc();
  443. spline = gsl_spline_alloc(gsl_interp_steffen, nRows);
  444. for (size_t j = 0; j < nColumns; j++) {
  445. for (size_t k = 0; k < nRows; k++) {
  446. ytemp[k]=y[j+k*nColumns];
  447. }
  448. gsl_spline_init(spline,xOld,ytemp,nRows);
  449. for (size_t k = 0; k < nPts; k++) {
  450. ydata[j+k*nColumns]=gsl_spline_eval(spline,xNew[k],acc);
  451. }
  452. }
  453. gsl_interp_accel_free(acc);
  454. gsl_spline_free(spline);
  455. }
  456. double systemMass(double* ydata,UserData data){
  457. double mass=0.0e0;
  458. double rho;
  459. for (size_t i = 2; i <=data->npts; i++) {
  460. data->gas->setState_TPY(T(i), P(i), &Y(i,1));
  461. rho=data->gas->density();
  462. //psi(i)=psi(i-1)+rho*(R(i)-R(i-1))*calc_area(HALF*(R(i)+R(i-1)),&m);
  463. mass+=rho*(R(i)-R(i-1))*calc_area(R(i),&data->metric);
  464. }
  465. return(mass);
  466. }
  467. int initializePsiGrid(double* ydata, double* psidata, UserData data){
  468. double rho,rhom;
  469. /*Create a psi grid that corresponds CONSISTENTLY to the spatial grid
  470. * "R" created above. Note that the Lagrangian variable psi has units
  471. * of kg. */
  472. psi(1)=ZERO;
  473. for (size_t i = 2; i <=data->npts; i++) {
  474. data->gas->setState_TPY(T(i), P(i), &Y(i,1));
  475. rho=data->gas->density();
  476. data->gas->setState_TPY(T(i-1), P(i-1), &Y(i-1,1));
  477. rhom=data->gas->density();
  478. //psi(i)=psi(i-1)+rho*(R(i)-R(i-1))*calc_area(HALF*(R(i)+R(i-1)),&data->metric);
  479. //psi(i)=psi(i-1)+rho*(R(i)-R(i-1))*calc_area(R(i),&data->metric);
  480. psi(i)=psi(i-1)+(R(i)-R(i-1))*(rho*calc_area(R(i),&data->metric)+rhom*calc_area(R(i-1),&data->metric))/TWO;
  481. }
  482. /*The mass of the entire system is the value of psi at the last grid
  483. * point. Normalize psi by this mass so that it varies from zero to
  484. * one. This makes psi dimensionless. So the mass needs to be
  485. * multiplied back in the approporiate places in the governing
  486. * equations so that units match.*/
  487. data->mass=psi(data->npts);
  488. for (size_t i = 1; i <=data->npts; i++) {
  489. psi(i)=psi(i)/data->mass;
  490. }
  491. return(0);
  492. }
  493. int setInitialCondition(N_Vector* y,
  494. N_Vector* ydot,
  495. UserData data){
  496. double* ydata;
  497. double* ydotdata;
  498. double* psidata;
  499. double* innerMassFractionsData, Rd, massDrop;
  500. double rhomhalf, lambdamhalf, YVmhalf[data->nsp];
  501. double f=ZERO;
  502. double g=ZERO;
  503. double perturb,rho;
  504. double epsilon=ZERO;
  505. int m,ier;
  506. ydata = N_VGetArrayPointer_OpenMP(*y);
  507. ydotdata = N_VGetArrayPointer_OpenMP(*ydot);
  508. innerMassFractionsData = data->innerMassFractions;
  509. Rd = data->Rd;
  510. massDrop = data->massDrop;
  511. //Mass of droplet
  512. //massDrop=1.0/3.0*Rd*Rd*Rd*997.0; //TODO: The density of the droplet should be a user input
  513. massDrop=1.0/3.0*Rd*Rd*Rd*684.0; //TODO:The density of the droplet(n-heptane) should be a user input
  514. if(data->adaptiveGrid){
  515. psidata = data->grid->xOld;
  516. }
  517. else{
  518. psidata = data->uniformGrid;
  519. }
  520. m=data->metric;
  521. data->innerTemperature=data->initialTemperature;
  522. for (size_t k = 1; k <=data->nsp; k++) {
  523. innerMassFractionsData[k-1]=data->gas->massFraction(k-1);
  524. }
  525. //Define Grid:
  526. double dR=(data->domainLength)/((double)(data->npts)-1.0e0);
  527. double dv=(pow(data->domainLength,1+data->metric)-pow(data->firstRadius*data->domainLength,1+data->metric))/((double)(data->npts)-1.0e0);
  528. //Initialize the R(i),T(i)(data->initialTemperature),Y(i,k),P(i)
  529. for (size_t i = 1; i <=data->npts; i++) {
  530. if(data->metric==0){
  531. R(i)=Rd+(double)((i-1)*dR);
  532. }else{
  533. if(i==1){
  534. R(i)=ZERO;
  535. }else if(i==2){
  536. R(i)=data->firstRadius*data->domainLength;
  537. }else{
  538. R(i)=pow(pow(R(i-1),1+data->metric)+dv,1.0/((double)(1+data->metric)));
  539. }
  540. }
  541. T(i)=data->initialTemperature;
  542. for (size_t k = 1; k <=data->nsp; k++) {
  543. Y(i,k)=data->gas->massFraction(k-1); //Indexing different in Cantera
  544. }
  545. P(i)=data->initialPressure*Cantera::OneAtm;
  546. }
  547. R(data->npts)=data->domainLength+data->Rd;
  548. // /********** test R(i) and the volumn between grids *****************/
  549. // printf("Print the first 4 R(i)s and volumn between them: \n") ;
  550. // printf("Grids: 1st:%2.6e,2nd:%2.6e,3rd:%2.6e,4th:%2.6e \n",R(1),R(2),R(3),R(4));
  551. // double v1,v2,v3,v4,v5;
  552. // v1 =pow(R(2),1+data->metric) - pow(R(1),1+data->metric);
  553. // v2 =pow(R(3),1+data->metric) - pow(R(2),1+data->metric);
  554. // v3 =pow(R(4),1+data->metric) - pow(R(3),1+data->metric);
  555. // v4 =pow(R(5),1+data->metric) - pow(R(4),1+data->metric);
  556. // v5 =pow(R(6),1+data->metric) - pow(R(5),1+data->metric);
  557. // printf("Volumn: 1st:%2.6e,2nd:%2.6e,3rd:%2.6e,4th:%2.6e,5th:%2.6e\n",v1,v2,v3,v4,v5) ;
  558. double Tmax;
  559. double Tmin=data->initialTemperature;
  560. double w=data->mixingWidth;
  561. double YN2=ZERO;
  562. double YO2=ZERO;
  563. double YFuel,YOxidizer,sum;
  564. //if(data->problemType==0){
  565. // data->gas->equilibrate("HP");
  566. // data->maxTemperature=data->gas->temperature();
  567. //}
  568. //else if(data->problemType==1){
  569. // /*Premixed Combustion: Equilibrium products comprise ignition
  570. // * kernel at t=0. The width of the kernel is "mixingWidth"
  571. // * shifted by "shift" from the center.*/
  572. // data->gas->equilibrate("HP");
  573. // Tmax=data->gas->temperature();
  574. // for (size_t i = 1; i <=data->npts; i++) {
  575. // g=HALF*(tanh((R(i)-data->shift)/w)+ONE); //increasing function of x
  576. // f=ONE-g; //decreasing function of x
  577. // T(i)=(Tmax-Tmin)*f+Tmin;
  578. // for (size_t k = 1; k <=data->nsp; k++) {
  579. // Y(i,k)=(data->gas->massFraction(k-1)-Y(i,k))*f+Y(i,k);
  580. // }
  581. // }
  582. // if(data->dirichletOuter){
  583. // T(data->npts)=data->wallTemperature;
  584. // }
  585. //}
  586. //else if(data->problemType==2){
  587. // FILE* input;
  588. // if(input=fopen("initialCondition.dat","r")){
  589. // readInitialCondition(input, ydata, data->nvar, data->nr, data->npts);
  590. // fclose(input);
  591. // }
  592. // else{
  593. // printf("file initialCondition.dat not found!\n");
  594. // return(-1);
  595. // }
  596. //}
  597. initializePsiGrid(ydata,psidata,data);
  598. if(data->adaptiveGrid){
  599. // if(data->problemType!=0){
  600. // data->grid->position=maxGradPosition(ydata, data->nt, data->nvar,
  601. // data->grid->xOld, data->npts);
  602. // //data->grid->position=maxCurvPosition(ydata, data->nt, data->nvar,
  603. // // data->grid->xOld, data->npts);
  604. // }
  605. // else{
  606. // }
  607. if(data->problemType!=3){
  608. data->grid->position=0.0e0;
  609. double x=data->grid->position+data->gridOffset*data->grid->leastMove;
  610. printf("New grid center:%15.6e\n",x);
  611. // /**************** TEST THE data->grid->xOld *******************/
  612. // double* ptr3 = data->grid->xOld ;
  613. // printf("SetInitialCondition function is called,before reGrid,Start print the first 5 elements of the xOld array : \n");
  614. // printf("1st:%.6f, 2nd:%.6f, 3rd:%.6f, 4th:%.6f, 5th:%.6f.\n",ptr3[0],ptr3[1],ptr3[2],ptr3[3],ptr3[4]);
  615. ier=reGrid(data->grid, x);
  616. if(ier==-1)return(-1);
  617. // /**************** TEST THE data->grid->xOld *******************/
  618. // double* ptr = data->grid->xOld ;
  619. // printf("SetInitialCondition function is called,after reGrid,Start print the first 5 elements of the xOld array : \n");
  620. // printf("1st:%.6f, 2nd:%.6f, 3rd:%.6f, 4th:%.6f, 5th:%.6f.\n",ptr[0],ptr[1],ptr[2],ptr[3],ptr[4]);
  621. updateSolution(ydata, ydotdata, data->nvar,
  622. data->grid->xOld,data->grid->x,data->npts);
  623. storeGrid(data->grid->x,data->grid->xOld,data->npts);
  624. }
  625. }
  626. else{
  627. double Rg = data->Rg, dpsi0;
  628. int NN = data->npts-2;
  629. double psiNew[data->npts];
  630. dpsi0 = (pow(Rg,1.0/NN) - 1.0)/(pow(Rg,(NN+1.0)/NN) - 1.0);
  631. psiNew[0] = 0;
  632. for (size_t i = 1; i < data->npts-1; i++) {
  633. psiNew[i]=psiNew[i-1]+dpsi0*pow(Rg,(i-1.0)/NN);
  634. }
  635. psiNew[data->npts-1] = 1.0;
  636. printf("Last point:%15.6e\n",psiNew[data->npts-1]);
  637. updateSolution(ydata, ydotdata, data->nvar,
  638. data->uniformGrid,psiNew,data->npts);
  639. storeGrid(psiNew,data->uniformGrid,data->npts);
  640. //double psiNew[data->npts];
  641. //double dpsi=1.0e0/((double)(data->npts)-1.0e0);
  642. //for (size_t i = 0; i < data->npts; i++) {
  643. // psiNew[i]=(double)(i)*dpsi;
  644. //}
  645. //printf("Last point:%15.6e\n",psiNew[data->npts-1]);
  646. //updateSolution(ydata, ydotdata, data->nvar,
  647. // data->uniformGrid,psiNew,data->npts);
  648. //storeGrid(psiNew,data->uniformGrid,data->npts);
  649. }
  650. if(data->problemType==0){
  651. data->gas->equilibrate("HP");
  652. data->maxTemperature=data->gas->temperature();
  653. }
  654. else if(data->problemType==1){
  655. /*Premixed Combustion: Equilibrium products comprise ignition
  656. * kernel at t=0. The width of the kernel is "mixingWidth"
  657. * shifted by "shift" from the center.*/
  658. data->gas->equilibrate("HP");
  659. Tmax=data->gas->temperature();
  660. for (size_t i = 1; i <=data->npts; i++) {
  661. g=HALF*(tanh((R(i)-data->shift)/w)+ONE); //increasing function of x
  662. f=ONE-g; //decreasing function of x
  663. T(i)=(Tmax-Tmin)*f+Tmin;
  664. for (size_t k = 1; k <=data->nsp; k++) {
  665. Y(i,k)=(data->gas->massFraction(k-1)-Y(i,k))*f+Y(i,k);
  666. }
  667. }
  668. if(data->dirichletOuter){
  669. T(data->npts)=data->wallTemperature;
  670. }
  671. }
  672. else if(data->problemType==2){
  673. FILE* input;
  674. if(input=fopen("initialCondition.dat","r")){
  675. readInitialCondition(input, ydata, data->nvar, data->nr, data->npts, data->Rg);
  676. fclose(input);
  677. }
  678. else{
  679. printf("file initialCondition.dat not found!\n");
  680. return(-1);
  681. }
  682. initializePsiGrid(ydata,psidata,data);
  683. }
  684. else if(data->problemType==3){
  685. FILE* input;
  686. if(input=fopen("restart.bin","r")){
  687. readRestart(y, ydot, input, data);
  688. fclose(input);
  689. printf("Restart solution loaded!\n");
  690. printf("Problem starting at t=%15.6e\n",data->tNow);
  691. return(0);
  692. }
  693. else{
  694. printf("file restart.bin not found!\n");
  695. return(-1);
  696. }
  697. }
  698. if(data->reflectProblem){
  699. double temp;
  700. int j=1;
  701. while (data->npts+1-2*j>=0) {
  702. temp=T(j);
  703. T(j)=T(data->npts+1-j);
  704. T(data->npts+1-j)=temp;
  705. for (size_t k = 1; k <=data->nsp; k++) {
  706. temp=Y(j,k);
  707. Y(j,k)=Y(data->npts+1-j,k);
  708. Y(data->npts+1-j,k)=temp;
  709. }
  710. j=j+1;
  711. }
  712. }
  713. /*Floor small values to zero*/
  714. for (size_t i = 1; i <=data->npts; i++) {
  715. for (size_t k = 1; k <=data->nsp; k++) {
  716. if(fabs(Y(i,k))<=data->massFractionTolerance){
  717. Y(i,k)=0.0e0;
  718. }
  719. }
  720. }
  721. //Set grid to location of maximum curvature calculated by r instead of x:
  722. if(data->adaptiveGrid){
  723. //data->grid->position=maxCurvPosition(ydata, data->nt, data->nvar,
  724. // data->grid->x, data->npts);
  725. int maxCurvII = 0;
  726. maxCurvII = maxCurvIndexR(ydata,data->nt,data->nvar,data->nr,data->npts);
  727. data->grid->position = data->grid->x[maxCurvII];
  728. ier=reGrid(data->grid, data->grid->position);
  729. updateSolution(ydata, ydotdata, data->nvar,
  730. data->grid->xOld,data->grid->x,data->npts);
  731. storeGrid(data->grid->x,data->grid->xOld,data->npts);
  732. /******** Test the maxCurvPosition and related variables *******/
  733. printf("The maxCurvPositition(based on r) is : %.6f,Temperature is : %.3f \n",data->grid->position,T(maxCurvII+1));
  734. }
  735. /*Ensure consistent boundary conditions*/
  736. //T(1)=T(2);
  737. //for (size_t k = 1; k <=data->nsp; k++) {
  738. // Y(1,k)=Y(2,k);
  739. // Y(data->npts,k)=Y(data->npts-1,k);
  740. //}
  741. return(0);
  742. }
  743. inline double Qdot(double* t,
  744. double* x,
  745. double* ignTime,
  746. double* kernelSize,
  747. double* maxQdot){
  748. double qdot;
  749. if(*x<=*kernelSize){
  750. if((*t)<=(*ignTime)){
  751. qdot=(*maxQdot);
  752. }
  753. else{
  754. qdot=0.0e0;
  755. }
  756. }else{
  757. qdot=0.0e0;
  758. }
  759. return(qdot);
  760. }
  761. inline void setGas(UserData data,
  762. double *ydata,
  763. size_t gridPoint){
  764. data->gas->setTemperature(T(gridPoint));
  765. data->gas->setMassFractions_NoNorm(&Y(gridPoint,1));
  766. data->gas->setPressure(P(gridPoint));
  767. }
  768. void getTransport(UserData data,
  769. double *ydata,
  770. size_t gridPoint,
  771. double *rho,
  772. double *lambda,
  773. double YV[]){
  774. double YAvg[data->nsp],
  775. XLeft[data->nsp],
  776. XRight[data->nsp],
  777. gradX[data->nsp];
  778. setGas(data,ydata,gridPoint);
  779. data->gas->getMoleFractions(XLeft);
  780. setGas(data,ydata,gridPoint+1);
  781. data->gas->getMoleFractions(XRight);
  782. for (size_t k = 1; k <=data->nsp; k++) {
  783. YAvg(k)=HALF*(Y(gridPoint,k)+
  784. Y(gridPoint+1,k));
  785. gradX(k)=(XRight(k)-XLeft(k))/
  786. (R(gridPoint+1)-R(gridPoint));
  787. }
  788. double TAvg = HALF*(T(gridPoint)+T(gridPoint+1));
  789. double gradT=(T(gridPoint+1)-T(gridPoint))/
  790. (R(gridPoint+1)-R(gridPoint));
  791. data->gas->setTemperature(TAvg);
  792. data->gas->setMassFractions_NoNorm(YAvg);
  793. data->gas->setPressure(P(gridPoint));
  794. *rho=data->gas->density();
  795. *lambda=data->trmix->thermalConductivity();
  796. data->trmix->getSpeciesFluxes(1,&gradT,data->nsp,
  797. gradX,data->nsp,YV);
  798. //setGas(data,ydata,gridPoint);
  799. }
  800. int residue(double t, N_Vector y, N_Vector ydot, N_Vector res, void *user_data){
  801. /*Declare and fetch nvectors and user data:*/
  802. double *ydata, *ydotdata, *resdata, *psidata, *innerMassFractionsData;
  803. UserData data;
  804. data = (UserData)user_data;
  805. size_t npts=data->npts;
  806. size_t nsp=data->nsp;
  807. size_t k_bath = data->k_bath;
  808. size_t k_drop = data->k_drop;
  809. ydata = N_VGetArrayPointer_OpenMP(y);
  810. ydotdata= N_VGetArrayPointer_OpenMP(ydot);
  811. resdata = N_VGetArrayPointer_OpenMP(res);
  812. if(data->adaptiveGrid==1){
  813. psidata = data->grid->x;
  814. }else{
  815. psidata = data->uniformGrid;
  816. }
  817. innerMassFractionsData = data->innerMassFractions;
  818. /* Grid stencil:*/
  819. /*-------|---------*---------|---------*---------|-------*/
  820. /*-------|---------*---------|---------*---------|-------*/
  821. /*-------|---------*---------|---------*---------|-------*/
  822. /*-------m-------mhalf-------j-------phalf-------p-------*/
  823. /*-------|---------*---------|---------*---------|-------*/
  824. /*-------|---------*---------|---------*---------|-------*/
  825. /*-------|<=======dxm=======>|<=======dxp=======>|-------*/
  826. /*-------|---------*<======dxav=======>*---------|-------*/
  827. /*-------|<================dxpm=================>|-------*/
  828. /* Various variables defined for book-keeping and storing previously
  829. * calculated values:
  830. * rho : densities at points m, mhalf, j, p, and phalf.
  831. * area : the matric at points m, mhalf, j, p, and phalf.
  832. * m : exponent that determines geometry;
  833. * lambda : thermal conductivities at mhalf and phalf.
  834. * mdot : mass flow rate at m, j, and p.
  835. * X : mole fractions at j and p.
  836. * YV : diffusion fluxes at mhalf and phalf.
  837. * Tgrad : temperature gradient at mhalf and phalf.
  838. * Tav : average temperature between two points.
  839. * Pav : average pressure between two points.
  840. * Yav : average mass fractions between two points.
  841. * Xgradhalf : mole fraction gradient at j.
  842. * Cpb : mass based bulk specific heat.
  843. * tranTerm : transient terms.
  844. * advTerm : advection terms.
  845. * diffTerm : diffusion terms.
  846. * srcTerm : source terms.
  847. */
  848. double rhomhalf, rhom, lambdamhalf, YVmhalf[nsp],
  849. rho,
  850. rhophalf, lambdaphalf, YVphalf[nsp],
  851. Cpb, Cvb, Cp[nsp], Cpl, dHvl, rhol, wdot[nsp], enthalpy[nsp], energy[nsp],
  852. tranTerm, diffTerm, srcTerm, advTerm,
  853. area,areamhalf,areaphalf,aream,areamhalfsq,areaphalfsq;
  854. /*Aliases for difference coefficients:*/
  855. double cendfm, cendfc, cendfp;
  856. /*Aliases for various grid spacings:*/
  857. double dpsip, dpsiav, dpsipm, dpsim, dpsimm;
  858. dpsip=dpsiav=dpsipm=dpsim=dpsimm=ONE;
  859. //double mass, mdotIn;
  860. double mass, massDrop;
  861. double sum, sum1, sum2, sum3;
  862. size_t j,k;
  863. int m;
  864. m=data->metric; //Unitless
  865. mass=data->mass; //Units: kg
  866. //massDrop=data->massDrop; //Units: kg
  867. //mdotIn=data->mdot*calc_area(R(npts),&m); //Units: kg/s
  868. // /*evaluate properties at j=1*************************/
  869. setGas(data,ydata,1);
  870. rhom=data->gas->density();
  871. Cpb=data->gas->cp_mass(); //J/kg/K
  872. Cvb=data->gas->cv_mass(); //J/kg/K
  873. //TODO: Create user input model for these. They should not be constant
  874. //Cpl=4.182e03; //J/kg/K for liquid water
  875. //Cpl= 5.67508633e-07*pow(T(1),4) - 7.78060597e-04*pow(T(1),3) + 4.08310544e-01*pow(T(1),2) //J/kg/K for liquid water
  876. // - 9.62429538e+01*T(1) + 1.27131046e+04;
  877. /*Update specific heat:Cpl for liquid n-heptane*/
  878. /*Based on the existiong data,a linear expression is used*/
  879. // Cpl= 12.10476*T(1) - 746.60143; // Unit:J/(kg*K), Need to be improved later
  880. Cpl = 2242.871642; //Unit:J/(kg*K),range:25~520K,Ginnings&Furukawa,NIST
  881. //dHvl=2.260e6; //J/kg heat of vaporization of water
  882. //double Tr = T(1)/647.1; //Reduced Temperature: Droplet Temperature divided by critical temperature of water
  883. //dHvl= 5.2053e07*pow(1-Tr,0.3199 - 0.212*Tr + 0.25795*Tr*Tr)/18.01; //J/kg latent heat of vaporization of water
  884. double Tr = T(1)/540.2; //Reduced Temperature:Droplet Temperature divided by critical temperature of liquid n-heptane, Source:NIST
  885. dHvl = 5.366e5*exp(-0.2831*Tr) * pow((1-Tr),0.2831); //Unit:J/kg, latent heat of vaporization of liquid n-heptane, Source: NIST
  886. /*Following section is related to the property of water*/
  887. //rhol = 997.0;
  888. //massDrop=1.0/3.0*R(1)*R(1)*R(1)*997.0; //TODO: The density of the droplet should be a user input
  889. /*Following section is related to the property of liquid n-heptane (mainly density rho)*/
  890. rhol = 684.0; //Unit:kg/m^3
  891. massDrop = 1.0/3.0*R(1)*R(1)*R(1)*rhol; //Unit:kg, this is the mass of liquid droplet
  892. aream= calc_area(R(1),&m);
  893. /*******************************************************************/
  894. /*Calculate values at j=2's m and mhalf*****************************/
  895. getTransport(data, ydata, 1, &rhomhalf,&lambdamhalf,YVmhalf);
  896. areamhalf= calc_area(HALF*(R(1)+R(2)),&m);
  897. aream = calc_area(R(1),&m);
  898. areamhalfsq= areamhalf*areamhalf;
  899. /*******************************************************************/
  900. /*Fill up res with left side (center) boundary conditions:**********/
  901. /*We impose zero fluxes at the center:*/
  902. /*Mass:*/
  903. if(data->quasiSteady){
  904. Rres(1)=Rdot(1); // Should remain satisfied for quasi-steady droplet
  905. }else{
  906. Rres(1)=Rdot(1) + Mdot(1)/rhol/aream;
  907. }
  908. /*Species:*/
  909. sum=ZERO;
  910. //TODO: Antoine Parameters should be part of user input, not hardcoded
  911. //Yres(1,k_drop)=Y(1,k_drop) - 1.0e5*pow(10,4.6543-(1435.264/(T(1)-64.848)))*data->gas->molecularWeight(k_drop-1)
  912. // / P(1) / data->gas->meanMolecularWeight();
  913. //Yres(1,k_drop)=Y(1,k_drop) - 1.0e3*pow(2.71828,16.7-(4060.0/(T(1)-37.0)))*data->gas->molecularWeight(k_drop-1)
  914. // / P(1) / data->gas->meanMolecularWeight();
  915. //Yres(1,k_drop)=Y(1,k_drop)-2.566785e-02;
  916. /*Following using the Antoine Parameters to calculate the pressure of volatile component(n-heptane)*/
  917. //Antoine parameter from NIST website
  918. double p_i=0.0 ;
  919. p_i = 1.0e5*pow(10,4.02832-(1268.636/(T(1)-56.199))) ; //unit:Pa,FOR N-HEPTANE
  920. //p_i = 1.0e3*pow(2.71828,16.7-(4060.0/(T(1)-37.0))); //Unit:Pa,FOR WATER
  921. Yres(1,k_drop)=Y(1,k_drop) - p_i * data->gas->molecularWeight(k_drop-1)
  922. / P(1) / data->gas->meanMolecularWeight();
  923. sum=sum+Y(1,k_drop);
  924. Mdotres(1)=Mdot(1) - (YVmhalf(k_drop)*areamhalf) / (1-Y(1,k_drop)); //Evaporating mass
  925. for (k = 1; k <=nsp; k++) {
  926. if(k!=k_bath && k!=k_drop){
  927. //TODO: May need to include chemical source term
  928. Yres(1,k)=Y(1,k)*Mdot(1) + YVmhalf(k)*areamhalf;
  929. //Yres(1,k)=YVmhalf(k)*areamhalf;
  930. sum=sum+Y(1,k);
  931. //if(fabs(Mdot(1))>1e-14){
  932. ///Yres(1,k)=innerMassFractionsData[k-1]-
  933. /// Y(1,k)-
  934. /// (YVmhalf(k)*areamhalf)/Mdot(1);
  935. //Yres(1,k)=Y(1,k)*Mdot(1) + YVmhalf(k)*areamhalf;
  936. //}
  937. //else{
  938. // //Yres(1,k)=Y(1,k)-innerMassFractionsData[k-1];
  939. // Yres(1,k)=Y(2,k)-Y(1,k);
  940. // /*The below flux boundary condition makes the
  941. // * problem more prone to diverge. How does one
  942. // * fix this?*/
  943. // //Yres(1,k)=YVmhalf(k);
  944. //}
  945. }
  946. }
  947. Yres(1,k_bath)=ONE-sum-Y(1,k_bath);
  948. /*Energy:*/
  949. if(data->dirichletInner){
  950. //Tres(1)=Tdot(1);
  951. //Tres(1)=T(1)-data->innerTemperature;
  952. Tres(1)=lambdamhalf*rhomhalf*areamhalfsq*(T(2)-T(1))/((psi(2)-psi(1))*mass)/dHvl - YVmhalf(k_drop)*areamhalf/(1-Y(1,k_drop));
  953. }else{
  954. //Tres(1)=Tdot(1) -
  955. // (rhomhalf*areamhalfsq*lambdamhalf*(T(2)-T(1))/((psi(2)-psi(1))*mass) - Mdot(1)*dHvl)
  956. // / (massDrop * Cpl);
  957. Tres(1)=Tdot(1) -
  958. (areamhalf*lambdamhalf*(T(2)-T(1))/(R(2)-R(1)) - Mdot(1)*dHvl)
  959. / (massDrop * Cpl);
  960. //Tres(1)=T(2)-T(1);
  961. //Tres(1)=Tdot(1) - (Pdot(1)/(rhom*Cpb))
  962. // +(double)(data->metric+1)*(rhomhalf*lambdamhalf*areamhalfsq*(T(2)-T(1))/psi(2)-psi(1));
  963. }
  964. /*Pressure:*/
  965. Pres(1)=P(2)-P(1);
  966. /*Fill up res with governing equations at inner points:*************/
  967. for (j = 2; j < npts; j++) {
  968. /*evaluate various mesh differences*///
  969. dpsip = (psi(j+1) - psi(j) )*mass;
  970. dpsim = (psi(j) - psi(j-1))*mass;
  971. dpsiav = HALF*(psi(j+1) - psi(j-1))*mass;
  972. dpsipm = (psi(j+1) - psi(j-1))*mass;
  973. /***********************************///
  974. /*evaluate various central difference coefficients*/
  975. cendfm = - dpsip / (dpsim*dpsipm);
  976. cendfc = (dpsip-dpsim) / (dpsip*dpsim);
  977. cendfp = dpsim / (dpsip*dpsipm);
  978. /**************************************************/
  979. /*evaluate properties at j*************************/
  980. setGas(data,ydata,j);
  981. rho=data->gas->density(); //kg/m^3
  982. Cpb=data->gas->cp_mass(); //J/kg/K
  983. Cvb=data->gas->cv_mass(); //J/kg/K
  984. data->gas->getNetProductionRates(wdot); //kmol/m^3
  985. data->gas->getEnthalpy_RT(enthalpy); //unitless
  986. data->gas->getCp_R(Cp); //unitless
  987. area = calc_area(R(j),&m); //m^2
  988. /*evaluate properties at p*************************/
  989. getTransport(data, ydata, j, &rhophalf,&lambdaphalf,YVphalf);
  990. areaphalf= calc_area(HALF*(R(j)+R(j+1)),&m);
  991. areaphalfsq= areaphalf*areaphalf;
  992. /**************************************************///
  993. /*Evaporating Mass*/
  994. Mdotres(j)=Mdot(j) - Mdot(j-1);
  995. /*Mass:*/
  996. /* ∂r/∂ψ = 1/ρA */
  997. Rres(j)=((R(j)-R(j-1))/dpsim)-(TWO/(rhom*aream+rho*area));
  998. /*Energy:*/
  999. /* ∂T/∂t = - ṁ(∂T/∂ψ)
  1000. * + (∂/∂ψ)(λρA²∂T/∂ψ)
  1001. * - (A/cₚ) ∑ YᵢVᵢcₚᵢ(∂T/∂ψ)
  1002. * - (1/ρcₚ)∑ ώᵢhᵢ
  1003. * + (1/ρcₚ)(∂P/∂t) */
  1004. /*Notes:
  1005. * λ has units J/m/s/K.
  1006. * YᵢVᵢ has units kg/m^2/s.
  1007. * hᵢ has units J/kmol, so we must multiply the enthalpy
  1008. * defined above (getEnthalpy_RT) by T (K) and the gas constant
  1009. * (J/kmol/K) to get the right units.
  1010. * cₚᵢ has units J/kg/K, so we must multiply the specific heat
  1011. * defined above (getCp_R) by the gas constant (J/kmol/K) and
  1012. * divide by the molecular weight (kg/kmol) to get the right
  1013. * units.
  1014. * */
  1015. //enthalpy formulation:
  1016. //tranTerm = Tdot(j) - (Pdot(j)/(rho*Cpb));
  1017. tranTerm = Tdot(j);
  1018. sum=ZERO;
  1019. sum1=ZERO;
  1020. for (k = 1; k <=nsp; k++) {
  1021. sum=sum+wdot(k)*enthalpy(k);
  1022. sum1=sum1+(Cp(k)/data->gas->molecularWeight(k-1))*rho
  1023. *HALF*(YVmhalf(k)+YVphalf(k));
  1024. }
  1025. sum=sum*Cantera::GasConstant*T(j);
  1026. sum1=sum1*Cantera::GasConstant;
  1027. diffTerm =(( (rhophalf*areaphalfsq*lambdaphalf*(T(j+1)-T(j))/dpsip)
  1028. -(rhomhalf*areamhalfsq*lambdamhalf*(T(j)-T(j-1))/dpsim) )
  1029. /(dpsiav*Cpb) )
  1030. -(sum1*area*(cendfp*T(j+1)
  1031. +cendfc*T(j)
  1032. +cendfm*T(j-1))/Cpb);
  1033. srcTerm = (sum-Qdot(&t,&R(j),&data->ignTime,&data->kernelSize,&data->maxQDot))/(rho*Cpb); // Qdot is forced heating to cause ignition, sum is the conversion of chemical enthalpy to sensible enthalpy
  1034. advTerm = (Mdot(j)*(T(j)-T(j-1))/dpsim);
  1035. Tres(j)= tranTerm - (Pdot(j)/(rho*Cpb))
  1036. +advTerm
  1037. -diffTerm
  1038. +srcTerm;
  1039. // //energy formulation:
  1040. // tranTerm = Tdot(j);
  1041. // sum=ZERO;
  1042. // sum1=ZERO;
  1043. // sum2=ZERO;
  1044. // sum3=ZERO;
  1045. // for (k = 1; k <=nsp; k++) {
  1046. // energy(k)=enthalpy(k)-ONE;
  1047. // sum=sum+wdot(k)*energy(k);
  1048. // sum1=sum1+(Cp(k)/data->gas->molecularWeight(k-1))*rho
  1049. // *HALF*(YVmhalf(k)+YVphalf(k));
  1050. // sum2=sum2+(YVmhalf(k)/data->gas->molecularWeight(k-1));
  1051. // sum3=sum3+(YVphalf(k)/data->gas->molecularWeight(k-1));
  1052. // }
  1053. // sum=sum*Cantera::GasConstant*T(j);
  1054. // sum1=sum1*Cantera::GasConstant;
  1055. // diffTerm =(( (rhophalf*areaphalfsq*lambdaphalf*(T(j+1)-T(j))/dpsip)
  1056. // -(rhomhalf*areamhalfsq*lambdamhalf*(T(j)-T(j-1))/dpsim) )
  1057. // /(dpsiav*Cvb) )
  1058. // -(sum1*area*(cendfp*T(j+1)
  1059. // +cendfc*T(j)
  1060. // +cendfm*T(j-1))/Cvb);
  1061. // srcTerm = (sum-Qdot(&t,&R(j),&data->ignTime,&data->kernelSize,&data->maxQDot))/(rho*Cvb);
  1062. // advTerm = (mdotIn*(T(j)-T(j-1))/dpsim);
  1063. // advTerm = advTerm + (Cantera::GasConstant*T(j)*area/Cvb)*((sum3-sum2)/dpsiav);
  1064. // Tres(j)= tranTerm
  1065. // +advTerm
  1066. // -diffTerm
  1067. // +srcTerm;
  1068. /*Species:*/
  1069. /* ∂Yᵢ/∂t = - ṁ(∂Yᵢ/∂ψ)
  1070. * - (∂/∂ψ)(AYᵢVᵢ)
  1071. * + (ώᵢWᵢ/ρ) */
  1072. sum=ZERO;
  1073. for (k = 1; k <=nsp; k++) {
  1074. if(k!=k_bath){
  1075. tranTerm = Ydot(j,k);
  1076. diffTerm = (YVphalf(k)*areaphalf
  1077. -YVmhalf(k)*areamhalf)/dpsiav;
  1078. srcTerm = wdot(k)
  1079. *(data->gas->molecularWeight(k-1))/rho;
  1080. advTerm = (Mdot(j)*(Y(j,k)-Y(j-1,k))/dpsim);
  1081. Yres(j,k)= tranTerm
  1082. +advTerm
  1083. +diffTerm
  1084. -srcTerm;
  1085. sum=sum+Y(j,k);
  1086. }
  1087. }
  1088. Yres(j,k_bath)=ONE-sum-Y(j,k_bath);
  1089. /*Pressure:*/
  1090. Pres(j) = P(j+1)-P(j);
  1091. /*Assign values evaluated at p and phalf to m
  1092. * and mhalf to save some cpu cost:****************/
  1093. areamhalf=areaphalf;
  1094. areamhalfsq=areaphalfsq;
  1095. aream=area;
  1096. rhom=rho;
  1097. rhomhalf=rhophalf;
  1098. lambdamhalf=lambdaphalf;
  1099. for (k = 1; k <=nsp; k++) {
  1100. YVmhalf(k)=YVphalf(k);
  1101. }
  1102. /**************************************************/
  1103. }
  1104. /*******************************************************************///
  1105. /*Fill up res with right side (wall) boundary conditions:***********/
  1106. /*We impose zero fluxes at the wall:*/
  1107. setGas(data,ydata,npts);
  1108. rho=data->gas->density();
  1109. area = calc_area(R(npts),&m);
  1110. /*Mass:*/
  1111. dpsim=(psi(npts)-psi(npts-1))*mass;
  1112. Rres(npts)=((R(npts)-R(npts-1))/dpsim)-(TWO/(rhom*aream+rho*area));
  1113. /*Energy:*/
  1114. if(data->dirichletOuter){
  1115. //Tres(npts)=T(npts)-data->wallTemperature;
  1116. Tres(npts)=Tdot(npts);
  1117. }
  1118. else{
  1119. Tres(npts)=T(npts)-T(npts-1);
  1120. }
  1121. /*Species:*/
  1122. sum=ZERO;
  1123. if(data->dirichletOuter){
  1124. for (k = 1; k <=nsp; k++) {
  1125. if(k!=k_bath){
  1126. Yres(npts,k)=Ydot(npts,k);
  1127. sum=sum+Y(npts,k);
  1128. }
  1129. }
  1130. }
  1131. else{
  1132. for (k = 1; k <=nsp; k++) {
  1133. if(k!=k_bath){
  1134. Yres(npts,k)=Y(npts,k)-Y(npts-1,k);
  1135. //Yres(npts,k)=YVmhalf(k);
  1136. sum=sum+Y(npts,k);
  1137. }
  1138. }
  1139. }
  1140. Yres(npts,k_bath)=ONE-sum-Y(npts,k_bath);
  1141. /*Pressure:*/
  1142. if(data->constantPressure){
  1143. Pres(npts)=Pdot(npts)-data->dPdt;
  1144. }
  1145. else{
  1146. Pres(npts)=R(npts)-data->domainLength;
  1147. //Pres(npts)=Rdot(npts);
  1148. }
  1149. /*Evaporating Mass*/
  1150. Mdotres(npts)=Mdot(npts) - Mdot(npts-1);
  1151. //for (j = 1; j <=npts; j++) {
  1152. // //for (k = 1; k <=nsp; k++) {
  1153. // // Yres(j,k)=Ydot(j,k);
  1154. // //}
  1155. // //Tres(j)=Tdot(j);
  1156. //}
  1157. return(0);
  1158. }
  1159. void printSpaceTimeHeader(UserData data)
  1160. {
  1161. fprintf((data->output), "%15s\t","#1");
  1162. for (size_t k = 1; k <=data->nvar+1; k++) {
  1163. fprintf((data->output), "%15lu\t",k+1);
  1164. }
  1165. fprintf((data->output), "%15lu\n",data->nvar+3);
  1166. fprintf((data->output), "%15s\t%15s\t%15s\t","#psi","time(s)","dpsi");
  1167. fprintf((data->output), "%15s\t%15s\t","radius(m)","Temp(K)");
  1168. for (size_t k = 1; k <=data->nsp; k++) {
  1169. fprintf((data->output), "%15s\t",data->gas->speciesName(k-1).c_str());
  1170. }
  1171. fprintf((data->output), "%15s\t","Pressure(Pa)");
  1172. fprintf((data->output), "%15s\n","Mdot (kg/s)");
  1173. }
  1174. void printSpaceTimeOutput(double t, N_Vector* y, FILE* output, UserData data)
  1175. {
  1176. double *ydata,*psidata;
  1177. ydata = N_VGetArrayPointer_OpenMP(*y);
  1178. if(data->adaptiveGrid){
  1179. psidata = data->grid->x;
  1180. }else{
  1181. psidata = data->uniformGrid;
  1182. }
  1183. for (size_t i = 0; i < data->npts; i++) {
  1184. fprintf(output, "%15.9e\t%15.9e\t",psi(i+1),t);
  1185. if(i==0){
  1186. fprintf(output, "%15.9e\t",psi(2)-psi(1));
  1187. }
  1188. else{
  1189. fprintf(output, "%15.6e\t",psi(i+1)-psi(i));
  1190. }
  1191. for (size_t j = 0; j < data->nvar; j++) {
  1192. if(j!=data->nvar-1){
  1193. fprintf(output, "%15.9e\t",ydata[j+i*data->nvar]);
  1194. }else{
  1195. fprintf(output, "%15.9e",ydata[j+i*data->nvar]);
  1196. }
  1197. }
  1198. fprintf(output, "\n");
  1199. }
  1200. fprintf(output, "\n");
  1201. }
  1202. void writeRestart(double t, N_Vector* y, N_Vector* ydot, FILE* output, UserData data){
  1203. double *ydata,*psidata, *ydotdata;
  1204. ydata = N_VGetArrayPointer_OpenMP(*y);
  1205. ydotdata = N_VGetArrayPointer_OpenMP(*ydot);
  1206. if(data->adaptiveGrid){
  1207. psidata = data->grid->x;
  1208. }else{
  1209. psidata = data->uniformGrid;
  1210. }
  1211. fwrite(&t, sizeof(t), 1, output); //write time
  1212. fwrite(psidata, data->npts*sizeof(psidata), 1, output); //write grid
  1213. fwrite(ydata, data->neq*sizeof(ydata), 1, output); //write solution
  1214. fwrite(ydotdata, data->neq*sizeof(ydotdata), 1, output); //write solutiondot
  1215. }
  1216. void readRestart(N_Vector* y, N_Vector* ydot, FILE* input, UserData data){
  1217. double *ydata,*psidata, *ydotdata;
  1218. double t;
  1219. if(data->adaptiveGrid){
  1220. psidata = data->grid->x;
  1221. }else{
  1222. psidata = data->uniformGrid;
  1223. }
  1224. ydata = N_VGetArrayPointer_OpenMP(*y);
  1225. ydotdata = N_VGetArrayPointer_OpenMP(*ydot);
  1226. fread(&t, sizeof(t), 1, input);
  1227. data->tNow=t;
  1228. fread(psidata, data->npts*sizeof(psidata), 1, input);
  1229. fread(ydata, data->neq*sizeof(ydata), 1, input);
  1230. fread(ydotdata, data->neq*sizeof(ydotdata), 1, input);
  1231. if(data->adaptiveGrid){
  1232. storeGrid(data->grid->x,data->grid->xOld,data->npts);
  1233. }
  1234. }
  1235. void printGlobalHeader(UserData data)
  1236. {
  1237. fprintf((data->globalOutput), "%8s\t","#Time(s)");
  1238. //fprintf((data->globalOutput), "%15s","S_u(exp*)(m/s)");
  1239. fprintf((data->globalOutput), "%15s","bFlux(kg/m^2/s)");
  1240. fprintf((data->globalOutput), "%16s"," IsothermPos(m)");
  1241. fprintf((data->globalOutput), "%15s\t","Pressure(Pa)");
  1242. fprintf((data->globalOutput), "%15s\t","Pdot(Pa/s)");
  1243. fprintf((data->globalOutput), "%15s\t","gamma");
  1244. fprintf((data->globalOutput), "%15s\t","S_u(m/s)");
  1245. fprintf((data->globalOutput), "%15s\t","Tu(K)");
  1246. fprintf((data->globalOutput), "\n");
  1247. }
  1248. //
  1249. //void printSpaceTimeRates(double t, N_Vector ydot, UserData data)
  1250. //{
  1251. // double *ydotdata,*psidata;
  1252. // ydotdata = N_VGetArrayPointer_OpenMP(ydot);
  1253. // psidata = N_VGetArrayPointer_OpenMP(data->grid);
  1254. // for (int i = 0; i < data->npts; i++) {
  1255. // fprintf((data->ratesOutput), "%15.6e\t%15.6e\t",psi(i+1),t);
  1256. // for (int j = 0; j < data->nvar; j++) {
  1257. // fprintf((data->ratesOutput), "%15.6e\t",ydotdata[j+i*data->nvar]);
  1258. // }
  1259. // fprintf((data->ratesOutput), "\n");
  1260. // }
  1261. // fprintf((data->ratesOutput), "\n\n");
  1262. //}
  1263. //
  1264. void printGlobalVariables(double t, N_Vector* y, N_Vector* ydot, UserData data)
  1265. {
  1266. double *ydata,*ydotdata, *innerMassFractionsData, *psidata;
  1267. innerMassFractionsData = data->innerMassFractions;
  1268. if(data->adaptiveGrid){
  1269. psidata = data->grid->x;
  1270. }else{
  1271. psidata = data->uniformGrid;
  1272. }
  1273. double TAvg, RAvg, YAvg, psiAvg;
  1274. ydata = N_VGetArrayPointer_OpenMP(*y);
  1275. ydotdata = N_VGetArrayPointer_OpenMP(*ydot);
  1276. TAvg=data->isotherm;
  1277. double sum=ZERO;
  1278. double dpsim,area,aream,drdt;
  1279. double Cpb,Cvb,gamma,rho,flameArea,Tu;
  1280. /*Find the isotherm chosen by the user*/
  1281. size_t j=1;
  1282. size_t jj=1;
  1283. size_t jjj=1;
  1284. double wdot[data->nsp];
  1285. double wdotMax=0.0e0;
  1286. double advTerm=0.0e0;
  1287. psiAvg=0.0e0;
  1288. if(T(data->npts)>T(1)){
  1289. while (T(j)<TAvg) {
  1290. j=j+1;
  1291. }
  1292. YAvg=innerMassFractionsData[data->k_oxidizer-1]-Y(data->npts,data->k_oxidizer);
  1293. while (fabs((T(jj+1)-T(jj))/T(jj))>1e-08) {
  1294. jj=jj+1;
  1295. }
  1296. setGas(data,ydata,jj);
  1297. Tu=T(jj);
  1298. rho=data->gas->density();
  1299. Cpb=data->gas->cp_mass(); //J/kg/K
  1300. Cvb=data->gas->cv_mass(); //J/kg/K
  1301. gamma=Cpb/Cvb;
  1302. }
  1303. else{
  1304. while (T(j)>TAvg) {
  1305. j=j+1;
  1306. }
  1307. YAvg=innerMassFractionsData[data->k_oxidizer-1]-Y(1,data->k_oxidizer);
  1308. while (fabs((T(data->npts-jj-1)-T(data->npts-jj))/T(data->npts-jj))>1e-08) {
  1309. jj=jj+1;
  1310. }
  1311. setGas(data,ydata,data->npts-jj);
  1312. Tu=T(data->npts-jj);
  1313. rho=data->gas->density();
  1314. Cpb=data->gas->cp_mass(); //J/kg/K
  1315. Cvb=data->gas->cv_mass(); //J/kg/K
  1316. gamma=Cpb/Cvb;
  1317. }
  1318. if(T(j)<TAvg){
  1319. RAvg=((R(j+1)-R(j))/(T(j+1)-T(j)))*(TAvg-T(j))+R(j);
  1320. }
  1321. else{
  1322. RAvg=((R(j)-R(j-1))/(T(j)-T(j-1)))*(TAvg-T(j-1))+R(j-1);
  1323. }
  1324. ////Experimental burning speed calculation:
  1325. //int nMax=0;
  1326. ////nMax=maxCurvIndex(ydata, data->nt, data->nvar,
  1327. //// data->grid->x, data->npts);
  1328. //nMax=maxGradIndex(ydata, data->nt, data->nvar,
  1329. // data->grid->x, data->npts);
  1330. //advTerm=(T(nMax)-T(nMax-1))/(data->mass*(psi(nMax)-psi(nMax-1)));
  1331. //aream=calc_area(R(nMax),&data->metric);
  1332. ////setGas(data,ydata,nMax);
  1333. ////rho=data->gas->density();
  1334. //psiAvg=-Tdot(nMax)/(rho*aream*advTerm);
  1335. ////if(t>data->ignTime){
  1336. //// for(size_t n=2;n<data->npts;n++){
  1337. //// setGas(data,ydata,n);
  1338. //// data->gas->getNetProductionRates(wdot); //kmol/m^3
  1339. //// advTerm=(T(n)-T(n-1))/(data->mass*(psi(n)-psi(n-1)));
  1340. //// if(fabs(wdot[data->k_oxidizer-1])>=wdotMax){
  1341. //// aream=calc_area(R(n),&data->metric);
  1342. //// psiAvg=-Tdot(n)/(rho*aream*advTerm);
  1343. //// wdotMax=fabs(wdot[data->k_oxidizer-1]);
  1344. //// }
  1345. //// }
  1346. ////}
  1347. ////else{
  1348. //// psiAvg=0.0e0;
  1349. ////}
  1350. //drdt=(RAvg-data->flamePosition[1])/(t-data->flameTime[1]);
  1351. //data->flamePosition[0]=data->flamePosition[1];
  1352. //data->flamePosition[1]=RAvg;
  1353. //data->flameTime[0]=data->flameTime[1];
  1354. //data->flameTime[1]=t;
  1355. //flameArea=calc_area(RAvg,&data->metric);
  1356. /*Use the Trapezoidal rule to calculate the mass burning rate based on
  1357. * the consumption of O2*/
  1358. aream= calc_area(R(1)+1e-03*data->domainLength,&data->metric);
  1359. for (j = 2; j <data->npts; j++) {
  1360. dpsim=(psi(j)-psi(j-1))*data->mass;
  1361. area= calc_area(R(j),&data->metric);
  1362. sum=sum+HALF*dpsim*((Ydot(j-1,data->k_oxidizer)/aream)
  1363. +(Ydot(j,data->k_oxidizer)/area));
  1364. aream=area;
  1365. }
  1366. //double maxOH,maxHO2;
  1367. //maxOH=0.0e0;
  1368. //maxHO2=0.0e0;
  1369. //for(j=1;j<data->npts;j++){
  1370. // if(Y(j,data->k_OH)>maxOH){
  1371. // maxOH=Y(j,data->k_OH);
  1372. // }
  1373. //}
  1374. //for(j=1;j<data->npts;j++){
  1375. // if(Y(j,data->k_HO2)>maxHO2){
  1376. // maxHO2=Y(j,data->k_HO2);
  1377. // }
  1378. //}
  1379. fprintf((data->globalOutput), "%15.6e\t",t);
  1380. //fprintf((data->globalOutput), "%15.6e\t",psiAvg);
  1381. fprintf((data->globalOutput), "%15.6e\t",fabs(sum)/YAvg);
  1382. fprintf((data->globalOutput), "%15.6e\t",RAvg);
  1383. fprintf((data->globalOutput), "%15.6e\t",P(data->npts));
  1384. fprintf((data->globalOutput), "%15.6e\t",Pdot(data->npts));
  1385. fprintf((data->globalOutput), "%15.6e\t",gamma);
  1386. fprintf((data->globalOutput), "%15.6e\t",fabs(sum)/(YAvg*rho));
  1387. fprintf((data->globalOutput), "%15.6e\t",Tu);
  1388. fprintf((data->globalOutput), "\n");
  1389. }
  1390. //
  1391. //void printSpaceTimeOutputInterpolated(double t, N_Vector y, UserData data)
  1392. //{
  1393. // double *ydata,*psidata;
  1394. // ydata = N_VGetArrayPointer_OpenMP(y);
  1395. // psidata = N_VGetArrayPointer_OpenMP(data->grid);
  1396. // for (int i = 0; i < data->npts; i++) {
  1397. // fprintf((data->gridOutput), "%15.6e\t%15.6e\t",psi(i+1),t);
  1398. // for (int j = 0; j < data->nvar; j++) {
  1399. // fprintf((data->gridOutput), "%15.6e\t",ydata[j+i*data->nvar]);
  1400. // }
  1401. // fprintf((data->gridOutput), "\n");
  1402. // }
  1403. // fprintf((data->gridOutput), "\n\n");
  1404. //}
  1405. //
  1406. //
  1407. ////void repairSolution(N_Vector y, N_Vector ydot, UserData data){
  1408. //// int npts=data->npts;
  1409. //// double *ydata;
  1410. //// double *ydotdata;
  1411. //// ydata = N_VGetArrayPointer_OpenMP(y);
  1412. //// ydotdata = N_VGetArrayPointer_OpenMP(ydot);
  1413. ////
  1414. //// T(2)=T(1);
  1415. //// T(npts-1)=T(npts);
  1416. //// Tdot(2)=Tdot(1);
  1417. //// Tdot(npts-1)=Tdot(npts);
  1418. //// for (int k = 1; k <=data->nsp; k++) {
  1419. //// Y(2,k)=Y(1,k);
  1420. //// Y(npts-1,k)=Y(npts,k);
  1421. ////
  1422. //// Ydot(2,k)=Ydot(1,k);
  1423. //// Ydot(npts-1,k)=Ydot(npts,k);
  1424. //// }
  1425. ////}
  1426. /*Following functions are added to derive the characteristic time scale of species*/
  1427. void getTimescale(UserData data, N_Vector* y){
  1428. size_t i, k, nsp,npts ;
  1429. nsp = data->nsp ;
  1430. npts = data->npts ;
  1431. double rho, wdot_mole[nsp], wdot_mass[nsp],MW[nsp],concentra[nsp];
  1432. //double time_scale[npts*nsp] ;
  1433. double* ydata ;
  1434. ydata = N_VGetArrayPointer_OpenMP(*y); //access the data stored in N_Vector* y
  1435. for(i=1; i<= npts;i++){
  1436. setGas(data,ydata,i); //set the gas state at each grid point
  1437. rho = data->gas->density(); //get the averaged density at each grid point, Unit:kg/m^3
  1438. data->gas->getNetProductionRates(wdot_mole) ; //Unit:kmol/(m^3 * s)
  1439. for(k=1; k<= nsp; k++){
  1440. MW(k) = data->gas->molecularWeight(k-1) ; //Unit:kg/kmol
  1441. }
  1442. for(k=1; k<= nsp; k++){
  1443. wdot_mass(k) = wdot_mole(k) * MW(k) ; //Unit:kg/(m^3 * s)
  1444. }
  1445. for(k=1; k<= nsp; k++){
  1446. concentra(k) = Y(i,k) * rho ; //Unit:kg/m^3
  1447. }
  1448. for(k=1;k<= nsp;k++){
  1449. data->time_scale(i,k) = concentra(k)/(wdot_mass(k)+ 1.00e-16) ;
  1450. }
  1451. }
  1452. }
  1453. void printTimescaleHeader(UserData data)
  1454. {
  1455. fprintf((data->timescaleOutput), "%15s\t","#1");
  1456. for (size_t k = 1; k <=data->nsp+1; k++) {
  1457. fprintf((data->timescaleOutput), "%15lu\t",k+1);
  1458. }
  1459. fprintf((data->timescaleOutput), "%15lu\n",data->nsp+3);
  1460. fprintf((data->timescaleOutput), "%15s\t%15s\t%15s\t","#time","radius","Temp(K)");
  1461. //fprintf((data->output), "%15s\t%15s\t","radius(m)","Temp(K)");
  1462. for (size_t k = 1; k <=(data->nsp); k++) {
  1463. fprintf((data->timescaleOutput), "%15s\t",data->gas->speciesName(k-1).c_str());
  1464. }
  1465. //fprintf((data->output), "%15s\t","Pressure(Pa)");
  1466. //fprintf((data->timescaleOutput), "%15s\n",data->gas->speciesName(data->nsp-1).c_str());
  1467. //fprintf((data->output), "%15s\n","Mdot (kg/s)");
  1468. fprintf((data->timescaleOutput), "\n");
  1469. }
  1470. void printTimescaleOutput(double t,N_Vector* y,FILE* output,UserData data)
  1471. {
  1472. double* ydata;
  1473. ydata = N_VGetArrayPointer_OpenMP(*y);
  1474. for(size_t i=1 ; i<= data->npts; i++){
  1475. fprintf(output, "%15.9e\t%15.9e\t",t,R(i));
  1476. fprintf(output, "%15.9e\t",T(i));
  1477. for(size_t k=1; k<=data->nsp;k++){
  1478. fprintf(output, "%15.9e\t",data->time_scale(i,k));
  1479. }
  1480. fprintf(output, "\n");
  1481. }
  1482. fprintf(output, "\n");
  1483. }
  1484. void floorSmallValue(UserData data, N_Vector* y)
  1485. {
  1486. double* ydata;
  1487. ydata = N_VGetArrayPointer_OpenMP(*y);
  1488. //double sum = 0.00;
  1489. size_t k_bath = data->k_bath;
  1490. /*Floor small values to zero*/
  1491. for (size_t i = 1; i <=data->npts; i++) {
  1492. for (size_t k = 1; k <=data->nsp; k++) {
  1493. if(fabs(Y(i,k))<=data->massFractionTolerance){
  1494. Y(i,k)=0.0e0;
  1495. }
  1496. }
  1497. }
  1498. /*Dump the error to the bath gas*/
  1499. for (size_t i = 1; i <=data->npts; i++) {
  1500. double sum = 0.00;
  1501. for (size_t k = 1; k <=data->nsp; k++) {
  1502. if(k!=k_bath){
  1503. sum = sum + Y(i,k);
  1504. }
  1505. }
  1506. Y(i,k_bath) = ONE-sum;
  1507. }
  1508. }
  1509. void resetTolerance(UserData data, N_Vector* y,N_Vector* atolv)
  1510. {
  1511. double* ydata;
  1512. realtype* atolvdata;
  1513. ydata = N_VGetArrayPointer_OpenMP(*y);
  1514. atolvdata = N_VGetArrayPointer_OpenMP(*atolv);
  1515. double relTol,radTol,tempTol,presTol,massFracTol,bathGasTol,mdotTol;
  1516. double maxT=0.00, ignT=1800;
  1517. relTol = 1.0e-03 ;
  1518. radTol = 1.0e-05 ;
  1519. tempTol = 1.0e-01 ;
  1520. presTol = 1.0e00 ;
  1521. massFracTol = 1.0e-08;
  1522. bathGasTol = 1.0e-04 ;
  1523. mdotTol = 1.0e-09 ;
  1524. /*Get the maximum Tempture*/
  1525. for (size_t i =1;i <= data->npts;i++){
  1526. if(T(i) > maxT){
  1527. maxT = T(i);
  1528. }
  1529. }
  1530. /*reset the tolerance when maxT > ignT*/
  1531. if(maxT >= ignT){
  1532. data->relativeTolerance = relTol;
  1533. for(size_t i =1; i<=data->npts; i++){
  1534. atolT(i) = tempTol;
  1535. atolR(i) = radTol ;
  1536. atolP(i) = presTol ;
  1537. atolMdot(i) = mdotTol ;
  1538. for(size_t k =1; k<= data->nsp; k++){
  1539. if(k!=data->k_bath){
  1540. atolY(i,k) = massFracTol;
  1541. }else{
  1542. atolY(i,k) = bathGasTol;
  1543. }
  1544. }
  1545. }
  1546. }
  1547. }