From 877916ddd25406ecc725e90b79cbda4525723cca Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Fri, 8 Dec 2023 11:16:13 -0500 Subject: [PATCH 1/9] Script to generate cvr/R values with extended precision --- src/tests/catch_test_multifluid.cxx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/tests/catch_test_multifluid.cxx b/src/tests/catch_test_multifluid.cxx index c335b3cc..66c4785c 100644 --- a/src/tests/catch_test_multifluid.cxx +++ b/src/tests/catch_test_multifluid.cxx @@ -14,6 +14,11 @@ using Catch::Approx; #include "teqp/cpp/deriv_adapter.hpp" #include "teqp/filesystem.hpp" #include "teqp/ideal_eosterms.hpp" +#include "teqp/math/finite_derivs.hpp" + +// Imports from boost +#include +using namespace boost::multiprecision; using namespace teqp; using multifluid_t = decltype(build_multifluid_model({""}, "")); @@ -510,3 +515,23 @@ TEST_CASE("Check models for R", "[multifluidR]") { CHECK(model_->get_R(z) == 8.31446261815324); } } + +TEST_CASE("Ar20 for CO2", "[Ar20CO2]"){ + double rho = 11000; + auto z = (Eigen::ArrayXd(1) << 1.0).finished(); + + using my_float = boost::multiprecision::number>; // Overkill: 200 digits of working precision! + auto model = build_multifluid_model({"CO2"}, "../mycp"); + + auto f = [&rho, &z, &model](const auto Trecip){ return model.alphar(1.0/Trecip, rho, z); }; + using tdx = TDXDerivatives; + + std::cout << std::setprecision(20); + for (double T = 304.2; T < 340; T += 0.05){ + my_float Trecip = 1.0/T; + my_float h = 1e-20; + auto mp = -teqp::centered_diff<2,6>(f, Trecip, h)*Trecip*Trecip; // cvr/R + auto ad = -tdx::get_Ar20(model, T, rho, z); + std::cout << T << "," << mp << "," << mp/ad-1 << std::endl; + } +} From 3e6f58ad1bad1ce2f2316e9fb0cca08e5f8091c8 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Sun, 10 Dec 2023 10:27:08 -0500 Subject: [PATCH 2/9] Add GERG-2004 implementation for residual --- include/teqp/models/GERG/GERG.hpp | 741 ++++++++++++++++++++++++++++++ src/tests/catch_test_GERG2004.cpp | 45 ++ 2 files changed, 786 insertions(+) create mode 100644 include/teqp/models/GERG/GERG.hpp create mode 100644 src/tests/catch_test_GERG2004.cpp diff --git a/include/teqp/models/GERG/GERG.hpp b/include/teqp/models/GERG/GERG.hpp new file mode 100644 index 00000000..baa9fa84 --- /dev/null +++ b/include/teqp/models/GERG/GERG.hpp @@ -0,0 +1,741 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "teqp/math/pow_templates.hpp" +#include "Eigen/Dense" + +namespace teqp{ + +namespace GERG2004{ + +const std::vector component_names = {"methane", "nitrogen","carbondioxide","ethane","propane","n-butane","isobutane","n-pentane","isopentane","n-hexane","n-heptane","n-octane","hydrogen", "oxygen","carbonmonoxide","water","helium","argon"}; + +struct PureInfo{ + double rhoc_molm3, Tc_K, M_kgmol; +}; + +/// Get the pure fluid information for a fluid from GERG-2004 monograph +PureInfo get_pure_info(const std::string& name){ + + // From Table A3.5 from GERG 2004 monograph + // Data are in mol/dm3, K, kg/mol + static std::map data_map = { + {"methane", {10.139342719,190.564000000,16.042460}}, + {"nitrogen", {11.183900000,126.192000000,28.013400}}, + {"carbondioxide", {10.624978698,304.128200000,44.009500}}, + {"ethane", {6.870854540,305.322000000,30.069040}}, + {"propane", {5.000043088,369.825000000,44.095620}}, + {"n-butane", {3.920016792,425.125000000,58.122200}}, + {"isobutane", {3.860142940,407.817000000,58.122200}}, + {"n-pentane", {3.215577588,469.700000000,72.148780}}, + {"isopentane", {3.271018581,460.350000000,72.148780}}, + {"n-hexane", {2.705877875,507.820000000,86.175360}}, + {"n-heptane", {2.315324434,540.130000000,100.201940}}, + {"n-octane", {2.056404127,569.320000000,114.228520}}, + {"hydrogen", {14.940000000,33.190000000 ,2.015880}}, + {"oxygen", {13.630000000,154.595000000,31.998800}}, + {"carbonmonoxide", {10.850000000,132.800000000,28.010100}}, + {"water", {17.873716090,647.096000000,18.015280}}, + {"helium", {17.399000000,5.195300000,4.002602}}, + {"argon", {13.407429659,150.687000000,39.948000}} + }; + auto data = data_map.at(name); + data.rhoc_molm3 *= 1000; // mol/dm^3 -> mol/m^3 + data.M_kgmol /= 1000; // kg/kmol -> kg/mol + return data; +} + +struct PureCoeffs{ + std::vector n, t, d, c, l; + std::set sizes(){ return {n.size(), t.size(), d.size(), c.size(), l.size()}; } +}; + +PureCoeffs get_pure_coeffs(const std::string& fluid){ + + // From Table A3.2 from GERG 2004 monograph + static std::map> n_dict_mne = { + {"methane", {0.57335704239162,-0.16760687523730e1,0.23405291834916,-0.21947376343441,0.16369201404128e-1,0.15004406389280e-1,0.98990489492918e-1,0.58382770929055,-0.74786867560390,0.30033302857974,0.20985543806568,-0.18590151133061e-1,-0.15782558339049,0.12716735220791,-0.32019743894346e-1,-0.68049729364536e-1,0.24291412853736e-1,0.51440451639444e-2,-0.19084949733532e-1,0.55229677241291e-2,-0.44197392976085e-2,0.40061416708429e-1,-0.33752085907575e-1,-0.25127658213357e-2}}, + {"nitrogen", { 0.59889711801201,-0.16941557480731e1,0.24579736191718,-0.23722456755175,0.17954918715141e-1,0.14592875720215e-1,0.10008065936206,0.73157115385532,-0.88372272336366,0.31887660246708,0.20766491728799,-0.19379315454158e-1,-0.16936641554983,0.13546846041701,-0.33066712095307e-1,-0.60690817018557e-1,0.12797548292871e-1,0.58743664107299e-2,-0.18451951971969e-1,0.47226622042472e-2,-0.52024079680599e-2,0.43563505956635e-1,-0.36251690750939e-1,-0.28974026866543e-2}}, + {"ethane", { 0.63596780450714,-0.17377981785459e1,0.28914060926272,-0.33714276845694,0.22405964699561e-1,0.15715424886913e-1,0.11450634253745,0.10612049379745e1,-0.12855224439423e1,0.39414630777652,0.31390924682041,-0.21592277117247e-1,-0.21723666564905,-0.28999574439489,0.42321173025732,0.46434100259260e-1,-0.13138398329741,0.11492850364368e-1,-0.33387688429909e-1,0.15183171583644e-1,-0.47610805647657e-2,0.46917166277885e-1,-0.39401755804649e-1,-0.32569956247611e-2}} + }; + + static std::map> n_dict_main = { + {"propane", {0.10403973107358e1,-0.28318404081403e1,0.84393809606294,-0.76559591850023e-1,0.94697373057280e-1,0.24796475497006e-3,0.27743760422870,-0.43846000648377e-1,-0.26991064784350,-0.69313413089860e-1,-0.29632145981653e-1,0.14040126751380e-1}}, + {"n-butane", { 0.10626277411455e1,-0.28620951828350e1,0.88738233403777,-0.12570581155345,0.10286308708106,0.25358040602654e-3,0.32325200233982,-0.37950761057432e-1,-0.32534802014452,-0.79050969051011e-1,-0.20636720547775e-1,0.57053809334750e-2}}, + {"isobutane", {0.10429331589100e1,-0.28184272548892e1,0.86176232397850,-0.10613619452487,0.98615749302134e-1,0.23948208682322e-3,0.30330004856950,-0.41598156135099e-1,-0.29991937470058,-0.80369342764109e-1,-0.29761373251151e-1,0.13059630303140e-1}}, + {"n-pentane", {0.10968643098001e1,-0.29988888298061e1,0.99516886799212,-0.16170708558539,0.11334460072775,0.26760595150748e-3,0.40979881986931,-0.40876423083075e-1,-0.38169482469447,-0.10931956843993,-0.32073223327990e-1,0.16877016216975e-1}}, + {"isopentane", {0.11017531966644e1,-0.30082368531980e1,0.99411904271336,-0.14008636562629,0.11193995351286,0.29548042541230e-3,0.36370108598133,-0.48236083488293e-1,-0.35100280270615,-0.10185043812047,-0.35242601785454e-1,0.19756797599888e-1}}, + {"n-hexane", {0.10553238013661e1,-0.26120615890629e1,0.76613882967260,-0.29770320622459,0.11879907733358,0.27922861062617e-3,0.46347589844105,0.11433196980297e-1,-0.48256968738131,-0.93750558924659e-1,-0.67273247155994e-2,-0.51141583585428e-2}}, + {"n-heptane", {0.10543747645262e1,-0.26500681506144e1,0.81730047827543,-0.30451391253428,0.12253868710800,0.27266472743928e-3,0.49865825681670,-0.71432815084176e-3,-0.54236895525450,-0.13801821610756,-0.61595287380011e-2,0.48602510393022e-3}}, + {"n-octane", {0.10722544875633e1,-0.24632951172003e1,0.65386674054928,-0.36324974085628,0.12713269626764,0.30713572777930e-3,0.52656856987540,0.19362862857653e-1,-0.58939426849155,-0.14069963991934,-0.78966330500036e-2,0.33036597968109e-2}}, + {"oxygen", { 0.88878286369701,-0.24879433312148e1,0.59750190775886,0.96501817061881e-2,0.71970428712770e-1,0.22337443000195e-3,0.18558686391474,-0.38129368035760e-1,-0.15352245383006,-0.26726814910919e-1,-0.25675298677127e-1,0.95714302123668e-2}}, + {"carbonmonoxide", {0.92310041400851,-0.24885845205800e1,0.58095213783396,0.28859164394654e-1,0.70256257276544e-1,0.21687043269488e-3,0.13758331015182,-0.51501116343466e-1,-0.14865357483379,-0.38857100886810e-1,-0.29100433948943e-1,0.14155684466279e-1}}, + {"argon", {0.85095714803969,-0.24003222943480e1,0.54127841476466,0.16919770692538e-1,0.68825965019035e-1,0.21428032815338e-3,0.17429895321992,-0.33654495604194e-1,-0.13526799857691,-0.16387350791552e-1,-0.24987666851475e-1,0.88769204815709e-2}} + }; + + if (n_dict_main.find(fluid) != n_dict_main.end()){ + PureCoeffs pc; + pc.n = n_dict_main[fluid], + pc.t = {0.250,1.125,1.500,1.375,0.250,0.875,0.625,1.750,3.625,3.625,14.500,12.000}; + pc.d = {1,1,1,2,3,7,2,5,1,4,3,4}; + pc.c = {0,0,0,0,0,0,1,1,1,1,1,1}; + pc.l = {0,0,0,0,0,0,1,1,2,2,3,3}; + return pc; + } + else if (n_dict_mne.find(fluid) != n_dict_mne.end()){ + PureCoeffs pc; + pc.n = n_dict_mne.at(fluid); + pc.t = {0.125,1.125,0.375,1.125,0.625,1.500,0.625,2.625,2.750,2.125,2.000,1.750,4.500,4.750,5.000,4.000,4.500,7.500,14.000,11.500,26.000,28.000,30.000,16.000}; + pc.d = {1,1,2,2,4,4,1,1,1,2,3,6,2,3,3,4,4,2,3,4,5,6,6,7}; + pc.c = {0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + pc.l = {0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,3,3,3,6,6,6,6}; + return pc; + } + else if (fluid == "carbondioxide"){ + PureCoeffs pc; + pc.n = {0.52646564804653,-0.14995725042592e1, 0.27329786733782, 0.12949500022786, 0.15404088341841,-0.58186950946814,-0.18022494838296,-0.95389904072812e-1,-0.80486819317679e-2,-0.35547751273090e-1,-0.28079014882405,-0.82435890081677e-1, 0.10832427979006e-1,-0.67073993161097e-2,-0.46827907600524e-2,-0.28359911832177e-1, 0.19500174744098e-1,-0.21609137507166, 0.43772794926972,-0.22130790113593, 0.15190189957331e-1,-0.15380948953300e-1}; + pc.t = {0.000,1.250,1.625,0.375,0.375,1.375,1.125,1.375,0.125,1.625,3.750,3.500,7.500,8.000,6.000,16.000,11.000,24.000,26.000,28.000,24.000,26.000}; + pc.d = {1,1,2,3,3,3,4,5,6,6,1,4,1,1,3,3,4,5,5,5,5,5}; + pc.c = {0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + pc.l = {0,0,0,0,1,1,1,1,1,1,2,2,3,3,3,3,3,5,5,5,6,6}; + return pc; + } + else if (fluid == "hydrogen"){ + PureCoeffs pc; + pc.n = {0.53579928451252e1,-0.62050252530595e1, 0.13830241327086,-0.71397954896129e-1, 0.15474053959733e-1,-0.14976806405771,-0.26368723988451e-1, 0.56681303156066e-1,-0.60063958030436e-1,-0.45043942027132, 0.42478840244500,-0.21997640827139e-1,-0.10499521374530e-1,-0.28955902866816e-2}; + pc.t = {0.500,0.625,0.375,0.625,1.125,2.625,0.000,0.250,1.375,4.000,4.250,5.000,8.000,8.000}; + pc.d = {1,1,2,2,4,1,5,5,5,1,1,2,5,1}; + pc.c = {0,0,0,0,0,1,1,1,1,1,1,1,1,1}; + pc.l = {0,0,0,0,0,1,1,1,1,2,2,3,3,5}; + return pc; + } + else if (fluid == "water"){ + PureCoeffs pc; + pc.n = {0.82728408749586,-0.18602220416584e1,-0.11199009613744e1,0.15635753976056,0.87375844859025,-0.36674403715731,0.53987893432436e-1,0.10957690214499e1,0.53213037828563e-1,0.13050533930825e-1,-0.41079520434476,0.14637443344120,-0.55726838623719e-1,-0.11201774143800e-1,-0.66062758068099e-2,0.46918522004538e-2}; + pc.t = {0.500,1.250,1.875,0.125,1.500,1.000,0.750,1.500,0.625,2.625,5.000,4.000,4.500,3.000,4.000,6.000}; + pc.d = {1,1,1,2,2,3,4,1,5,5,1,2,4,4,1,1}; + pc.c = {0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1}; + pc.l = {0,0,0,0,0,0,0,1,1,1,2,2,2,3,5,5}; + return pc; + } + else if (fluid == "helium"){ + PureCoeffs pc; + pc.n = {-0.45579024006737,0.12516390754925e1,-0.15438231650621e1,0.20467489707221e-1,-0.34476212380781,-0.20858459512787e-1,0.16227414711778e-1,-0.57471818200892e-1,0.19462416430715e-1,-0.33295680123020e-1,-0.10863577372367e-1,-0.22173365245954e-1}; + pc.t = {0.000,0.125,0.750,1.000,0.750,2.625,0.125,1.250,2.000,1.000,4.500,5.000}; + pc.d = {1,1,1,4,1,3,5,5,5,2,1,2}; + pc.c = {0,0,0,0,1,1,1,1,1,1,1,1}; + pc.l = {0,0,0,0,1,1,1,1,1,2,3,3}; + return pc; + } + else{ + throw std::invalid_argument("unable to load pure coefficients for " + fluid); + } +} + +struct BetasGammas { + double betaT, gammaT, betaV, gammaV; +}; + +BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2){ + + // From Table A3.8 of GERG 2004 monograph + std::map,BetasGammas> BIP_data = { + {{"methane","nitrogen"}, {0.998721377,1.013950311,0.998098830,0.979273013}}, + {{"methane","carbondioxide"}, {0.999518072,1.002806594,1.022624490,0.975665369}}, + {{"methane","ethane"}, {0.997547866,1.006617867,0.996336508,1.049707697}}, + {{"methane","propane"}, {1.004827070,1.038470657,0.989680305,1.098655531}}, + {{"methane","n-butane"}, {0.979105972,1.045375122,0.994174910,1.171607691}}, + {{"methane","isobutane"}, {1.011240388,1.054319053,0.980315756,1.161117729}}, + {{"methane","n-pentane"}, {0.948330120,1.124508039,0.992127525,1.249173968}}, + {{"methane","isopentane"}, {1.000000000,1.343685343,1.000000000,1.188899743}}, + {{"methane","n-hexane"}, {0.958015294,1.052643846,0.981844797,1.330570181}}, + {{"methane","n-heptane"}, {0.962050831,1.156655935,0.977431529,1.379850328}}, + {{"methane","n-octane"}, {0.994740603,1.116549372,0.957473785,1.449245409}}, + {{"methane","hydrogen"}, {1.000000000,1.018702573,1.000000000,1.352643115}}, + {{"methane","oxygen"}, {1.000000000,1.000000000,1.000000000,0.950000000}}, + {{"methane","carbonmonoxide"}, {0.997340772,1.006102927,0.987411732,0.987473033}}, + {{"methane","water"}, {1.012783169,1.585018334,1.063333913,0.775810513}}, + {{"methane","helium"}, {1.000000000,0.881405683,1.000000000,3.159776855}}, + {{"methane","argon"}, {1.034630259,1.014678542,0.990954281,0.989843388}}, + {{"nitrogen","carbondioxide"}, {0.977794634,1.047578256,1.005894529,1.107654104}}, + {{"nitrogen","ethane"}, {0.978880168,1.042352891,1.007671428,1.098650964}}, + {{"nitrogen","propane"}, {0.974424681,1.081025408,1.002677329,1.201264026}}, + {{"nitrogen","n-butane"}, {0.996082610,1.146949309,0.994515234,1.304886838}}, + {{"nitrogen","isobutane"}, {0.986415830,1.100576129,0.992868130,1.284462634}}, + {{"nitrogen","n-pentane"}, {1.000000000,1.078877166,1.000000000,1.419029041}}, + {{"nitrogen","isopentane"}, {1.000000000,1.154135439,1.000000000,1.381770770}}, + {{"nitrogen","n-hexane"}, {1.000000000,1.195952177,1.000000000,1.472607971}}, + {{"nitrogen","n-heptane"}, {1.000000000,1.404554090,1.000000000,1.520975334}}, + {{"nitrogen","n-octane"}, {1.000000000,1.186067025,1.000000000,1.733280051}}, + {{"nitrogen","hydrogen"}, {0.972532065,0.970115357,0.946134337,1.175696583}}, + {{"nitrogen","oxygen"}, {0.999521770,0.997082328,0.997190589,0.995157044}}, + {{"nitrogen","carbonmonoxide"}, {1.000000000,1.008690943,1.000000000,0.993425388}}, + {{"nitrogen","water"}, {1.000000000,1.094749685,1.000000000,0.968808467}}, + {{"nitrogen","helium"}, {0.969501055,0.932629867,0.692868765,1.471831580}}, + {{"nitrogen","argon"}, {1.004166412,1.002212182,0.999069843,0.990034831}}, + {{"carbondioxide","ethane"}, {1.002525718,1.032876701,1.013871147,0.900949530}}, + {{"carbondioxide","propane"}, {0.996898004,1.047596298,1.033620538,0.908772477}}, + {{"carbondioxide","n-butane"}, {1.174760923,1.222437324,1.018171004,0.911498231}}, + {{"carbondioxide","isobutane"}, {1.076551882,1.081909003,1.023339824,0.929982936}}, + {{"carbondioxide","n-pentane"}, {1.024311498,1.068406078,1.027000795,0.979217302}}, + {{"carbondioxide","isopentane"}, {1.060793104,1.116793198,1.019180957,0.961218039}}, + {{"carbondioxide","n-hexane"}, {1.000000000,0.851343711,1.000000000,1.038675574}}, + {{"carbondioxide","n-heptane"}, {1.205469976,1.164585914,1.011806317,1.046169823}}, + {{"carbondioxide","n-octane"}, {1.026169373,1.104043935,1.029690780,1.074455386}}, + {{"carbondioxide","hydrogen"}, {0.904142159,1.152792550,0.942320195,1.782924792}}, + {{"carbondioxide","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"carbondioxide","carbonmonoxide"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"carbondioxide","water"}, {0.949055959,1.542328793,0.997372205,0.775453996}}, + {{"carbondioxide","helium"}, {0.846647561,0.864141549,0.768377630,3.207456948}}, + {{"carbondioxide","argon"}, {1.008392428,1.029205465,0.996512863,1.050971635}}, + {{"ethane","propane"}, {0.997607277,1.003034720,0.996199694,1.014730190}}, + {{"ethane","n-butane"}, {0.999157205,1.006179146,0.999130554,1.034832749}}, + {{"ethane","isobutane"}, {1.000000000,1.006616886,1.000000000,1.033283811}}, + {{"ethane","n-pentane"}, {0.993851009,1.026085655,0.998688946,1.066665676}}, + {{"ethane","isopentane"} , {1.000000000,1.045439246,1.000000000,1.021150247}}, + {{"ethane","n-hexane"}, {1.000000000,1.169701102,1.000000000,1.092177796}}, + {{"ethane","n-heptane"}, {1.000000000,1.057666085,1.000000000,1.134532014}}, + {{"ethane","n-octane"}, {1.007469726,1.071917985,0.984068272,1.168636194}}, + {{"ethane","hydrogen"}, {0.925367171,1.106072040,0.932969831,1.902008495}}, + {{"ethane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"ethane","carbonmonoxide"}, {1.000000000,1.201417898,1.000000000,1.069224728}}, + {{"ethane","water"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"ethane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"ethane","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"propane","n-butane"}, {0.999795868,1.003264179,1.000310289,1.007392782}}, + {{"propane","isobutane"}, {0.999243146,1.001156119,0.998012298,1.005250774}}, + {{"propane","n-pentane"}, {1.044919431,1.019921513,0.996484021,1.008344412}}, + {{"propane","isopentane"}, {1.040459289,0.999432118,0.994364425,1.003269500}}, + {{"propane","n-hexane"}, {1.000000000,1.057872566,1.000000000,1.025657518}}, + {{"propane","n-heptane"}, {1.000000000,1.079648053,1.000000000,1.050044169}}, + {{"propane","n-octane"}, {1.000000000,1.102764612,1.000000000,1.063694129}}, + {{"propane","hydrogen"}, {1.000000000,1.074006110,1.000000000,2.308215191}}, + {{"propane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"propane","carbonmonoxide"}, {1.000000000,1.108143673,1.000000000,1.197564208}}, + {{"propane","water"}, {1.000000000,1.011759763,1.000000000,0.600340961}}, + {{"propane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"propane","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-butane","isobutane"}, {1.000880464,1.000414440,1.000077547,1.001432824}}, + {{"n-butane","n-pentane"}, {1.000000000,1.018159650,1.000000000,1.002143640}}, + {{"n-butane","isopentane"}, {1.000000000,1.002728262,1.000000000,1.000792201}}, + {{"n-butane","n-hexane"}, {1.000000000,1.034995284,1.000000000,1.009157060}}, + {{"n-butane","n-heptane"}, {1.000000000,1.019174227,1.000000000,1.021283378}}, + {{"n-butane","n-octane"}, {1.000000000,1.046905515,1.000000000,1.033180106}}, + {{"n-butane","hydrogen"}, {1.000000000,1.232939523,1.000000000,2.509259945}}, + {{"n-butane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-butane","carbonmonoxide"}, {1.000000000,1.084740904,1.000000000,1.174055065}}, + {{"n-butane","water"}, {1.000000000,1.223638763,1.000000000,0.615512682}}, + {{"n-butane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-butane","argon"}, {1.000000000,1.214638734,1.000000000,1.245039498}}, + {{"isobutane","n-pentane"}, {1.000000000,1.002779804,1.000000000,1.002495889}}, + {{"isobutane","isopentane"}, {1.000000000,1.002284197,1.000000000,1.001835788}}, + {{"isobutane","n-hexane"}, {1.000000000,1.010493989,1.000000000,1.006018054}}, + {{"isobutane","n-heptane"}, {1.000000000,1.021668316,1.000000000,1.009885760}}, + {{"isobutane","n-octane"}, {1.000000000,1.032807063,1.000000000,1.013945424}}, + {{"isobutane","hydrogen"}, {1.000000000,1.147595688,1.000000000,1.895305393}}, + {{"isobutane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"isobutane","carbonmonoxide"}, {1.000000000,1.087272232,1.000000000,1.161523504}}, + {{"isobutane","water"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"isobutane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"isobutane","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-pentane","isopentane"}, {1.000000000,1.000024352,1.000000000,1.000050537}}, + {{"n-pentane","n-hexane"}, {1.000000000,1.002480637,1.000000000,1.000761237}}, + {{"n-pentane","n-heptane"}, {1.000000000,1.008972412,1.000000000,1.002441051}}, + {{"n-pentane","n-octane"}, {1.000000000,1.069223964,1.000000000,1.016422347}}, + {{"n-pentane","hydrogen"}, {1.000000000,1.188334783,1.000000000,2.013859174}}, + {{"n-pentane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-pentane","carbonmonoxide"}, {1.000000000,1.119954454,1.000000000,1.206195595}}, + {{"n-pentane","water"}, {1.000000000,0.956677310,1.000000000,0.447666011}}, + {{"n-pentane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-pentane","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"isopentane","n-hexane"}, {1.000000000,1.002996055,1.000000000,1.001204174}}, + {{"isopentane","n-heptane"}, {1.000000000,1.009928531,1.000000000,1.003194615}}, + {{"isopentane","n-octane"}, {1.000000000,1.017880981,1.000000000,1.005647480}}, + {{"isopentane","hydrogen"}, {1.000000000,1.184339122,1.000000000,1.996386669}}, + {{"isopentane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"isopentane","carbonmonoxide"}, {1.000000000,1.116693501,1.000000000,1.199475627}}, + {{"isopentane","water"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"isopentane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"isopentane","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-hexane","n-heptane"}, {1.000000000,1.001508227,1.000000000,0.999762786}}, + {{"n-hexane","n-octane"}, {1.000000000,1.006268954,1.000000000,1.001633952}}, + {{"n-hexane","hydrogen"}, {1.000000000,1.243461678,1.000000000,3.021197546}}, + {{"n-hexane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-hexane","carbonmonoxide"}, {1.000000000,1.155145836,1.000000000,1.233435828}}, + {{"n-hexane","water"}, {1.000000000,1.170217596,1.000000000,0.569681333}}, + {{"n-hexane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-hexane","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-heptane","n-octane"}, {1.000000000,1.006767176,1.000000000,0.998793111}}, + {{"n-heptane","hydrogen"}, {1.000000000,1.159131722,1.000000000,3.169143057}}, + {{"n-heptane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-heptane","carbonmonoxide"}, {1.000000000,1.190354273,1.000000000,1.256295219}}, + {{"n-heptane","water"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-heptane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-heptane","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-octane","hydrogen"}, {1.000000000,1.305249405,1.000000000,2.191555216}}, + {{"n-octane","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-octane","carbonmonoxide"}, {1.000000000,1.219206702,1.000000000,1.276744779}}, + {{"n-octane","water"}, {1.000000000,0.599484191,1.000000000,0.662072469}}, + {{"n-octane","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"n-octane","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"hydrogen","oxygen"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"hydrogen","carbonmonoxide"}, {1.000000000,1.121416201,1.000000000,1.377504607}}, + {{"hydrogen","water"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"hydrogen","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"hydrogen","argon"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"oxygen","carbonmonoxide"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"oxygen","water"}, {1.000000000,1.143174289,1.000000000,0.964767932}}, + {{"oxygen","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"oxygen","argon"}, {0.999746847,0.993907223,1.000023103,0.990430423}}, + {{"carbonmonoxide","water"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"carbonmonoxide","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"carbonmonoxide","argon"}, {1.000000000,1.159720623,1.000000000,0.954215746}}, + {{"water","helium"}, {1.000000000,1.000000000,1.000000000,1.000000000}}, + {{"water","argon"}, {1.000000000,1.038993495,1.000000000,1.070941866}}, + {{"helium","argon"}, {1.00000000,1.00000000,1.00000000,1.00000000}} + }; + + try{ + // Try in the given order + return BIP_data.at(std::make_pair(fluid1, fluid2)); + } + catch(...){ + // Try the other order + try{ + auto bg = BIP_data.at(std::make_pair(fluid2, fluid1)); + // Because the order is backwards, need to take the reciprocals of the beta values + bg.betaT = 1/bg.betaT; + bg.betaV = 1/bg.betaV; + return bg; + } + catch(...){ + throw std::invalid_argument("Unable to obtain BIP for the pair {" + fluid1 + "," + fluid2 + "}"); + } + } +} + +std::optional get_Fij(const std::string& fluid1, const std::string& fluid2, bool ok_missing=true){ + + /// Table A3.6 from GERG 2004 monograph + static std::map, double> Fij_dict = { + {{"methane","nitrogen"}, 0.100000000000e1}, + {{"methane","carbondioxide"}, 0.100000000000e1}, + {{"methane","ethane"}, 0.100000000000e1}, + {{"methane","propane"}, 0.100000000000e1}, + {{"methane","n-butane"}, 0.100000000000e1}, + {{"methane","isobutane"}, 0.771035405688}, + {{"methane","hydrogen"}, 0.100000000000e1}, + {{"nitrogen","carbondioxide"}, 0.100000000000e1}, + {{"nitrogen","ethane"}, 0.100000000000e1}, + {{"ethane","propane"}, 0.130424765150}, + {{"ethane","n-butane"}, 0.281570073085}, + {{"ethane","isobutane"}, 0.260632376098}, + {{"propane","n-butane"}, 0.312572600489e-1}, + {{"propane","isobutane"}, -0.551609771024e-1}, + {{"n-butane","isobutane"}, -0.551240293009e-1} + }; + try{ + // Try in the given order + return Fij_dict.at(std::make_pair(fluid1, fluid2)); + } + catch(...){ + // Try the other order + try{ + return Fij_dict.at(std::make_pair(fluid2, fluid1)); + } + catch(...){ + if (ok_missing){ + return std::nullopt; + } + else{ + throw std::invalid_argument("Unable to obtain Fij for the pair {" + fluid1 + "," + fluid2 + "}"); + } + } + } +} + +struct DepartureCoeffs{ + std::vector n, t, d, eta, beta, gamma, epsilon; + std::set sizes(){ return {n.size(), t.size(), d.size(), eta.size(), beta.size(), gamma.size(), epsilon.size()}; } +}; + +DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string &fluid2){ + + std::pair sortedpair = std::minmax(fluid1, fluid2); + auto sortpair = [](const std::string &n1, const std::string& n2) ->std::pair { return std::minmax(n1, n2); }; + + // The set of pairnames using the generalized form + const std::set> generalized = { + sortpair("methane","n-butane"), sortpair("methane","isobutane"), sortpair("ethane","propane"), + sortpair("ethane","n-butane"), sortpair("ethane","isobutane"), sortpair("propane","n-butane"), + sortpair("propane","isobutane"), sortpair("n-butane","isobutane") + }; + + if (sortedpair == sortpair("methane","nitrogen")){ + DepartureCoeffs dc; + dc.n = {-0.98038985517335e-2,0.42487270143005e-3,-0.34800214576142e-1 ,-0.13333813013896 ,-0.11993694974627e-1 ,0.69243379775168e-1 ,-0.31022508148249 ,0.24495491753226 ,0.22369816716981}; + dc.d = {1,4,1,2,2,2,2,2,3}; + dc.t = {0.000,1.850,7.850,5.400,0.000,0.750,2.800,4.450,4.250}; + dc.eta = {0,0,1.000,1.000,0.250,0.000,0.000,0.000,0.000}; + dc.epsilon = {0,0,0.5,0.5,0.5,0.5,0.5,0.5,0.5}; + dc.beta = {0,0,1.0,1.0,2.5,3.0,3.0,3.0,3.0}; + dc.gamma = {0,0,0.500,0.500,0.500,0.500,0.500,0.500,0.500}; + return dc; + } + if (sortedpair == sortpair("methane","carbondioxide")){ + DepartureCoeffs dc; + dc.n = {-0.10859387354942,0.80228576727389e-1,-0.93303985115717e-2,0.40989274005848e-1,-0.24338019772494,0.23855347281124}; + dc.d = {1,2,3,1,2,3}; + dc.t = {2.600,1.950,0.000,3.950,7.950,8.000}; + dc.eta = {0,0,0,1.000,0.500,0.000}; + dc.epsilon = {0,0,0,0.5,0.5,0.5}; + dc.beta = {0,0,0,1.0,2.0,3.0}; + dc.gamma = {0,0,0,0.500,0.500,0.500}; + return dc; + } + if (sortedpair == sortpair("ethane", "methane")){ + DepartureCoeffs dc; + dc.n = {-0.80926050298746e-3,-0.75381925080059e-3,-0.41618768891219e-1,-0.23452173681569,0.14003840584586,0.63281744807738e-1,-0.34660425848809e-1,-0.23918747334251,0.19855255066891e-2,0.61777746171555e1,-0.69575358271105e1,0.10630185306388e1}; + dc.t = {0.650,1.550,3.100,5.900,7.050,3.350,1.200,5.800,2.700,0.450,0.550,1.950}; + dc.d = {3,4,1,2,2,2,2,2,2,3,3,3}; + dc.eta = {0,0,1.000,1.000,1.000,0.875,0.750,0.500,0.000,0.000,0.000,0.000}; + dc.epsilon = {0,0,0.500,0.500,0.500,0.500,0.500,0.500,0.500,0.500,0.500,0.500}; + dc.beta = {0,0,1.000,1.000,1.000,1.250,1.500,2.000,3.000,3.000,3.000,3.000}; + dc.gamma = {0,0,0.500,0.500,0.500,0.500,0.500,0.500,0.500,0.500,0.500,0.500}; + return dc; + } + if (sortedpair == sortpair("propane", "methane")){ + DepartureCoeffs dc; + dc.n = {0.13746429958576e-1,-0.74425012129552e-2,-0.45516600213685e-2,-0.54546603350237e-2, 0.23682016824471e-2, 0.18007763721438,-0.44773942932486, 0.19327374888200e-1,-0.30632197804624}; + dc.t = {1.850,3.950,0.000,1.850,3.850,5.250,3.850,0.200,6.500}; + dc.d = {3,3,4,4,4,1,1,1,2}; + dc.eta = {0,0,0,0,0,0.250,0.250,0.000,0.000}; + dc.epsilon = {0,0,0,0,0,0.500,0.500,0.500,0.500}; + dc.beta = {0,0,0,0,0,0.750,1.000,2.000,3.000}; + dc.gamma = {0,0,0,0,0,0.500,0.500,0.500,0.500}; + return dc; + } + if (sortedpair == sortpair("nitrogen", "carbondioxide")){ + DepartureCoeffs dc; + dc.n = {0.28661625028399,-0.10919833861247,-0.11374032082270e1,0.76580544237358,0.42638000926819e2,0.17673538204534}; + dc.t = {1.850,1.400,3.200,2.500,8.000,3.750}; + dc.d = {2,3,1,1,1,2}; + dc.eta = {0,0,0.250,0.250,0.000,0.000}; + dc.epsilon = {0,0,0.500,0.500,0.500,0.500}; + dc.beta = {0,0,0.750,1.000,2.000,3.000}; + dc.gamma = {0,0,0.500,0.500,0.500,0.500}; + return dc; + } + if (sortedpair == sortpair("nitrogen", "ethane")){ + DepartureCoeffs dc; + dc.n = {-0.47376518126608,0.48961193461001,-0.57011062090535e-2,-0.19966820041320,-0.69411103101723,0.69226192739021}; + dc.d = {2,2,3,1,2,2}; + dc.t = {0.000,0.050,0.000,3.650,4.900,4.450}; + dc.eta = {0,0,0,1.000,1.000,0.875}; + dc.epsilon = {0,0,0,0.500, 0.500, 0.500}; + dc.beta = {0,0,0,1.000,1.000,1.250}; + dc.gamma = {0,0,0,0.500,0.500,0.500}; + return dc; + } + else if (sortedpair == sortpair("methane", "hydrogen")){ + DepartureCoeffs dc; + dc.n = {-0.25157134971934,-0.62203841111983e-2,0.88850315184396e-1,-0.35592212573239e-1}; + dc.t = {2.000,-1.000,1.750,1.400}; + dc.d = {1,3,3,4}; + dc.eta = {0,0,0,0}; + dc.epsilon = {0,0,0,0}; + dc.beta = {0,0,0,0}; + dc.gamma = {0,0,0,0}; + return dc; + } + else if (generalized.find(sortedpair) != generalized.end()){ + DepartureCoeffs dc; + dc.n = {0.25574776844118e1,-0.79846357136353e1,0.47859131465806e1,-0.73265392369587,0.13805471345312e1,0.28349603476365,-0.49087385940425,-0.10291888921447,0.11836314681968,0.55527385721943e-4}; + dc.d = {1,1,1,2,2,3,3,4,4,4}; + dc.t = {1.000,1.550,1.700,0.250,1.350,0.000,1.250,0.000,0.700,5.400}; + dc.eta = {0,0,0,0,0,0,0,0,0,0}; + dc.epsilon = {0,0,0,0,0,0,0,0,0,0}; + dc.beta = {0,0,0,0,0,0,0,0,0,0}; + dc.gamma = {0,0,0,0,0,0,0,0,0,0}; + return dc; + } + else{ + throw std::invalid_argument("could not get departure coeffs for {" + fluid1 + "," + fluid2 + "}"); + } +} + +// *********************************************************** +// *********************************************************** +// Pures, Reducing, Corresponding States +// *********************************************************** +// *********************************************************** + +/** +\f$ \alpha^{\rm r}=\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-c_i\delta^{l_i})\f$ +*/ +class GERG2004PureFluidEOS { +private: + PureCoeffs pc; + std::vector l_i; + auto get_li(std::vector&el){ + std::vector li(el.size()); + for (auto i = 0; i < el.size(); ++i){ + li[i] = static_cast(el[i]); + } + return li; + } + +public: + GERG2004PureFluidEOS(const std::string& name): pc(get_pure_coeffs(name)), l_i(get_li(pc.l)){} + + template + auto alphar(const TauType& tau, const DeltaType& delta) const { + using result = std::common_type_t; + result r = 0.0, lntau = log(tau); + if (l_i.size() == 0 && pc.n.size() > 0) { + throw std::invalid_argument("l_i cannot be zero length if some terms are provided"); + } + if (getbaseval(delta) == 0) { + for (auto i = 0; i < pc.n.size(); ++i) { + r = r + pc.n[i] * exp(pc.t[i] * lntau - pc.c[i] * powi(delta, l_i[i])) * powi(delta, static_cast(pc.d[i])); + } + } + else { + result lndelta = log(delta); + for (auto i = 0; i < pc.n.size(); ++i) { + r = r + pc.n[i] * exp(pc.t[i] * lntau + pc.d[i] * lndelta - pc.c[i] * powi(delta, l_i[i])); + } + } + return forceeval(r); + } +}; + +class GERG2004Reducing{ +public: + // As a structure to allow them to be initialized in one + // pass through the fluids + struct TcVc{ std::vector Tc_K, vc_m3mol; }; + struct Matrices {Eigen::ArrayXXd betaT, gammaT, betaV, gammaV, YT, Yv; }; +private: + TcVc get_Tcvc(const std::vector& names){ + std::vector Tc(names.size()), vc(names.size()); + std::size_t i = 0; + for (auto &name : names){ + auto pd = get_pure_info(name); + Tc[i] = pd.Tc_K; + vc[i] = 1.0/pd.rhoc_molm3; + i++; + } + return TcVc{Tc, vc}; + } + Matrices get_matrices(const std::vector& names){ + Matrices m; + std::size_t N = names.size(); + m.betaT.resize(N,N); m.gammaT.resize(N,N); m.betaV.resize(N,N); m.gammaV.resize(N,N); m.YT.resize(N,N); m.Yv.resize(N,N); + const auto& Tc = m_Tcvc.Tc_K; + const auto& vc = m_Tcvc.vc_m3mol; + for (auto i = 0; i < N; ++i){ + for (auto j = i+1; j < N; ++j){ + auto bg = get_betasgammas(names[i], names[j]); + m.betaT(i,j) = bg.betaT; m.betaT(j,i) = 1/bg.betaT; + m.gammaT(i,j) = bg.gammaT; m.gammaT(j,i) = bg.gammaT; + m.betaV(i,j) = bg.betaV; m.betaV(j,i) = 1/bg.betaV; + m.gammaV(i,j) = bg.gammaV; m.gammaV(j,i) = bg.gammaV; + m.YT(i,j) = m.betaT(i,j)*m.gammaT(i,j)*sqrt(Tc[i]*Tc[j]); + m.YT(j,i) = m.betaT(j,i)*m.gammaT(j,i)*sqrt(Tc[j]*Tc[i]); + m.Yv(i,j) = 1.0/8.0*m.betaV(i,j)*m.gammaV(i,j)*POW3(cbrt(vc[i]) + cbrt(vc[j])); + m.Yv(j,i) = 1.0/8.0*m.betaV(j,i)*m.gammaV(j,i)*POW3(cbrt(vc[j]) + cbrt(vc[i])); + } + } + return m; + } + const TcVc m_Tcvc; + const Matrices matrices; +public: + GERG2004Reducing(const std::vector& names): m_Tcvc(get_Tcvc(names)), matrices(get_matrices(names)) {} + + template + auto Y(const MoleFractions& z, const std::vector& Yc, const Eigen::ArrayXd& beta, const Eigen::ArrayXd& Yij){ + decltype(z[0]) sum1 = 0.0, sum2 = 0.0; + std::size_t N = len(z); + for (auto i = 0; i < N-1; ++i){ + sum1 += z[i]*z[i]*Yc[i]; + for (auto j = i+1; j < N; ++j){ + sum2 += 2.0*z[i]*z[j]*(z[i]+z[j])/(POW2(beta(i,j))*z[i]+z[j])*Yij(i,j); + } + } + return forcceeval(sum1 + sum2); + } + + template + auto get_Tr(const MoleFractions& z){ + return Y(z, m_Tcvc.Tc_K, matrices.betaT, matrices.YT); + } + + template + auto get_rhor(const MoleFractions& z){ + return 1.0/Y(z, m_Tcvc.vc_m3mol, matrices.betaV, matrices.Yv); + } +}; + +class GERG2004CorrespondingStatesTerm { + +private: + const std::vector EOSs; + auto get_EOS(const std::vector& names){ + std::vector theEOS; + for (auto& name: names){ + theEOS.emplace_back(name); + } + return theEOS; + } +public: + GERG2004CorrespondingStatesTerm(const std::vector& names) : EOSs(get_EOS(names)) {}; + + auto size() const { return EOSs.size(); } + + template + auto alphar(const TauType& tau, const DeltaType& delta, const MoleFractions& molefracs) const { + using resulttype = std::common_type_t; // Type promotion, without the const-ness + resulttype alphar = 0.0; + auto N = molefracs.size(); + if (N != size()){ + throw std::invalid_argument("wrong size"); + } + for (auto i = 0; i < N; ++i) { + alphar = alphar + molefracs[i] * EOSs[i].alphar(tau, delta); + } + return forceeval(alphar); + } +}; + + +// *********************************************************** +// *********************************************************** +// Departure +// *********************************************************** +// *********************************************************** + + +class GERG2004DepartureFunction { +private: + const DepartureCoeffs dc; +public: + GERG2004DepartureFunction() {}; + GERG2004DepartureFunction(const std::string& fluid1, const std::string& fluid2) : dc(get_departurecoeffs(fluid1, fluid2)){} + + template + auto alphar(const TauType& tau, const DeltaType& delta) const { + using result = std::common_type_t; + result r = 0.0, lntau = log(tau); + auto square = [](auto x) { return x * x; }; + if (getbaseval(delta) == 0) { + for (auto i = 0; i < dc.n.size(); ++i) { + r += dc.n[i] * exp(dc.t[i] * lntau - dc.eta[i] * square(delta - dc.epsilon[i]) - dc.beta[i] * (delta - dc.gamma[i]))*powi(delta, static_cast(dc.d[i])); + } + } + else { + result lndelta = log(delta); + for (auto i = 0; i < dc.n.size(); ++i) { + r += dc.n[i] * exp(dc.t[i] * lntau + dc.d[i] * lndelta - dc.eta[i] * square(delta - dc.epsilon[i]) - dc.beta[i] * (delta - dc.gamma[i])); + } + } + return forceeval(r); + } +}; + +class GERG2004DepartureTerm { +private: + const Eigen::ArrayXXd Fmat; + const std::vector> depmat; + + auto get_Fmat(const std::vector& names){ + std::size_t N = names.size(); + Eigen::ArrayXXd mat(N, N); mat.setZero(); + for (auto i = 0; i < N; ++i){ + for (auto j = i; j < N; ++j){ + auto Fij = get_Fij(names[i], names[j]); + if (Fij){ + mat(i,j) = Fij.value(); + mat(j,i) = mat(i,j); // Fij are symmetric + } + } + } + return mat; + } + auto get_depmat(const std::vector& names){ + std::size_t N = names.size(); + std::vector> mat(N); + for (auto i = 0; i < N; ++i){ + std::vector row; + for (auto j = 0; j < N; ++j){ + if (i != j && Fmat(i,j) != 0){ + row.emplace_back(names[i], names[j]); + } + else{ + row.emplace_back(); + } + } + mat.emplace_back(row); + } + return mat; + } +public: + GERG2004DepartureTerm(const std::vector& names) : Fmat(get_Fmat(names)), depmat(get_depmat(names)) {}; + + template + auto alphar(const TauType& tau, const DeltaType& delta, const MoleFractions& molefracs) const { + using resulttype = std::common_type_t; // Type promotion, without the const-ness + resulttype alphar = 0.0; + auto N = molefracs.size(); + if (N != Fmat.cols()){ + throw std::invalid_argument("wrong size"); + } + + for (auto i = 0; i < N; ++i){ + for (auto j = 0; j < N; ++j){ + auto Fij = Fmat(i,j); + if (Fij != 0){ + alphar += molefracs[i]*molefracs[j]*Fmat(i,j)*depmat[i][j].alphar(tau, delta); + } + } + } + return forceeval(alphar); + } +}; + +class GERG2004ResidualModel{ +public: + GERG2004Reducing red; + + GERG2004CorrespondingStatesTerm corr; + GERG2004DepartureTerm dep; + GERG2004ResidualModel(const std::vector& names) : red(names), corr(names), dep(names){} + + template + auto alphar(const TType &T, + const RhoType &rho, + const MoleFracType& molefrac) const { + auto Tred = forceeval(red.get_Tr(molefrac)); + auto rhored = forceeval(red.get_rhor(molefrac)); + auto delta = forceeval(rho / rhored); + auto tau = forceeval(Tred / T); + auto val = corr.alphar(tau, delta, molefrac) + dep.alphar(tau, delta, molefrac); + } +}; + +} /* namespace GERG2004 */ + +namespace GERG2008{ +//.... +} /* namespace GERG2008 */ + +} diff --git a/src/tests/catch_test_GERG2004.cpp b/src/tests/catch_test_GERG2004.cpp new file mode 100644 index 00000000..37b802f6 --- /dev/null +++ b/src/tests/catch_test_GERG2004.cpp @@ -0,0 +1,45 @@ +#include +#include + +using Catch::Approx; + +#include "teqp/models/GERG/GERG.hpp" + +using namespace teqp; + +TEST_CASE("Load all GERG2004 models", "[GERG2004]"){ + const auto& names = GERG2004::component_names; + REQUIRE(names.size() == 18); + + for (auto &name : names){ + CHECK_NOTHROW(GERG2004::get_pure_info(name)); + } + + for (auto &name : names){ + CHECK_NOTHROW(GERG2004::get_pure_coeffs(name)); + CHECK(GERG2004::get_pure_coeffs(name).sizes().size() == 1); + } + CHECK_THROWS(GERG2004::get_pure_info("NOT A FLUID")); + + for (auto i = 0; i < names.size(); ++i){ + for (auto j = i+1; j < names.size(); ++j){ + CHECK_NOTHROW(GERG2004::get_betasgammas(names[i], names[j])); + CHECK_NOTHROW(GERG2004::get_betasgammas(names[j], names[i])); + CAPTURE(i); + CAPTURE(j); + CHECK_NOTHROW(GERG2004::GERG2004Reducing({names[i], names[j]})); + auto Fij = GERG2004::get_Fij(names[i], names[j]); + + if (Fij){ + CHECK_NOTHROW(GERG2004::get_departurecoeffs(names[i], names[j])); + CHECK(GERG2004::get_departurecoeffs(names[i], names[j]).sizes().size() == 1); + } + else{ + CHECK_THROWS(GERG2004::get_departurecoeffs(names[i], names[j])); + } + } + } + CHECK_THROWS(GERG2004::get_betasgammas("NOT A FLUID","water")); + CHECK_NOTHROW(GERG2004::GERG2004CorrespondingStatesTerm(names)); + CHECK_NOTHROW(GERG2004::GERG2004ResidualModel(names)); +} From fb6be9557bd6c5a64a68b6c23240905feb96d05d Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Mon, 11 Dec 2023 09:06:22 -0500 Subject: [PATCH 3/9] Implement the residual part for GERG-2008 models too All tests pass so far, now need to calculate pressures, that is the real test --- include/teqp/models/GERG/GERG.hpp | 697 +++++++++++++++++++----------- src/tests/catch_test_GERG2004.cpp | 42 +- 2 files changed, 494 insertions(+), 245 deletions(-) diff --git a/include/teqp/models/GERG/GERG.hpp b/include/teqp/models/GERG/GERG.hpp index baa9fa84..87145e8b 100644 --- a/include/teqp/models/GERG/GERG.hpp +++ b/include/teqp/models/GERG/GERG.hpp @@ -14,13 +14,285 @@ namespace teqp{ -namespace GERG2004{ - -const std::vector component_names = {"methane", "nitrogen","carbondioxide","ethane","propane","n-butane","isobutane","n-pentane","isopentane","n-hexane","n-heptane","n-octane","hydrogen", "oxygen","carbonmonoxide","water","helium","argon"}; - +namespace GERGGeneral{ struct PureInfo{ double rhoc_molm3, Tc_K, M_kgmol; }; +struct PureCoeffs{ + std::vector n, t, d, c, l; + std::set sizes(){ return {n.size(), t.size(), d.size(), c.size(), l.size()}; } +}; +struct BetasGammas { + double betaV, gammaV, betaT, gammaT; +}; +struct DepartureCoeffs{ + std::vector n, t, d, eta, beta, gamma, epsilon; + std::set sizes(){ return {n.size(), t.size(), d.size(), eta.size(), beta.size(), gamma.size(), epsilon.size()}; } +}; + + +// *********************************************************** +// *********************************************************** +// Pures, Reducing, Corresponding States +// *********************************************************** +// *********************************************************** + +/** +\f$ \alpha^{\rm r}=\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-c_i\delta^{l_i})\f$ +*/ +class GERG200XPureFluidEOS { +private: + PureCoeffs pc; + std::vector l_i; + auto get_li(std::vector&el){ + std::vector li(el.size()); + for (auto i = 0; i < el.size(); ++i){ + li[i] = static_cast(el[i]); + } + return li; + } + +public: + using GetPureCoeffs = std::function; + GERG200XPureFluidEOS(const std::string& name, const GetPureCoeffs& get_pure_coeffs): pc(get_pure_coeffs(name)), l_i(get_li(pc.l)){} + + template + auto alphar(const TauType& tau, const DeltaType& delta) const { + using result = std::common_type_t; + result r = 0.0, lntau = log(tau); + if (l_i.size() == 0 && pc.n.size() > 0) { + throw std::invalid_argument("l_i cannot be zero length if some terms are provided"); + } + if (getbaseval(delta) == 0) { + for (auto i = 0; i < pc.n.size(); ++i) { + r = r + pc.n[i] * exp(pc.t[i] * lntau - pc.c[i] * powi(delta, l_i[i])) * powi(delta, static_cast(pc.d[i])); + } + } + else { + result lndelta = log(delta); + for (auto i = 0; i < pc.n.size(); ++i) { + r = r + pc.n[i] * exp(pc.t[i] * lntau + pc.d[i] * lndelta - pc.c[i] * powi(delta, l_i[i])); + } + } + return forceeval(r); + } +}; + +class GERG200XReducing{ +public: + // As a structure to allow them to be initialized in one + // pass through the fluids + struct TcVc{ std::vector Tc_K, vc_m3mol; }; + struct Matrices {Eigen::ArrayXXd betaT, gammaT, betaV, gammaV, YT, Yv; }; + using GetPureInfo = std::function; + GetPureInfo _get_pure_info; + using GetBetasGammas = std::function; + GetBetasGammas _get_betasgammas; +private: + TcVc get_Tcvc(const std::vector& names){ + std::vector Tc(names.size()), vc(names.size()); + std::size_t i = 0; + for (auto &name : names){ + auto pd = _get_pure_info(name); + Tc[i] = pd.Tc_K; + vc[i] = 1.0/pd.rhoc_molm3; + i++; + } + return TcVc{Tc, vc}; + } + Matrices get_matrices(const std::vector& names){ + Matrices m; + std::size_t N = names.size(); + m.betaT.resize(N,N); m.gammaT.resize(N,N); m.betaV.resize(N,N); m.gammaV.resize(N,N); m.YT.resize(N,N); m.Yv.resize(N,N); + const auto& Tc = m_Tcvc.Tc_K; + const auto& vc = m_Tcvc.vc_m3mol; + for (auto i = 0; i < N; ++i){ + for (auto j = i+1; j < N; ++j){ + auto bg = _get_betasgammas(names[i], names[j]); + m.betaT(i,j) = bg.betaT; m.betaT(j,i) = 1/bg.betaT; + m.gammaT(i,j) = bg.gammaT; m.gammaT(j,i) = bg.gammaT; + m.betaV(i,j) = bg.betaV; m.betaV(j,i) = 1/bg.betaV; + m.gammaV(i,j) = bg.gammaV; m.gammaV(j,i) = bg.gammaV; + m.YT(i,j) = m.betaT(i,j)*m.gammaT(i,j)*sqrt(Tc[i]*Tc[j]); + m.YT(j,i) = m.betaT(j,i)*m.gammaT(j,i)*sqrt(Tc[j]*Tc[i]); + m.Yv(i,j) = 1.0/8.0*m.betaV(i,j)*m.gammaV(i,j)*POW3(cbrt(vc[i]) + cbrt(vc[j])); + m.Yv(j,i) = 1.0/8.0*m.betaV(j,i)*m.gammaV(j,i)*POW3(cbrt(vc[j]) + cbrt(vc[i])); + } + } + return m; + } + const TcVc m_Tcvc; + const Matrices matrices; +public: + GERG200XReducing(const std::vector& names, const GetPureInfo &get_pure_info, const GetBetasGammas& get_betasgammas): _get_pure_info(get_pure_info), _get_betasgammas(get_betasgammas), m_Tcvc(get_Tcvc(names)), matrices(get_matrices(names)) {} + + template + auto Y(const MoleFractions& z, const std::vector& Yc, const Eigen::ArrayXd& beta, const Eigen::ArrayXd& Yij){ + decltype(z[0]) sum1 = 0.0, sum2 = 0.0; + std::size_t N = len(z); + for (auto i = 0; i < N-1; ++i){ + sum1 += z[i]*z[i]*Yc[i]; + for (auto j = i+1; j < N; ++j){ + sum2 += 2.0*z[i]*z[j]*(z[i]+z[j])/(POW2(beta(i,j))*z[i]+z[j])*Yij(i,j); + } + } + return forcceeval(sum1 + sum2); + } + + template + auto get_Tr(const MoleFractions& z){ + return Y(z, m_Tcvc.Tc_K, matrices.betaT, matrices.YT); + } + + template + auto get_rhor(const MoleFractions& z){ + return 1.0/Y(z, m_Tcvc.vc_m3mol, matrices.betaV, matrices.Yv); + } +}; + +class GERG200XCorrespondingStatesTerm{ +public: + using GetPureCoeffs = std::function; + GetPureCoeffs _get_pure_coeffs; + +private: + const std::vector EOSs; + auto get_EOS(const std::vector& names){ + std::vector theEOS; + for (auto& name: names){ + theEOS.emplace_back(name, _get_pure_coeffs); + } + return theEOS; + } +public: + GERG200XCorrespondingStatesTerm(const std::vector& names, const GetPureCoeffs &get_pure_coeffs) : _get_pure_coeffs(get_pure_coeffs), EOSs(get_EOS(names)) {}; + + auto size() const { return EOSs.size(); } + + template + auto alphar(const TauType& tau, const DeltaType& delta, const MoleFractions& molefracs) const { + using resulttype = std::common_type_t; // Type promotion, without the const-ness + resulttype alphar = 0.0; + auto N = molefracs.size(); + if (N != size()){ + throw std::invalid_argument("wrong size"); + } + for (auto i = 0; i < N; ++i) { + alphar = alphar + molefracs[i] * EOSs[i].alphar(tau, delta); + } + return forceeval(alphar); + } +}; + +// *********************************************************** +// *********************************************************** +// Departure +// *********************************************************** +// *********************************************************** + + +class GERG200XDepartureFunction { +private: + const DepartureCoeffs dc; +public: + using GetDepartureCoeffs = std::function; + GERG200XDepartureFunction() {}; + GERG200XDepartureFunction(const std::string& fluid1, const std::string& fluid2, const GetDepartureCoeffs& get_departurecoeffs) : dc(get_departurecoeffs(fluid1, fluid2)){} + + template + auto alphar(const TauType& tau, const DeltaType& delta) const { + using result = std::common_type_t; + result r = 0.0, lntau = log(tau); + auto square = [](auto x) { return x * x; }; + if (getbaseval(delta) == 0) { + for (auto i = 0; i < dc.n.size(); ++i) { + r += dc.n[i] * exp(dc.t[i] * lntau - dc.eta[i] * square(delta - dc.epsilon[i]) - dc.beta[i] * (delta - dc.gamma[i]))*powi(delta, static_cast(dc.d[i])); + } + } + else { + result lndelta = log(delta); + for (auto i = 0; i < dc.n.size(); ++i) { + r += dc.n[i] * exp(dc.t[i] * lntau + dc.d[i] * lndelta - dc.eta[i] * square(delta - dc.epsilon[i]) - dc.beta[i] * (delta - dc.gamma[i])); + } + } + return forceeval(r); + } +}; + +class GERG200XDepartureTerm { +public: + using GetFij = std::function(const std::string&, const std::string&, bool)>; + GetFij _get_Fij; + using GetDepartureCoeffs = std::function; + GetDepartureCoeffs _get_departurecoeffs; +private: + const Eigen::ArrayXXd Fmat; + const std::vector> depmat; + + auto get_Fmat(const std::vector& names){ + std::size_t N = names.size(); + Eigen::ArrayXXd mat(N, N); mat.setZero(); + for (auto i = 0; i < N; ++i){ + for (auto j = i; j < N; ++j){ + auto Fij = _get_Fij(names[i], names[j], true); + if (Fij){ + mat(i,j) = Fij.value(); + mat(j,i) = mat(i,j); // Fij are symmetric + } + } + } + return mat; + } + auto get_depmat(const std::vector& names){ + std::size_t N = names.size(); + std::vector> mat(N); + for (auto i = 0; i < N; ++i){ + std::vector row; + for (auto j = 0; j < N; ++j){ + if (i != j && Fmat(i,j) != 0){ + row.emplace_back(names[i], names[j], _get_departurecoeffs); + } + else{ + row.emplace_back(); + } + } + mat.emplace_back(row); + } + return mat; + } +public: + + GERG200XDepartureTerm(const std::vector& names, const GetFij& get_Fij, const GetDepartureCoeffs& get_departurecoeffs) : _get_Fij(get_Fij), _get_departurecoeffs(get_departurecoeffs), Fmat(get_Fmat(names)), depmat(get_depmat(names)) {}; + + template + auto alphar(const TauType& tau, const DeltaType& delta, const MoleFractions& molefracs) const { + using resulttype = std::common_type_t; // Type promotion, without the const-ness + resulttype alphar = 0.0; + auto N = molefracs.size(); + if (N != Fmat.cols()){ + throw std::invalid_argument("wrong size"); + } + + for (auto i = 0; i < N; ++i){ + for (auto j = 0; j < N; ++j){ + auto Fij = Fmat(i,j); + if (Fij != 0){ + alphar += molefracs[i]*molefracs[j]*Fmat(i,j)*depmat[i][j].alphar(tau, delta); + } + } + } + return forceeval(alphar); + } +}; + + +} + +namespace GERG2004{ + +using namespace GERGGeneral; + +const std::vector component_names = {"methane", "nitrogen","carbondioxide","ethane","propane","n-butane","isobutane","n-pentane","isopentane","n-hexane","n-heptane","n-octane","hydrogen", "oxygen","carbonmonoxide","water","helium","argon"}; /// Get the pure fluid information for a fluid from GERG-2004 monograph PureInfo get_pure_info(const std::string& name){ @@ -53,10 +325,7 @@ PureInfo get_pure_info(const std::string& name){ return data; } -struct PureCoeffs{ - std::vector n, t, d, c, l; - std::set sizes(){ return {n.size(), t.size(), d.size(), c.size(), l.size()}; } -}; + PureCoeffs get_pure_coeffs(const std::string& fluid){ @@ -140,9 +409,7 @@ PureCoeffs get_pure_coeffs(const std::string& fluid){ } } -struct BetasGammas { - double betaT, gammaT, betaV, gammaV; -}; + BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2){ @@ -362,10 +629,6 @@ std::optional get_Fij(const std::string& fluid1, const std::string& flui } } -struct DepartureCoeffs{ - std::vector n, t, d, eta, beta, gamma, epsilon; - std::set sizes(){ return {n.size(), t.size(), d.size(), eta.size(), beta.size(), gamma.size(), epsilon.size()}; } -}; DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string &fluid2){ @@ -472,253 +735,205 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string } } -// *********************************************************** -// *********************************************************** -// Pures, Reducing, Corresponding States -// *********************************************************** -// *********************************************************** - -/** -\f$ \alpha^{\rm r}=\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-c_i\delta^{l_i})\f$ -*/ -class GERG2004PureFluidEOS { -private: - PureCoeffs pc; - std::vector l_i; - auto get_li(std::vector&el){ - std::vector li(el.size()); - for (auto i = 0; i < el.size(); ++i){ - li[i] = static_cast(el[i]); - } - return li; - } - +class GERG2004ResidualModel{ public: - GERG2004PureFluidEOS(const std::string& name): pc(get_pure_coeffs(name)), l_i(get_li(pc.l)){} + GERG200XReducing red; + GERG200XCorrespondingStatesTerm corr; + GERG200XDepartureTerm dep; + GERG2004ResidualModel(const std::vector& names) : red(names, get_pure_info, get_betasgammas), corr(names, get_pure_coeffs), dep(names, get_Fij, get_departurecoeffs){} - template - auto alphar(const TauType& tau, const DeltaType& delta) const { - using result = std::common_type_t; - result r = 0.0, lntau = log(tau); - if (l_i.size() == 0 && pc.n.size() > 0) { - throw std::invalid_argument("l_i cannot be zero length if some terms are provided"); - } - if (getbaseval(delta) == 0) { - for (auto i = 0; i < pc.n.size(); ++i) { - r = r + pc.n[i] * exp(pc.t[i] * lntau - pc.c[i] * powi(delta, l_i[i])) * powi(delta, static_cast(pc.d[i])); - } - } - else { - result lndelta = log(delta); - for (auto i = 0; i < pc.n.size(); ++i) { - r = r + pc.n[i] * exp(pc.t[i] * lntau + pc.d[i] * lndelta - pc.c[i] * powi(delta, l_i[i])); - } - } - return forceeval(r); + template + auto alphar(const TType &T, + const RhoType &rho, + const MoleFracType& molefrac) const { + auto Tred = forceeval(red.get_Tr(molefrac)); + auto rhored = forceeval(red.get_rhor(molefrac)); + auto delta = forceeval(rho / rhored); + auto tau = forceeval(Tred / T); + auto val = corr.alphar(tau, delta, molefrac) + dep.alphar(tau, delta, molefrac); } }; -class GERG2004Reducing{ -public: - // As a structure to allow them to be initialized in one - // pass through the fluids - struct TcVc{ std::vector Tc_K, vc_m3mol; }; - struct Matrices {Eigen::ArrayXXd betaT, gammaT, betaV, gammaV, YT, Yv; }; -private: - TcVc get_Tcvc(const std::vector& names){ - std::vector Tc(names.size()), vc(names.size()); - std::size_t i = 0; - for (auto &name : names){ - auto pd = get_pure_info(name); - Tc[i] = pd.Tc_K; - vc[i] = 1.0/pd.rhoc_molm3; - i++; - } - return TcVc{Tc, vc}; - } - Matrices get_matrices(const std::vector& names){ - Matrices m; - std::size_t N = names.size(); - m.betaT.resize(N,N); m.gammaT.resize(N,N); m.betaV.resize(N,N); m.gammaV.resize(N,N); m.YT.resize(N,N); m.Yv.resize(N,N); - const auto& Tc = m_Tcvc.Tc_K; - const auto& vc = m_Tcvc.vc_m3mol; - for (auto i = 0; i < N; ++i){ - for (auto j = i+1; j < N; ++j){ - auto bg = get_betasgammas(names[i], names[j]); - m.betaT(i,j) = bg.betaT; m.betaT(j,i) = 1/bg.betaT; - m.gammaT(i,j) = bg.gammaT; m.gammaT(j,i) = bg.gammaT; - m.betaV(i,j) = bg.betaV; m.betaV(j,i) = 1/bg.betaV; - m.gammaV(i,j) = bg.gammaV; m.gammaV(j,i) = bg.gammaV; - m.YT(i,j) = m.betaT(i,j)*m.gammaT(i,j)*sqrt(Tc[i]*Tc[j]); - m.YT(j,i) = m.betaT(j,i)*m.gammaT(j,i)*sqrt(Tc[j]*Tc[i]); - m.Yv(i,j) = 1.0/8.0*m.betaV(i,j)*m.gammaV(i,j)*POW3(cbrt(vc[i]) + cbrt(vc[j])); - m.Yv(j,i) = 1.0/8.0*m.betaV(j,i)*m.gammaV(j,i)*POW3(cbrt(vc[j]) + cbrt(vc[i])); - } - } - return m; - } - const TcVc m_Tcvc; - const Matrices matrices; -public: - GERG2004Reducing(const std::vector& names): m_Tcvc(get_Tcvc(names)), matrices(get_matrices(names)) {} - - template - auto Y(const MoleFractions& z, const std::vector& Yc, const Eigen::ArrayXd& beta, const Eigen::ArrayXd& Yij){ - decltype(z[0]) sum1 = 0.0, sum2 = 0.0; - std::size_t N = len(z); - for (auto i = 0; i < N-1; ++i){ - sum1 += z[i]*z[i]*Yc[i]; - for (auto j = i+1; j < N; ++j){ - sum2 += 2.0*z[i]*z[j]*(z[i]+z[j])/(POW2(beta(i,j))*z[i]+z[j])*Yij(i,j); - } - } - return forcceeval(sum1 + sum2); - } - - template - auto get_Tr(const MoleFractions& z){ - return Y(z, m_Tcvc.Tc_K, matrices.betaT, matrices.YT); - } - - template - auto get_rhor(const MoleFractions& z){ - return 1.0/Y(z, m_Tcvc.vc_m3mol, matrices.betaV, matrices.Yv); - } -}; +} /* namespace GERG2004 */ -class GERG2004CorrespondingStatesTerm { -private: - const std::vector EOSs; - auto get_EOS(const std::vector& names){ - std::vector theEOS; - for (auto& name: names){ - theEOS.emplace_back(name); - } - return theEOS; - } -public: - GERG2004CorrespondingStatesTerm(const std::vector& names) : EOSs(get_EOS(names)) {}; - - auto size() const { return EOSs.size(); } - template - auto alphar(const TauType& tau, const DeltaType& delta, const MoleFractions& molefracs) const { - using resulttype = std::common_type_t; // Type promotion, without the const-ness - resulttype alphar = 0.0; - auto N = molefracs.size(); - if (N != size()){ - throw std::invalid_argument("wrong size"); - } - for (auto i = 0; i < N; ++i) { - alphar = alphar + molefracs[i] * EOSs[i].alphar(tau, delta); - } - return forceeval(alphar); - } -}; -// *********************************************************** -// *********************************************************** -// Departure -// *********************************************************** -// *********************************************************** +namespace GERG2008{ -class GERG2004DepartureFunction { -private: - const DepartureCoeffs dc; -public: - GERG2004DepartureFunction() {}; - GERG2004DepartureFunction(const std::string& fluid1, const std::string& fluid2) : dc(get_departurecoeffs(fluid1, fluid2)){} +using namespace GERGGeneral; - template - auto alphar(const TauType& tau, const DeltaType& delta) const { - using result = std::common_type_t; - result r = 0.0, lntau = log(tau); - auto square = [](auto x) { return x * x; }; - if (getbaseval(delta) == 0) { - for (auto i = 0; i < dc.n.size(); ++i) { - r += dc.n[i] * exp(dc.t[i] * lntau - dc.eta[i] * square(delta - dc.epsilon[i]) - dc.beta[i] * (delta - dc.gamma[i]))*powi(delta, static_cast(dc.d[i])); - } - } - else { - result lndelta = log(delta); - for (auto i = 0; i < dc.n.size(); ++i) { - r += dc.n[i] * exp(dc.t[i] * lntau + dc.d[i] * lndelta - dc.eta[i] * square(delta - dc.epsilon[i]) - dc.beta[i] * (delta - dc.gamma[i])); - } - } - return forceeval(r); +const std::vector component_names = {"methane", "nitrogen","carbondioxide","ethane","propane","n-butane","isobutane","n-pentane","isopentane","n-hexane","n-heptane","n-octane","hydrogen", "oxygen","carbonmonoxide","water","helium","argon","hydrogensulfide","n-nonane","n-decane"}; + +auto get_pure_info(const std::string& name){ + // From Table A3.5 from GERG 2004 monograph + // Data are in mol/dm3, K, kg/mol + // All others are unchanged + static std::map data_map = { + {"carbonmonoxide", {10.850000000,132.860000000,28.010100}}, // Changed from GERG-2004 + {"isopentane", {3.271,460.35,72.148780}}, // Changed from GERG-2004 + + {"n-nonane", {1.81,594.55,128.2551}}, // Added in GERG-2008 + {"n-decane", {1.64,617.7,142.28168}}, // Added in GERG-2008 + {"hydrogensulfide", {10.19,373.1,34.08088}} // Added in GERG-2008 + }; + if (data_map.find(name) != data_map.end()){ + auto data = data_map.at(name); + data.rhoc_molm3 *= 1000; // mol/dm^3 -> mol/m^3 + data.M_kgmol /= 1000; // kg/kmol -> kg/mol + return data; } -}; + else{ + // Fallback to GERG-2004 + return GERG2004::get_pure_info(name); + } +} -class GERG2004DepartureTerm { -private: - const Eigen::ArrayXXd Fmat; - const std::vector> depmat; +/// Pass-through functions to GERG-2004 functions (all values are identical for Fij and departure functions) +using GERG2004::get_Fij; +using GERG2004::get_departurecoeffs; + +BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2){ - auto get_Fmat(const std::vector& names){ - std::size_t N = names.size(); - Eigen::ArrayXXd mat(N, N); mat.setZero(); - for (auto i = 0; i < N; ++i){ - for (auto j = i; j < N; ++j){ - auto Fij = get_Fij(names[i], names[j]); - if (Fij){ - mat(i,j) = Fij.value(); - mat(j,i) = mat(i,j); // Fij are symmetric - } - } - } - return mat; + // From Table A8 of GERG-2008 manuscript. Pairs that are unchanged + // from GERG-2004 are left out and are looked up from the GERG-2004 + // coefficients. + std::map,BetasGammas> BIP_data = { + + // This set has different values than in GERG-2004. The change + // occurs because the EOS has changed for isopentane and CO and + // thus the estimated interaction parameters need to be calculated + // with the "new" Tc. + {{"n-butane","carbonmonoxide"}, {1.0, 1.084740904, 1.0, 1.173916162}}, + {{"isobutane","carbonmonoxide"}, {1.0, 1.087272232, 1.0, 1.161390082}}, + {{"n-pentane","carbonmonoxide"}, {1.0, 1.119954454, 1.0, 1.206043295}}, + {{"isopentane","carbonmonoxide"}, {1.0, 1.116694577, 1.0, 1.199326059}}, + {{"n-hexane","carbonmonoxide"}, {1.0, 1.155145836, 1.0, 1.233272781}}, + {{"n-heptane","carbonmonoxide"}, {1.0, 1.190354273, 1.0, 1.256123503}}, + {{"n-octane","carbonmonoxide"}, {1.0, 1.219206702, 1.0, 1.276565536}}, + {{"n-pentane","isopentane"}, {1.0, 1.000024335, 1.0, 1.000050537}}, + {{"isopentane","n-hexane"}, {1.0, 1.002995876, 1.0, 1.001204174}}, + {{"isopentane","n-heptane"}, {1.0, 1.009928206, 1.0, 1.003194615}}, + {{"isopentane","n-octane"}, {1.0, 1.017880545, 1.0, 1.00564748}}, + + // The 57 new models added in GERG-2008 + {{"methane","n-nonane"}, {1.002852287, 1.141895355, 0.947716769, 1.528532478}}, + {{"methane","n-decane"}, {1.033086292, 1.146089637, 0.937777823, 1.568231489}}, + {{"methane","hydrogensulfide"}, {1.012599087, 1.040161207, 1.011090031, 0.961155729}}, + {{"nitrogen","n-nonane"}, {1.0, 1.100405929, 0.95637945, 1.749119996}}, + {{"nitrogen","n-decane"}, {1.0, 1.0, 0.957934447, 1.822157123}}, + {{"nitrogen","hydrogensulfide"}, {0.910394249, 1.256844157, 1.004692366, 0.9601742}}, + {{"carbondioxide","n-nonane"}, {1.0, 0.973386152, 1.00768862, 1.140671202}}, + {{"carbondioxide","n-decane"}, {1.000151132, 1.183394668, 1.02002879, 1.145512213}}, + {{"carbondioxide","hydrogensulfide"}, {0.906630564, 1.024085837, 1.016034583, 0.92601888}}, + {{"ethane","n-nonane"}, {1.0, 1.14353473, 1.0, 1.05603303}}, + {{"ethane","n-decane"}, {0.995676258, 1.098361281, 0.970918061, 1.237191558}}, + {{"ethane","hydrogensulfide"}, {1.010817909, 1.030988277, 0.990197354, 0.90273666}}, + {{"propane","n-nonane"}, {1.0, 1.199769134, 1.0, 1.109973833}}, + {{"propane","n-decane"}, {0.984104227, 1.053040574, 0.985331233, 1.140905252}}, + {{"propane","hydrogensulfide"}, {0.936811219, 1.010593999, 0.992573556, 0.905829247}}, + {{"n-butane","n-nonane"}, {1.0, 1.049219137, 1.0, 1.014096448}}, + {{"n-butane","n-decane"}, {0.976951968, 1.027845529, 0.993688386, 1.076466918}}, + {{"n-butane","hydrogensulfide"}, {0.908113163, 1.033366041, 0.985962886, 0.926156602}}, + {{"isobutane","n-nonane"}, {1.0, 1.047298475, 1.0, 1.017817492}}, + {{"isobutane","n-decane"}, {1.0, 1.060243344, 1.0, 1.021624748}}, + {{"isobutane","hydrogensulfide"}, {1.012994431, 0.988591117, 0.974550548, 0.937130844}}, + {{"n-pentane","n-nonane"}, {1.0, 1.034910633, 1.0, 1.103421755}}, + {{"n-pentane","n-decane"}, {1.0, 1.016370338, 1.0, 1.049035838}}, + {{"n-pentane","hydrogensulfide"}, {0.984613203, 1.076539234, 0.962006651, 0.959065662}}, + {{"isopentane","n-nonane"}, {1.0, 1.028994325, 1.0, 1.008191499}}, + {{"isopentane","n-decane"}, {1.0, 1.039372957, 1.0, 1.010825138}}, + {{"isopentane","hydrogensulfide"}, {1.0, 0.835763343, 1.0, 0.982651529}}, + {{"n-hexane","n-nonane"}, {1.0, 1.02076168, 1.0, 1.055369591}}, + {{"n-hexane","n-decane"}, {1.001516371, 1.013511439, 0.99764101, 1.028939539}}, + {{"n-hexane","hydrogensulfide"}, {0.754473958, 1.339283552, 0.985891113, 0.956075596}}, + {{"n-heptane","n-nonane"}, {1.0, 1.001370076, 1.0, 1.001150096}}, + {{"n-heptane","n-decane"}, {1.0, 1.002972346, 1.0, 1.002229938}}, + {{"n-heptane","hydrogensulfide"}, {0.828967164, 1.087956749, 0.988937417, 1.013453092}}, + {{"n-octane","n-nonane"}, {1.0, 1.001357085, 1.0, 1.000235044}}, + {{"n-octane","n-decane"}, {1.0, 1.002553544, 1.0, 1.007186267}}, + {{"n-octane","hydrogensulfide"}, {1.0, 1.0, 1.0, 1.0}}, + {{"n-nonane","n-decane"}, {1.0, 1.00081052, 1.0, 1.000182392}}, + {{"n-nonane","hydrogen"}, {1.0, 1.342647661, 1.0, 2.23435404}}, + {{"n-nonane","oxygen"}, {1.0, 1.0, 1.0, 1.0}}, + {{"n-nonane","carbonmonoxide"}, {1.0, 1.252151449, 1.0, 1.294070556}}, + {{"n-nonane","water"}, {1.0, 1.0, 1.0, 1.0}}, + {{"n-nonane","hydrogensulfide"}, {1.0, 1.082905109, 1.0, 1.086557826}}, + {{"n-nonane","helium"}, {1.0, 1.0, 1.0, 1.0}}, + {{"n-nonane","argon"}, {1.0, 1.0, 1.0, 1.0}}, + {{"n-decane","hydrogen"}, {1.695358382, 1.120233729, 1.064818089, 3.786003724}}, + {{"n-decane","oxygen"}, {1.0, 1.0, 1.0, 1.0}}, + {{"n-decane","carbonmonoxide"}, {1.0, 0.87018496, 1.049594632, 1.803567587}}, + {{"n-decane","water"}, {1.0, 0.551405318, 0.897162268, 0.740416402}}, + {{"n-decane","hydrogensulfide"}, {0.975187766, 1.171714677, 0.973091413, 1.103693489}}, + {{"n-decane","helium"}, {1.0, 1.0, 1.0, 1.0}}, + {{"n-decane","argon"}, {1.0, 1.0, 1.0, 1.0}}, + {{"hydrogen","hydrogensulfide"}, {1.0, 1.0, 1.0, 1.0}}, + {{"oxygen","hydrogensulfide"}, {1.0, 1.0, 1.0, 1.0}}, + {{"carbonmonoxide","hydrogensulfide"}, {0.795660392, 1.101731308, 1.025536736, 1.022749748}}, + {{"water","hydrogensulfide"}, {1.0, 1.014832832, 1.0, 0.940587083}}, + {{"hydrogensulfide","helium"}, {1.0, 1.0, 1.0, 1.0}}, + {{"hydrogensulfide","argon"}, {1.0, 1.0, 1.0, 1.0}}, + }; + + try{ + // Try in the given order + return BIP_data.at(std::make_pair(fluid1, fluid2)); } - auto get_depmat(const std::vector& names){ - std::size_t N = names.size(); - std::vector> mat(N); - for (auto i = 0; i < N; ++i){ - std::vector row; - for (auto j = 0; j < N; ++j){ - if (i != j && Fmat(i,j) != 0){ - row.emplace_back(names[i], names[j]); - } - else{ - row.emplace_back(); - } - } - mat.emplace_back(row); + catch(...){ + // Try the other order + try{ + auto bg = BIP_data.at(std::make_pair(fluid2, fluid1)); + // Because the order is backwards, need to take the reciprocals of the beta values + bg.betaT = 1/bg.betaT; + bg.betaV = 1/bg.betaV; + return bg; + } + catch(...){ + // Fall back to looking up from GERG-2004 + return GERG2004::get_betasgammas(fluid1, fluid2); } - return mat; } -public: - GERG2004DepartureTerm(const std::vector& names) : Fmat(get_Fmat(names)), depmat(get_depmat(names)) {}; +} + +PureCoeffs get_pure_coeffs(const std::string& fluid){ - template - auto alphar(const TauType& tau, const DeltaType& delta, const MoleFractions& molefracs) const { - using resulttype = std::common_type_t; // Type promotion, without the const-ness - resulttype alphar = 0.0; - auto N = molefracs.size(); - if (N != Fmat.cols()){ - throw std::invalid_argument("wrong size"); - } - for (auto i = 0; i < N; ++i){ - for (auto j = 0; j < N; ++j){ - auto Fij = Fmat(i,j); - if (Fij != 0){ - alphar += molefracs[i]*molefracs[j]*Fmat(i,j)*depmat[i][j].alphar(tau, delta); - } - } - } - return forceeval(alphar); + static std::map> n_dict_main = { + + // Updated in GERG-2008 + {"carbonmonoxide", {0.90554,-0.24515e1, 0.53149, 0.24173e-1, 0.72156e-1, 0.18818e-3, 0.19405,-0.43268e-1,-0.12778,-0.27896e-1,-0.34154e-1, 0.16329e-1}}, + {"isopentane", { 0.10963e1,-0.30402e1,0.10317e1,-0.15410,0.11535,0.29809e-3,0.39571,-0.45881e-1,-0.35804,-0.10107,-0.35484e-1,0.18156e-1}}, + + // New in GERG-2008 + {"hydrogensulfide", {0.87641,-0.20367e1,0.21634,-0.50199e-1,0.66994e-1,0.19076e-3,0.20227,-0.45348e-2,-0.22230,-0.34714e-1,-0.14885e-1,0.74154e-2}}, + {"n-decane", {0.10461e1,-0.24807e1,0.74372,-0.52579,0.15315,0.32865e-3,0.84178,0.55424e-1, -0.73555, -0.18507, -0.20775e-1, 0.12335e-1}}, + {"n-nonane", { 0.11151e1,-0.27020e1, 0.83416,-0.38828, 0.13760, 0.28185e-3, 0.62037, 0.15847e-1,-0.61726,-0.15043,-0.12982e-1, 0.44325e-2}}, + }; + + if (n_dict_main.find(fluid) != n_dict_main.end()){ + PureCoeffs pc; + pc.n = n_dict_main[fluid], + pc.t = {0.250,1.125,1.500,1.375,0.250,0.875,0.625,1.750,3.625,3.625,14.500,12.000}; + pc.d = {1,1,1,2,3,7,2,5,1,4,3,4}; + pc.c = {0,0,0,0,0,0,1,1,1,1,1,1}; + pc.l = {0,0,0,0,0,0,1,1,2,2,3,3}; + return pc; } -}; + else{ + return GERG2004::get_pure_coeffs(fluid); + } +} -class GERG2004ResidualModel{ + +class GERG2008ResidualModel{ public: - GERG2004Reducing red; - - GERG2004CorrespondingStatesTerm corr; - GERG2004DepartureTerm dep; - GERG2004ResidualModel(const std::vector& names) : red(names), corr(names), dep(names){} + GERG200XReducing red; + GERG200XCorrespondingStatesTerm corr; + GERG200XDepartureTerm dep; + GERG2008ResidualModel(const std::vector& names) : red(names, get_pure_info, get_betasgammas), corr(names, get_pure_coeffs), dep(names, get_Fij, get_departurecoeffs){} template auto alphar(const TType &T, @@ -731,11 +946,7 @@ class GERG2004ResidualModel{ auto val = corr.alphar(tau, delta, molefrac) + dep.alphar(tau, delta, molefrac); } }; - -} /* namespace GERG2004 */ - -namespace GERG2008{ -//.... + } /* namespace GERG2008 */ } diff --git a/src/tests/catch_test_GERG2004.cpp b/src/tests/catch_test_GERG2004.cpp index 37b802f6..4993d25f 100644 --- a/src/tests/catch_test_GERG2004.cpp +++ b/src/tests/catch_test_GERG2004.cpp @@ -27,7 +27,7 @@ TEST_CASE("Load all GERG2004 models", "[GERG2004]"){ CHECK_NOTHROW(GERG2004::get_betasgammas(names[j], names[i])); CAPTURE(i); CAPTURE(j); - CHECK_NOTHROW(GERG2004::GERG2004Reducing({names[i], names[j]})); + CHECK_NOTHROW(GERG2004::GERG200XReducing({names[i], names[j]}, GERG2004::get_pure_info, GERG2004::get_betasgammas)); auto Fij = GERG2004::get_Fij(names[i], names[j]); if (Fij){ @@ -40,6 +40,44 @@ TEST_CASE("Load all GERG2004 models", "[GERG2004]"){ } } CHECK_THROWS(GERG2004::get_betasgammas("NOT A FLUID","water")); - CHECK_NOTHROW(GERG2004::GERG2004CorrespondingStatesTerm(names)); + CHECK_NOTHROW(GERG2004::GERG200XCorrespondingStatesTerm(names, GERG2004::get_pure_coeffs)); CHECK_NOTHROW(GERG2004::GERG2004ResidualModel(names)); } + + +TEST_CASE("Load all GERG2008 models", "[GERG2008]"){ + const auto& names = GERG2008::component_names; + REQUIRE(names.size() == 21); + + for (auto &name : names){ + CHECK_NOTHROW(GERG2008::get_pure_info(name)); + } + + for (auto &name : names){ + CHECK_NOTHROW(GERG2008::get_pure_coeffs(name)); + CHECK(GERG2008::get_pure_coeffs(name).sizes().size() == 1); + } + CHECK_THROWS(GERG2008::get_pure_info("NOT A FLUID")); + + for (auto i = 0; i < names.size(); ++i){ + for (auto j = i+1; j < names.size(); ++j){ + CHECK_NOTHROW(GERG2008::get_betasgammas(names[i], names[j])); + CHECK_NOTHROW(GERG2008::get_betasgammas(names[j], names[i])); + CAPTURE(i); + CAPTURE(j); + CHECK_NOTHROW(GERG2008::GERG200XReducing({names[i], names[j]}, GERG2008::get_pure_info, GERG2008::get_betasgammas)); + auto Fij = GERG2008::get_Fij(names[i], names[j]); + + if (Fij){ + CHECK_NOTHROW(GERG2008::get_departurecoeffs(names[i], names[j])); + CHECK(GERG2008::get_departurecoeffs(names[i], names[j]).sizes().size() == 1); + } + else{ + CHECK_THROWS(GERG2008::get_departurecoeffs(names[i], names[j])); + } + } + } + CHECK_THROWS(GERG2008::get_betasgammas("NOT A FLUID","water")); + CHECK_NOTHROW(GERG2008::GERG200XCorrespondingStatesTerm(names, GERG2008::get_pure_coeffs)); + CHECK_NOTHROW(GERG2008::GERG2008ResidualModel(names)); +} From 5bf03c8fb64e52db82ec2b8675d0c7e1ab8065f4 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Mon, 11 Dec 2023 09:07:21 -0500 Subject: [PATCH 4/9] Rename test file --- src/tests/{catch_test_GERG2004.cpp => catch_test_GERG.cxx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tests/{catch_test_GERG2004.cpp => catch_test_GERG.cxx} (100%) diff --git a/src/tests/catch_test_GERG2004.cpp b/src/tests/catch_test_GERG.cxx similarity index 100% rename from src/tests/catch_test_GERG2004.cpp rename to src/tests/catch_test_GERG.cxx From 2bd11b7c0a27bd492b05c078c064cb4d3d03ba18 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Mon, 11 Dec 2023 17:06:10 -0500 Subject: [PATCH 5/9] GERG-2008 tests are working Bug in the EOS-CG-2021, GERG-2004, and GERG-2008 documents; double-summation for departure term should have N as limit in both cases --- include/teqp/models/GERG/GERG.hpp | 105 +- src/tests/GERG2008.cpp | 1637 +++++++++++++++++++++++++++++ src/tests/catch_test_GERG.cxx | 506 +++++++++ 3 files changed, 2198 insertions(+), 50 deletions(-) create mode 100644 src/tests/GERG2008.cpp diff --git a/include/teqp/models/GERG/GERG.hpp b/include/teqp/models/GERG/GERG.hpp index 87145e8b..f1a3f965 100644 --- a/include/teqp/models/GERG/GERG.hpp +++ b/include/teqp/models/GERG/GERG.hpp @@ -10,6 +10,7 @@ #include #include "teqp/math/pow_templates.hpp" +#include "teqp/types.hpp" #include "Eigen/Dense" namespace teqp{ @@ -113,11 +114,14 @@ class GERG200XReducing{ m.gammaT(i,j) = bg.gammaT; m.gammaT(j,i) = bg.gammaT; m.betaV(i,j) = bg.betaV; m.betaV(j,i) = 1/bg.betaV; m.gammaV(i,j) = bg.gammaV; m.gammaV(j,i) = bg.gammaV; + m.YT(i,j) = m.betaT(i,j)*m.gammaT(i,j)*sqrt(Tc[i]*Tc[j]); m.YT(j,i) = m.betaT(j,i)*m.gammaT(j,i)*sqrt(Tc[j]*Tc[i]); m.Yv(i,j) = 1.0/8.0*m.betaV(i,j)*m.gammaV(i,j)*POW3(cbrt(vc[i]) + cbrt(vc[j])); m.Yv(j,i) = 1.0/8.0*m.betaV(j,i)*m.gammaV(j,i)*POW3(cbrt(vc[j]) + cbrt(vc[i])); } + m.YT(i,i) = Tc[i]; + m.Yv(i,i) = vc[i]; } return m; } @@ -127,25 +131,30 @@ class GERG200XReducing{ GERG200XReducing(const std::vector& names, const GetPureInfo &get_pure_info, const GetBetasGammas& get_betasgammas): _get_pure_info(get_pure_info), _get_betasgammas(get_betasgammas), m_Tcvc(get_Tcvc(names)), matrices(get_matrices(names)) {} template - auto Y(const MoleFractions& z, const std::vector& Yc, const Eigen::ArrayXd& beta, const Eigen::ArrayXd& Yij){ - decltype(z[0]) sum1 = 0.0, sum2 = 0.0; - std::size_t N = len(z); - for (auto i = 0; i < N-1; ++i){ + auto Y(const MoleFractions& z, const std::vector& Yc, const Eigen::ArrayXXd& beta, const Eigen::ArrayXXd& Yij) const { + using resulttype = std::common_type_t; + resulttype sum1 = 0.0, sum2 = 0.0; + std::size_t N = z.size(); + + for (auto i = 0; i < N; ++i){ sum1 += z[i]*z[i]*Yc[i]; for (auto j = i+1; j < N; ++j){ - sum2 += 2.0*z[i]*z[j]*(z[i]+z[j])/(POW2(beta(i,j))*z[i]+z[j])*Yij(i,j); + auto denom = POW2(beta(i,j))*z[i]+z[j]; + if (getbaseval(z[i]) != 0 && getbaseval(z[j]) != 0){ + sum2 += 2.0*z[i]*z[j]*(z[i]+z[j])/denom*Yij(i,j); + } } } - return forcceeval(sum1 + sum2); + return forceeval(sum1 + sum2); } template - auto get_Tr(const MoleFractions& z){ + auto get_Tr(const MoleFractions& z) const { return Y(z, m_Tcvc.Tc_K, matrices.betaT, matrices.YT); } template - auto get_rhor(const MoleFractions& z){ + auto get_rhor(const MoleFractions& z) const{ return 1.0/Y(z, m_Tcvc.vc_m3mol, matrices.betaV, matrices.Yv); } }; @@ -178,7 +187,7 @@ class GERG200XCorrespondingStatesTerm{ throw std::invalid_argument("wrong size"); } for (auto i = 0; i < N; ++i) { - alphar = alphar + molefracs[i] * EOSs[i].alphar(tau, delta); + alphar += molefracs[i] * EOSs[i].alphar(tau, delta); } return forceeval(alphar); } @@ -203,7 +212,7 @@ class GERG200XDepartureFunction { auto alphar(const TauType& tau, const DeltaType& delta) const { using result = std::common_type_t; result r = 0.0, lntau = log(tau); - auto square = [](auto x) { return x * x; }; + auto square = [](auto x) { return forceeval(x * x); }; if (getbaseval(delta) == 0) { for (auto i = 0; i < dc.n.size(); ++i) { r += dc.n[i] * exp(dc.t[i] * lntau - dc.eta[i] * square(delta - dc.epsilon[i]) - dc.beta[i] * (delta - dc.gamma[i]))*powi(delta, static_cast(dc.d[i])); @@ -233,8 +242,8 @@ class GERG200XDepartureTerm { std::size_t N = names.size(); Eigen::ArrayXXd mat(N, N); mat.setZero(); for (auto i = 0; i < N; ++i){ - for (auto j = i; j < N; ++j){ - auto Fij = _get_Fij(names[i], names[j], true); + for (auto j = i+1; j < N; ++j){ + auto Fij = _get_Fij(names[i], names[j], true /* ok_missing */); if (Fij){ mat(i,j) = Fij.value(); mat(j,i) = mat(i,j); // Fij are symmetric @@ -245,7 +254,7 @@ class GERG200XDepartureTerm { } auto get_depmat(const std::vector& names){ std::size_t N = names.size(); - std::vector> mat(N); + std::vector> mat; for (auto i = 0; i < N; ++i){ std::vector row; for (auto j = 0; j < N; ++j){ @@ -266,7 +275,7 @@ class GERG200XDepartureTerm { template auto alphar(const TauType& tau, const DeltaType& delta, const MoleFractions& molefracs) const { - using resulttype = std::common_type_t; // Type promotion, without the const-ness + using resulttype = std::common_type_t; // Type promotion, without the const-ness resulttype alphar = 0.0; auto N = molefracs.size(); if (N != Fmat.cols()){ @@ -274,14 +283,14 @@ class GERG200XDepartureTerm { } for (auto i = 0; i < N; ++i){ - for (auto j = 0; j < N; ++j){ + for (auto j = i+1; j < N; ++j){ auto Fij = Fmat(i,j); if (Fij != 0){ - alphar += molefracs[i]*molefracs[j]*Fmat(i,j)*depmat[i][j].alphar(tau, delta); + alphar += molefracs[i]*molefracs[j]*Fij*depmat[i][j].alphar(tau, delta); } } } - return forceeval(alphar); + return alphar; } }; @@ -298,7 +307,7 @@ const std::vector component_names = {"methane", "nitrogen","carbond PureInfo get_pure_info(const std::string& name){ // From Table A3.5 from GERG 2004 monograph - // Data are in mol/dm3, K, kg/mol + // Data in table are in mol/dm3, K, kg/mol, so some conversion is needed static std::map data_map = { {"methane", {10.139342719,190.564000000,16.042460}}, {"nitrogen", {11.183900000,126.192000000,28.013400}}, @@ -317,7 +326,7 @@ PureInfo get_pure_info(const std::string& name){ {"carbonmonoxide", {10.850000000,132.800000000,28.010100}}, {"water", {17.873716090,647.096000000,18.015280}}, {"helium", {17.399000000,5.195300000,4.002602}}, - {"argon", {13.407429659,150.687000000,39.948000}} + {"argon", {13.407429659,150.687,39.948000}} }; auto data = data_map.at(name); data.rhoc_molm3 *= 1000; // mol/dm^3 -> mol/m^3 @@ -352,7 +361,7 @@ PureCoeffs get_pure_coeffs(const std::string& fluid){ if (n_dict_main.find(fluid) != n_dict_main.end()){ PureCoeffs pc; - pc.n = n_dict_main[fluid], + pc.n = n_dict_main[fluid]; pc.t = {0.250,1.125,1.500,1.375,0.250,0.875,0.625,1.750,3.625,3.625,14.500,12.000}; pc.d = {1,1,1,2,3,7,2,5,1,4,3,4}; pc.c = {0,0,0,0,0,0,1,1,1,1,1,1}; @@ -593,15 +602,15 @@ std::optional get_Fij(const std::string& fluid1, const std::string& flui /// Table A3.6 from GERG 2004 monograph static std::map, double> Fij_dict = { - {{"methane","nitrogen"}, 0.100000000000e1}, - {{"methane","carbondioxide"}, 0.100000000000e1}, - {{"methane","ethane"}, 0.100000000000e1}, - {{"methane","propane"}, 0.100000000000e1}, - {{"methane","n-butane"}, 0.100000000000e1}, + {{"methane","nitrogen"}, 1.0}, + {{"methane","carbondioxide"}, 1.0}, + {{"methane","ethane"}, 1.0}, + {{"methane","propane"}, 1.0}, + {{"methane","n-butane"}, 1.0}, {{"methane","isobutane"}, 0.771035405688}, - {{"methane","hydrogen"}, 0.100000000000e1}, - {{"nitrogen","carbondioxide"}, 0.100000000000e1}, - {{"nitrogen","ethane"}, 0.100000000000e1}, + {{"methane","hydrogen"}, 1.0}, + {{"nitrogen","carbondioxide"}, 1.0}, + {{"nitrogen","ethane"}, 1.0}, {{"ethane","propane"}, 0.130424765150}, {{"ethane","n-butane"}, 0.281570073085}, {{"ethane","isobutane"}, 0.260632376098}, @@ -642,8 +651,8 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string sortpair("propane","isobutane"), sortpair("n-butane","isobutane") }; + DepartureCoeffs dc; if (sortedpair == sortpair("methane","nitrogen")){ - DepartureCoeffs dc; dc.n = {-0.98038985517335e-2,0.42487270143005e-3,-0.34800214576142e-1 ,-0.13333813013896 ,-0.11993694974627e-1 ,0.69243379775168e-1 ,-0.31022508148249 ,0.24495491753226 ,0.22369816716981}; dc.d = {1,4,1,2,2,2,2,2,3}; dc.t = {0.000,1.850,7.850,5.400,0.000,0.750,2.800,4.450,4.250}; @@ -654,7 +663,6 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string return dc; } if (sortedpair == sortpair("methane","carbondioxide")){ - DepartureCoeffs dc; dc.n = {-0.10859387354942,0.80228576727389e-1,-0.93303985115717e-2,0.40989274005848e-1,-0.24338019772494,0.23855347281124}; dc.d = {1,2,3,1,2,3}; dc.t = {2.600,1.950,0.000,3.950,7.950,8.000}; @@ -665,7 +673,6 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string return dc; } if (sortedpair == sortpair("ethane", "methane")){ - DepartureCoeffs dc; dc.n = {-0.80926050298746e-3,-0.75381925080059e-3,-0.41618768891219e-1,-0.23452173681569,0.14003840584586,0.63281744807738e-1,-0.34660425848809e-1,-0.23918747334251,0.19855255066891e-2,0.61777746171555e1,-0.69575358271105e1,0.10630185306388e1}; dc.t = {0.650,1.550,3.100,5.900,7.050,3.350,1.200,5.800,2.700,0.450,0.550,1.950}; dc.d = {3,4,1,2,2,2,2,2,2,3,3,3}; @@ -676,7 +683,6 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string return dc; } if (sortedpair == sortpair("propane", "methane")){ - DepartureCoeffs dc; dc.n = {0.13746429958576e-1,-0.74425012129552e-2,-0.45516600213685e-2,-0.54546603350237e-2, 0.23682016824471e-2, 0.18007763721438,-0.44773942932486, 0.19327374888200e-1,-0.30632197804624}; dc.t = {1.850,3.950,0.000,1.850,3.850,5.250,3.850,0.200,6.500}; dc.d = {3,3,4,4,4,1,1,1,2}; @@ -687,8 +693,7 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string return dc; } if (sortedpair == sortpair("nitrogen", "carbondioxide")){ - DepartureCoeffs dc; - dc.n = {0.28661625028399,-0.10919833861247,-0.11374032082270e1,0.76580544237358,0.42638000926819e2,0.17673538204534}; + dc.n = {0.28661625028399,-0.10919833861247,-0.11374032082270e1,0.76580544237358,0.42638000926819e-2,0.17673538204534}; dc.t = {1.850,1.400,3.200,2.500,8.000,3.750}; dc.d = {2,3,1,1,1,2}; dc.eta = {0,0,0.250,0.250,0.000,0.000}; @@ -698,7 +703,6 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string return dc; } if (sortedpair == sortpair("nitrogen", "ethane")){ - DepartureCoeffs dc; dc.n = {-0.47376518126608,0.48961193461001,-0.57011062090535e-2,-0.19966820041320,-0.69411103101723,0.69226192739021}; dc.d = {2,2,3,1,2,2}; dc.t = {0.000,0.050,0.000,3.650,4.900,4.450}; @@ -708,8 +712,7 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string dc.gamma = {0,0,0,0.500,0.500,0.500}; return dc; } - else if (sortedpair == sortpair("methane", "hydrogen")){ - DepartureCoeffs dc; + if (sortedpair == sortpair("methane", "hydrogen")){ dc.n = {-0.25157134971934,-0.62203841111983e-2,0.88850315184396e-1,-0.35592212573239e-1}; dc.t = {2.000,-1.000,1.750,1.400}; dc.d = {1,3,3,4}; @@ -719,8 +722,7 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string dc.gamma = {0,0,0,0}; return dc; } - else if (generalized.find(sortedpair) != generalized.end()){ - DepartureCoeffs dc; + if (generalized.find(sortedpair) != generalized.end()){ dc.n = {0.25574776844118e1,-0.79846357136353e1,0.47859131465806e1,-0.73265392369587,0.13805471345312e1,0.28349603476365,-0.49087385940425,-0.10291888921447,0.11836314681968,0.55527385721943e-4}; dc.d = {1,1,1,2,2,3,3,4,4,4}; dc.t = {1.000,1.550,1.700,0.250,1.350,0.000,1.250,0.000,0.700,5.400}; @@ -730,16 +732,15 @@ DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string dc.gamma = {0,0,0,0,0,0,0,0,0,0}; return dc; } - else{ - throw std::invalid_argument("could not get departure coeffs for {" + fluid1 + "," + fluid2 + "}"); - } + + throw std::invalid_argument("could not get departure coeffs for {" + fluid1 + "," + fluid2 + "}"); } class GERG2004ResidualModel{ public: - GERG200XReducing red; - GERG200XCorrespondingStatesTerm corr; - GERG200XDepartureTerm dep; + const GERG200XReducing red; + const GERG200XCorrespondingStatesTerm corr; + const GERG200XDepartureTerm dep; GERG2004ResidualModel(const std::vector& names) : red(names, get_pure_info, get_betasgammas), corr(names, get_pure_coeffs), dep(names, get_Fij, get_departurecoeffs){} template @@ -750,7 +751,8 @@ class GERG2004ResidualModel{ auto rhored = forceeval(red.get_rhor(molefrac)); auto delta = forceeval(rho / rhored); auto tau = forceeval(Tred / T); - auto val = corr.alphar(tau, delta, molefrac) + dep.alphar(tau, delta, molefrac); + auto val = forceeval(corr.alphar(tau, delta, molefrac) + dep.alphar(tau, delta, molefrac)); + return val; } }; @@ -772,7 +774,7 @@ auto get_pure_info(const std::string& name){ // Data are in mol/dm3, K, kg/mol // All others are unchanged static std::map data_map = { - {"carbonmonoxide", {10.850000000,132.860000000,28.010100}}, // Changed from GERG-2004 + {"carbonmonoxide", {10.85, 132.86, 28.010100}}, // Changed from GERG-2004 {"isopentane", {3.271,460.35,72.148780}}, // Changed from GERG-2004 {"n-nonane", {1.81,594.55,128.2551}}, // Added in GERG-2008 @@ -900,7 +902,6 @@ BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2) PureCoeffs get_pure_coeffs(const std::string& fluid){ - static std::map> n_dict_main = { // Updated in GERG-2008 @@ -915,7 +916,7 @@ PureCoeffs get_pure_coeffs(const std::string& fluid){ if (n_dict_main.find(fluid) != n_dict_main.end()){ PureCoeffs pc; - pc.n = n_dict_main[fluid], + pc.n = n_dict_main[fluid]; pc.t = {0.250,1.125,1.500,1.375,0.250,0.875,0.625,1.750,3.625,3.625,14.500,12.000}; pc.d = {1,1,1,2,3,7,2,5,1,4,3,4}; pc.c = {0,0,0,0,0,0,1,1,1,1,1,1}; @@ -939,11 +940,15 @@ class GERG2008ResidualModel{ auto alphar(const TType &T, const RhoType &rho, const MoleFracType& molefrac) const { + if (molefrac.size() != corr.size()){ + throw std::invalid_argument("sizes don't match"); + } auto Tred = forceeval(red.get_Tr(molefrac)); auto rhored = forceeval(red.get_rhor(molefrac)); auto delta = forceeval(rho / rhored); auto tau = forceeval(Tred / T); - auto val = corr.alphar(tau, delta, molefrac) + dep.alphar(tau, delta, molefrac); + auto val = forceeval(corr.alphar(tau, delta, molefrac) + dep.alphar(tau, delta, molefrac)); + return val; } }; diff --git a/src/tests/GERG2008.cpp b/src/tests/GERG2008.cpp new file mode 100644 index 00000000..adca4d78 --- /dev/null +++ b/src/tests/GERG2008.cpp @@ -0,0 +1,1637 @@ +// This file was taken, unmodified, from the https://github.com/usnistgov/AGA8 repository +// The code is available under the NIST "unlicense": +/* + This software was developed by employees of the National Institute of Standards and Technology (NIST), an agency of the Federal Government and is being made available as a public service. Pursuant to title 17 United States Code Section 105, works of NIST employees are not subject to copyright protection in the United States. This software may be subject to foreign copyright. Permission in the United States and in foreign countries, to the extent that NIST may hold copyright, to use, copy, modify, create derivative works, and distribute this software and its documentation without fee is hereby granted on a non-exclusive basis, provided that this notice and disclaimer of warranty appears in all copies. + + THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. +*/ + +#include "GERG2008.h" +// We add both math headers to placate some non-standards-compliant compilers +#include +#include +#include + +// ********** This code is preliminary, and will be updated. ********** +// ********** Use only for beta testing. ********** +// ********** June 7, 2016 ********** + +// Version 1.7 of routines for the calculation of thermodynamic properties from the +// AGA 8 Part 2, GERG-2008 equation of state. + +// 06/19/2012 - Change kexp from 7 to 9 for water +// 02/20/2013 - Remove one of the negative signs in the calculation of Cv +// 03/20/2014 - Change n1 and n2 constants in the ideal gas terms to match the latest values +// 03/10/2015 - Multiple changes to work with Excel, with new fluid order that matches other methods +// 03/18/2015 - Change order of butane and isobutane, and the order of pentane and isopentane +// 08/13/2015 - Change generalized equation array location from 0 to 10 to avoid arrays starting at 0 +// 08/13/2015 - Declare kexp, kpol, kpolij, kexpij as integers instead of doubles +// 10/31/2015 - Change code to more closely match the DETAIL code +// 11/17/2015 - Modify density search to find liquid phase roots +// 12/17/2015 - Add subroutine tTermsGERG +// 05/16/2016 - Fix error in the calculation of entropy +// 05/16/2016 - Make minor final changes before publication +// 05/25/2016 - Change the ideal gas coefficients so that the GERG and DETAIL use the same values + +// Written by Eric W. Lemmon +// Applied Chemicals and Materials Division +// National Institute of Standards and Technology (NIST) +// Boulder, Colorado, USA +// Eric.Lemmon@nist.gov +// 303-497-7939 + +// C++ translation by Ian H. Bell +// Applied Chemicals and Materials Division +// National Institute of Standards and Technology (NIST) +// Boulder, Colorado, USA +// ian.bell@nist.gov + +// Other contributors: +// Volker Heinemann, RMG Messtechnik GmbH +// Jason Lu, Thermo Fisher Scientific +// Ian Bell, NIST + +// The publication for the AGA 8 equation of state is available from AGA +// and the Transmission Measurement Committee + +// The GERG-2008 equation of state was developed by Oliver Kunz and Wolfgang Wagner; + +// Kunz, O. and Wagner, W. +// The GERG-2008 Wide-Range Equation of State for Natural Gases and Other Mixtures; +// An Expansion of GERG-2004 +// J. Chem. Eng. Data, 57(11):3032-3091, 2012. + +// Kunz, O., Klimeck, R., Wagner, W., and Jaeschke, M. +// The GERG-2004 Wide-Range Equation of State for Natural Gases and Other Mixtures +// GERG Technical Monograph 15 +// Fortschr.-Ber. VDI, Reihe 6, Nr. 557, VDI Verlag, Düsseldorf, 2007. +// http://www.gerg.eu/public/uploads/files/publications/technical_monographs/tm15_04.pdf + +// Subroutines contained here for property calculations: +// ***** Subroutine SetupGERG must be called once before calling other routines. ****** +// Sub MolarMassGERG(x, Mm) +// Sub PressureGERG(T, D, x, P, Z) +// Sub DensityGERG(iFlag, T, P, x, D, ierr, herr) +// Sub PropertiesGERG(T, D, x, P, Z, dPdD, d2PdD2, d2PdTD, dPdT, U, H, S, Cv, Cp, W, G, JT, Kappa) +// Sub SetupGERG() + +// The compositions in the x() array use the following order and must be sent as mole fractions: +// 1 - Methane +// 2 - Nitrogen +// 3 - Carbon dioxide +// 4 - Ethane +// 5 - Propane +// 6 - Isobutane +// 7 - n-Butane +// 8 - Isopentane +// 9 - n-Pentane +// 10 - n-Hexane +// 11 - n-Heptane +// 12 - n-Octane +// 13 - n-Nonane +// 14 - n-Decane +// 15 - Hydrogen +// 16 - Oxygen +// 17 - Carbon monoxide +// 18 - Water +// 19 - Hydrogen sulfide +// 20 - Helium +// 21 - Argon + +// For example, a mixture (in moles) of 94% methane, 5% CO2, and 1% helium would be (in mole fractions): +// x(1)=0.94, x(3)=0.05, x(20)=0.01 + +// Function prototypes (not exported) +void xTerms(const std::vector &x); +void Alpha0GERG(const double T, const double D, const std::vector &x, double a0[3]); +void AlpharGERG(const int iprop, const double T, const double D, const std::vector &x, double ar[4][4]); +void PseudoCriticalPointGERG(const std::vector &x, double &Tcx, double &Dcx); +void tTermsGERG(const double tau, const double lntau, const std::vector &x); + +// Variables containing the common parameters in the GERG-2008 equations +static double RGERG; +static const int NcGERG = 21, MaxFlds = 21, MaxMdl = 10, MaxTrmM = 12, MaxTrmP = 24; +static int coik[MaxFlds+1][MaxTrmP+1], doik[MaxFlds+1][MaxTrmP+1], dijk[MaxMdl+1][MaxTrmM+1]; +static double Drold, Trold, Told, Trold2, xold[MaxFlds+1]; +static int mNumb[MaxFlds+1][MaxFlds+1], kpol[MaxFlds+1], kexp[MaxFlds+1], kpolij[MaxMdl+1], kexpij[MaxMdl+1]; +static double Dc[MaxFlds+1], Tc[MaxFlds+1], MMiGERG[MaxFlds+1], Vc3[MaxFlds+1], Tc2[MaxFlds+1]; +static double noik[MaxFlds+1][MaxTrmP+1], toik[MaxFlds+1][MaxTrmP+1]; +static double cijk[MaxMdl+1][MaxTrmM+1]; +static double eijk[MaxMdl+1][MaxTrmM+1], gijk[MaxMdl+1][MaxTrmM+1], nijk[MaxMdl+1][MaxTrmM+1], tijk[MaxMdl+1][MaxTrmM+1]; +static double btij[MaxFlds+1][MaxFlds+1], bvij[MaxFlds+1][MaxFlds+1], gtij[MaxFlds+1][MaxFlds+1], gvij[MaxFlds+1][MaxFlds+1]; +static double fij[MaxFlds+1][MaxFlds+1], th0i[MaxFlds+1][MaxFlds+1], n0i[MaxFlds+1][MaxFlds+1]; +static double taup[MaxFlds+1][MaxTrmP+1], taupijk[MaxFlds+1][MaxTrmM+1]; +static double dPdDsave, d2PdTDsave; //Calculated in the PressureGERG subroutine, but not included as an argument since it is only used internally in the density algorithm. + +inline double Tanh(double xx){ return (exp(xx) - exp(-xx)) / (exp(xx) + exp(-xx)); } +inline double Sinh(double xx){ return (exp(xx) - exp(-xx)) / 2; } +inline double Cosh(double xx){ return (exp(xx) + exp(-xx)) / 2; } + +void MolarMassGERG(const std::vector &x, double &Mm) +{ + // Sub MolarMassGERG(x, Mm) + + // Calculate molar mass of the mixture with the compositions contained in the x() input array + + // Inputs: + // x() - composition (mole fraction) + // Do not send mole percents or mass fractions in the x() array, otherwise the output will be incorrect. + // The sum of the compositions in the x() array must be equal to one. + // The order of the fluids in this array is given at the top of this module. + + // Outputs: + // Mm - molar mass (g/mol) + + Mm = 0; + for (int i = 1; i <= NcGERG; ++i){ + Mm += x[i] * MMiGERG[i]; + } +} + +void PressureGERG(const double T, const double D, const std::vector &x, double &P, double &Z) +{ + // Sub PressureGERG(T, D, x, P, Z) + + // Calculate pressure as a function of temperature and density. The derivative d(P)/d(D) is also calculated + // for use in the iterative DensityGERG subroutine (and is only returned as a common variable). + + // Inputs: + // T - temperature (K) + // D - density (mol/l) + // x() - composition (mole fraction) + // Do not send mole percents or mass fractions in the x() array, otherwise the output will be incorrect. + // The sum of the compositions in the x() array must be equal to one. + + // Outputs: + // P - pressure (kPa) + // Z - compressibility factor + // dPdDsave - d(P)/d(D) [kPa/(mol/l)] (stored in global block) + + double ar[4][4]; + AlpharGERG(0, T, D,x,ar); + + Z = 1 + ar[0][1]; + P = D * RGERG * T * Z; + dPdDsave = RGERG * T * (1 + 2 * ar[0][1] + ar[0][2]); +} + +void DensityGERG(const int iFlag, const double T, const double P, const std::vector &x, double &D, int &ierr, std::string &herr) +{ + // Sub DensityGERG(iFlag T, P, x, D, ierr, herr) + + // Calculate density as a function of temperature and pressure. This is an iterative routine that calls PressureGERG + // to find the correct state point. Generally only 6 iterations at most are required. + // If the iteration fails to converge, the ideal gas density and an error message are returned. + // No checks are made to determine the phase boundary, which would have guaranteed that the output is in the gas phase (or liquid phase when iFlag=2). + // It is up to the user to locate the phase boundary, and thus identify the phase of the T and P inputs. + // If the state point is 2-phase, the output density will represent a metastable state. + + // Inputs: + // iFlag - set to 0 for strict pressure solver in gas phase without checks (fastest mode, but output state may not be stable single phase) + // set to 1 to make checks for possible 2-phase state (result may still not be stable single phase, but many unstable states will be identified) + // set to 2 to search for liquid phase (and make the same checks when iFlag=1) + // T - temperature (K) + // P - pressure (kPa) + // x() - composition (mole fraction) + // (An initial guess for the density can be sent in D as the negative of the guess for roots that are in the liquid phase instead of using iFlag=2) + + // Outputs: + // D - density (mol/l) + // For the liquid phase, an initial value can be sent to the routine to avoid + // a solution in the metastable or gas phases. + // The initial value should be sent as a negative number. + // ierr - Error number (0 indicates no error) + // herr - Error message if ierr is not equal to zero + + int nFail, iFail; + double plog, vlog, P2, Z, dpdlv, vdiff, tolr, vinc; + double Tcx, Dcx; + + double dPdD, d2PdD2, d2PdTD, dPdT, U, H, S, A; + double Cv, Cp, W, G, JT, Kappa, PP; + + ierr = 0; + herr = ""; + nFail = 0; + iFail = 0; + if (P == 0) { D = 0; return; } + tolr = 0.00000001; + PseudoCriticalPointGERG(x, Tcx, Dcx); + + if (D >= 0){ + D = P / RGERG / T; // Ideal gas estimate for vapor phase + if (iFlag == 2){ D = Dcx*3; } // Initial estimate for liquid phase + } + else{ + D = std::abs(D); // If D<0, then use as initial estimate + } + + plog = log(P); + vlog = -log(D); + for (int it = 1; it <= 50; ++it){ + if (vlog < -7 || vlog > 100 || it == 20 || it == 30 || it == 40 || iFail == 1){ + //Current state is bad or iteration is taking too long. Restart with completely different initial state + iFail = 0; + if (nFail > 2) { + // Iteration failed (above loop did find a solution or checks made below indicate possible 2-phase state) + ierr = 1; + herr = "Calculation failed to converge in GERG method, ideal gas density returned."; + D = P / RGERG / T; + } + nFail++; + if (nFail == 1){ + D = Dcx * 3; // If vapor phase search fails, look for root in liquid region + } + else if (nFail == 2) { + D = Dcx * 2.5; // If liquid phase search fails, look for root between liquid and critical regions + } + else if (nFail == 3) { + D = Dcx * 2; // If search fails, look for root in critical region + } + vlog = -log(D); + } + D = exp(-vlog); + PressureGERG(T, D, x, P2, Z); + if (dPdDsave < 0 || P2 <= 0){ + // Current state is 2-phase, try locating a different state that is single phase + vinc = 0.1; + if (D > Dcx) { vinc = -0.1; } + if (it > 5) { vinc = vinc / 2; } + if (it > 10 && it < 20) { vinc = vinc / 5; } + vlog += vinc; + } + else{ + // Find the next density with a first order Newton's type iterative scheme, with + // log(P) as the known variable and log(v) as the unknown property. + // See AGA 8 publication for further information. + dpdlv = -D * dPdDsave; // d(p)/d[log(v)] + vdiff = (log(P2) - plog) * P2 / dpdlv; + vlog += - vdiff; + if (std::abs(vdiff) < tolr) { + // Check to see if state is possibly 2-phase, and if so restart + if (dPdDsave < 0 || d2PdTDsave < 0){ + iFail = 1; + } + else{ + D = exp(-vlog); + // NumbItGERG = it; // Used to pass back the number of iterations (not currently used) + + // If requested, check to see if point is possibly 2-phase + if (iFlag > 0){ + PropertiesGERG(T, D, x, PP, Z, dPdD, d2PdD2, d2PdTD, dPdT, U, H, S, Cv, Cp, W, G, JT, Kappa, A); + if ((PP <= 0 || dPdD <= 0 || d2PdTD <= 0) || (Cv <= 0 || Cp <= 0 || W <= 0)) { + // Iteration failed (above loop did find a solution or checks made below indicate possible 2-phase state) + ierr = 1; + herr = "Calculation failed to converge in GERG method, ideal gas density returned."; + D = P / RGERG / T; + } + return; + } + return; // Iteration converged + } + } + } + } +} + +void PropertiesGERG(const double T, const double D, const std::vector &x, double &P, double &Z, double &dPdD, double &d2PdD2, double &d2PdTD, double &dPdT, double &U, double &H, double &S, double &Cv, double &Cp, double &W, double &G, double &JT, double &Kappa, double &A) +{ + // Sub PropertiesGERG(T, D, x, P, Z, dPdD, d2PdD2, d2PdTD, dPdT, U, H, S, Cv, Cp, W, G, JT, Kappa, A) + + // Calculate thermodynamic properties as a function of temperature and density. Calls are made to the subroutines + // ReducingParametersGERG, IdealGERG, and ResidualGERG. If the density is not known, call subroutine DENSITY first + // with the known values of pressure and temperature. + + // Inputs: + // T - temperature (K) + // D - density (mol/l) + // x() - composition (mole fraction) + + // Outputs: + // P - pressure (kPa) + // Z - compressibility factor + // dPdD - first derivative of pressure with respect to density [kPa/(mol/l)] + // d2PdD2 - second derivative of pressure with respect to density [kPa/(mol/l)^2] + // d2PdTD - second derivative of pressure with respect to temperature and density [kPa/(mol/l)/K] + // dPdT - first derivative of pressure with respect to temperature (kPa/K) + // U - internal energy (J/mol) + // H - enthalpy (J/mol) + // S - entropy (J/mol-K) + // Cv - isochoric heat capacity (J/mol-K) + // Cp - isobaric heat capacity (J/mol-K) + // W - speed of sound (m/s) + // G - Gibbs energy (J/mol) + // JT - Joule-Thomson coefficient (K/kPa) + // Kappa - Isentropic Exponent + // A - Helmholtz energy (J/mol) + + double a0[2+1], ar[3+1][3+1], Mm, R, RT; + + // Calculate molar mass + MolarMassGERG(x, Mm); + + // Calculate the ideal gas Helmholtz energy, and its first and second derivatives with respect to temperature. + Alpha0GERG(T, D, x, a0); + + // Calculate the real gas Helmholtz energy, and its derivatives with respect to temperature and/or density. + AlpharGERG(1, T, D, x, ar); + + R = RGERG; + RT = R * T; + Z = 1 + ar[0][1]; + P = D * RT * Z; + dPdD = RT * (1 + 2 * ar[0][1] + ar[0][2]); + dPdT = D * R * (1 + ar[0][1] - ar[1][1]); + d2PdTD = R * (1 + 2 * ar[0][1] + ar[0][2] - 2 * ar[1][1] - ar[1][2]); + A = a0[0] + ar[0][0]; + G = RT * (1 + ar[0][1] + a0[0] + ar[0][0]); + U = RT * (a0[1] + ar[1][0]); + H = RT * (1 + ar[0][1] + a0[1] + ar[1][0]); + S = R * (a0[1] + ar[1][0] - a0[0] - ar[0][0]); + Cv = -R * (a0[2] + ar[2][0]); + if (D > 0){ + Cp = Cv + T * (dPdT / D) * (dPdT / D) / dPdD; + d2PdD2 = RT * (2 * ar[0][1] + 4 * ar[0][2] + ar[0][3]) / D; + JT = (T / D * dPdT / dPdD - 1) / Cp / D; // '=(dB/dT*T-B)/Cp for an ideal gas, but dB/dT is not known + } + else{ + Cp = Cv + R; + d2PdD2 = 0; + JT = 1E+20; + } + W = 1000 * Cp / Cv * dPdD / Mm; + if (W < 0) { W = 0; } + W = sqrt(W); + Kappa = pow(W, 2) * Mm / (RT * 1000 * Z); +} + + +// The following routines are low-level routines that should not be called outside of this code. + +void ReducingParametersGERG(const std::vector &x, double &Tr, double &Dr) +{ + // Private Sub ReducingParametersGERG(x, Tr, Dr) + + // Calculate reducing variables. Only need to call this if the composition has changed. + + // Inputs: + // x() - composition (mole fraction) + + // Outputs: + // Tr - reducing temperature (K) + // Dr - reducing density (mol/l) + + double Vr, xij, F; + int icheck; + + // Check to see if a component fraction has changed. If x is the same as the previous call, then exit. + icheck = 0; + for (int i = 1; i <= NcGERG; ++i){ + if (std::abs(x[i] - xold[i]) > 0.00000001){ icheck = 1; } + xold[i] = x[i]; + } + if (icheck == 0){ + Dr = Drold; + Tr = Trold; + return; + } + Told = 0; + Trold2 = 0; + + // Calculate reducing variables for T and D + Dr = 0; + Vr = 0; + Tr = 0; + for (int i = 1; i <= NcGERG; ++i){ + if (x[i] > 0){ + F = 1; + for (int j = i; j <= NcGERG; ++j){ + if (x[j] > 0){ + xij = F * (x[i] * x[j]) * (x[i] + x[j]); + Vr = Vr + xij * gvij[i][j] / (bvij[i][j] * x[i] + x[j]); + Tr = Tr + xij * gtij[i][j] / (btij[i][j] * x[i] + x[j]); + F = 2; + } + } + } + } + if (Vr > 0){ Dr = 1 / Vr; } + Drold = Dr; + Trold = Tr; +} + +void Alpha0GERG(const double T, const double D, const std::vector &x, double a0[3]) +{ + // Private Sub Alpha0GERG(T, D, x, a0) + + // Calculate the ideal gas Helmholtz energy and its derivatives with respect to tau and delta. + // This routine is not needed when only P (or Z) is calculated. + + // Inputs: + // T - temperature (K) + // D - density (mol/l) + // x() - composition (mole fraction) + + // Outputs: + // a0(0) - ideal gas Helmholtz energy (dimensionless [i.e., divided by RT]) + // a0(1) - tau*partial(a0)/partial(tau) + // a0(2) - tau^2*partial^2(a0)/partial(tau)^2 + + double LogT, LogD, LogHyp, th0T, LogxD; + double SumHyp0, SumHyp1, SumHyp2; + double em, ep, hcn, hsn; + + a0[0] = 0; a0[1] = 0; a0[2] = 0; + if (D > 0) {LogD = log(D);} else {LogD = log(1E-20);} + LogT = log(T); + for (int i = 1; i <= NcGERG; ++i){ + if (x[i] > 0){ + LogxD = LogD + log(x[i]); + SumHyp0 = 0; + SumHyp1 = 0; + SumHyp2 = 0; + for (int j = 4; j <= 7; ++j){ + if (th0i[i][j] > 0){ + th0T = th0i[i][j] / T; + ep = exp(th0T); + em = 1 / ep; + hsn = (ep - em) / 2; + hcn = (ep + em) / 2; + if (j == 4 || j == 6){ + LogHyp = log(std::abs(hsn)); + SumHyp0 = SumHyp0 + n0i[i][j] * LogHyp; + SumHyp1 = SumHyp1 + n0i[i][j] * th0T * hcn / hsn; + SumHyp2 = SumHyp2 + n0i[i][j] * (th0T / hsn)* (th0T / hsn); + } + else{ + LogHyp = log(std::abs(hcn)); + SumHyp0 = SumHyp0 - n0i[i][j] * LogHyp; + SumHyp1 = SumHyp1 - n0i[i][j] * th0T * hsn / hcn; + SumHyp2 = SumHyp2 + n0i[i][j] * (th0T / hcn) * (th0T / hcn); + } + } + } + a0[0] += +x[i] * (LogxD + n0i[i][1] + n0i[i][2] / T - n0i[i][3] * LogT + SumHyp0); + a0[1] += +x[i] * (n0i[i][3] + n0i[i][2] / T + SumHyp1); + a0[2] += -x[i] * (n0i[i][3] + SumHyp2); + } + } +} + +void AlpharGERG(const int iprop, const double T, const double D, const std::vector &x, double ar[4][4]) +{ + // Private Sub AlpharGERG(iprop, T, D, x, ar) + + // Calculate dimensionless residual Helmholtz energy and its derivatives with respect to tau and delta. + + // Inputs: + // iprop - set to 1 to return all derivatives or 0 to return only pressure related properties [ar(0,1) and ar(0,2)] + // T - temperature (K) + // D - density (mol/l) + // x() - composition (mole fraction) + + // Outputs: + // ar(0,0) - residual Helmholtz energy (dimensionless, =a/RT) + // ar(0,1) - del*partial (ar)/partial(del) + // ar(0,2) - del^2*partial^2(ar)/partial(del)^2 + // ar(0,3) - del^3*partial^3(ar)/partial(del)^3 + // ar(1,0) - tau*partial (ar)/partial(tau) + // ar(1,1) - tau*del*partial^2(ar)/partial(tau)/partial(del) + // ar(2,0) - tau^2*partial^2(ar)/partial(tau)^2 + + int mn; + double Tr, Dr, del, tau; + double lntau, ex, ex2, ex3, cij0, eij0; + double delp[7+1], Expd[7+1], ndt, ndtd, ndtt, xijf; + + for (int i = 0; i <= 3; ++i){ for (int j = 0; j <= 3; ++j){ ar[i][j] = 0; } } + + //Set up del, tau, log(tau), and the first 7 calculations for del^i + ReducingParametersGERG(x, Tr, Dr); + del = D / Dr; + tau = Tr / T; + lntau = log(tau); + delp[1] = del; + Expd[1] = exp(-delp[1]); + for (int i = 2; i <= 7; ++i){ + delp[i] = delp[i - 1] * del; + Expd[i] = exp(-delp[i]); + } + + // If temperature has changed, calculate temperature dependent parts + if (std::abs(T - Told) > 0.00000001 || std::abs(Tr - Trold2) > 0.00000001) { + tTermsGERG(tau, lntau, x); + } + Told = T; + Trold2 = Tr; + + // Calculate pure fluid contributions + for (int i = 1; i <= NcGERG; ++i){ + if (x[i] > 0){ + for (int k = 1; k <= kpol[i]; ++k){ + ndt = x[i] * delp[doik[i][k]] * taup[i][k]; + ndtd = ndt * doik[i][k]; + ar[0][1] += ndtd; + ar[0][2] += ndtd * (doik[i][k] - 1); + if (iprop > 0){ + ndtt = ndt * toik[i][k]; + ar[0][0] += ndt; + ar[1][0] += ndtt; + ar[2][0] += ndtt * (toik[i][k] - 1); + ar[1][1] += ndtt * doik[i][k]; + ar[1][2] += ndtt * doik[i][k] * (doik[i][k] - 1); + ar[0][3] += ndtd * (doik[i][k] - 1) * (doik[i][k] - 2); + } + } + for (int k = 1 + kpol[i]; k <= kpol[i] + kexp[i]; ++k){ + ndt = x[i] * delp[doik[i][k]] * taup[i][k]*Expd[coik[i][k]]; + ex = coik[i][k] * delp[coik[i][k]]; + ex2 = doik[i][k] - ex; + ex3 = ex2 * (ex2 - 1); + ar[0][1] += ndt * ex2; + ar[0][2] += ndt * (ex3 - coik[i][k] * ex); + if (iprop > 0){ + ndtt = ndt * toik[i][k]; + ar[0][0] += ndt; + ar[1][0] += ndtt; + ar[2][0] += ndtt * (toik[i][k] - 1); + ar[1][1] += ndtt * ex2; + ar[1][2] += ndtt * (ex3 - coik[i][k] * ex); + ar[0][3] += ndt * (ex3 * (ex2 - 2) - ex * (3 * ex2 - 3 + coik[i][k]) * coik[i][k]); + } + } + } + } + + // Calculate mixture contributions + for (int i = 1; i <= NcGERG - 1; ++i){ + if (x[i] > 0){ + for (int j = i + 1; j <= NcGERG; ++j){ + if (x[j] > 0){ + mn = mNumb[i][j]; + if (mn >= 0){ + xijf = x[i] * x[j] * fij[i][j]; + for (int k = 1; k <= kpolij[mn]; ++k){ + ndt = xijf * delp[dijk[mn][k]] * taupijk[mn][k]; + ndtd = ndt * dijk[mn][k]; + ar[0][1] += ndtd; + ar[0][2] += ndtd * (dijk[mn][k] - 1); + if (iprop > 0){ + ndtt = ndt * tijk[mn][k]; + ar[0][0] += ndt; + ar[1][0] += ndtt; + ar[2][0] += ndtt * (tijk[mn][k] - 1); + ar[1][1] += ndtt * dijk[mn][k]; + ar[1][2] += ndtt * dijk[mn][k] * (dijk[mn][k] - 1); + ar[0][3] += ndtd * (dijk[mn][k] - 1) * (dijk[mn][k] - 2); + } + } + for (int k = 1 + kpolij[mn]; k <= kpolij[mn] + kexpij[mn]; ++k){ + cij0 = cijk[mn][k] * delp[2]; + eij0 = eijk[mn][k] * del; + ndt = xijf * nijk[mn][k] * delp[dijk[mn][k]] * exp(cij0 + eij0 + gijk[mn][k] + tijk[mn][k] * lntau); + ex = dijk[mn][k] + 2 * cij0 + eij0; + ex2 = (ex * ex - dijk[mn][k] + 2 * cij0); + ar[0][1] += ndt * ex; + ar[0][2] += ndt * ex2; + if(iprop > 0){ + ndtt = ndt * tijk[mn][k]; + ar[0][0] += ndt; + ar[1][0] += ndtt; + ar[2][0] += ndtt * (tijk[mn][k] - 1); + ar[1][1] += ndtt * ex; + ar[1][2] += ndtt * ex2; + // ar[0][3] += ... 'The contribution from the Fij terms with an exponential piece is negligible for the 3rd derivative (<1 ppm) + } + } + } + } + } + } + } +} + +void tTermsGERG(const double tau, const double lntau, const std::vector &x) +{ + // Private Sub tTermsGERG(tau, lntau, x) + + // Calculate temperature dependent parts of the GERG-2008 equation of state + + int i, mn; + double taup0[12+1]; + + i = 5; // Use propane to get exponents for short form of EOS + for (int k = 1; k <= kpol[i] + kexp[i]; ++k){ + taup0[k] = exp(toik[i][k] * lntau); + } + for (int i = 1; i <= NcGERG; ++i){ + if (x[i] > 0){ + if (i > 4 && i != 15 && i != 18 && i != 20 ) { + for (int k = 1; k <= kpol[i] + kexp[i]; ++k){ + taup[i][k] = noik[i][k] * taup0[k]; + } + } + else{ + for (int k = 1; k <= kpol[i] + kexp[i]; ++k){ + taup[i][k] = noik[i][k] * exp(toik[i][k] * lntau); + } + } + } + } + + for (int i = 1; i <= NcGERG - 1; ++i) { + if (x[i] > 0){ + for (int j = i + 1; j <= NcGERG; ++j) { + if (x[j] > 0) { + mn = mNumb[i][j]; + if (mn >= 0) { + for (int k = 1; k <= kpolij[mn]; ++k) { + taupijk[mn][k] = nijk[mn][k] * exp(tijk[mn][k] * lntau); + } + } + } + } + } + } +} + + +void PseudoCriticalPointGERG(const std::vector &x, double &Tcx, double &Dcx) +{ + // PseudoCriticalPointGERG(x, Tcx, Dcx) + + // Calculate a pseudo critical point as the mole fraction average of the critical temperatures and critical volumes + + double Vcx; + Tcx = 0; + Vcx = 0; + Dcx = 0; + for (int i = 1; i <= NcGERG; ++i){ + Tcx = Tcx + x[i] * Tc[i]; + Vcx = Vcx + x[i] / Dc[i]; + } + if (Vcx > 0){ Dcx = 1 / Vcx; } +} + +// The following routine must be called once before any other routine. +void SetupGERG() +{ + // Initialize all the constants and parameters in the GERG-2008 model. + // Some values are modified for calculations that do not depend on T, D, and x in order to speed up the program. + + double o13, bijk[MaxMdl+1][MaxTrmM+1], Rs, Rsr; + double n1, n2, T0, d0; + + RGERG = 8.314472; + Rs = 8.31451; + Rsr = Rs / RGERG; + o13 = 1.0 / 3.0; + + for (int i = 1; i <= MaxFlds; ++i){ + xold[i] = 0; + } + Told = 0; + + // Molar masses [g/mol] + MMiGERG[1] = 16.04246; // Methane + MMiGERG[2] = 28.0134; // Nitrogen + MMiGERG[3] = 44.0095; // Carbon dioxide + MMiGERG[4] = 30.06904; // Ethane + MMiGERG[5] = 44.09562; // Propane + MMiGERG[6] = 58.1222; // Isobutane + MMiGERG[7] = 58.1222; // n-Butane + MMiGERG[8] = 72.14878; // Isopentane + MMiGERG[9] = 72.14878; // n-Pentane + MMiGERG[10] = 86.17536; // Hexane + MMiGERG[11] = 100.20194; // Heptane + MMiGERG[12] = 114.22852; // Octane + MMiGERG[13] = 128.2551; // Nonane + MMiGERG[14] = 142.28168; // Decane + MMiGERG[15] = 2.01588; // Hydrogen + MMiGERG[16] = 31.9988; // Oxygen + MMiGERG[17] = 28.0101; // Carbon monoxide + MMiGERG[18] = 18.01528; // Water + MMiGERG[19] = 34.08088; // Hydrogen sulfide + MMiGERG[20] = 4.002602; // Helium + MMiGERG[21] = 39.948; // Argon + + // Number of polynomial and exponential terms + for(int i = 1; i <= MaxFlds; ++i){ + kpol[i] = 6; + kexp[i] = 6; + } + kexp[1] = 18; + kexp[2] = 18; + kexp[4] = 18; + kpol[3] = 4; kexp[3] = 18; + kpol[15] = 5; kexp[15] = 9; + kpol[18] = 7; kexp[18] = 9; + kpol[20] = 4; kexp[20] = 8; + kpolij[1] = 2; kexpij[1] = 10; + kpolij[2] = 5; kexpij[2] = 4; + kpolij[3] = 2; kexpij[3] = 7; + kpolij[4] = 3; kexpij[4] = 3; + kpolij[5] = 2; kexpij[5] = 4; + kpolij[6] = 3; kexpij[6] = 3; + kpolij[7] = 4; kexpij[7] = 0; + kpolij[10] = 10; kexpij[10] = 0; + + // Critical densities [mol/l] + Dc[1] = 10.139342719; + Dc[2] = 11.1839; + Dc[3] = 10.624978698; + Dc[4] = 6.87085454; + Dc[5] = 5.000043088; + Dc[6] = 3.86014294; + Dc[7] = 3.920016792; + Dc[8] = 3.271; + Dc[9] = 3.215577588; + Dc[10] = 2.705877875; + Dc[11] = 2.315324434; + Dc[12] = 2.056404127; + Dc[13] = 1.81; + Dc[14] = 1.64; + Dc[15] = 14.94; + Dc[16] = 13.63; + Dc[17] = 10.85; + Dc[18] = 17.87371609; + Dc[19] = 10.19; + Dc[20] = 17.399; + Dc[21] = 13.407429659; + + // Critical temperatures [K] + Tc[1] = 190.564; + Tc[2] = 126.192; + Tc[3] = 304.1282; + Tc[4] = 305.322; + Tc[5] = 369.825; + Tc[6] = 407.817; + Tc[7] = 425.125; + Tc[8] = 460.35; + Tc[9] = 469.7; + Tc[10] = 507.82; + Tc[11] = 540.13; + Tc[12] = 569.32; + Tc[13] = 594.55; + Tc[14] = 617.7; + Tc[15] = 33.19; + Tc[16] = 154.595; + Tc[17] = 132.86; + Tc[18] = 647.096; + Tc[19] = 373.1; + Tc[20] = 5.1953; + Tc[21] = 150.687; + + // Exponents in pure fluid equations + for(int i = 1; i <= MaxFlds; ++i){ + Vc3[i] = 1 / pow(Dc[i], o13) / 2; + Tc2[i] = sqrt(Tc[i]); + coik[i][1] = 0; doik[i][1] = 1; toik[i][1] = 0.25; + coik[i][2] = 0; doik[i][2] = 1; toik[i][2] = 1.125; + coik[i][3] = 0; doik[i][3] = 1; toik[i][3] = 1.5; + coik[i][4] = 0; doik[i][4] = 2; toik[i][4] = 1.375; + coik[i][5] = 0; doik[i][5] = 3; toik[i][5] = 0.25; + coik[i][6] = 0; doik[i][6] = 7; toik[i][6] = 0.875; + coik[i][7] = 1; doik[i][7] = 2; toik[i][7] = 0.625; + coik[i][8] = 1; doik[i][8] = 5; toik[i][8] = 1.75; + coik[i][9] = 2; doik[i][9] = 1; toik[i][9] = 3.625; + coik[i][10] = 2; doik[i][10] = 4; toik[i][10] = 3.625; + coik[i][11] = 3; doik[i][11] = 3; toik[i][11] = 14.5; + coik[i][12] = 3; doik[i][12] = 4; toik[i][12] = 12; + } + for (int i = 1; i <= 4; ++i){ + if (i != 3){ + coik[i][1] = 0; doik[i][1] = 1; toik[i][1] = 0.125; + coik[i][2] = 0; doik[i][2] = 1; toik[i][2] = 1.125; + coik[i][3] = 0; doik[i][3] = 2; toik[i][3] = 0.375; + coik[i][4] = 0; doik[i][4] = 2; toik[i][4] = 1.125; + coik[i][5] = 0; doik[i][5] = 4; toik[i][5] = 0.625; + coik[i][6] = 0; doik[i][6] = 4; toik[i][6] = 1.5; + coik[i][7] = 1; doik[i][7] = 1; toik[i][7] = 0.625; + coik[i][8] = 1; doik[i][8] = 1; toik[i][8] = 2.625; + coik[i][9] = 1; doik[i][9] = 1; toik[i][9] = 2.75; + coik[i][10] = 1; doik[i][10] = 2; toik[i][10] = 2.125; + coik[i][11] = 1; doik[i][11] = 3; toik[i][11] = 2; + coik[i][12] = 1; doik[i][12] = 6; toik[i][12] = 1.75; + coik[i][13] = 2; doik[i][13] = 2; toik[i][13] = 4.5; + coik[i][14] = 2; doik[i][14] = 3; toik[i][14] = 4.75; + coik[i][15] = 2; doik[i][15] = 3; toik[i][15] = 5; + coik[i][16] = 2; doik[i][16] = 4; toik[i][16] = 4; + coik[i][17] = 2; doik[i][17] = 4; toik[i][17] = 4.5; + coik[i][18] = 3; doik[i][18] = 2; toik[i][18] = 7.5; + coik[i][19] = 3; doik[i][19] = 3; toik[i][19] = 14; + coik[i][20] = 3; doik[i][20] = 4; toik[i][20] = 11.5; + coik[i][21] = 6; doik[i][21] = 5; toik[i][21] = 26; + coik[i][22] = 6; doik[i][22] = 6; toik[i][22] = 28; + coik[i][23] = 6; doik[i][23] = 6; toik[i][23] = 30; + coik[i][24] = 6; doik[i][24] = 7; toik[i][24] = 16; + } + } + + // Coefficients of pure fluid equations + // Methane + noik[1][1] = 0.57335704239162; + noik[1][2] = -1.676068752373; + noik[1][3] = 0.23405291834916; + noik[1][4] = -0.21947376343441; + noik[1][5] = 0.016369201404128; + noik[1][6] = 0.01500440638928; + noik[1][7] = 0.098990489492918; + noik[1][8] = 0.58382770929055; + noik[1][9] = -0.7478686756039; + noik[1][10] = 0.30033302857974; + noik[1][11] = 0.20985543806568; + noik[1][12] = -0.018590151133061; + noik[1][13] = -0.15782558339049; + noik[1][14] = 0.12716735220791; + noik[1][15] = -0.032019743894346; + noik[1][16] = -0.068049729364536; + noik[1][17] = 0.024291412853736; + noik[1][18] = 5.1440451639444E-03; + noik[1][19] = -0.019084949733532; + noik[1][20] = 5.5229677241291E-03; + noik[1][21] = -4.4197392976085E-03; + noik[1][22] = 0.040061416708429; + noik[1][23] = -0.033752085907575; + noik[1][24] = -2.5127658213357E-03; + // Nitrogen + noik[2][1] = 0.59889711801201; + noik[2][2] = -1.6941557480731; + noik[2][3] = 0.24579736191718; + noik[2][4] = -0.23722456755175; + noik[2][5] = 0.017954918715141; + noik[2][6] = 0.014592875720215; + noik[2][7] = 0.10008065936206; + noik[2][8] = 0.73157115385532; + noik[2][9] = -0.88372272336366; + noik[2][10] = 0.31887660246708; + noik[2][11] = 0.20766491728799; + noik[2][12] = -0.019379315454158; + noik[2][13] = -0.16936641554983; + noik[2][14] = 0.13546846041701; + noik[2][15] = -0.033066712095307; + noik[2][16] = -0.060690817018557; + noik[2][17] = 0.012797548292871; + noik[2][18] = 5.8743664107299E-03; + noik[2][19] = -0.018451951971969; + noik[2][20] = 4.7226622042472E-03; + noik[2][21] = -5.2024079680599E-03; + noik[2][22] = 0.043563505956635; + noik[2][23] = -0.036251690750939; + noik[2][24] = -2.8974026866543E-03; + // Ethane + noik[4][1] = 0.63596780450714; + noik[4][2] = -1.7377981785459; + noik[4][3] = 0.28914060926272; + noik[4][4] = -0.33714276845694; + noik[4][5] = 0.022405964699561; + noik[4][6] = 0.015715424886913; + noik[4][7] = 0.11450634253745; + noik[4][8] = 1.0612049379745; + noik[4][9] = -1.2855224439423; + noik[4][10] = 0.39414630777652; + noik[4][11] = 0.31390924682041; + noik[4][12] = -0.021592277117247; + noik[4][13] = -0.21723666564905; + noik[4][14] = -0.28999574439489; + noik[4][15] = 0.42321173025732; + noik[4][16] = 0.04643410025926; + noik[4][17] = -0.13138398329741; + noik[4][18] = 0.011492850364368; + noik[4][19] = -0.033387688429909; + noik[4][20] = 0.015183171583644; + noik[4][21] = -4.7610805647657E-03; + noik[4][22] = 0.046917166277885; + noik[4][23] = -0.039401755804649; + noik[4][24] = -3.2569956247611E-03; + // Propane + noik[5][1] = 1.0403973107358; + noik[5][2] = -2.8318404081403; + noik[5][3] = 0.84393809606294; + noik[5][4] = -0.076559591850023; + noik[5][5] = 0.09469737305728; + noik[5][6] = 2.4796475497006E-04; + noik[5][7] = 0.2774376042287; + noik[5][8] = -0.043846000648377; + noik[5][9] = -0.2699106478435; + noik[5][10] = -0.06931341308986; + noik[5][11] = -0.029632145981653; + noik[5][12] = 0.01404012675138; + // Isobutane + noik[6][1] = 1.04293315891; + noik[6][2] = -2.8184272548892; + noik[6][3] = 0.8617623239785; + noik[6][4] = -0.10613619452487; + noik[6][5] = 0.098615749302134; + noik[6][6] = 2.3948208682322E-04; + noik[6][7] = 0.3033000485695; + noik[6][8] = -0.041598156135099; + noik[6][9] = -0.29991937470058; + noik[6][10] = -0.080369342764109; + noik[6][11] = -0.029761373251151; + noik[6][12] = 0.01305963030314; + // n-Butane + noik[7][1] = 1.0626277411455; + noik[7][2] = -2.862095182835; + noik[7][3] = 0.88738233403777; + noik[7][4] = -0.12570581155345; + noik[7][5] = 0.10286308708106; + noik[7][6] = 2.5358040602654E-04; + noik[7][7] = 0.32325200233982; + noik[7][8] = -0.037950761057432; + noik[7][9] = -0.32534802014452; + noik[7][10] = -0.079050969051011; + noik[7][11] = -0.020636720547775; + noik[7][12] = 0.005705380933475; + // Isopentane + noik[8][1] = 1.0963; + noik[8][2] = -3.0402; + noik[8][3] = 1.0317; + noik[8][4] = -0.1541; + noik[8][5] = 0.11535; + noik[8][6] = 0.00029809; + noik[8][7] = 0.39571; + noik[8][8] = -0.045881; + noik[8][9] = -0.35804; + noik[8][10] = -0.10107; + noik[8][11] = -0.035484; + noik[8][12] = 0.018156; + // n-Pentane + noik[9][1] = 1.0968643098001; + noik[9][2] = -2.9988888298061; + noik[9][3] = 0.99516886799212; + noik[9][4] = -0.16170708558539; + noik[9][5] = 0.11334460072775; + noik[9][6] = 2.6760595150748E-04; + noik[9][7] = 0.40979881986931; + noik[9][8] = -0.040876423083075; + noik[9][9] = -0.38169482469447; + noik[9][10] = -0.10931956843993; + noik[9][11] = -0.03207322332799; + noik[9][12] = 0.016877016216975; + // Hexane + noik[10][1] = 1.0553238013661; + noik[10][2] = -2.6120615890629; + noik[10][3] = 0.7661388296726; + noik[10][4] = -0.29770320622459; + noik[10][5] = 0.11879907733358; + noik[10][6] = 2.7922861062617E-04; + noik[10][7] = 0.46347589844105; + noik[10][8] = 0.011433196980297; + noik[10][9] = -0.48256968738131; + noik[10][10] = -0.093750558924659; + noik[10][11] = -6.7273247155994E-03; + noik[10][12] = -5.1141583585428E-03; + // Heptane + noik[11][1] = 1.0543747645262; + noik[11][2] = -2.6500681506144; + noik[11][3] = 0.81730047827543; + noik[11][4] = -0.30451391253428; + noik[11][5] = 0.122538687108; + noik[11][6] = 2.7266472743928E-04; + noik[11][7] = 0.4986582568167; + noik[11][8] = -7.1432815084176E-04; + noik[11][9] = -0.5423689552545; + noik[11][10] = -0.13801821610756; + noik[11][11] = -6.1595287380011E-03; + noik[11][12] = 4.8602510393022E-04; + // Octane + noik[12][1] = 1.0722544875633; + noik[12][2] = -2.4632951172003; + noik[12][3] = 0.65386674054928; + noik[12][4] = -0.36324974085628; + noik[12][5] = 0.12713269626764; + noik[12][6] = 3.071357277793E-04; + noik[12][7] = 0.5265685698754; + noik[12][8] = 0.019362862857653; + noik[12][9] = -0.58939426849155; + noik[12][10] = -0.14069963991934; + noik[12][11] = -7.8966330500036E-03; + noik[12][12] = 3.3036597968109E-03; + // Nonane + noik[13][1] = 1.1151; + noik[13][2] = -2.702; + noik[13][3] = 0.83416; + noik[13][4] = -0.38828; + noik[13][5] = 0.1376; + noik[13][6] = 0.00028185; + noik[13][7] = 0.62037; + noik[13][8] = 0.015847; + noik[13][9] = -0.61726; + noik[13][10] = -0.15043; + noik[13][11] = -0.012982; + noik[13][12] = 0.0044325; + // Decane + noik[14][1] = 1.0461; + noik[14][2] = -2.4807; + noik[14][3] = 0.74372; + noik[14][4] = -0.52579; + noik[14][5] = 0.15315; + noik[14][6] = 0.00032865; + noik[14][7] = 0.84178; + noik[14][8] = 0.055424; + noik[14][9] = -0.73555; + noik[14][10] = -0.18507; + noik[14][11] = -0.020775; + noik[14][12] = 0.012335; + // Oxygen + noik[16][1] = 0.88878286369701; + noik[16][2] = -2.4879433312148; + noik[16][3] = 0.59750190775886; + noik[16][4] = 9.6501817061881E-03; + noik[16][5] = 0.07197042871277; + noik[16][6] = 2.2337443000195E-04; + noik[16][7] = 0.18558686391474; + noik[16][8] = -0.03812936803576; + noik[16][9] = -0.15352245383006; + noik[16][10] = -0.026726814910919; + noik[16][11] = -0.025675298677127; + noik[16][12] = 9.5714302123668E-03; + // Carbon monoxide + noik[17][1] = 0.90554; + noik[17][2] = -2.4515; + noik[17][3] = 0.53149; + noik[17][4] = 0.024173; + noik[17][5] = 0.072156; + noik[17][6] = 0.00018818; + noik[17][7] = 0.19405; + noik[17][8] = -0.043268; + noik[17][9] = -0.12778; + noik[17][10] = -0.027896; + noik[17][11] = -0.034154; + noik[17][12] = 0.016329; + // Hydrogen sulfide + noik[19][1] = 0.87641; + noik[19][2] = -2.0367; + noik[19][3] = 0.21634; + noik[19][4] = -0.050199; + noik[19][5] = 0.066994; + noik[19][6] = 0.00019076; + noik[19][7] = 0.20227; + noik[19][8] = -0.0045348; + noik[19][9] = -0.2223; + noik[19][10] = -0.034714; + noik[19][11] = -0.014885; + noik[19][12] = 0.0074154; + // Argon + noik[21][1] = 0.85095714803969; + noik[21][2] = -2.400322294348; + noik[21][3] = 0.54127841476466; + noik[21][4] = 0.016919770692538; + noik[21][5] = 0.068825965019035; + noik[21][6] = 2.1428032815338E-04; + noik[21][7] = 0.17429895321992; + noik[21][8] = -0.033654495604194; + noik[21][9] = -0.13526799857691; + noik[21][10] = -0.016387350791552; + noik[21][11] = -0.024987666851475; + noik[21][12] = 8.8769204815709E-03; + // Carbon dioxide + coik[3][1] = 0; doik[3][1] = 1; toik[3][1] = 0; noik[3][1] = 0.52646564804653; + coik[3][2] = 0; doik[3][2] = 1; toik[3][2] = 1.25; noik[3][2] = -1.4995725042592; + coik[3][3] = 0; doik[3][3] = 2; toik[3][3] = 1.625; noik[3][3] = 0.27329786733782; + coik[3][4] = 0; doik[3][4] = 3; toik[3][4] = 0.375; noik[3][4] = 0.12949500022786; + coik[3][5] = 1; doik[3][5] = 3; toik[3][5] = 0.375; noik[3][5] = 0.15404088341841; + coik[3][6] = 1; doik[3][6] = 3; toik[3][6] = 1.375; noik[3][6] = -0.58186950946814; + coik[3][7] = 1; doik[3][7] = 4; toik[3][7] = 1.125; noik[3][7] = -0.18022494838296; + coik[3][8] = 1; doik[3][8] = 5; toik[3][8] = 1.375; noik[3][8] = -0.095389904072812; + coik[3][9] = 1; doik[3][9] = 6; toik[3][9] = 0.125; noik[3][9] = -8.0486819317679E-03; + coik[3][10] = 1; doik[3][10] = 6; toik[3][10] = 1.625; noik[3][10] = -0.03554775127309; + coik[3][11] = 2; doik[3][11] = 1; toik[3][11] = 3.75; noik[3][11] = -0.28079014882405; + coik[3][12] = 2; doik[3][12] = 4; toik[3][12] = 3.5; noik[3][12] = -0.082435890081677; + coik[3][13] = 3; doik[3][13] = 1; toik[3][13] = 7.5; noik[3][13] = 0.010832427979006; + coik[3][14] = 3; doik[3][14] = 1; toik[3][14] = 8; noik[3][14] = -6.7073993161097E-03; + coik[3][15] = 3; doik[3][15] = 3; toik[3][15] = 6; noik[3][15] = -4.6827907600524E-03; + coik[3][16] = 3; doik[3][16] = 3; toik[3][16] = 16; noik[3][16] = -0.028359911832177; + coik[3][17] = 3; doik[3][17] = 4; toik[3][17] = 11; noik[3][17] = 0.019500174744098; + coik[3][18] = 5; doik[3][18] = 5; toik[3][18] = 24; noik[3][18] = -0.21609137507166; + coik[3][19] = 5; doik[3][19] = 5; toik[3][19] = 26; noik[3][19] = 0.43772794926972; + coik[3][20] = 5; doik[3][20] = 5; toik[3][20] = 28; noik[3][20] = -0.22130790113593; + coik[3][21] = 6; doik[3][21] = 5; toik[3][21] = 24; noik[3][21] = 0.015190189957331; + coik[3][22] = 6; doik[3][22] = 5; toik[3][22] = 26; noik[3][22] = -0.0153809489533; + // Hydrogen + coik[15][1] = 0; doik[15][1] = 1; toik[15][1] = 0.5; noik[15][1] = 5.3579928451252; + coik[15][2] = 0; doik[15][2] = 1; toik[15][2] = 0.625; noik[15][2] = -6.2050252530595; + coik[15][3] = 0; doik[15][3] = 2; toik[15][3] = 0.375; noik[15][3] = 0.13830241327086; + coik[15][4] = 0; doik[15][4] = 2; toik[15][4] = 0.625; noik[15][4] = -0.071397954896129; + coik[15][5] = 0; doik[15][5] = 4; toik[15][5] = 1.125; noik[15][5] = 0.015474053959733; + coik[15][6] = 1; doik[15][6] = 1; toik[15][6] = 2.625; noik[15][6] = -0.14976806405771; + coik[15][7] = 1; doik[15][7] = 5; toik[15][7] = 0; noik[15][7] = -0.026368723988451; + coik[15][8] = 1; doik[15][8] = 5; toik[15][8] = 0.25; noik[15][8] = 0.056681303156066; + coik[15][9] = 1; doik[15][9] = 5; toik[15][9] = 1.375; noik[15][9] = -0.060063958030436; + coik[15][10] = 2; doik[15][10] = 1; toik[15][10] = 4; noik[15][10] = -0.45043942027132; + coik[15][11] = 2; doik[15][11] = 1; toik[15][11] = 4.25; noik[15][11] = 0.424788402445; + coik[15][12] = 3; doik[15][12] = 2; toik[15][12] = 5; noik[15][12] = -0.021997640827139; + coik[15][13] = 3; doik[15][13] = 5; toik[15][13] = 8; noik[15][13] = -0.01049952137453; + coik[15][14] = 5; doik[15][14] = 1; toik[15][14] = 8; noik[15][14] = -2.8955902866816E-03; + // Water + coik[18][1] = 0; doik[18][1] = 1; toik[18][1] = 0.5; noik[18][1] = 0.82728408749586; + coik[18][2] = 0; doik[18][2] = 1; toik[18][2] = 1.25; noik[18][2] = -1.8602220416584; + coik[18][3] = 0; doik[18][3] = 1; toik[18][3] = 1.875; noik[18][3] = -1.1199009613744; + coik[18][4] = 0; doik[18][4] = 2; toik[18][4] = 0.125; noik[18][4] = 0.15635753976056; + coik[18][5] = 0; doik[18][5] = 2; toik[18][5] = 1.5; noik[18][5] = 0.87375844859025; + coik[18][6] = 0; doik[18][6] = 3; toik[18][6] = 1; noik[18][6] = -0.36674403715731; + coik[18][7] = 0; doik[18][7] = 4; toik[18][7] = 0.75; noik[18][7] = 0.053987893432436; + coik[18][8] = 1; doik[18][8] = 1; toik[18][8] = 1.5; noik[18][8] = 1.0957690214499; + coik[18][9] = 1; doik[18][9] = 5; toik[18][9] = 0.625; noik[18][9] = 0.053213037828563; + coik[18][10] = 1; doik[18][10] = 5; toik[18][10] = 2.625; noik[18][10] = 0.013050533930825; + coik[18][11] = 2; doik[18][11] = 1; toik[18][11] = 5; noik[18][11] = -0.41079520434476; + coik[18][12] = 2; doik[18][12] = 2; toik[18][12] = 4; noik[18][12] = 0.1463744334412; + coik[18][13] = 2; doik[18][13] = 4; toik[18][13] = 4.5; noik[18][13] = -0.055726838623719; + coik[18][14] = 3; doik[18][14] = 4; toik[18][14] = 3; noik[18][14] = -0.0112017741438; + coik[18][15] = 5; doik[18][15] = 1; toik[18][15] = 4; noik[18][15] = -6.6062758068099E-03; + coik[18][16] = 5; doik[18][16] = 1; toik[18][16] = 6; noik[18][16] = 4.6918522004538E-03; + // Helium + coik[20][1] = 0; doik[20][1] = 1; toik[20][1] = 0; noik[20][1] = -0.45579024006737; + coik[20][2] = 0; doik[20][2] = 1; toik[20][2] = 0.125; noik[20][2] = 1.2516390754925; + coik[20][3] = 0; doik[20][3] = 1; toik[20][3] = 0.75; noik[20][3] = -1.5438231650621; + coik[20][4] = 0; doik[20][4] = 4; toik[20][4] = 1; noik[20][4] = 0.020467489707221; + coik[20][5] = 1; doik[20][5] = 1; toik[20][5] = 0.75; noik[20][5] = -0.34476212380781; + coik[20][6] = 1; doik[20][6] = 3; toik[20][6] = 2.625; noik[20][6] = -0.020858459512787; + coik[20][7] = 1; doik[20][7] = 5; toik[20][7] = 0.125; noik[20][7] = 0.016227414711778; + coik[20][8] = 1; doik[20][8] = 5; toik[20][8] = 1.25; noik[20][8] = -0.057471818200892; + coik[20][9] = 1; doik[20][9] = 5; toik[20][9] = 2; noik[20][9] = 0.019462416430715; + coik[20][10] = 2; doik[20][10] = 2; toik[20][10] = 1; noik[20][10] = -0.03329568012302; + coik[20][11] = 3; doik[20][11] = 1; toik[20][11] = 4.5; noik[20][11] = -0.010863577372367; + coik[20][12] = 3; doik[20][12] = 2; toik[20][12] = 5; noik[20][12] = -0.022173365245954; + + // Exponents in mixture equations + // Methane-Nitrogen + dijk[3][1] = 1; tijk[3][1] = 0; cijk[3][1] = 0; eijk[3][1] = 0; bijk[3][1] = 0; gijk[3][1] = 0; nijk[3][1] = -9.8038985517335E-03; + dijk[3][2] = 4; tijk[3][2] = 1.85; cijk[3][2] = 0; eijk[3][2] = 0; bijk[3][2] = 0; gijk[3][2] = 0; nijk[3][2] = 4.2487270143005E-04; + dijk[3][3] = 1; tijk[3][3] = 7.85; cijk[3][3] = 1; eijk[3][3] = 0.5; bijk[3][3] = 1; gijk[3][3] = 0.5; nijk[3][3] = -0.034800214576142; + dijk[3][4] = 2; tijk[3][4] = 5.4; cijk[3][4] = 1; eijk[3][4] = 0.5; bijk[3][4] = 1; gijk[3][4] = 0.5; nijk[3][4] = -0.13333813013896; + dijk[3][5] = 2; tijk[3][5] = 0; cijk[3][5] = 0.25; eijk[3][5] = 0.5; bijk[3][5] = 2.5; gijk[3][5] = 0.5; nijk[3][5] = -0.011993694974627; + dijk[3][6] = 2; tijk[3][6] = 0.75; cijk[3][6] = 0; eijk[3][6] = 0.5; bijk[3][6] = 3; gijk[3][6] = 0.5; nijk[3][6] = 0.069243379775168; + dijk[3][7] = 2; tijk[3][7] = 2.8; cijk[3][7] = 0; eijk[3][7] = 0.5; bijk[3][7] = 3; gijk[3][7] = 0.5; nijk[3][7] = -0.31022508148249; + dijk[3][8] = 2; tijk[3][8] = 4.45; cijk[3][8] = 0; eijk[3][8] = 0.5; bijk[3][8] = 3; gijk[3][8] = 0.5; nijk[3][8] = 0.24495491753226; + dijk[3][9] = 3; tijk[3][9] = 4.25; cijk[3][9] = 0; eijk[3][9] = 0.5; bijk[3][9] = 3; gijk[3][9] = 0.5; nijk[3][9] = 0.22369816716981; + // Methane-Carbon dioxide + dijk[4][1] = 1; tijk[4][1] = 2.6; cijk[4][1] = 0; eijk[4][1] = 0; bijk[4][1] = 0; gijk[4][1] = 0; nijk[4][1] = -0.10859387354942; + dijk[4][2] = 2; tijk[4][2] = 1.95; cijk[4][2] = 0; eijk[4][2] = 0; bijk[4][2] = 0; gijk[4][2] = 0; nijk[4][2] = 0.080228576727389; + dijk[4][3] = 3; tijk[4][3] = 0; cijk[4][3] = 0; eijk[4][3] = 0; bijk[4][3] = 0; gijk[4][3] = 0; nijk[4][3] = -9.3303985115717E-03; + dijk[4][4] = 1; tijk[4][4] = 3.95; cijk[4][4] = 1; eijk[4][4] = 0.5; bijk[4][4] = 1; gijk[4][4] = 0.5; nijk[4][4] = 0.040989274005848; + dijk[4][5] = 2; tijk[4][5] = 7.95; cijk[4][5] = 0.5; eijk[4][5] = 0.5; bijk[4][5] = 2; gijk[4][5] = 0.5; nijk[4][5] = -0.24338019772494; + dijk[4][6] = 3; tijk[4][6] = 8; cijk[4][6] = 0; eijk[4][6] = 0.5; bijk[4][6] = 3; gijk[4][6] = 0.5; nijk[4][6] = 0.23855347281124; + // Methane-Ethane + dijk[1][1] = 3; tijk[1][1] = 0.65; cijk[1][1] = 0; eijk[1][1] = 0; bijk[1][1] = 0; gijk[1][1] = 0; nijk[1][1] = -8.0926050298746E-04; + dijk[1][2] = 4; tijk[1][2] = 1.55; cijk[1][2] = 0; eijk[1][2] = 0; bijk[1][2] = 0; gijk[1][2] = 0; nijk[1][2] = -7.5381925080059E-04; + dijk[1][3] = 1; tijk[1][3] = 3.1; cijk[1][3] = 1; eijk[1][3] = 0.5; bijk[1][3] = 1; gijk[1][3] = 0.5; nijk[1][3] = -0.041618768891219; + dijk[1][4] = 2; tijk[1][4] = 5.9; cijk[1][4] = 1; eijk[1][4] = 0.5; bijk[1][4] = 1; gijk[1][4] = 0.5; nijk[1][4] = -0.23452173681569; + dijk[1][5] = 2; tijk[1][5] = 7.05; cijk[1][5] = 1; eijk[1][5] = 0.5; bijk[1][5] = 1; gijk[1][5] = 0.5; nijk[1][5] = 0.14003840584586; + dijk[1][6] = 2; tijk[1][6] = 3.35; cijk[1][6] = 0.875; eijk[1][6] = 0.5; bijk[1][6] = 1.25; gijk[1][6] = 0.5; nijk[1][6] = 0.063281744807738; + dijk[1][7] = 2; tijk[1][7] = 1.2; cijk[1][7] = 0.75; eijk[1][7] = 0.5; bijk[1][7] = 1.5; gijk[1][7] = 0.5; nijk[1][7] = -0.034660425848809; + dijk[1][8] = 2; tijk[1][8] = 5.8; cijk[1][8] = 0.5; eijk[1][8] = 0.5; bijk[1][8] = 2; gijk[1][8] = 0.5; nijk[1][8] = -0.23918747334251; + dijk[1][9] = 2; tijk[1][9] = 2.7; cijk[1][9] = 0; eijk[1][9] = 0.5; bijk[1][9] = 3; gijk[1][9] = 0.5; nijk[1][9] = 1.9855255066891E-03; + dijk[1][10] = 3; tijk[1][10] = 0.45; cijk[1][10] = 0; eijk[1][10] = 0.5; bijk[1][10] = 3; gijk[1][10] = 0.5; nijk[1][10] = 6.1777746171555; + dijk[1][11] = 3; tijk[1][11] = 0.55; cijk[1][11] = 0; eijk[1][11] = 0.5; bijk[1][11] = 3; gijk[1][11] = 0.5; nijk[1][11] = -6.9575358271105; + dijk[1][12] = 3; tijk[1][12] = 1.95; cijk[1][12] = 0; eijk[1][12] = 0.5; bijk[1][12] = 3; gijk[1][12] = 0.5; nijk[1][12] = 1.0630185306388; + // Methane-Propane + dijk[2][1] = 3; tijk[2][1] = 1.85; cijk[2][1] = 0; eijk[2][1] = 0; bijk[2][1] = 0; gijk[2][1] = 0; nijk[2][1] = 0.013746429958576; + dijk[2][2] = 3; tijk[2][2] = 3.95; cijk[2][2] = 0; eijk[2][2] = 0; bijk[2][2] = 0; gijk[2][2] = 0; nijk[2][2] = -7.4425012129552E-03; + dijk[2][3] = 4; tijk[2][3] = 0; cijk[2][3] = 0; eijk[2][3] = 0; bijk[2][3] = 0; gijk[2][3] = 0; nijk[2][3] = -4.5516600213685E-03; + dijk[2][4] = 4; tijk[2][4] = 1.85; cijk[2][4] = 0; eijk[2][4] = 0; bijk[2][4] = 0; gijk[2][4] = 0; nijk[2][4] = -5.4546603350237E-03; + dijk[2][5] = 4; tijk[2][5] = 3.85; cijk[2][5] = 0; eijk[2][5] = 0; bijk[2][5] = 0; gijk[2][5] = 0; nijk[2][5] = 2.3682016824471E-03; + dijk[2][6] = 1; tijk[2][6] = 5.25; cijk[2][6] = 0.25; eijk[2][6] = 0.5; bijk[2][6] = 0.75; gijk[2][6] = 0.5; nijk[2][6] = 0.18007763721438; + dijk[2][7] = 1; tijk[2][7] = 3.85; cijk[2][7] = 0.25; eijk[2][7] = 0.5; bijk[2][7] = 1; gijk[2][7] = 0.5; nijk[2][7] = -0.44773942932486; + dijk[2][8] = 1; tijk[2][8] = 0.2; cijk[2][8] = 0; eijk[2][8] = 0.5; bijk[2][8] = 2; gijk[2][8] = 0.5; nijk[2][8] = 0.0193273748882; + dijk[2][9] = 2; tijk[2][9] = 6.5; cijk[2][9] = 0; eijk[2][9] = 0.5; bijk[2][9] = 3; gijk[2][9] = 0.5; nijk[2][9] = -0.30632197804624; + // Nitrogen-Carbon dioxide + dijk[5][1] = 2; tijk[5][1] = 1.85; cijk[5][1] = 0; eijk[5][1] = 0; bijk[5][1] = 0; gijk[5][1] = 0; nijk[5][1] = 0.28661625028399; + dijk[5][2] = 3; tijk[5][2] = 1.4; cijk[5][2] = 0; eijk[5][2] = 0; bijk[5][2] = 0; gijk[5][2] = 0; nijk[5][2] = -0.10919833861247; + dijk[5][3] = 1; tijk[5][3] = 3.2; cijk[5][3] = 0.25; eijk[5][3] = 0.5; bijk[5][3] = 0.75; gijk[5][3] = 0.5; nijk[5][3] = -1.137403208227; + dijk[5][4] = 1; tijk[5][4] = 2.5; cijk[5][4] = 0.25; eijk[5][4] = 0.5; bijk[5][4] = 1; gijk[5][4] = 0.5; nijk[5][4] = 0.76580544237358; + dijk[5][5] = 1; tijk[5][5] = 8; cijk[5][5] = 0; eijk[5][5] = 0.5; bijk[5][5] = 2; gijk[5][5] = 0.5; nijk[5][5] = 4.2638000926819E-03; + dijk[5][6] = 2; tijk[5][6] = 3.75; cijk[5][6] = 0; eijk[5][6] = 0.5; bijk[5][6] = 3; gijk[5][6] = 0.5; nijk[5][6] = 0.17673538204534; + // Nitrogen-Ethane + dijk[6][1] = 2; tijk[6][1] = 0; cijk[6][1] = 0; eijk[6][1] = 0; bijk[6][1] = 0; gijk[6][1] = 0; nijk[6][1] = -0.47376518126608; + dijk[6][2] = 2; tijk[6][2] = 0.05; cijk[6][2] = 0; eijk[6][2] = 0; bijk[6][2] = 0; gijk[6][2] = 0; nijk[6][2] = 0.48961193461001; + dijk[6][3] = 3; tijk[6][3] = 0; cijk[6][3] = 0; eijk[6][3] = 0; bijk[6][3] = 0; gijk[6][3] = 0; nijk[6][3] = -5.7011062090535E-03; + dijk[6][4] = 1; tijk[6][4] = 3.65; cijk[6][4] = 1; eijk[6][4] = 0.5; bijk[6][4] = 1; gijk[6][4] = 0.5; nijk[6][4] = -0.1996682004132; + dijk[6][5] = 2; tijk[6][5] = 4.9; cijk[6][5] = 1; eijk[6][5] = 0.5; bijk[6][5] = 1; gijk[6][5] = 0.5; nijk[6][5] = -0.69411103101723; + dijk[6][6] = 2; tijk[6][6] = 4.45; cijk[6][6] = 0.875; eijk[6][6] = 0.5; bijk[6][6] = 1.25; gijk[6][6] = 0.5; nijk[6][6] = 0.69226192739021; + // Methane-Hydrogen + dijk[7][1] = 1; tijk[7][1] = 2; cijk[7][1] = 0; eijk[7][1] = 0; bijk[7][1] = 0; gijk[7][1] = 0; nijk[7][1] = -0.25157134971934; + dijk[7][2] = 3; tijk[7][2] = -1; cijk[7][2] = 0; eijk[7][2] = 0; bijk[7][2] = 0; gijk[7][2] = 0; nijk[7][2] = -6.2203841111983E-03; + dijk[7][3] = 3; tijk[7][3] = 1.75; cijk[7][3] = 0; eijk[7][3] = 0; bijk[7][3] = 0; gijk[7][3] = 0; nijk[7][3] = 0.088850315184396; + dijk[7][4] = 4; tijk[7][4] = 1.4; cijk[7][4] = 0; eijk[7][4] = 0; bijk[7][4] = 0; gijk[7][4] = 0; nijk[7][4] = -0.035592212573239; + // Methane-n-Butane, Methane-Isobutane, Ethane-Propane, Ethane-n-Butane, + // Ethane-Isobutane, Propane-n-Butane, Propane-Isobutane, and n-Butane-Isobutane + dijk[10][1] = 1; tijk[10][1] = 1; cijk[10][1] = 0; eijk[10][1] = 0; bijk[10][1] = 0; gijk[10][1] = 0; nijk[10][1] = 2.5574776844118; + dijk[10][2] = 1; tijk[10][2] = 1.55; cijk[10][2] = 0; eijk[10][2] = 0; bijk[10][2] = 0; gijk[10][2] = 0; nijk[10][2] = -7.9846357136353; + dijk[10][3] = 1; tijk[10][3] = 1.7; cijk[10][3] = 0; eijk[10][3] = 0; bijk[10][3] = 0; gijk[10][3] = 0; nijk[10][3] = 4.7859131465806; + dijk[10][4] = 2; tijk[10][4] = 0.25; cijk[10][4] = 0; eijk[10][4] = 0; bijk[10][4] = 0; gijk[10][4] = 0; nijk[10][4] = -0.73265392369587; + dijk[10][5] = 2; tijk[10][5] = 1.35; cijk[10][5] = 0; eijk[10][5] = 0; bijk[10][5] = 0; gijk[10][5] = 0; nijk[10][5] = 1.3805471345312; + dijk[10][6] = 3; tijk[10][6] = 0; cijk[10][6] = 0; eijk[10][6] = 0; bijk[10][6] = 0; gijk[10][6] = 0; nijk[10][6] = 0.28349603476365; + dijk[10][7] = 3; tijk[10][7] = 1.25; cijk[10][7] = 0; eijk[10][7] = 0; bijk[10][7] = 0; gijk[10][7] = 0; nijk[10][7] = -0.49087385940425; + dijk[10][8] = 4; tijk[10][8] = 0; cijk[10][8] = 0; eijk[10][8] = 0; bijk[10][8] = 0; gijk[10][8] = 0; nijk[10][8] = -0.10291888921447; + dijk[10][9] = 4; tijk[10][9] = 0.7; cijk[10][9] = 0; eijk[10][9] = 0; bijk[10][9] = 0; gijk[10][9] = 0; nijk[10][9] = 0.11836314681968; + dijk[10][10] = 4; tijk[10][10] = 5.4; cijk[10][10] = 0; eijk[10][10] = 0; bijk[10][10] = 0; gijk[10][10] = 0; nijk[10][10] = 5.5527385721943E-05; + + // Generalized parameters + fij[1][2] = 1; // Methane-Nitrogen + fij[1][3] = 1; // Methane-CO2 + fij[1][4] = 1; // Methane-Ethane + fij[1][5] = 1; // Methane-Propane + fij[2][3] = 1; // Nitrogen-CO2 + fij[2][4] = 1; // Nitrogen-Ethane + fij[1][15] = 1; // Methane-Hydrogen + fij[1][6] = 0.771035405688; // Methane-Isobutane + fij[1][7] = 1; // Methane-n-Butane + fij[4][5] = 0.13042476515; // Ethane-Propane + fij[4][6] = 0.260632376098; // Ethane-Isobutane + fij[4][7] = 0.281570073085; // Ethane-n-Butane + fij[5][6] = -0.0551609771024; // Propane-Isobutane + fij[5][7] = 0.0312572600489; // Propane-n-Butane + fij[6][7] = -0.0551240293009; // Isobutane-n-Butane + + // Model numbers for binary mixtures with no excess functions (mn=-1) + for(int i = 1; i <= MaxFlds; ++i){ + mNumb[i][i] = -1; + for (int j = i + 1; j <= MaxFlds; ++j){ + fij[j][i] = fij[i][j]; + mNumb[i][j] = -1; + mNumb[j][i] = -1; + } + } + + // Model numbers for excess functions, 10 is for generalized equation + mNumb[1][2] = 3; + mNumb[1][3] = 4; + mNumb[1][4] = 1; + mNumb[1][5] = 2; + mNumb[1][6] = 10; + mNumb[1][7] = 10; + mNumb[1][15] = 7; + mNumb[2][3] = 5; + mNumb[2][4] = 6; + mNumb[4][5] = 10; + mNumb[4][6] = 10; + mNumb[4][7] = 10; + mNumb[5][6] = 10; + mNumb[5][7] = 10; + mNumb[6][7] = 10; + + // Ideal gas parameters + n0i[1][3] = 4.00088; n0i[1][4] = 0.76315; n0i[1][5] = 0.0046; n0i[1][6] = 8.74432; n0i[1][7] = -4.46921; n0i[1][1] = 29.83843397; n0i[1][2] = -15999.69151; + n0i[2][3] = 3.50031; n0i[2][4] = 0.13732; n0i[2][5] = -0.1466; n0i[2][6] = 0.90066; n0i[2][7] = 0; n0i[2][1] = 17.56770785; n0i[2][2] = -2801.729072; + n0i[3][3] = 3.50002; n0i[3][4] = 2.04452; n0i[3][5] = -1.06044; n0i[3][6] = 2.03366; n0i[3][7] = 0.01393; n0i[3][1] = 20.65844696; n0i[3][2] = -4902.171516; + n0i[4][3] = 4.00263; n0i[4][4] = 4.33939; n0i[4][5] = 1.23722; n0i[4][6] = 13.1974; n0i[4][7] = -6.01989; n0i[4][1] = 36.73005938; n0i[4][2] = -23639.65301; + n0i[5][3] = 4.02939; n0i[5][4] = 6.60569; n0i[5][5] = 3.197; n0i[5][6] = 19.1921; n0i[5][7] = -8.37267; n0i[5][1] = 44.70909619; n0i[5][2] = -31236.63551; + n0i[6][3] = 4.06714; n0i[6][4] = 8.97575; n0i[6][5] = 5.25156; n0i[6][6] = 25.1423; n0i[6][7] = 16.1388; n0i[6][1] = 34.30180349; n0i[6][2] = -38525.50276; + n0i[7][3] = 4.33944; n0i[7][4] = 9.44893; n0i[7][5] = 6.89406; n0i[7][6] = 24.4618; n0i[7][7] = 14.7824; n0i[7][1] = 36.53237783; n0i[7][2] = -38957.80933; + n0i[8][3] = 4; n0i[8][4] = 11.7618; n0i[8][5] = 20.1101; n0i[8][6] = 33.1688; n0i[8][7] = 0; n0i[8][1] = 43.17218626; n0i[8][2] = -51198.30946; + n0i[9][3] = 4; n0i[9][4] = 8.95043; n0i[9][5] = 21.836; n0i[9][6] = 33.4032; n0i[9][7] = 0; n0i[9][1] = 42.67837089; n0i[9][2] = -45215.83; + n0i[10][3] = 4; n0i[10][4] = 11.6977; n0i[10][5] = 26.8142; n0i[10][6] = 38.6164; n0i[10][7] = 0; n0i[10][1] = 46.99717188; n0i[10][2] = -52746.83318; + n0i[11][3] = 4; n0i[11][4] = 13.7266; n0i[11][5] = 30.4707; n0i[11][6] = 43.5561; n0i[11][7] = 0; n0i[11][1] = 52.07631631; n0i[11][2] = -57104.81056; + n0i[12][3] = 4; n0i[12][4] = 15.6865; n0i[12][5] = 33.8029; n0i[12][6] = 48.1731; n0i[12][7] = 0; n0i[12][1] = 57.25830934; n0i[12][2] = -60546.76385; + n0i[13][3] = 4; n0i[13][4] = 18.0241; n0i[13][5] = 38.1235; n0i[13][6] = 53.3415; n0i[13][7] = 0; n0i[13][1] = 62.09646901; n0i[13][2] = -66600.12837; + n0i[14][3] = 4; n0i[14][4] = 21.0069; n0i[14][5] = 43.4931; n0i[14][6] = 58.3657; n0i[14][7] = 0; n0i[14][1] = 65.93909154; n0i[14][2] = -74131.45483; + n0i[15][3] = 2.47906; n0i[15][4] = 0.95806; n0i[15][5] = 0.45444; n0i[15][6] = 1.56039; n0i[15][7] = -1.3756; n0i[15][1] = 13.07520288; n0i[15][2] = -5836.943696; + n0i[16][3] = 3.50146; n0i[16][4] = 1.07558; n0i[16][5] = 1.01334; n0i[16][6] = 0; n0i[16][7] = 0; n0i[16][1] = 16.8017173; n0i[16][2] = -2318.32269; + n0i[17][3] = 3.50055; n0i[17][4] = 1.02865; n0i[17][5] = 0.00493; n0i[17][6] = 0; n0i[17][7] = 0; n0i[17][1] = 17.45786899; n0i[17][2] = -2635.244116; + n0i[18][3] = 4.00392; n0i[18][4] = 0.01059; n0i[18][5] = 0.98763; n0i[18][6] = 3.06904; n0i[18][7] = 0; n0i[18][1] = 21.57882705; n0i[18][2] = -7766.733078; + n0i[19][3] = 4; n0i[19][4] = 3.11942; n0i[19][5] = 1.00243; n0i[19][6] = 0; n0i[19][7] = 0; n0i[19][1] = 21.5830944; n0i[19][2] = -6069.035869; + n0i[20][3] = 2.5; n0i[20][4] = 0; n0i[20][5] = 0; n0i[20][6] = 0; n0i[20][7] = 0; n0i[20][1] = 10.04639507; n0i[20][2] = -745.375; + n0i[21][3] = 2.5; n0i[21][4] = 0; n0i[21][5] = 0; n0i[21][6] = 0; n0i[21][7] = 0; n0i[21][1] = 10.04639507; n0i[21][2] = -745.375; + th0i[1][4] = 820.659; th0i[1][5] = 178.41; th0i[1][6] = 1062.82; th0i[1][7] = 1090.53; + th0i[2][4] = 662.738; th0i[2][5] = 680.562; th0i[2][6] = 1740.06; th0i[2][7] = 0; + th0i[3][4] = 919.306; th0i[3][5] = 865.07; th0i[3][6] = 483.553; th0i[3][7] = 341.109; + th0i[4][4] = 559.314; th0i[4][5] = 223.284; th0i[4][6] = 1031.38; th0i[4][7] = 1071.29; + th0i[5][4] = 479.856; th0i[5][5] = 200.893; th0i[5][6] = 955.312; th0i[5][7] = 1027.29; + th0i[6][4] = 438.27; th0i[6][5] = 198.018; th0i[6][6] = 1905.02; th0i[6][7] = 893.765; + th0i[7][4] = 468.27; th0i[7][5] = 183.636; th0i[7][6] = 1914.1; th0i[7][7] = 903.185; + th0i[8][4] = 292.503; th0i[8][5] = 910.237; th0i[8][6] = 1919.37; th0i[8][7] = 0; + th0i[9][4] = 178.67; th0i[9][5] = 840.538; th0i[9][6] = 1774.25; th0i[9][7] = 0; + th0i[10][4] = 182.326; th0i[10][5] = 859.207; th0i[10][6] = 1826.59; th0i[10][7] = 0; + th0i[11][4] = 169.789; th0i[11][5] = 836.195; th0i[11][6] = 1760.46; th0i[11][7] = 0; + th0i[12][4] = 158.922; th0i[12][5] = 815.064; th0i[12][6] = 1693.07; th0i[12][7] = 0; + th0i[13][4] = 156.854; th0i[13][5] = 814.882; th0i[13][6] = 1693.79; th0i[13][7] = 0; + th0i[14][4] = 164.947; th0i[14][5] = 836.264; th0i[14][6] = 1750.24; th0i[14][7] = 0; + th0i[15][4] = 228.734; th0i[15][5] = 326.843; th0i[15][6] = 1651.71; th0i[15][7] = 1671.69; + th0i[16][4] = 2235.71; th0i[16][5] = 1116.69; th0i[16][6] = 0; th0i[16][7] = 0; + th0i[17][4] = 1550.45; th0i[17][5] = 704.525; th0i[17][6] = 0; th0i[17][7] = 0; + th0i[18][4] = 268.795; th0i[18][5] = 1141.41; th0i[18][6] = 2507.37; th0i[18][7] = 0; + th0i[19][4] = 1833.63; th0i[19][5] = 847.181; th0i[19][6] = 0; th0i[19][7] = 0; + th0i[20][4] = 0; th0i[20][5] = 0; th0i[20][6] = 0; th0i[20][7] = 0; + th0i[21][4] = 0; th0i[21][5] = 0; th0i[21][6] = 0; th0i[21][7] = 0; + + // Mixture parameters for reducing variables + bvij[1][2] = 0.998721377; gvij[1][2] = 1.013950311; btij[1][2] = 0.99809883; gtij[1][2] = 0.979273013; // CH4-N2 + bvij[1][3] = 0.999518072; gvij[1][3] = 1.002806594; btij[1][3] = 1.02262449; gtij[1][3] = 0.975665369; // CH4-CO2 + bvij[1][4] = 0.997547866; gvij[1][4] = 1.006617867; btij[1][4] = 0.996336508; gtij[1][4] = 1.049707697; // CH4-C2H6 + bvij[1][5] = 1.00482707; gvij[1][5] = 1.038470657; btij[1][5] = 0.989680305; gtij[1][5] = 1.098655531; // CH4-C3H8 + bvij[1][6] = 1.011240388; gvij[1][6] = 1.054319053; btij[1][6] = 0.980315756; gtij[1][6] = 1.161117729; // CH4-i-C4H10 + bvij[1][7] = 0.979105972; gvij[1][7] = 1.045375122; btij[1][7] = 0.99417491; gtij[1][7] = 1.171607691; // CH4-C4H10 + bvij[1][8] = 1; gvij[1][8] = 1.343685343; btij[1][8] = 1; gtij[1][8] = 1.188899743; // CH4-i-C5H12 + bvij[1][9] = 0.94833012; gvij[1][9] = 1.124508039; btij[1][9] = 0.992127525; gtij[1][9] = 1.249173968; // CH4-C5H12 + bvij[1][10] = 0.958015294; gvij[1][10] = 1.052643846; btij[1][10] = 0.981844797; gtij[1][10] = 1.330570181; // CH4-C6H14 + bvij[1][11] = 0.962050831; gvij[1][11] = 1.156655935; btij[1][11] = 0.977431529; gtij[1][11] = 1.379850328; // CH4-C7H16 + bvij[1][12] = 0.994740603; gvij[1][12] = 1.116549372; btij[1][12] = 0.957473785; gtij[1][12] = 1.449245409; // CH4-C8H18 + bvij[1][13] = 1.002852287; gvij[1][13] = 1.141895355; btij[1][13] = 0.947716769; gtij[1][13] = 1.528532478; // CH4-C9H20 + bvij[1][14] = 1.033086292; gvij[1][14] = 1.146089637; btij[1][14] = 0.937777823; gtij[1][14] = 1.568231489; // CH4-C10H22 + bvij[1][15] = 1; gvij[1][15] = 1.018702573; btij[1][15] = 1; gtij[1][15] = 1.352643115; // CH4-H2 + bvij[1][16] = 1; gvij[1][16] = 1; btij[1][16] = 1; gtij[1][16] = 0.95; // CH4-O2 + bvij[1][17] = 0.997340772; gvij[1][17] = 1.006102927; btij[1][17] = 0.987411732; gtij[1][17] = 0.987473033; // CH4-CO + bvij[1][18] = 1.012783169; gvij[1][18] = 1.585018334; btij[1][18] = 1.063333913; gtij[1][18] = 0.775810513; // CH4-H2O + bvij[1][19] = 1.012599087; gvij[1][19] = 1.040161207; btij[1][19] = 1.011090031; gtij[1][19] = 0.961155729; // CH4-H2S + bvij[1][20] = 1; gvij[1][20] = 0.881405683; btij[1][20] = 1; gtij[1][20] = 3.159776855; // CH4-He + bvij[1][21] = 1.034630259; gvij[1][21] = 1.014678542; btij[1][21] = 0.990954281; gtij[1][21] = 0.989843388; // CH4-Ar + bvij[2][3] = 0.977794634; gvij[2][3] = 1.047578256; btij[2][3] = 1.005894529; gtij[2][3] = 1.107654104; // N2-CO2 + bvij[2][4] = 0.978880168; gvij[2][4] = 1.042352891; btij[2][4] = 1.007671428; gtij[2][4] = 1.098650964; // N2-C2H6 + bvij[2][5] = 0.974424681; gvij[2][5] = 1.081025408; btij[2][5] = 1.002677329; gtij[2][5] = 1.201264026; // N2-C3H8 + bvij[2][6] = 0.98641583; gvij[2][6] = 1.100576129; btij[2][6] = 0.99286813; gtij[2][6] = 1.284462634; // N2-i-C4H10 + bvij[2][7] = 0.99608261; gvij[2][7] = 1.146949309; btij[2][7] = 0.994515234; gtij[2][7] = 1.304886838; // N2-C4H10 + bvij[2][8] = 1; gvij[2][8] = 1.154135439; btij[2][8] = 1; gtij[2][8] = 1.38177077; // N2-i-C5H12 + bvij[2][9] = 1; gvij[2][9] = 1.078877166; btij[2][9] = 1; gtij[2][9] = 1.419029041; // N2-C5H12 + bvij[2][10] = 1; gvij[2][10] = 1.195952177; btij[2][10] = 1; gtij[2][10] = 1.472607971; // N2-C6H14 + bvij[2][11] = 1; gvij[2][11] = 1.40455409; btij[2][11] = 1; gtij[2][11] = 1.520975334; // N2-C7H16 + bvij[2][12] = 1; gvij[2][12] = 1.186067025; btij[2][12] = 1; gtij[2][12] = 1.733280051; // N2-C8H18 + bvij[2][13] = 1; gvij[2][13] = 1.100405929; btij[2][13] = 0.95637945; gtij[2][13] = 1.749119996; // N2-C9H20 + bvij[2][14] = 1; gvij[2][14] = 1; btij[2][14] = 0.957934447; gtij[2][14] = 1.822157123; // N2-C10H22 + bvij[2][15] = 0.972532065; gvij[2][15] = 0.970115357; btij[2][15] = 0.946134337; gtij[2][15] = 1.175696583; // N2-H2 + bvij[2][16] = 0.99952177; gvij[2][16] = 0.997082328; btij[2][16] = 0.997190589; gtij[2][16] = 0.995157044; // N2-O2 + bvij[2][17] = 1; gvij[2][17] = 1.008690943; btij[2][17] = 1; gtij[2][17] = 0.993425388; // N2-CO + bvij[2][18] = 1; gvij[2][18] = 1.094749685; btij[2][18] = 1; gtij[2][18] = 0.968808467; // N2-H2O + bvij[2][19] = 0.910394249; gvij[2][19] = 1.256844157; btij[2][19] = 1.004692366; gtij[2][19] = 0.9601742; // N2-H2S + bvij[2][20] = 0.969501055; gvij[2][20] = 0.932629867; btij[2][20] = 0.692868765; gtij[2][20] = 1.47183158; // N2-He + bvij[2][21] = 1.004166412; gvij[2][21] = 1.002212182; btij[2][21] = 0.999069843; gtij[2][21] = 0.990034831; // N2-Ar + bvij[3][4] = 1.002525718; gvij[3][4] = 1.032876701; btij[3][4] = 1.013871147; gtij[3][4] = 0.90094953; // CO2-C2H6 + bvij[3][5] = 0.996898004; gvij[3][5] = 1.047596298; btij[3][5] = 1.033620538; gtij[3][5] = 0.908772477; // CO2-C3H8 + bvij[3][6] = 1.076551882; gvij[3][6] = 1.081909003; btij[3][6] = 1.023339824; gtij[3][6] = 0.929982936; // CO2-i-C4H10 + bvij[3][7] = 1.174760923; gvij[3][7] = 1.222437324; btij[3][7] = 1.018171004; gtij[3][7] = 0.911498231; // CO2-C4H10 + bvij[3][8] = 1.060793104; gvij[3][8] = 1.116793198; btij[3][8] = 1.019180957; gtij[3][8] = 0.961218039; // CO2-i-C5H12 + bvij[3][9] = 1.024311498; gvij[3][9] = 1.068406078; btij[3][9] = 1.027000795; gtij[3][9] = 0.979217302; // CO2-C5H12 + bvij[3][10] = 1; gvij[3][10] = 0.851343711; btij[3][10] = 1; gtij[3][10] = 1.038675574; // CO2-C6H14 + bvij[3][11] = 1.205469976; gvij[3][11] = 1.164585914; btij[3][11] = 1.011806317; gtij[3][11] = 1.046169823; // CO2-C7H16 + bvij[3][12] = 1.026169373; gvij[3][12] = 1.104043935; btij[3][12] = 1.02969078; gtij[3][12] = 1.074455386; // CO2-C8H18 + bvij[3][13] = 1; gvij[3][13] = 0.973386152; btij[3][13] = 1.00768862; gtij[3][13] = 1.140671202; // CO2-C9H20 + bvij[3][14] = 1.000151132; gvij[3][14] = 1.183394668; btij[3][14] = 1.02002879; gtij[3][14] = 1.145512213; // CO2-C10H22 + bvij[3][15] = 0.904142159; gvij[3][15] = 1.15279255; btij[3][15] = 0.942320195; gtij[3][15] = 1.782924792; // CO2-H2 + bvij[3][16] = 1; gvij[3][16] = 1; btij[3][16] = 1; gtij[3][16] = 1; // CO2-O2 + bvij[3][17] = 1; gvij[3][17] = 1; btij[3][17] = 1; gtij[3][17] = 1; // CO2-CO + bvij[3][18] = 0.949055959; gvij[3][18] = 1.542328793; btij[3][18] = 0.997372205; gtij[3][18] = 0.775453996; // CO2-H2O + bvij[3][19] = 0.906630564; gvij[3][19] = 1.024085837; btij[3][19] = 1.016034583; gtij[3][19] = 0.92601888; // CO2-H2S + bvij[3][20] = 0.846647561; gvij[3][20] = 0.864141549; btij[3][20] = 0.76837763; gtij[3][20] = 3.207456948; // CO2-He + bvij[3][21] = 1.008392428; gvij[3][21] = 1.029205465; btij[3][21] = 0.996512863; gtij[3][21] = 1.050971635; // CO2-Ar + bvij[4][5] = 0.997607277; gvij[4][5] = 1.00303472; btij[4][5] = 0.996199694; gtij[4][5] = 1.01473019; // C2H6-C3H8 + bvij[4][6] = 1; gvij[4][6] = 1.006616886; btij[4][6] = 1; gtij[4][6] = 1.033283811; // C2H6-i-C4H10 + bvij[4][7] = 0.999157205; gvij[4][7] = 1.006179146; btij[4][7] = 0.999130554; gtij[4][7] = 1.034832749; // C2H6-C4H10 + bvij[4][8] = 1; gvij[4][8] = 1.045439935; btij[4][8] = 1; gtij[4][8] = 1.021150247; // C2H6-i-C5H12 + bvij[4][9] = 0.993851009; gvij[4][9] = 1.026085655; btij[4][9] = 0.998688946; gtij[4][9] = 1.066665676; // C2H6-C5H12 + bvij[4][10] = 1; gvij[4][10] = 1.169701102; btij[4][10] = 1; gtij[4][10] = 1.092177796; // C2H6-C6H14 + bvij[4][11] = 1; gvij[4][11] = 1.057666085; btij[4][11] = 1; gtij[4][11] = 1.134532014; // C2H6-C7H16 + bvij[4][12] = 1.007469726; gvij[4][12] = 1.071917985; btij[4][12] = 0.984068272; gtij[4][12] = 1.168636194; // C2H6-C8H18 + bvij[4][13] = 1; gvij[4][13] = 1.14353473; btij[4][13] = 1; gtij[4][13] = 1.05603303; // C2H6-C9H20 + bvij[4][14] = 0.995676258; gvij[4][14] = 1.098361281; btij[4][14] = 0.970918061; gtij[4][14] = 1.237191558; // C2H6-C10H22 + bvij[4][15] = 0.925367171; gvij[4][15] = 1.10607204; btij[4][15] = 0.932969831; gtij[4][15] = 1.902008495; // C2H6-H2 + bvij[4][16] = 1; gvij[4][16] = 1; btij[4][16] = 1; gtij[4][16] = 1; // C2H6-O2 + bvij[4][17] = 1; gvij[4][17] = 1.201417898; btij[4][17] = 1; gtij[4][17] = 1.069224728; // C2H6-CO + bvij[4][18] = 1; gvij[4][18] = 1; btij[4][18] = 1; gtij[4][18] = 1; // C2H6-H2O + bvij[4][19] = 1.010817909; gvij[4][19] = 1.030988277; btij[4][19] = 0.990197354; gtij[4][19] = 0.90273666; // C2H6-H2S + bvij[4][20] = 1; gvij[4][20] = 1; btij[4][20] = 1; gtij[4][20] = 1; // C2H6-He + bvij[4][21] = 1; gvij[4][21] = 1; btij[4][21] = 1; gtij[4][21] = 1; // C2H6-Ar + bvij[5][6] = 0.999243146; gvij[5][6] = 1.001156119; btij[5][6] = 0.998012298; gtij[5][6] = 1.005250774; // C3H8-i-C4H10 + bvij[5][7] = 0.999795868; gvij[5][7] = 1.003264179; btij[5][7] = 1.000310289; gtij[5][7] = 1.007392782; // C3H8-C4H10 + bvij[5][8] = 1.040459289; gvij[5][8] = 0.999432118; btij[5][8] = 0.994364425; gtij[5][8] = 1.0032695; // C3H8-i-C5H12 + bvij[5][9] = 1.044919431; gvij[5][9] = 1.019921513; btij[5][9] = 0.996484021; gtij[5][9] = 1.008344412; // C3H8-C5H12 + bvij[5][10] = 1; gvij[5][10] = 1.057872566; btij[5][10] = 1; gtij[5][10] = 1.025657518; // C3H8-C6H14 + bvij[5][11] = 1; gvij[5][11] = 1.079648053; btij[5][11] = 1; gtij[5][11] = 1.050044169; // C3H8-C7H16 + bvij[5][12] = 1; gvij[5][12] = 1.102764612; btij[5][12] = 1; gtij[5][12] = 1.063694129; // C3H8-C8H18 + bvij[5][13] = 1; gvij[5][13] = 1.199769134; btij[5][13] = 1; gtij[5][13] = 1.109973833; // C3H8-C9H20 + bvij[5][14] = 0.984104227; gvij[5][14] = 1.053040574; btij[5][14] = 0.985331233; gtij[5][14] = 1.140905252; // C3H8-C10H22 + bvij[5][15] = 1; gvij[5][15] = 1.07400611; btij[5][15] = 1; gtij[5][15] = 2.308215191; // C3H8-H2 + bvij[5][16] = 1; gvij[5][16] = 1; btij[5][16] = 1; gtij[5][16] = 1; // C3H8-O2 + bvij[5][17] = 1; gvij[5][17] = 1.108143673; btij[5][17] = 1; gtij[5][17] = 1.197564208; // C3H8-CO + bvij[5][18] = 1; gvij[5][18] = 1.011759763; btij[5][18] = 1; gtij[5][18] = 0.600340961; // C3H8-H2O + bvij[5][19] = 0.936811219; gvij[5][19] = 1.010593999; btij[5][19] = 0.992573556; gtij[5][19] = 0.905829247; // C3H8-H2S + bvij[5][20] = 1; gvij[5][20] = 1; btij[5][20] = 1; gtij[5][20] = 1; // C3H8-He + bvij[5][21] = 1; gvij[5][21] = 1; btij[5][21] = 1; gtij[5][21] = 1; // C3H8-Ar + + // The beta values for isobutane+butane are the reciprocal values of those in the GERG-2008 publication because the order was reversed in this work. + bvij[6][7] = 0.999120311; gvij[6][7] = 1.00041444; btij[6][7] = 0.999922459; gtij[6][7] = 1.001432824; // C4H10-i-C4H10 + + bvij[6][8] = 1; gvij[6][8] = 1.002284353; btij[6][8] = 1; gtij[6][8] = 1.001835788; // i-C4H10-i-C5H1 + bvij[6][9] = 1; gvij[6][9] = 1.002779804; btij[6][9] = 1; gtij[6][9] = 1.002495889; // i-C4H10-C5H12 + bvij[6][10] = 1; gvij[6][10] = 1.010493989; btij[6][10] = 1; gtij[6][10] = 1.006018054; // i-C4H10-C6H14 + bvij[6][11] = 1; gvij[6][11] = 1.021668316; btij[6][11] = 1; gtij[6][11] = 1.00988576; // i-C4H10-C7H16 + bvij[6][12] = 1; gvij[6][12] = 1.032807063; btij[6][12] = 1; gtij[6][12] = 1.013945424; // i-C4H10-C8H18 + bvij[6][13] = 1; gvij[6][13] = 1.047298475; btij[6][13] = 1; gtij[6][13] = 1.017817492; // i-C4H10-C9H20 + bvij[6][14] = 1; gvij[6][14] = 1.060243344; btij[6][14] = 1; gtij[6][14] = 1.021624748; // i-C4H10-C10H22 + bvij[6][15] = 1; gvij[6][15] = 1.147595688; btij[6][15] = 1; gtij[6][15] = 1.895305393; // i-C4H10-H2 + bvij[6][16] = 1; gvij[6][16] = 1; btij[6][16] = 1; gtij[6][16] = 1; // i-C4H10-O2 + bvij[6][17] = 1; gvij[6][17] = 1.087272232; btij[6][17] = 1; gtij[6][17] = 1.161390082; // i-C4H10-CO + bvij[6][18] = 1; gvij[6][18] = 1; btij[6][18] = 1; gtij[6][18] = 1; // i-C4H10-H2O + bvij[6][19] = 1.012994431; gvij[6][19] = 0.988591117; btij[6][19] = 0.974550548; gtij[6][19] = 0.937130844; // i-C4H10-H2S + bvij[6][20] = 1; gvij[6][20] = 1; btij[6][20] = 1; gtij[6][20] = 1; // i-C4H10-He + bvij[6][21] = 1; gvij[6][21] = 1; btij[6][21] = 1; gtij[6][21] = 1; // i-C4H10-Ar + bvij[7][8] = 1; gvij[7][8] = 1.002728434; btij[7][8] = 1; gtij[7][8] = 1.000792201; // C4H10-i-C5H12 + bvij[7][9] = 1; gvij[7][9] = 1.01815965; btij[7][9] = 1; gtij[7][9] = 1.00214364; // C4H10-C5H12 + bvij[7][10] = 1; gvij[7][10] = 1.034995284; btij[7][10] = 1; gtij[7][10] = 1.00915706; // C4H10-C6H14 + bvij[7][11] = 1; gvij[7][11] = 1.019174227; btij[7][11] = 1; gtij[7][11] = 1.021283378; // C4H10-C7H16 + bvij[7][12] = 1; gvij[7][12] = 1.046905515; btij[7][12] = 1; gtij[7][12] = 1.033180106; // C4H10-C8H18 + bvij[7][13] = 1; gvij[7][13] = 1.049219137; btij[7][13] = 1; gtij[7][13] = 1.014096448; // C4H10-C9H20 + bvij[7][14] = 0.976951968; gvij[7][14] = 1.027845529; btij[7][14] = 0.993688386; gtij[7][14] = 1.076466918; // C4H10-C10H22 + bvij[7][15] = 1; gvij[7][15] = 1.232939523; btij[7][15] = 1; gtij[7][15] = 2.509259945; // C4H10-H2 + bvij[7][16] = 1; gvij[7][16] = 1; btij[7][16] = 1; gtij[7][16] = 1; // C4H10-O2 + bvij[7][17] = 1; gvij[7][17] = 1.084740904; btij[7][17] = 1; gtij[7][17] = 1.173916162; // C4H10-CO + bvij[7][18] = 1; gvij[7][18] = 1.223638763; btij[7][18] = 1; gtij[7][18] = 0.615512682; // C4H10-H2O + bvij[7][19] = 0.908113163; gvij[7][19] = 1.033366041; btij[7][19] = 0.985962886; gtij[7][19] = 0.926156602; // C4H10-H2S + bvij[7][20] = 1; gvij[7][20] = 1; btij[7][20] = 1; gtij[7][20] = 1; // C4H10-He + bvij[7][21] = 1; gvij[7][21] = 1.214638734; btij[7][21] = 1; gtij[7][21] = 1.245039498; // C4H10-Ar + bvij[8][9] = 1; gvij[8][9] = 1.000024335; btij[8][9] = 1; gtij[8][9] = 1.000050537; // C5H12-i-C5H12 + bvij[8][10] = 1; gvij[8][10] = 1.002995876; btij[8][10] = 1; gtij[8][10] = 1.001204174; // i-C5H12-C6H14 + bvij[8][11] = 1; gvij[8][11] = 1.009928206; btij[8][11] = 1; gtij[8][11] = 1.003194615; // i-C5H12-C7H16 + bvij[8][12] = 1; gvij[8][12] = 1.017880545; btij[8][12] = 1; gtij[8][12] = 1.00564748; // i-C5H12-C8H18 + bvij[8][13] = 1; gvij[8][13] = 1.028994325; btij[8][13] = 1; gtij[8][13] = 1.008191499; // i-C5H12-C9H20 + bvij[8][14] = 1; gvij[8][14] = 1.039372957; btij[8][14] = 1; gtij[8][14] = 1.010825138; // i-C5H12-C10H22 + bvij[8][15] = 1; gvij[8][15] = 1.184340443; btij[8][15] = 1; gtij[8][15] = 1.996386669; // i-C5H12-H2 + bvij[8][16] = 1; gvij[8][16] = 1; btij[8][16] = 1; gtij[8][16] = 1; // i-C5H12-O2 + bvij[8][17] = 1; gvij[8][17] = 1.116694577; btij[8][17] = 1; gtij[8][17] = 1.199326059; // i-C5H12-CO + bvij[8][18] = 1; gvij[8][18] = 1; btij[8][18] = 1; gtij[8][18] = 1; // i-C5H12-H2O + bvij[8][19] = 1; gvij[8][19] = 0.835763343; btij[8][19] = 1; gtij[8][19] = 0.982651529; // i-C5H12-H2S + bvij[8][20] = 1; gvij[8][20] = 1; btij[8][20] = 1; gtij[8][20] = 1; // i-C5H12-He + bvij[8][21] = 1; gvij[8][21] = 1; btij[8][21] = 1; gtij[8][21] = 1; // i-C5H12-Ar + bvij[9][10] = 1; gvij[9][10] = 1.002480637; btij[9][10] = 1; gtij[9][10] = 1.000761237; // C5H12-C6H14 + bvij[9][11] = 1; gvij[9][11] = 1.008972412; btij[9][11] = 1; gtij[9][11] = 1.002441051; // C5H12-C7H16 + bvij[9][12] = 1; gvij[9][12] = 1.069223964; btij[9][12] = 1; gtij[9][12] = 1.016422347; // C5H12-C8H18 + bvij[9][13] = 1; gvij[9][13] = 1.034910633; btij[9][13] = 1; gtij[9][13] = 1.103421755; // C5H12-C9H20 + bvij[9][14] = 1; gvij[9][14] = 1.016370338; btij[9][14] = 1; gtij[9][14] = 1.049035838; // C5H12-C10H22 + bvij[9][15] = 1; gvij[9][15] = 1.188334783; btij[9][15] = 1; gtij[9][15] = 2.013859174; // C5H12-H2 + bvij[9][16] = 1; gvij[9][16] = 1; btij[9][16] = 1; gtij[9][16] = 1; // C5H12-O2 + bvij[9][17] = 1; gvij[9][17] = 1.119954454; btij[9][17] = 1; gtij[9][17] = 1.206043295; // C5H12-CO + bvij[9][18] = 1; gvij[9][18] = 0.95667731; btij[9][18] = 1; gtij[9][18] = 0.447666011; // C5H12-H2O + bvij[9][19] = 0.984613203; gvij[9][19] = 1.076539234; btij[9][19] = 0.962006651; gtij[9][19] = 0.959065662; // C5H12-H2S + bvij[9][20] = 1; gvij[9][20] = 1; btij[9][20] = 1; gtij[9][20] = 1; // C5H12-He + bvij[9][21] = 1; gvij[9][21] = 1; btij[9][21] = 1; gtij[9][21] = 1; // C5H12-Ar + bvij[10][11] = 1; gvij[10][11] = 1.001508227; btij[10][11] = 1; gtij[10][11] = 0.999762786; // C6H14-C7H16 + bvij[10][12] = 1; gvij[10][12] = 1.006268954; btij[10][12] = 1; gtij[10][12] = 1.001633952; // C6H14-C8H18 + bvij[10][13] = 1; gvij[10][13] = 1.02076168; btij[10][13] = 1; gtij[10][13] = 1.055369591; // C6H14-C9H20 + bvij[10][14] = 1.001516371; gvij[10][14] = 1.013511439; btij[10][14] = 0.99764101; gtij[10][14] = 1.028939539; // C6H14-C10H22 + bvij[10][15] = 1; gvij[10][15] = 1.243461678; btij[10][15] = 1; gtij[10][15] = 3.021197546; // C6H14-H2 + bvij[10][16] = 1; gvij[10][16] = 1; btij[10][16] = 1; gtij[10][16] = 1; // C6H14-O2 + bvij[10][17] = 1; gvij[10][17] = 1.155145836; btij[10][17] = 1; gtij[10][17] = 1.233272781; // C6H14-CO + bvij[10][18] = 1; gvij[10][18] = 1.170217596; btij[10][18] = 1; gtij[10][18] = 0.569681333; // C6H14-H2O + bvij[10][19] = 0.754473958; gvij[10][19] = 1.339283552; btij[10][19] = 0.985891113; gtij[10][19] = 0.956075596; // C6H14-H2S + bvij[10][20] = 1; gvij[10][20] = 1; btij[10][20] = 1; gtij[10][20] = 1; // C6H14-He + bvij[10][21] = 1; gvij[10][21] = 1; btij[10][21] = 1; gtij[10][21] = 1; // C6H14-Ar + bvij[11][12] = 1; gvij[11][12] = 1.006767176; btij[11][12] = 1; gtij[11][12] = 0.998793111; // C7H16-C8H18 + bvij[11][13] = 1; gvij[11][13] = 1.001370076; btij[11][13] = 1; gtij[11][13] = 1.001150096; // C7H16-C9H20 + bvij[11][14] = 1; gvij[11][14] = 1.002972346; btij[11][14] = 1; gtij[11][14] = 1.002229938; // C7H16-C10H22 + bvij[11][15] = 1; gvij[11][15] = 1.159131722; btij[11][15] = 1; gtij[11][15] = 3.169143057; // C7H16-H2 + bvij[11][16] = 1; gvij[11][16] = 1; btij[11][16] = 1; gtij[11][16] = 1; // C7H16-O2 + bvij[11][17] = 1; gvij[11][17] = 1.190354273; btij[11][17] = 1; gtij[11][17] = 1.256123503; // C7H16-CO + bvij[11][18] = 1; gvij[11][18] = 1; btij[11][18] = 1; gtij[11][18] = 1; // C7H16-H2O + bvij[11][19] = 0.828967164; gvij[11][19] = 1.087956749; btij[11][19] = 0.988937417; gtij[11][19] = 1.013453092; // C7H16-H2S + bvij[11][20] = 1; gvij[11][20] = 1; btij[11][20] = 1; gtij[11][20] = 1; // C7H16-He + bvij[11][21] = 1; gvij[11][21] = 1; btij[11][21] = 1; gtij[11][21] = 1; // C7H16-Ar + bvij[12][13] = 1; gvij[12][13] = 1.001357085; btij[12][13] = 1; gtij[12][13] = 1.000235044; // C8H18-C9H20 + bvij[12][14] = 1; gvij[12][14] = 1.002553544; btij[12][14] = 1; gtij[12][14] = 1.007186267; // C8H18-C10H22 + bvij[12][15] = 1; gvij[12][15] = 1.305249405; btij[12][15] = 1; gtij[12][15] = 2.191555216; // C8H18-H2 + bvij[12][16] = 1; gvij[12][16] = 1; btij[12][16] = 1; gtij[12][16] = 1; // C8H18-O2 + bvij[12][17] = 1; gvij[12][17] = 1.219206702; btij[12][17] = 1; gtij[12][17] = 1.276565536; // C8H18-CO + bvij[12][18] = 1; gvij[12][18] = 0.599484191; btij[12][18] = 1; gtij[12][18] = 0.662072469; // C8H18-H2O + bvij[12][19] = 1; gvij[12][19] = 1; btij[12][19] = 1; gtij[12][19] = 1; // C8H18-H2S + bvij[12][20] = 1; gvij[12][20] = 1; btij[12][20] = 1; gtij[12][20] = 1; // C8H18-He + bvij[12][21] = 1; gvij[12][21] = 1; btij[12][21] = 1; gtij[12][21] = 1; // C8H18-Ar + bvij[13][14] = 1; gvij[13][14] = 1.00081052; btij[13][14] = 1; gtij[13][14] = 1.000182392; // C9H20-C10H22 + bvij[13][15] = 1; gvij[13][15] = 1.342647661; btij[13][15] = 1; gtij[13][15] = 2.23435404; // C9H20-H2 + bvij[13][16] = 1; gvij[13][16] = 1; btij[13][16] = 1; gtij[13][16] = 1; // C9H20-O2 + bvij[13][17] = 1; gvij[13][17] = 1.252151449; btij[13][17] = 1; gtij[13][17] = 1.294070556; // C9H20-CO + bvij[13][18] = 1; gvij[13][18] = 1; btij[13][18] = 1; gtij[13][18] = 1; // C9H20-H2O + bvij[13][19] = 1; gvij[13][19] = 1.082905109; btij[13][19] = 1; gtij[13][19] = 1.086557826; // C9H20-H2S + bvij[13][20] = 1; gvij[13][20] = 1; btij[13][20] = 1; gtij[13][20] = 1; // C9H20-He + bvij[13][21] = 1; gvij[13][21] = 1; btij[13][21] = 1; gtij[13][21] = 1; // C9H20-Ar + bvij[14][15] = 1.695358382; gvij[14][15] = 1.120233729; btij[14][15] = 1.064818089; gtij[14][15] = 3.786003724; // C10H22-H2 + bvij[14][16] = 1; gvij[14][16] = 1; btij[14][16] = 1; gtij[14][16] = 1; // C10H22-O2 + bvij[14][17] = 1; gvij[14][17] = 0.87018496; btij[14][17] = 1.049594632; gtij[14][17] = 1.803567587; // C10H22-CO + bvij[14][18] = 1; gvij[14][18] = 0.551405318; btij[14][18] = 0.897162268; gtij[14][18] = 0.740416402; // C10H22-H2O + bvij[14][19] = 0.975187766; gvij[14][19] = 1.171714677; btij[14][19] = 0.973091413; gtij[14][19] = 1.103693489; // C10H22-H2S + bvij[14][20] = 1; gvij[14][20] = 1; btij[14][20] = 1; gtij[14][20] = 1; // C10H22-He + bvij[14][21] = 1; gvij[14][21] = 1; btij[14][21] = 1; gtij[14][21] = 1; // C10H22-Ar + bvij[15][16] = 1; gvij[15][16] = 1; btij[15][16] = 1; gtij[15][16] = 1; // H2-O2 + bvij[15][17] = 1; gvij[15][17] = 1.121416201; btij[15][17] = 1; gtij[15][17] = 1.377504607; // H2-CO + bvij[15][18] = 1; gvij[15][18] = 1; btij[15][18] = 1; gtij[15][18] = 1; // H2-H2O + bvij[15][19] = 1; gvij[15][19] = 1; btij[15][19] = 1; gtij[15][19] = 1; // H2-H2S + bvij[15][20] = 1; gvij[15][20] = 1; btij[15][20] = 1; gtij[15][20] = 1; // H2-He + bvij[15][21] = 1; gvij[15][21] = 1; btij[15][21] = 1; gtij[15][21] = 1; // H2-Ar + bvij[16][17] = 1; gvij[16][17] = 1; btij[16][17] = 1; gtij[16][17] = 1; // O2-CO + bvij[16][18] = 1; gvij[16][18] = 1.143174289; btij[16][18] = 1; gtij[16][18] = 0.964767932; // O2-H2O + bvij[16][19] = 1; gvij[16][19] = 1; btij[16][19] = 1; gtij[16][19] = 1; // O2-H2S + bvij[16][20] = 1; gvij[16][20] = 1; btij[16][20] = 1; gtij[16][20] = 1; // O2-He + bvij[16][21] = 0.999746847; gvij[16][21] = 0.993907223; btij[16][21] = 1.000023103; gtij[16][21] = 0.990430423; // O2-Ar + bvij[17][18] = 1; gvij[17][18] = 1; btij[17][18] = 1; gtij[17][18] = 1; // CO-H2O + bvij[17][19] = 0.795660392; gvij[17][19] = 1.101731308; btij[17][19] = 1.025536736; gtij[17][19] = 1.022749748; // CO-H2S + bvij[17][20] = 1; gvij[17][20] = 1; btij[17][20] = 1; gtij[17][20] = 1; // CO-He + bvij[17][21] = 1; gvij[17][21] = 1.159720623; btij[17][21] = 1; gtij[17][21] = 0.954215746; // CO-Ar + bvij[18][19] = 1; gvij[18][19] = 1.014832832; btij[18][19] = 1; gtij[18][19] = 0.940587083; // H2O-H2S + bvij[18][20] = 1; gvij[18][20] = 1; btij[18][20] = 1; gtij[18][20] = 1; // H2O-He + bvij[18][21] = 1; gvij[18][21] = 1.038993495; btij[18][21] = 1; gtij[18][21] = 1.070941866; // H2O-Ar + bvij[19][20] = 1; gvij[19][20] = 1; btij[19][20] = 1; gtij[19][20] = 1; // H2S-He + bvij[19][21] = 1; gvij[19][21] = 1; btij[19][21] = 1; gtij[19][21] = 1; // H2S-Ar + bvij[20][21] = 1; gvij[20][21] = 1; btij[20][21] = 1; gtij[20][21] = 1; // He-Ar + + for(int i = 1; i <= MaxFlds; ++i){ + bvij[i][i] = 1; + btij[i][i] = 1; + gvij[i][i] = 1 / Dc[i]; + gtij[i][i] = 1 * Tc[i]; + for (int j = i + 1; j <= MaxFlds; ++j){ + gvij[i][j] = gvij[i][j] * bvij[i][j] * pow(Vc3[i] + Vc3[j], 3); + gtij[i][j] = gtij[i][j] * btij[i][j] * Tc2[i] * Tc2[j]; + bvij[i][j] = pow(bvij[i][j], 2); + btij[i][j] = pow(btij[i][j], 2); + } + } + + for (int i = 1; i <= MaxMdl; ++i){ + for (int j = 1; j <= MaxTrmM; ++j){ + gijk[i][j] = -cijk[i][j] * pow(eijk[i][j], 2) + bijk[i][j] * gijk[i][j]; + eijk[i][j] = 2 * cijk[i][j] * eijk[i][j] - bijk[i][j]; + cijk[i][j] = -cijk[i][j]; + } + } + + // Ideal gas terms + T0 = 298.15; + d0 = 101.325 / RGERG / T0; + for (int i = 1; i <= MaxFlds; ++i){ + n0i[i][3] = n0i[i][3] - 1; + n0i[i][2] = n0i[i][2] + T0; + for (int j = 1; j <= 7; ++j){ + n0i[i][j] = Rsr * n0i[i][j]; + } + n0i[i][2] = n0i[i][2] - T0; + n0i[i][1] = n0i[i][1] - log(d0); + } + return; + + // Code to produce nearly exact values for n0(1) and n0(2) + // This is not called in the current code, but included below to show how the values were calculated. The return above can be removed to call this code. + T0 = 298.15; + d0 = 101.325 / RGERG / T0; + for (int i = 1; i <= MaxFlds; ++i){ + n1 = 0; n2 = 0; + if (th0i[i][4] > 0) { n2 += - n0i[i][4] * th0i[i][4] / Tanh(th0i[i][4] / T0); n1 += - n0i[i][4] * log(Sinh(th0i[i][4] / T0)); } + if (th0i[i][5] > 0) { n2 += + n0i[i][5] * th0i[i][5] * Tanh(th0i[i][5] / T0); n1 += + n0i[i][5] * log(Cosh(th0i[i][5] / T0)); } + if (th0i[i][6] > 0) { n2 += - n0i[i][6] * th0i[i][6] / Tanh(th0i[i][6] / T0); n1 += - n0i[i][6] * log(Sinh(th0i[i][6] / T0)); } + if (th0i[i][7] > 0) { n2 += + n0i[i][7] * th0i[i][7] * Tanh(th0i[i][7] / T0); n1 += + n0i[i][7] * log(Cosh(th0i[i][7] / T0)); } + n0i[i][3] = n0i[i][3] - 1; + n0i[i][1] = n1 - n2 / T0 + n0i[i][3] * (1 + log(T0)); + n0i[i][2] = n2 - n0i[i][3] * T0; + for (int j = 1; j <= 7; ++j){ + n0i[i][j] = Rsr * n0i[i][j]; + } + n0i[i][2] = n0i[i][2] - T0; + n0i[i][1] = n0i[i][1] - log(d0); + } +} + +#ifdef TEST_GERG +int main() +{ + SetupGERG(); + double _x[] = {0.77824, 0.02, 0.06, 0.08, 0.03, 0.0015, 0.003, 0.0005, 0.00165, 0.00215, 0.00088, 0.00024, 0.00015, 0.00009, 0.004, 0.005, 0.002, 0.0001, 0.0025, 0.007, 0.001}; + std::vector x(_x, _x+NcGERG), xGrs(4,0); + x.insert(x.begin(), 0.0); + + double mm = 0; + MolarMassGERG(x, mm); + + int ierr = 0; + std::string herr; + + double T = 400, P = 50000, D = 6.36570, Z = 0; + + printf("Inputs-----\n"); + printf("Temperature [K]: 400.0000000000000 != %0.16g\n", T); + printf("Pressure [kPa]: 50000.00000000000 != %0.16g\n", P); + + double dPdD, dPdD2, d2PdTD, dPdT, U, H, S, Cv, Cp, W, G, JT, Kappa, A; + + // void DensityGERG(const int iFlag, const double T, const double P, const std::vector &x, double &D, int &ierr, std::string &herr) + DensityGERG(0, T, P, x, D, ierr, herr); + + // Sub PropertiesGERG(T, D, x, P, Z, dPdD, dPdD2, d2PdTD, dPdT, U, H, S, Cv, Cp, W, G, JT, Kappa) + PropertiesGERG(T, D, x, P, Z, dPdD, dPdD2, d2PdTD, dPdT, U, H, S, Cv, Cp, W, G, JT, Kappa, A); + + printf("Outputs-----\n"); + printf("Molar mass [g/mol]: 20.54274450160000 != %0.16g\n",mm); + printf("Molar density [mol/l]: 12.79828626082062 != %0.16g\n",D); + printf("Pressure [kPa]: 50000.00000000001 != %0.16g\n",P); + printf("Compressibility factor: 1.174690666383717 != %0.16g\n",Z); + printf("d(P)/d(rho) [kPa/(mol/l)]: 7000.694030193327 != %0.16g\n",dPdD); + printf("d^2(P)/d(rho)^2 [kPa/(mol/l)^2]: 1130.481239114938 != %0.16g\n",dPdD2); + printf("d(P)/d(T) [kPa/K]: 235.9832292593096 != %0.16g\n",dPdT); + printf("Energy [J/mol]: -2746.492901212530 != %0.16g\n",U); + printf("Enthalpy [J/mol]: 1160.280160510973 != %0.16g\n",H); + printf("Entropy [J/mol-K]: -38.57590392409089 != %0.16g\n",S); + printf("Isochoric heat capacity [J/mol-K]: 39.02948218156372 != %0.16g\n",Cv); + printf("Isobaric heat capacity [J/mol-K]: 58.45522051000366 != %0.16g\n",Cp); + printf("Speed of sound [m/s]: 714.4248840596024 != %0.16g\n",W); + printf("Gibbs energy [J/mol]: 16590.64173014733 != %0.16g\n",G); + printf("Joule-Thomson coefficient [K/kPa]: 7.155629581480913E-05 != %0.16g\n",JT); + printf("Isentropic exponent: 2.683820255058032 != %0.16g\n",Kappa); + +} +#endif diff --git a/src/tests/catch_test_GERG.cxx b/src/tests/catch_test_GERG.cxx index 4993d25f..eca5f984 100644 --- a/src/tests/catch_test_GERG.cxx +++ b/src/tests/catch_test_GERG.cxx @@ -5,6 +5,8 @@ using Catch::Approx; #include "teqp/models/GERG/GERG.hpp" +#include "GERG2008.cpp" + using namespace teqp; TEST_CASE("Load all GERG2004 models", "[GERG2004]"){ @@ -81,3 +83,507 @@ TEST_CASE("Load all GERG2008 models", "[GERG2008]"){ CHECK_NOTHROW(GERG2008::GERG200XCorrespondingStatesTerm(names, GERG2008::get_pure_coeffs)); CHECK_NOTHROW(GERG2008::GERG2008ResidualModel(names)); } + + +// A structure to hold the values for one validation call +struct G08El +{ + int GasNo; + double T_K, D_molL, P_MPa, cv_JmolK, cp_JmolK, w_ms; +}; + +// Mole percentages! +std::vector > mixture_comps = { + {99.69531,0.2016,0.00937,0.07671,0.00679,0.00197,0.00068,0.00156,0,0,0,0,0,0,0,0,0,0,0,0.00601,0}, + {99.5494,0.3672,0.047,0.0344,0,0,0,0,0,0.001,0.001,0,0,0,0,0,0,0,0,0,0}, + {99.28959,0.3683,0.21808,0.09224,0.0095,0.00174,0.00118,0.00048,0,0,0,0,0,0,0,0,0,0,0,0.01889,0}, + {99.2875,0.5122,0.04833,0.12665,0.00983,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.01549,0}, + {99.15997,0.56734,0.11887,0.13489,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.01893,0}, + {99.06261,0.86044,0.05602,0.01077,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.01016,0}, + {98.69541,0.9137,0.37495,0.00651,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.00943,0}, + {98.306,0,1.694,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {98.36206,1.29427,0.26024,0.05756,0,0.00584,0,0.00118,0,0,0,0,0,0,0,0,0,0,0,0.01885,0}, + {98.34086,0.86109,0.76775,0.00879,0.00384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.01767,0}, + {98.110602,0.813399,0.1209,0.611199,0.2153,0.0339,0.0453,0.0115,0.00925,0.006,0.0061,0.0028,0.0003,0.00005,0,0,0,0,0,0.0134,0}, + {97.474689,0.382492,1.125685,0.947428,0.068591,0,0,0,0,0,0,0,0,0,0,0.001115,0,0,0,0,0}, + {97.18,0.629,1.711,0.454,0.022,0.002,0.002,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {96.675,1.931,0,1.345,0.046,0.001,0.002,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {96.6039,3.0703,0.3109,0.0149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {96.531,0.894,0.663,1.709,0.149,0.016,0.025,0.006,0.004,0.002,0.001,0,0,0,0,0,0,0,0,0,0}, + {96.370276,0.291926,0.298014,1.400282,0.780001,0.14425,0.460146,0.0759,0.0549,0.124306,0,0,0,0,0,0,0,0,0,0,0}, + {96.218,0.346,0.815,1.4,0.496,0.196,0.145,0.089,0.053,0.242,0,0,0,0,0,0,0,0,0,0,0}, + {96.167,0.66,0.16,2.066,0.626,0.086,0.125,0.035,0.031,0.027,0.013,0.004,0,0,0,0,0,0,0,0,0}, + {96.0217,0.0914,1.82778,1.58387,0.28571,0.05895,0.04797,0.02461,0.01342,0.03928,0,0,0,0,0,0,0,0,0,0.00531,0}, + {95.924,0.089,2.429,1.282,0.198,0.022,0.015,0.01,0.001,0.03,0,0,0,0,0,0,0,0,0,0,0}, + {95.485503,0.25073,0.814426,3.120734,0.305107,0,0,0,0,0.0235,0,0,0,0,0,0,0,0,0,0,0}, + {95.485,1.5987,0.5995,1.8984,0.177,0.0154,0.02013,0.005,0.003,0.003,0,0,0,0,0.1599,0,0,0,0,0.03497,0}, + {95.468539,0.246562,0.976951,1.965924,0.687402,0.167186,0.204834,0.0852,0.0655,0.131902,0,0,0,0,0,0,0,0,0,0,0}, + {95.29257,1.4941,0.6137,2.1226,0.207,0.0094,0.013,0.00177,0.0013,0.00196,0,0,0,0,0.2105,0,0,0,0,0.0321,0}, + {95.19,1.3,0.7,2.5,0.2,0.03,0.03,0.01,0.01,0.004,0.002,0.002,0,0,0,0.02,0,0.002,0,0,0}, + {95.12963,0.14167,4.51793,0.10715,0.07112,0.0216,0.00516,0.00144,0,0,0,0,0,0,0,0,0,0,0,0.0043,0}, + {95.1278,0.4483,1.5803,2.1265,0.388,0.0852,0.0964,0.0438,0.0288,0.03745,0.03745,0,0,0,0,0,0,0,0,0,0}, + {95.123,0.089,2.555,1.835,0.238,0.04,0.016,0.014,0.011,0.079,0,0,0,0,0,0,0,0,0,0,0}, + {95.065106,0.21485,1.25606,2.427795,0.49213,0.108789,0.106762,0.073877,0.068847,0.089252,0.072182,0.017708,0.005126,0.000552,0,0.000963,0,0,0,0,0}, + {94.8987,0.0075,0,3.7404,0.931,0.231,0.1836,0.0074,0.0004,0,0,0,0,0,0,0,0,0,0,0,0}, + {94.806,0.084,3.166,1.547,0.231,0.024,0.019,0.014,0.028,0.081,0,0,0,0,0,0,0,0,0,0,0}, + {94.725,1.7425,0.7459,2.2003,0.333,0.0545,0.0737,0.0279,0.0205,0.0194,0.0088,0.0038,0.001,0,0.0129,0.0288,0,0.002,0,0,0}, + {94.609,0.924,3.331,1.095,0.041,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {94.606705,0.178168,1.188857,2.479371,0.459308,0.094474,0.105551,0.087094,0.061014,0.191996,0.246145,0.237172,0.060691,0.002781,0,0.000672,0,0,0,0,0}, + {94.5487,2.349,0.561,2.0869,0.288,0.0299,0.0693,0.0211,0.0182,0.0116,0.0105,0.0049,0.0005,0.0004,0,0,0,0,0,0,0}, + {94.50248,0.3018,0.6028,2.7308,0.9948,0.2498,0.2735,0.12,0.0763,0.0833,0.0452,0.0153,0.00392,0,0,0,0,0,0,0,0}, + {94.46603,0.494,0.84028,1.81705,1.14551,0.30879,0.47012,0.1627,0.10109,0.17922,0,0,0,0,0,0,0,0,0,0.01521,0}, + {94.3627,0.2463,0.9726,2.6069,0.9541,0.2723,0.2345,0.1071,0.0712,0.1723,0,0,0,0,0,0,0,0,0,0,0}, + {94.329,0.062,2.103,2.31,0.671,0.103,0.115,0.048,0.037,0.222,0,0,0,0,0,0,0,0,0,0,0}, + {94.3127,1.3696,0.7678,3.1501,0.3198,0.0243,0.0332,0.0065,0.0052,0.007236,0.003132,0.000432,0,0,0,0,0,0,0,0,0}, + {94.27798,0.11705,1.55146,2.86558,0.71038,0.13411,0.13665,0.06285,0.03614,0.10138,0,0,0,0,0,0,0,0,0,0.00642,0}, + {94.2344,0.646,1.611,2.694,0.452,0.089,0.101,0.042,0.027,0.031,0.022,0.009,0.002,0.0006,0.004,0,0,0,0,0.035,0}, + {94.056896,0.26329,0.399681,3.089199,1.372261,0.186449,0.342525,0.0913,0.0874,0.0555,0.0555,0,0,0,0,0,0,0,0,0,0}, + {94.01163,2.18087,0.08967,2.05712,0.89961,0.14084,0.20385,0.16781,0.18605,0.02375,0,0,0,0,0,0,0,0,0,0.0388,0}, + {93.998912,0.316537,1.284648,2.650034,0.982546,0.24702,0.256324,0.102139,0.076741,0.0851,0,0,0,0,0,0,0,0,0,0,0}, + {93.95949,5.675,0,0.2804,0.0176,0.0024,0.0024,0.001,0.0009,0.0003,0.0004,0.0001,0.00001,0,0,0,0,0,0,0.06,0}, + {93.9566,4.5259,1.5175,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {93.913996,0.237979,1.016264,3.914341,0.742569,0.0759,0.059082,0.0172,0.00837,0.0143,0,0,0,0,0,0,0,0,0,0,0}, + {93.85591,0.34655,0.92581,2.45284,1.13853,0.3116,0.33756,0.13582,0.10387,0.27365,0.07191,0.04095,0.002,0.003,0,0,0,0,0,0,0}, + {93.81568,0.25567,4.96027,0.26704,0.42695,0.11119,0.06312,0.03125,0.0071,0.05132,0,0,0,0,0,0,0,0,0,0.01041,0}, + {93.502,0.512,0.957,3.013,1.005,0.292,0.27,0.133,0.082,0.234,0,0,0,0,0,0,0,0,0,0,0}, + {93.3574,0.1104,0.7971,3.8551,1.0291,0.2289,0.2087,0.0891,0.0598,0.2644,0,0,0,0,0,0,0,0,0,0,0}, + {93.098,0.078,1.694,2.963,1.174,0.23,0.313,0.118,0.087,0.245,0,0,0,0,0,0,0,0,0,0,0}, + {92.897,0.113,2.32,2.852,0.874,0.188,0.207,0.103,0.076,0.37,0,0,0,0,0,0,0,0,0,0,0}, + {92.892,0.86,1.098,3.936,0.774,0.096,0.149,0.038,0.028,0.023,0.014,0.004,0,0,0.042,0.003,0,0,0,0.04,0.003}, + {92.9619,2.632,1.207,2.6674,0.3038,0.0396,0.068,0.0194,0.0247,0.0114,0.0069,0.0034,0.0005,0,0,0,0,0,0,0.054,0}, + {92.821,0.492,0.133,2.599,1.946,0.308,0.764,0.218,0.25,0.224,0.164,0.081,0,0,0,0,0,0,0,0,0}, + {92.884157,0.827584,0.877833,3.321687,1.027678,0.137811,0.294644,0.109147,0.13939,0.122191,0.168669,0.067254,0.018879,0.001072,0,0.002007,0,0,0,0,0}, + {92.770458,0.108454,0.745392,4.261351,1.192365,0.262195,0.244552,0.100902,0.0694,0.088,0.083,0.062631,0.0113,0,0,0,0,0,0,0,0}, + {92.665,0.164,1.713,3.083,1.143,0.349,0.293,0.14,0.087,0.159,0.09,0.057,0.018,0.039,0,0,0,0,0,0,0}, + {92.469,0.113,2.571,3.158,0.932,0.211,0.201,0.071,0.044,0.23,0,0,0,0,0,0,0,0,0,0,0}, + {92.288,0.381,0.59,3.521,1.89,0.35,0.446,0.129,0.088,0.317,0,0,0,0,0,0,0,0,0,0,0}, + {92.208,6.196,0.549,0.629,0.134,0.038,0.049,0.028,0.022,0.09849,0.04263,0.00588,0,0,0,0,0,0,0,0,0}, + {92.173,0.303,1.088,3.37,1.335,0.367,0.466,0.237,0.175,0.486,0,0,0,0,0,0,0,0,0,0,0}, + {92.1244,1.1733,0.9663,4.3547,0.9299,0.093,0.1218,0.0259,0.024,0.0147,0,0,0,0,0.1427,0,0,0,0,0.0293,0}, + {92.07,0.9,1.97,4.63,0.35,0.03,0.04,0.01,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {92.067257,0.157545,0.679069,4.805366,1.520166,0.306933,0.283102,0.0372,0.00244,0.140922,0,0,0,0,0,0,0,0,0,0,0}, + {92.066,0.246,0.431,3.259,1.949,0.426,0.77,0.256,0.222,0.179,0.131,0.065,0,0,0,0,0,0,0,0,0}, + {92.03649,2.3046,0.13287,2.38147,1.70895,0.36904,0.65858,0.17845,0.13289,0.04541,0,0,0,0,0,0,0,0,0,0.05125,0}, + {92.015043,0.13873,0.47158,4.28605,2.04799,0.33852,0.51189,0.10219,0.07189,0.000047,0.01607,0,0,0,0,0,0,0,0,0,0}, + {91.96848,1.054,1.119,4.562,0.8,0.096,0.158,0.044,0.036,0.0347,0.0238,0.0127,0.00336,0.00096,0.046,0.001,0,0,0,0.035,0.005}, + {91.702,0.122,2.185,3.325,1.385,0.298,0.38,0.147,0.109,0.347,0,0,0,0,0,0,0,0,0,0,0}, + {91.5724,5.508,1.085,1.614,0.1283,0.0232,0.0175,0.0082,0.0048,0.0018,0.0008,0.0009,0.0001,0,0,0,0,0,0,0.035,0}, + {91.438166,0.163873,0.675596,4.956436,1.599984,0.360954,0.350597,0.136459,0.100087,0.217849,0,0,0,0,0,0,0,0,0,0,0}, + {91.34,0.85,2.05,4.87,0.62,0.08,0.11,0.04,0.03,0.01,0,0,0,0,0,0,0,0,0,0,0}, + {91.156,0.337,0.742,5.223,1.806,0.278,0.313,0.07,0.045,0.018,0.009,0.003,0,0,0,0,0,0,0,0,0}, + {91.0481,7.8453,0.0847,0.6367,0.1497,0.0575,0.057,0.032,0.0216,0.0337,0.0337,0,0,0,0,0,0,0,0,0,0}, + {91.003,0.296,0.515,4.616,2.009,0.447,0.56,0.179,0.135,0.115,0.084,0.041,0,0,0,0,0,0,0,0,0}, + {90.81921,7.12831,0.87065,0.88296,0.07926,0.01707,0.01635,0.00765,0.00503,0.04098,0,0,0,0,0,0,0,0,0,0.13253,0}, + {90.778696,0.218559,1.082231,4.081287,2.204731,0.691659,0.523352,0.193033,0.100592,0.125861,0,0,0,0,0,0,0,0,0,0,0}, + {90.7072,0.2818,0.5716,4.0796,2.2932,0.4856,0.8144,0.2499,0.2119,0.3048,0,0,0,0,0,0,0,0,0,0,0}, + {90.601,0.555,1.186,3.985,1.798,0.53,0.498,0.221,0.145,0.481,0,0,0,0,0,0,0,0,0,0,0}, + {90.585,0.209,1.336,4.286,1.613,0.371,0.543,0.233,0.221,0.288,0.211,0.104,0,0,0,0,0,0,0,0,0}, + {90.4054,4.1499,0.6147,3.7884,0.7247,0.0777,0.118,0.0284,0.0259,0.0257,0.0084,0.0024,0.0005,0,0.0001,0.0268,0,0.003,0,0,0}, + {90.389101,2.175303,0.319142,4.256873,1.716217,0.167522,0.416726,0.104049,0.136972,0.090131,0.09575,0.085796,0.040432,0.004163,0,0.001822,0,0,0,0,0}, + {90.195993,0.196547,0.607043,5.56051,1.926996,0.441314,0.446464,0.166889,0.126551,0.137885,0.116008,0.06971,0.00809,0,0,0,0,0,0,0,0}, + {90.076537,0.212278,1.15296,4.309807,2.350053,0.757585,0.573712,0.224241,0.119511,0.223316,0,0,0,0,0,0,0,0,0,0,0}, + {89.973843,1.702552,0.698605,4.444986,1.04861,0.164982,0.414362,0.211575,0.29689,0.418376,0.484131,0.109091,0.025649,0.00231,0,0.004038,0,0,0,0,0}, + {89.7879,6.935,2.815,0.3716,0.0114,0.0006,0.0014,0.0001,0,0,0,0,0,0,0,0,0,0,0,0.077,0}, + {89.741,0.15,0.962,4.754,2.37,0.568,0.683,0.275,0.185,0.312,0,0,0,0,0,0,0,0,0,0,0}, + {89.7,1,1,5,1.5,0.5,0.5,0.35,0.25,0.1,0.1,0,0,0,0,0,0,0,0,0,0}, + {89.6437,0.4283,2.1759,4.0698,1.7465,0.5081,0.4588,0.1691,0.0885,0.35565,0.35565,0,0,0,0,0,0,0,0,0,0}, + {89.581465,0.209144,1.261752,5.455874,2.2016,0.603999,0.457865,0.0736,0.0551,0.0996,0,0,0,0,0,0,0,0,0,0,0}, + {89.573,0.101,2.333,5.225,1.478,0.301,0.228,0.132,0.058,0.571,0,0,0,0,0,0,0,0,0,0,0}, + {89.46039,5.01537,0.0497,2.96667,1.10882,0.17962,0.3367,0.09144,0.08423,0.09412,0,0,0,0,0,0,0,0,0,0.61294,0}, + {89.3266,0.152,0.3279,5.6208,2.5886,0.4661,0.7645,0.2356,0.1961,0.3218,0,0,0,0,0,0,0,0,0,0,0}, + {89.2923,0.1072,4.0183,3.9297,1.1935,0.3476,0.3044,0.1632,0.0953,0.27425,0.27425,0,0,0,0,0,0,0,0,0,0}, + {89.166,0.295,1.348,4.897,2.292,0.478,0.689,0.231,0.191,0.197,0.145,0.071,0,0,0,0,0,0,0,0,0}, + {89.12266,8.44852,0.86181,1.16145,0.10696,0.03044,0.01913,0.00866,0.0036,0.05588,0,0,0,0,0,0,0,0,0,0.18089,0}, + {88.80292,0.600283,9.698425,0.864011,0.033097,0,0,0,0,0,0,0,0,0,0,0.001264,0,0,0,0,0}, + {88.5275,0.0821,0.6722,6.5923,2.4754,0.5148,0.6513,0.1408,0.097,0.1368,0.0785,0.0184,0.0129,0,0,0,0,0,0,0,0}, + {88.479,0.247,0.212,4.657,3.426,0.571,1.303,0.343,0.345,0.199,0.146,0.072,0,0,0,0,0,0,0,0,0}, + {88.404,0.216,0.984,5.976,2.605,0.42,0.607,0.161,0.129,0.498,0,0,0,0,0,0,0,0,0,0,0}, + {88.3889,2.086,1.803,4.9413,1.7055,0.3086,0.4677,0.1209,0.1111,0.0232,0.0041,0.0017,0,0,0,0,0,0,0,0.038,0}, + {88.2203,0.0504,7.5601,3.2634,0.473,0.1329,0.0777,0.0485,0.0258,0.1479,0,0,0,0,0,0,0,0,0,0,0}, + {88.1024,9.615,0.724,1.4254,0.0588,0.0134,0.01,0.004,0.003,0.0015,0.0008,0.0004,0.0002,0.0001,0,0,0,0,0,0.041,0}, + {88.06,0.166,2.112,4.911,2.629,0.54,0.746,0.263,0.195,0.378,0,0,0,0,0,0,0,0,0,0,0}, + {88.0501,3.557,0.146,4.739,1.956,0.279,0.557,0.156,0.165,0.128,0.065,0.027,0.0023,0.0006,0.032,0,0,0,0,0.122,0.018}, + {87.8114,0.693608,0,9.159537,1.857564,0.1876,0.23005,0.02308,0.018705,0.004554,0.001116,0.000129,0,0,0,0.00015,0,0,0,0,0.012506}, + {87.7585,0.4479,0.0067,8.5377,2.3391,0.3931,0.3418,0.092,0.0421,0.02055,0.02055,0,0,0,0,0,0,0,0,0,0}, + {87.744,0.414,1.207,5.54,2.398,0.725,0.72,0.375,0.228,0.649,0,0,0,0,0,0,0,0,0,0,0}, + {87.57247,0.21764,1.88718,6.81648,2.06788,0.3665,0.47401,0.15509,0.10979,0.32645,0,0,0,0,0,0,0,0,0,0.00651,0}, + {87.47047,0.948391,0.670202,6.633493,2.596537,0.299792,0.636925,0.17724,0.159765,0.145009,0.147976,0.097974,0.014799,0.000905,0,0.000522,0,0,0,0,0}, + {87.37838,0.20143,1.54039,7.6701,2.01135,0.3055,0.32428,0.10187,0.06964,0.39059,0,0,0,0,0,0,0,0,0,0.00647,0}, + {87.24227,1.84185,0.14129,5.71159,2.90147,0.71461,0.83363,0.27219,0.19623,0.1166,0,0,0,0,0,0,0,0,0,0.02827,0}, + {87.1484,9.31528,0.17051,1.56491,0.82581,0.16698,0.22774,0.07244,0.04924,0.0546,0,0,0,0,0,0,0,0,0,0.40409,0}, + {87.0964,0.0603,4.7921,5.7486,1.2839,0.3165,0.2351,0.1276,0.0723,0.2672,0,0,0,0,0,0,0,0,0,0,0}, + {87.0604,0.4203,0.4686,7.6632,2.5745,0.4268,0.5982,0.2034,0.1299,0.4545,0,0,0,0,0,0,0,0,0.0002,0,0}, + {87.0151,10.994,0.467,1.3691,0.069,0.0139,0.0109,0.0047,0.0032,0.0014,0.0009,0.0003,0.0004,0.0001,0,0,0,0,0,0.05,0}, + {86.9808,5.4976,0.0012,5.0545,1.4683,0.2955,0.3367,0.1465,0.0426,0.0816,0.0173,0.005,0.0023,0,0.0001,0.065,0,0.005,0,0,0}, + {86.945,0.131,1.994,6.402,2.19,0.486,0.558,0.31,0.189,0.795,0,0,0,0,0,0,0,0,0,0,0}, + {86.8952,9.33596,1.7281,1.64516,0.09214,0.03923,0.0264,0.00875,0.00485,0.01996,0,0,0,0,0,0,0,0,0,0.20425,0}, + {86.8614,0.3004,0.7936,6.9925,2.8641,0.6977,0.6889,0.2534,0.1889,0.3591,0,0,0,0,0,0,0,0,0,0,0}, + {86.19646,0.55988,0.8122,7.32335,3.3262,0.56283,1.0227,0.09899,0.0581,0.01973,0,0,0,0,0,0,0,0,0,0.01956,0}, + {85.11,0.322,2.537,5.771,3.022,1.007,0.92,0.482,0.29,0.539,0,0,0,0,0,0,0,0,0,0,0}, + {85.10946,0.49356,0,9.71687,3.52962,0.34733,0.60476,0.08049,0.06974,0.02904,0,0,0,0,0,0,0,0,0,0.01913,0}, + {84.8128,0.409,2.1109,10.6707,1.7673,0.08,0.1258,0.0115,0.01,0.002,0,0,0,0,0,0,0,0,0,0,0}, + {84.339,0.164,1.822,7.799,2.884,0.718,0.768,0.292,0.196,1.018,0,0,0,0,0,0,0,0,0,0,0}, + {84.3186,12.663,0.684,1.9567,0.2196,0.036,0.0375,0.0094,0.0086,0.0029,0.0021,0.001,0.0005,0.0001,0,0,0,0,0,0.06,0}, + {84.2749,3.0264,0.0642,7.1697,3.2646,0.3387,0.9764,0.1976,0.2479,0.1256,0.1303,0.1158,0.0202,0,0,0.0003,0,0,0,0.0474,0}, + {83.628,0.208,15.233,0.765,0.148,0.009,0.009,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {83.58133,4.23534,0,7.52796,3.27016,0.27318,0.60219,0.06742,0.05495,0.02031,0,0,0,0,0,0,0,0,0,0.36716,0}, + {83.483,3.266,0,9.906,2.955,0.208,0.162,0.01,0.004,0.004,0.001,0.001,0,0,0,0,0,0,0,0,0}, + {83.29,0,7.89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8.82,0,0}, + {83.26911,0.60063,0.868,9.26637,5.03144,0.53156,0.39038,0.01883,0.01302,0,0,0,0,0,0,0,0,0,0,0.01066,0}, + {83.1,6.4,0,8.7,1.2,0.1,0.2,0.1,0.1,0.1,0,0,0,0,0,0,0,0,0,0,0}, + {82.75,0.25,4,2.5,0.25,0.05,0.05,0.05,0.05,0.05,0,0,0,0,0,0,0,0,10,0,0}, + {82.71012,1.690648,0.074913,6.838511,3.787402,0.566305,1.455215,0.441801,0.604675,0.448334,0.651589,0.499925,0.196589,0.033125,0,0.000849,0,0,0,0,0}, + {82.4255,0.3344,3.4692,5.148,3.32,2.5356,1.1595,0.6124,0.3544,0.3205,0.3205,0,0,0,0,0,0,0,0,0,0}, + {82.315035,10.246063,1.476152,4.436326,1.004784,0.138222,0.176057,0.044695,0.036874,0.029867,0.036616,0.009333,0.001639,0.000612,0.0003,0.001068,0,0,0,0.041437,0.004919}, + {82.22839,0.4398,1.39064,10.5382,4.90575,0.19811,0.25262,0.02142,0.01543,0,0,0,0,0,0,0,0,0,0,0.00964,0}, + {81.998043,6.073341,0.30695,5.838525,3.737102,0.394363,0.54481,0.230385,0.369107,0.149374,0.050218,0.011072,0.000121,0,0,0.001272,0,0,0,0.295317,0}, + {81.95156,1.60528,1.32751,9.04654,4.16965,0.53414,0.95291,0.16312,0.14319,0.08159,0,0,0,0,0,0,0,0,0,0.02451,0}, + {81.6967,7.3856,0.009,6.7207,2.7017,0.2636,0.5704,0.1114,0.1179,0.0325,0.0094,0.0022,0.0005,0,0.0245,0.0192,0,0.012,0.001,0.3217,0}, + {81.3,0.219,16.117,1.609,0.278,0.039,0.059,0.031,0.028,0.32,0,0,0,0,0,0,0,0,0,0,0}, + {81.078,0.416,0.207,8.01,6.928,0.784,1.719,0.293,0.308,0.123,0.09,0.044,0,0,0,0,0,0,0,0,0}, + {81,0,1.03,7.44,5.72,1.06,1.64,0.49,0.39,0.55,0.5,0.14,0.03,0.01,0,0,0,0,0,0,0}, + {80.946949,3.378699,0.141227,6.791011,3.988482,0.59416,1.566385,0.479023,0.645727,0.732772,0.548692,0.171329,0.014957,0.000425,0,0.000162,0,0,0,0,0}, + {80.58289,0.44598,1.02247,12.00581,5.22714,0.23518,0.38233,0.04489,0.03336,0.01274,0,0,0,0,0,0,0,0,0,0.00721,0}, + {80.21816,1.46108,0.84727,11.90565,4.85869,0.30351,0.3354,0.01813,0.00979,0,0,0,0,0,0,0,0,0,0,0.04232,0}, + {79.881,0.195,0.16,7.872,6.895,0.884,2.378,0.551,0.581,0.421,0.117,0.052,0.013,0,0,0,0,0,0,0,0}, + {79.8501,0.632,0.569,10.3779,4.576,0.545,1.567,0.356,0.584,0.943,0,0,0,0,0,0,0,0,0,0,0}, + {79.848,0.545,0.926,9.003,6.203,1.306,1.525,0.362,0.201,0.05427,0.02349,0.00324,0,0,0,0,0,0,0,0,0}, + {79.36567,1.163,0.114,11.677,4.988,0.447,1.197,0.263,0.252,0.153,0.0876,0.0385,0.00542,0.00081,0.174,0,0,0,0,0.071,0.003}, + {77.97,0.371,0.242,10.097,7.376,0.905,2.02,0.328,0.345,0.199,0.067,0.08,0,0,0,0,0,0,0,0,0}, + {77.961,0.64,0.385,8.608,7.721,0.947,2.479,0.453,0.455,0.168,0.123,0.06,0,0,0,0,0,0,0,0,0}, + {77.999778,0.552942,0.895427,12.02321,4.511631,0.43559,1.50226,0.282258,0.474022,0.371922,0.378585,0.354861,0.192679,0.024835,0,0,0,0,0,0,0}, + {77.58612,1.52306,0,15.3834,4.69307,0.32929,0.39609,0.03631,0.02028,0,0,0,0,0,0,0,0,0,0,0.03238,0}, + {77.411,0.447,0.098,15.508,4.967,0.415,0.859,0.101,0.103,0.027,0.004,0,0,0,0.035,0.004,0,0,0,0.021,0}, + {77.2797,5.0894,0.0001,14.9209,2.1267,0.2492,0.2681,0.0355,0.0246,0.003886,0.001682,0.000232,0,0,0,0,0,0,0,0,0}, + {77.1203,0.5364,0.1685,12.5944,6.342,0.8574,1.5559,0.3129,0.2879,0.2243,0,0,0,0,0,0,0,0,0,0,0}, + {76.255,22.065,0.58,0.9625,0.0299,0.0077,0.0041,0.0022,0.0015,0.0006,0.0004,0,0.0001,0,0,0,0,0,0,0.091,0}, + {75.769,0.33,0.457,10.648,7.942,1.073,2.545,0.508,0.496,0.143,0.06,0.029,0,0,0,0,0,0,0,0,0}, + {75.554281,5.769795,0.20124,8.164206,5.027471,0.821108,2.345239,0.677005,0.922851,0.381812,0.117568,0.015599,0.000561,0,0,0.001264,0,0,0,0,0}, + {75.45,0,11.28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13.27,0,0}, + {75.1,3.4,0,17.3,2.7,0.3,0.6,0.2,0.2,0.2,0,0,0,0,0,0,0,0,0,0,0}, + {74.7042,0.8729,1.5901,6.0731,8.1212,5.0359,2.4555,0.6363,0.3099,0.10045,0.10045,0,0,0,0,0,0,0,0,0,0}, + {73.72889,2.83044,0.96973,21.97829,0.29266,0.03822,0.06787,0.01452,0.01352,0.00332,0,0,0,0,0,0,0,0,0,0.06254,0}, + {73.6505,0.8567,1.7302,13.995,6.7047,1.4275,1.2579,0.2356,0.1104,0.0315,0,0,0,0,0,0,0,0,0,0,0}, + {71.38541,3.14628,0.95362,24.26673,0.15307,0.00776,0.01522,0.00145,0.0017,0,0,0,0,0,0,0,0,0,0,0.06876,0}, + {69.56109,8.54918,1.04002,16.86119,3.04172,0.12064,0.25717,0.02072,0.01624,0,0,0,0,0,0,0,0,0,0,0.53203,0}, + {68.365571,2.301598,0.349596,10.458479,8.988222,1.175538,3.242343,0.896405,1.340342,1.100411,1.27877,0.421622,0.069836,0.007742,0,0.003525,0,0,0,0,0}, + {67.441167,0.442886,1.901399,22.471043,6.461846,0.288192,0.803343,0.071433,0.083677,0.026594,0.006686,0.000894,0.000031,0,0,0.000809,0,0,0,0,0}, + {67.14,0.04,29.04,3.13,0.57,0.06,0,0.02,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {66.100492,9.920358,0.5784,12.809981,6.59326,0.756312,1.829677,0.371826,0.456861,0.27078,0.200677,0.090216,0.018772,0.001171,0,0.001218,0,0,0,0,0}, + {66.01,0.27,2.48,10.24,4.79,0.55,1.27,0.2,0.27,0.14,0.06,0.01,0,0,0,0,0,0,13.7,0.01,0}, + {65.275,16.816,17.83,0.079,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {63.155785,1.284518,9.305238,6.509759,7.122961,1.563064,4.296421,1.334616,2.929742,1.56106,0.619214,0.157308,0.06613,0.094185,0,0,0,0,0,0,0}, + {62.36,0.24,4.54,5.97,2.94,0.57,1.21,0.53,0.74,1.12,0.81,0.27,0.01,0,0.01,0,0,0,18.67,0.01,0}, + {62.232,0.41,0.347,18.174,13.439,1.46,3.206,0.351,0.317,0.041,0.019,0.004,0,0,0,0,0,0,0,0,0}, + {62.225,0.575,0.266,18.446,14.098,1.247,2.585,0.262,0.227,0.033,0.024,0.012,0,0,0,0,0,0,0,0,0}, + {61.836,32.92,0.04,2.585,1.227,0.149,0.291,0.062,0.053,0.072,0,0,0,0,0,0.044,0,0,0,0.721,0}, + {56.255,1.529,4.172,14.462,8.19,1.155,3.965,0.945,1.191,0.558,0,0,0,0,0,0,0,0,7.578,0,0}, + {48.253,2.587,6.142,19.773,13.015,1.736,4.006,0.976,0.922,1.19,0,0,0,0,0,0,0,0,1.4,0,0}, + {47.626349,45.560329,0.069854,2.816443,2.041189,0.325189,0.793324,0.177154,0.227927,0.093194,0.101909,0.10147,0.057024,0.007773,0,0.000871,0,0,0,0,0}, + {45.473,3.505,9.498,14.676,13.749,1.933,5.164,1.507,1.307,0.738,0,0,0,0,0,0,0,0,2.45,0,0}, + {32.8042,1.3411,6.8507,21.422,17.7536,2.3134,5.9043,1.3381,1.3033,1.6911,0,0,0,0,0,0,0,0,7.2782,0,0}, + {32.095,0.39,3.34,21.24,22.535,2.763,8.415,2.217,3.101,3.895,0,0,0,0,0,0,0,0,0,0.009,0}, + {31.3359,0.4148,67.6289,0.36,0.1439,0.0156,0.0399,0.0105,0.0131,0.0176,0.0131,0.0064,0.0003,0,0,0,0,0,0,0,0}, + {24.771,64.615,1.149,1.835,1.415,0.323,0.767,0.285,0.353,0.718,0,0,0,0,0,0.283,0,0,0,3.486,0}, + {21.2401,7.74,64.5369,0.512,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5.09,0.629,0.252}, + {20,1.99,29.458,7.97,19.9,2.1,2.1,1.04,1.03,0.312,0,0,0,0,0,0,0,0,14,0,0.1}, + {18.330586,79.049225,0.135005,0.380462,0.043199,0,0.000473,0.000223,0,0,0,0,0,0,0,2.060827,0,0,0,0,0}, + {17.853193,29.009483,0.502491,12.351052,20.500845,3.688749,9.577971,2.121356,2.221701,0.854673,0.410747,0.091845,0.004282,0.000093,0,0.811519,0,0,0,0,0}, + {9.488,1.647,86.536,1.734,0.401,0.029,0.093,0.014,0.02,0.018,0,0,0,0,0,0,0,0,0.02,0,0}, + {9.15799,0.41788,87.913605,1.336899,0.673546,0.04486,0.197206,0.048737,0.06558,0.054068,0.063497,0.015834,0.006521,0.001611,0,0.002167,0,0,0,0,0}, + {1.113,0,19.185,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79.702,0,0}, + {0.96,0.92,45.32,0.96,0.61,0.49,0.48,0.07,0.19,0.04,0,0,0,0,0,0,0,0,49.96,0,0}, + {100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +}; + +std::vector validation_data = { + { 2,190.68,11.0,4.62270367011,45.4451259446,7883.3949099,229.601025004 }, + { 3,190.5,11.0,4.61746427515,45.5151912828,7771.78810714,229.085523569 }, + { 4,190.83,11.0,4.64516211814,45.2658426433,4905.55490022,230.317348488 }, + { 5,190.65,11.0,4.64297558383,45.1856923279,4744.40155422,230.704421197 }, + { 6,130.8,1.0,0.816531614503,46.940490349,97.8401467136,248.612998885 }, + { 9,191.68,12.0,4.62468477409,42.0537079316,1946.67809823,241.885646942 }, + { 10,190.3,11.0,4.6663056297,44.914958222,2902.964215,231.36172711 }, + { 12,230.6,5.0,6.58054561299,29.2228095011,65.3720465645,346.404609362 }, + { 13,194.05,10.0,4.8619048335,45.0799761925,1481.30706334,236.03859612 }, + { 14,193.15,10.0,4.7971453615,46.0796923329,1867.29001195,231.348043201 }, + { 15,193.11,10.0,4.91403161515,43.6894498673,1077.65187345,241.347857919 }, + { 17,196.2,10.0,5.08916825631,42.4239390997,790.091839087,247.905572913 }, + { 18,225.89,8.0,7.86175274559,32.1986731579,112.23566486,330.504863964 }, + { 19,247.99,6.0,8.41095710807,30.2380337316,68.3464658457,362.008654969 }, + { 20,222.02,7.0,7.09598653117,31.782452571,105.248324057,321.164128485 }, + { 21,213.06,6.0,5.8900296652,32.1306740606,108.971527681,300.33738017 }, + { 22,199.01,9.0,5.22647829222,41.103244467,568.646792395,251.766405114 }, + { 23,201.28,9.0,5.37982847365,39.9620298817,450.937490798,259.788742619 }, + { 24,196.37,10.0,5.19157888165,41.2818157085,636.277497057,252.810869976 }, + { 25,231.86,7.0,7.83733139315,31.4783001914,92.2051822127,334.746641412 }, + { 26,196.85,10.0,5.22148503243,41.1025787658,609.024627195,253.98705191 }, + { 27,246.54,3.5,5.66177517777,28.5056264506,50.801413577,366.055831605 }, + { 28,196.02,10.0,4.94240303924,45.6848657651,1221.88921461,231.212226699 }, + { 29,234.05,6.0,7.40322191186,30.5415601377,77.5671754472,338.155827887 }, + { 30,221.05,6.0,6.45415409646,31.3430191493,93.315236451,313.627351501 }, + { 31,255.57,7.0,9.97926759849,30.56156681,70.7440829023,377.977990114 }, + { 32,211.52,8.0,6.11581362063,35.6247051707,200.408967133,286.770323857 }, + { 33,181.16,18.0,3.18204781896,31.6700403854,97.2159372943,549.617923002 }, + { 34,242.44,11.0,12.9095560514,30.4240098053,82.4863204228,431.951122477 }, + { 35,196.14,10.0,4.99882564087,44.5409462682,960.424608357,236.275664671 }, + { 36,273.35,10.0,15.6545907684,31.639830008,70.5051265019,454.724468103 }, + { 37,234.59,6.0,7.61364436363,29.9654328183,73.3329902401,345.688950086 }, + { 38,241.69,8.0,9.35481494409,31.7127286702,89.7485809812,357.613524565 }, + { 39,236.5,8.0,8.75849157855,32.1463991117,97.7521265976,344.453796488 }, + { 40,231.01,8.0,8.18423596668,32.4330998871,107.552637682,333.365652348 }, + { 41,236.97,7.0,8.23061398495,31.3624849451,87.2482019715,340.192922049 }, + { 42,201.46,9.0,5.47266203231,39.1998335928,393.758164264,262.64872431 }, + { 43,226.13,7.0,7.23313132978,32.2418314792,105.203129887,318.958847984 }, + { 44,247.1,6.0,8.33411935702,30.2114128073,68.9618723857,358.351699507 }, + { 45,232.94,8.0,8.30415554865,32.5671616693,105.800327699,335.993914233 }, + { 46,227.22,7.0,7.50324389677,31.6835795586,97.0429632513,326.998331734 }, + { 47,231.03,7.0,7.60758922075,32.1036356548,97.9455334285,326.487573118 }, + { 49,170.47,19.0,2.77384777303,30.756485902,87.041515141,599.937363291 }, + { 50,207.24,9.0,5.84820929949,37.8277545916,296.942776559,273.730227574 }, + { 51,261.45,8.0,11.3436891099,31.6611908223,75.0970172748,389.32509397 }, + { 52,238.57,2.0,3.39777306021,27.615808921,43.4631657762,357.530699336 }, + { 53,237.06,8.0,8.75101482894,32.2698258184,98.4709237108,343.392863743 }, + { 54,237.02,8.0,8.66778109895,32.453650345,100.393192163,341.920465102 }, + { 55,238.06,8.0,8.76031434399,32.4530923518,99.2203049076,341.536457882 }, + { 56,242.68,8.0,9.30124541534,32.0536020178,91.789682505,351.034557936 }, + { 57,223.8,7.0,7.00953554963,32.6072486709,111.007622635,313.27999208 }, + { 58,202.47,9.0,5.71915100585,37.5900469278,309.348011177,269.875078353 }, + { 59,261.72,9.0,12.1292810299,32.8015013361,81.0171183867,397.921231366 }, + { 60,259.34,9.0,12.237590247,31.7676325747,78.3618191292,402.068996966 }, + { 61,258.26,8.0,10.891394584,31.861415713,78.32824206,381.712054461 }, + { 62,270.55,9.0,13.538516296,31.9382536625,73.1012246759,418.603814715 }, + { 63,233.28,8.0,8.28604231415,32.650856773,107.16353144,330.746284279 }, + { 64,246.46,8.0,9.45352634679,32.7176539319,91.6751582623,353.648260877 }, + { 65,238.64,7.0,9.09762160388,29.4803232957,72.2479993202,362.116587241 }, + { 66,246.79,9.0,10.238785593,32.924812429,95.200693943,366.380555381 }, + { 67,212.89,8.0,6.26949122568,35.3548810196,185.166017215,287.488222533 }, + { 68,204.46,10.0,5.62077028367,39.865962246,392.736260379,263.716759856 }, + { 69,230.28,8.0,7.77072719526,33.5936252164,119.889993904,321.492875878 }, + { 70,257.13,9.0,11.4030030108,33.0825663167,86.1156991851,385.326354275 }, + { 71,233.84,8.0,8.42776381739,32.6465466941,103.047719554,335.561625352 }, + { 72,230.75,8.0,7.71655059351,33.9265358788,121.992584935,319.511432491 }, + { 73,252.78,6.0,8.59046840657,30.7419943263,68.7381871461,360.324854111 }, + { 74,246.36,8.0,9.45805643807,32.5907431701,91.7009234444,351.129014303 }, + { 76,240.87,8.0,8.76330453951,33.1732520223,101.36027497,340.10291148 }, + { 77,212.68,8.0,6.12995336715,36.0816525275,201.926945138,281.059176853 }, + { 78,227.56,8.0,7.38691723508,34.2809431308,131.913749557,311.666792124 }, + { 79,231.93,6.0,7.76277074981,29.1238121393,68.6450483976,347.400436959 }, + { 80,255.83,8.0,10.2653604751,32.9577115673,85.2644386911,365.991066619 }, + { 81,209.74,6.0,6.08973069491,30.7258454944,94.3516644609,304.52964904 }, + { 82,242.46,8.0,8.77950585052,33.5928118854,102.259020255,337.384402389 }, + { 83,246.66,9.0,9.85052469167,33.8551588583,101.21119028,357.409357652 }, + { 84,248.38,9.0,10.2241838576,33.4018863878,96.4457739305,363.331727547 }, + { 85,265.89,9.0,12.3921187705,33.217492979,80.9090739965,396.947957401 }, + { 87,264.02,9.0,12.7036564403,32.1710600142,76.731901663,406.019919568 }, + { 88,264.23,8.0,11.0824330058,33.0370344112,80.0101892606,378.482675777 }, + { 89,249.38,8.0,9.39142552101,33.6500343743,95.1008837745,346.992315346 }, + { 90,283.26,9.0,14.7992125107,33.255922569,71.1106660163,430.046107672 }, + { 91,190.6,11.0,5.02463332845,41.996918555,593.361408615,241.453850824 }, + { 92,246.87,9.0,9.73818062937,34.1416951875,103.376211234,353.669374085 }, + { 93,251.94,8.0,9.83191285185,33.1153456235,89.3111068954,356.290213018 }, + { 94,262.02,9.0,11.8517619025,33.3274021219,84.2096198186,386.009374638 }, + { 95,238.1,8.0,8.23273432916,34.1175127144,112.591123082,325.525123479 }, + { 96,254.46,8.0,10.064139923,33.0040639842,87.5233777336,358.402488324 }, + { 97,186.4,17.0,5.04833870664,31.9105995386,98.1181880374,518.60922022 }, + { 98,247.94,9.0,9.76227826876,34.3693143337,103.541465467,354.495741403 }, + { 99,253.61,9.0,10.9174043368,32.9833208652,90.23919527,369.687791845 }, + { 100,258.58,9.0,11.2335200316,33.7756229208,89.0922749531,377.139569914 }, + { 101,207.63,7.0,6.41425622373,31.6602809277,116.411274674,299.01766929 }, + { 102,203.03,10.0,5.39068762355,43.3983182562,557.00704534,237.529516591 }, + { 103,257.36,8.0,10.0646842666,33.8602490725,89.3828572907,358.090266488 }, + { 104,265.65,9.0,11.6827824024,34.9119885774,88.1612603561,382.093439703 }, + { 105,250.86,9.0,10.0837978671,34.3425117357,100.224212896,357.901302852 }, + { 106,231.97,8.0,7.89448862723,33.7913350643,117.122917741,318.256796948 }, + { 107,230.07,7.0,7.27715826734,33.0390810593,109.337214095,304.866741453 }, + { 109,250.27,9.0,9.97133706727,34.4587392885,101.806187558,353.381524146 }, + { 110,254.92,8.0,10.4901035642,32.4125141009,81.5599108086,368.572177752 }, + { 111,224.33,9.0,7.02599693886,36.3734399912,173.460975175,300.623292839 }, + { 112,236.25,8.0,7.83116332192,34.9613804227,123.224247533,317.472618577 }, + { 113,259.85,9.0,11.0444438772,34.6038683657,92.3083026167,371.112319966 }, + { 114,250.2,8.0,9.31295428194,33.9879367689,97.3805421901,342.545944156 }, + { 115,262.0,9.0,11.5826755,33.9513569985,87.0030001035,382.16902755 }, + { 116,250.16,8.0,9.30208970798,33.9845960702,97.5436893482,343.0853598 }, + { 117,244.73,9.0,9.41062776308,34.5835338586,107.451797521,346.317273065 }, + { 118,217.39,8.0,7.68814687039,31.5072524171,107.753257685,319.698576419 }, + { 119,241.39,8.0,8.55984724345,33.8163788663,107.582608578,325.467201647 }, + { 120,250.67,9.0,9.88829158121,34.7540978658,103.204374199,354.132003199 }, + { 123,260.51,9.0,11.0704708266,34.6119399597,92.488931266,369.853687611 }, + { 124,193.87,10.0,5.5164309055,38.4084389799,348.32829958,259.265403571 }, + { 125,251.57,9.0,9.88657642886,35.0209798543,103.812041846,352.55450895 }, + { 126,240.5,9.0,8.52763155273,35.6856392575,124.853882476,327.470034612 }, + { 127,262.33,9.0,10.9244361035,35.5644329631,95.4749721845,362.848796116 }, + { 128,238.91,9.0,8.18873272315,36.2175530089,133.330813522,321.432766598 }, + { 129,225.2,9.0,6.83994236212,37.4596116376,188.588898926,289.951007446 }, + { 130,268.85,9.0,11.5925656297,35.8330503479,91.3047230915,373.144623421 }, + { 132,266.55,9.0,12.0369503718,34.4967848717,84.8900132112,385.085115401 }, + { 133,210.96,10.0,5.90739329681,41.4597156023,372.254770376,244.512338754 }, + { 134,235.18,9.0,8.52878642711,34.6954872135,119.615641817,328.307597543 }, + { 135,229.06,9.0,7.5140295957,36.0972999074,149.297275562,307.359128171 }, + { 136,226.11,9.0,7.27364565958,34.5676454521,184.449674906,288.945310537 }, + { 137,241.02,9.0,8.19176501205,36.8513015751,134.541535309,317.105346144 }, + { 138,231.81,8.0,8.04517729342,33.5542392643,111.458050195,320.547852421 }, + { 139,233.1,9.0,7.82790324222,34.0662646041,155.807755896,305.082547493 }, + { 140,316.17,9.0,17.3334211335,39.2195064272,74.3816254092,440.129200554 }, + { 141,276.5,9.0,12.0884841896,37.2359159472,90.6649126465,372.319311105 }, + { 142,234.18,8.0,9.08170708489,31.3420922259,89.0954860843,339.919163572 }, + { 143,238.99,9.0,7.87151425572,37.2948870588,144.206748973,309.302082618 }, + { 144,252.44,9.0,10.7176513835,33.9197547019,91.54111138,363.217788956 }, + { 145,248.37,9.0,9.10784037388,36.2759907734,116.060814975,332.670989384 }, + { 146,266.6,11.0,16.1903284162,32.3372854558,73.0790755829,458.314146445 }, + { 147,236.88,8.0,8.12712284814,33.8607879483,119.072995232,298.444102989 }, + { 148,268.82,9.0,10.764572463,38.0268220872,100.884009866,356.624016449 }, + { 149,292.78,9.0,13.6104830364,39.1286934828,86.1079257312,393.037173526 }, + { 150,285.26,10.0,14.9460472976,37.5605850558,82.3486470927,423.534881035 }, + { 151,243.7,9.0,8.15112070576,37.643279493,137.700524199,313.634683613 }, + { 152,241.6,9.0,8.11015138579,37.3028366829,137.112508665,313.348100291 }, + { 153,282.26,9.0,11.982782144,39.4550807536,94.7482549712,371.328834117 }, + { 154,277.36,9.0,11.7789232371,38.1251945967,94.1318860748,370.668263038 }, + { 155,263.44,9.0,10.0412378515,38.1373315424,108.108750703,343.612519562 }, + { 156,271.38,8.0,10.4329685026,37.0094527178,93.5625015556,350.065218057 }, + { 157,274.98,9.0,10.9880076324,39.3513597496,101.606635249,356.055640094 }, + { 158,278.69,9.0,11.3870508883,39.7125305262,99.0284581842,360.720155115 }, + { 159,302.25,9.0,14.7947901938,39.4250461962,82.3114961797,406.771005698 }, + { 160,241.44,10.0,8.15220195415,38.212892703,144.510885805,321.286149934 }, + { 161,252.44,9.0,8.66976027666,38.4146476305,128.448451009,321.860804089 }, + { 162,234.5,9.0,7.79220737002,36.6616090976,141.458313202,308.505453731 }, + { 163,266.92,9.0,10.0670811805,39.0095179884,109.656609812,342.868883517 }, + { 165,270.5,10.0,10.8113759956,40.4400323578,109.086346908,363.549698422 }, + { 166,272.86,10.0,12.7291480031,38.0187708768,91.7953390826,391.09934158 }, + { 167,241.31,10.0,8.68109917043,34.0334463172,154.053528285,307.556427573 }, + { 168,251.57,9.0,9.04636788041,37.2611727547,118.947630681,329.251743401 }, + { 169,279.04,10.0,11.5988108076,42.0432122407,104.754607578,371.064181191 }, + { 170,231.58,10.0,7.08144168186,39.1507399174,182.997336534,295.514900796 }, + { 171,258.6,10.0,9.40330616186,39.7599018221,124.011685219,337.683858805 }, + { 172,233.24,10.0,7.08036243751,39.6032729349,182.842508006,293.937853235 }, + { 173,233.84,11.0,8.74209766117,36.4081184335,126.901796343,338.882311953 }, + { 174,310.19,10.0,15.2305393633,47.0753061878,94.3158152769,418.855629697 }, + { 175,256.95,10.0,8.42178432564,41.4264820298,144.032850503,316.58381689 }, + { 176,235.1,10.0,7.32275532405,39.7926633191,217.775362468,255.625552191 }, + { 177,274.07,10.0,12.689788628,38.6390864134,92.6566262261,382.506505033 }, + { 178,270.13,10.0,9.94380785805,38.7560507764,127.474989409,331.866622904 }, + { 179,209.29,10.0,6.9634757629,36.0947263441,182.130130219,262.418283535 }, + { 180,312.27,10.0,14.6520630866,48.6605146663,99.12252193,396.381149952 }, + { 181,303.93,10.0,13.7594443195,40.2460098847,99.0003926199,372.187226825 }, + { 182,281.88,10.0,9.91423544546,45.9003644661,123.713235736,343.374275975 }, + { 183,279.84,10.0,9.75365568702,45.5437243318,125.190814315,340.165736981 }, + { 184,215.01,10.0,10.4432902756,29.4388006779,82.9645750887,347.973036852 }, + { 185,292.77,10.0,11.037547721,45.4429261207,117.446946458,347.505909999 }, + { 186,299.33,10.0,10.7232913039,50.1402659086,120.922039815,348.892729043 }, + { 187,328.8,2.5,6.52997732457,28.9004427604,41.2456635657,391.802899563 }, + { 188,302.77,10.0,10.9593914062,50.9941968459,120.345314168,347.434252464 }, + { 189,324.72,9.0,9.5977360334,59.0054683434,144.60265504,306.753927376 }, + { 190,349.46,8.0,9.45674189307,71.732506713,152.503753711,299.294045031 }, + { 191,274.9,12.0,8.94266971098,43.9624144043,227.90004516,244.798877242 }, + { 192,308.71,4.0,9.85057517622,26.5629014571,40.4279546981,380.469340157 }, + { 193,275.94,13.0,10.1168205478,40.91404509,169.070296748,274.533510953 }, + { 194,317.98,9.0,8.76339697904,54.6455382659,183.097969149,255.592992441 }, + { 195,143.86,10.0,4.53641557343,33.9856970778,287.657541197,198.734160276 }, + { 196,374.45,4.0,9.14695409611,62.0642856225,95.4592625121,280.34143267 }, + { 197,293.55,12.0,8.13545547114,52.266177497,433.576985698,206.046707897 }, + { 198,297.68,11.0,8.11287585377,54.1055225168,543.627296793,196.766426663 }, + { 199,357.24,11.0,9.77272264849,43.6891149152,673.95827868,247.228832437 }, + { 200,331.57,11.0,9.01349433702,47.2424214857,513.285937824,230.179140482 }, +}; + +TEST_CASE("Validate all GERG2008 binaries", "[GERG20082]"){ + + // In the component order of the AGA8 test code + static std::vector components = {"methane","nitrogen","carbondioxide","ethane","propane","isobutane","n-butane","isopentane","n-pentane","n-hexane","n-heptane","n-octane","n-nonane","n-decane","hydrogen","oxygen","carbonmonoxide","water","hydrogensulfide","helium","argon"}; + + SetupGERG(); + + CHECK_NOTHROW(GERG2008::GERG2008ResidualModel(components)); + auto model = GERG2008::GERG2008ResidualModel(components); + + double R = 8.314472; + + for (auto i = 0; i < components.size(); ++i){ + for(auto j = i+1; j < components.size(); ++j){ + + double T_K = 300; + double rho_molm3 = 1000; + std::vector molefracs(21); + molefracs[i] = 0.5; + molefracs[j] = 0.5; + + auto rhocomplex = std::complex(rho_molm3, 1e-100); + double Ar01 = rho_molm3*model.alphar(T_K, rhocomplex, molefracs).imag()/1e-100; + double p_calc_MPa = rho_molm3*R*T_K*(1.0 + Ar01)/1e6; + + double pbin_MPa; + { + auto bin = GERG2008::GERG2008ResidualModel({components[i], components[j]}); + std::vector molefracs = {0.5, 0.5}; + double Ar01 = rho_molm3*bin.alphar(T_K, rhocomplex, molefracs).imag()/1e-100; + pbin_MPa = rho_molm3*R*T_K*(1.0 + Ar01)/1e6; + } + + CAPTURE(i); + CAPTURE(j); + CAPTURE(components[i]); + CAPTURE(components[j]); + + double rho_moldm3 = rho_molm3/1000; + double pGERG2008_AGA8 = -1, ZZ = -1; + std::vector molefracsGERG = molefracs; + molefracsGERG.insert(molefracsGERG.begin(), 0.0); // This array uses 1-based indexing, so insert a placeholder + PressureGERG(T_K, rho_moldm3, molefracsGERG, pGERG2008_AGA8, ZZ); + double pGERG2008_AGA8_MPa = pGERG2008_AGA8/1000.0; + CHECK(pGERG2008_AGA8_MPa == Approx(p_calc_MPa).margin(1e-120)); + CHECK(pGERG2008_AGA8_MPa == Approx(pbin_MPa).margin(1e-120)); + + } + } +} + +TEST_CASE("Validate all GERG2008 models", "[GERG2008]"){ + + // In the component order of the AGA8 test code + static std::vector components = {"methane","nitrogen","carbondioxide","ethane","propane","isobutane","n-butane","isopentane","n-pentane","n-hexane","n-heptane","n-octane","n-nonane","n-decane","hydrogen","oxygen","carbonmonoxide","water","hydrogensulfide","helium","argon"}; + + CHECK_NOTHROW(GERG2008::GERG2008ResidualModel(components)); + auto model = GERG2008::GERG2008ResidualModel(components); + + SetupGERG(); + for (auto i = 0; i < validation_data.size(); ++i){ + double p_given_MPa = validation_data[i].P_MPa; + + double rho = validation_data[i].D_molL*1e3; + double T = validation_data[i].T_K; + double R = 8.314472; + + auto ptr = mixture_comps[validation_data[i].GasNo-2]; + Eigen::ArrayXd molefracs = Eigen::Map(&(ptr[0]), ptr.size())/100.0; + + auto rhocomplex = std::complex(rho, 1e-100); + double alphar = model.alphar(T, rho, molefracs); + + double pGERG2008_AGA8 = -1, ZZ = -1; + REQUIRE(ptr.size() == 21); + std::vector x = ptr; + x.insert(x.begin(), 0.0); + for (auto k = 0; k < x.size(); ++k){ + x[k] /= 100.0; + } + PressureGERG(T, rho/1e3, x, pGERG2008_AGA8, ZZ); + double pGERG2008_AGA8_MPa = pGERG2008_AGA8/1000.0; + + double Tr = model.red.get_Tr(molefracs); + double rhor = model.red.get_rhor(molefracs); + + CAPTURE(i); + CAPTURE(validation_data[i].GasNo); + CAPTURE(molefracs); + CAPTURE(Tr); + CAPTURE(rhor); + CAPTURE(T); + CAPTURE(rho); + CAPTURE(pGERG2008_AGA8); + CAPTURE(validation_data[i].GasNo-2); + CHECK(std::isfinite(alphar)); + double Ar01 = rho*model.alphar(T, rhocomplex, molefracs).imag()/1e-100; + double p_calc_MPa = rho*R*T*(1.0 + Ar01)/1e6; + CHECK(pGERG2008_AGA8_MPa == Approx(p_calc_MPa)); + } +} From 93328ca5f26e55a60cffc04a680abe2b21f08d3e Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Tue, 12 Dec 2023 10:46:15 -0500 Subject: [PATCH 6/9] Expose GERG-200X to python --- include/teqp/models/GERG/GERG.hpp | 29 +++++++++++++----- include/teqp/models/fwd.hpp | 1 + interface/pybind11_wrapper.cpp | 34 +++++++++++++++++++++ src/bench_AbstractModel.cpp | 50 +++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 8 deletions(-) diff --git a/include/teqp/models/GERG/GERG.hpp b/include/teqp/models/GERG/GERG.hpp index f1a3f965..6c025f68 100644 --- a/include/teqp/models/GERG/GERG.hpp +++ b/include/teqp/models/GERG/GERG.hpp @@ -130,6 +130,9 @@ class GERG200XReducing{ public: GERG200XReducing(const std::vector& names, const GetPureInfo &get_pure_info, const GetBetasGammas& get_betasgammas): _get_pure_info(get_pure_info), _get_betasgammas(get_betasgammas), m_Tcvc(get_Tcvc(names)), matrices(get_matrices(names)) {} + auto get_Tcvec() const { return m_Tcvc.Tc_K; } + auto get_vcvec() const { return m_Tcvc.vc_m3mol; } + template auto Y(const MoleFractions& z, const std::vector& Yc, const Eigen::ArrayXXd& beta, const Eigen::ArrayXXd& Yij) const { using resulttype = std::common_type_t; @@ -304,7 +307,7 @@ using namespace GERGGeneral; const std::vector component_names = {"methane", "nitrogen","carbondioxide","ethane","propane","n-butane","isobutane","n-pentane","isopentane","n-hexane","n-heptane","n-octane","hydrogen", "oxygen","carbonmonoxide","water","helium","argon"}; /// Get the pure fluid information for a fluid from GERG-2004 monograph -PureInfo get_pure_info(const std::string& name){ +inline PureInfo get_pure_info(const std::string& name){ // From Table A3.5 from GERG 2004 monograph // Data in table are in mol/dm3, K, kg/mol, so some conversion is needed @@ -336,7 +339,7 @@ PureInfo get_pure_info(const std::string& name){ -PureCoeffs get_pure_coeffs(const std::string& fluid){ +inline PureCoeffs get_pure_coeffs(const std::string& fluid){ // From Table A3.2 from GERG 2004 monograph static std::map> n_dict_mne = { @@ -420,7 +423,7 @@ PureCoeffs get_pure_coeffs(const std::string& fluid){ -BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2){ +inline BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2){ // From Table A3.8 of GERG 2004 monograph std::map,BetasGammas> BIP_data = { @@ -598,7 +601,7 @@ BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2) } } -std::optional get_Fij(const std::string& fluid1, const std::string& fluid2, bool ok_missing=true){ +inline std::optional get_Fij(const std::string& fluid1, const std::string& fluid2, bool ok_missing=true){ /// Table A3.6 from GERG 2004 monograph static std::map, double> Fij_dict = { @@ -639,7 +642,7 @@ std::optional get_Fij(const std::string& fluid1, const std::string& flui } -DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string &fluid2){ +inline DepartureCoeffs get_departurecoeffs(const std::string&fluid1, const std::string &fluid2){ std::pair sortedpair = std::minmax(fluid1, fluid2); auto sortpair = [](const std::string &n1, const std::string& n2) ->std::pair { return std::minmax(n1, n2); }; @@ -743,6 +746,11 @@ class GERG2004ResidualModel{ const GERG200XDepartureTerm dep; GERG2004ResidualModel(const std::vector& names) : red(names, get_pure_info, get_betasgammas), corr(names, get_pure_coeffs), dep(names, get_Fij, get_departurecoeffs){} + template + auto R(const VecType& /*molefrac*/) const { + return 8.314472; + } + template auto alphar(const TType &T, const RhoType &rho, @@ -769,7 +777,7 @@ using namespace GERGGeneral; const std::vector component_names = {"methane", "nitrogen","carbondioxide","ethane","propane","n-butane","isobutane","n-pentane","isopentane","n-hexane","n-heptane","n-octane","hydrogen", "oxygen","carbonmonoxide","water","helium","argon","hydrogensulfide","n-nonane","n-decane"}; -auto get_pure_info(const std::string& name){ +inline auto get_pure_info(const std::string& name){ // From Table A3.5 from GERG 2004 monograph // Data are in mol/dm3, K, kg/mol // All others are unchanged @@ -797,7 +805,7 @@ auto get_pure_info(const std::string& name){ using GERG2004::get_Fij; using GERG2004::get_departurecoeffs; -BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2){ +inline BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2){ // From Table A8 of GERG-2008 manuscript. Pairs that are unchanged // from GERG-2004 are left out and are looked up from the GERG-2004 @@ -900,7 +908,7 @@ BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2) } } -PureCoeffs get_pure_coeffs(const std::string& fluid){ +inline PureCoeffs get_pure_coeffs(const std::string& fluid){ static std::map> n_dict_main = { @@ -936,6 +944,11 @@ class GERG2008ResidualModel{ GERG200XDepartureTerm dep; GERG2008ResidualModel(const std::vector& names) : red(names, get_pure_info, get_betasgammas), corr(names, get_pure_coeffs), dep(names, get_Fij, get_departurecoeffs){} + template + auto R(const VecType& /*molefrac*/) const { + return 8.314472; + } + template auto alphar(const TType &T, const RhoType &rho, diff --git a/include/teqp/models/fwd.hpp b/include/teqp/models/fwd.hpp index c98897d2..b2b5119f 100644 --- a/include/teqp/models/fwd.hpp +++ b/include/teqp/models/fwd.hpp @@ -26,6 +26,7 @@ #include "teqp/models/model_potentials/2center_ljf.hpp" #include "teqp/models/mie/lennardjones.hpp" #include "teqp/models/mie/mie.hpp" +#include "teqp/models/GERG/GERG.hpp" namespace teqp { diff --git a/interface/pybind11_wrapper.cpp b/interface/pybind11_wrapper.cpp index c78c80fc..c688f68f 100644 --- a/interface/pybind11_wrapper.cpp +++ b/interface/pybind11_wrapper.cpp @@ -95,6 +95,18 @@ void attach_multifluid_methods(py::object&obj){ setattr("set_meta", MethodType(py::cpp_function([](py::object& o, const std::string& s){ return get_mutable_typed(o).set_meta(s); }, "self"_a, "s"_a), obj)); setattr("get_alpharij", MethodType(py::cpp_function([](py::object& o, const int i, const int j, const double tau, const double delta){ return get_typed(o).dep.get_alpharij(i,j,tau,delta); }, "self"_a, "i"_a, "j"_a, "tau"_a, "delta"_a), obj)); } +template +void attach_GERG_methods(py::object&obj){ + auto setattr = py::getattr(obj, "__setattr__"); + auto MethodType = py::module_::import("types").attr("MethodType"); + setattr("get_Tcvec", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).red.get_Tcvec(); }), obj)); + setattr("get_vcvec", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).red.get_vcvec(); }), obj)); + setattr("get_Tr", MethodType(py::cpp_function([](py::object& o, REArrayd& molefrac){ return get_typed(o).red.get_Tr(molefrac); }, "self"_a, "molefrac"_a.noconvert()), obj)); + setattr("get_rhor", MethodType(py::cpp_function([](py::object& o, REArrayd& molefrac){ return get_typed(o).red.get_rhor(molefrac); }, "self"_a, "molefrac"_a.noconvert()), obj)); +// setattr("get_meta", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).get_meta(); }), obj)); +// setattr("set_meta", MethodType(py::cpp_function([](py::object& o, const std::string& s){ return get_mutable_typed(o).set_meta(s); }, "self"_a, "s"_a), obj)); +// setattr("get_alpharij", MethodType(py::cpp_function([](py::object& o, const int i, const int j, const double tau, const double delta){ return get_typed(o).dep.get_alpharij(i,j,tau,delta); }, "self"_a, "i"_a, "j"_a, "tau"_a, "delta"_a), obj)); +} // Type index variables matching the model types, used for runtime attachment of model-specific methods const std::type_index vdWEOS1_i{std::type_index(typeid(vdWEOS1))}; @@ -111,6 +123,8 @@ const std::type_index twocenterLJF_i{std::type_index(typeid(twocenterLJF_t))}; const std::type_index QuantumPR_i{std::type_index(typeid(QuantumPR_t))}; const std::type_index advancedPRaEres_i{std::type_index(typeid(advancedPRaEres_t))}; const std::type_index RKPRCismondi2005_i{std::type_index(typeid(RKPRCismondi2005_t))}; +const std::type_index GERG2004ResidualModel_i{std::type_index(typeid(GERG2004::GERG2004ResidualModel))}; +const std::type_index GERG2008ResidualModel_i{std::type_index(typeid(GERG2008::GERG2008ResidualModel))}; /** At runtime we can add additional model-specific methods that only apply for a particular model. We take in a Python-wrapped @@ -155,10 +169,24 @@ void attach_model_specific_methods(py::object& obj){ setattr("get_epsilon_over_k_K", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).get_epsilon_over_k_K(); }), obj)); setattr("get_lambda_r", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).get_lambda_r(); }), obj)); setattr("get_lambda_a", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).get_lambda_a(); }), obj)); + // setattr("max_rhoN", MethodType(py::cpp_function([](py::object& o, double T, REArrayd& molefrac){ return get_typed(o).max_rhoN(T, molefrac); }, "self"_a, "T"_a, "molefrac"_a), obj)); setattr("get_kmat", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).get_kmat(); }), obj)); setattr("has_polar", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).has_polar(); }), obj)); setattr("get_core_calcs", MethodType(py::cpp_function([](py::object& o, double T, double rhomolar, REArrayd& molefrac){ return get_typed(o).get_core_calcs(T, rhomolar, molefrac); }, "self"_a, "T"_a, "rhomolar"_a, "molefrac"_a), obj)); + setattr("get_Eprime", MethodType(py::cpp_function([](py::object& o, double T, double rhoN, double rhostar, REArrayd& molefrac, REArrayd& muprime){ + auto m = get_typed(o); + using namespace teqp::SAFTpolar; + auto multipol = std::get>(m.get_polar().value()); + return multipol.get_Eprime(T, rhoN, rhostar, molefrac, muprime); + }, "self"_a, "T"_a, "rhoN"_a, "rhostar"_a, "molefrac"_a, "muprime"_a), obj)); + setattr("iterate_muprime_SS", MethodType(py::cpp_function([](py::object& o, double T, double rhoN, double rhostar, REArrayd& molefrac, REArrayd& muprime, int Niter){ + auto m = get_typed(o); + using namespace teqp::SAFTpolar; + auto multipol = std::get>(m.get_polar().value()); + return multipol.iterate_muprime_SS(T, rhoN, rhostar, molefrac, muprime, Niter); + }, "self"_a, "T"_a, "rhoN"_a, "rhostar"_a, "molefrac"_a, "muprime"_a, "Niter"_a), obj)); + } else if (index == canonical_cubic_i){ setattr("get_a", MethodType(py::cpp_function([](py::object& o, double T, REArrayd& molefrac){ return get_typed(o).get_a(T, molefrac); }, "self"_a, "T"_a, "molefrac"_a), obj)); @@ -230,6 +258,12 @@ void attach_model_specific_methods(py::object& obj){ return teqp::MultiFluidVLEAncillaries(jancillaries); }, "self"_a, py::arg_v("i", std::nullopt, "None")), obj)); } + else if (index == GERG2004ResidualModel_i){ + attach_GERG_methods(obj); + } + else if (index == GERG2008ResidualModel_i){ + attach_GERG_methods(obj); + } else if (index == idealgas_i){ // Here X-Macros are used to create functions like get_Aig00, get_Aig01, .... #define X(i,j) setattr(stringify(get_Aig ## i ## j), MethodType(py::cpp_function([](py::object& o, double T, double rho, REArrayd& molefrac){ \ diff --git a/src/bench_AbstractModel.cpp b/src/bench_AbstractModel.cpp index d9f259d0..b2201a1c 100644 --- a/src/bench_AbstractModel.cpp +++ b/src/bench_AbstractModel.cpp @@ -25,6 +25,9 @@ TEST_CASE("multifluid derivatives", "[mf]") auto z = (Eigen::ArrayXd(1) << 1.0).finished(); auto rhovec = 300.0* z; + BENCHMARK("construction"){ + return teqp::cppinterface::make_model(j); + }; BENCHMARK("alphar") { return am->get_Arxy(0, 0, 300, 3.0, z); }; @@ -84,3 +87,50 @@ TEST_CASE("multifluid derivatives via DerivativeAdapter", "[mf]") return view(model)->get_Bnvir(4, 300, z); }; } + +TEST_CASE("GERG2008 derivatives", "[GERG2008]") +{ + nlohmann::json j = { + {"kind", "GERG2008resid"}, + {"model", { + {"names", {"methane"}}, + } + }}; + //std::cout << j.dump(2); + + + auto z = (Eigen::ArrayXd(1) << 1.0).finished(); + auto rhovec = 300.0* z; + auto am = teqp::cppinterface::make_model(j); + + BENCHMARK("construction"){ + return teqp::cppinterface::make_model(j); + }; + BENCHMARK("alphar") { + return am->get_Arxy(0, 0, 300, 3.0, z); + }; + BENCHMARK("Ar20") { + return am->get_Ar20(300, 3.0, z); + }; + BENCHMARK("get_Ar02n") { + return am->get_Ar02n(300, 3.0, z); + }; + BENCHMARK("fugacity coefficients") { + return am->get_fugacity_coefficients(300.0, rhovec); + }; + BENCHMARK("cvr/R") { + return -1*am->get_Arxy(2, 0, 300, 3.0, z); + }; + BENCHMARK("partial_molar_volumes") { + return am->get_partial_molar_volumes(300.0, rhovec); + }; + BENCHMARK("get_deriv_mat2") { + return am->get_deriv_mat2(300.0, 3.0, z); + }; + BENCHMARK("build_iteration_Jv") { + auto mat = am->get_deriv_mat2(300.0, 3.0, z); + auto mat2 = am->get_deriv_mat2(300.0, 3.0, z); + const std::vector vars = {'T','D','P','S'}; + return teqp::cppinterface::build_iteration_Jv(vars, mat, mat2, 8.3144, 300.0, 300.0, z); + }; +} From 5ccc8b0eaa77a865611b7c157279395293e3495b Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Tue, 12 Dec 2023 11:49:24 -0500 Subject: [PATCH 7/9] Really expose to python Some additional speed optimizations with map lookup. Wonder if the seeming speedup is due to processor caching --- include/teqp/models/GERG/GERG.hpp | 102 +++++++++++++--------------- interface/CPP/teqp_impl_factory.cpp | 3 + src/bench_AbstractModel.cpp | 17 ++++- 3 files changed, 65 insertions(+), 57 deletions(-) diff --git a/include/teqp/models/GERG/GERG.hpp b/include/teqp/models/GERG/GERG.hpp index 6c025f68..a8236585 100644 --- a/include/teqp/models/GERG/GERG.hpp +++ b/include/teqp/models/GERG/GERG.hpp @@ -12,6 +12,7 @@ #include "teqp/math/pow_templates.hpp" #include "teqp/types.hpp" #include "Eigen/Dense" +#include namespace teqp{ @@ -331,6 +332,9 @@ inline PureInfo get_pure_info(const std::string& name){ {"helium", {17.399000000,5.195300000,4.002602}}, {"argon", {13.407429659,150.687,39.948000}} }; + if (data_map.find(name) == data_map.end()){ + throw std::invalid_argument("Unable to load pure info for"+name); + } auto data = data_map.at(name); data.rhoc_molm3 *= 1000; // mol/dm^3 -> mol/m^3 data.M_kgmol /= 1000; // kg/kmol -> kg/mol @@ -426,7 +430,7 @@ inline PureCoeffs get_pure_coeffs(const std::string& fluid){ inline BetasGammas get_betasgammas(const std::string&fluid1, const std::string &fluid2){ // From Table A3.8 of GERG 2004 monograph - std::map,BetasGammas> BIP_data = { + static std::unordered_map,BetasGammas, boost::hash>> BIP_data = { {{"methane","nitrogen"}, {0.998721377,1.013950311,0.998098830,0.979273013}}, {{"methane","carbondioxide"}, {0.999518072,1.002806594,1.022624490,0.975665369}}, {{"methane","ethane"}, {0.997547866,1.006617867,0.996336508,1.049707697}}, @@ -581,24 +585,19 @@ inline BetasGammas get_betasgammas(const std::string&fluid1, const std::string & {{"water","argon"}, {1.000000000,1.038993495,1.000000000,1.070941866}}, {{"helium","argon"}, {1.00000000,1.00000000,1.00000000,1.00000000}} }; - - try{ - // Try in the given order - return BIP_data.at(std::make_pair(fluid1, fluid2)); - } - catch(...){ - // Try the other order - try{ - auto bg = BIP_data.at(std::make_pair(fluid2, fluid1)); - // Because the order is backwards, need to take the reciprocals of the beta values - bg.betaT = 1/bg.betaT; - bg.betaV = 1/bg.betaV; - return bg; - } - catch(...){ - throw std::invalid_argument("Unable to obtain BIP for the pair {" + fluid1 + "," + fluid2 + "}"); - } - } + auto pair_normal = std::make_pair(fluid1, fluid2); + if (BIP_data.find(pair_normal) != BIP_data.end()){ + return BIP_data[pair_normal]; + } + auto pair_backwards = std::make_pair(fluid2, fluid1); + if (BIP_data.find(pair_backwards) != BIP_data.end()){ + auto bg = BIP_data.at(pair_backwards); + // Because the order is backwards, need to take the reciprocals of the beta values + bg.betaT = 1/bg.betaT; + bg.betaV = 1/bg.betaV; + return bg; + } + throw std::invalid_argument("Unable to obtain BIP for the pair {" + fluid1 + "," + fluid2 + "}"); } inline std::optional get_Fij(const std::string& fluid1, const std::string& fluid2, bool ok_missing=true){ @@ -621,23 +620,19 @@ inline std::optional get_Fij(const std::string& fluid1, const std::strin {{"propane","isobutane"}, -0.551609771024e-1}, {{"n-butane","isobutane"}, -0.551240293009e-1} }; - try{ - // Try in the given order - return Fij_dict.at(std::make_pair(fluid1, fluid2)); - } - catch(...){ - // Try the other order - try{ - return Fij_dict.at(std::make_pair(fluid2, fluid1)); - } - catch(...){ - if (ok_missing){ - return std::nullopt; - } - else{ - throw std::invalid_argument("Unable to obtain Fij for the pair {" + fluid1 + "," + fluid2 + "}"); - } - } + auto pair_normal = std::make_pair(fluid1, fluid2); + if (Fij_dict.find(pair_normal) != Fij_dict.end()){ + return Fij_dict[pair_normal]; + } + auto pair_backwards = std::make_pair(fluid2, fluid1); + if (Fij_dict.find(pair_backwards) != Fij_dict.end()){ + return Fij_dict[pair_backwards]; + } + if (ok_missing){ + return std::nullopt; + } + else{ + throw std::invalid_argument("Unable to obtain Fij for the pair {" + fluid1 + "," + fluid2 + "}"); } } @@ -810,7 +805,7 @@ inline BetasGammas get_betasgammas(const std::string&fluid1, const std::string & // From Table A8 of GERG-2008 manuscript. Pairs that are unchanged // from GERG-2004 are left out and are looked up from the GERG-2004 // coefficients. - std::map,BetasGammas> BIP_data = { + static std::unordered_map,BetasGammas, boost::hash>> BIP_data = { // This set has different values than in GERG-2004. The change // occurs because the EOS has changed for isopentane and CO and @@ -887,25 +882,20 @@ inline BetasGammas get_betasgammas(const std::string&fluid1, const std::string & {{"hydrogensulfide","helium"}, {1.0, 1.0, 1.0, 1.0}}, {{"hydrogensulfide","argon"}, {1.0, 1.0, 1.0, 1.0}}, }; - - try{ - // Try in the given order - return BIP_data.at(std::make_pair(fluid1, fluid2)); - } - catch(...){ - // Try the other order - try{ - auto bg = BIP_data.at(std::make_pair(fluid2, fluid1)); - // Because the order is backwards, need to take the reciprocals of the beta values - bg.betaT = 1/bg.betaT; - bg.betaV = 1/bg.betaV; - return bg; - } - catch(...){ - // Fall back to looking up from GERG-2004 - return GERG2004::get_betasgammas(fluid1, fluid2); - } - } + auto pair_normal = std::make_pair(fluid1, fluid2); + if (BIP_data.find(pair_normal) != BIP_data.end()){ + return BIP_data[pair_normal]; + } + auto pair_backwards = std::make_pair(fluid2, fluid1); + if (BIP_data.find(pair_backwards) != BIP_data.end()){ + auto bg = BIP_data.at(pair_backwards); + // Because the order is backwards, need to take the reciprocals of the beta values + bg.betaT = 1/bg.betaT; + bg.betaV = 1/bg.betaV; + return bg; + } + // Fall back to looking up from GERG-2004 + return GERG2004::get_betasgammas(fluid1, fluid2); } inline PureCoeffs get_pure_coeffs(const std::string& fluid){ diff --git a/interface/CPP/teqp_impl_factory.cpp b/interface/CPP/teqp_impl_factory.cpp index 7c001acf..5a0462cb 100644 --- a/interface/CPP/teqp_impl_factory.cpp +++ b/interface/CPP/teqp_impl_factory.cpp @@ -42,6 +42,9 @@ namespace teqp { {"2CLJF-Quadrupole", [](const nlohmann::json& spec){ return make_owned(twocenterljf::build_two_center_model_quadrupole(spec.at("author"), spec.at("L^*"), spec.at("(Q^*)^2")));}}, {"IdealHelmholtz", [](const nlohmann::json& spec){ return make_owned(IdealHelmholtz(spec));}}, + {"GERG2004resid", [](const nlohmann::json& spec){ return make_owned(GERG2004::GERG2004ResidualModel(spec.at("names")));}}, + {"GERG2008resid", [](const nlohmann::json& spec){ return make_owned(GERG2008::GERG2008ResidualModel(spec.at("names")));}}, + // Implemented in its own compilation unit to help with compilation time {"SAFT-VR-Mie", [](const nlohmann::json& spec){ return make_SAFTVRMie(spec); }} }; diff --git a/src/bench_AbstractModel.cpp b/src/bench_AbstractModel.cpp index b2201a1c..b3a2a812 100644 --- a/src/bench_AbstractModel.cpp +++ b/src/bench_AbstractModel.cpp @@ -6,9 +6,23 @@ #include "teqp/derivs.hpp" #include "teqp/cpp/deriv_adapter.hpp" #include "teqp/models/multifluid.hpp" +#include "teqp/models/GERG/GERG.hpp" using namespace teqp; +TEST_CASE("GERG2008 parts", "[GERG2008]") +{ + BENCHMARK("bg"){ + return GERG2008::get_betasgammas("methane","n-decane"); + }; + BENCHMARK("bg backwards"){ + return GERG2008::get_betasgammas("n-decane", "methane"); + }; + BENCHMARK("bg fallback to 2004"){ + return GERG2008::get_betasgammas("ethane", "methane"); + }; +} + TEST_CASE("multifluid derivatives", "[mf]") { nlohmann::json j = { @@ -88,12 +102,13 @@ TEST_CASE("multifluid derivatives via DerivativeAdapter", "[mf]") }; } + TEST_CASE("GERG2008 derivatives", "[GERG2008]") { nlohmann::json j = { {"kind", "GERG2008resid"}, {"model", { - {"names", {"methane"}}, + {"names", {"methane","ethane","propane","n-butane"}}, } }}; //std::cout << j.dump(2); From 76e805e807eec74855165a3d7f938980bed7fd76 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Tue, 12 Dec 2023 11:52:27 -0500 Subject: [PATCH 8/9] Didn't intend to expose those functions (yet) --- interface/pybind11_wrapper.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/interface/pybind11_wrapper.cpp b/interface/pybind11_wrapper.cpp index c688f68f..aebb25cd 100644 --- a/interface/pybind11_wrapper.cpp +++ b/interface/pybind11_wrapper.cpp @@ -174,18 +174,6 @@ void attach_model_specific_methods(py::object& obj){ setattr("get_kmat", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).get_kmat(); }), obj)); setattr("has_polar", MethodType(py::cpp_function([](py::object& o){ return get_typed(o).has_polar(); }), obj)); setattr("get_core_calcs", MethodType(py::cpp_function([](py::object& o, double T, double rhomolar, REArrayd& molefrac){ return get_typed(o).get_core_calcs(T, rhomolar, molefrac); }, "self"_a, "T"_a, "rhomolar"_a, "molefrac"_a), obj)); - setattr("get_Eprime", MethodType(py::cpp_function([](py::object& o, double T, double rhoN, double rhostar, REArrayd& molefrac, REArrayd& muprime){ - auto m = get_typed(o); - using namespace teqp::SAFTpolar; - auto multipol = std::get>(m.get_polar().value()); - return multipol.get_Eprime(T, rhoN, rhostar, molefrac, muprime); - }, "self"_a, "T"_a, "rhoN"_a, "rhostar"_a, "molefrac"_a, "muprime"_a), obj)); - setattr("iterate_muprime_SS", MethodType(py::cpp_function([](py::object& o, double T, double rhoN, double rhostar, REArrayd& molefrac, REArrayd& muprime, int Niter){ - auto m = get_typed(o); - using namespace teqp::SAFTpolar; - auto multipol = std::get>(m.get_polar().value()); - return multipol.iterate_muprime_SS(T, rhoN, rhostar, molefrac, muprime, Niter); - }, "self"_a, "T"_a, "rhoN"_a, "rhostar"_a, "molefrac"_a, "muprime"_a, "Niter"_a), obj)); } else if (index == canonical_cubic_i){ From d7d4f199caeb8f492aee4ce1fa772ec510466974 Mon Sep 17 00:00:00 2001 From: Ian Bell Date: Tue, 12 Dec 2023 11:54:38 -0500 Subject: [PATCH 9/9] Another mistaken commit --- src/tests/catch_test_multifluid.cxx | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/tests/catch_test_multifluid.cxx b/src/tests/catch_test_multifluid.cxx index 66c4785c..c335b3cc 100644 --- a/src/tests/catch_test_multifluid.cxx +++ b/src/tests/catch_test_multifluid.cxx @@ -14,11 +14,6 @@ using Catch::Approx; #include "teqp/cpp/deriv_adapter.hpp" #include "teqp/filesystem.hpp" #include "teqp/ideal_eosterms.hpp" -#include "teqp/math/finite_derivs.hpp" - -// Imports from boost -#include -using namespace boost::multiprecision; using namespace teqp; using multifluid_t = decltype(build_multifluid_model({""}, "")); @@ -515,23 +510,3 @@ TEST_CASE("Check models for R", "[multifluidR]") { CHECK(model_->get_R(z) == 8.31446261815324); } } - -TEST_CASE("Ar20 for CO2", "[Ar20CO2]"){ - double rho = 11000; - auto z = (Eigen::ArrayXd(1) << 1.0).finished(); - - using my_float = boost::multiprecision::number>; // Overkill: 200 digits of working precision! - auto model = build_multifluid_model({"CO2"}, "../mycp"); - - auto f = [&rho, &z, &model](const auto Trecip){ return model.alphar(1.0/Trecip, rho, z); }; - using tdx = TDXDerivatives; - - std::cout << std::setprecision(20); - for (double T = 304.2; T < 340; T += 0.05){ - my_float Trecip = 1.0/T; - my_float h = 1e-20; - auto mp = -teqp::centered_diff<2,6>(f, Trecip, h)*Trecip*Trecip; // cvr/R - auto ad = -tdx::get_Ar20(model, T, rho, z); - std::cout << T << "," << mp << "," << mp/ad-1 << std::endl; - } -}