//! This utility routine decides whether a Cantera ThermoPhase needs //! a constraint equation representing the charge neutrality of the //! phase. It does this by searching for charged species. If it //! finds one, and if the phase needs one, then it returns true. static bool chargeNeutralityElement(const ThermoPhase* const tPhase) { int hasCharge = hasChargedSpecies(tPhase); if (tPhase->chargeNeutralityNecessary() && hasCharge) { return true; } return false; }
size_t vcs_VolPhase::transferElementsFM(const ThermoPhase* const tPhase) { size_t nebase = tPhase->nElements(); size_t ne = nebase; size_t ns = tPhase->nSpecies(); /* * Decide whether we need an extra element constraint for charge * neutrality of the phase */ bool cne = chargeNeutralityElement(tPhase); if (cne) { ChargeNeutralityElement = ne; ne++; } /* * Assign and malloc structures */ elemResize(ne); if (ChargeNeutralityElement != npos) { m_elementType[ChargeNeutralityElement] = VCS_ELEM_TYPE_CHARGENEUTRALITY; } size_t eFound = npos; if (hasChargedSpecies(tPhase)) { if (cne) { /* * We need a charge neutrality constraint. * We also have an Electron Element. These are * duplicates of each other. To avoid trouble with * possible range error conflicts, sometimes we eliminate * the Electron condition. Flag that condition for elimination * by toggling the ElActive variable. If we find we need it * later, we will retoggle ElActive to true. */ for (size_t eT = 0; eT < nebase; eT++) { if (tPhase->elementName(eT) == "E") { eFound = eT; m_elementActive[eT] = 0; m_elementType[eT] = VCS_ELEM_TYPE_ELECTRONCHARGE; } } } else { for (size_t eT = 0; eT < nebase; eT++) { if (tPhase->elementName(eT) == "E") { eFound = eT; m_elementType[eT] = VCS_ELEM_TYPE_ELECTRONCHARGE; } } } if (eFound == npos) { eFound = ne; m_elementType[ne] = VCS_ELEM_TYPE_ELECTRONCHARGE; m_elementActive[ne] = 0; std::string ename = "E"; m_elementNames[ne] = ename; ne++; elemResize(ne); } } m_formulaMatrix.resize(ns, ne, 0.0); m_speciesUnknownType.resize(ns, VCS_SPECIES_TYPE_MOLNUM); elemResize(ne); size_t e = 0; for (size_t eT = 0; eT < nebase; eT++) { m_elementNames[e] = tPhase->elementName(eT); m_elementType[e] = tPhase->elementType(eT); e++; } if (cne) { std::string pname = tPhase->id(); if (pname == "") { std::stringstream sss; sss << "phase" << VP_ID_; pname = sss.str(); } e = ChargeNeutralityElement; m_elementNames[e] = "cn_" + pname; } for (size_t k = 0; k < ns; k++) { e = 0; for (size_t eT = 0; eT < nebase; eT++) { m_formulaMatrix(k,e) = tPhase->nAtoms(k, eT); e++; } if (eFound != npos) { m_formulaMatrix(k,eFound) = - tPhase->charge(k); } } if (cne) { for (size_t k = 0; k < ns; k++) { m_formulaMatrix(k,ChargeNeutralityElement) = tPhase->charge(k); } } /* * Here, we figure out what is the species types are * The logic isn't set in stone, and is just for a particular type * of problem that I'm solving first. */ if (ns == 1) { if (tPhase->charge(0) != 0.0) { m_speciesUnknownType[0] = VCS_SPECIES_TYPE_INTERFACIALVOLTAGE; setPhiVarIndex(0); } } return ne; }