19vcs_VolPhase::vcs_VolPhase(VCS_SOLVE* owningSolverObject,
20 ThermoPhase* thermoPhase,
size_t phaseNum)
21 : m_owningSolverObject(owningSolverObject)
23 if (!m_owningSolverObject) {
24 throw CanteraError(
"vcs_VolPhase::vcs_VolPhase",
25 "owningSolverObject must not be null");
28 throw CanteraError(
"vcs_VolPhase::vcs_VolPhase",
29 "thermoPhase must not be null");
33 PhaseName = thermoPhase->name().empty() ?
34 fmt::format(
"Phase_{}", VP_ID_) : thermoPhase->name();
36 m_numSpecies = thermoPhase->nSpecies();
39 m_singleSpecies = (m_numSpecies == 1);
42 p_activityConvention = thermoPhase->activityConvention();
44 IndSpecies.assign(m_numSpecies, npos);
45 Xmol_.assign(m_numSpecies, 0.0);
46 creationMoleNumbers_.assign(m_numSpecies, 0.0);
47 creationGlobalRxnNumbers_.assign(m_numSpecies, npos);
48 for (
size_t k = 0; k < m_numSpecies; k++) {
49 double defaultFrac = 1.0 / m_numSpecies;
50 Xmol_[k] = defaultFrac;
51 creationMoleNumbers_[k] = defaultFrac;
54 SS0ChemicalPotential.assign(m_numSpecies, -1.0);
55 StarChemicalPotential.assign(m_numSpecies, -1.0);
56 StarMolarVol.assign(m_numSpecies, -1.0);
57 PartialMolarVol.assign(m_numSpecies, -1.0);
58 ActCoeff.assign(m_numSpecies, 1.0);
59 np_dLnActCoeffdMolNumber.resize(m_numSpecies, m_numSpecies, 0.0);
64 m_UpToDate_AC =
false;
65 m_UpToDate_VolStar =
false;
66 m_UpToDate_VolPM =
false;
67 m_UpToDate_GStar =
false;
68 m_UpToDate_G0 =
false;
71 Temp_ = TP_ptr->temperature();
72 Pres_ = TP_ptr->pressure();
73 m_phi = TP_ptr->electricPotential();
75 transferElementsFM(TP_ptr);
79 size_t neVP = nElemConstraints();
80 for (
size_t eVP = 0; eVP < neVP; eVP++) {
81 string enVP = elementName(eVP);
82 size_t foundPos = m_owningSolverObject->elementIndex(enVP);
83 if (foundPos == npos) {
84 int elType = elementType(eVP);
85 int elactive = elementActive(eVP);
86 foundPos = m_owningSolverObject->addElement(enVP.c_str(), elType, elactive);
88 setElemGlobalIndex(eVP, foundPos);
91 setState_TP(Temp_, Pres_);
92 TP_ptr->getMoleFractions(&Xmol_[0]);
93 creationMoleNumbers_ = Xmol_;
94 _updateMoleFractionDependencies();
96 m_isIdealSoln = m_singleSpecies ? true : TP_ptr->isIdeal();
99void vcs_VolPhase::elemResize(
const size_t numElemConstraints)
101 m_elementNames.resize(numElemConstraints);
102 m_elementActive.resize(numElemConstraints+1, 1);
104 m_formulaMatrix.resize(m_numSpecies, numElemConstraints, 0.0);
105 m_elementNames.resize(numElemConstraints,
"");
106 m_elemGlobalIndex.resize(numElemConstraints, npos);
107 m_numElemConstraints = numElemConstraints;
110void vcs_VolPhase::_updateActCoeff()
const
113 m_UpToDate_AC =
true;
116 TP_ptr->getActivityCoefficients(&ActCoeff[0]);
117 m_UpToDate_AC =
true;
120void vcs_VolPhase::_updateG0()
const
122 TP_ptr->getGibbs_ref(&SS0ChemicalPotential[0]);
123 m_UpToDate_G0 =
true;
126double vcs_VolPhase::G0_calc_one(
size_t kspec)
const
128 if (!m_UpToDate_G0) {
131 return SS0ChemicalPotential[kspec];
134void vcs_VolPhase::_updateGStar()
const
136 TP_ptr->getStandardChemPotentials(&StarChemicalPotential[0]);
137 m_UpToDate_GStar =
true;
140double vcs_VolPhase::GStar_calc_one(
size_t kspec)
const
142 if (!m_UpToDate_GStar) {
145 return StarChemicalPotential[kspec];
148void vcs_VolPhase::setMoleFractions(
const double*
const xmol)
151 for (
size_t k = 0; k < m_numSpecies; k++) {
155 if (std::fabs(sum) > 1.0E-13) {
156 for (
size_t k = 0; k < m_numSpecies; k++) {
160 _updateMoleFractionDependencies();
165void vcs_VolPhase::_updateMoleFractionDependencies()
168 TP_ptr->setMoleFractions(&Xmol_[m_MFStartIndex]);
169 TP_ptr->setPressure(Pres_);
171 if (!m_isIdealSoln) {
172 m_UpToDate_AC =
false;
173 m_UpToDate_VolPM =
false;
177const vector<double> & vcs_VolPhase::moleFractions()
const
182double vcs_VolPhase::moleFraction(
size_t k)
const
187void vcs_VolPhase::setMoleFractionsState(
const double totalMoles,
188 const double*
const moleFractions,
189 const int vcsStateStatus)
191 if (totalMoles != 0.0) {
195 throw CanteraError(
"vcs_VolPhase::setMolesFractionsState",
196 "inappropriate usage");
201 throw CanteraError(
"vcs_VolPhase::setMolesFractionsState",
202 "inappropriate usage");
207 m_vcsStateStatus = vcsStateStatus;
210 double fractotal = 1.0;
211 v_totalMoles = totalMoles;
213 for (
size_t k = 0; k < m_numSpecies; k++) {
214 Xmol_[k] = moleFractions[k];
215 sum += moleFractions[k];
218 throw CanteraError(
"vcs_VolPhase::setMolesFractionsState",
219 "inappropriate usage");
221 if (sum != fractotal) {
222 for (
size_t k = 0; k < m_numSpecies; k++) {
223 Xmol_[k] *= (fractotal /sum);
226 _updateMoleFractionDependencies();
229void vcs_VolPhase::setMolesFromVCS(
const int stateCalc,
230 const double* molesSpeciesVCS)
234 if (molesSpeciesVCS == 0) {
236 molesSpeciesVCS = &m_owningSolverObject->m_molNumSpecies_old[0];
238 molesSpeciesVCS = &m_owningSolverObject->m_molNumSpecies_new[0];
240 throw CanteraError(
"vcs_VolPhase::setMolesFromVCS",
"shouldn't be here");
244 for (
size_t k = 0; k < m_numSpecies; k++) {
246 size_t kglob = IndSpecies[k];
247 v_totalMoles += std::max(0.0, molesSpeciesVCS[kglob]);
250 if (v_totalMoles > 0.0) {
251 for (
size_t k = 0; k < m_numSpecies; k++) {
253 size_t kglob = IndSpecies[k];
254 double tmp = std::max(0.0, molesSpeciesVCS[kglob]);
255 Xmol_[k] = tmp / v_totalMoles;
268 if (m_phiVarIndex !=
npos) {
269 size_t kglob = IndSpecies[m_phiVarIndex];
270 if (m_numSpecies == 1) {
271 Xmol_[m_phiVarIndex] = 1.0;
273 Xmol_[m_phiVarIndex] = 0.0;
275 double phi = molesSpeciesVCS[kglob];
276 setElectricPotential(phi);
277 if (m_numSpecies == 1) {
281 _updateMoleFractionDependencies();
287 creationMoleNumbers_ = Xmol_;
292 m_vcsStateStatus = stateCalc;
295void vcs_VolPhase::setMolesFromVCSCheck(
const int vcsStateStatus,
296 const double* molesSpeciesVCS,
297 const double*
const TPhMoles)
299 setMolesFromVCS(vcsStateStatus, molesSpeciesVCS);
302 double Tcheck = TPhMoles[VP_ID_];
303 if (Tcheck != v_totalMoles) {
305 Tcheck = v_totalMoles;
307 throw CanteraError(
"vcs_VolPhase::setMolesFromVCSCheck",
308 "We have a consistency problem: {} {}", Tcheck, v_totalMoles);
313void vcs_VolPhase::updateFromVCS_MoleNumbers(
const int vcsStateStatus)
315 if ((!m_UpToDate || vcsStateStatus != m_vcsStateStatus) &&
317 setMolesFromVCS(vcsStateStatus);
321void vcs_VolPhase::sendToVCS_ActCoeff(
const int vcsStateStatus,
324 updateFromVCS_MoleNumbers(vcsStateStatus);
325 if (!m_UpToDate_AC) {
328 for (
size_t k = 0; k < m_numSpecies; k++) {
329 size_t kglob = IndSpecies[k];
330 AC[kglob] = ActCoeff[k];
334double vcs_VolPhase::sendToVCS_VolPM(
double*
const VolPM)
const
336 if (!m_UpToDate_VolPM) {
339 for (
size_t k = 0; k < m_numSpecies; k++) {
340 size_t kglob = IndSpecies[k];
341 VolPM[kglob] = PartialMolarVol[k];
346void vcs_VolPhase::sendToVCS_GStar(
double*
const gstar)
const
348 if (!m_UpToDate_GStar) {
351 for (
size_t k = 0; k < m_numSpecies; k++) {
352 size_t kglob = IndSpecies[k];
353 gstar[kglob] = StarChemicalPotential[k];
357void vcs_VolPhase::setElectricPotential(
const double phi)
360 TP_ptr->setElectricPotential(m_phi);
362 m_UpToDate_AC =
false;
363 m_UpToDate_VolStar =
false;
364 m_UpToDate_VolPM =
false;
365 m_UpToDate_GStar =
false;
368double vcs_VolPhase::electricPotential()
const
373void vcs_VolPhase::setState_TP(
const double temp,
const double pres)
375 if (Temp_ == temp && Pres_ == pres) {
378 TP_ptr->setElectricPotential(m_phi);
379 TP_ptr->setState_TP(temp, pres);
382 m_UpToDate_AC =
false;
383 m_UpToDate_VolStar =
false;
384 m_UpToDate_VolPM =
false;
385 m_UpToDate_GStar =
false;
386 m_UpToDate_G0 =
false;
389void vcs_VolPhase::_updateVolStar()
const
391 TP_ptr->getStandardVolumes(&StarMolarVol[0]);
392 m_UpToDate_VolStar =
true;
395double vcs_VolPhase::_updateVolPM()
const
397 TP_ptr->getPartialMolarVolumes(&PartialMolarVol[0]);
399 for (
size_t k = 0; k < m_numSpecies; k++) {
400 m_totalVol += PartialMolarVol[k] * Xmol_[k];
402 m_totalVol *= v_totalMoles;
403 m_UpToDate_VolPM =
true;
407void vcs_VolPhase::_updateLnActCoeffJac()
409 double phaseTotalMoles = v_totalMoles;
410 if (phaseTotalMoles < 1.0E-14) {
411 phaseTotalMoles = 1.0;
415 if (!m_UpToDate_AC) {
421 TP_ptr->getdlnActCoeffdlnN(m_numSpecies, &np_dLnActCoeffdMolNumber(0,0));
422 for (
size_t j = 0; j < m_numSpecies; j++) {
423 double moles_j_base = phaseTotalMoles * Xmol_[j];
424 double*
const np_lnActCoeffCol = np_dLnActCoeffdMolNumber.ptrColumn(j);
425 if (moles_j_base < 1.0E-200) {
426 moles_j_base = 1.0E-7 * moles_j_base + 1.0E-13 * phaseTotalMoles + 1.0E-150;
428 for (
size_t k = 0; k < m_numSpecies; k++) {
429 np_lnActCoeffCol[k] = np_lnActCoeffCol[k] * phaseTotalMoles / moles_j_base;
433 double deltaMoles_j = 0.0;
435 vector<double> ActCoeff_Base(ActCoeff);
436 vector<double> Xmol_Base(Xmol_);
437 double TMoles_base = phaseTotalMoles;
440 for (
size_t j = 0; j < m_numSpecies; j++) {
443 double moles_j_base = phaseTotalMoles * Xmol_Base[j];
444 deltaMoles_j = 1.0E-7 * moles_j_base + 1.0E-13 * phaseTotalMoles + 1.0E-150;
448 phaseTotalMoles = TMoles_base + deltaMoles_j;
449 for (
size_t k = 0; k < m_numSpecies; k++) {
450 Xmol_[k] = Xmol_Base[k] * TMoles_base / phaseTotalMoles;
452 Xmol_[j] = (moles_j_base + deltaMoles_j) / phaseTotalMoles;
456 _updateMoleFractionDependencies();
460 v_totalMoles = TMoles_base;
467 setMoleFractions(&Xmol_Base[0]);
468 _updateMoleFractionDependencies();
472void vcs_VolPhase::sendToVCS_LnActCoeffJac(
Array2D& np_LnACJac_VCS)
476 _updateLnActCoeffJac();
479 for (
size_t j = 0; j < m_numSpecies; j++) {
480 size_t jglob = IndSpecies[j];
481 for (
size_t k = 0; k < m_numSpecies; k++) {
482 size_t kglob = IndSpecies[k];
483 np_LnACJac_VCS(kglob,jglob) = np_dLnActCoeffdMolNumber(k,j);
488double vcs_VolPhase::totalMoles()
const
493double vcs_VolPhase::molefraction(
size_t k)
const
498void vcs_VolPhase::setCreationMoleNumbers(
const double*
const n_k,
499 const vector<size_t> &creationGlobalRxnNumbers)
501 creationMoleNumbers_.assign(n_k, n_k+m_numSpecies);
502 for (
size_t k = 0; k < m_numSpecies; k++) {
503 creationGlobalRxnNumbers_[k] = creationGlobalRxnNumbers[k];
507const vector<double>& vcs_VolPhase::creationMoleNumbers(
508 vector<size_t> &creationGlobalRxnNumbers)
const
510 creationGlobalRxnNumbers = creationGlobalRxnNumbers_;
511 return creationMoleNumbers_;
514void vcs_VolPhase::setTotalMoles(
const double totalMols)
516 v_totalMoles = totalMols;
517 if (m_singleSpecies && (m_phiVarIndex == 0)) {
520 if (totalMols > 0.0) {
528void vcs_VolPhase::setMolesOutOfDate(
int stateCalc)
531 if (stateCalc != -1) {
532 m_vcsStateStatus = stateCalc;
536void vcs_VolPhase::setMolesCurrent(
int stateCalc)
539 m_vcsStateStatus = stateCalc;
542bool vcs_VolPhase::isIdealSoln()
const
544 return m_isIdealSoln;
547size_t vcs_VolPhase::phiVarIndex()
const
549 return m_phiVarIndex;
552void vcs_VolPhase::setPhiVarIndex(
size_t phiVarIndex)
554 m_phiVarIndex = phiVarIndex;
556 if (m_singleSpecies && m_phiVarIndex == 0) {
561int vcs_VolPhase::exists()
const
566void vcs_VolPhase::setExistence(
const int existence)
569 if (v_totalMoles != 0.0) {
571 "setting false existence for phase with moles");
573 }
else if (v_totalMoles == 0.0 && (!m_singleSpecies || m_phiVarIndex != 0)) {
575 "setting true existence for phase with no moles");
579 "Trying to set existence of an electron phase to false");
581 m_existence = existence;
584size_t vcs_VolPhase::spGlobalIndexVCS(
const size_t spIndex)
const
586 return IndSpecies[spIndex];
589void vcs_VolPhase::setSpGlobalIndexVCS(
const size_t spIndex,
590 const size_t spGlobalIndex)
592 IndSpecies[spIndex] = spGlobalIndex;
593 if (spGlobalIndex >= m_numElemConstraints) {
594 creationGlobalRxnNumbers_[spIndex] = spGlobalIndex - m_numElemConstraints;
598size_t vcs_VolPhase::elemGlobalIndex(
const size_t e)
const
600 AssertThrow(e < m_numElemConstraints,
" vcs_VolPhase::elemGlobalIndex");
601 return m_elemGlobalIndex[e];
604void vcs_VolPhase::setElemGlobalIndex(
const size_t eLocal,
const size_t eGlobal)
607 "vcs_VolPhase::setElemGlobalIndex");
608 m_elemGlobalIndex[eLocal] = eGlobal;
611size_t vcs_VolPhase::nElemConstraints()
const
613 return m_numElemConstraints;
616string vcs_VolPhase::elementName(
size_t e)
const
619 if (e < m_elementNames.size()) {
620 return m_elementNames[e];
622 throw IndexError(
"vcs_VolPhase::elementName",
"element", e, m_elementNames.size());
628 for (
size_t k = 0; k < tPhase->
nSpecies(); k++) {
629 if (tPhase->
charge(k) != 0.0) {
649size_t vcs_VolPhase::transferElementsFM(
const ThermoPhase*
const tPhase)
659 ChargeNeutralityElement = ne;
666 if (ChargeNeutralityElement !=
npos) {
670 size_t eFound =
npos;
679 for (
size_t eT = 0; eT < nebase; eT++) {
682 m_elementActive[eT] = 0;
687 for (
size_t eT = 0; eT < nebase; eT++) {
694 if (eFound ==
npos) {
697 m_elementActive[ne] = 0;
699 m_elementNames[ne] = ename;
705 m_formulaMatrix.resize(ns, ne, 0.0);
710 for (
size_t eT = 0; eT < nebase; eT++) {
717 string pname = tPhase->
name();
719 pname = fmt::format(
"phase{}", VP_ID_);
721 e = ChargeNeutralityElement;
722 m_elementNames[e] =
"cn_" + pname;
725 for (
size_t k = 0; k < ns; k++) {
727 for (
size_t eT = 0; eT < nebase; eT++) {
728 m_formulaMatrix(k,e) = tPhase->
nAtoms(k, eT);
731 if (eFound !=
npos) {
732 m_formulaMatrix(k,eFound) = - tPhase->
charge(k);
737 for (
size_t k = 0; k < ns; k++) {
738 m_formulaMatrix(k,ChargeNeutralityElement) = tPhase->
charge(k);
745 if (ns == 1 && tPhase->
charge(0) != 0.0) {
753int vcs_VolPhase::elementType(
const size_t e)
const
755 return m_elementType[e];
758const Array2D& vcs_VolPhase::getFormulaMatrix()
const
760 return m_formulaMatrix;
763int vcs_VolPhase::speciesUnknownType(
const size_t k)
const
765 return m_speciesUnknownType[k];
768int vcs_VolPhase::elementActive(
const size_t e)
const
770 return m_elementActive[e];
773size_t vcs_VolPhase::nSpecies()
const
778string vcs_VolPhase::eos_name()
const
780 return TP_ptr->type();
Header file for class ThermoPhase, the base class for phases with thermodynamic properties,...
A class for 2D arrays stored in column-major (Fortran-compatible) form.
Base class for exceptions thrown by Cantera classes.
An array index is out of range.
size_t nSpecies() const
Returns the number of species in the phase.
int elementType(size_t m) const
Return the element constraint type Possible types include:
double nAtoms(size_t k, size_t m) const
Number of atoms of element m in species k.
size_t nElements() const
Number of elements.
string elementName(size_t m) const
Name of the element with index m.
double charge(size_t k) const
Dimensionless electrical charge of a single molecule of species k The charge is normalized by the the...
string name() const
Return the name of the phase.
Base class for a phase with thermodynamic properties.
bool chargeNeutralityNecessary() const
Returns the chargeNeutralityNecessity boolean.
#define AssertThrow(expr, procedure)
Assertion must be true or an error is thrown.
#define AssertThrowMsg(expr, procedure,...)
Assertion must be true or an error is thrown.
Namespace for the Cantera kernel.
const size_t npos
index returned by functions to indicate "no position"
static bool chargeNeutralityElement(const ThermoPhase *const tPhase)
This utility routine decides whether a Cantera ThermoPhase needs a constraint equation representing t...
static bool hasChargedSpecies(const ThermoPhase *const tPhase)
This function decides whether a phase has charged species or not.
bool vcs_doubleEqual(double d1, double d2)
Simple routine to check whether two doubles are equal up to roundoff error.
Contains declarations for string manipulation functions within Cantera.
Header for the object representing each phase within vcs.
#define VCS_SPECIES_TYPE_INTERFACIALVOLTAGE
Unknown refers to the voltage level of a phase.
#define VCS_STATECALC_OLD
State Calculation based on the old or base mole numbers.
#define VCS_STATECALC_TMP
State Calculation based on a temporary set of mole numbers.
#define VCS_PHASE_EXIST_NO
Phase doesn't currently exist in the mixture.
#define VCS_PHASE_EXIST_ALWAYS
These defines are valid values for the phase existence flag.
#define VCS_ELEM_TYPE_ABSPOS
Normal element constraint consisting of positive coefficients for the formula matrix.
#define VCS_STATECALC_NEW
State Calculation based on the new or tentative mole numbers.
#define VCS_SPECIES_TYPE_MOLNUM
Unknown refers to mole number of a single species.
#define VCS_ELEM_TYPE_ELECTRONCHARGE
This refers to conservation of electrons.
#define VCS_ELEM_TYPE_CHARGENEUTRALITY
This refers to a charge neutrality of a single phase.
#define VCS_PHASE_EXIST_YES
Phase is a normal phase that currently exists.
#define VCS_PHASE_EXIST_ZEROEDPHASE
Phase currently is zeroed due to a programmatic issue.
Header file for the internal object that holds the vcs equilibrium problem (see Class VCS_SOLVE and C...