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 "IdealMolalSoln.h"
00027 #include "ThermoFactory.h"
00028 #include <cmath>
00029
00030
00031 #ifndef MAX
00032 #define MAX(x,y) (( (x) > (y) ) ? (x) : (y))
00033 #endif
00034
00035
00036 namespace Cantera {
00037
00038
00039 static double xxSmall = 1.0E-150;
00040
00041
00042
00043 IdealMolalSoln::IdealMolalSoln() :
00044 MolalityVPSSTP(),
00045 m_formGC(2),
00046 IMS_typeCutoff_(0),
00047 IMS_X_o_cutoff_(0.20),
00048 IMS_gamma_o_min_(0.00001),
00049 IMS_gamma_k_min_(10.0),
00050 IMS_cCut_(.05),
00051 IMS_slopefCut_(0.6),
00052 IMS_dfCut_(0.0),
00053 IMS_efCut_(0.0),
00054 IMS_afCut_(0.0),
00055 IMS_bfCut_(0.0),
00056 IMS_slopegCut_(0.0),
00057 IMS_dgCut_(0.0),
00058 IMS_egCut_(0.0),
00059 IMS_agCut_(0.0),
00060 IMS_bgCut_(0.0)
00061 {
00062 }
00063
00064
00065
00066
00067
00068
00069
00070 IdealMolalSoln::IdealMolalSoln(const IdealMolalSoln &b) :
00071 MolalityVPSSTP(b)
00072 {
00073
00074
00075
00076
00077 *this = b;
00078 }
00079
00080
00081
00082
00083
00084
00085
00086 IdealMolalSoln& IdealMolalSoln::
00087 operator=(const IdealMolalSoln &b) {
00088 if (&b != this) {
00089 MolalityVPSSTP::operator=(b);
00090 m_speciesMolarVolume = b.m_speciesMolarVolume;
00091 m_formGC = b.m_formGC;
00092 IMS_typeCutoff_ = b.IMS_typeCutoff_;
00093 IMS_X_o_cutoff_ = b.IMS_X_o_cutoff_;
00094 IMS_gamma_o_min_ = b.IMS_gamma_o_min_;
00095 IMS_gamma_k_min_ = b.IMS_gamma_k_min_;
00096 IMS_cCut_ = b.IMS_cCut_;
00097 IMS_slopefCut_ = b.IMS_slopefCut_;
00098 IMS_dfCut_ = b.IMS_dfCut_;
00099 IMS_efCut_ = b.IMS_efCut_;
00100 IMS_afCut_ = b.IMS_afCut_;
00101 IMS_bfCut_ = b.IMS_bfCut_;
00102 IMS_slopegCut_ = b.IMS_slopegCut_;
00103 IMS_dgCut_ = b.IMS_dgCut_;
00104 IMS_egCut_ = b.IMS_egCut_;
00105 IMS_agCut_ = b.IMS_agCut_;
00106 IMS_bgCut_ = b.IMS_bgCut_;
00107 m_expg0_RT = b.m_expg0_RT;
00108 m_pe = b.m_pe;
00109 m_pp = b.m_pp;
00110 m_tmpV = b.m_tmpV;
00111 IMS_lnActCoeffMolal_ = b.IMS_lnActCoeffMolal_;
00112 }
00113 return *this;
00114 }
00115
00116 IdealMolalSoln::IdealMolalSoln(std::string inputFile, std::string id) :
00117 MolalityVPSSTP(),
00118 m_formGC(2),
00119 IMS_typeCutoff_(0),
00120 IMS_X_o_cutoff_(0.2),
00121 IMS_gamma_o_min_(0.00001),
00122 IMS_gamma_k_min_(10.0),
00123 IMS_cCut_(.05),
00124 IMS_slopefCut_(0.6),
00125 IMS_dfCut_(0.0),
00126 IMS_efCut_(0.0),
00127 IMS_afCut_(0.0),
00128 IMS_bfCut_(0.0),
00129 IMS_slopegCut_(0.0),
00130 IMS_dgCut_(0.0),
00131 IMS_egCut_(0.0),
00132 IMS_agCut_(0.0),
00133 IMS_bgCut_(0.0)
00134 {
00135 constructPhaseFile(inputFile, id);
00136 }
00137
00138 IdealMolalSoln::IdealMolalSoln(XML_Node& root, std::string id) :
00139 MolalityVPSSTP(),
00140 m_formGC(2),
00141 IMS_typeCutoff_(0),
00142 IMS_X_o_cutoff_(0.2),
00143 IMS_gamma_o_min_(0.00001),
00144 IMS_gamma_k_min_(10.0),
00145 IMS_cCut_(.05),
00146 IMS_slopefCut_(0.6),
00147 IMS_dfCut_(0.0),
00148 IMS_efCut_(0.0),
00149 IMS_afCut_(0.0),
00150 IMS_bfCut_(0.0),
00151 IMS_slopegCut_(0.0),
00152 IMS_dgCut_(0.0),
00153 IMS_egCut_(0.0),
00154 IMS_agCut_(0.0),
00155 IMS_bgCut_(0.0)
00156 {
00157 constructPhaseXML(root, id);
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167 IdealMolalSoln::~IdealMolalSoln() {
00168 }
00169
00170
00171
00172
00173 ThermoPhase* IdealMolalSoln::duplMyselfAsThermoPhase() const {
00174 IdealMolalSoln* mtp = new IdealMolalSoln(*this);
00175 return (ThermoPhase *) mtp;
00176 }
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 doublereal IdealMolalSoln::enthalpy_mole() const {
00197 getPartialMolarEnthalpies(DATA_PTR(m_tmpV));
00198 getMoleFractions(DATA_PTR(m_pp));
00199 double val = mean_X(DATA_PTR(m_tmpV));
00200 return val;
00201 }
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 doublereal IdealMolalSoln::intEnergy_mole() const {
00215 getPartialMolarEnthalpies(DATA_PTR(m_tmpV));
00216 return mean_X(DATA_PTR(m_tmpV));
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 doublereal IdealMolalSoln::entropy_mole() const {
00235 getPartialMolarEntropies(DATA_PTR(m_tmpV));
00236 return mean_X(DATA_PTR(m_tmpV));
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 doublereal IdealMolalSoln::gibbs_mole() const {
00252 getChemPotentials(DATA_PTR(m_tmpV));
00253 return mean_X(DATA_PTR(m_tmpV));
00254 }
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 doublereal IdealMolalSoln::cp_mole() const {
00265 getPartialMolarCp(DATA_PTR(m_tmpV));
00266 double val = mean_X(DATA_PTR(m_tmpV));
00267 return val;
00268 }
00269
00270
00271
00272
00273
00274
00275 doublereal IdealMolalSoln::cv_mole() const {
00276 return err("not implemented");
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 void IdealMolalSoln::setPressure(doublereal p) {
00291 setState_TP(temperature(), p);
00292 }
00293
00294 void IdealMolalSoln::calcDensity() {
00295 double *vbar = &m_pp[0];
00296 getPartialMolarVolumes(vbar);
00297 double *x = &m_tmpV[0];
00298 getMoleFractions(x);
00299 doublereal vtotal = 0.0;
00300 for (int i = 0; i < m_kk; i++) {
00301 vtotal += vbar[i] * x[i];
00302 }
00303 doublereal dd = meanMolecularWeight() / vtotal;
00304 State::setDensity(dd);
00305 }
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 doublereal IdealMolalSoln::isothermalCompressibility() const {
00318 return 0.0;
00319 }
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 doublereal IdealMolalSoln::thermalExpansionCoeff() const {
00333 return 0.0;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 void IdealMolalSoln::setDensity(const doublereal rho) {
00353 double dens = density();
00354 if (rho != dens) {
00355 throw CanteraError("Idea;MolalSoln::setDensity",
00356 "Density is not an independent variable");
00357 }
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 void IdealMolalSoln::setMolarDensity(const doublereal conc) {
00370 double concI = State::molarDensity();
00371 if (conc != concI) {
00372 throw CanteraError("IdealMolalSoln::setMolarDensity",
00373 "molarDensity/denisty is not an independent variable");
00374 }
00375 }
00376
00377 void IdealMolalSoln::setState_TP(doublereal temp, doublereal pres) {
00378 State::setTemperature(temp);
00379 m_Pcurrent = pres;
00380 updateStandardStateThermo();
00381
00382 calcDensity();
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 void IdealMolalSoln::getActivityConcentrations(doublereal* c) const {
00403 if (m_formGC != 1) {
00404 double c_solvent = standardConcentration();
00405 getActivities(c);
00406 for (int k = 0; k < m_kk; k++) {
00407 c[k] *= c_solvent;
00408 }
00409 } else {
00410 getActivities(c);
00411 for (int k = 0; k < m_kk; k++) {
00412 double c0 = standardConcentration(k);
00413 c[k] *= c0;
00414 }
00415 }
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 doublereal IdealMolalSoln::standardConcentration(int k) const {
00431 double c0 = 1.0, mvSolvent;
00432 switch (m_formGC) {
00433 case 0:
00434 break;
00435 case 1:
00436 c0 = 1.0 /m_speciesMolarVolume[m_indexSolvent];
00437 break;
00438 case 2:
00439 mvSolvent = m_speciesMolarVolume[m_indexSolvent];
00440 c0 = 1.0 / mvSolvent;
00441 break;
00442 }
00443 return c0;
00444 }
00445
00446
00447
00448
00449
00450 doublereal IdealMolalSoln::logStandardConc(int k) const {
00451 double c0 = standardConcentration(k);
00452 return log(c0);
00453 }
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 void IdealMolalSoln::getUnitsStandardConc(double *uA, int k, int sizeUA) const {
00478 int eos = eosType();
00479 if (eos == 0) {
00480 for (int i = 0; i < sizeUA; i++) {
00481 uA[i] = 0.0;
00482 }
00483 } else {
00484 for (int i = 0; i < sizeUA; i++) {
00485 if (i == 0) uA[0] = 1.0;
00486 if (i == 1) uA[1] = -nDim();
00487 if (i == 2) uA[2] = 0.0;
00488 if (i == 3) uA[3] = 0.0;
00489 if (i == 4) uA[4] = 0.0;
00490 if (i == 5) uA[5] = 0.0;
00491 }
00492 }
00493 }
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 void IdealMolalSoln::getActivities(doublereal* ac) const {
00504 _updateStandardStateThermo();
00505
00506
00507
00508
00509 if (IMS_typeCutoff_ == 0) {
00510 calcMolalities();
00511 for (int k = 0; k < m_kk; k++) {
00512 ac[k] = m_molalities[k];
00513 }
00514 double xmolSolvent = moleFraction(m_indexSolvent);
00515 xmolSolvent = fmaxx(m_xmolSolventMIN, xmolSolvent);
00516 ac[m_indexSolvent] =
00517 exp((xmolSolvent - 1.0)/xmolSolvent);
00518 } else {
00519
00520 s_updateIMS_lnMolalityActCoeff();
00521
00522
00523
00524 for (int k = 1; k < m_kk; k++) {
00525 ac[k] = m_molalities[k] * exp(IMS_lnActCoeffMolal_[k]);
00526 }
00527 double xmolSolvent = moleFraction(m_indexSolvent);
00528 ac[m_indexSolvent] =
00529 exp(IMS_lnActCoeffMolal_[m_indexSolvent]) * xmolSolvent;
00530
00531 }
00532 }
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545 void IdealMolalSoln::
00546 getMolalityActivityCoefficients(doublereal* acMolality) const {
00547 if (IMS_typeCutoff_ == 0) {
00548 for (int k = 0; k < m_kk; k++) {
00549 acMolality[k] = 1.0;
00550 }
00551 double xmolSolvent = moleFraction(m_indexSolvent);
00552 xmolSolvent = fmaxx(m_xmolSolventMIN, xmolSolvent);
00553 acMolality[m_indexSolvent] =
00554 exp((xmolSolvent - 1.0)/xmolSolvent) / xmolSolvent;
00555 } else {
00556 s_updateIMS_lnMolalityActCoeff();
00557 std::copy(IMS_lnActCoeffMolal_.begin(), IMS_lnActCoeffMolal_.end(), acMolality);
00558 for (int k = 0; k < m_kk; k++) {
00559 acMolality[k] = exp(acMolality[k]);
00560 }
00561 }
00562 }
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589 void IdealMolalSoln::getChemPotentials(doublereal* mu) const{
00590 double xx;
00591
00592
00593
00594 AssertThrow(m_indexSolvent == 0, "solvent not the first species");
00595
00596
00597
00598
00599
00600
00601
00602 getStandardChemPotentials(mu);
00603
00604
00605
00606
00607 calcMolalities();
00608
00609
00610
00611 double xmolSolvent = moleFraction(m_indexSolvent);
00612
00613
00614
00615 doublereal RT = GasConstant * temperature();
00616
00617 if (IMS_typeCutoff_ == 0 || xmolSolvent > 3.* IMS_X_o_cutoff_/2.0) {
00618
00619 for (int k = 1; k < m_kk; k++) {
00620 xx = fmaxx(m_molalities[k], xxSmall);
00621 mu[k] += RT * log(xx);
00622 }
00623
00624
00625
00626
00627
00628 xx = fmaxx(xmolSolvent, xxSmall);
00629 mu[m_indexSolvent] +=
00630 (RT * (xmolSolvent - 1.0) / xx);
00631 } else {
00632
00633
00634
00635
00636 s_updateIMS_lnMolalityActCoeff();
00637
00638
00639 for (int k = 1; k < m_kk; k++) {
00640 xx = MAX(m_molalities[k], xxSmall);
00641 mu[k] += RT * (log(xx) + IMS_lnActCoeffMolal_[k]);
00642 }
00643 xx = MAX(xmolSolvent, xxSmall);
00644 mu[m_indexSolvent] +=
00645 RT * (log(xx) + IMS_lnActCoeffMolal_[m_indexSolvent]);
00646 }
00647
00648 }
00649
00650
00651
00652
00653
00654
00655 void IdealMolalSoln::getPartialMolarEnthalpies(doublereal* hbar) const {
00656 getEnthalpy_RT(hbar);
00657 doublereal RT = _RT();
00658 for (int k = 0; k < m_kk; k++) {
00659 hbar[k] *= RT;
00660 }
00661 }
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690 void IdealMolalSoln::getPartialMolarEntropies(doublereal* sbar) const {
00691 getEntropy_R(sbar);
00692 doublereal R = GasConstant;
00693 doublereal mm;
00694 calcMolalities();
00695 if (IMS_typeCutoff_ == 0) {
00696 for (int k = 0; k < m_kk; k++) {
00697 if (k != m_indexSolvent) {
00698 mm = fmaxx(SmallNumber, m_molalities[k]);
00699 sbar[k] -= R * log(mm);
00700 }
00701 }
00702 double xmolSolvent = moleFraction(m_indexSolvent);
00703 sbar[m_indexSolvent] -= (R * (xmolSolvent - 1.0) / xmolSolvent);
00704 } else {
00705
00706
00707
00708
00709 s_updateIMS_lnMolalityActCoeff();
00710
00711
00712
00713
00714 doublereal mm;
00715 for (int k = 0; k < m_kk; k++) {
00716 if (k != m_indexSolvent) {
00717 mm = fmaxx(SmallNumber, m_molalities[k]);
00718 sbar[k] -= R * (log(mm) + IMS_lnActCoeffMolal_[k]);
00719 }
00720 }
00721 double xmolSolvent = moleFraction(m_indexSolvent);
00722 mm = fmaxx(SmallNumber, xmolSolvent);
00723 sbar[m_indexSolvent] -= R *(log(mm) + IMS_lnActCoeffMolal_[m_indexSolvent]);
00724
00725 }
00726 }
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737 void IdealMolalSoln::getPartialMolarVolumes(doublereal* vbar) const {
00738 getStandardVolumes(vbar);
00739 }
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757 void IdealMolalSoln::getPartialMolarCp(doublereal* cpbar) const {
00758
00759
00760
00761
00762 getCp_R(cpbar);
00763
00764 for (int k = 0; k < m_kk; k++) {
00765 cpbar[k] *= GasConstant;
00766 }
00767 }
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792 void IdealMolalSoln::initThermo() {
00793 initLengths();
00794 MolalityVPSSTP::initThermo();
00795 }
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811 void IdealMolalSoln::constructPhaseFile(std::string inputFile,
00812 std::string id) {
00813
00814 if (inputFile.size() == 0) {
00815 throw CanteraError("IdealMolalSoln::constructPhaseFile",
00816 "input file is null");
00817 }
00818 std::string path = findInputFile(inputFile);
00819 std::ifstream fin(path.c_str());
00820 if (!fin) {
00821 throw CanteraError("IdealMolalSoln::constructPhaseFile",
00822 "could not open "
00823 +path+" for reading.");
00824 }
00825
00826
00827
00828
00829 XML_Node &phaseNode_XML = xml();
00830 XML_Node *fxml = new XML_Node();
00831 fxml->build(fin);
00832 XML_Node *fxml_phase = findXMLPhase(fxml, id);
00833 if (!fxml_phase) {
00834 throw CanteraError("IdealMolalSoln::constructPhaseFile",
00835 "ERROR: Can not find phase named " +
00836 id + " in file named " + inputFile);
00837 }
00838 fxml_phase->copy(&phaseNode_XML);
00839 constructPhaseXML(*fxml_phase, id);
00840 delete fxml;
00841 }
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867 void IdealMolalSoln::constructPhaseXML(XML_Node& phaseNode,
00868 std::string id) {
00869 if (id.size() > 0) {
00870 std::string idp = phaseNode.id();
00871 if (idp != id) {
00872 throw CanteraError("IdealMolalSoln::constructPhaseXML",
00873 "phasenode and Id are incompatible");
00874 }
00875 }
00876
00877
00878
00879
00880 if (!phaseNode.hasChild("thermo")) {
00881 throw CanteraError("IdealMolalSoln::constructPhaseXML",
00882 "no thermo XML node");
00883 }
00884
00885
00886
00887
00888
00889
00890 bool m_ok = importPhase(phaseNode, this);
00891 if (!m_ok) {
00892 throw CanteraError("IdealMolalSoln::constructPhaseXML","importPhase failed ");
00893 }
00894 }
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915 void IdealMolalSoln::initThermoXML(XML_Node& phaseNode, std::string id) {
00916
00917
00918
00919
00920 initThermo();
00921
00922 if (id.size() > 0) {
00923 std::string idp = phaseNode.id();
00924 if (idp != id) {
00925 throw CanteraError("IdealMolalSoln::initThermo",
00926 "phasenode and Id are incompatible");
00927 }
00928 }
00929
00930
00931
00932
00933 if (!phaseNode.hasChild("thermo")) {
00934 throw CanteraError("IdealMolalSoln::initThermo",
00935 "no thermo XML node");
00936 }
00937 XML_Node& thermoNode = phaseNode.child("thermo");
00938
00939
00940
00941
00942 if (thermoNode.hasChild("standardConc")) {
00943 XML_Node& scNode = thermoNode.child("standardConc");
00944 m_formGC = 2;
00945 std::string formString = scNode.attrib("model");
00946 if (formString != "") {
00947 if (formString == "unity") {
00948 m_formGC = 0;
00949 } else if (formString == "molar_volume") {
00950 m_formGC = 1;
00951 } else if (formString == "solvent_volume") {
00952 m_formGC = 2;
00953 } else {
00954 throw CanteraError("IdealMolalSoln::initThermo",
00955 "Unknown standardConc model: " + formString);
00956 }
00957 }
00958 }
00959
00960
00961
00962
00963
00964 std::string solventName = "";
00965 if (thermoNode.hasChild("solvent")) {
00966 XML_Node& scNode = thermoNode.child("solvent");
00967 std::vector<std::string> nameSolventa;
00968 getStringArray(scNode, nameSolventa);
00969 int nsp = static_cast<int>(nameSolventa.size());
00970 if (nsp != 1) {
00971 throw CanteraError("IdealMolalSoln::initThermoXML",
00972 "badly formed solvent XML node");
00973 }
00974 solventName = nameSolventa[0];
00975 }
00976
00977 if (thermoNode.hasChild("activityCoefficients")) {
00978 XML_Node& acNode = thermoNode.child("activityCoefficients");
00979 std::string modelString = acNode.attrib("model");
00980 IMS_typeCutoff_ = 0;
00981 if (modelString != "IdealMolalSoln") {
00982 throw CanteraError("IdealMolalSoln::initThermoXML",
00983 "unknown ActivityCoefficient model: " + modelString);
00984 }
00985 if (acNode.hasChild("idealMolalSolnCutoff")) {
00986 XML_Node& ccNode = acNode.child("idealMolalSolnCutoff");
00987 modelString = ccNode.attrib("model");
00988 if (modelString != "") {
00989 if (modelString == "polyExp") {
00990 IMS_typeCutoff_ = 2;
00991 } else if (modelString == "poly") {
00992 IMS_typeCutoff_ = 1;
00993 } else {
00994 throw CanteraError("IdealMolalSoln::initThermoXML",
00995 "Unknown idealMolalSolnCutoff form: " + modelString);
00996 }
00997
00998 if (ccNode.hasChild("gamma_o_limit")) {
00999 IMS_gamma_o_min_ = getFloat(ccNode, "gamma_o_limit");
01000 }
01001 if (ccNode.hasChild("gamma_k_limit")) {
01002 IMS_gamma_k_min_ = getFloat(ccNode, "gamma_k_limit");
01003 }
01004 if (ccNode.hasChild("X_o_cutoff")) {
01005 IMS_X_o_cutoff_ = getFloat(ccNode, "X_o_cutoff");
01006 }
01007 if (ccNode.hasChild("c_0_param")) {
01008 IMS_cCut_ = getFloat(ccNode, "c_0_param");
01009 }
01010 if (ccNode.hasChild("slope_f_limit")) {
01011 IMS_slopefCut_ = getFloat(ccNode, "slope_f_limit");
01012 }
01013 if (ccNode.hasChild("slope_g_limit")) {
01014 IMS_slopegCut_ = getFloat(ccNode, "slope_g_limit");
01015 }
01016
01017 }
01018 }
01019 }
01020
01021
01022
01023
01024
01025 for (int k = 0; k < m_kk; k++) {
01026 std::string sname = speciesName(k);
01027 if (solventName == sname) {
01028 m_indexSolvent = k;
01029 break;
01030 }
01031 }
01032 if (m_indexSolvent == -1) {
01033 std::cout << "IdealMolalSoln::initThermo: Solvent Name not found"
01034 << std::endl;
01035 throw CanteraError("IdealMolalSoln::initThermo",
01036 "Solvent name not found");
01037 }
01038 if (m_indexSolvent != 0) {
01039 throw CanteraError("IdealMolalSoln::initThermo",
01040 "Solvent " + solventName +
01041 " should be first species");
01042 }
01043
01044
01045
01046
01047
01048 XML_Node& speciesList = phaseNode.child("speciesArray");
01049 XML_Node* speciesDB =
01050 get_XML_NameID("speciesData", speciesList["datasrc"],
01051 &phaseNode.root());
01052 const std::vector<std::string> &sss = speciesNames();
01053
01054 for (int k = 0; k < m_kk; k++) {
01055 XML_Node* s = speciesDB->findByAttr("name", sss[k]);
01056 XML_Node *ss = s->findByName("standardState");
01057 m_speciesMolarVolume[k] = getFloat(*ss, "molarVolume", "toSI");
01058 }
01059
01060 IMS_typeCutoff_ = 2;
01061 if (IMS_typeCutoff_ == 2) {
01062 calcIMSCutoffParams_();
01063 }
01064
01065 MolalityVPSSTP::initThermoXML(phaseNode, id);
01066
01067
01068 setMoleFSolventMin(1.0E-5);
01069
01070
01071
01072 if (phaseNode.hasChild("state")) {
01073 XML_Node& stateNode = phaseNode.child("state");
01074 setStateFromXML(stateNode);
01075 }
01076
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087 void IdealMolalSoln::setParameters(int n, doublereal* const c) {
01088 }
01089
01090 void IdealMolalSoln::getParameters(int &n, doublereal * const c) const {
01091 }
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107 void IdealMolalSoln::setParametersFromXML(const XML_Node& eosdata) {
01108 }
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122 doublereal IdealMolalSoln::err(std::string msg) const {
01123 throw CanteraError("IdealMolalSoln",
01124 "Unfinished func called: " + msg );
01125 return 0.0;
01126 }
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140 void IdealMolalSoln::s_updateIMS_lnMolalityActCoeff() const {
01141 int k;
01142 double tmp;
01143
01144
01145
01146
01147
01148 calcMolalities();
01149
01150 double xmolSolvent = moleFraction(m_indexSolvent);
01151 double xx = MAX(m_xmolSolventMIN, xmolSolvent);
01152
01153 if (IMS_typeCutoff_ == 0) {
01154 for (k = 1; k < m_kk; k++) {
01155 IMS_lnActCoeffMolal_[k]= 0.0;
01156 }
01157 IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
01158 return;
01159 } else if (IMS_typeCutoff_ == 1) {
01160 if (xmolSolvent > 3.0 * IMS_X_o_cutoff_/2.0 ) {
01161 for (k = 1; k < m_kk; k++) {
01162 IMS_lnActCoeffMolal_[k]= 0.0;
01163 }
01164 IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
01165 return;
01166 } else if (xmolSolvent < IMS_X_o_cutoff_/2.0) {
01167 tmp = log(xx * IMS_gamma_k_min_);
01168 for (k = 1; k < m_kk; k++) {
01169 IMS_lnActCoeffMolal_[k]= tmp;
01170 }
01171 IMS_lnActCoeffMolal_[m_indexSolvent] = log(IMS_gamma_o_min_);
01172 return;
01173 } else {
01174
01175
01176
01177
01178 double xminus = xmolSolvent - IMS_X_o_cutoff_/2.0;
01179 double xminus2 = xminus * xminus;
01180 double xminus3 = xminus2 * xminus;
01181 double x_o_cut2 = IMS_X_o_cutoff_ * IMS_X_o_cutoff_;
01182 double x_o_cut3 = x_o_cut2 * IMS_X_o_cutoff_;
01183
01184 double h2 = 3.5 * xminus2 / IMS_X_o_cutoff_ - 2.0 * xminus3 / x_o_cut2;
01185 double h2_prime = 7.0 * xminus / IMS_X_o_cutoff_ - 6.0 * xminus2 / x_o_cut2;
01186
01187 double h1 = (1.0 - 3.0 * xminus2 / x_o_cut2 + 2.0 * xminus3/ x_o_cut3);
01188 double h1_prime = (- 6.0 * xminus / x_o_cut2 + 6.0 * xminus2/ x_o_cut3);
01189
01190 double h1_g = h1 / IMS_gamma_o_min_;
01191 double h1_g_prime = h1_prime / IMS_gamma_o_min_;
01192
01193 double alpha = 1.0 / ( exp(1.0) * IMS_gamma_k_min_);
01194 double h1_f = h1 * alpha;
01195 double h1_f_prime = h1_prime * alpha;
01196
01197 double f = h2 + h1_f;
01198 double f_prime = h2_prime + h1_f_prime;
01199
01200 double g = h2 + h1_g;
01201 double g_prime = h2_prime + h1_g_prime;
01202
01203 tmp = (xmolSolvent/ g * g_prime + (1.0-xmolSolvent) / f * f_prime);
01204 double lngammak = -1.0 - log(f) + tmp * xmolSolvent;
01205 double lngammao =-log(g) - tmp * (1.0-xmolSolvent);
01206
01207 tmp = log(xmolSolvent) + lngammak;
01208 for (k = 1; k < m_kk; k++) {
01209 IMS_lnActCoeffMolal_[k]= tmp;
01210 }
01211 IMS_lnActCoeffMolal_[m_indexSolvent] = lngammao;
01212 }
01213 }
01214
01215
01216 else if (IMS_typeCutoff_ == 2) {
01217 if (xmolSolvent > IMS_X_o_cutoff_) {
01218 for (k = 1; k < m_kk; k++) {
01219 IMS_lnActCoeffMolal_[k]= 0.0;
01220 }
01221 IMS_lnActCoeffMolal_[m_indexSolvent] = - log(xx) + (xx - 1.0)/xx;
01222 return;
01223 } else {
01224
01225 double xoverc = xmolSolvent/IMS_cCut_;
01226 double eterm = std::exp(-xoverc);
01227
01228 double fptmp = IMS_bfCut_ - IMS_afCut_ / IMS_cCut_ - IMS_bfCut_*xoverc
01229 + 2.0*IMS_dfCut_*xmolSolvent - IMS_dfCut_*xmolSolvent*xoverc;
01230 double f_prime = 1.0 + eterm*fptmp;
01231 double f = xmolSolvent + IMS_efCut_ + eterm * (IMS_afCut_ + xmolSolvent * (IMS_bfCut_ + IMS_dfCut_*xmolSolvent));
01232
01233 double gptmp = IMS_bgCut_ - IMS_agCut_ / IMS_cCut_ - IMS_bgCut_*xoverc
01234 + 2.0*IMS_dgCut_*xmolSolvent - IMS_dgCut_*xmolSolvent*xoverc;
01235 double g_prime = 1.0 + eterm*gptmp;
01236 double g = xmolSolvent + IMS_egCut_ + eterm * (IMS_agCut_ + xmolSolvent * (IMS_bgCut_ + IMS_dgCut_*xmolSolvent));
01237
01238 tmp = (xmolSolvent / g * g_prime + (1.0 - xmolSolvent) / f * f_prime);
01239 double lngammak = -1.0 - log(f) + tmp * xmolSolvent;
01240 double lngammao =-log(g) - tmp * (1.0-xmolSolvent);
01241
01242 tmp = log(xx) + lngammak;
01243 for (k = 1; k < m_kk; k++) {
01244 IMS_lnActCoeffMolal_[k]= tmp;
01245 }
01246 IMS_lnActCoeffMolal_[m_indexSolvent] = lngammao;
01247 }
01248 }
01249 return;
01250 }
01251
01252
01253
01254
01255
01256
01257 void IdealMolalSoln::initLengths() {
01258 m_kk = nSpecies();
01259
01260
01261
01262
01263 int leng = m_kk;
01264 m_expg0_RT.resize(leng);
01265 m_pe.resize(leng, 0.0);
01266 m_pp.resize(leng);
01267 m_speciesMolarVolume.resize(leng);
01268 m_tmpV.resize(leng);
01269 IMS_lnActCoeffMolal_.resize(leng);
01270 }
01271
01272
01273 void IdealMolalSoln::calcIMSCutoffParams_() {
01274 IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_);
01275 IMS_efCut_ = 0.0;
01276 bool converged = false;
01277 double oldV = 0.0;
01278 int its;
01279 for (its = 0; its < 100 && !converged; its++) {
01280 oldV = IMS_efCut_;
01281 IMS_afCut_ = 1.0 / (std::exp(1.0) * IMS_gamma_k_min_) - IMS_efCut_;
01282 IMS_bfCut_ = IMS_afCut_ / IMS_cCut_ + IMS_slopefCut_ - 1.0;
01283 IMS_dfCut_ = ((- IMS_afCut_/IMS_cCut_ + IMS_bfCut_ - IMS_bfCut_*IMS_X_o_cutoff_/IMS_cCut_)
01284 /
01285 (IMS_X_o_cutoff_*IMS_X_o_cutoff_/IMS_cCut_ - 2.0 * IMS_X_o_cutoff_));
01286 double tmp = IMS_afCut_ + IMS_X_o_cutoff_*( IMS_bfCut_ + IMS_dfCut_ * IMS_X_o_cutoff_);
01287 double eterm = std::exp(-IMS_X_o_cutoff_/IMS_cCut_);
01288 IMS_efCut_ = - eterm * (tmp);
01289 if (fabs(IMS_efCut_ - oldV) < 1.0E-14) {
01290 converged = true;
01291 }
01292 }
01293 if (!converged) {
01294 throw CanteraError(" IdealMolalSoln::calcCutoffParams_()",
01295 " failed to converge on the f polynomial");
01296 }
01297 converged = false;
01298 double f_0 = IMS_afCut_ + IMS_efCut_;
01299 double f_prime_0 = 1.0 - IMS_afCut_ / IMS_cCut_ + IMS_bfCut_;
01300 IMS_egCut_ = 0.0;
01301 for (its = 0; its < 100 && !converged; its++) {
01302 oldV = IMS_egCut_;
01303 double lng_0 = -log(IMS_gamma_o_min_) - f_prime_0 / f_0;
01304 IMS_agCut_ = exp(lng_0) - IMS_egCut_;
01305 IMS_bgCut_ = IMS_agCut_ / IMS_cCut_ + IMS_slopegCut_ - 1.0;
01306 IMS_dgCut_ = ((- IMS_agCut_/IMS_cCut_ + IMS_bgCut_ - IMS_bgCut_*IMS_X_o_cutoff_/IMS_cCut_)
01307 /
01308 (IMS_X_o_cutoff_*IMS_X_o_cutoff_/IMS_cCut_ - 2.0 * IMS_X_o_cutoff_));
01309 double tmp = IMS_agCut_ + IMS_X_o_cutoff_*( IMS_bgCut_ + IMS_dgCut_ *IMS_X_o_cutoff_);
01310 double eterm = std::exp(-IMS_X_o_cutoff_/IMS_cCut_);
01311 IMS_egCut_ = - eterm * (tmp);
01312 if (fabs(IMS_egCut_ - oldV) < 1.0E-14) {
01313 converged = true;
01314 }
01315 }
01316 if (!converged) {
01317 throw CanteraError(" IdealMolalSoln::calcCutoffParams_()",
01318 " failed to converge on the g polynomial");
01319 }
01320 }
01321
01322 }
01323