17 #if defined(WITH_HTML_LOGS)
27 static string coeffString(
bool first, doublereal nu,
string sym)
36 if (nu == 1.0 || nu == -1.0) {
39 string s =
fp2str(fabs(nu));
40 return strt + s +
" " + sym;
44 MultiPhaseEquil::MultiPhaseEquil(
MultiPhase* mix,
bool start,
int loglevel) : m_mix(mix)
61 m_incl_species.resize(m_nsp_mix,1);
62 m_incl_element.resize(m_nel_mix,1);
63 for (m = 0; m < m_nel_mix; m++) {
68 if (enm ==
"E" || enm ==
"e") {
78 m_incl_element[m] = 0;
79 for (k = 0; k < m_nsp_mix; k++) {
80 if (m_mix->
nAtoms(k,m) != 0.0) {
81 m_incl_species[k] = 0;
90 if (m_eloc < m_nel_mix) {
91 m_element.push_back(m_eloc);
95 for (m = 0; m < m_nel_mix; m++) {
96 if (m_incl_element[m] == 1 && m != m_eloc) {
98 m_element.push_back(m);
114 for (k = 0; k < m_nsp_mix; k++) {
118 m_incl_species[k] = 0;
122 +
" is excluded since its thermo properties are \n"
123 "not valid at this temperature, but it has "
124 "non-zero moles in the initial state.");
131 for (k = 0; k < m_nsp_mix; k++) {
132 if (m_incl_species[k] ==1) {
134 m_species.push_back(k);
139 m_work.resize(m_nsp);
140 m_work2.resize(m_nsp);
141 m_work3.resize(m_nsp_mix);
142 m_mu.resize(m_nsp_mix);
145 m_moles.resize(m_nsp);
146 m_lastmoles.resize(m_nsp);
147 m_dxi.resize(
nFree());
151 for (ik = 0; ik < m_nsp; ik++) {
156 m_deltaG_RT.resize(
nFree(), 0.0);
158 m_majorsp.resize(m_nsp);
159 m_sortindex.resize(m_nsp,0);
160 m_lastsort.resize(m_nel);
161 m_solnrxn.resize(
nFree());
162 m_A.
resize(m_nel, m_nsp, 0.0);
164 m_order.resize(std::max(m_nsp, m_nel), 0);
165 for (k = 0; k < m_nsp; k++) {
186 for (k = 0; k < m_nsp; k++) {
187 m_moles[k] += m_work[k];
188 m_lastmoles[k] = m_moles[k];
190 m_dsoln.push_back(1);
192 m_dsoln.push_back(0);
204 doublereal MultiPhaseEquil::equilibrate(
int XY, doublereal err,
205 int maxsteps,
int loglevel)
214 for (i = 0; i < maxsteps; i++) {
216 iterstr =
"iteration "+
int2str(i);
234 throw CanteraError(
"MultiPhaseEquil::equilibrate",
235 "no convergence in " +
int2str(maxsteps) +
236 " iterations. Error = " +
fp2str(error()));
248 void MultiPhaseEquil::updateMixMoles()
250 fill(m_work3.begin(), m_work3.end(), 0.0);
252 for (k = 0; k < m_nsp; k++) {
253 m_work3[m_species[k]] = m_moles[k];
260 fill(m_work3.begin(), m_work3.end(), 0.0);
262 for (k = 0; k < m_nsp; k++) {
263 m_work3[m_species[k]] = (m_moles[k] > 0.0 ? m_moles[k] : 0.0);
272 double not_mu = 1.0e12;
282 double delta_xi, dxi_min = 1.0e10;
301 for (j = 0; j <
nFree(); j++) {
304 for (ik = 0; ik < m_nsp; ik++) {
305 dg_rt += mu(ik) * m_N(ik,j);
309 idir = (dg_rt < 0.0 ? 1 : -1);
311 for (ik = 0; ik < m_nsp; ik++) {
320 delta_xi = fabs(0.99*moles(ik)/nu);
323 if (!redo && delta_xi < 1.0e-10 && ik < m_nel) {
325 addLogEntry(
"component too small",speciesName(ik));
329 if (delta_xi < dxi_min) {
335 for (ik = 0; ik < m_nsp; ik++) {
336 moles(ik) += m_N(ik, j) * idir*dxi_min;
342 for (ik = 0; ik < m_nsp; ik++)
343 if (moles(ik) != 0.0) {
358 if (order.size() != m_nsp) {
359 for (k = 0; k < m_nsp; k++) {
363 for (k = 0; k < m_nsp; k++) {
364 m_order[k] = order[k];
368 size_t nRows = m_nel;
369 size_t nColumns = m_nsp;
373 for (m = 0; m < nRows; m++) {
374 for (k = 0; k < nColumns; k++) {
375 m_A(m, k) = m_mix->
nAtoms(m_species[m_order[k]], m_element[m]);
380 for (m = 0; m < nRows; m++) {
382 bool isZeroRow =
true;
383 for (k = m; k < nColumns; k++) {
384 if (fabs(m_A(m,k)) > sqrt(
Tiny)) {
391 size_t n = nRows - 1;
392 bool foundSwapCandidate =
false;
394 for (k = m; k < nColumns; k++) {
395 if (fabs(m_A(n,k)) > sqrt(
Tiny)) {
396 foundSwapCandidate =
true;
400 if (foundSwapCandidate) {
406 for (k = 0; k < nColumns; k++) {
407 std::swap(m_A(n,k), m_A(m,k));
419 if (m < nColumns && m_A(m,m) == 0.0) {
427 doublereal maxmoles = -999.0;
429 for (k = m+1; k < nColumns; k++) {
430 if (m_A(m,k) != 0.0) {
431 if (fabs(m_moles[m_order[k]]) > maxmoles) {
433 maxmoles = fabs(m_moles[m_order[k]]);
440 for (
size_t n = 0; n < nRows; n++) {
441 std::swap(m_A(n, m), m_A(n, kmax));
445 std::swap(m_order[m], m_order[kmax]);
450 for (k = 0; k < nColumns; k++) {
456 for (
size_t n = m+1; n < m_nel; n++) {
457 fctr = m_A(n,m)/m_A(m,m);
458 for (k = 0; k < m_nsp; k++) {
459 m_A(n,k) -= m_A(m,k)*fctr;
466 for (m = std::min(nRows,nColumns)-1; m > 0; m--) {
467 for (
size_t n = m-1; n !=
npos; n--) {
468 if (m_A(n,m) != 0.0) {
470 for (k = m; k < m_nsp; k++) {
471 m_A(n,k) -= fctr*m_A(m,k);
478 for (
size_t n = 0; n < m_nsp; n++) {
480 for (k = 0; k <
nFree(); k++) {
481 m_N(n, k) = -m_A(n, k + m_nel);
484 for (k = 0; k <
nFree(); k++) {
487 m_N(n, n - m_nel) = 1.0;
492 for (j = 0; j <
nFree(); j++) {
493 m_solnrxn[j] =
false;
494 for (k = 0; k < m_nsp; k++) {
505 copy(x.begin(), x.end(), m_work2.begin());
507 for (k = 0; k < m_nsp; k++) {
508 x[m_order[k]] = m_work2[k];
512 #if defined(WITH_HTML_LOGS)
513 void MultiPhaseEquil::printInfo(
int loglevel)
520 for (m = 0; m < m_nel; m++) {
531 for (m = m_nel; m < m_nsp; m++) {
543 for (k = 0; k <
nFree(); k++) {
556 string sr =
"", sp =
"";
561 for (i = 0; i < m_nsp; i++) {
563 k = m_species[m_order[i]];
573 return sr +
" <=> " + sp;
577 void MultiPhaseEquil::step(doublereal omega,
vector_fp& deltaN,
585 throw CanteraError(
"step",
"negative omega");
588 for (ik = 0; ik < m_nel; ik++) {
590 m_lastmoles[k] = m_moles[k];
597 m_moles[k] += omega * deltaN[k];
600 for (ik = m_nel; ik < m_nsp; ik++) {
602 m_lastmoles[k] = m_moles[k];
604 m_moles[k] += omega * deltaN[k];
606 m_moles[k] = fabs(m_moles[k])*std::min(10.0,
607 exp(-m_deltaG_RT[ik - m_nel]));
636 doublereal FCTR = 0.99;
637 const doublereal MAJOR_THRESHOLD = 1.0e-12;
639 doublereal omega = 1.0, omax, omegamax = 1.0;
640 for (ik = 0; ik < m_nsp; ik++) {
644 if (m_moles[k] < MAJOR_THRESHOLD) {
654 if (m_dsoln[k] == 1) {
656 if ((m_moles[k] > MAJOR_THRESHOLD) || (ik < m_nel)) {
657 if (m_moles[k] < MAJOR_THRESHOLD) {
660 omax = m_moles[k]*FCTR/(fabs(m_work[k]) +
Tiny);
661 if (m_work[k] < 0.0 && omax < omegamax) {
663 if (omegamax < 1.0e-5) {
669 m_majorsp[k] =
false;
672 if (m_work[k] < 0.0 && m_moles[k] > 0.0) {
673 omax = -m_moles[k]/m_work[k];
674 if (omax < omegamax) {
676 if (omegamax < 1.0e-5) {
681 if (m_moles[k] < -
Tiny) {
694 step(omegamax, m_work);
698 doublereal not_mu = 1.0e12;
700 doublereal grad1 = 0.0;
701 for (k = 0; k < m_nsp; k++) {
702 grad1 += m_work[k] * m_mu[m_species[k]];
707 omega *= fabs(grad0) / (grad1 + fabs(grad0));
708 for (k = 0; k < m_nsp; k++) {
709 m_moles[k] = m_lastmoles[k];
725 size_t j, k, ik, kc, ip;
726 doublereal stoich, nmoles, csum, term1, fctr, rfctr;
728 doublereal grad = 0.0;
732 doublereal not_mu = 1.0e12;
735 for (j = 0; j <
nFree(); j++) {
738 getStoichVector(j, nu);
741 doublereal dg_rt = 0.0;
742 for (k = 0; k < m_nsp; k++) {
743 dg_rt += m_mu[m_species[k]] * nu[k];
747 m_deltaG_RT[j] = dg_rt;
755 if (m_moles[k] <= 0.0 && dg_rt > 0.0) {
760 }
else if (!m_solnrxn[j]) {
766 for (k = 0; k < m_nel; k++) {
770 csum += stoich*stoich*m_dsoln[kc]/nmoles;
774 kc = m_order[j + m_nel];
776 term1 = m_dsoln[kc]/nmoles;
779 doublereal sum = 0.0, psum;
780 for (ip = 0; ip < m_np; ip++) {
784 for (k = 0; k < m_nsp; k++) {
789 psum += stoich * stoich;
795 rfctr = term1 + csum + sum;
796 if (fabs(rfctr) <
Tiny) {
799 fctr = 1.0/(term1 + csum + sum);
802 dxi[j] = -fctr*dg_rt;
805 for (m = 0; m < m_nel; m++) {
806 if (m_moles[m_order[m]] <= 0.0 && (m_N(m, j)*dxi[j] < 0.0)) {
810 grad += dxi[j]*dg_rt;
816 void MultiPhaseEquil::computeN()
819 std::vector<std::pair<double, size_t> > moleFractions(m_nsp);
820 for (
size_t k = 0; k < m_nsp; k++) {
822 moleFractions[k].first = - m_mix->
speciesMoles(m_species[k]);
823 moleFractions[k].second = k;
825 std::sort(moleFractions.begin(), moleFractions.end());
826 for (
size_t k = 0; k < m_nsp; k++) {
827 m_sortindex[k] = moleFractions[k].second;
831 for (
size_t m = 0; m < m_nel; m++) {
833 for (
size_t ik = 0; ik < m_nsp; ik++) {
835 if (m_mix->
nAtoms(m_species[k],m_element[m]) != 0) {
840 for (
size_t ij = 0; ij < m_nel; ij++) {
841 if (k == m_order[ij]) {
845 if (!ok || m_force) {
853 doublereal MultiPhaseEquil::error()
855 doublereal err, maxerr = 0.0;
858 for (
size_t j = 0; j <
nFree(); j++) {
859 size_t ik = j + m_nel;
863 if (!isStoichPhase(ik) && fabs(moles(ik)) <=
SmallNumber) {
869 if (isStoichPhase(ik) && moles(ik) <= 0.0 &&
870 m_deltaG_RT[j] >= 0.0) {
873 err = fabs(m_deltaG_RT[j]);
882 double MultiPhaseEquil::phaseMoles(
size_t iph)
const
887 void MultiPhaseEquil::reportCSV(
const std::string& reportFile)
895 size_t nphase = m_np;
897 FILE* FP = fopen(reportFile.c_str(),
"w");
899 printf(
"Failure to open file\n");
904 vector<double> mf(m_nsp_mix, 1.0);
905 vector<double> fe(m_nsp_mix, 0.0);
907 std::vector<double> VolPM;
908 std::vector<double> activity;
909 std::vector<double> ac;
910 std::vector<double> mu;
911 std::vector<double> mu0;
912 std::vector<double> molalities;
916 for (
size_t iphase = 0; iphase < nphase; iphase++) {
918 ThermoPhase& tref = m_mix->
phase(iphase);
920 VolPM.resize(nSpecies, 0.0);
921 tref.getMoleFractions(&mf[istart]);
922 tref.getPartialMolarVolumes(
DATA_PTR(VolPM));
925 double TMolesPhase = phaseMoles(iphase);
926 double VolPhaseVolumes = 0.0;
927 for (k = 0; k < nSpecies; k++) {
928 VolPhaseVolumes += VolPM[k] * mf[istart + k];
930 VolPhaseVolumes *= TMolesPhase;
931 vol += VolPhaseVolumes;
933 fprintf(FP,
"--------------------- VCS_MULTIPHASE_EQUIL FINAL REPORT"
934 " -----------------------------\n");
935 fprintf(FP,
"Temperature = %11.5g kelvin\n", Temp);
936 fprintf(FP,
"Pressure = %11.5g Pascal\n", pres);
937 fprintf(FP,
"Total Volume = %11.5g m**3\n", vol);
941 for (
size_t iphase = 0; iphase < nphase; iphase++) {
944 ThermoPhase& tref = m_mix->
phase(iphase);
945 ThermoPhase* tp = &tref;
947 string phaseName = tref.name();
949 double TMolesPhase = phaseMoles(iphase);
951 nSpecies = tref.nSpecies();
952 activity.resize(nSpecies, 0.0);
953 ac.resize(nSpecies, 0.0);
955 mu0.resize(nSpecies, 0.0);
956 mu.resize(nSpecies, 0.0);
957 VolPM.resize(nSpecies, 0.0);
958 molalities.resize(nSpecies, 0.0);
960 int actConvention = tp->activityConvention();
961 tp->getActivities(
DATA_PTR(activity));
962 tp->getActivityCoefficients(
DATA_PTR(ac));
963 tp->getStandardChemPotentials(
DATA_PTR(mu0));
965 tp->getPartialMolarVolumes(
DATA_PTR(VolPM));
966 tp->getChemPotentials(
DATA_PTR(mu));
967 double VolPhaseVolumes = 0.0;
968 for (k = 0; k < nSpecies; k++) {
969 VolPhaseVolumes += VolPM[k] * mf[istart + k];
971 VolPhaseVolumes *= TMolesPhase;
972 vol += VolPhaseVolumes;
973 if (actConvention == 1) {
974 MolalityVPSSTP* mTP =
static_cast<MolalityVPSSTP*
>(tp);
975 mTP->getMolalities(
DATA_PTR(molalities));
976 tp->getChemPotentials(
DATA_PTR(mu));
979 fprintf(FP,
" Name, Phase, PhaseMoles, Mole_Fract, "
980 "Molalities, ActCoeff, Activity,"
981 "ChemPot_SS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
983 fprintf(FP,
" , , (kmol), , "
985 " (kJ/gmol), (kJ/gmol), (kmol), (m**3/kmol), (m**3)\n");
987 for (k = 0; k < nSpecies; k++) {
988 sName = tp->speciesName(k);
989 fprintf(FP,
"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e,"
990 "%11.3e, %11.3e, %11.3e, %11.3e, %11.3e\n",
992 phaseName.c_str(), TMolesPhase,
993 mf[istart + k], molalities[k], ac[k], activity[k],
994 mu0[k]*1.0E-6, mu[k]*1.0E-6,
995 mf[istart + k] * TMolesPhase,
996 VolPM[k], VolPhaseVolumes);
1001 fprintf(FP,
" Name, Phase, PhaseMoles, Mole_Fract, "
1002 "Molalities, ActCoeff, Activity,"
1003 " ChemPotSS0, ChemPot, mole_num, PMVol, Phase_Volume\n");
1005 fprintf(FP,
" , , (kmol), , "
1007 " (kJ/gmol), (kJ/gmol), (kmol), (m**3/kmol), (m**3)\n");
1009 for (k = 0; k < nSpecies; k++) {
1010 molalities[k] = 0.0;
1012 for (k = 0; k < nSpecies; k++) {
1013 sName = tp->speciesName(k);
1014 fprintf(FP,
"%12s, %11s, %11.3e, %11.3e, %11.3e, %11.3e, %11.3e, "
1015 "%11.3e, %11.3e,% 11.3e, %11.3e, %11.3e\n",
1017 phaseName.c_str(), TMolesPhase,
1018 mf[istart + k], molalities[k], ac[k],
1019 activity[k], mu0[k]*1.0E-6, mu[k]*1.0E-6,
1020 mf[istart + k] * TMolesPhase,
1021 VolPM[k], VolPhaseVolumes);
1028 tp->getChemPotentials(&(fe[istart]));
1029 for (k = 0; k < nSpecies; k++) {
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
bool tempOK(size_t p) const
Return true if the phase p has valid thermo data for the current temperature.
void beginLogGroup(const std::string &title, int loglevel)
Create a new group for log messages.
doublereal speciesMoles(size_t kGlob) const
Returns the moles of global species k. units = kmol.
doublereal computeReactionSteps(vector_fp &dxi)
Compute the change in extent of reaction for each reaction.
const size_t npos
index returned by functions to indicate "no position"
std::string speciesName(const size_t kGlob) const
Name of species with global index kGlob.
size_t nFree() const
Number of degrees of freedom.
doublereal phaseMoles(const size_t n) const
Return the number of moles in phase n.
doublereal temperature() const
Temperature [K].
void getComponents(const std::vector< size_t > &order)
This method finds a set of component species and a complete set of formation reactions for the non-co...
This file contains definitions for utility functions and text for modules, inputfiles, logs, textlogs, HTML_logs (see Input File Handling, Diagnostic Output, Writing messages to the screen and Writing HTML Logfiles).
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
Headers for the MultiPhase object that is used to set up multiphase equilibrium problems (see Equilib...
Header for intermediate ThermoPhase object for phases which employ molality based activity coefficien...
int setInitialMoles(int loglevel=0)
Estimate the initial mole numbers.
Base class for a phase with thermodynamic properties.
size_t speciesPhaseIndex(const size_t kGlob) const
Returns the phase index of the Kth "global" species.
A class for multiphase mixtures.
doublereal stepComposition(int loglevel=0)
Take one step in composition, given the gradient of G at the starting point, and a vector of reaction...
void resize(size_t n, size_t m, doublereal v=0.0)
Resize the matrix.
void unsort(vector_fp &x)
Re-arrange a vector of species properties in sorted form (components first) into unsorted, sequential form.
std::string elementName(size_t m) const
Returns the name of the global element m.
void getValidChemPotentials(doublereal not_mu, doublereal *mu, bool standard=false) const
Returns a vector of Valid chemical potentials.
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
void multiply(const DenseMatrix &A, const double *const b, double *const prod)
Multiply A*b and return the result in prod. Uses BLAS routine DGEMV.
std::string reactionString(size_t j)
Return a string specifying the jth reaction.
Base class for exceptions thrown by Cantera classes.
doublereal nAtoms(const size_t kGlob, const size_t mGlob) const
Returns the Number of atoms of global element mGlob in global species kGlob.
void endLogGroup(const std::string &title)
Close the current group of log messages.
size_t nSpecies() const
Returns the number of species in the phase.
void addLogEntry(const std::string &tag, const std::string &value)
Add an entry to an HTML log file.
const doublereal SmallNumber
smallest number to compare to zero.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
static string coeffString(bool first, doublereal nu, string sym)
Used to print reaction equations.
const doublereal Tiny
Small number to compare differences of mole fractions against.
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
doublereal elementMoles(size_t m) const
Total moles of global element m, summed over all phases.
Contains declarations for string manipulation functions within Cantera.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
bool solutionSpecies(size_t kGlob) const
Return true is species kGlob is a species in a multicomponent solution phase.
thermo_t & phase(size_t n)
Return a reference to phase n.
doublereal pressure() const
Pressure [Pa].
size_t nSpecies() const
Number of species, summed over all phases.
size_t speciesIndex(size_t k, size_t p) const
Return the global index of the species belonging to phase number p with local index k within the phas...
void finish()
Clean up the composition.
void setMoles(const doublereal *n)
Sets all of the global species mole numbers.
size_t nElements() const
Number of elements.
size_t nPhases() const
Number of phases.