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.

2076 lines
63KB

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