//Evaluate any routines prior to solving the system int SCOPSOWL_preprocesses(SCOPSOWL_DATA *owl_dat) { int success = 0; //Establish boundary conditions before simulation starts owl_dat->magpie_dat.sys_dat.T = owl_dat->gas_temperature; owl_dat->magpie_dat.sys_dat.PT = owl_dat->total_pressure; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { if (owl_dat->SurfDiff == true && owl_dat->Heterogeneous == true) { for (int l=0; l<owl_dat->finch_dat[i].LN; l++) { double p_out = owl_dat->y[i]*owl_dat->total_pressure; if (p_out >= owl_dat->param_dat[i].ref_pressure) owl_dat->param_dat[i].ref_pressure = p_out; owl_dat->skua_dat[l].param_dat[i].ref_diffusion = D_inf(owl_dat->param_dat[i].ref_diffusion, owl_dat->param_dat[i].ref_temperature, owl_dat->param_dat[i].affinity, owl_dat->param_dat[i].ref_pressure, owl_dat->gas_temperature); owl_dat->skua_dat[l].param_dat[i].activation_energy = owl_dat->param_dat[i].activation_energy; owl_dat->skua_dat[l].param_dat[i].ref_temperature = 0.0; owl_dat->skua_dat[l].param_dat[i].affinity = 0.0; } } owl_dat->finch_dat[i].uo = Cstd(owl_dat->magpie_dat.sys_dat.PT*owl_dat->y[i], owl_dat->magpie_dat.sys_dat.T); owl_dat->finch_dat[i].Ro = (*owl_dat->eval_retard) (i,-1,owl_dat); if (owl_dat->finch_dat[i].Ro < 0.0) { mError(simulation_fail); return -1; } owl_dat->finch_dat[i].Do = (*owl_dat->eval_diff) (i,-1,owl_dat); owl_dat->finch_dat[i].kfnp1 = (*owl_dat->eval_kf) (i,owl_dat); } return success; }
Real MAGPIE_Perturbation::computeValue() { MAGPIE_DATA magpie_copy; magpie_copy = _magpie_dat[_qp]; //Check for adsorption if (_magpie_dat[_qp].gsta_dat[_index].qmax > 0.0) { //perturn the copy's _index y double pi = _magpie_dat[_qp].gpast_dat[_index].y * _magpie_dat[_qp].sys_dat.PT; double ci = Cstd(pi,_magpie_dat[_qp].sys_dat.T) + sqrt(DBL_EPSILON); double yi = Pstd(ci,_magpie_dat[_qp].sys_dat.T) / _magpie_dat[_qp].sys_dat.PT; magpie_copy.gpast_dat[_index].y = yi; int success = 0; success = MAGPIE( (void *)&magpie_copy ); if (success < 0 || success > 3) {mError(simulation_fail);} else success = 0; return magpie_copy.gpast_dat[_index].q; //This override was used to demonstrate that we can do perturbation with kinetics //double k = magpie_copy.gpast_dat[_index].q * 0.008; //double qe = magpie_copy.gpast_dat[_index].q; //return (_u_old[_qp] + (_dt*k*qe))/(1.0+(_dt*k)); } else { return 0.0; } }
//Set up the ICs for the problem int set_SCOPSOWL_ICs(SCOPSOWL_DATA *owl_dat) { int success = 0; //Print file header if (owl_dat->Print2File == true) print2file_SCOPSOWL_header(owl_dat); owl_dat->magpie_dat.sys_dat.PT = owl_dat->total_pressure; owl_dat->magpie_dat.sys_dat.T = owl_dat->gas_temperature; if (owl_dat->SurfDiff == true && owl_dat->Heterogeneous == true) { //Call SKUA ICs to establish SCOPSOWL ICs for (int l=0; l<owl_dat->finch_dat[0].LN; l++) { owl_dat->skua_dat[l].total_steps = 0; owl_dat->skua_dat[l].magpie_dat.sys_dat.T = owl_dat->gas_temperature; owl_dat->skua_dat[l].magpie_dat.sys_dat.PT = owl_dat->total_pressure; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { owl_dat->skua_dat[l].param_dat[i].ref_diffusion = D_inf(owl_dat->param_dat[i].ref_diffusion, owl_dat->param_dat[i].ref_temperature, owl_dat->param_dat[i].affinity, owl_dat->y[i]*owl_dat->total_pressure, owl_dat->gas_temperature); owl_dat->skua_dat[l].param_dat[i].activation_energy = owl_dat->param_dat[i].activation_energy; owl_dat->skua_dat[l].param_dat[i].ref_temperature = 0.0; owl_dat->skua_dat[l].param_dat[i].affinity = 0.0; owl_dat->skua_dat[l].param_dat[i].xIC = owl_dat->param_dat[i].xIC; } success = set_SKUA_ICs(&owl_dat->skua_dat[l]); if (success != 0) {mError(simulation_fail); return -1;} owl_dat->total_steps = owl_dat->total_steps + owl_dat->skua_dat[l].total_steps; //Loop for species for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { owl_dat->param_dat[i].qAvg.edit(l, 0, owl_dat->skua_dat[l].finch_dat[i].uAvg); owl_dat->param_dat[i].Qst.edit(l, 0, owl_dat->skua_dat[l].param_dat[i].Qstn); owl_dat->param_dat[i].qAvg_old.edit(l, 0, owl_dat->param_dat[i].qAvg(l,0)); owl_dat->param_dat[i].Qst_old.edit(l, 0, owl_dat->param_dat[i].Qst(l,0)); owl_dat->magpie_dat.gpast_dat[i].y = owl_dat->skua_dat[l].magpie_dat.gpast_dat[i].y; } } //Outer species loop double yad_sum = 0.0; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { //Now form averages and totals owl_dat->param_dat[i].Qsto = owl_dat->param_dat[i].Qst(0,0); owl_dat->param_dat[i].qo = owl_dat->param_dat[i].qAvg(owl_dat->finch_dat[i].LN-1,0); owl_dat->param_dat[i].qIntegralAvg = owl_dat->param_dat[i].qAvg.sphericalAvg(owl_dat->finch_dat[i].L,owl_dat->finch_dat[i].dz,owl_dat->param_dat[i].qo,owl_dat->DirichletBC); owl_dat->param_dat[i].QstAvg = owl_dat->param_dat[i].Qst.sphericalAvg(owl_dat->finch_dat[i].L, owl_dat->finch_dat[i].dz,owl_dat->param_dat[i].Qsto,owl_dat->DirichletBC); owl_dat->param_dat[i].QstAvg_old = owl_dat->param_dat[i].QstAvg; owl_dat->param_dat[i].qIntegralAvg_old = owl_dat->param_dat[i].qIntegralAvg; //SCOPSOWL ICs owl_dat->finch_dat[i].Sn.ConstantICFill(0.0); owl_dat->finch_dat[i].Snp1.ConstantICFill(0.0); owl_dat->finch_dat[i].vn.ConstantICFill(0.0); owl_dat->finch_dat[i].vnp1.ConstantICFill(0.0); owl_dat->finch_dat[i].kn.ConstantICFill(0.0); owl_dat->finch_dat[i].knp1.ConstantICFill(0.0); owl_dat->finch_dat[i].ko = 0.0; owl_dat->finch_dat[i].vo = 0.0; owl_dat->finch_dat[i].kfn = (*owl_dat->eval_kf) (i,owl_dat); owl_dat->finch_dat[i].kfnp1 = owl_dat->finch_dat[i].kfn; if (owl_dat->finch_dat[i].kfn < 0.0) { mError(simulation_fail); return -1; } if (owl_dat->param_dat[i].Adsorbable == true) { owl_dat->finch_dat[i].un.ConstantICFill(Cstd(owl_dat->magpie_dat.sys_dat.PT*owl_dat->magpie_dat.gpast_dat[i].y,owl_dat->magpie_dat.sys_dat.T)); } if (owl_dat->param_dat[i].Adsorbable == true) yad_sum = yad_sum + owl_dat->magpie_dat.gpast_dat[i].y; } //Need to re-adjust the initial conditions for non-adsorbing species double rat_frac = 0.0; int first = 0; bool changed = false; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { if (owl_dat->param_dat[i].Adsorbable == false) { if (changed == false) { first = i; changed = true; rat_frac = rat_frac + (owl_dat->y[i] / owl_dat->y[first]); } else { rat_frac = rat_frac + (owl_dat->y[i] / owl_dat->y[first]); } } } double yFirst = (1.0 - yad_sum) / rat_frac; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { double yi = 0.0; if (owl_dat->param_dat[i].Adsorbable == false) { yi = yFirst * (owl_dat->y[i] / owl_dat->y[first]); owl_dat->finch_dat[i].un.ConstantICFill(Cstd(owl_dat->magpie_dat.sys_dat.PT*yi,owl_dat->magpie_dat.sys_dat.T)); } owl_dat->finch_dat[i].uo = owl_dat->finch_dat[i].un(0,0); owl_dat->finch_dat[i].unp1 = owl_dat->finch_dat[i].un; owl_dat->finch_dat[i].unm1 = owl_dat->finch_dat[i].un; //Form Totals success = uTotal(&owl_dat->finch_dat[i]); if (success != 0) {mError(simulation_fail); return -1;} //Form Averages success = uAverage(&owl_dat->finch_dat[i]); if (success != 0) {mError(simulation_fail); return -1;} } //Print out ICs if (owl_dat->Print2File == true) print2file_SCOPSOWL_result_old(owl_dat); //Call parameter functions for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { for (int l=0; l<owl_dat->finch_dat[i].LN; l++) { double p_out = owl_dat->y[i]*owl_dat->total_pressure; double p_in = Pstd(owl_dat->finch_dat[i].un(l,0), owl_dat->gas_temperature); if (p_out >= p_in) owl_dat->param_dat[i].ref_pressure = p_out; else owl_dat->param_dat[i].ref_pressure = p_in; owl_dat->skua_dat[l].param_dat[i].ref_diffusion = D_inf(owl_dat->param_dat[i].ref_diffusion, owl_dat->param_dat[i].ref_temperature, owl_dat->param_dat[i].affinity, owl_dat->param_dat[i].ref_pressure, owl_dat->gas_temperature); owl_dat->skua_dat[l].param_dat[i].activation_energy = owl_dat->param_dat[i].activation_energy; owl_dat->skua_dat[l].param_dat[i].ref_temperature = 0.0; owl_dat->skua_dat[l].param_dat[i].affinity = 0.0; //Now Recall skua parameter functions to apply corrections owl_dat->skua_dat[l].finch_dat[i].Do = (*owl_dat->skua_dat[l].eval_diff) (i, -1, (void *)&owl_dat->skua_dat[l]); owl_dat->skua_dat[l].finch_dat[i].Dn.ConstantICFill(owl_dat->skua_dat[l].finch_dat[i].Do); owl_dat->skua_dat[l].finch_dat[i].Dnp1.ConstantICFill(owl_dat->skua_dat[l].finch_dat[i].Do); owl_dat->finch_dat[i].Rn.edit(l, 0, (*owl_dat->eval_retard) (i,l,owl_dat)); owl_dat->finch_dat[i].Dn.edit(l, 0, (*owl_dat->eval_diff) (i,l,owl_dat)); } owl_dat->finch_dat[i].Ro = (*owl_dat->eval_retard) (i,-1,owl_dat); owl_dat->finch_dat[i].Do = (*owl_dat->eval_diff) (i,-1,owl_dat); owl_dat->finch_dat[i].Rnp1 = owl_dat->finch_dat[i].Rn; owl_dat->finch_dat[i].Dnp1 = owl_dat->finch_dat[i].Dn; //Update averages and totals owl_dat->finch_dat[i].uT_old = owl_dat->finch_dat[i].uT; owl_dat->finch_dat[i].uAvg_old = owl_dat->finch_dat[i].uAvg; } } else { //Call MAGPIE to establish SCOPSOWL ICs owl_dat->magpie_dat.sys_dat.Recover = true; owl_dat->magpie_dat.sys_dat.Carrier = false; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { if (owl_dat->param_dat[i].Adsorbable == false) { owl_dat->magpie_dat.sys_dat.Carrier = true; break; } } for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) owl_dat->magpie_dat.gpast_dat[i].x = owl_dat->param_dat[i].xIC; //Temperature, pressure, total adsorption, and x's are set: Call MAGPIE success = MAGPIE((void *)&owl_dat->magpie_dat); if (success < 0 || success > 3) {mError(simulation_fail); return -1;} else success = 0; owl_dat->total_steps = owl_dat->total_steps + owl_dat->magpie_dat.sys_dat.total_eval; //Reset the MAGPIE parameters before continuing owl_dat->magpie_dat.sys_dat.Recover = false; owl_dat->magpie_dat.sys_dat.Carrier = false; //The GPAST structure of MAGPIE now holds the y's which establish the SCOPSOWL ICs double yad_sum = 0.0; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { owl_dat->param_dat[i].qAvg.ConstantICFill(owl_dat->magpie_dat.sys_dat.qT * owl_dat->magpie_dat.gpast_dat[i].x); owl_dat->param_dat[i].qAvg_old = owl_dat->param_dat[i].qAvg; owl_dat->param_dat[i].qo = owl_dat->magpie_dat.sys_dat.qT * owl_dat->magpie_dat.gpast_dat[i].x; owl_dat->finch_dat[i].Sn.ConstantICFill(0.0); owl_dat->finch_dat[i].Snp1.ConstantICFill(0.0); owl_dat->finch_dat[i].vn.ConstantICFill(0.0); owl_dat->finch_dat[i].vnp1.ConstantICFill(0.0); owl_dat->finch_dat[i].kn.ConstantICFill(0.0); owl_dat->finch_dat[i].knp1.ConstantICFill(0.0); owl_dat->finch_dat[i].ko = 0.0; owl_dat->finch_dat[i].vo = 0.0; owl_dat->finch_dat[i].kfn = (*owl_dat->eval_kf) (i,owl_dat); owl_dat->finch_dat[i].kfnp1 = owl_dat->finch_dat[i].kfn; if (owl_dat->finch_dat[i].kfn < 0.0) { mError(simulation_fail); return -1; } if (owl_dat->param_dat[i].Adsorbable == true) { owl_dat->finch_dat[i].un.ConstantICFill(Cstd(owl_dat->magpie_dat.sys_dat.PT*owl_dat->magpie_dat.gpast_dat[i].y,owl_dat->magpie_dat.sys_dat.T)); } if (owl_dat->param_dat[i].Adsorbable == true) yad_sum = yad_sum + owl_dat->magpie_dat.gpast_dat[i].y; } //Need to re-adjust the initial conditions for non-adsorbing species double rat_frac = 0.0; int first = 0; bool changed = false; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { if (owl_dat->param_dat[i].Adsorbable == false) { if (changed == false) { first = i; changed = true; rat_frac = rat_frac + (owl_dat->y[i] / owl_dat->y[first]); } else { rat_frac = rat_frac + (owl_dat->y[i] / owl_dat->y[first]); } } } double yFirst = (1.0 - yad_sum) / rat_frac; for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { double yi = 0.0; if (owl_dat->param_dat[i].Adsorbable == false) { yi = yFirst * (owl_dat->y[i] / owl_dat->y[first]); owl_dat->finch_dat[i].un.ConstantICFill(Cstd(owl_dat->magpie_dat.sys_dat.PT*yi,owl_dat->magpie_dat.sys_dat.T)); } owl_dat->finch_dat[i].uo = owl_dat->finch_dat[i].un(0,0); owl_dat->finch_dat[i].unp1 = owl_dat->finch_dat[i].un; owl_dat->finch_dat[i].unm1 = owl_dat->finch_dat[i].un; //Form Totals success = uTotal(&owl_dat->finch_dat[i]); if (success != 0) {mError(simulation_fail); return -1;} //Form Averages success = uAverage(&owl_dat->finch_dat[i]); if (success != 0) {mError(simulation_fail); return -1;} } //Use established info to call the retardation and diffusion functions as well as heats of adsorption for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { if (owl_dat->param_dat[i].Adsorbable == true) { owl_dat->param_dat[i].Qst.ConstantICFill(Qst(Pstd(owl_dat->finch_dat[i].un(0,0),owl_dat->magpie_dat.sys_dat.T), (void *)&owl_dat->magpie_dat, i)); } else { owl_dat->param_dat[i].Qst.ConstantICFill(0.0); } owl_dat->param_dat[i].Qst_old = owl_dat->param_dat[i].Qst; owl_dat->param_dat[i].Qsto = owl_dat->param_dat[i].Qst(0,0); //Now form averages and totals owl_dat->param_dat[i].qIntegralAvg = owl_dat->param_dat[i].qAvg.sphericalAvg(owl_dat->finch_dat[i].L,owl_dat->finch_dat[i].dz,owl_dat->param_dat[i].qo,owl_dat->DirichletBC); owl_dat->param_dat[i].QstAvg = owl_dat->param_dat[i].Qst.sphericalAvg(owl_dat->finch_dat[i].L, owl_dat->finch_dat[i].dz,owl_dat->param_dat[i].Qsto,owl_dat->DirichletBC); //Update adsorption info owl_dat->param_dat[i].QstAvg_old = owl_dat->param_dat[i].QstAvg; owl_dat->param_dat[i].qIntegralAvg_old = owl_dat->param_dat[i].qIntegralAvg; } //Print out ICs if (owl_dat->Print2File == true) print2file_SCOPSOWL_result_old(owl_dat); //Call the parameter functions for (int i=0; i<owl_dat->magpie_dat.sys_dat.N; i++) { //Set the reference pressure for (int l=0; l<owl_dat->finch_dat[i].LN; l++) { double p_out = owl_dat->y[i]*owl_dat->total_pressure; double p_in = Pstd(owl_dat->finch_dat[i].un(l,0), owl_dat->gas_temperature); if (p_out >= p_in) owl_dat->param_dat[i].ref_pressure = p_out; else owl_dat->param_dat[i].ref_pressure = p_in; } for (int l=0; l<owl_dat->finch_dat[i].LN; l++) { owl_dat->finch_dat[i].Rn.edit(l, 0, (*owl_dat->eval_retard) (i,l,owl_dat)); owl_dat->finch_dat[i].Dn.edit(l, 0, (*owl_dat->eval_diff) (i,l,owl_dat)); } owl_dat->finch_dat[i].Ro = (*owl_dat->eval_retard) (i,-1,owl_dat); owl_dat->finch_dat[i].Do = (*owl_dat->eval_diff) (i,-1,owl_dat); owl_dat->finch_dat[i].Rnp1 = owl_dat->finch_dat[i].Rn; owl_dat->finch_dat[i].Dnp1 = owl_dat->finch_dat[i].Dn; //Update averages and totals owl_dat->finch_dat[i].uT_old = owl_dat->finch_dat[i].uT; owl_dat->finch_dat[i].uAvg_old = owl_dat->finch_dat[i].uAvg; } } return success; }
//Default Adsorption Strength function is based on input args double default_adsorption(int i, int l, const void *user_data) { SCOPSOWL_DATA *dat = (SCOPSOWL_DATA *) user_data; double dq_dc = 0.0; double eps = sqrt(DBL_EPSILON); double qEPS = 0.0; double uo = 0.0; int success = 0; //Check if any work needs to be done if (dat->param_dat[i].Adsorbable == false) { if (l < 0) dat->param_dat[i].dq_dco = 0.0; else dat->param_dat[i].dq_dc.edit(l, 0, 0.0); return 0.0; } //Boundary value of dq/dc if (l < 0) { //Based on MAGPIE simulations ONLY! uo = Cstd(dat->magpie_dat.sys_dat.PT*dat->y[i], dat->magpie_dat.sys_dat.T); //Perturb the ith concentration for (int j=0; j<dat->magpie_dat.sys_dat.N; j++) { if (j == i) dat->magpie_dat.gpast_dat[j].y = Pstd(uo+eps,dat->magpie_dat.sys_dat.T)/dat->magpie_dat.sys_dat.PT; else if (dat->param_dat[j].Adsorbable == true) dat->magpie_dat.gpast_dat[j].y = Pstd(uo,dat->magpie_dat.sys_dat.T)/dat->magpie_dat.sys_dat.PT; else dat->magpie_dat.gpast_dat[j].y = 0.0; } //Call MAGPIE to evaluate perturbed adsorption success = MAGPIE((void *)&dat->magpie_dat); if (success < 0 || success > 3) {mError(simulation_fail); return -1;} else success = 0; dat->total_steps = dat->total_steps + dat->magpie_dat.sys_dat.total_eval; //Store perturbed result in temp location qEPS = dat->magpie_dat.sys_dat.qT * dat->magpie_dat.gpast_dat[i].x; //Restore original info for (int j=0; j<dat->magpie_dat.sys_dat.N; j++) { if (dat->param_dat[j].Adsorbable == true) dat->magpie_dat.gpast_dat[j].y = dat->y[j]; else dat->magpie_dat.gpast_dat[j].y = 0.0; } //Call MAGPIE to evaluate adsorption success = MAGPIE((void *)&dat->magpie_dat); if (success < 0 || success > 3) {mError(simulation_fail); return -1;} else success = 0; dat->total_steps = dat->total_steps + dat->magpie_dat.sys_dat.total_eval; //Store the solution if (dat->param_dat[i].Adsorbable == true) { dat->param_dat[i].qo = dat->magpie_dat.sys_dat.qT * dat->magpie_dat.gpast_dat[i].x; dat->param_dat[i].Qsto = Qst(Pstd(uo,dat->magpie_dat.sys_dat.T), (void *)&dat->magpie_dat, i); } else { dat->param_dat[i].qo = 0.0; dat->param_dat[i].Qsto = 0.0; } dq_dc = ( qEPS - dat->param_dat[i].qo ) / eps; dat->param_dat[i].dq_dco = dq_dc; } //Nodal values of dq/dc else { if (dat->SurfDiff == true && dat->Heterogeneous == true) { //Adjust interior pressure with perturbation double tempPT = 0.0; for (int j=0; j<dat->skua_dat[l].magpie_dat.sys_dat.N; j++) { if (i == j) tempPT = tempPT + Pstd(dat->finch_dat[j].unp1(l,0)+eps, dat->skua_dat[l].magpie_dat.sys_dat.T); else tempPT = tempPT + Pstd(dat->finch_dat[j].unp1(l,0), dat->skua_dat[l].magpie_dat.sys_dat.T); } dat->skua_dat[l].magpie_dat.sys_dat.PT = tempPT; //Perform SKUA simulation dat->skua_dat[l].finch_dat[i].dt = dat->finch_dat[i].dt; dat->skua_dat[l].finch_dat[i].dt_old = dat->finch_dat[i].dt_old; dat->skua_dat[l].finch_dat[i].t = dat->finch_dat[i].t; dat->skua_dat[l].finch_dat[i].t_old = dat->finch_dat[i].t_old; dat->skua_dat[l].t = dat->skua_dat[l].finch_dat[i].t; dat->skua_dat[l].t_old = dat->skua_dat[l].finch_dat[i].t_old; //Set up SKUA data dat->skua_dat[l].magpie_dat.sys_dat.T = dat->magpie_dat.sys_dat.T; for (int j=0; j<dat->skua_dat[l].magpie_dat.sys_dat.N; j++) { if (i == j) dat->skua_dat[l].y[j] = Pstd(dat->finch_dat[j].unp1(l,0)+eps,dat->skua_dat[l].magpie_dat.sys_dat.T)/dat->skua_dat[l].magpie_dat.sys_dat.PT; else dat->skua_dat[l].y[j] = Pstd(dat->finch_dat[j].unp1(l,0),dat->skua_dat[l].magpie_dat.sys_dat.T)/dat->skua_dat[l].magpie_dat.sys_dat.PT; } //Call SKUA executioner to evaluate adsorption dat->skua_dat[l].total_steps = 0; success = SKUA_Executioner(&dat->skua_dat[l]); if (success != 0) {mError(simulation_fail); return -1;} dat->total_steps = dat->total_steps + dat->skua_dat[l].total_steps; //Store the results temporarily qEPS = dat->skua_dat[l].finch_dat[i].uAvg; //Adjust again without perturbation tempPT = 0.0; for (int j=0; j<dat->skua_dat[l].magpie_dat.sys_dat.N; j++) tempPT = tempPT + Pstd(dat->finch_dat[j].unp1(l,0), dat->skua_dat[l].magpie_dat.sys_dat.T); dat->skua_dat[l].magpie_dat.sys_dat.PT = tempPT; //Undo perturbation for (int j=0; j<dat->magpie_dat.sys_dat.N; j++) { dat->skua_dat[l].y[j] = Pstd(dat->finch_dat[j].unp1(l,0),dat->magpie_dat.sys_dat.T)/dat->skua_dat[l].magpie_dat.sys_dat.PT; } //Call SKUA again to evaluate perturbation dat->skua_dat[l].total_steps = 0; success = SKUA_Executioner(&dat->skua_dat[l]); if (success != 0) {mError(simulation_fail); return -1;} dat->total_steps = dat->total_steps + dat->skua_dat[l].total_steps; //Store perturbed result in temp location dat->param_dat[i].qAvg.edit(l, 0, dat->skua_dat[l].finch_dat[i].uAvg); dat->param_dat[i].Qst.edit(l, 0, dat->skua_dat[l].param_dat[i].Qstnp1); dq_dc = ( qEPS - dat->param_dat[i].qAvg(l,0) ) / eps; dat->param_dat[i].dq_dc.edit(l, 0, dq_dc); } else { //Perturb the ith value and form the total pressure double tempPT = 0.0; for (int j=0; j<dat->magpie_dat.sys_dat.N; j++) { if (i == j) tempPT = tempPT + Pstd(dat->finch_dat[j].unp1(l,0)+eps, dat->magpie_dat.sys_dat.T); else tempPT = tempPT + Pstd(dat->finch_dat[j].unp1(l,0), dat->magpie_dat.sys_dat.T); } dat->magpie_dat.sys_dat.PT = tempPT; //Perturb the ith concentration for (int j=0; j<dat->magpie_dat.sys_dat.N; j++) { if (j == i) dat->magpie_dat.gpast_dat[j].y = Pstd(dat->finch_dat[j].unp1(l,0)+eps,dat->magpie_dat.sys_dat.T)/dat->magpie_dat.sys_dat.PT; else if (dat->param_dat[j].Adsorbable == true) dat->magpie_dat.gpast_dat[j].y = Pstd(dat->finch_dat[j].unp1(l,0),dat->magpie_dat.sys_dat.T)/dat->magpie_dat.sys_dat.PT; else dat->magpie_dat.gpast_dat[j].y = 0.0; } //Call MAGPIE to evaluate perturbed adsorption success = MAGPIE((void *)&dat->magpie_dat); if (success < 0 || success > 3) {mError(simulation_fail); return -1;} else success = 0; dat->total_steps = dat->total_steps + dat->magpie_dat.sys_dat.total_eval; //Store perturbed result in temp location qEPS = dat->magpie_dat.sys_dat.qT * dat->magpie_dat.gpast_dat[i].x; //Adjust interior pressure back to true values tempPT = 0.0; for (int j=0; j<dat->magpie_dat.sys_dat.N; j++) tempPT = tempPT + Pstd(dat->finch_dat[j].unp1(l,0), dat->magpie_dat.sys_dat.T); dat->magpie_dat.sys_dat.PT = tempPT; //Perform MAGPIE simulation for (int j=0; j<dat->magpie_dat.sys_dat.N; j++) { if (dat->param_dat[j].Adsorbable == true) dat->magpie_dat.gpast_dat[j].y = Pstd(dat->finch_dat[j].unp1(l,0),dat->magpie_dat.sys_dat.T)/dat->magpie_dat.sys_dat.PT; else dat->magpie_dat.gpast_dat[j].y = 0.0; } //Call MAGPIE to evaluate adsorption success = MAGPIE((void *)&dat->magpie_dat); if (success < 0 || success > 3) {mError(simulation_fail); return -1;} else success = 0; dat->total_steps = dat->total_steps + dat->magpie_dat.sys_dat.total_eval; //Store the solutions if (dat->param_dat[i].Adsorbable == true) { dat->param_dat[i].qAvg.edit(l, 0, dat->magpie_dat.sys_dat.qT * dat->magpie_dat.gpast_dat[i].x); dat->param_dat[i].Qst.edit(l,0,Qst(Pstd(dat->finch_dat[i].unp1(l,0),dat->magpie_dat.sys_dat.T), (void *)&dat->magpie_dat, i)); } else { dat->param_dat[i].qAvg.edit(l, 0, 0.0); dat->param_dat[i].Qst.edit(l,0,0.0); } dq_dc = ( qEPS - dat->param_dat[i].qAvg(l,0) ) / eps; dat->param_dat[i].dq_dc.edit(l, 0, dq_dc); } } return dq_dc; }