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);
}
示例#2
0
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);
}
示例#3
0
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);
}
示例#7
0
void DenseFreeMat(DenseMat A)
{
  denfree(A->data);
  free(A);
}
示例#8
0
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);

}
示例#9
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);
}