static void FreePreconData(PreconData pdata) { int lx, ly; for (lx = 0; lx < MXSUB; lx++) { for (ly = 0; ly < MYSUB; ly++) { denfree((pdata->P)[lx][ly]); denfree((pdata->Jbd)[lx][ly]); denfreepiv((pdata->pivot)[lx][ly]); } } free(pdata); }
static void FreeUserData(UserData data) { int jx, jy; for (jx=0; jx < MX; jx++) { for (jy=0; jy < MY; jy++) { denfree((data->P)[jx][jy]); denfree((data->Jbd)[jx][jy]); denfreepiv((data->pivot)[jx][jy]); } } free(data); }
static void FreeUserData(UserData data) { int jx, jz; for (jx=0; jx < MX; jx++) { for (jz=0; jz < MZ; jz++) { denfree((data->P)[jx][jz]); denfree((data->Jbd)[jx][jz]); denfreepiv((data->pivot)[jx][jz]); } } free(data->p); free(data); }
static void FreeUserData(UserData webdata) { long int ix, jy; for (ix = 0; ix < MXSUB; ix++) { for (jy = 0; jy < MYSUB; jy++) { denfree((webdata->PP)[ix][jy]); denfreepiv((webdata->pivot)[ix][jy]); } } denfree(webdata->acoef); N_VDestroy_Parallel(webdata->rates); N_VDestroy_Parallel(webdata->ewt); free(webdata); }
static void FreeUserData(UserData data) { int jx, jy; for (jx = 0; jx < MXSUB; jx++) { for (jy = 0; jy < MYSUB; jy++) { denfree((data->P)[jx][jy]); denfreepiv((data->pivot)[jx][jy]); } } denfree(acoef); free(bcoef); free(cox); free(coy); N_VDestroy_Parallel(data->rates); free(data); }
static void FreeUserData(WebData wdata) { int i, ngrp; ngrp = wdata->ngrp; for(i=0; i < ngrp; i++) { denfree((wdata->P)[i]); denfreepiv((wdata->pivot)[i]); } N_VDestroy_Serial(wdata->rewt); free(wdata); }
void DenseFreeMat(DenseMat A) { denfree(A->data); free(A); }
int React (realtype t, realtype stepsize, Chem_Data CD, int cell, int * NR_times){ if (CD->Vcele[cell].sat < 1.0E-2) return(0); // very dry, no reaction can take place. int i, j ,k, control, speciation_flg = CD->SPCFlg, num_spe = CD->NumStc + CD->NumSsc, min_pos , pivot_flg; int stc = CD->NumStc, ssc = CD->NumSsc, spc = CD->NumSpc, sdc = CD->NumSdc, nkr = CD->NumMkr + CD->NumAkr, smc = CD->NumMin; double * residue, * residue_t, * tmpconc, * totconc, * area, * error, * gamma, * Keq, * Rate_pre, * IAP, * dependency, * Rate_spe, * Rate_spe_t, * Rate_spet; residue = (double*) malloc ( stc * sizeof(double)); residue_t = (double*) malloc ( stc * sizeof(double)); tmpconc = (double*) malloc ( num_spe * sizeof(double)); totconc = (double*) malloc ( stc * sizeof(double)); area = (double*) malloc ( smc * sizeof(double)); error = (double*) malloc ( stc * sizeof(double)); gamma = (double*) malloc ( num_spe * sizeof(double)); Keq = (double*) malloc ( ssc * sizeof(double)); Rate_pre = (double*) malloc ( nkr * sizeof(double)); IAP = (double*) malloc ( nkr * sizeof(double)); dependency = (double*) malloc ( nkr * sizeof(double)); Rate_spe = (double*) malloc ( stc * sizeof(double)); Rate_spe_t = (double*) malloc ( stc * sizeof(double)); Rate_spet = (double*) malloc ( stc * sizeof(double)); long int * p = (long int*)malloc ( (CD->NumStc - CD->NumMin) * sizeof(long int)); realtype * x_= (realtype*)malloc ( (CD->NumStc - CD->NumMin) * sizeof(realtype)); double tmpval, tmpprb, inv_sat, I, Iroot, tmpKeq, ISupdateflg, adh, bdh, bdt, maxerror = 1, surf_ratio, tot_cec, tmpprb_inv; realtype ** jcb; control = 0; tmpprb = 1.0E-2; tmpprb_inv = 1.0 /tmpprb ; inv_sat = 1.0 / CD->Vcele[cell].sat; for (i = 0 ; i < CD->NumMin; i++){ area[i] = CD->Vcele[cell].p_para[i+CD->NumStc - CD->NumMin] * CD->Vcele[cell].p_conc[i+ CD->NumStc - CD->NumMin] * CD->chemtype[i + CD->NumStc - CD->NumMin].MolarMass; } if ( CD->SUFEFF){ if ( CD->Vcele[cell].sat < 1.0){ surf_ratio = pow(CD->Vcele[cell].sat, 0.6667); for ( i = 0 ; i < CD->NumMin; i ++){ area[i] *= surf_ratio; } } }// Lichtner's 2 third law if SUF_EFF is turned on. for ( j = 0 ; j < CD->NumStc; j ++){ Rate_spe[j] = 0.0; } for (i = 0 ; i < CD->NumMkr + CD->NumAkr; i ++){ min_pos = CD->kinetics[i].position - CD->NumStc + CD->NumMin; IAP[i] = 0.0; for ( j = 0; j < CD->NumStc; j ++){ IAP[i] += log10(CD->Vcele[cell].p_actv[j])* CD->Dep_kinetic[min_pos][j]; } IAP[i] = pow(10, IAP[i]); tmpKeq = pow(10, CD->KeqKinect[min_pos]); dependency[i] = 1.0; for ( k = 0 ; k < CD->kinetics[i].num_dep; k ++) dependency[i] *= pow(CD->Vcele[cell].p_actv[CD->kinetics[i].dep_position[k]], CD->kinetics[i].dep_power[k]); /* Calculate the predicted rate depending on the type of rate law! */ Rate_pre[i] = area[min_pos]*(pow(10,CD->kinetics[i].rate))* dependency[i] *(1 - (IAP[i] / tmpKeq)) * 60; /* Rate_pre: in mol/L water / min rate per reaction area: m2/L water rate: mol/m2/s dependency: dimensionless; */ for ( j = 0 ; j < CD->NumStc; j ++){ Rate_spe[j] += Rate_pre[i]*CD->Dep_kinetic[min_pos][j]; } } for (i = 0 ; i < CD->NumMkr + CD->NumAkr; i++){ min_pos = CD->kinetics[i].position - CD->NumStc + CD->NumMin; if ( Rate_pre[i] < 0.0){ if ( CD->Vcele[cell].p_conc[min_pos + CD->NumStc - CD->NumMin] < 1.0E-8) // mineral cutoff when mineral is disappearing. area[min_pos] = 0.0; } } for ( i = 0 ; i < CD->NumSpc; i ++) if ( CD->chemtype[i].itype == 1) Rate_spe[i] = Rate_spe[i]*inv_sat; jcb = denalloc(CD->NumStc - CD->NumMin); /* long int p[CD->NumStc]; realtype x_[CD->NumStc]; control =0; double maxerror= 1; */ if ( CD->TEMcpl == 0 ){ for ( i = 0 ; i < CD->NumSsc; i ++) Keq[i] = CD->Keq[i]; adh = CD->DH.adh; bdh = CD->DH.bdh; bdt = CD->DH.bdt; } for ( i = 0; i < CD->NumStc; i ++){ tmpconc[i] = log10(CD->Vcele[cell].p_conc[i]); } for ( i = 0; i < CD->NumSsc; i ++){ tmpconc[i + CD->NumStc] = log10(CD->Vcele[cell].s_conc[i]); } tot_cec = 0.0; for ( i = 0; i < num_spe; i ++){ if ( CD->chemtype[i].itype == 3){ tot_cec += pow (10, tmpconc[i]); } } // if ( cell == 1) fprintf(stderr, " Tot_site is %f, while the tot_conc for site %s is %f, p_conc is %f\n", tot_cec, CD->chemtype[7].ChemName, CD->Vcele[cell].t_conc[7], CD->Vcele[cell].p_conc[7]); I = 0; for ( i = 0 ; i < num_spe; i ++){ I += 0.5 * pow( 10, tmpconc[i]) * sqr(CD->chemtype[i].Charge); } Iroot = sqrt(I); for ( i = 0 ; i < num_spe; i ++){ switch ( CD->chemtype[i].itype){ case 1: gamma[i] = ( - adh * sqr(CD->chemtype[i].Charge) * Iroot)/(1 + bdh * CD->chemtype[i].SizeF * Iroot) + bdt * I; break; case 2: gamma[i] = log10(CD->Vcele[cell].sat); break; case 3: gamma[i] = - log10(tot_cec); break; case 4: gamma[i] = - tmpconc[i]; break; } } /* for ( i = 0 ; i < num_spe; i ++){ if ( CD->chemtype[i].itype == 2) { if ( cell == 700) fprintf(stderr, "%s with %f\n", CD->chemtype[i].ChemName, gamma[i]); } } */ while (maxerror > TOL){ for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++){ tmpval += (tmpconc[j] + gamma[j])* CD->Dependency[i][j]; } tmpval -= Keq[i] + gamma[i + CD->NumStc]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " UPDATE %s %6.4f\n", CD->chemtype[i+CD->NumStc].ChemName, tmpconc[i+CD->NumStc]); } for ( j = 0 ; j < CD->NumStc; j ++){ Rate_spet[j] = 0.0; } for (i = 0 ; i < CD->NumMkr + CD->NumAkr; i ++){ min_pos = CD->kinetics[i].position - CD->NumStc + CD->NumMin; // fprintf(stderr, " Min_pos %d\n", min_pos); IAP[i] = 0.0; // fprintf(stderr, " IAP_BC %s %6.4f\n", CD->kinetics[i].Label, IAP[i]); for ( j = 0; j < CD->NumStc; j ++){ if ( CD->chemtype[j].itype !=4){ IAP[i] += (tmpconc[j]+gamma[j]) * CD->Dep_kinetic[min_pos][j]; // fprintf(stderr, " IAP_CALC, %s %6.4f\t %6.4f\n" ,CD->chemtype[j].ChemName, tmpconc[j]+gamma[j], CD->Dep_kinetic[min_pos][j]); } } IAP[i] = pow(10, IAP[i]); tmpKeq = pow(10, CD->KeqKinect[min_pos]); /* if ( IAP[i] < tmpKeq) rct_drct[i] = 1.0; if ( IAP[i] > tmpKeq) rct_drct[i] = -1.0; if ( IAP[i] == tmpKeq) rct_drct[i] = 0.0; */ // fprintf(stderr, " IAP_BC %s %6.4f\n", CD->kinetics[i].Label, IAP[i]); dependency[i] = 0.0; for ( k = 0 ; k < CD->kinetics[i].num_dep; k ++) dependency[i] += (tmpconc[CD->kinetics[i].dep_position[k]] + gamma[CD->kinetics[i].dep_position[k]])* CD->kinetics[i].dep_power[k]; dependency[i] = pow(10, dependency[i]); // fprintf(stderr, " Dep: %6.4f\n", dependency[i]); /* Calculate the predicted rate depending on the type of rate law! */ Rate_pre[i] = area[min_pos]*(pow(10,CD->kinetics[i].rate))* dependency[i] *(1 - (IAP[i] / tmpKeq)) * 60; /* Rate_pre: in mol/L water / min area: m2/L water rate: mol/m2/s dependency: dimensionless; */ // fprintf(stderr, " Reaction %s, Label %s, IAP %6.4f\t, Rate %2.1g\n",CD->kinetics[i].species, CD->kinetics[i].Label, IAP[i], Rate_pre[i]); for ( j = 0 ; j < CD->NumStc; j ++){ Rate_spet[j] += Rate_pre[i]*CD->Dep_kinetic[min_pos][j]; //fprintf(stderr, " Rate for %s: %6.4g\n", CD->chemtype[j].ChemName, Rate_pre[i]*CD->Dep_kinetic[min_pos][j]); } // Adjust the unit of the calcuated rate. Note that for mineral, the unit of rate and the unit of concentration are mol/L porous media // for the aqueous species, the unit of the rate and the unit of the concentration are mol/L pm and mol/L water respectively. } /*for ( i = 0 ; i < CD->NumSpc; i ++){ // fprintf(stderr, " Tot_rate for %s: %6.4g\n", CD->chemtype[i].ChemName, Rate_spet[i]); Rate_spet[i] = Rate_spet[i]/(CD->Vcele[cell].porosity * CD->Vcele[cell].sat); // fprintf(stderr, " Tot_rate for %s: %6.4g\n", CD->chemtype[i].ChemName, Rate_spet[i]); }*/ for ( i = 0 ; i < CD->NumSpc; i ++) if ( CD->chemtype[i].itype == 1) Rate_spet[i] = Rate_spet[i]*inv_sat; for ( i = 0; i < CD->NumStc - CD->NumMin; i ++){ tmpval = 0.0; for ( j = 0; j < CD->NumStc + CD-> NumSsc; j++){ tmpval+= CD->Totalconc[i][j]*pow(10,tmpconc[j]); //fprintf(stderr, " %s %6.4f\t %6.4f\n", CD->chemtype[j].ChemName,CD->Totalconc[i][j], tmpconc[j]); } totconc[i] = tmpval; residue[i] = tmpval -( CD->Vcele[cell].t_conc[i] + (Rate_spe[i]+ Rate_spet[i])*stepsize *0.5); //residue[i] = tmpval -( CD->Vcele[cell].t_conc[i] + (Rate_spet[i])*stepsize); // fprintf(stderr, " %s Residue: %6.4g\t Sum1:%6.4g\tSum2:%6.4g\tRate1%6.4g\tRate2%6.4g\n", CD->chemtype[i].ChemName, residue[i],totconc[i], CD->Vcele[cell].t_conc[i], Rate_spe[i], Rate_spet[i]); } if ( control % SKIP_JACOB == 0) // update jacobian every the other iteration { for ( k = 0; k < CD->NumStc - CD->NumMin; k ++){ tmpconc[k] += tmpprb; for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++) tmpval += (tmpconc[j]+ gamma[j])* CD->Dependency[i][j]; tmpval -= Keq[i] + gamma[i + CD->NumStc]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " CALC_SEC %s %6.4f\t %6.4f\n", CD->chemtype[i+CD->NumSpc].ChemName, tmpval, pow(10,tmpconc[i+CD->NumSpc])); } for ( i = 0; i < CD->NumStc - CD->NumMin; i ++){ tmpval = 0.0; for ( j = 0; j < CD->NumStc + CD-> NumSsc; j++){ tmpval+= CD->Totalconc[i][j]*pow(10,tmpconc[j]); // fprintf(stderr, " CALC_TOT %s %6.4f\t %6.4f\n",CD->chemtype[j].ChemName, CD->Totalconc[i][j], pow(10,tmpconc[j])); } // totconc[i] = tmpval; //fprintf(stderr, " CALC_TOT Sum%s %6.4f\t %12.10f\n", CD->chemtype[i].ChemName, log10(totconc[i]), totconc[i]); residue_t[i] = tmpval - (CD->Vcele[cell].t_conc[i] + (Rate_spe[i] + Rate_spet[i])*stepsize *0.5); jcb[k][i] = (residue_t[i]- residue[i]) * tmpprb_inv; // fprintf(stderr, "%g\n", jcb[k][i]); // fprintf(stderr, " Sum%s %6.4f\t %6.4f\n", CD->chemtype[i].ChemName, tmpval, residue_t[i]); } tmpconc[k] -= tmpprb; } } for ( i = 0 ; i < CD->NumStc - CD->NumMin; i ++) x_[i] = - residue[i]; // fprintf(stderr, " Jacobian Matrix!\n"); // if (control == 1) denprint(jcb, CD->NumStc); // fprintf(stderr, " LU %ld\n",gefa(jcb,CD->NumStc,p)); pivot_flg = gefa(jcb, CD->NumStc - CD->NumMin, p); if (pivot_flg != 0){/* for ( i = 0 ; i < CD->NumStc; i ++) fprintf(stderr, "%d %s Conp: %6.4g\t, sat: %6.4g\t, height: %6.4g\t, tot_conc: %6.4g\n", cell , CD->chemtype[i].ChemName, CD->Vcele[cell].p_conc[i], CD->Vcele[cell].sat, CD->Vcele[cell].height_o, CD->Vcele[cell].t_conc[i]);*/ CD->Vcele[cell].illness ++; // denprint(jcb, CD->NumStc); return(1); } // assert(pivot_flg ==0); gesl(jcb, CD->NumStc - CD->NumMin, p, x_); // gauss(jcb, x_, CD->NumStc); for (i = 0 ; i < CD->NumStc - CD->NumMin; i ++){ if ( fabs(x_[i])< 0.3) tmpconc[i] += x_[i] ; else{ if (x_[i] < 0) tmpconc[i] += -0.3; else tmpconc[i] += 0.3; } // fprintf(stderr, " %s TMPCON %6.4f\t IMPROVE %g\n", CD->chemtype[i].ChemName, tmpconc[i], x_[i]); error[i] = residue[i]/totconc[i] ; // fprintf(stderr, " RESI %6.4g\t TOT_CONC %6.4g\t ERROR %6.4g\n", residue[i], totconc[i], error[i] ); } maxerror = fabs(error[0]); for ( i = 1; i < CD->NumStc- CD->NumMin; i ++) if ( fabs(error[i])>maxerror ) maxerror = fabs(error[i]); control ++; if (control > 10) return(1); } *(NR_times) = control; denfree(jcb); // fprintf(stderr, " Solution Reached After %d Newton Ralphson Iterations!\n", control); for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++){ tmpval += (tmpconc[j] + gamma[j])* CD->Dependency[i][j]; } tmpval -= Keq[i] + gamma[i + CD->NumStc]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " UPDATE %s %6.4f\n", CD->chemtype[i+CD->NumStc].ChemName, (tmpconc[i+CD->NumStc])); } for ( i = 0; i < CD->NumStc - CD->NumMin; i ++){ tmpval = 0.0; for ( j = 0; j < CD->NumStc + CD-> NumSsc; j++){ tmpval+= CD->Totalconc[i][j]*pow(10,tmpconc[j]); } totconc[i] = tmpval; residue[i] = tmpval - CD->Vcele[cell].t_conc[i]; error[i] = residue[i]/totconc[i]; } /* for ( i = 0; i < CD->NumStc; i ++){ // fprintf(stderr, " Sum%s: log10(TOTCONC_NR) %4.3f\t log10(TOTCONC_B) %4.3f\t TOTCONC_NR %4.3g\t RESIDUE %2.1g\t RELATIVE ERROR %2.1g\n", CD->chemtype[i].ChemName,log10(totconc[i]),log10(CD->Vcele[cell].t_conc[i]), totconc[i], fabs(residue[i]), fabs(error[i]*100)); } */ for ( i = 0; i < CD->NumStc + CD->NumSsc; i ++){ /* if ( tmpconc[i]!=tmpconc[i]){ fprintf(stderr, " Nan type error from reaction at cell %d, species %d", cell+1, i+1); ReportError(CD->Vcele[cell], CD); CD->Vcele[cell].illness += 20; }*/ if ( i < CD->NumStc){ if ( CD->chemtype[i].itype == 4){ CD->Vcele[cell].t_conc[i] += (Rate_spe[i] + Rate_spet[i])*stepsize *0.5; CD->Vcele[cell].p_actv[i] = 1.0; CD->Vcele[cell].p_conc[i] = CD->Vcele[cell].t_conc[i]; } else{ CD->Vcele[cell].p_conc[i] = pow(10,tmpconc[i]); CD->Vcele[cell].p_actv[i] = pow(10,(tmpconc[i] + gamma[i])); CD->Vcele[cell].t_conc[i] = totconc[i]; } } else{ CD->Vcele[cell].s_conc[i-CD->NumStc] = pow(10,tmpconc[i]); CD->Vcele[cell].s_actv[i-CD->NumStc] = pow(10,(tmpconc[i] + gamma[i])); } // fprintf(stderr, " %s LogC: %6.4f\t C: %6.4f\t Loga: %6.4f\t a: %6.4f\n", CD->chemtype[i].ChemName, tmpconc[i], pow(10, tmpconc[i]), tmpconc[i]+gamma[i], pow(10,(tmpconc[i]+gamma[i]))); } // if (cell == 700) fprintf(stderr, "Conc. %s %6.4g %6.4g\n",CD->chemtype[19].ChemName, CD->Vcele[cell].s_conc[3], CD->Vcele[cell].s_actv[3]); /* for ( i = 0; i < CD->NumStc; i ++){ fprintf(stderr, " Sum%s: log10(TOTCONC_NR) %4.3f\t log10(TOTCONC_B) %4.3f\t TOTCONC_NR %4.3g\t RESIDUE %2.1g\t RELATIVE ERROR %2.1g%\n", CD->chemtype[i].ChemName,log10(totconc[i]),log10(CD->Vcele[cell].t_conc[i]), totconc[i], fabs(residue[i]), fabs(error[i]*100)); } */ /* if (( cell == 440) || ( cell == 270) || (cell == 440+535) || ( cell == 270 + 535)) { fprintf(stderr, " %d React maximum kinetic rate is %10.6g, sat %f, h %f, htot %f, %s is %14.12f!\n",cell, Rate_spe[11], CD->Vcele[cell].sat, CD->Vcele[cell].height_t,CD->Vcele[cell].height_v, CD->chemtype[11].ChemName, CD->Vcele[cell].p_conc[11]); } */ free(residue); free(residue_t); free(tmpconc); free(totconc); free(area); free(error); free(gamma); free(Keq); free(Rate_pre); free(IAP); free(dependency); free(Rate_spe); free(Rate_spe_t); free(Rate_spet); free(p); free(x_); return(0); }
int Speciation(Chem_Data CD, int cell){ /* if speciation flg = 1, pH is defined * if speciation flg = 0, all defined value is total concentration */ int i, j ,k, control, speciation_flg = CD->SPCFlg, num_spe = CD->NumStc + CD->NumSsc ; double residue[CD->NumStc], residue_t[CD->NumStc], tmpconc[CD->NumStc+CD->NumSsc], totconc[CD->NumStc]; double tmpval, tmpprb= 1E-2, I, Iroot; double error[CD->NumStc], gamma[num_spe], Keq[CD->NumSsc], current_totconc[CD->NumStc], adh, bdh, bdt; realtype ** jcb; if ( CD->TEMcpl == 0 ){ for ( i = 0 ; i < CD->NumSsc; i ++) Keq[i] = CD->Keq[i]; adh = CD->DH.adh; bdh = CD->DH.bdh; bdt = CD->DH.bdt; } /* if ( CD->TEMcpl == 1){ for ( i = 0 ; i < CD->NumSsc; i ++) Keq[i] = CD->Vcele[cell].Keq[i]; adh = CD->Vcele[cell].DH.adh; bdh = CD->Vcele[cell].DH.bdh; bdt = CD->Vcele[cell].DH.bdt; } */ // fprintf(stderr, "\n The activity correction is set to %d.\n", CD->ACTmod); for ( i = 0; i < CD->NumStc; i ++){ tmpconc[i] = log10(CD->Vcele[cell].p_conc[i]); } // using log10 conc as the primary unknowns. works better because negative numbers are not problem. for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++){ tmpval += tmpconc[j]* CD->Dependency[i][j]; } tmpval -= Keq[i]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " %s %6.4f\t", CD->chemtype[i+CD->NumSpc].ChemName, tmpconc[i+CD->NumSpc]); } // initial speciation to get secondary species, no activity corrections // if ( CD->ACTmod !=1) for ( i = 0 ; i < num_spe; i ++) gamma[i] = 0; for ( i = 0; i < CD->NumStc; i++){ // fprintf(stderr, " Sum%s:%12.10f\t %s:%12.10f\n",CD->chemtype[i].ChemName, log10(CD->Vcele[cell].t_conc[i]), CD->chemtype[i].ChemName,log10( CD->Vcele[cell].p_conc[i])); current_totconc[i] = CD->Vcele[cell].t_conc[i]; } if ( speciation_flg ==1){ /* pH is defined, total concentration is calculated from the activity of H */ /* Dependency is the same but the total concentration for H need not be solved */ jcb = denalloc(CD->NumStc -1); long int p[CD->NumStc-1]; realtype x_[CD->NumStc-1]; double maxerror= 1; control = 0; while ( maxerror>TOL){ if ( CD->ACTmod ==1){ I = 0; // calculate the ionic strength in this block for ( i = 0 ; i < num_spe; i ++) I += 0.5 * pow( 10, tmpconc[i]) * sqr(CD->chemtype[i].Charge); Iroot = sqrt(I); for ( i = 0 ; i < num_spe; i ++){ if ( CD->chemtype[i].itype == 4) gamma[i] = -tmpconc[i]; // aqueous species in the unit of mol/L, however the solids are in the unit of mol/L porous media // the activity of solid is 1, the log10 of activity is 0. // by assigning gamma[minerals] to negative of the tmpconc[minerals], we ensured the log 10 of activity of solids are 0; else gamma[i] = (-adh * sqr(CD->chemtype[i].Charge) * Iroot)/(1 + bdh * CD->chemtype[i].SizeF * Iroot) + bdt * I; // fprintf(stderr, " Log10gamma of %s %6.4f\n", CD->chemtype[i].ChemName, gamma[i]); if ( strcmp(CD->chemtype[i].ChemName, "'H+'")== 0){ tmpconc[i] = log10(CD->Vcele[cell].p_actv[i]) - gamma[i]; // log a = log c + log gamma; log c = log a - log gamma; } } // gamma stores log10gamma[i]. } // fprintf(stderr, "\n Ionic strength is %6.4f\n", I); // fprintf(stderr, " Newton Iterations = %d\n\n",control); for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++){ tmpval += (tmpconc[j] + gamma[j])* CD->Dependency[i][j]; } tmpval -= Keq[i] + gamma[i + CD->NumStc]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " UPDATE %s %6.4f\n", CD->chemtype[i+CD->NumSpc].ChemName, tmpconc[i+CD->NumSpc]); } for ( i = 0; i < CD->NumStc; i ++){ tmpval = 0.0; for ( j = 0; j < num_spe; j++){ tmpval+= CD->Totalconc[i][j]*pow(10,tmpconc[j]); //fprintf(stderr, " %s %6.4f\t %6.4f\n", CD->chemtype[j].ChemName,CD->Totalconc[i][j], tmpconc[j]); } totconc[i] = tmpval; if ( strcmp(CD->chemtype[i].ChemName, "'H+'") == 0) CD->Vcele[cell].t_conc[i] = totconc[i]; residue[i] = tmpval - CD->Vcele[cell].t_conc[i]; /* update the total concentration of H+ for later stage RT at initialization */ // fprintf(stderr, " Residue: Sum%s %6.4g\n", CD->chemtype[i].ChemName, residue[i]); } int row, col; col = 0; for ( k = 0; k < CD->NumStc; k ++){ if ( strcmp(CD->chemtype[k].ChemName, "'H+'")!=0){ tmpconc[k] += tmpprb; for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++) tmpval += (tmpconc[j]+gamma[j])* CD->Dependency[i][j]; tmpval -= Keq[i] + gamma[i + CD->NumStc]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " CALC_SEC %s %6.4f\t %6.4f\n", CD->chemtype[i+CD->NumStc].ChemName, tmpval, pow(10,tmpconc[i+CD->NumStc])); } row = 0; for ( i = 0; i < CD->NumStc; i ++){ if ( strcmp(CD->chemtype[i].ChemName, "'H+'")!=0){ tmpval = 0.0; for ( j = 0; j < CD->NumStc + CD-> NumSsc; j++){ tmpval+= CD->Totalconc[i][j]*pow(10,tmpconc[j]); // fprintf(stderr, " CALC_TOT %s %6.4f\t %6.4f\n",CD->chemtype[j].ChemName, CD->Totalconc[i][j], pow(10,tmpconc[j])); } //totconc[i] = tmpval; // fprintf(stderr, " CALC_TOT Sum%s %6.4f\t %12.10f\n", CD->chemtype[i].ChemName, log10(totconc[i]), totconc[i]); residue_t[i] = tmpval - CD->Vcele[cell].t_conc[i]; //fprintf(stderr, " %d %d\n",col,row); jcb[col][row] = (residue_t[i]- residue[i])/(tmpprb); // fprintf(stderr, "%g\n", jcb[k][i]); // fprintf(stderr, " Sum%s %6.4f\t %6.4f\n", CD->chemtype[i].ChemName, tmpval, residue_t[i]); row ++; } } tmpconc[k] -= tmpprb; col ++; } } row = 0; for ( i = 0 ; i < CD->NumStc; i ++) if ( strcmp(CD->chemtype[i].ChemName, "'H+'")!=0) x_[row++] = - residue[i]; //fprintf(stderr, " Jacobian Matrix!\n"); //denprint(jcb, CD->NumSpc-1); // fprintf(stderr, " LU flag %ld\n",gefa(jcb,CD->NumStc-1,p)); if(gefa(jcb, CD->NumStc-1, p)!=0){ ReportError(CD->Vcele[cell], CD); return(1); // assert(gefa(jcb, CD->NumStc-1, p) == 0 ); } gesl(jcb, CD->NumStc-1, p, x_); // gauss(jcb, x_, CD->NumStc-1); // assert(gefa(jcb, CD->NumStc-1, p)==0); row = 0; for (i = 0 ; i < CD->NumStc; i ++){ if ( strcmp(CD->chemtype[i].ChemName, "'H+'")!=0) tmpconc[i] += x_[row++] ; // fprintf(stderr, " %s %6.4f\t %6.4f\n", CD->chemtype[i].ChemName, tmpconc[i], x_[i]); error[i] = residue[i]/totconc[i]; } maxerror = fabs(error[0]); for ( i = 1; i < CD->NumStc; i ++) if ( fabs(error[i])>maxerror ) maxerror = fabs(error[i]); control ++; } } if ( speciation_flg ==0){ // fprintf(stderr, " \n\nTotal H+\n\n"); jcb = denalloc(CD->NumStc); long int p[CD->NumStc]; realtype x_[CD->NumStc]; control =0; double maxerror= 1; while ( maxerror > TOL){ if ( CD->ACTmod ==1){ I = 0.0; // calculate the ionic strength in this block for ( i = 0 ; i < num_spe; i ++){ I += 0.5 * pow( 10, tmpconc[i]) * sqr(CD->chemtype[i].Charge); // fprintf(stderr, " I_CALC, %s: %6.4f\t %6.4f\n",CD->chemtype[i].ChemName, pow(10,tmpconc[i]), sqr(CD->chemtype[i].Charge)); } Iroot = sqrt(I); for ( i = 0 ; i < num_spe; i ++){ if ( CD->chemtype[i].itype == 4) gamma[i] = - tmpconc[i]; else gamma[i] = ( - adh * sqr(CD->chemtype[i].Charge) * Iroot)/(1 + bdh * CD->chemtype[i].SizeF * Iroot) + bdt * I; // fprintf(stderr, " Log10gamma of %s %6.4f\n", CD->chemtype[i].ChemName, gamma[i]); // log a = log c + log gamma; log c = log a - log gamma; } } // gamma stores log10gamma[i]. // fprintf(stderr, "\n Ionic strength is %6.4f\n", I); // fprintf(stderr, "\n NEWTON ITERATION = %d\n",control); for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++){ tmpval += (tmpconc[j] + gamma[j])* CD->Dependency[i][j]; } tmpval -= Keq[i] + gamma[i + CD->NumStc]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " UPDATE %s %6.4f\n", CD->chemtype[i+CD->NumStc].ChemName, tmpconc[i+CD->NumStc]); } for ( i = 0; i < CD->NumStc; i ++){ tmpval = 0.0; for ( j = 0; j < CD->NumStc + CD-> NumSsc; j++){ tmpval+= CD->Totalconc[i][j]*pow(10,tmpconc[j]); // fprintf(stderr, " %s %6.4f\t %6.4f\n", CD->chemtype[j].ChemName,CD->Totalconc[i][j], tmpconc[j]); } totconc[i] = tmpval; residue[i] = tmpval - CD->Vcele[cell].t_conc[i]; // fprintf(stderr, " Residue: Sum%s %6.4f\n", CD->chemtype[i].ChemName, residue[i]); } for ( k = 0; k < CD->NumStc; k ++){ tmpconc[k] += tmpprb; for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++) tmpval += (tmpconc[j]+ gamma[j])* CD->Dependency[i][j]; tmpval -= Keq[i] + gamma[i+ CD->NumStc]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " CALC_SEC %s %6.4f\t %6.4f\n", CD->chemtype[i+CD->NumSpc].ChemName, tmpval, pow(10,tmpconc[i+CD->NumSpc])); } for ( i = 0; i < CD->NumStc; i ++){ tmpval = 0.0; for ( j = 0; j < CD->NumStc + CD-> NumSsc; j++){ tmpval+= CD->Totalconc[i][j]*pow(10,tmpconc[j]); // fprintf(stderr, " CALC_TOT %s %6.4f\t %6.4f\n",CD->chemtype[j].ChemName, CD->Totalconc[i][j], pow(10,tmpconc[j])); } // totconc[i] = tmpval; //fprintf(stderr, " CALC_TOT Sum%s %6.4f\t %12.10f\n", CD->chemtype[i].ChemName, log10(totconc[i]), totconc[i]); residue_t[i] = tmpval - CD->Vcele[cell].t_conc[i]; jcb[k][i] = (residue_t[i]- residue[i])/(tmpprb); // fprintf(stderr, "%g\n", jcb[k][i]); // fprintf(stderr, " Sum%s %6.4f\t %6.4f\n", CD->chemtype[i].ChemName, tmpval, residue_t[i]); } tmpconc[k] -= tmpprb; } for ( i = 0 ; i < CD->NumStc; i ++) x_[i] = - residue[i]; // fprintf(stderr, " Jacobian Matrix!\n"); // denprint(jcb, CD->NumSpc); if(gefa(jcb, CD->NumStc, p)!=0){ ReportError(CD->Vcele[cell], CD); return(1); // assert(gefa(jcb, CD->NumStc, p) == 0 ); } // fprintf(stderr, " LU %ld\n",gefa(jcb,CD->NumStc,p)); gesl(jcb, CD->NumStc, p, x_); // gauss(jcb, x_, CD->NumStc); for (i = 0 ; i < CD->NumStc; i ++){ tmpconc[i] += x_[i] ; // fprintf(stderr, " %s TMPCON %6.4f\t IMPROVE %g", CD->chemtype[i].ChemName, tmpconc[i], x_[i]); error[i] = residue[i]/totconc[i] ; // fprintf(stderr, " RESI %6.4g\t TOT_CONC %6.4g\t ERROR %6.4g\n", residue[i], totconc[i], error[i] ); } maxerror = fabs(error[0]); for ( i = 1; i < CD->NumStc; i ++) if ( fabs(error[i])>maxerror ) maxerror = fabs(error[i]); control ++; } } // fprintf(stderr, " Solution Reached!\n"); for ( i = 0; i < CD->NumSsc; i ++){ tmpval = 0.0; for ( j = 0 ; j < CD->NumSdc; j ++){ tmpval += (tmpconc[j] + gamma[j])* CD->Dependency[i][j]; } tmpval -= Keq[i] + gamma[i + CD->NumStc]; tmpconc[i+CD->NumStc] = tmpval; // fprintf(stderr, " UPDATE %s %6.4f\n", CD->chemtype[i+CD->NumStc].ChemName, (tmpconc[i+CD->NumStc])); } for ( i = 0; i < CD->NumStc; i ++){ tmpval = 0.0; for ( j = 0; j < CD->NumStc + CD-> NumSsc; j++){ tmpval+= CD->Totalconc[i][j]*pow(10,tmpconc[j]); // fprintf(stderr, " %s %6.4f\t %6.4f\n", CD->chemtype[j].ChemName,CD->Totalconc[i][j], tmpconc[j]); } totconc[i] = tmpval; residue[i] = tmpval - CD->Vcele[cell].t_conc[i]; error[i] = residue[i]/totconc[i]; // fprintf(stderr, " Residue: Sum%s %6.4f\n", CD->chemtype[i].ChemName, residue[i]); } for ( i = 0; i < CD->NumStc + CD->NumSsc; i ++){ if ( i < CD->NumStc){ if ( CD->chemtype[i].itype == 4){ CD->Vcele[cell].p_conc[i] = pow(10,tmpconc[i]); CD->Vcele[cell].p_actv[i] = 1.0; } else{ CD->Vcele[cell].p_conc[i] = pow(10,tmpconc[i]); CD->Vcele[cell].p_actv[i] = pow(10,(tmpconc[i] + gamma[i])); } } else{ CD->Vcele[cell].s_conc[i-CD->NumStc] = pow(10,tmpconc[i]); CD->Vcele[cell].s_actv[i-CD->NumStc] = pow(10,(tmpconc[i] + gamma[i])); } // fprintf(stderr, " %s LogC: %6.4f\t C: %6.4f\t Loga: %6.4f\t a: %6.4f\n", CD->chemtype[i].ChemName, tmpconc[i], pow(10, tmpconc[i]), tmpconc[i]+gamma[i], pow(10, tmpconc[i]+gamma[i])); } // for ( i = 0; i < CD->NumStc; i ++){ // fprintf(stderr, " Sum%s: log10(TOTCONC_NR) %4.3f\t log10(TOTCONC_B) %4.3f\t TOTCONC_NR %4.3g\t RESIDUE %2.1g\t RELATIVE ERROR %2.1g\n", CD->chemtype[i].ChemName,log10(totconc[i]),log10(CD->Vcele[cell].t_conc[i]), totconc[i], fabs(residue[i]), fabs(error[i]*100)); // } denfree(jcb); return(0); }
int main(int argc, char *argv[]) { MPI_Comm comm; void *mem, *P_data; UserData webdata; long int SystemSize, local_N, mudq, mldq, mukeep, mlkeep; realtype rtol, atol, t0, tout, tret; N_Vector cc, cp, res, id; int thispe, npes, maxl, iout, retval; cc = cp = res = id = NULL; webdata = NULL; mem = P_data = NULL; /* Set communicator, and get processor number and total number of PE's. */ MPI_Init(&argc, &argv); comm = MPI_COMM_WORLD; MPI_Comm_rank(comm, &thispe); MPI_Comm_size(comm, &npes); if (npes != NPEX*NPEY) { if (thispe == 0) fprintf(stderr, "\nMPI_ERROR(0): npes = %d not equal to NPEX*NPEY = %d\n", npes, NPEX*NPEY); MPI_Finalize(); return(1); } /* Set local length (local_N) and global length (SystemSize). */ local_N = MXSUB*MYSUB*NUM_SPECIES; SystemSize = NEQ; /* Set up user data block webdata. */ webdata = (UserData) malloc(sizeof *webdata); webdata->rates = N_VNew_Parallel(comm, local_N, SystemSize); webdata->acoef = denalloc(NUM_SPECIES, NUM_SPECIES); InitUserData(webdata, thispe, npes, comm); /* Create needed vectors, and load initial values. The vector res is used temporarily only. */ cc = N_VNew_Parallel(comm, local_N, SystemSize); if(check_flag((void *)cc, "N_VNew_Parallel", 0, thispe)) MPI_Abort(comm, 1); cp = N_VNew_Parallel(comm, local_N, SystemSize); if(check_flag((void *)cp, "N_VNew_Parallel", 0, thispe)) MPI_Abort(comm, 1); res = N_VNew_Parallel(comm, local_N, SystemSize); if(check_flag((void *)res, "N_VNew_Parallel", 0, thispe)) MPI_Abort(comm, 1); id = N_VNew_Parallel(comm, local_N, SystemSize); if(check_flag((void *)id, "N_VNew_Parallel", 0, thispe)) MPI_Abort(comm, 1); SetInitialProfiles(cc, cp, id, res, webdata); N_VDestroy_Parallel(res); /* Set remaining inputs to IDAMalloc. */ t0 = ZERO; rtol = RTOL; atol = ATOL; /* Call IDACreate and IDAMalloc to initialize solution */ mem = IDACreate(); if(check_flag((void *)mem, "IDACreate", 0, thispe)) MPI_Abort(comm, 1); retval = IDASetRdata(mem, webdata); if(check_flag(&retval, "IDASetRdata", 1, thispe)) MPI_Abort(comm, 1); retval = IDASetId(mem, id); if(check_flag(&retval, "IDASetId", 1, thispe)) MPI_Abort(comm, 1); retval = IDAMalloc(mem, resweb, t0, cc, cp, IDA_SS, rtol, &atol); if(check_flag(&retval, "IDAMalloc", 1, thispe)) MPI_Abort(comm, 1); /* Call IDABBDPrecAlloc to initialize the band-block-diagonal preconditioner. The half-bandwidths for the difference quotient evaluation are exact for the system Jacobian, but only a 5-diagonal band matrix is retained. */ mudq = mldq = NSMXSUB; mukeep = mlkeep = 2; P_data = IDABBDPrecAlloc(mem, local_N, mudq, mldq, mukeep, mlkeep, ZERO, reslocal, NULL); if(check_flag((void *)P_data, "IDABBDPrecAlloc", 0, thispe)) MPI_Abort(comm, 1); /* Call IDABBDSpgmr to specify the IDA linear solver IDASPGMR and specify the preconditioner routines supplied maxl (max. Krylov subspace dim.) is set to 16. */ maxl = 16; retval = IDABBDSpgmr(mem, maxl, P_data); if(check_flag(&retval, "IDABBDSpgmr", 1, thispe)) MPI_Abort(comm, 1); /* Call IDACalcIC (with default options) to correct the initial values. */ tout = RCONST(0.001); retval = IDACalcIC(mem, IDA_YA_YDP_INIT, tout); if(check_flag(&retval, "IDACalcIC", 1, thispe)) MPI_Abort(comm, 1); /* On PE 0, print heading, basic parameters, initial values. */ if (thispe == 0) PrintHeader(SystemSize, maxl, mudq, mldq, mukeep, mlkeep, rtol, atol); PrintOutput(mem, cc, t0, webdata, comm); /* Call IDA in tout loop, normal mode, and print selected output. */ for (iout = 1; iout <= NOUT; iout++) { retval = IDASolve(mem, tout, &tret, cc, cp, IDA_NORMAL); if(check_flag(&retval, "IDASolve", 1, thispe)) MPI_Abort(comm, 1); PrintOutput(mem, cc, tret, webdata, comm); if (iout < 3) tout *= TMULT; else tout += TADD; } /* On PE 0, print final set of statistics. */ if (thispe == 0) PrintFinalStats(mem, P_data); /* Free memory. */ N_VDestroy_Parallel(cc); N_VDestroy_Parallel(cp); N_VDestroy_Parallel(id); IDABBDPrecFree(&P_data); IDAFree(&mem); denfree(webdata->acoef); N_VDestroy_Parallel(webdata->rates); free(webdata); MPI_Finalize(); return(0); }