00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifndef MAX
00015 #define MAX(x,y) (( (x) > (y) ) ? (x) : (y))
00016 #endif
00017
00018
00019 #include "WaterProps.h"
00020 #include "ctml.h"
00021 #include "PDSS_Water.h"
00022 #include "WaterPropsIAPWS.h"
00023
00024 #include <cmath>
00025
00026 namespace Cantera {
00027
00028
00029
00030
00031
00032 WaterProps::WaterProps():
00033 m_waterIAPWS(0),
00034 m_own_sub(false)
00035 {
00036 m_waterIAPWS = new WaterPropsIAPWS();
00037 m_own_sub = true;
00038 }
00039
00040
00041
00042
00043
00044 WaterProps::WaterProps(PDSS_Water *wptr) :
00045 m_waterIAPWS(0),
00046 m_own_sub(false)
00047 {
00048 if (wptr) {
00049 m_waterIAPWS = wptr->getWater();
00050 m_own_sub = false;
00051 } else {
00052 m_waterIAPWS = new WaterPropsIAPWS();
00053 m_own_sub = true;
00054 }
00055 }
00056
00057 WaterProps::WaterProps(WaterPropsIAPWS *waterIAPWS) :
00058 m_waterIAPWS(0),
00059 m_own_sub(false)
00060 {
00061 if (waterIAPWS) {
00062 m_waterIAPWS = waterIAPWS;
00063 m_own_sub = false;
00064 } else {
00065 m_waterIAPWS = new WaterPropsIAPWS();
00066 m_own_sub = true;
00067 }
00068 }
00069
00070
00071
00072
00073 WaterProps::WaterProps(const WaterProps &b) :
00074 m_waterIAPWS(0),
00075 m_own_sub(false)
00076 {
00077 *this = b;
00078 }
00079
00080
00081
00082
00083 WaterProps::~WaterProps() {
00084 if (m_own_sub) {
00085 delete m_waterIAPWS;
00086 }
00087 }
00088
00089
00090
00091
00092 WaterProps& WaterProps::operator=(const WaterProps&b) {
00093 if (&b == this) return *this;
00094
00095 if (m_own_sub) {
00096 if (m_waterIAPWS) {
00097 delete m_waterIAPWS;
00098 m_waterIAPWS = 0;
00099 }
00100 }
00101 if (b.m_own_sub) {
00102 m_waterIAPWS = new WaterPropsIAPWS();
00103 m_own_sub = true;
00104 } else {
00105 m_waterIAPWS = b.m_waterIAPWS;
00106 m_own_sub = false;
00107 }
00108
00109 return *this;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 doublereal WaterProps::density_T(doublereal T, doublereal P, int ifunc) {
00134 doublereal Tc = T - 273.15;
00135 const doublereal U1 = 288.9414;
00136 const doublereal U2 = 508929.2;
00137 const doublereal U3 = 68.12963;
00138 const doublereal U4 = -3.9863;
00139
00140 doublereal tmp1 = Tc + U1;
00141 doublereal tmp4 = Tc + U4;
00142 doublereal t4t4 = tmp4 * tmp4;
00143 doublereal tmp3 = Tc + U3;
00144 doublereal rho = 1000. * (1.0 - tmp1*t4t4/(U2 * tmp3));
00145
00146
00147
00148
00149
00150
00151 doublereal rhomin = P / (GasConstant * T);
00152 if (rho < rhomin) {
00153 rho = rhomin;
00154 if (ifunc == 1) {
00155 doublereal drhodT = - rhomin / T;
00156 return drhodT;
00157 } else if (ifunc == 3) {
00158 doublereal drhodP = rhomin / P;
00159 return drhodP;
00160 } else if (ifunc == 2) {
00161 doublereal d2rhodT2 = 2.0 * rhomin / (T * T);
00162 return d2rhodT2;
00163 }
00164 }
00165
00166 if (ifunc == 1) {
00167 doublereal drhodT = 1000./U2 * (
00168 - tmp4 * tmp4 / (tmp3)
00169 - tmp1 * 2 * tmp4 / (tmp3)
00170 + tmp1 * t4t4 / (tmp3*tmp3)
00171 );
00172 return drhodT;
00173 } else if (ifunc == 3) {
00174 return 0.0;
00175 } else if (ifunc == 2) {
00176 doublereal t3t3 = tmp3 * tmp3;
00177 doublereal d2rhodT2 = 1000./U2 *
00178 ((-4.0*tmp4-2.0*tmp1)/tmp3 +
00179 (2.0*t4t4 + 4.0*tmp1*tmp4)/t3t3
00180 - 2.0*tmp1 * t4t4/(t3t3*tmp3));
00181 return d2rhodT2;
00182 }
00183
00184 return rho;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 doublereal WaterProps::relEpsilon(doublereal T, doublereal P_pascal,
00219 int ifunc) {
00220 const doublereal U1 = 3.4279E2;
00221 const doublereal U2 = -5.0866E-3;
00222 const doublereal U3 = 9.4690E-7;
00223 const doublereal U4 = -2.0525;
00224 const doublereal U5 = 3.1159E3;
00225 const doublereal U6 = -1.8289E2;
00226 const doublereal U7 = -8.0325E3;
00227 const doublereal U8 = 4.2142E6;
00228 const doublereal U9 = 2.1417;
00229 doublereal T2 = T * T;
00230
00231 doublereal eps1000 = U1 * exp(U2 * T + U3 * T2);
00232 doublereal C = U4 + U5/(U6 + T);
00233 doublereal B = U7 + U8/T + U9 * T;
00234
00235 doublereal Pbar = P_pascal * 1.0E-5;
00236 doublereal tmpBpar = B + Pbar;
00237 doublereal tmpB1000 = B + 1000.0;
00238 doublereal ltmp = log(tmpBpar/tmpB1000);
00239 doublereal epsRel = eps1000 + C * ltmp;
00240
00241 if (ifunc == 1 || ifunc == 2) {
00242 doublereal tmpC = U6 + T;
00243 doublereal dCdT = - U5/(tmpC * tmpC);
00244
00245 doublereal dBdT = - U8/(T * T) + U9;
00246
00247 doublereal deps1000dT = eps1000 * (U2 + 2.0 * U3 * T);
00248
00249 doublereal dltmpdT = (dBdT/tmpBpar - dBdT/tmpB1000);
00250 if (ifunc == 1) {
00251 doublereal depsReldT = deps1000dT + dCdT * ltmp + C * dltmpdT;
00252 return depsReldT;
00253 }
00254 doublereal T3 = T2 * T;
00255 doublereal d2CdT2 = - 2.0 * dCdT / tmpC;
00256 doublereal d2BdT2 = 2.0 * U8 / (T3);
00257
00258 doublereal d2ltmpdT2 = (d2BdT2*(1.0/tmpBpar - 1.0/tmpB1000) +
00259 dBdT*dBdT*(1.0/(tmpB1000*tmpB1000) - 1.0/(tmpBpar*tmpBpar)));
00260
00261 doublereal d2eps1000dT2 = (deps1000dT * (U2 + 2.0 * U3 * T) + eps1000 * (2.0 * U3));
00262
00263 if (ifunc == 2) {
00264 doublereal d2epsReldT2 = (d2eps1000dT2 + d2CdT2 * ltmp + 2.0 * dCdT * dltmpdT
00265 + C * d2ltmpdT2);
00266 return d2epsReldT2;
00267 }
00268 }
00269 if (ifunc == 3) {
00270 doublereal dltmpdP = 1.0E-5 / tmpBpar;
00271 doublereal depsReldP = C * dltmpdP;
00272 return depsReldP;
00273 }
00274
00275 return epsRel;
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 doublereal WaterProps::ADebye(doublereal T, doublereal P_input, int ifunc) {
00322 const doublereal e = 1.60217653E-19;
00323 const doublereal epsilon0 = 8.854187817E-12;
00324 const doublereal R = 8.314472E3;
00325 doublereal psat = satPressure(T);
00326 doublereal P;
00327 if (psat > P_input) {
00328
00329
00330 P = psat;
00331 } else {
00332 P = P_input;
00333 }
00334 doublereal epsRelWater = relEpsilon(T, P, 0);
00335
00336
00337 const doublereal Na = 6.0221415E26;
00338
00339 doublereal epsilon = epsilon0 * epsRelWater;
00340 doublereal dw = density_IAPWS(T, P);
00341 doublereal tmp = sqrt( 2.0 * Na * dw / 1000.);
00342 doublereal tmp2 = e * e * Na / (epsilon * R * T);
00343 doublereal tmp3 = tmp2 * sqrt(tmp2);
00344 doublereal A_Debye = tmp * tmp3 / (8.0 * Pi);
00345
00346
00347
00348
00349
00350
00351
00352 if (ifunc == 1 || ifunc == 2) {
00353 doublereal dAdT = - 1.5 * A_Debye / T;
00354
00355 doublereal depsRelWaterdT = relEpsilon(T, P, 1);
00356 dAdT -= A_Debye * (1.5 * depsRelWaterdT / epsRelWater);
00357
00358
00359
00360
00361
00362
00363
00364
00365 doublereal cte = coeffThermalExp_IAPWS(T, P);
00366 doublereal contrib2 = - A_Debye * (0.5 * cte);
00367
00368
00369 dAdT += contrib2;
00370
00371 #ifdef DEBUG_HKM
00372
00373
00374 #endif
00375
00376 if (ifunc == 1) {
00377 return dAdT;
00378 }
00379
00380 if (ifunc == 2) {
00381
00382
00383
00384
00385
00386 doublereal d2AdT2 = 1.5 / T * (A_Debye/T - dAdT);
00387
00388 doublereal d2epsRelWaterdT2 = relEpsilon(T, P, 2);
00389
00390
00391
00392
00393
00394
00395
00396
00397 d2AdT2 += 1.5 * (- dAdT * depsRelWaterdT / epsRelWater
00398 - A_Debye / epsRelWater *
00399 (d2epsRelWaterdT2 - depsRelWaterdT * depsRelWaterdT / epsRelWater));
00400
00401 doublereal deltaT = -0.1;
00402 doublereal Tdel = T + deltaT;
00403 doublereal cte_del = coeffThermalExp_IAPWS(Tdel, P);
00404 doublereal dctedT = (cte_del - cte) / Tdel;
00405
00406
00407
00408
00409 doublereal contrib3 = 0.5 * ( -(dAdT * cte) -(A_Debye * dctedT));
00410 d2AdT2 += contrib3;
00411
00412 return d2AdT2;
00413 }
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 if (ifunc == 3) {
00428
00429 doublereal dAdP = 0.0;
00430
00431 doublereal depsRelWaterdP = relEpsilon(T, P, 3);
00432 dAdP -= A_Debye * (1.5 * depsRelWaterdP / epsRelWater);
00433
00434 doublereal kappa = isothermalCompressibility_IAPWS(T,P);
00435
00436
00437 dAdP += A_Debye * (0.5 * kappa);
00438
00439 return dAdP;
00440 }
00441
00442 return A_Debye;
00443 }
00444
00445 doublereal WaterProps::satPressure(doublereal T) {
00446 doublereal pres = m_waterIAPWS->psat(T);
00447 return pres;
00448 }
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 doublereal WaterProps::density_IAPWS(doublereal temp, doublereal press) {
00459 doublereal dens = m_waterIAPWS->density(temp, press, WATER_LIQUID);
00460 return dens;
00461 }
00462
00463
00464
00465
00466
00467
00468 doublereal WaterProps::density_IAPWS() const {
00469 doublereal dens = m_waterIAPWS->density();
00470 return dens;
00471 }
00472
00473 doublereal WaterProps::coeffThermalExp_IAPWS(doublereal temp, doublereal press) {
00474 doublereal dens = m_waterIAPWS->density(temp, press, WATER_LIQUID);
00475 if (dens < 0.0) {
00476 throw CanteraError("WaterProps::coeffThermalExp_IAPWS",
00477 "Unable to solve for density at T = " + fp2str(temp) + " and P = " + fp2str(press));
00478 }
00479 doublereal cte = m_waterIAPWS->coeffThermExp();
00480 return cte;
00481 }
00482
00483 doublereal WaterProps::isothermalCompressibility_IAPWS(doublereal temp, doublereal press) {
00484 doublereal dens = m_waterIAPWS->density(temp, press, WATER_LIQUID);
00485 if (dens < 0.0) {
00486 throw CanteraError("WaterProps::isothermalCompressibility_IAPWS",
00487 "Unable to solve for density at T = " + fp2str(temp) + " and P = " + fp2str(press));
00488 }
00489 doublereal kappa = m_waterIAPWS->isothermalCompressibility();
00490 return kappa;
00491 }
00492
00493
00494
00495
00496
00497
00498
00499
00500 const doublereal H[4] = {1.,
00501 0.978197,
00502 0.579829,
00503 -0.202354};
00504
00505 const doublereal Hij[6][7] =
00506 {
00507 { 0.5132047, 0.2151778, -0.2818107, 0.1778064, -0.04176610, 0., 0.},
00508 { 0.3205656, 0.7317883, -1.070786 , 0.4605040, 0., -0.01578386, 0.},
00509 { 0., 1.241044 , -1.263184 , 0.2340379, 0., 0., 0.},
00510 { 0., 1.476783 , 0., -0.4924179, 0.1600435, 0., -0.003629481},
00511 {-0.7782567, 0.0 , 0., 0. , 0., 0., 0.},
00512 { 0.1885447, 0.0 , 0., 0. , 0., 0., 0.},
00513 };
00514 const doublereal TStar = 647.27;
00515 const doublereal rhoStar = 317.763;
00516 const doublereal presStar = 22.115E6;
00517 const doublereal muStar = 55.071E-6;
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 doublereal WaterProps::viscosityWater() const {
00537
00538 doublereal temp = m_waterIAPWS->temperature();
00539 doublereal dens = m_waterIAPWS->density();
00540
00541
00542
00543
00544
00545
00546
00547
00548 doublereal rhobar = dens/rhoStar;
00549 doublereal tbar = temp / TStar;
00550
00551
00552 doublereal tbar2 = tbar * tbar;
00553 doublereal tbar3 = tbar2 * tbar;
00554
00555 doublereal mu0bar = std::sqrt(tbar) / (H[0] + H[1]/tbar + H[2]/tbar2 + H[3]/tbar3);
00556
00557
00558
00559
00560 doublereal tfac1 = 1.0 / tbar - 1.0;
00561 doublereal tfac2 = tfac1 * tfac1;
00562 doublereal tfac3 = tfac2 * tfac1;
00563 doublereal tfac4 = tfac3 * tfac1;
00564 doublereal tfac5 = tfac4 * tfac1;
00565
00566 doublereal rfac1 = rhobar - 1.0;
00567 doublereal rfac2 = rfac1 * rfac1;
00568 doublereal rfac3 = rfac2 * rfac1;
00569 doublereal rfac4 = rfac3 * rfac1;
00570 doublereal rfac5 = rfac4 * rfac1;
00571 doublereal rfac6 = rfac5 * rfac1;
00572
00573 doublereal sum = (Hij[0][0] + Hij[1][0]*tfac1 + Hij[4][0]*tfac4 + Hij[5][0]*tfac5 +
00574 Hij[0][1]*rfac1 + Hij[1][1]*tfac1*rfac1 + Hij[2][1]*tfac2*rfac1 + Hij[3][1]*tfac3*rfac1 +
00575 Hij[0][2]*rfac2 + Hij[1][2]*tfac1*rfac2 + Hij[2][2]*tfac2*rfac2 +
00576 Hij[0][3]*rfac3 + Hij[1][3]*tfac1*rfac3 + Hij[2][3]*tfac2*rfac3 + Hij[3][3]*tfac3*rfac3 +
00577 Hij[0][4]*rfac4 + Hij[3][4]*tfac3*rfac4 +
00578 Hij[1][5]*tfac1*rfac5 + Hij[3][6]*tfac3*rfac6
00579 );
00580 doublereal mu1bar = std::exp(rhobar * sum);
00581
00582
00583 doublereal mu2bar = 1.0;
00584 if ((tbar >= 0.9970) && tbar <= 1.0082) {
00585 if ((rhobar >= 0.755) && (rhobar <= 1.290)) {
00586 doublereal drhodp = 1.0 / m_waterIAPWS->dpdrho();
00587 drhodp *= presStar / rhoStar;
00588 doublereal xsi = rhobar * drhodp;
00589 if (xsi >= 21.93) {
00590 mu2bar = 0.922 * std::pow(xsi, 0.0263);
00591 }
00592 }
00593 }
00594
00595 doublereal mubar = mu0bar * mu1bar * mu2bar;
00596
00597 return mubar * muStar;
00598 }
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615 doublereal WaterProps::thermalConductivityWater() const {
00616 static const doublereal Tstar = 647.27;
00617 static const doublereal rhostar = 317.763;
00618 static const doublereal lambdastar = 0.4945;
00619 static const doublereal presstar = 22.115E6;
00620 static const doublereal L[4] =
00621 {
00622 1.0000,
00623 6.978267,
00624 2.599096,
00625 -0.998254
00626 };
00627 static const doublereal Lji[6][5] =
00628 {
00629 { 1.3293046, 1.7018363, 5.2246158, 8.7127675, -1.8525999},
00630 {-0.40452437, -2.2156845, -10.124111, -9.5000611, 0.93404690},
00631 { 0.24409490, 1.6511057, 4.9874687, 4.3786606, 0.0},
00632 { 0.018660751, -0.76736002, -0.27297694, -0.91783782, 0.0},
00633 {-0.12961068, 0.37283344, -0.43083393, 0.0, 0.0},
00634 { 0.044809953, -0.11203160, 0.13333849, 0.0, 0.0},
00635 };
00636
00637 doublereal temp = m_waterIAPWS->temperature();
00638 doublereal dens = m_waterIAPWS->density();
00639
00640 doublereal rhobar = dens/rhostar;
00641 doublereal tbar = temp / Tstar;
00642 doublereal tbar2 = tbar * tbar;
00643 doublereal tbar3 = tbar2 * tbar;
00644 doublereal lambda0bar = sqrt(tbar) / (L[0] + L[1]/tbar + L[2]/tbar2 + L[3]/tbar3);
00645
00646
00647
00648 doublereal tfac1 = 1.0 / tbar - 1.0;
00649 doublereal tfac2 = tfac1 * tfac1;
00650 doublereal tfac3 = tfac2 * tfac1;
00651 doublereal tfac4 = tfac3 * tfac1;
00652
00653 doublereal rfac1 = rhobar - 1.0;
00654 doublereal rfac2 = rfac1 * rfac1;
00655 doublereal rfac3 = rfac2 * rfac1;
00656 doublereal rfac4 = rfac3 * rfac1;
00657 doublereal rfac5 = rfac4 * rfac1;
00658
00659 doublereal sum = (Lji[0][0] + Lji[0][1]*tfac1 + Lji[0][2]*tfac2 + Lji[0][3]*tfac3 + Lji[0][4]*tfac4 +
00660 Lji[1][0]*rfac1 + Lji[1][1]*tfac1*rfac1 + Lji[1][2]*tfac2*rfac1 + Lji[1][3]*tfac3*rfac1 + Lji[1][4]*tfac4*rfac1 +
00661 Lji[2][0]*rfac2 + Lji[2][1]*tfac1*rfac2 + Lji[2][2]*tfac2*rfac2 + Lji[2][3]*tfac3*rfac2 +
00662 Lji[3][0]*rfac3 + Lji[3][1]*tfac1*rfac3 + Lji[3][2]*tfac2*rfac3 + Lji[3][3]*tfac3*rfac3 +
00663 Lji[4][0]*rfac4 + Lji[4][1]*tfac1*rfac4 + Lji[4][2]*tfac2*rfac4 +
00664 Lji[5][0]*rfac5 + Lji[5][1]*tfac1*rfac5 + Lji[5][2]*tfac2*rfac5
00665 );
00666 doublereal lambda1bar = exp(rhobar * sum);
00667
00668 doublereal mu0bar = std::sqrt(tbar) / (H[0] + H[1]/tbar + H[2]/tbar2 + H[3]/tbar3);
00669
00670 doublereal tfac5 = tfac4 * tfac1;
00671 doublereal rfac6 = rfac5 * rfac1;
00672
00673 sum = (Hij[0][0] + Hij[1][0]*tfac1 + Hij[4][0]*tfac4 + Hij[5][0]*tfac5 +
00674 Hij[0][1]*rfac1 + Hij[1][1]*tfac1*rfac1 + Hij[2][1]*tfac2*rfac1 + Hij[3][1]*tfac3*rfac1 +
00675 Hij[0][2]*rfac2 + Hij[1][2]*tfac1*rfac2 + Hij[2][2]*tfac2*rfac2 +
00676 Hij[0][3]*rfac3 + Hij[1][3]*tfac1*rfac3 + Hij[2][3]*tfac2*rfac3 + Hij[3][3]*tfac3*rfac3 +
00677 Hij[0][4]*rfac4 + Hij[3][4]*tfac3*rfac4 +
00678 Hij[1][5]*tfac1*rfac5 + Hij[3][6]*tfac3*rfac6
00679 );
00680 doublereal mu1bar = std::exp(rhobar * sum);
00681
00682 doublereal t2r2 = tbar * tbar / (rhobar * rhobar);
00683 doublereal drhodp = 1.0 / m_waterIAPWS->dpdrho();
00684 drhodp *= presStar / rhoStar;
00685 doublereal xsi = rhobar * drhodp;
00686 doublereal xsipow = std::pow(xsi, 0.4678);
00687 doublereal rho1 = rhobar - 1.;
00688 doublereal rho2 = rho1 * rho1;
00689 doublereal rho4 = rho2 * rho2;
00690 doublereal temp2 = (tbar - 1.0) * (tbar - 1.0);
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700 doublereal beta = m_waterIAPWS->coeffPresExp();
00701
00702 doublereal dpdT_const_rho = beta * GasConstant * dens / 18.015268;
00703 dpdT_const_rho *= Tstar / presstar;
00704
00705 doublereal lambda2bar = 0.0013848 / (mu0bar * mu1bar) * t2r2 * dpdT_const_rho * dpdT_const_rho *
00706 xsipow * sqrt(rhobar) * exp(-18.66*temp2 - rho4);
00707
00708 doublereal lambda = ( lambda0bar * lambda1bar + lambda2bar) * lambdastar;
00709 return lambda;
00710 }
00711
00712
00713 }