00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "MolalityVPSSTP.h"
00027 using namespace std;
00028
00029 namespace Cantera {
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 MolalityVPSSTP::MolalityVPSSTP() :
00042 VPStandardStateTP(),
00043 m_indexSolvent(0),
00044 m_pHScalingType(PHSCALE_PITZER),
00045 m_indexCLM(-1),
00046 m_weightSolvent(18.01528),
00047 m_xmolSolventMIN(0.01),
00048 m_Mnaught(18.01528E-3)
00049 {
00050
00051
00052
00053
00054
00055 m_chargeNeutralityNecessary = true;
00056 }
00057
00058
00059
00060
00061
00062
00063
00064 MolalityVPSSTP::MolalityVPSSTP(const MolalityVPSSTP &b) :
00065 VPStandardStateTP(),
00066 m_indexSolvent(b.m_indexSolvent),
00067 m_pHScalingType(b.m_pHScalingType),
00068 m_indexCLM(b.m_indexCLM),
00069 m_xmolSolventMIN(b.m_xmolSolventMIN),
00070 m_Mnaught(b.m_Mnaught),
00071 m_molalities(b.m_molalities)
00072 {
00073 *this = operator=(b);
00074 }
00075
00076
00077
00078
00079
00080
00081
00082 MolalityVPSSTP& MolalityVPSSTP::
00083 operator=(const MolalityVPSSTP &b) {
00084 if (&b != this) {
00085 VPStandardStateTP::operator=(b);
00086 m_indexSolvent = b.m_indexSolvent;
00087 m_pHScalingType = b.m_pHScalingType;
00088 m_indexCLM = b.m_indexCLM;
00089 m_weightSolvent = b.m_weightSolvent;
00090 m_xmolSolventMIN = b.m_xmolSolventMIN;
00091 m_Mnaught = b.m_Mnaught;
00092 m_molalities = b.m_molalities;
00093 }
00094 return *this;
00095 }
00096
00097
00098
00099
00100
00101
00102
00103
00104 MolalityVPSSTP::~MolalityVPSSTP() {
00105 }
00106
00107
00108
00109
00110
00111 ThermoPhase*
00112 MolalityVPSSTP::duplMyselfAsThermoPhase() const {
00113 MolalityVPSSTP* mtp = new MolalityVPSSTP(*this);
00114 return (ThermoPhase *) mtp;
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 int MolalityVPSSTP::eosType() const {
00130 return 0;
00131 }
00132
00133
00134
00135
00136
00137
00138
00139 void MolalityVPSSTP::setpHScale(const int pHscaleType) {
00140 m_pHScalingType = pHscaleType;
00141 if (pHscaleType != PHSCALE_PITZER && pHscaleType != PHSCALE_NBS) {
00142 throw CanteraError("MolalityVPSSTP::setpHScale",
00143 "Unknown scale type: " + int2str(pHscaleType));
00144 }
00145 }
00146
00147
00148
00149
00150
00151
00152
00153 int MolalityVPSSTP::pHScale() const {
00154 return m_pHScalingType;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164 void MolalityVPSSTP::setSolvent(int k) {
00165 if (k < 0 || k >= m_kk) {
00166 throw CanteraError("MolalityVPSSTP::setSolute ",
00167 "bad value");
00168 }
00169 m_indexSolvent = k;
00170 AssertThrowMsg(m_indexSolvent==0, "MolalityVPSSTP::setSolvent",
00171 "Molality-based methods limit solvent id to being 0");
00172 m_weightSolvent = molecularWeight(k);
00173 m_Mnaught = m_weightSolvent / 1000.;
00174 }
00175
00176
00177
00178
00179 int MolalityVPSSTP::solventIndex() const {
00180 return m_indexSolvent;
00181 }
00182
00183
00184
00185
00186
00187 void MolalityVPSSTP::
00188 setMoleFSolventMin(doublereal xmolSolventMIN) {
00189 if (xmolSolventMIN <= 0.0) {
00190 throw CanteraError("MolalityVPSSTP::setSolute ", "trouble");
00191 } else if (xmolSolventMIN > 0.9) {
00192 throw CanteraError("MolalityVPSSTP::setSolute ", "trouble");
00193 }
00194 m_xmolSolventMIN = xmolSolventMIN;
00195 }
00196
00197
00198
00199
00200 doublereal MolalityVPSSTP::moleFSolventMin() const {
00201 return m_xmolSolventMIN;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 void MolalityVPSSTP::calcMolalities() const {
00220 getMoleFractions(DATA_PTR(m_molalities));
00221 double xmolSolvent = m_molalities[m_indexSolvent];
00222 if (xmolSolvent < m_xmolSolventMIN) {
00223 xmolSolvent = m_xmolSolventMIN;
00224 }
00225 double denomInv = 1.0/ (m_Mnaught * xmolSolvent);
00226 for (int k = 0; k < m_kk; k++) {
00227 m_molalities[k] *= denomInv;
00228 }
00229 }
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 void MolalityVPSSTP::getMolalities(doublereal * const molal) const {
00247 calcMolalities();
00248 for (int k = 0; k < m_kk; k++) {
00249 molal[k] = m_molalities[k];
00250 }
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 void MolalityVPSSTP::setMolalities(const doublereal * const molal) {
00269
00270 double Lsum = 1.0 / m_Mnaught;
00271 for (int k = 1; k < m_kk; k++) {
00272 m_molalities[k] = molal[k];
00273 Lsum += molal[k];
00274 }
00275 double tmp = 1.0 / Lsum;
00276 m_molalities[m_indexSolvent] = tmp / m_Mnaught;
00277 double sum = m_molalities[m_indexSolvent];
00278 for (int k = 1; k < m_kk; k++) {
00279 m_molalities[k] = tmp * molal[k];
00280 sum += m_molalities[k];
00281 }
00282 if (sum != 1.0) {
00283 tmp = 1.0 / sum;
00284 for (int k = 0; k < m_kk; k++) {
00285 m_molalities[k] *= tmp;
00286 }
00287 }
00288 setMoleFractions(DATA_PTR(m_molalities));
00289
00290
00291
00292
00293
00294 calcMolalities();
00295 }
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 void MolalityVPSSTP::setMolalitiesByName(compositionMap& mMap) {
00306 int kk = nSpecies();
00307 doublereal x;
00308
00309
00310
00311 vector_fp mf(kk, 0.0);
00312 getMoleFractions(DATA_PTR(mf));
00313 double xmolS = mf[m_indexSolvent];
00314 double xmolSmin = max(xmolS, m_xmolSolventMIN);
00315 compositionMap::iterator p;
00316 for (int k = 0; k < kk; k++) {
00317 p = mMap.find(speciesName(k));
00318 if (p != mMap.end()) {
00319 x = mMap[speciesName(k)];
00320 if (x > 0.0) {
00321 mf[k] = x * m_Mnaught * xmolSmin;
00322 }
00323 }
00324 }
00325
00326
00327
00328 int largePos = -1;
00329 double cPos = 0.0;
00330 int largeNeg = -1;
00331 double cNeg = 0.0;
00332 double sum = 0.0;
00333 for (int k = 0; k < kk; k++) {
00334 double ch = charge(k);
00335 if (mf[k] > 0.0) {
00336 if (ch > 0.0) {
00337 if (ch * mf[k] > cPos) {
00338 largePos = k;
00339 cPos = ch * mf[k];
00340 }
00341 }
00342 if (ch < 0.0) {
00343 if (fabs(ch) * mf[k] > cNeg) {
00344 largeNeg = k;
00345 cNeg = fabs(ch) * mf[k];
00346 }
00347 }
00348 }
00349 sum += mf[k] * ch;
00350 }
00351 if (sum != 0.0) {
00352 if (sum > 0.0) {
00353 if (cPos > sum) {
00354 mf[largePos] -= sum / charge(largePos);
00355 } else {
00356 throw CanteraError("MolalityVPSSTP:setMolalitiesbyName",
00357 "unbalanced charges");
00358 }
00359 } else {
00360 if (cNeg > (-sum)) {
00361 mf[largeNeg] -= (-sum) / fabs(charge(largeNeg));
00362 } else {
00363 throw CanteraError("MolalityVPSSTP:setMolalitiesbyName",
00364 "unbalanced charges");
00365 }
00366 }
00367
00368 }
00369 sum = 0.0;
00370 for (int k = 0; k < kk; k++) {
00371 sum += mf[k];
00372 }
00373 sum = 1.0/sum;
00374 for (int k = 0; k < kk; k++) {
00375 mf[k] *= sum;
00376 }
00377 setMoleFractions(DATA_PTR(mf));
00378
00379
00380
00381
00382
00383 calcMolalities();
00384 }
00385
00386
00387
00388
00389
00390
00391 void MolalityVPSSTP::setMolalitiesByName(const std::string& x) {
00392 compositionMap xx;
00393 int kk = nSpecies();
00394 for (int k = 0; k < kk; k++) {
00395 xx[speciesName(k)] = -1.0;
00396 }
00397 parseCompString(x, xx);
00398 setMolalitiesByName(xx);
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 int MolalityVPSSTP::activityConvention() const {
00431 return cAC_CONVENTION_MOLALITY;
00432 }
00433
00434 void MolalityVPSSTP::getActivityConcentrations(doublereal* c) const {
00435 err("getActivityConcentrations");
00436 }
00437
00438 doublereal MolalityVPSSTP::standardConcentration(int k) const {
00439 err("standardConcentration");
00440 return -1.0;
00441 }
00442
00443 doublereal MolalityVPSSTP::logStandardConc(int k) const {
00444 err("logStandardConc");
00445 return -1.0;
00446 }
00447
00448 void MolalityVPSSTP::getActivities(doublereal* ac) const {
00449 err("getActivities");
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 void MolalityVPSSTP::getActivityCoefficients(doublereal* ac) const {
00466 getMolalityActivityCoefficients(ac);
00467 AssertThrow(m_indexSolvent==0, "MolalityVPSSTP::getActivityCoefficients");
00468 double xmolSolvent = moleFraction(m_indexSolvent);
00469 if (xmolSolvent < m_xmolSolventMIN) {
00470 xmolSolvent = m_xmolSolventMIN;
00471 }
00472 for (int k = 1; k < m_kk; k++) {
00473 ac[k] /= xmolSolvent;
00474 }
00475 }
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 void MolalityVPSSTP::getMolalityActivityCoefficients(doublereal *acMolality) const {
00492 getUnscaledMolalityActivityCoefficients(acMolality);
00493 applyphScale(acMolality);
00494 }
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508 doublereal MolalityVPSSTP::osmoticCoefficient() const {
00509
00510
00511
00512 vector_fp act(m_kk);
00513 getActivities(DATA_PTR(act));
00514
00515
00516
00517 double sum = 0;
00518 for (int k = 1; k < m_kk; k++) {
00519 sum += fmaxx(m_molalities[k], 0.0);
00520 }
00521 double oc = 1.0;
00522 double lac = log(act[m_indexSolvent]);
00523 if (sum > 1.0E-200) {
00524 oc = - lac / (m_Mnaught * sum);
00525 }
00526 return oc;
00527 }
00528
00529
00530 void MolalityVPSSTP::getElectrochemPotentials(doublereal* mu) const {
00531 getChemPotentials(mu);
00532 double ve = Faraday * electricPotential();
00533 for (int k = 0; k < m_kk; k++) {
00534 mu[k] += ve*charge(k);
00535 }
00536 }
00537
00538
00539
00540
00541
00542
00543 doublereal MolalityVPSSTP::err(std::string msg) const {
00544 throw CanteraError("MolalityVPSSTP","Base class method "
00545 +msg+" called. Equation of state type: "+int2str(eosType()));
00546 return 0;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 void MolalityVPSSTP::getUnitsStandardConc(double *uA, int k, int sizeUA) const {
00572 for (int i = 0; i < sizeUA; i++) {
00573 if (i == 0) uA[0] = 1.0;
00574 if (i == 1) uA[1] = -nDim();
00575 if (i == 2) uA[2] = 0.0;
00576 if (i == 3) uA[3] = 0.0;
00577 if (i == 4) uA[4] = 0.0;
00578 if (i == 5) uA[5] = 0.0;
00579 }
00580 }
00581
00582 void MolalityVPSSTP::setToEquilState(const doublereal* lambda_RT) {
00583 updateStandardStateThermo();
00584 err("setToEquilState");
00585 }
00586
00587
00588
00589
00590 void MolalityVPSSTP::setStateFromXML(const XML_Node& state) {
00591 VPStandardStateTP::setStateFromXML(state);
00592 string comp = getChildValue(state,"soluteMolalities");
00593 if (comp != "") {
00594 setMolalitiesByName(comp);
00595 }
00596 if (state.hasChild("pressure")) {
00597 double p = getFloat(state, "pressure", "pressure");
00598 setPressure(p);
00599 }
00600 }
00601
00602
00603
00604
00605
00606 void MolalityVPSSTP::setState_TPM(doublereal t, doublereal p,
00607 const doublereal * const molalities) {
00608 setMolalities(molalities);
00609 setState_TP(t, p);
00610 }
00611
00612
00613
00614
00615 void MolalityVPSSTP::setState_TPM(doublereal t, doublereal p, compositionMap& m) {
00616 setMolalitiesByName(m);
00617 setState_TP(t, p);
00618 }
00619
00620
00621
00622
00623 void MolalityVPSSTP::setState_TPM(doublereal t, doublereal p, const std::string& m) {
00624 setMolalitiesByName(m);
00625 setState_TP(t, p);
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642 void MolalityVPSSTP::initThermo() {
00643 initLengths();
00644 VPStandardStateTP::initThermo();
00645
00646
00647
00648
00649 setSolvent(0);
00650
00651
00652
00653 m_indexCLM = findCLMIndex();
00654 }
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668 void MolalityVPSSTP::getUnscaledMolalityActivityCoefficients(doublereal *acMolality) const {
00669 err("getUnscaledMolalityActivityCoefficients");
00670 }
00671
00672
00673
00674
00675
00676
00677
00678
00679 void MolalityVPSSTP::applyphScale(doublereal *acMolality) const {
00680 err("applyphScale");
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 int MolalityVPSSTP::findCLMIndex() const {
00697 int indexCLM = -1;
00698 int eCl = -1;
00699 int eE = -1;
00700 int ne= nElements();
00701 string sn;
00702 for (int e = 0; e < ne; e++) {
00703 sn = elementName(e);
00704 if (sn == "Cl" || sn == "CL") {
00705 eCl = e;
00706 break;
00707 }
00708 }
00709
00710 if (eCl == -1) {
00711 return -1;
00712 }
00713 for (int e = 0; e < ne; e++) {
00714 sn = elementName(e);
00715 if (sn == "E" || sn == "e") {
00716 eE = e;
00717 break;
00718 }
00719 }
00720
00721 if (eE == -1) {
00722 return -1;
00723 }
00724 for (int k = 1; k < m_kk; k++) {
00725 doublereal nCl = nAtoms(k, eCl);
00726 if (nCl != 1.0) {
00727 continue;
00728 }
00729 doublereal nE = nAtoms(k, eE);
00730 if (nE != 1.0) {
00731 continue;
00732 }
00733 for (int e = 0; e < ne; e++) {
00734 if (e != eE && e != eCl) {
00735 doublereal nA = nAtoms(k, e);
00736 if (nA != 0.0) {
00737 continue;
00738 }
00739 }
00740 }
00741 sn = speciesName(k);
00742 if (sn != "Cl-" && sn != "CL-") {
00743 continue;
00744 }
00745
00746 indexCLM = k;
00747 break;
00748 }
00749 return indexCLM;
00750 }
00751
00752
00753
00754 void MolalityVPSSTP::initLengths() {
00755 m_kk = nSpecies();
00756 m_molalities.resize(m_kk);
00757 }
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774 void MolalityVPSSTP::initThermoXML(XML_Node& phaseNode, std::string id) {
00775
00776 initLengths();
00777
00778
00779
00780 setSolvent(0);
00781
00782 VPStandardStateTP::initThermoXML(phaseNode, id);
00783 }
00784
00785
00786
00787
00788 std::string MolalityVPSSTP::report(bool show_thermo) const {
00789
00790
00791 char p[800];
00792 string s = "";
00793 try {
00794 if (name() != "") {
00795 sprintf(p, " \n %s:\n", name().c_str());
00796 s += p;
00797 }
00798 sprintf(p, " \n temperature %12.6g K\n", temperature());
00799 s += p;
00800 sprintf(p, " pressure %12.6g Pa\n", pressure());
00801 s += p;
00802 sprintf(p, " density %12.6g kg/m^3\n", density());
00803 s += p;
00804 sprintf(p, " mean mol. weight %12.6g amu\n", meanMolecularWeight());
00805 s += p;
00806
00807 doublereal phi = electricPotential();
00808 sprintf(p, " potential %12.6g V\n", phi);
00809 s += p;
00810
00811 int kk = nSpecies();
00812 array_fp x(kk);
00813 array_fp molal(kk);
00814 array_fp mu(kk);
00815 array_fp muss(kk);
00816 array_fp acMolal(kk);
00817 array_fp actMolal(kk);
00818 getMoleFractions(&x[0]);
00819 getMolalities(&molal[0]);
00820 getChemPotentials(&mu[0]);
00821 getStandardChemPotentials(&muss[0]);
00822 getMolalityActivityCoefficients(&acMolal[0]);
00823 getActivities(&actMolal[0]);
00824
00825 int iHp = speciesIndex("H+");
00826 if (iHp >= 0) {
00827 double pH = -log(actMolal[iHp]) / log(10.0);
00828 sprintf(p, " pH %12.4g \n", pH);
00829 s += p;
00830 }
00831
00832 if (show_thermo) {
00833 sprintf(p, " \n");
00834 s += p;
00835 sprintf(p, " 1 kg 1 kmol\n");
00836 s += p;
00837 sprintf(p, " ----------- ------------\n");
00838 s += p;
00839 sprintf(p, " enthalpy %12.6g %12.4g J\n",
00840 enthalpy_mass(), enthalpy_mole());
00841 s += p;
00842 sprintf(p, " internal energy %12.6g %12.4g J\n",
00843 intEnergy_mass(), intEnergy_mole());
00844 s += p;
00845 sprintf(p, " entropy %12.6g %12.4g J/K\n",
00846 entropy_mass(), entropy_mole());
00847 s += p;
00848 sprintf(p, " Gibbs function %12.6g %12.4g J\n",
00849 gibbs_mass(), gibbs_mole());
00850 s += p;
00851 sprintf(p, " heat capacity c_p %12.6g %12.4g J/K\n",
00852 cp_mass(), cp_mole());
00853 s += p;
00854 try {
00855 sprintf(p, " heat capacity c_v %12.6g %12.4g J/K\n",
00856 cv_mass(), cv_mole());
00857 s += p;
00858 }
00859 catch(CanteraError) {
00860 sprintf(p, " heat capacity c_v <not implemented> \n");
00861 s += p;
00862 }
00863 }
00864
00865
00866
00867 int k;
00868
00869
00870 sprintf(p, " \n");
00871 s += p;
00872 if (show_thermo) {
00873 sprintf(p, " X "
00874 " Molalities Chem.Pot. ChemPotSS ActCoeffMolal\n");
00875 s += p;
00876 sprintf(p, " "
00877 " (J/kmol) (J/kmol) \n");
00878 s += p;
00879 sprintf(p, " ------------- "
00880 " ------------ ------------ ------------ ------------\n");
00881 s += p;
00882 for (k = 0; k < kk; k++) {
00883 if (x[k] > SmallNumber) {
00884 sprintf(p, "%18s %12.6g %12.6g %12.6g %12.6g %12.6g\n",
00885 speciesName(k).c_str(), x[k], molal[k], mu[k], muss[k], acMolal[k]);
00886 }
00887 else {
00888 sprintf(p, "%18s %12.6g %12.6g N/A %12.6g %12.6g \n",
00889 speciesName(k).c_str(), x[k], molal[k], muss[k], acMolal[k]);
00890 }
00891 s += p;
00892 }
00893 }
00894 else {
00895 sprintf(p, " X"
00896 "Molalities\n");
00897 s += p;
00898 sprintf(p, " -------------"
00899 " ------------\n");
00900 s += p;
00901 for (k = 0; k < kk; k++) {
00902 sprintf(p, "%18s %12.6g %12.6g\n",
00903 speciesName(k).c_str(), x[k], molal[k]);
00904 s += p;
00905 }
00906 }
00907 } catch (CanteraError) {
00908 ;
00909 }
00910 return s;
00911 }
00912
00913
00914 }
00915