示例#1
0
/*
 *  This routine is mostly concerned with changing the private data
 *  to be consistent with that needed for solution. It is called for
 *  every invocation of the vcs_solve() except for the cleanup invocation.
 *
 * Tasks:
 *  1)  Initialization of arrays to zero.
 *  2)  Calculate total number of moles in all phases
 *
 *  return code
 *     VCS_SUCCESS = everything went OK
 *     VCS_PUB_BAD = There is an irreconcilable difference in the
 *                   public data structure from when the problem was
 *                   initially set up.
 */
int VCS_SOLVE::vcs_prep() {
    /*
     *        Initialize various arrays in the data to zero
     */
    vcs_vdzero(m_feSpecies_old, m_numSpeciesTot);
    vcs_vdzero(m_feSpecies_new, m_numSpeciesTot);
    vcs_vdzero(m_molNumSpecies_new, m_numSpeciesTot);
    vcs_dzero(&(m_deltaMolNumPhase[0][0]), m_numSpeciesTot * m_numPhases);
    vcs_izero(&(m_phaseParticipation[0][0]), m_numSpeciesTot * m_numPhases);
    vcs_dzero(VCS_DATA_PTR(m_deltaPhaseMoles), m_numPhases);
    vcs_dzero(VCS_DATA_PTR(m_tPhaseMoles_new), m_numPhases);
    /*
     *   Calculate the total number of moles in all phases.
     */
    vcs_tmoles();
    return VCS_SUCCESS;
}
示例#2
0
  /*
   *  Redimensionalize the free energies using the multiplier R * T
   *
   *  Essentially the internal data can either be in dimensional form
   *  or in nondimensional form. This routine switches the data from 
   *  nondimensional form into dimensional form.
   *
   *  What we do is to multiply by RT.
   */
  void VCS_SOLVE::vcs_redim_TP(void)
  {
    double tf;
    if (m_unitsState != VCS_DIMENSIONAL_G) {
      m_unitsState = VCS_DIMENSIONAL_G;
      tf = vcs_nondimMult_TP(m_VCS_UnitsFormat, m_temperature);
      for (size_t i = 0; i < m_numSpeciesTot; ++i) {
	/* 
	 *        Modify the standard state and total chemical potential data,
	 *        FF(I),  to make it have units, i.e. mu = RT * mu_star
	 */  
	m_SSfeSpecies[i] *= tf;
	m_deltaGRxn_new[i] *= tf;
	m_deltaGRxn_old[i] *= tf;
	m_feSpecies_old[i] *= tf;
      } 
      m_Faraday_dim *= tf;
    }
    if (m_totalMoleScale != 1.0) {
      if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
#ifdef DEBUG_MODE
	if (m_debug_print_lvl >= 2) {
	  plogf("  --- vcs_redim_TP() called: getting rid of mole scale of %g", m_totalMoleScale);
	  plogendl();
	}
#endif
	for (size_t i = 0; i < m_numSpeciesTot; ++i) {
	  if (m_speciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	    m_molNumSpecies_old[i] *= m_totalMoleScale;
	  }
	}
	for (size_t i = 0; i < m_numElemConstraints; ++i) {
	  m_elemAbundancesGoal[i] *= m_totalMoleScale;
	}

	for (size_t iph = 0; iph < m_numPhases; iph++) {
	  TPhInertMoles[iph] *= m_totalMoleScale;
	  if (TPhInertMoles[iph] != 0.0) {
	    vcs_VolPhase *vphase = m_VolPhaseList[iph];
	    vphase->setTotalMolesInert(TPhInertMoles[iph]);
	  }
	}
	vcs_tmoles();
      }
    }
  } 
示例#3
0
int VCS_SOLVE::vcs_prep()
{
    /*
     *        Initialize various arrays in the data to zero
     */
    m_feSpecies_old.assign(m_feSpecies_old.size(), 0.0);
    m_feSpecies_new.assign(m_feSpecies_new.size(), 0.0);
    m_molNumSpecies_new.assign(m_molNumSpecies_new.size(), 0.0);
    m_deltaMolNumPhase.zero();
    m_phaseParticipation.zero();
    m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0);
    m_tPhaseMoles_new.assign(m_tPhaseMoles_new.size(), 0.0);
    /*
     *   Calculate the total number of moles in all phases.
     */
    vcs_tmoles();
    return VCS_SUCCESS;
}
示例#4
0
  int VCS_SOLVE::vcs_elcorr(double aa[], double x[])
   
    /**************************************************************************
     *
     * vcs_elcorr:
     *
     * This subroutine corrects for element abundances. At the end of the 
     * surbroutine, the total moles in all phases are recalculated again,
     * because we have changed the number of moles in this routine.
     *
     * Input
     *  -> temporary work vectors:
     *     aa[ne*ne]
     *     x[ne]
     *
     * Return Values:
     *      0 = Nothing of significance happened,   
     *          Element abundances were and still are good.
     *      1 = The solution changed significantly; 
     *          The element abundances are now good.
     *      2 = The solution changed significantly,
     *          The element abundances are still bad.
     *      3 = The solution changed significantly,
     *          The element abundances are still bad and a component 
     *          species got zeroed out.
     *
     *  Internal data to be worked on::
     *
     *  ga    Current element abundances
     *  m_elemAbundancesGoal   Required elemental abundances
     *  m_molNumSpecies_old     Current mole number of species.
     *  m_formulaMatrix[][]  Formular matrix of the species
     *  ne    Number of elements
     *  nc    Number of components.
     *
     * NOTES:
     *  This routine is turning out to be very problematic. There are 
     *  lots of special cases and problems with zeroing out species.
     *
     *  Still need to check out when we do loops over nc vs. ne.
     *  
     *************************************************************************/
  {
    int i, j, retn = 0, kspec, goodSpec, its; 
    double xx, par, saveDir, dir;

#ifdef DEBUG_MODE
    double l2before = 0.0, l2after = 0.0;
    std::vector<double> ga_save(m_numElemConstraints, 0.0);
    vcs_dcopy(VCS_DATA_PTR(ga_save), VCS_DATA_PTR(m_elemAbundances), m_numElemConstraints);
    if (m_debug_print_lvl >= 2) {
      plogf("   --- vcsc_elcorr: Element abundances correction routine");
      if (m_numElemConstraints != m_numComponents) {
	plogf(" (m_numComponents != m_numElemConstraints)");
      }
      plogf("\n");
    }

    for (i = 0; i < m_numElemConstraints; ++i) {
      x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i];
    }
    l2before = 0.0;
    for (i = 0; i < m_numElemConstraints; ++i) {
      l2before += x[i] * x[i];
    }
    l2before = sqrt(l2before/m_numElemConstraints);
#endif

    /*
     * Special section to take out single species, single component,
     * moles. These are species which have non-zero entries in the
     * formula matrix, and no other species have zero values either.
     *
     */
    int numNonZero = 0;
    bool changed = false;
    bool multisign = false;
    for (i = 0; i < m_numElemConstraints; ++i) {
      numNonZero = 0;
      multisign = false;
      for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
	if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	  double eval = m_formulaMatrix[i][kspec];
	  if (eval < 0.0) {
	    multisign = true;
	  }
	  if (eval != 0.0) {
	    numNonZero++;
	  }
	}
      }
      if (!multisign) {
	if (numNonZero < 2) {
	  for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
	    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	      double eval = m_formulaMatrix[i][kspec];
	      if (eval > 0.0) {
		m_molNumSpecies_old[kspec] = m_elemAbundancesGoal[i] / eval;
		changed = true;
	      }
	    }
	  }
	} else {
	  int numCompNonZero = 0;
	  int compID = -1;
	  for (kspec = 0; kspec < m_numComponents; kspec++) {
	    if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	      double eval = m_formulaMatrix[i][kspec];
	      if (eval > 0.0) {
		compID = kspec;
		numCompNonZero++;
	      }
	    }
	  }
	  if (numCompNonZero == 1) {
	    double diff = m_elemAbundancesGoal[i];
	    for (kspec = m_numComponents; kspec < m_numSpeciesTot; kspec++) {
	      if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
		double eval = m_formulaMatrix[i][kspec];
		diff -= eval * m_molNumSpecies_old[kspec];
	      }
	      m_molNumSpecies_old[compID] = MAX(0.0,diff/m_formulaMatrix[i][compID]);
	      changed = true;
	    }
	  }
	}
      }
    }
    if (changed) {
      vcs_elab();
    }

    /*
     *  Section to check for maximum bounds errors on all species
     *  due to elements.
     *    This may only be tried on element types which are VCS_ELEM_TYPE_ABSPOS.
     *    This is because no other species may have a negative number of these.
     *
     *  Note, also we can do this over ne, the number of elements, not just
     *  the number of components.
     */
    changed = false;
    for (i = 0; i < m_numElemConstraints; ++i) {
      int elType = m_elType[i];
      if (elType == VCS_ELEM_TYPE_ABSPOS) {
	for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
	  if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	    double atomComp = m_formulaMatrix[i][kspec];
	    if (atomComp > 0.0) {
	      double maxPermissible = m_elemAbundancesGoal[i] / atomComp;
	      if (m_molNumSpecies_old[kspec] > maxPermissible) {
	      
#ifdef DEBUG_MODE
		if (m_debug_print_lvl >= 3) {
		  plogf("  ---  vcs_elcorr: Reduced species %s from %g to %g "
			"due to %s max bounds constraint\n",
			m_speciesName[kspec].c_str(), m_molNumSpecies_old[kspec], 
			maxPermissible, m_elementName[i].c_str());
		}
#endif
		m_molNumSpecies_old[kspec] = maxPermissible;
		changed = true;
		if (m_molNumSpecies_old[kspec] < VCS_DELETE_MINORSPECIES_CUTOFF) {
		  m_molNumSpecies_old[kspec] = 0.0;
		  if (m_SSPhase[kspec]) {
		    m_speciesStatus[kspec] = VCS_SPECIES_ZEROEDSS;
		  } else {
		    m_speciesStatus[kspec] = VCS_SPECIES_ACTIVEBUTZERO;
		  } 
#ifdef DEBUG_MODE
		  if (m_debug_print_lvl >= 2) {
		    plogf("  ---  vcs_elcorr: Zeroed species %s and changed "
			  "status to %d due to max bounds constraint\n",
			  m_speciesName[kspec].c_str(), m_speciesStatus[kspec]);
		  }
#endif
		}
	      }
	    }
	  }
	}
      }
    }

    // Recalculate the element abundances if something has changed.
    if (changed) {
      vcs_elab();
    }

    /*
     * Ok, do the general case. Linear algebra problem is 
     * of length nc, not ne, as there may be degenerate rows when
     * nc .ne. ne.
     */
    for (i = 0; i < m_numComponents; ++i) {
      x[i] = m_elemAbundances[i] - m_elemAbundancesGoal[i];
      if (fabs(x[i]) > 1.0E-13) retn = 1;
      for (j = 0; j < m_numComponents; ++j) {
	aa[j + i*m_numElemConstraints] = m_formulaMatrix[j][i];
      }
    }
    i = vcsUtil_mlequ(aa, m_numElemConstraints, m_numComponents, x, 1);
    if (i == 1) {
      plogf("vcs_elcorr ERROR: mlequ returned error condition\n");
      return VCS_FAILED_CONVERGENCE;
    }
    /*
     * Now apply the new direction without creating negative species.
     */
    par = 0.5;
    for (i = 0; i < m_numComponents; ++i) {
      if (m_molNumSpecies_old[i] > 0.0) {
	xx = -x[i] / m_molNumSpecies_old[i];
	if (par < xx) par = xx;
      }
    }
    if (par > 100.0) {
      par = 100.0;
    }
    par = 1.0 / par;
    if (par < 1.0 && par > 0.0) {
      retn = 2;
      par *= 0.9999;
      for (i = 0; i < m_numComponents; ++i) {
	double tmp = m_molNumSpecies_old[i] + par * x[i];
	if (tmp > 0.0) {
	  m_molNumSpecies_old[i] = tmp;
	} else {
	  if (m_SSPhase[i]) {
	    m_molNumSpecies_old[i] =  0.0;
	  }  else {
	    m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001;
	  }
	}
      }
    } else {
      for (i = 0; i < m_numComponents; ++i) {
	double tmp = m_molNumSpecies_old[i] + x[i];
	if (tmp > 0.0) {
	  m_molNumSpecies_old[i] = tmp;
	} else { 
	  if (m_SSPhase[i]) {
	    m_molNumSpecies_old[i] =  0.0;
	  }  else {
	    m_molNumSpecies_old[i] = m_molNumSpecies_old[i] * 0.0001;
	  }
	}
      }
    }
   
    /*
     *   We have changed the element abundances. Calculate them again
     */
    vcs_elab();
    /*
     *   We have changed the total moles in each phase. Calculate them again
     */
    vcs_tmoles();
    
    /*
     *       Try some ad hoc procedures for fixing the problem
     */
    if (retn >= 2) {
      /*
       *       First find a species whose adjustment is a win-win
       *       situation.
       */
      for (kspec = 0; kspec < m_numSpeciesTot; kspec++) {
	if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	  continue;
	}
	saveDir = 0.0;
	goodSpec = TRUE;
	for (i = 0; i < m_numComponents; ++i) {
	  dir = m_formulaMatrix[i][kspec] *  (m_elemAbundancesGoal[i] - m_elemAbundances[i]);
	  if (fabs(dir) > 1.0E-10) {
	    if (dir > 0.0) {
	      if (saveDir < 0.0) {
		goodSpec = FALSE;
		break;
	      }
	    } else {
	      if (saveDir > 0.0) {
		goodSpec = FALSE;
		break;
	      }		   
	    }
	    saveDir = dir;
	  } else {
	    if (m_formulaMatrix[i][kspec] != 0.) {
	      goodSpec = FALSE;
	      break;
	    }
	  }
	}
	if (goodSpec) {
	  its = 0;
	  xx = 0.0;
	  for (i = 0; i < m_numComponents; ++i) {
	    if (m_formulaMatrix[i][kspec] != 0.0) {
	      xx += (m_elemAbundancesGoal[i] - m_elemAbundances[i]) / m_formulaMatrix[i][kspec];
	      its++;
	    }
	  }
	  if (its > 0) xx /= its;
	  m_molNumSpecies_old[kspec] += xx;
	  m_molNumSpecies_old[kspec] = MAX(m_molNumSpecies_old[kspec], 1.0E-10);
	  /*
	   *   If we are dealing with a deleted species, then
	   *   we need to reinsert it into the active list.
	   */
	  if (kspec >= m_numSpeciesRdc) {
	    vcs_reinsert_deleted(kspec);	
	    m_molNumSpecies_old[m_numSpeciesRdc - 1] = xx;
	    vcs_elab();
	    goto L_CLEANUP;
	  }
	  vcs_elab();  
	}
      }     
    }
    if (vcs_elabcheck(0)) {
      retn = 1;
      goto L_CLEANUP;
    }
  
    for (i = 0; i < m_numElemConstraints; ++i) {
      if (m_elType[i] == VCS_ELEM_TYPE_CHARGENEUTRALITY ||
	  (m_elType[i] == VCS_ELEM_TYPE_ABSPOS && m_elemAbundancesGoal[i] == 0.0)) { 
	for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
	  if (m_elemAbundances[i] > 0.0) {
	    if (m_formulaMatrix[i][kspec] < 0.0) {
	      m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix[i][kspec] ;
	      if (m_molNumSpecies_old[kspec] < 0.0) {
		m_molNumSpecies_old[kspec] = 0.0;
	      }
	      vcs_elab();
	      break;
	    }
	  }
	  if (m_elemAbundances[i] < 0.0) {
	    if (m_formulaMatrix[i][kspec] > 0.0) {
	      m_molNumSpecies_old[kspec] -= m_elemAbundances[i] / m_formulaMatrix[i][kspec];
	      if (m_molNumSpecies_old[kspec] < 0.0) {
		m_molNumSpecies_old[kspec] = 0.0;
	      }
	      vcs_elab();
	      break;
	    }
	  }
	}
      }
    }
    if (vcs_elabcheck(1)) {
      retn = 1;      
      goto L_CLEANUP;
    }

    /*
     *  For electron charges element types, we try positive deltas
     *  in the species concentrations to match the desired
     *  electron charge exactly.
     */
    for (i = 0; i < m_numElemConstraints; ++i) {
      double dev = m_elemAbundancesGoal[i] - m_elemAbundances[i];
      if (m_elType[i] == VCS_ELEM_TYPE_ELECTRONCHARGE && (fabs(dev) > 1.0E-300)) {
	bool useZeroed = true;
	for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
	  if (dev < 0.0) {
	    if (m_formulaMatrix[i][kspec] < 0.0) {
	      if (m_molNumSpecies_old[kspec] > 0.0) {
		useZeroed = false;
	      }
	    }
	  } else {
	    if (m_formulaMatrix[i][kspec] > 0.0) {
	      if (m_molNumSpecies_old[kspec] > 0.0) {
		useZeroed = false;
	      }
	    }
	  }
	}
	for (kspec = 0; kspec < m_numSpeciesRdc; kspec++) {
	  if (m_molNumSpecies_old[kspec] > 0.0 || useZeroed) {
	    if (dev < 0.0) {
	      if (m_formulaMatrix[i][kspec] < 0.0) {
		double delta = dev / m_formulaMatrix[i][kspec] ;
		m_molNumSpecies_old[kspec] += delta;
		if (m_molNumSpecies_old[kspec] < 0.0) {
		  m_molNumSpecies_old[kspec] = 0.0;
		}
		vcs_elab();
		break;
	      }
	    }
	    if (dev > 0.0) {
	      if (m_formulaMatrix[i][kspec] > 0.0) {
		double delta = dev / m_formulaMatrix[i][kspec] ;
		m_molNumSpecies_old[kspec] += delta;
		if (m_molNumSpecies_old[kspec] < 0.0) {
		  m_molNumSpecies_old[kspec] = 0.0;
		}
		vcs_elab();
		break;
	      }
	    }
	  }
	}
      }
    }
    if (vcs_elabcheck(1)) {
      retn = 1;      
      goto L_CLEANUP;
    }

  L_CLEANUP: ;
    vcs_tmoles();
#ifdef DEBUG_MODE
    l2after = 0.0;
    for (i = 0; i < m_numElemConstraints; ++i) {
      l2after += SQUARE(m_elemAbundances[i] - m_elemAbundancesGoal[i]);
    }
    l2after = sqrt(l2after/m_numElemConstraints);
    if (m_debug_print_lvl >= 2) {
      plogf("   ---    Elem_Abund:  Correct             Initial  "
	    "              Final\n");
      for (i = 0; i < m_numElemConstraints; ++i) {
	plogf("   ---       "); plogf("%-2.2s", m_elementName[i].c_str());
	plogf(" %20.12E %20.12E %20.12E\n", m_elemAbundancesGoal[i], ga_save[i], m_elemAbundances[i]);
      }
      plogf("   ---            Diff_Norm:         %20.12E %20.12E\n",
	    l2before, l2after);
    }
#endif
    return retn;
  }
示例#5
0
  /*
   *   Nondimensionalize the free energies using the divisor, R * T
   *
   *  Essentially the internal data can either be in dimensional form
   *  or in nondimensional form. This routine switches the data from 
   *  dimensional form into nondimensional form.
   *
   *  What we do is to divide by RT.
   *
   *  @todo Add a scale factor based on the total mole numbers.
   *        The algorithm contains hard coded numbers based on the
   *        total mole number. If we ever were faced with a problem
   *        with significantly different total kmol numbers than one
   *        the algorithm would have problems.
   */
  void VCS_SOLVE::vcs_nondim_TP() {
    double tf;
    if (m_unitsState == VCS_DIMENSIONAL_G) {
      m_unitsState = VCS_NONDIMENSIONAL_G;
      tf = 1.0 / vcs_nondimMult_TP(m_VCS_UnitsFormat, m_temperature);
      for (size_t i = 0; i < m_numSpeciesTot; ++i) {
	/* 
	 *        Modify the standard state and total chemical potential data,
	 *        FF(I),  to make it dimensionless, i.e.,  mu / RT.
	 *        Thus, we may divide it by the temperature.
	 */  
	m_SSfeSpecies[i] *= tf;
	m_deltaGRxn_new[i] *= tf;
	m_deltaGRxn_old[i] *= tf;
	m_feSpecies_old[i] *= tf;
      }

      m_Faraday_dim =  vcs_nondim_Farad(m_VCS_UnitsFormat, m_temperature);

      /*
       * Scale the total moles if necessary:
       *  First find out the total moles
       */
      double tmole_orig = vcs_tmoles();

      /*
       * Then add in the total moles of elements that are goals. Either one
       * or the other is specified here. 
       */
      double esum = 0.0;
      for (size_t i = 0; i < m_numElemConstraints; ++i) {
	if (m_elType[i] == VCS_ELEM_TYPE_ABSPOS) {
	  esum += fabs(m_elemAbundancesGoal[i]);
	}
      }
      tmole_orig += esum;
      
      /*
       * Ok now test out the bounds on the total moles that this program can
       * handle. These are a bit arbitrary. However, it would seem that any
       * reasonable input would be between these two numbers below.
       */
      if (tmole_orig < 1.0E-200 || tmole_orig > 1.0E200) {
	plogf(" VCS_SOLVE::vcs_nondim_TP ERROR: Total input moles , %g,  is outside the range handled by vcs. exit",
	      tmole_orig);
	plogendl();
	throw vcsError("VCS_SOLVE::vcs_nondim_TP", " Total input moles ," + Cantera::fp2str(tmole_orig) + 
		       "is outside the range handled by vcs.\n");
      }

      // Determine the scale of the problem
      if (tmole_orig > 1.0E4) {
	m_totalMoleScale =  tmole_orig / 1.0E4;
      } else if  (tmole_orig < 1.0E-4) {
	m_totalMoleScale =  tmole_orig / 1.0E-4;
      } else {
	m_totalMoleScale = 1.0;
      }

      if (m_totalMoleScale != 1.0) {
	if (m_VCS_UnitsFormat == VCS_UNITS_MKS) {
#ifdef DEBUG_MODE
	  if (m_debug_print_lvl >= 2) {
	    plogf("  --- vcs_nondim_TP() called: USING A MOLE SCALE OF %g until further notice", m_totalMoleScale);
	    plogendl();
	  }
#endif
	  for (size_t i = 0; i < m_numSpeciesTot; ++i) {
	    if (m_speciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
	      m_molNumSpecies_old[i] *= (1.0 / m_totalMoleScale);
	    }
	  }
	  for (size_t i = 0; i < m_numElemConstraints; ++i) {
	    m_elemAbundancesGoal[i] *= (1.0 / m_totalMoleScale);
	  }

	  for (size_t iph = 0; iph < m_numPhases; iph++) {
	    TPhInertMoles[iph] *= (1.0 / m_totalMoleScale);
	    if (TPhInertMoles[iph] != 0.0) {
	      vcs_VolPhase *vphase = m_VolPhaseList[iph];
	      vphase->setTotalMolesInert(TPhInertMoles[iph]);
	    }
	  }
	}
	vcs_tmoles();
      }
    }
  }
示例#6
0
int VCS_SOLVE::vcs_prep(int printLvl)
{
    int retn = VCS_SUCCESS;
    m_debug_print_lvl = printLvl;

    // Calculate the Single Species status of phases
    // Also calculate the number of species per phase
    vcs_SSPhase();

    // Set an initial estimate for the number of noncomponent species equal to
    // nspecies - nelements. This may be changed below
    if (m_nelem > m_nsp) {
        m_numRxnTot = 0;
    } else {
        m_numRxnTot = m_nsp - m_nelem;
    }
    m_numRxnRdc = m_numRxnTot;
    m_numSpeciesRdc = m_nsp;
    for (size_t i = 0; i < m_numRxnRdc; ++i) {
        m_indexRxnToSpecies[i] = m_nelem + i;
    }

    for (size_t kspec = 0; kspec < m_nsp; ++kspec) {
        size_t pID = m_phaseID[kspec];
        size_t spPhIndex = m_speciesLocalPhaseIndex[kspec];
        vcs_VolPhase* vPhase = m_VolPhaseList[pID].get();
        vcs_SpeciesProperties* spProp = vPhase->speciesProperty(spPhIndex);
        double sz = 0.0;
        size_t eSize = spProp->FormulaMatrixCol.size();
        for (size_t e = 0; e < eSize; e++) {
            sz += fabs(spProp->FormulaMatrixCol[e]);
        }
        if (sz > 0.0) {
            m_spSize[kspec] = sz;
        } else {
            m_spSize[kspec] = 1.0;
        }
    }

    // DETERMINE THE NUMBER OF COMPONENTS
    //
    // Obtain a valid estimate of the mole fraction. This will be used as an
    // initial ordering vector for prioritizing which species are defined as
    // components.
    //
    // If a mole number estimate was supplied from the input file, use that mole
    // number estimate.
    //
    // If a solution estimate wasn't supplied from the input file, supply an
    // initial estimate for the mole fractions based on the relative reverse
    // ordering of the chemical potentials.
    //
    // For voltage unknowns, set these to zero for the moment.
    double test = -1.0e-10;
    bool modifiedSoln = false;
    if (m_doEstimateEquil < 0) {
        double sum = 0.0;
        for (size_t kspec = 0; kspec < m_nsp; ++kspec) {
            if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
                sum += fabs(m_molNumSpecies_old[kspec]);
            }
        }
        if (fabs(sum) < 1.0E-6) {
            modifiedSoln = true;
            double pres = (m_pressurePA <= 0.0) ? 1.01325E5 : m_pressurePA;
            retn = vcs_evalSS_TP(0, 0, m_temperature, pres);
            for (size_t kspec = 0; kspec < m_nsp; ++kspec) {
                if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
                    m_molNumSpecies_old[kspec] = - m_SSfeSpecies[kspec];
                } else {
                    m_molNumSpecies_old[kspec] = 0.0;
                }
            }
        }
        test = -1.0e20;
    }

    // NC = number of components is in the vcs.h common block. This call to
    // BASOPT doesn't calculate the stoichiometric reaction matrix.
    vector_fp awSpace(m_nsp + (m_nelem + 2)*(m_nelem), 0.0);
    double* aw = &awSpace[0];
    if (aw == NULL) {
        plogf("vcs_prep_oneTime: failed to get memory: global bailout\n");
        return VCS_NOMEMORY;
    }
    double* sa = aw + m_nsp;
    double* sm = sa + m_nelem;
    double* ss = sm + m_nelem * m_nelem;
    bool conv;
    retn = vcs_basopt(true, aw, sa, sm, ss, test, &conv);
    if (retn != VCS_SUCCESS) {
        plogf("vcs_prep_oneTime:");
        plogf(" Determination of number of components failed: %d\n",
              retn);
        plogf("          Global Bailout!\n");
        return retn;
    }

    if (m_nsp >= m_numComponents) {
        m_numRxnTot = m_numRxnRdc = m_nsp - m_numComponents;
        for (size_t i = 0; i < m_numRxnRdc; ++i) {
            m_indexRxnToSpecies[i] = m_numComponents + i;
        }
    } else {
        m_numRxnTot = m_numRxnRdc = 0;
    }

    // The elements might need to be rearranged.
    awSpace.resize(m_nelem + (m_nelem + 2)*m_nelem, 0.0);
    aw = &awSpace[0];
    sa = aw + m_nelem;
    sm = sa + m_nelem;
    ss = sm + m_nelem * m_nelem;
    retn = vcs_elem_rearrange(aw, sa, sm, ss);
    if (retn != VCS_SUCCESS) {
        plogf("vcs_prep_oneTime:");
        plogf(" Determination of element reordering failed: %d\n",
              retn);
        plogf("          Global Bailout!\n");
        return retn;
    }

    // If we mucked up the solution unknowns because they were all
    // zero to start with, set them back to zero here
    if (modifiedSoln) {
        for (size_t kspec = 0; kspec < m_nsp; ++kspec) {
            m_molNumSpecies_old[kspec] = 0.0;
        }
    }

    // Initialize various arrays in the data to zero
    m_feSpecies_old.assign(m_feSpecies_old.size(), 0.0);
    m_feSpecies_new.assign(m_feSpecies_new.size(), 0.0);
    m_molNumSpecies_new.assign(m_molNumSpecies_new.size(), 0.0);
    m_deltaMolNumPhase.zero();
    m_phaseParticipation.zero();
    m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0);
    m_tPhaseMoles_new.assign(m_tPhaseMoles_new.size(), 0.0);

    // Calculate the total number of moles in all phases.
    vcs_tmoles();

    // Check to see if the current problem is well posed.
    double sum = 0.0;
    for (size_t e = 0; e < m_nelem; e++) {
        sum += m_mix->elementMoles(e);
    }
    if (sum < 1.0E-20) {
        // Check to see if the current problem is well posed.
        plogf("vcs has determined the problem is not well posed: Bailing\n");
        return VCS_PUB_BAD;
    }
    return VCS_SUCCESS;
}
示例#7
0
/**************************************************************************
 *
 *  vcs_report:
 *
 *     Print out a report on the state of the equilibrium problem to
 *     standard output.
 *     This prints out the current contents of the VCS_SOLVE class, V.
 *     The "old" solution vector is printed out.
 ***************************************************************************/
int VCS_SOLVE::vcs_report(int iconv) {
    bool printActualMoles = true, inertYes = false;
    size_t i, j, l, k, kspec;
    size_t nspecies = m_numSpeciesTot;
    double  g;

    char originalUnitsState = m_unitsState;


    std::vector<size_t> sortindex(nspecies,0);
    std::vector<double> xy(nspecies,0.0);

    /* ************************************************************** */
    /* **** SORT DEPENDENT SPECIES IN DECREASING ORDER OF MOLES ***** */
    /* ************************************************************** */

    for (i = 0; i < nspecies; ++i) {
        sortindex[i] = i;
        xy[i] = m_molNumSpecies_old[i];
    }
    /*
     *       Sort the XY vector, the mole fraction vector,
     *       and the sort index vector, sortindex, according to
     *       the magnitude of the mole fraction vector.
     */
    for (l = m_numComponents; l < m_numSpeciesRdc; ++l) {
        k = vcs_optMax(VCS_DATA_PTR(xy), 0, l, m_numSpeciesRdc);
        if (k != l) {
            vcsUtil_dsw(VCS_DATA_PTR(xy), k, l);
            vcsUtil_ssw(VCS_DATA_PTR(sortindex), k, l);
        }
    }

    /*
     *  Decide whether we have to nondimensionalize the equations.
     *     -> For the printouts from this routine, we will use nondimensional
     *        representations. This may be expanded in the future.
     */
    if (m_unitsState == VCS_DIMENSIONAL_G) {
        vcs_nondim_TP();
    }
    double molScale = 1.0;
    if (printActualMoles) {
        molScale = m_totalMoleScale;
    }

    vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
    vcs_dfe(VCS_STATECALC_OLD, 0, 0, m_numSpeciesTot);
    /* ******************************************************** */
    /* *** PRINT OUT RESULTS ********************************** */
    /* ******************************************************** */

    plogf("\n\n\n\n");
    print_line("-", 80);
    print_line("-", 80);
    plogf("\t\t VCS_TP REPORT\n");
    print_line("-", 80);
    print_line("-", 80);
    if (iconv < 0) {
        plogf(" ERROR: CONVERGENCE CRITERION NOT SATISFIED.\n");
    } else if (iconv == 1) {
        plogf(" RANGE SPACE ERROR: Equilibrium Found but not all Element Abundances are Satisfied\n");
    }
    /*
     *   Calculate some quantities that may need updating
     */
    vcs_tmoles();
    m_totalVol = vcs_VolTotal(m_temperature, m_pressurePA,
                              VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_PMVolumeSpecies));

    plogf("\t\tTemperature  = %15.2g Kelvin\n", m_temperature);
    plogf("\t\tPressure     = %15.5g Pa \n", m_pressurePA);
    plogf("\t\ttotal Volume = %15.5g m**3\n", m_totalVol * molScale);
    if (!printActualMoles) {
        plogf("\t\tMole Scale = %15.5g kmol (all mole numbers and volumes are scaled by this value)\n",
              molScale);
    }

    /*
     * -------- TABLE OF SPECIES IN DECREASING MOLE NUMBERS --------------
     */
    plogf("\n\n");
    print_line("-", 80);
    plogf(" Species                 Equilibrium kmoles   ");
    plogf("Mole Fraction    ChemPot/RT    SpecUnkType\n");
    print_line("-", 80);
    for (i = 0; i < m_numComponents; ++i) {
        plogf(" %-12.12s", m_speciesName[i].c_str());
        print_space(13);
        plogf("%14.7E     %14.7E    %12.4E", m_molNumSpecies_old[i] * molScale,
              m_molNumSpecies_new[i] * molScale, m_feSpecies_old[i]);
        plogf("   %3d", m_speciesUnknownType[i]);
        plogf("\n");
    }
    for (i = m_numComponents; i < m_numSpeciesRdc; ++i) {
        l = sortindex[i];
        plogf(" %-12.12s", m_speciesName[l].c_str());
        print_space(13);

        if (m_speciesUnknownType[l] == VCS_SPECIES_TYPE_MOLNUM) {
            plogf("%14.7E     %14.7E    %12.4E", m_molNumSpecies_old[l] * molScale,
                  m_molNumSpecies_new[l] * molScale, m_feSpecies_old[l]);
            plogf("  KMolNum ");
        } else if (m_speciesUnknownType[l] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            plogf("        NA         %14.7E    %12.4E", 1.0, m_feSpecies_old[l]);
            plogf("   Voltage = %14.7E", m_molNumSpecies_old[l] * molScale);
        } else {
            plogf("we have a problem\n");
            exit(EXIT_FAILURE);
        }
        plogf("\n");
    }
    for (i = 0; i < m_numPhases; i++) {
        if (TPhInertMoles[i] > 0.0) {
            inertYes = true;
            if (i == 0) {
                plogf(" Inert Gas Species        ");
            } else {
                plogf(" Inert Species in phase %16s ",
                      (m_VolPhaseList[i])->PhaseName.c_str());
            }
            plogf("%14.7E     %14.7E    %12.4E\n", TPhInertMoles[i] * molScale,
                  TPhInertMoles[i] /  m_tPhaseMoles_old[i], 0.0);
        }
    }
    if (m_numSpeciesRdc != nspecies) {
        plogf("\n SPECIES WITH LESS THAN 1.0E-32 KMOLES:\n\n");
        for (kspec = m_numSpeciesRdc; kspec < nspecies; ++kspec) {
            plogf(" %-12.12s", m_speciesName[kspec].c_str());
            // Note m_deltaGRxn_new[] stores in kspec slot not irxn slot, after solve
            plogf("             %14.7E     %14.7E    %12.4E",
                  m_molNumSpecies_old[kspec]*molScale,
                  m_molNumSpecies_new[kspec]*molScale, m_deltaGRxn_new[kspec]);
            if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_MOLNUM) {
                plogf("  KMol_Num");
            } else if (m_speciesUnknownType[i] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                plogf("   Voltage");
            } else {
                plogf("   Unknown");
            }

            plogf("\n");
        }
    }
    print_line("-", 80);
    plogf("\n");

    /*
     * ---------- TABLE OF SPECIES FORMATION REACTIONS ------------------
     */
    plogf("\n");
    print_line("-", m_numComponents*10 + 45);
    plogf("               |ComponentID|");
    for (j = 0; j < m_numComponents; j++) {
        plogf("        %3d", j);
    }
    plogf(" |           |\n");
    plogf("               | Components|");
    for (j = 0; j < m_numComponents; j++) {
        plogf(" %10.10s", m_speciesName[j].c_str());
    }
    plogf(" |           |\n");
    plogf(" NonComponent  |   Moles   |");
    for (j = 0; j < m_numComponents; j++) {
        plogf(" %10.3g", m_molNumSpecies_old[j] * molScale);
    }
    plogf(" | DG/RT Rxn |\n");
    print_line("-", m_numComponents*10 + 45);
    for (size_t irxn = 0; irxn < m_numRxnTot; irxn++) {
        size_t kspec = m_indexRxnToSpecies[irxn];
        plogf(" %3d ", kspec);
        plogf("%-10.10s", m_speciesName[kspec].c_str());
        plogf("|%10.3g |", m_molNumSpecies_old[kspec]*molScale);
        for (j = 0; j < m_numComponents; j++) {
            plogf("     %6.2f", m_stoichCoeffRxnMatrix[irxn][j]);
        }
        plogf(" |%10.3g |", m_deltaGRxn_new[irxn]);
        plogf("\n");
    }
    print_line("-", m_numComponents*10 + 45);
    plogf("\n");

    /*
     * ------------------ TABLE OF PHASE INFORMATION ---------------------
     */
    std::vector<double> gaPhase(m_numElemConstraints, 0.0);
    std::vector<double> gaTPhase(m_numElemConstraints, 0.0);
    double totalMoles = 0.0;
    double gibbsPhase = 0.0;
    double gibbsTotal = 0.0;
    plogf("\n\n");
    plogf("\n");
    print_line("-", m_numElemConstraints*10 + 58);
    plogf("                  | ElementID |");
    for (j = 0; j < m_numElemConstraints; j++) {
        plogf("        %3d", j);
    }
    plogf(" |                     |\n");
    plogf("                  | Element   |");
    for (j = 0; j < m_numElemConstraints; j++) {
        plogf(" %10.10s", (m_elementName[j]).c_str());
    }
    plogf(" |                     |\n");
    plogf("    PhaseName     |KMolTarget |");
    for (j = 0; j < m_numElemConstraints; j++) {
        plogf(" %10.3g", m_elemAbundancesGoal[j]);
    }
    plogf(" |     Gibbs Total     |\n");
    print_line("-", m_numElemConstraints*10 + 58);
    for (size_t iphase = 0; iphase < m_numPhases; iphase++) {
        plogf(" %3d ", iphase);
        vcs_VolPhase *VPhase = m_VolPhaseList[iphase];
        plogf("%-12.12s |",VPhase->PhaseName.c_str());
        plogf("%10.3e |", m_tPhaseMoles_old[iphase]*molScale);
        totalMoles +=  m_tPhaseMoles_old[iphase];
        if (m_tPhaseMoles_old[iphase] != VPhase->totalMoles()) {
            if (! vcs_doubleEqual(m_tPhaseMoles_old[iphase], VPhase->totalMoles())) {
                plogf("We have a problem\n");
                exit(EXIT_FAILURE);
            }
        }
        vcs_elabPhase(iphase, VCS_DATA_PTR(gaPhase));
        for (j = 0; j < m_numElemConstraints; j++) {
            plogf(" %10.3g", gaPhase[j]);
            gaTPhase[j] += gaPhase[j];
        }
        gibbsPhase = vcs_GibbsPhase(iphase, VCS_DATA_PTR(m_molNumSpecies_old),
                                    VCS_DATA_PTR(m_feSpecies_old));
        gibbsTotal += gibbsPhase;
        plogf(" | %18.11E |\n", gibbsPhase);
    }
    print_line("-", m_numElemConstraints*10 + 58);
    plogf("    TOTAL         |%10.3e |", totalMoles);
    for (j = 0; j < m_numElemConstraints; j++) {
        plogf(" %10.3g", gaTPhase[j]);
    }
    plogf(" | %18.11E |\n", gibbsTotal);

    print_line("-", m_numElemConstraints*10 + 58);
    plogf("\n");

    /*
     * ----------- GLOBAL SATISFACTION INFORMATION -----------------------
     */

    /*
     *    Calculate the total dimensionless Gibbs Free Energy
     *     -> Inert species are handled as if they had a standard free
     *        energy of zero
     */

    g = vcs_Total_Gibbs(VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_feSpecies_old),
                        VCS_DATA_PTR(m_tPhaseMoles_old));
    plogf("\n\tTotal Dimensionless Gibbs Free Energy = G/RT = %15.7E\n", g);
    if (inertYes)
        plogf("\t\t(Inert species have standard free energy of zero)\n");

    plogf("\nElemental Abundances (kmol): ");
    plogf("         Actual                    Target         Type      ElActive\n");
    for (i = 0; i < m_numElemConstraints; ++i) {
        print_space(26);
        plogf("%-2.2s", (m_elementName[i]).c_str());
        plogf("%20.12E  %20.12E", m_elemAbundances[i]*molScale, m_elemAbundancesGoal[i]*molScale);
        plogf("   %3d     %3d\n", m_elType[i], m_elementActive[i]);
    }
    plogf("\n");

    /*
     * ------------------ TABLE OF SPECIES CHEM POTS ---------------------
     */
    plogf("\n");
    print_line("-", 93);
    plogf("Chemical Potentials of the Species: (dimensionless)\n");

    double rt = vcs_nondimMult_TP(m_VCS_UnitsFormat, m_temperature);
    plogf("\t\t(RT = %g ", rt);
    vcs_printChemPotUnits(m_VCS_UnitsFormat);
    plogf(")\n");
    plogf("    Name        TKMoles     StandStateChemPot   "
          "   ln(AC)       ln(X_i)      |   F z_i phi   |    ChemPot    | (-lnMnaught)");
    plogf("|  (MolNum ChemPot)|");
    plogf("\n");
    print_line("-", 147);
    for (i = 0; i < nspecies; ++i) {
        l = sortindex[i];
        size_t pid = m_phaseID[l];
        plogf(" %-12.12s", m_speciesName[l].c_str());
        plogf(" %14.7E ", m_molNumSpecies_old[l]*molScale);
        plogf("%14.7E  ", m_SSfeSpecies[l]);
        plogf("%14.7E  ", log(m_actCoeffSpecies_old[l]));
        double tpmoles = m_tPhaseMoles_old[pid];
        double phi = m_phasePhi[pid];
        double eContrib = phi * m_chargeSpecies[l] * m_Faraday_dim;
        double lx = 0.0;
        if (m_speciesUnknownType[l] == VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            lx = 0.0;
        } else {
            if (tpmoles > 0.0 && m_molNumSpecies_old[l] > 0.0) {
                double tmp = MAX(VCS_DELETE_MINORSPECIES_CUTOFF, m_molNumSpecies_old[l]);
                lx = log(tmp) - log(tpmoles);
            } else {
                lx = m_feSpecies_old[l] - m_SSfeSpecies[l]
                     - log(m_actCoeffSpecies_old[l]) + m_lnMnaughtSpecies[l];
            }
        }
        plogf("%14.7E  |", lx);
        plogf("%14.7E | ", eContrib);
        double tmp = m_SSfeSpecies[l] + log(m_actCoeffSpecies_old[l])
                     + lx - m_lnMnaughtSpecies[l] + eContrib;
        if (fabs(m_feSpecies_old[l] - tmp) > 1.0E-7) {
            plogf("\n\t\twe have a problem - doesn't add up\n");
            exit(EXIT_FAILURE);
        }
        plogf(" %12.4E |", m_feSpecies_old[l]);
        if( m_lnMnaughtSpecies[l] != 0.0) {
            plogf("(%11.5E)", - m_lnMnaughtSpecies[l]);
        } else {
            plogf("             ");
        }

        plogf("|  %20.9E |", m_feSpecies_old[l] * m_molNumSpecies_old[l] * molScale);
        plogf("\n");
    }
    for (i = 0; i < 125; i++) plogf(" ");
    plogf(" %20.9E\n", g);
    print_line("-", 147);

    /*
     * ------------- TABLE OF SOLUTION COUNTERS --------------------------
     */
    plogf("\n");
    plogf("\nCounters:         Iterations          Time (seconds)\n");
    if (m_timing_print_lvl > 0) {
        plogf("    vcs_basopt:   %5d             %11.5E\n",
              m_VCount->Basis_Opts, m_VCount->Time_basopt);
        plogf("    vcs_TP:       %5d             %11.5E\n",
              m_VCount->Its, m_VCount->Time_vcs_TP);
    } else {
        plogf("    vcs_basopt:   %5d             %11s\n",
              m_VCount->Basis_Opts,"    NA     ");
        plogf("    vcs_TP:       %5d             %11s\n",
              m_VCount->Its,"    NA     " );
    }
    print_line("-", 80);
    print_line("-", 80);

    /*
     *   Set the Units state of the system back to where it was when we
     *   entered the program.
     */
    if (originalUnitsState != m_unitsState) {
        if (originalUnitsState == VCS_DIMENSIONAL_G ) vcs_redim_TP();
        else                                          vcs_nondim_TP();
    }
    /*
     *   Return a successful completion flag
     */
    return VCS_SUCCESS;
} /* vcs_report() ************************************************************/
示例#8
0
void VCS_SOLVE::vcs_inest(double* const aw, double* const sa, double* const sm,
                          double* const ss, double test)
{
    size_t nspecies = m_numSpeciesTot;
    size_t nrxn = m_numRxnTot;

    /*
     *       CALL ROUTINE TO SOLVE MAX(CC*molNum) SUCH THAT AX*molNum = BB
     *           AND molNum(I) .GE. 0.0
     *
     *   Note, both of these programs do this.
     */
    vcs_setMolesLinProg();

    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        plogf("%s Mole Numbers returned from linear programming (vcs_inest initial guess):\n",
              pprefix);
        plogf("%s     SPECIES          MOLE_NUMBER      -SS_ChemPotential\n", pprefix);
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            plogf("%s     ", pprefix);
            plogf("%-12.12s", m_speciesName[kspec].c_str());
            plogf(" %15.5g  %12.3g\n", m_molNumSpecies_old[kspec], -m_SSfeSpecies[kspec]);
        }
        plogf("%s Element Abundance Agreement returned from linear "
              "programming (vcs_inest initial guess):",
              pprefix);
        plogendl();
        plogf("%s     Element           Goal         Actual\n", pprefix);
        for (size_t j = 0; j < m_numElemConstraints; j++) {
            if (m_elementActive[j]) {
                double tmp = 0.0;
                for (size_t kspec = 0; kspec < nspecies; ++kspec) {
                    tmp +=  m_formulaMatrix(kspec,j) * m_molNumSpecies_old[kspec];
                }
                plogf("%s     ", pprefix);
                plogf("   %-9.9s", (m_elementName[j]).c_str());
                plogf(" %12.3g %12.3g\n", m_elemAbundancesGoal[j], tmp);
            }
        }
        plogendl();
    }

    /*
     *     Make sure all species have positive definite mole numbers
     *     Set voltages to zero for now, until we figure out what to do
     */
    m_deltaMolNumSpecies.assign(m_deltaMolNumSpecies.size(), 0.0);
    for (size_t kspec = 0; kspec < nspecies; ++kspec) {
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            if (m_molNumSpecies_old[kspec] <= 0.0) {
                /*
                 * HKM Should eventually include logic here for non SS phases
                 */
                if (!m_SSPhase[kspec]) {
                    m_molNumSpecies_old[kspec] = 1.0e-30;
                }
            }
        } else {
            m_molNumSpecies_old[kspec] = 0.0;
        }
    }

    /*
     *      Now find the optimized basis that spans the stoichiometric
     *      coefficient matrix
     */
    bool conv;
    (void) vcs_basopt(false, aw, sa, sm, ss, test, &conv);

    /* ***************************************************************** */
    /* **** CALCULATE TOTAL MOLES,                    ****************** */
    /* **** CHEMICAL POTENTIALS OF BASIS              ****************** */
    /* ***************************************************************** */
    /*
     * Calculate TMoles and m_tPhaseMoles_old[]
     */
    vcs_tmoles();
    /*
     * m_tPhaseMoles_new[] will consist of just the component moles
     */
    for (size_t iph = 0; iph < m_numPhases; iph++) {
        m_tPhaseMoles_new[iph] = TPhInertMoles[iph] + 1.0E-20;
    }
    for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
        if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
            m_tPhaseMoles_new[m_phaseID[kspec]] += m_molNumSpecies_old[kspec];
        }
    }
    double TMolesMultiphase = 0.0;
    for (size_t iph = 0; iph < m_numPhases; iph++) {
        if (! m_VolPhaseList[iph]->m_singleSpecies) {
            TMolesMultiphase += m_tPhaseMoles_new[iph];
        }
    }
    m_molNumSpecies_new = m_molNumSpecies_old;
    for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_MOLNUM) {
            m_molNumSpecies_new[kspec] = 0.0;
        }
    }
    m_feSpecies_new = m_SSfeSpecies;

    for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
        if (m_speciesUnknownType[kspec] == VCS_SPECIES_TYPE_MOLNUM) {
            if (! m_SSPhase[kspec]) {
                size_t iph = m_phaseID[kspec];
                m_feSpecies_new[kspec] += log(m_molNumSpecies_new[kspec] / m_tPhaseMoles_old[iph]);
            }
        } else {
            m_molNumSpecies_new[kspec] = 0.0;
        }
    }
    vcs_deltag(0, true, VCS_STATECALC_NEW);
    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            plogf("%s", pprefix);
            plogf("%-12.12s", m_speciesName[kspec].c_str());
            if (kspec < m_numComponents)
                plogf("fe* = %15.5g ff = %15.5g\n", m_feSpecies_new[kspec],
                      m_SSfeSpecies[kspec]);
            else
                plogf("fe* = %15.5g ff = %15.5g dg* = %15.5g\n",
                      m_feSpecies_new[kspec], m_SSfeSpecies[kspec], m_deltaGRxn_new[kspec-m_numComponents]);
        }
    }
    /* ********************************************************** */
    /* **** ESTIMATE REACTION ADJUSTMENTS *********************** */
    /* ********************************************************** */
    double* xtphMax = VCS_DATA_PTR(m_TmpPhase);
    double* xtphMin = VCS_DATA_PTR(m_TmpPhase2);
    m_deltaPhaseMoles.assign(m_deltaPhaseMoles.size(), 0.0);
    for (size_t iph = 0; iph < m_numPhases; iph++) {
        xtphMax[iph] = log(m_tPhaseMoles_new[iph] * 1.0E32);
        xtphMin[iph] = log(m_tPhaseMoles_new[iph] * 1.0E-32);
    }
    for (size_t irxn = 0; irxn < nrxn; ++irxn) {
        size_t kspec = m_indexRxnToSpecies[irxn];
        /*
         * For single species phases, we will not estimate the
         * mole numbers. If the phase exists, it stays. If it
         * doesn't exist in the estimate, it doesn't come into
         * existence here.
         */
        if (! m_SSPhase[kspec]) {
            size_t iph = m_phaseID[kspec];
            if (m_deltaGRxn_new[irxn] > xtphMax[iph]) {
                m_deltaGRxn_new[irxn] = 0.8 * xtphMax[iph];
            }
            if (m_deltaGRxn_new[irxn] < xtphMin[iph]) {
                m_deltaGRxn_new[irxn] = 0.8 * xtphMin[iph];
            }
            /*
             *   HKM -> The TMolesMultiphase is a change of mine.
             *          It more evenly distributes the initial moles amongst
             *          multiple multispecies phases according to the
             *          relative values of the standard state free energies.
             *          There is no change for problems with one multispecies
             *          phase.
             *            It cut diamond4.vin iterations down from 62 to 14.
             */
            m_deltaMolNumSpecies[kspec] = 0.5 * (m_tPhaseMoles_new[iph] + TMolesMultiphase)
                                          * exp(-m_deltaGRxn_new[irxn]);

            for (size_t k = 0; k < m_numComponents; ++k) {
                m_deltaMolNumSpecies[k] += m_stoichCoeffRxnMatrix(k,irxn) * m_deltaMolNumSpecies[kspec];
            }

            for (iph = 0; iph < m_numPhases; iph++) {
                m_deltaPhaseMoles[iph] += m_deltaMolNumPhase(iph,irxn) * m_deltaMolNumSpecies[kspec];
            }
        }
    }
    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                plogf("%sdirection (", pprefix);
                plogf("%-12.12s", m_speciesName[kspec].c_str());
                plogf(") = %g", m_deltaMolNumSpecies[kspec]);
                if (m_SSPhase[kspec]) {
                    if (m_molNumSpecies_old[kspec] > 0.0) {
                        plogf(" (ssPhase exists at w = %g moles)", m_molNumSpecies_old[kspec]);
                    } else {
                        plogf(" (ssPhase doesn't exist -> stability not checked)");
                    }
                }
                plogendl();
            }
        }
    }
    /* *********************************************************** */
    /* **** KEEP COMPONENT SPECIES POSITIVE ********************** */
    /* *********************************************************** */
    double par = 0.5;
    for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
        if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            if (par < -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec]) {
                par = -m_deltaMolNumSpecies[kspec] / m_molNumSpecies_new[kspec];
            }
        }
    }
    par = 1. / par;
    if (par <= 1.0 && par > 0.0) {
        par *= 0.8;
    } else {
        par = 1.0;
    }
    /* ******************************************** */
    /* **** CALCULATE NEW MOLE NUMBERS ************ */
    /* ******************************************** */
    size_t lt = 0;
    size_t ikl = 0;
    double s1 = 0.0;
    while (true) {
        for (size_t kspec = 0; kspec < m_numComponents; ++kspec) {
            if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                m_molNumSpecies_old[kspec] = m_molNumSpecies_new[kspec] + par * m_deltaMolNumSpecies[kspec];
            } else {
                m_deltaMolNumSpecies[kspec] = 0.0;
            }
        }
        for (size_t kspec = m_numComponents; kspec < nspecies; ++kspec) {
            if (m_speciesUnknownType[kspec] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                if (m_deltaMolNumSpecies[kspec] != 0.0) {
                    m_molNumSpecies_old[kspec] = m_deltaMolNumSpecies[kspec] * par;
                }
            }
        }
        /*
         * We have a new w[] estimate, go get the
         * TMoles and m_tPhaseMoles_old[] values
         */
        vcs_tmoles();
        if (lt > 0) {
            break;
        }
        /* ******************************************* */
        /* **** CONVERGENCE FORCING SECTION ********** */
        /* ******************************************* */
        vcs_setFlagsVolPhases(false, VCS_STATECALC_OLD);
        vcs_dfe(VCS_STATECALC_OLD, 0, 0, nspecies);
        double s = 0.0;
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            s += m_deltaMolNumSpecies[kspec] * m_feSpecies_old[kspec];
        }
        if (s == 0.0) {
            break;
        }
        if (s < 0.0) {
            if (ikl == 0) {
                break;
            }
        }
        /* ***************************************** */
        /* *** TRY HALF STEP SIZE ****************** */
        /* ***************************************** */
        if (ikl == 0) {
            s1 = s;
            par *= 0.5;
            ikl = 1;
            continue;
        }
        /* **************************************************** */
        /* **** FIT PARABOLA THROUGH HALF AND FULL STEPS ****** */
        /* **************************************************** */
        double xl = (1.0 - s / (s1 - s)) * 0.5;
        if (xl < 0.0) {
            /* *************************************************** */
            /* *** POOR DIRECTION, REDUCE STEP SIZE TO 0.2 ******* */
            /* *************************************************** */
            par *= 0.2;
        } else {
            if (xl > 1.0) {
                /* *************************************************** */
                /* **** TOO BIG A STEP, TAKE ORIGINAL FULL STEP ****** */
                /* *************************************************** */
                par *= 2.0;
            } else {
                /* *************************************************** */
                /* **** ACCEPT RESULTS OF FORCER ********************* */
                /* *************************************************** */
                par = par * 2.0 * xl;
            }
        }
        lt = 1;
    }

    if (DEBUG_MODE_ENABLED && m_debug_print_lvl >= 2) {
        plogf("%s     Final Mole Numbers produced by inest:\n",
              pprefix);
        plogf("%s     SPECIES      MOLE_NUMBER\n", pprefix);
        for (size_t kspec = 0; kspec < nspecies; ++kspec) {
            plogf("%s     ", pprefix);
            plogf("%-12.12s", m_speciesName[kspec].c_str());
            plogf(" %g", m_molNumSpecies_old[kspec]);
            plogendl();
        }
    }
}
示例#9
0
/*
 *   The VCS_PUB structure is  returned to the user.
 *
 *  @param pub  Pointer to VCS_PROB that will get the results of the
 *              equilibrium calculation transfered to it.
 */
int VCS_SOLVE::vcs_prob_update(VCS_PROB* pub)
{
    size_t k1 = 0;

    vcs_tmoles();
    m_totalVol = vcs_VolTotal(m_temperature, m_pressurePA,
                              VCS_DATA_PTR(m_molNumSpecies_old), VCS_DATA_PTR(m_PMVolumeSpecies));

    for (size_t i = 0; i < m_numSpeciesTot; ++i) {
        /*
         *         Find the index of I in the index vector, m_speciesIndexVector[].
         *         Call it K1 and continue.
         */
        for (size_t j = 0; j < m_numSpeciesTot; ++j) {
            k1 = j;
            if (m_speciesMapIndex[j] == i) {
                break;
            }
        }
        /*
         * - Switch the species data back from K1 into I
         */
        if (pub->SpeciesUnknownType[i] != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
            pub->w[i] = m_molNumSpecies_old[k1];
        } else {
            pub->w[i] = 0.0;
            // plogf("voltage species = %g\n", m_molNumSpecies_old[k1]);
        }
        //pub->mf[i] = m_molNumSpecies_new[k1];
        pub->m_gibbsSpecies[i] = m_feSpecies_old[k1];
        pub->VolPM[i] = m_PMVolumeSpecies[k1];
    }

    pub->T    = m_temperature;
    pub->PresPA = m_pressurePA;
    pub->Vol  = m_totalVol;
    size_t kT = 0;
    for (size_t iph = 0; iph < pub->NPhase; iph++) {
        vcs_VolPhase* pubPhase = pub->VPhaseList[iph];
        vcs_VolPhase* vPhase = m_VolPhaseList[iph];
        pubPhase->setTotalMolesInert(vPhase->totalMolesInert());
        pubPhase->setTotalMoles(vPhase->totalMoles());
        pubPhase->setElectricPotential(vPhase->electricPotential());
        double sumMoles = pubPhase->totalMolesInert();
        pubPhase->setMoleFractionsState(vPhase->totalMoles(),
                                        VCS_DATA_PTR(vPhase->moleFractions()),
                                        VCS_STATECALC_TMP);
        const std::vector<double> & mfVector = pubPhase->moleFractions();
        for (size_t k = 0; k < pubPhase->nSpecies(); k++) {
            kT = pubPhase->spGlobalIndexVCS(k);
            pub->mf[kT] = mfVector[k];
            if (pubPhase->phiVarIndex() == k) {
                k1 = vPhase->spGlobalIndexVCS(k);
                double tmp = m_molNumSpecies_old[k1];
                if (! vcs_doubleEqual(pubPhase->electricPotential() , tmp)) {
                    plogf("We have an inconsistency in voltage, %g, %g\n",
                          pubPhase->electricPotential(), tmp);
                    exit(EXIT_FAILURE);
                }
            }

            if (! vcs_doubleEqual(pub->mf[kT], vPhase->molefraction(k))) {
                plogf("We have an inconsistency in mole fraction, %g, %g\n",
                      pub->mf[kT], vPhase->molefraction(k));
                exit(EXIT_FAILURE);
            }
            if (pubPhase->speciesUnknownType(k) != VCS_SPECIES_TYPE_INTERFACIALVOLTAGE) {
                sumMoles +=  pub->w[kT];
            }
        }
        if (! vcs_doubleEqual(sumMoles, vPhase->totalMoles())) {
            plogf("We have an inconsistency in total moles, %g %g\n",
                  sumMoles, pubPhase->totalMoles());
            exit(EXIT_FAILURE);
        }

    }

    pub->m_Iterations            = m_VCount->Its;
    pub->m_NumBasisOptimizations = m_VCount->Basis_Opts;

    return VCS_SUCCESS;
}
示例#10
0
/*
 *  Use the contents of the VCS_PROB to specify the contents of the
 *  private data, VCS_SOLVE.
 *
 *  It's assumed we are solving the same problem.
 *
 *  @param pub  Pointer to VCS_PROdB that will be used to
 *              initialize the current equilibrium problem
 */
int VCS_SOLVE::vcs_prob_specify(const VCS_PROB* pub)
{
    size_t kspec, k, i, j, iph;
    string yo("vcs_prob_specify ERROR: ");
    int retn = VCS_SUCCESS;
    bool status_change = false;

    m_temperature = pub->T;
    m_pressurePA = pub->PresPA;
    m_VCS_UnitsFormat = pub->m_VCS_UnitsFormat;
    m_doEstimateEquil = pub->iest;

    m_totalVol = pub->Vol;

    m_tolmaj = pub->tolmaj;
    m_tolmin = pub->tolmin;
    m_tolmaj2 = 0.01 * m_tolmaj;
    m_tolmin2 = 0.01 * m_tolmin;

    for (kspec = 0; kspec < m_numSpeciesTot; ++kspec) {
        k = m_speciesMapIndex[kspec];
        m_molNumSpecies_old[kspec] = pub->w[k];
        m_molNumSpecies_new[kspec] = pub->mf[k];
        m_feSpecies_old[kspec] = pub->m_gibbsSpecies[k];
    }

    /*
     * Transfer the element abundance goals to the solve object
     */
    for (i = 0; i < m_numElemConstraints; i++) {
        j = m_elementMapIndex[i];
        m_elemAbundancesGoal[i] = pub->gai[j];
    }

    /*
     *  Try to do the best job at guessing at the title
     */
    if (pub->Title.size() == 0) {
        if (m_title.size() == 0) {
            m_title = "Unspecified Problem Title";
        }
    } else {
        m_title = pub->Title;
    }

    /*
     *   Copy over the phase information.
     *      -> For each entry in the phase structure, determine
     *         if that entry can change from its initial value
     *         Either copy over the new value or create an error
     *         condition.
     */

    for (iph = 0; iph < m_numPhases; iph++) {
        vcs_VolPhase* vPhase = m_VolPhaseList[iph];
        vcs_VolPhase* pub_phase_ptr = pub->VPhaseList[iph];

        if (vPhase->VP_ID_ != pub_phase_ptr->VP_ID_) {
            plogf("%sPhase numbers have changed:%d %d\n", yo.c_str(),
                  vPhase->VP_ID_, pub_phase_ptr->VP_ID_);
            retn = VCS_PUB_BAD;
        }

        if (vPhase->m_singleSpecies != pub_phase_ptr->m_singleSpecies) {
            plogf("%sSingleSpecies value have changed:%d %d\n", yo.c_str(),
                  vPhase->m_singleSpecies,
                  pub_phase_ptr->m_singleSpecies);
            retn = VCS_PUB_BAD;
        }

        if (vPhase->m_gasPhase != pub_phase_ptr->m_gasPhase) {
            plogf("%sGasPhase value have changed:%d %d\n", yo.c_str(),
                  vPhase->m_gasPhase,
                  pub_phase_ptr->m_gasPhase);
            retn = VCS_PUB_BAD;
        }

        vPhase->m_eqnState = pub_phase_ptr->m_eqnState;

        if (vPhase->nSpecies() != pub_phase_ptr->nSpecies()) {
            plogf("%sNVolSpecies value have changed:%d %d\n", yo.c_str(),
                  vPhase->nSpecies(),
                  pub_phase_ptr->nSpecies());
            retn = VCS_PUB_BAD;
        }

        if (vPhase->PhaseName != pub_phase_ptr->PhaseName) {
            plogf("%sPhaseName value have changed:%s %s\n", yo.c_str(),
                  vPhase->PhaseName.c_str(),
                  pub_phase_ptr->PhaseName.c_str());
            retn = VCS_PUB_BAD;
        }

        if (vPhase->totalMolesInert() != pub_phase_ptr->totalMolesInert()) {
            status_change = true;
        }
        /*
         * Copy over the number of inert moles if it has changed.
         */
        TPhInertMoles[iph] = pub_phase_ptr->totalMolesInert();
        vPhase->setTotalMolesInert(pub_phase_ptr->totalMolesInert());
        if (TPhInertMoles[iph] > 0.0) {
            vPhase->setExistence(2);
            vPhase->m_singleSpecies = false;
        }

        /*
         * Copy over the interfacial potential
         */
        double phi = pub_phase_ptr->electricPotential();
        vPhase->setElectricPotential(phi);
    }


    if (status_change) {
        vcs_SSPhase();
    }
    /*
     *   Calculate the total number of moles in all phases.
     */
    vcs_tmoles();

    return retn;
}