From db142e633b87e960119a620873dbf9eb91fd291b Mon Sep 17 00:00:00 2001 From: AJSchiller <53826388+AJSchiller@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:06:55 +0200 Subject: [PATCH 01/58] Add SH to `properties.ion_to_mass`. --- pytzer/properties.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pytzer/properties.py b/pytzer/properties.py index ad9fb8f0..b39d3bfb 100644 --- a/pytzer/properties.py +++ b/pytzer/properties.py @@ -188,6 +188,7 @@ "NO3": 62.00490, "OH": 17.00734, "HSO4": 97.07054, + "HS": 33.08, "SO4": 96.06260, "HCO3": 61.01684, "CO3": 60.00890, From 51e0d2df7fc4d52636114e69bfd992bbafa4e74c Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Fri, 15 Oct 2021 14:11:51 +0200 Subject: [PATCH 02/58] Update docstring --- pytzer/equilibrate/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pytzer/equilibrate/__init__.py b/pytzer/equilibrate/__init__.py index 4ba52c2b..a8b2f526 100644 --- a/pytzer/equilibrate/__init__.py +++ b/pytzer/equilibrate/__init__.py @@ -43,8 +43,8 @@ def solve( temperature=298.15, verbose=False, ): - """Solve for thermodynamic equilibrium to return solute molalities and stoichiometric - equilibrium constants. + """Solve for thermodynamic equilibrium to return solute molalities and + stoichiometric equilibrium constants. """ # Make first estimates of all stoichiometric dissociation constants ks_constants_pz = dissociation.assemble( From 9792eafacfab511fbd7493607b923fb91f25ee06 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Wed, 20 Oct 2021 16:44:50 +0200 Subject: [PATCH 03/58] Towards validation --- pytzer/model.py | 15 ++++++ tests/data/pytzerQuickStart_py_v0_4_3.csv | 28 ++++++++++ .../data/pytzerQuickStart_py_v0_4_3__GM89.csv | 28 ++++++++++ tests/test_jaxscan.py | 53 +++++++++++++++++++ tests/test_v0_4_3.py | 32 +++++++++++ 5 files changed, 156 insertions(+) create mode 100644 tests/data/pytzerQuickStart_py_v0_4_3.csv create mode 100644 tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv create mode 100644 tests/test_jaxscan.py create mode 100644 tests/test_v0_4_3.py diff --git a/pytzer/model.py b/pytzer/model.py index 4b58e456..171d1aba 100644 --- a/pytzer/model.py +++ b/pytzer/model.py @@ -62,6 +62,21 @@ def ionic_z(molalities, charges): func_J = unsymmetrical.Harvie +@jax.jit +def Gibbs_nRT_fori(solutes, params): + # Evaluate terms dependent on overall ionic strength + I = ( + np.sum( + np.array([m * convert.solute_to_charge[s] ** 2 for s, m in solutes.items()]) + ) + / 2 + ) + Z = np.sum( + np.abs(np.array([m * convert.solute_to_charge[s] for s, m in solutes.items()])) + ) + sqrt_I = np.sqrt(I) + Gibbs = Gibbs_DH(params["Aphi"], I) + @jax.jit def Gibbs_nRT( solutes, diff --git a/tests/data/pytzerQuickStart_py_v0_4_3.csv b/tests/data/pytzerQuickStart_py_v0_4_3.csv new file mode 100644 index 00000000..91013f28 --- /dev/null +++ b/tests/data/pytzerQuickStart_py_v0_4_3.csv @@ -0,0 +1,28 @@ +tempK,pres,H,Na,Mg,Ca,K,MgOH,trisH,Cl,SO4,HSO4,OH,tris,osm,aw,gH,gNa,gMg,gCa,gK,gMgOH,gtrisH,gCl,gSO4,gHSO4,gOH,gtris +2.731499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.270651165535649163e+00,7.917687092281933126e-01,1.986900846348706562e+00,7.596126256208743932e-01,3.921451299821462899e-01,1.736326442962471961e-01,8.365271327656608191e-01,3.188864987613973523e-01,3.089483220459226520e-01,1.239920021462926902e+00,3.305120155151135969e-02,1.424828301056913027e+01,3.109452700972893946e-01,1.000000000000000000e+00 +2.781499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.277479955771146258e+00,7.907758124651669274e-01,1.911575656894108022e+00,7.555989031374172882e-01,3.875989455842740461e-01,1.839747409152557300e-01,8.938974743786546329e-01,3.162499744149512848e-01,3.063939656337459905e-01,1.256641199554693111e+00,3.286018609176129951e-02,1.463440320477755385e+01,3.177629818327650235e-01,1.000000000000000000e+00 +2.831499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.282751178598207531e+00,7.900102354643958602e-01,1.838689969439061267e+00,7.509202644001256033e-01,3.807159280834045423e-01,1.849904391373967949e-01,9.508530981886873512e-01,3.135802867847282127e-01,3.038074794797451239e-01,1.263968791439409323e+00,3.250006137201097434e-02,1.515130452211254308e+01,3.247630561516453573e-01,1.000000000000000000e+00 +2.881499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.286963589581041845e+00,7.893989700524186581e-01,1.768058002083337854e+00,7.455205702833996861e-01,3.718027117627663580e-01,1.821808790829727853e-01,1.007197348046920737e+00,3.108360064229080399e-01,3.011487252951024485e-01,1.265745428341789047e+00,3.198532477330902346e-02,1.580990408755105214e+01,3.312963568243175172e-01,1.000000000000000000e+00 +2.931499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.290307235291805910e+00,7.889141083992003978e-01,1.699619608133386528e+00,7.394317797774971890e-01,3.611676629976013353e-01,1.775515420098804087e-01,1.062777359987671089e+00,3.079960063676356885e-01,2.983972345449617536e-01,1.263487894495997521e+00,3.133214260557735248e-02,1.662568018996233477e+01,3.369333633624798652e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.292888688580800416e+00,7.885399759023913324e-01,1.633359451976793331e+00,7.327250319582517823e-01,3.491117542601997470e-01,1.719813047844447607e-01,1.117465247091178338e+00,3.050477394674859233e-01,2.955408511129798410e-01,1.257994267642398523e+00,3.055762635809584904e-02,1.761886188906396811e+01,3.413889699758317353e-01,1.000000000000000000e+00 +3.031499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.294785096546285708e+00,7.882652407335171141e-01,1.569280885423912864e+00,7.254894786443010224e-01,3.359206783341233682e-01,1.659032919818008156e-01,1.171153837744317361e+00,3.019835633475233538e-01,2.925721708007287258e-01,1.249768013709677161e+00,2.967918934862700392e-02,1.881514936376612468e+01,3.444815621088829216e-01,1.000000000000000000e+00 +3.081499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.296060939404793722e+00,7.880804615283623082e-01,1.507394283962848913e+00,7.178209781721738292e-01,3.218594689192699754e-01,1.595494662301328859e-01,1.223754990369602780e+00,2.987991107475755359e-01,2.894869624547812270e-01,1.239167946839898171e+00,2.871403706460205416e-02,2.024677580297213453e+01,3.461075496564077758e-01,1.000000000000000000e+00 +3.131499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.296774090044934269e+00,7.879771954178967919e-01,1.447710879659009908e+00,7.098155588954849771e-01,3.071693130765590918e-01,1.530525634962173753e-01,1.275198325850684933e+00,2.954923944305531402e-01,2.862833007707838995e-01,1.226472278445068564e+00,2.767877774277826067e-02,2.195392560729232656e+01,3.462238379555496737e-01,1.000000000000000000e+00 +3.181499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.296978245072167191e+00,7.879476357180557056e-01,1.390239234437057325e+00,7.015655603202929358e-01,2.920660759722942812e-01,1.464932653080993075e-01,1.325429925010778387e+00,2.920632422265184713e-01,2.829610189445178614e-01,1.211909830761835671e+00,2.658913470466101395e-02,2.398658242816286901e+01,3.448347584261822751e-01,1.000000000000000000e+00 +3.231499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,1.296723983116087942e+00,7.879844505925435172e-01,1.334983191531409430e+00,6.931573995758490980e-01,2.767400982989949298e-01,1.399237506027251332e-01,1.374410919837756095e+00,2.885129050188177668e-01,2.795213288752401715e-01,1.195676780474124401e+00,2.545974379032903134e-02,2.640692012984681369e+01,3.419817378893591497e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.325272386354586107e-01,9.966457424922744446e-01,8.002421789748257464e-01,7.776755105901680398e-01,3.705514561052524192e-01,3.685055590352138144e-01,7.668750232203559447e-01,9.018767617098231160e-01,7.383821443108892213e-01,7.776755105901680398e-01,3.142543178366834500e-01,7.843212830163399651e-01,7.691560822325580471e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.363158308002696995e-01,9.668272358831682123e-01,8.617434503250347433e-01,6.571916893751158506e-01,2.418274065576971332e-01,2.206471444431880868e-01,5.935216711036866988e-01,1.049571440136835232e+00,4.788057134200547349e-01,6.571916893751158506e-01,8.438257096136696223e-02,6.555504651286744311e-01,5.973246561507280505e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.838264253427924100e-01,9.315601365353554097e-01,1.139827189233774130e+00,6.684380543027761412e-01,3.067111161227217275e-01,2.524215114102060231e-01,5.521442515943266738e-01,9.594461722228686540e-01,3.968394702878727531e-01,6.684380543027761412e-01,5.057248861488232439e-02,6.223887878073266489e-01,5.540517840184483456e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.044505120847031288e+00,8.932394807625034794e-01,1.579673752064217229e+00,7.135054025991576232e-01,4.486996361187824967e-01,3.353581702696908362e-01,5.356849263733566291e-01,8.070361324248296331e-01,3.532030201969094119e-01,7.135054025991576232e-01,3.703832459157098411e-02,6.003218342557061771e-01,5.369807042428165200e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000111e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,8.617902997540748400e-01,9.953532838712774167e-01,6.800514026013662061e-01,6.514783631898126703e-01,2.373632837601243883e-01,2.359663657296998673e-01,6.278308561842269597e-01,7.894969050101438013e-01,5.899317193981068463e-01,7.850596588212667148e-01,1.607382646442801766e-01,1.189039032681080021e+00,6.083285540412896042e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.108784020511432100e+00,9.418358915367924800e-01,7.893824160133536827e-01,5.171146794125383028e-01,1.451244963268614185e-01,1.221681695233233778e-01,3.786125346400965319e-01,5.301674443283694860e-01,2.889660696287453812e-01,1.118729183004812500e+00,7.313170314936970340e-02,1.634464862236418847e+00,2.800816892133365932e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,4.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.531301825450311238e+00,8.474542577733499282e-01,1.425851182646996396e+00,5.872507654290760604e-01,2.963411250659474527e-01,1.899084105611521245e-01,3.062602266537939877e-01,3.543159595885431168e-01,2.190849473386949076e-01,1.991362829271862367e+00,8.428613133431360482e-02,3.004364081651869078e+00,1.866468415079050869e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,6.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.020531350022046091e+00,7.206520509852143430e-01,2.905661756276947116e+00,7.151814505834948044e-01,8.614249434227910784e-01,3.901997547845781344e-01,2.514856234406388502e-01,2.764841735263518507e-01,1.871666093411497589e-01,3.851685742491151920e+00,1.248252019695434284e-01,1.729928078869860997e+01,1.378367889568912763e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.266424530851353758e-01,9.966668744787137157e-01,7.969441238181294018e-01,7.777467093013644694e-01,3.664971982376761250e-01,3.743804464956406175e-01,7.679853227378377056e-01,9.025707184556972518e-01,7.389502987326819206e-01,7.679853227378377056e-01,3.127715548106541621e-01,9.938285248772641411e-01,7.833938899308788839e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,8.988551358284879722e-01,9.681330521877006268e-01,8.192003456367619174e-01,6.561033558730196003e-01,2.157627402710333153e-01,2.505193141322052397e-01,6.046279313626753416e-01,1.058468444766088590e+00,4.828644525262330012e-01,6.046279313626753416e-01,8.291521867991059891e-02,5.388170901761772935e-01,6.836965000448789187e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.135091845339095018e-01,9.362923871627033545e-01,1.001798257241684365e+00,6.577492360584993314e-01,2.352172389246501849e-01,2.951158634071363585e-01,5.741262197158149005e-01,9.705046499035268059e-01,4.014134011159205540e-01,5.741262197158149005e-01,4.974411377092958358e-02,3.955808514980437840e-01,7.021742326345865592e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.373633822565380358e-01,9.036441748309678168e-01,1.249528549227590046e+00,6.838260559383528836e-01,2.859745979179877384e-01,3.674890460932229708e-01,5.701779766360495216e-01,8.151127285369744735e-01,3.567377790820524530e-01,5.701779766360495216e-01,3.622170039964870553e-02,1.234937793565655584e+00,7.454491834211794954e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,1.000000000000000000e+00,9.982001217271316840e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,9.821463000533079413e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,1.000000000000000000e+00,9.646113547084023132e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,1.000000000000000000e+00,9.473894730162663036e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 diff --git a/tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv b/tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv new file mode 100644 index 00000000..5fdc4fdd --- /dev/null +++ b/tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv @@ -0,0 +1,28 @@ +tempK,pres,H,Na,Mg,Ca,K,MgOH,trisH,Cl,SO4,HSO4,OH,tris,osm,aw,gH,gNa,gMg,gCa,gK,gMgOH,gtrisH,gCl,gSO4,gHSO4,gOH,gtris +2.731499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.062372422796003857e-01,8.782945950273439717e-01,2.857331378599501925e-01,4.182016043905244507e-01,5.434159945176756344e-03,1.444179920191257238e-01,3.745542479901715627e-01,2.857331378599501925e-01,2.857331378599501925e-01,5.109166954927724102e-01,1.107284846948461063e-02,2.638977225444948393e-01,2.638977225444948393e-01,1.000000000000000000e+00 +2.781499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.207169875212338095e-01,8.759608256634302537e-01,2.816004399951441139e-01,4.642778626266697017e-01,5.171356160560190360e-03,1.519660046398969844e-01,3.871910769212975612e-01,2.816004399951441139e-01,2.816004399951441139e-01,5.182210093424902686e-01,1.196306404918001144e-02,2.599372422608295929e-01,2.599372422608295929e-01,1.000000000000000000e+00 +2.831499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.269335154126306264e-01,8.749607819499574113e-01,2.773547350542601708e-01,4.923045356081406365e-01,4.909810348243863996e-03,1.516195341367289895e-01,3.984041282880847468e-01,2.773547350542601708e-01,2.773547350542601708e-01,5.214730264428605322e-01,1.233830787010791082e-02,2.558663137424085909e-01,2.558663137424085909e-01,1.000000000000000000e+00 +2.881499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.297910255396373724e-01,8.745014815857097279e-01,2.731305249959270487e-01,5.117783485064506532e-01,4.655176849261500986e-03,1.481981047009016395e-01,4.084349117963301246e-01,2.731305249959270487e-01,2.731305249959270487e-01,5.225683215780814184e-01,1.247060470558513864e-02,2.518107835212509693e-01,2.518107835212509693e-01,1.000000000000000000e+00 +2.931499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.309143861663111030e-01,8.743209848455324451e-01,2.689534824552924364e-01,5.262479065392274835e-01,4.408548551168494506e-03,1.434336583738412829e-01,4.173879217532588948e-01,2.689534824552924364e-01,2.689534824552924364e-01,5.222203534250097201e-01,1.246069697868473596e-02,2.477950802694408039e-01,2.477950802694408039e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.309851978666368488e-01,8.743096083752250891e-01,2.648220792261193890e-01,5.373488000574595524e-01,4.169959105136950353e-03,1.380649601532618620e-01,4.253301226297480642e-01,2.648220792261193890e-01,2.648220792261193890e-01,5.207801142795274174e-01,1.235502722556713201e-02,2.438182706967681745e-01,2.438182706967681745e-01,1.000000000000000000e+00 +3.031499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.303319295524042243e-01,8.744145668110627767e-01,2.607271848132418635e-01,5.459448808439228973e-01,3.939194259419566586e-03,1.324409527385421725e-01,4.323159085254302259e-01,2.607271848132418635e-01,2.607271848132418635e-01,5.184518658987588013e-01,1.217861247742121900e-02,2.398723251388059363e-01,2.398723251388059363e-01,1.000000000000000000e+00 +3.081499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.291276073767847254e-01,8.746080942549333548e-01,2.566580475313561815e-01,5.525391912642051429e-01,3.716020638567173531e-03,1.267370801634971067e-01,4.383950999909317359e-01,2.566580475313561815e-01,2.566580475313561815e-01,5.153690387964847686e-01,1.194673274289369952e-02,2.359476943156209594e-01,2.359476943156209594e-01,1.000000000000000000e+00 +3.131499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.274689853988456356e-01,8.748746951047501330e-01,2.526043376943494234e-01,5.574478584110224011e-01,3.500250973684984092e-03,1.210449646286840819e-01,4.436157705260125317e-01,2.526043376943494234e-01,2.526043376943494234e-01,5.116264652774196175e-01,1.166978219025168600e-02,2.320352156847610980e-01,2.320352156847610980e-01,1.000000000000000000e+00 +3.181499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.254124430803614576e-01,8.752053690718412104e-01,2.485568487382299463e-01,5.608827653209497166e-01,3.291756595491947702e-03,1.154135581083153700e-01,4.480251962695029344e-01,2.485568487382299463e-01,2.485568487382299463e-01,5.072960144160019169e-01,1.135551232284992725e-02,2.281267683102726762e-01,2.281267683102726762e-01,1.000000000000000000e+00 +3.231499999999999773e+02,1.013250000000000028e+01,1.000000000000000000e+00,1.500000000000000000e+00,5.000000000000000000e-01,2.000000000000000111e-01,1.199999999999999956e+00,3.499999999999999778e-01,4.500000000000000111e-01,2.250000000000000000e+00,1.500000000000000000e+00,2.500000000000000000e-01,4.000000000000000222e-01,5.999999999999999778e-01,7.229918126963166269e-01,8.755947453431948135e-01,2.445076930933001991e-01,5.629944591336792925e-01,3.090462067598785927e-03,1.098694524269453743e-01,4.516700541712272421e-01,2.445076930933001991e-01,2.445076930933001991e-01,5.024349590002848975e-01,1.101015222881662411e-02,2.242154562240317450e-01,2.242154562240317450e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.325272386354586107e-01,9.966457424922744446e-01,7.383821443108892213e-01,7.776755105901680398e-01,2.736188927533313997e-01,3.685055590352138144e-01,7.668750232203559447e-01,7.383821443108892213e-01,7.383821443108892213e-01,7.776755105901680398e-01,3.222476300513624214e-01,7.383821443108892213e-01,7.383821443108892213e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.363158308002696995e-01,9.668272358831682123e-01,4.788057134200547349e-01,6.571916893751158506e-01,3.935595532986398831e-02,2.206471444431880868e-01,5.935216711036866988e-01,4.788057134200547349e-01,4.788057134200547349e-01,6.571916893751158506e-01,8.988466430447046573e-02,4.788057134200547349e-01,4.788057134200547349e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.838264253427924100e-01,9.315601365353554097e-01,3.968394702878727531e-01,6.684380543027761412e-01,1.633943597866910347e-02,2.524215114102060231e-01,5.521442515943266738e-01,3.968394702878727531e-01,3.968394702878727531e-01,6.684380543027761412e-01,5.355974830849882795e-02,3.968394702878727531e-01,3.968394702878727531e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.044505120847031288e+00,8.932394807625034794e-01,3.532030201969094119e-01,7.135054025991576232e-01,9.261987939380718349e-03,3.353581702696908362e-01,5.356849263733566291e-01,3.532030201969094119e-01,3.532030201969094119e-01,7.135054025991576232e-01,3.897588590724829216e-02,3.532030201969094119e-01,3.532030201969094119e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000111e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,7.412369072270318382e-01,9.960019985083056193e-01,6.006803711520398714e-01,6.542831988602103577e-01,1.594641774420291758e-01,2.533687545489414772e-01,6.395514002826402367e-01,6.006803711520398714e-01,6.006803711520398714e-01,6.319253596019652752e-01,1.481762825090282842e-01,6.319253596019652752e-01,6.319253596019652752e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,5.594845119885116791e-01,9.702152348991421871e-01,3.254085977982292821e-01,5.185468607581866785e-01,2.202435222843856025e-02,2.002747219982044524e-01,4.455410189942163313e-01,3.254085977982292821e-01,3.254085977982292821e-01,3.852350430356383248e-01,2.079275679833012327e-02,3.852350430356383248e-01,3.852350430356383248e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,4.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,5.131657680956749346e-01,9.460422134075477940e-01,2.521545443385974639e-01,5.622845992224936307e-01,1.054801626828858439e-02,3.700658469850643395e-01,4.203267140040462535e-01,2.521545443385974639e-01,2.521545443385974639e-01,3.204739237629308790e-01,1.143204444477695370e-02,3.204739237629308790e-01,3.204739237629308790e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,6.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,4.893802253047268014e-01,9.237205733870466062e-01,2.132970326019776319e-01,6.645853784323926261e-01,6.711090700556418716e-03,8.508400344372202273e-01,4.258576009673012419e-01,2.132970326019776319e-01,2.132970326019776319e-01,2.862188794299707628e-01,8.633234669510072429e-03,2.862188794299707628e-01,2.862188794299707628e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.266424530851353758e-01,9.966668744787137157e-01,7.389502987326819206e-01,7.777467093013644694e-01,2.744680458719048199e-01,3.743804465731373488e-01,7.679853227378377056e-01,7.389502987326819206e-01,7.389502987326819206e-01,7.679853227378377056e-01,3.127715533249892932e-01,7.389502987326819206e-01,7.389502987326819206e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,8.988551358284879722e-01,9.681330521877006268e-01,4.828644525262330012e-01,6.561033558730196003e-01,4.079695832765516117e-02,2.505193193179551248e-01,6.046279313626753416e-01,4.828644525262330012e-01,4.828644525262330012e-01,6.046279313626753416e-01,8.291517929519107155e-02,4.828644525262330012e-01,4.828644525262330012e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.135091845339095018e-01,9.362923871627033545e-01,4.014134011159205540e-01,6.577492360584993314e-01,1.725678220067057220e-02,2.951158878427307952e-01,5.741262197158149005e-01,4.014134011159205540e-01,4.014134011159205540e-01,5.741262197158149005e-01,4.974401925720320361e-02,4.014134011159205540e-01,4.014134011159205540e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,9.373633822565380358e-01,9.036441748309678168e-01,3.567377790820524530e-01,6.838260559383528836e-01,9.830738478882217191e-03,3.674891145564385675e-01,5.701779766360495216e-01,3.567377790820524530e-01,3.567377790820524530e-01,5.701779766360495216e-01,3.622154555221047262e-02,3.567377790820524530e-01,3.567377790820524530e-01,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000056e-01,1.000000000000000000e+00,9.982001217271316840e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,9.821463000533079413e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,2.000000000000000000e+00,1.000000000000000000e+00,9.646113547084023132e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 +2.981499999999999773e+02,1.013250000000000028e+01,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,0.000000000000000000e+00,3.000000000000000000e+00,1.000000000000000000e+00,9.473894730162663036e-01,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00,1.000000000000000000e+00 diff --git a/tests/test_jaxscan.py b/tests/test_jaxscan.py new file mode 100644 index 00000000..8d32ced6 --- /dev/null +++ b/tests/test_jaxscan.py @@ -0,0 +1,53 @@ +import itertools +from jax import numpy as np, vmap, jit, lax +from time import time + +cats = np.vstack([1., 2, 3, 4, 5]) +anis = np.array([[5., 2, 6]]) +ca = np.array([[3., 1, 4, 7, 5], + [3, 2, 6, 8, 4], + [1, 4, 3, 6, 8]]) + +m_cats = cats.ravel() +m_anis = anis.ravel() + +go = time() +@jit +def test_matmul(): + anisanis = np.array([(np.transpose(anis) @ anis) + [np.triu_indices(len(anis[0]), k=1)]]) + catscats = np.array([(np.transpose(cats) @ cats) + [np.triu_indices(len(cats[0]), k=1)]]) + return (anis @ ca @ cats)[0][0] + + +test_matmul() +print(time() - go) +go = time() +test_matmul() +print(time() - go) + +def map_func(i_ca): + ic, ia = i_ca + return ( + m_cats[ic] + * m_anis[ia] + * ca[ia][ic] + ) + +go = time() +@jit +def test_map(): + r_cats = range(len(m_cats)) + r_anis = range(len(m_anis)) + i_ca = np.array(list(itertools.product(r_cats, r_anis))) + i_cc = np.array(list(itertools.product(r_cats, r_cats))) + i_aa = np.array(list(itertools.product(r_anis, r_anis))) + return np.sum(lax.map(map_func, i_ca)) + + +test_map() +print(time() - go) +go = time() +test_map() +print(time() - go) diff --git a/tests/test_v0_4_3.py b/tests/test_v0_4_3.py new file mode 100644 index 00000000..f785d898 --- /dev/null +++ b/tests/test_v0_4_3.py @@ -0,0 +1,32 @@ +from collections import OrderedDict +import pandas as pd, numpy as np +import pytzer as pz + +v4 = pd.read_csv("tests/data/pytzerQuickStart_py_v0_4_3__GM89.csv") +solutes = [ + k + for k in v4.columns + if k not in ["tempK", "pres", "aw", "osm"] and not k.startswith("g") +] +for s in solutes: + v4["g{}_new".format(s)] = np.nan +plib = pz.libraries.GM89 +plib.set_func_J(pz) + +for i, row in v4.iterrows(): + print(i) + solutes = OrderedDict( + (k, v) + for k, v in row.iteritems() + if k not in ["tempK", "pres", "aw", "osm"] and not k.startswith("g") + ) + params = plib.get_parameters( + solutes, temperature=row.tempK, pressure=row.pres, verbose=False + ) + acfs = pz.activity_coefficients(solutes, **params) + for s in solutes: + v4.loc[i, "g{}_new".format(s)] = acfs[s] +for s in solutes: + gsdiff = "g{}_diff".format(s) + v4[gsdiff] = v4["g{}_new".format(s)] - v4["g{}".format(s)] + v4.loc[v4[gsdiff].abs() < 1e-12, gsdiff] = 0 From 6bfb7d0dbb94b20905f75cd564dca956a6f9a7b9 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Fri, 22 Oct 2021 15:49:00 +0200 Subject: [PATCH 04/58] Add value checks on parameters --- tests/test_CRP94.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/test_CRP94.py b/tests/test_CRP94.py index f5847508..29b34b53 100644 --- a/tests/test_CRP94.py +++ b/tests/test_CRP94.py @@ -1,4 +1,4 @@ -import pandas as pd +import pandas as pd, numpy as np import pytzer as pz # Update unsymmetrical mixing function @@ -16,9 +16,42 @@ # Close but not exact --- not sure why. Excluding OH makes things much worse. +def test_CRP94_table7(): + """Does Pytzer reproduce the interaction parameters at 298.15 K from Table 7?""" + tp = 298.15, 10.10325 + # H-HSO4 interaction + b0, b1, _, C0, C1, alph1, _, omega, _ = pz.parameters.bC_H_HSO4_CRP94(*tp) + assert np.round(b0, decimals=9) == 0.295_903_322 + assert np.round(b1, decimals=9) == 0.400_482_398 + assert np.round(C0, decimals=10) == -0.005_657_866_5 # should be -0.005_657_866_56 + assert np.round(C1, decimals=8) == -0.409_364_25 # should be -0.409_364_246 + assert alph1 == 2 + assert omega == 2.5 + # H-SO4 interaction + b0, b1, _, C0, C1, alph1, _, omega, _ = pz.parameters.bC_H_SO4_CRP94(*tp) + assert np.round(b0, decimals=11) == -0.008_386_089_24 + assert np.round(b1, decimals=9) == 0.314_734_575 + assert np.round(C0, decimals=10) == 0.010_192_247_4 + assert np.round(C1, decimals=8) == -0.323_662_60 # should be -0.323_662_605 + assert alph1 == 2 + assert omega == 2.5 + k_HSO4 = np.exp(pz.equilibrate.dissociation.HSO4_CRP94(tp[0]).item()) + assert np.round(k_HSO4, decimals=4) == 0.0105 + + def test_CRP94_table8(): - """Are Pytzer's values close to CRP94 Table 8?""" + """Are Pytzer's HSO4-SO4 speciation values close to CRP94 Table 8?""" assert (crp94.alpha_diff.abs() < 4e-5).all() +def test_CRP94_Aphi(): + """Does Pytzer reproduce the Aphi test values from CRP94 Appendix II?""" + Aphi_25 = np.round(pz.debyehueckel.Aosm_CRP94(298.15, 10.10325)[0], decimals=9) + assert Aphi_25 == 0.391_475_238 + Aphi_00 = np.round(pz.debyehueckel.Aosm_CRP94(273.15, 10.10325)[0], decimals=9) + assert Aphi_00 == 0.376_421_452 + + +test_CRP94_table7() # test_CRP94_table8() +# test_CRP94_Aphi() From e7a75c5cff74b86e7dc85a9056b49e3f2f849144 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Fri, 22 Oct 2021 15:49:50 +0200 Subject: [PATCH 05/58] Restyle --- pytzer/model.py | 1 + pytzer/parameters.py | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/pytzer/model.py b/pytzer/model.py index 171d1aba..1da69962 100644 --- a/pytzer/model.py +++ b/pytzer/model.py @@ -77,6 +77,7 @@ def Gibbs_nRT_fori(solutes, params): sqrt_I = np.sqrt(I) Gibbs = Gibbs_DH(params["Aphi"], I) + @jax.jit def Gibbs_nRT( solutes, diff --git a/pytzer/parameters.py b/pytzer/parameters.py index b4726acc..89bca47e 100644 --- a/pytzer/parameters.py +++ b/pytzer/parameters.py @@ -8916,38 +8916,38 @@ def bC_H_HSO4_CRP94(T, P): b0 = CRP94_eq24( T, [ - 0.227784933, - -3.78667718, - -0.124645729, - -0.00235747806, + 0.227_784_933, + -3.786_677_18, + -0.124_645_729, + -0.002_357_478_06, ], ) b1 = CRP94_eq24( T, [ - 0.372293409, + 0.372_293_409, 1.50, - 0.207494846, - 0.00448526492, + 0.207_494_846, + 0.004_485_264_92, ], ) b2 = 0 C0 = CRP94_eq24( T, [ - -0.00280032520, - 0.216200279, - 0.0101500824, - 0.000208682230, + -0.002_800_325_20, + 0.216_200_279, + 0.010_150_082_4, + 0.000_208_682_230, ], ) C1 = CRP94_eq24( T, [ -0.025, - 18.1728946, - 0.382383535, - 0.0025, + 18.172_894_6, + 0.382_383_535, + 0.002_5, ], ) alph1 = 2 From 93e9c318d3f84d65869923914f30852bd7d80a77 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Fri, 22 Oct 2021 15:50:13 +0200 Subject: [PATCH 06/58] Testing --- tests/test_jaxscan.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/tests/test_jaxscan.py b/tests/test_jaxscan.py index 8d32ced6..fa02121e 100644 --- a/tests/test_jaxscan.py +++ b/tests/test_jaxscan.py @@ -2,22 +2,26 @@ from jax import numpy as np, vmap, jit, lax from time import time -cats = np.vstack([1., 2, 3, 4, 5]) -anis = np.array([[5., 2, 6]]) -ca = np.array([[3., 1, 4, 7, 5], - [3, 2, 6, 8, 4], - [1, 4, 3, 6, 8]]) +cats = np.vstack([1.0, 2, 3, 4, 5]) +anis = np.array([[5.0, 2, 6]]) +ca = np.array([[3.0, 1, 4, 7, 5], [3, 2, 6, 8, 4], [1, 4, 3, 6, 8]]) m_cats = cats.ravel() m_anis = anis.ravel() go = time() + + @jit def test_matmul(): - anisanis = np.array([(np.transpose(anis) @ anis) - [np.triu_indices(len(anis[0]), k=1)]]) - catscats = np.array([(np.transpose(cats) @ cats) - [np.triu_indices(len(cats[0]), k=1)]]) + anisanis = np.array( + [(np.transpose(anis) @ anis)[np.triu_indices(np.size(anis), k=1)]] + ) + # anix = np.triu_indices(np.size(anis), k=1) + # anisanis = anis[0][anix[0]] * anis[0][anix[1]] + catscats = np.array( + [(np.transpose(cats) @ cats)[np.triu_indices(np.size(cats), k=1)]] + ) return (anis @ ca @ cats)[0][0] @@ -27,15 +31,15 @@ def test_matmul(): test_matmul() print(time() - go) + def map_func(i_ca): ic, ia = i_ca - return ( - m_cats[ic] - * m_anis[ia] - * ca[ia][ic] - ) - + return m_cats[ic] * m_anis[ia] * ca[ia][ic] + + go = time() + + @jit def test_map(): r_cats = range(len(m_cats)) From aad19183bc6070fe1fbd74fd1146b8ae40062128 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Fri, 22 Oct 2021 15:50:42 +0200 Subject: [PATCH 07/58] Don't run test --- tests/test_CRP94.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_CRP94.py b/tests/test_CRP94.py index 29b34b53..fe5ed58f 100644 --- a/tests/test_CRP94.py +++ b/tests/test_CRP94.py @@ -52,6 +52,6 @@ def test_CRP94_Aphi(): assert Aphi_00 == 0.376_421_452 -test_CRP94_table7() +# test_CRP94_table7() # test_CRP94_table8() # test_CRP94_Aphi() From 1ad4e90531cc9d99abb9ad3f8e6381945cbe1151 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Fri, 22 Oct 2021 16:29:06 +0200 Subject: [PATCH 08/58] Fix presumed typo in M88 Table 4 --- tests/data/M88 Table 4.csv | 2 +- tests/test_M88.py | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/data/M88 Table 4.csv b/tests/data/M88 Table 4.csv index 1d40a212..e4141ca8 100644 --- a/tests/data/M88 Table 4.csv +++ b/tests/data/M88 Table 4.csv @@ -2,6 +2,6 @@ point,Na,Ca,Cl,SO4,a_H2O 1,6.734,0.02590,6.734,0.0259,0.7413 2,6.930,0.00637,6.664,0.1391,0.7401 3,7.381,0.00121,6.509,0.4374,0.7364 -4,7.382,0.00000,6.590,0.4366,0.7365 +4,7.382,0.00000,6.509,0.4366,0.7365 5,5.976,0.00371,0.000,2.9920,0.9040 6,3.292,0.00794,0.000,1.6540,0.9445 diff --git a/tests/test_M88.py b/tests/test_M88.py index b510e283..b9024c09 100644 --- a/tests/test_M88.py +++ b/tests/test_M88.py @@ -19,14 +19,11 @@ def get_activity_water(data_row): def test_M88_activity_water(): """Can we reproduce the values from M88 Table 4? - - We presume that their Point 4 contains some typo, hence worse agreement. + Note that we have corrected a presumed typo in row 4 (6.590 => 6.509 for Cl, + based on an analysis of charge balance). """ for i, row in data.iterrows(): - if row.name == 4: - assert np.isclose(row["a_H2O"], row["a_H2O_pytzer"], rtol=0, atol=0.01) - else: - assert np.isclose(row["a_H2O"], row["a_H2O_pytzer"], rtol=0, atol=0.0001) + assert np.isclose(row["a_H2O"], row["a_H2O_pytzer"], rtol=0, atol=0.0001) # test_M88_activity_water() From 1d34c8dedc0a3d21af0bdeb97d065ffbc4ae5a3a Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Fri, 22 Oct 2021 16:32:50 +0200 Subject: [PATCH 09/58] Don't round --- tests/test_M88.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_M88.py b/tests/test_M88.py index b9024c09..574c8906 100644 --- a/tests/test_M88.py +++ b/tests/test_M88.py @@ -11,7 +11,7 @@ def get_activity_water(data_row): dr = pz.odict(data_row[m_cols]) - return np.round(pz.activity_water(dr, **params).item(), decimals=4) + return pz.activity_water(dr, **params).item() data["a_H2O_pytzer"] = data.apply(get_activity_water, axis=1) From 52cb1656d85a43d2782d89f682b58404fe6be582 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Fri, 18 Feb 2022 16:38:45 +0100 Subject: [PATCH 10/58] Try out matrix approach --- pytzer/__init__.py | 1 + pytzer/debyehueckel.py | 10 +- pytzer/dissociation.py | 20 +- pytzer/equilibrate/components.py | 14 +- pytzer/libraries/ParameterLibrary.py | 161 + pytzer/matrix.py | 182 + pytzer/model.py | 21 +- pytzer/parameters.py | 100 +- pytzer/teos10.py | 2 +- pytzer/unsymmetrical.py | 6 +- pytzer4/__init__.py | 156 + pytzer4/constants.py | 21 + pytzer4/debyehueckel.py | 202 + pytzer4/dissociation.py | 129 + pytzer4/equilibrate.py | 505 + pytzer4/io.py | 145 + pytzer4/libraries/CRP94.py | 17 + pytzer4/libraries/GM89.py | 33 + pytzer4/libraries/HMW84.py | 266 + pytzer4/libraries/M88.py | 25 + pytzer4/libraries/MIAMI.py | 272 + pytzer4/libraries/MarChemSpec.py | 23 + pytzer4/libraries/MarChemSpec05.py | 20 + pytzer4/libraries/MarChemSpec25.py | 31 + pytzer4/libraries/ParameterLibrary.py | 249 + pytzer4/libraries/Seawater.py | 38 + pytzer4/libraries/WM13.py | 112 + pytzer4/libraries/WM13_MarChemSpec25.py | 20 + pytzer4/libraries/__init__.py | 86 + pytzer4/matrix.py | 274 + pytzer4/meta.py | 48 + pytzer4/model.py | 256 + pytzer4/parameters.py | 12337 ++++++++++++++++++++++ pytzer4/plot.py | 92 + pytzer4/properties.py | 325 + pytzer4/teos10.py | 147 + pytzer4/unsymmetrical.py | 175 + tests/test_convert.py | 6 +- tests/test_matrix.py | 58 + tests/test_stoichiometric.py | 52 +- tests/untitled0.py | 28 + 41 files changed, 16555 insertions(+), 110 deletions(-) create mode 100644 pytzer/matrix.py create mode 100644 pytzer4/__init__.py create mode 100644 pytzer4/constants.py create mode 100644 pytzer4/debyehueckel.py create mode 100644 pytzer4/dissociation.py create mode 100644 pytzer4/equilibrate.py create mode 100644 pytzer4/io.py create mode 100644 pytzer4/libraries/CRP94.py create mode 100644 pytzer4/libraries/GM89.py create mode 100644 pytzer4/libraries/HMW84.py create mode 100644 pytzer4/libraries/M88.py create mode 100644 pytzer4/libraries/MIAMI.py create mode 100644 pytzer4/libraries/MarChemSpec.py create mode 100644 pytzer4/libraries/MarChemSpec05.py create mode 100644 pytzer4/libraries/MarChemSpec25.py create mode 100644 pytzer4/libraries/ParameterLibrary.py create mode 100644 pytzer4/libraries/Seawater.py create mode 100644 pytzer4/libraries/WM13.py create mode 100644 pytzer4/libraries/WM13_MarChemSpec25.py create mode 100644 pytzer4/libraries/__init__.py create mode 100644 pytzer4/matrix.py create mode 100644 pytzer4/meta.py create mode 100644 pytzer4/model.py create mode 100644 pytzer4/parameters.py create mode 100644 pytzer4/plot.py create mode 100644 pytzer4/properties.py create mode 100644 pytzer4/teos10.py create mode 100644 pytzer4/unsymmetrical.py create mode 100644 tests/test_matrix.py create mode 100644 tests/untitled0.py diff --git a/pytzer/__init__.py b/pytzer/__init__.py index 694e4b39..1afbd91d 100644 --- a/pytzer/__init__.py +++ b/pytzer/__init__.py @@ -22,6 +22,7 @@ equilibrate, io, libraries, + matrix, meta, model, parameters, diff --git a/pytzer/debyehueckel.py b/pytzer/debyehueckel.py index faa62261..00df3cf7 100644 --- a/pytzer/debyehueckel.py +++ b/pytzer/debyehueckel.py @@ -146,9 +146,9 @@ def _gm1drho(tempK, presMPa): + b[4] / (tempK - 215) ** 0.25 + np.exp( b[5] / tempK - + b[6] / tempK ** 2 + + b[6] / tempK**2 + b[7] * presMPa / tempK - + b[8] * presMPa / tempK ** 2 + + b[8] * presMPa / tempK**2 ) ) return gm1drho @@ -168,14 +168,14 @@ def _D(tempK, presMPa, rho): k = 1.380658e-16 mu = 1.84e-18 A = ( - (al + _g(tempK, presMPa, rho) * mu ** 2 / (3 * k * tempK)) + (al + _g(tempK, presMPa, rho) * mu**2 / (3 * k * tempK)) * 4 * np.pi * NA * rho / (3 * Mw) ) - return (1 + 9 * A + 3 * np.sqrt(9 * A ** 2 + 2 * A + 1)) / 4 + return (1 + 9 * A + 3 * np.sqrt(9 * A**2 + 2 * A + 1)) / 4 def Aosm_AW90(tempK, pres): @@ -190,7 +190,7 @@ def Aosm_AW90(tempK, pres): rho = teos10.rho(tempK, presPa) * 1e-3 Aosm = ( np.sqrt(2e-3 * np.pi * rho * NA) - * (100 * e ** 2 / (4 * np.pi * _D(tempK, presMPa, rho) * E0 * k * tempK)) ** 1.5 + * (100 * e**2 / (4 * np.pi * _D(tempK, presMPa, rho) * E0 * k * tempK)) ** 1.5 / 3 ) valid = np.logical_and( diff --git a/pytzer/dissociation.py b/pytzer/dissociation.py index bbb3b4af..f1331ac1 100644 --- a/pytzer/dissociation.py +++ b/pytzer/dissociation.py @@ -14,7 +14,7 @@ def HSO4_CRP94_extra(T=298.15): log10kHSO4 = ( 562.694864456 - 102.5154 * np.log(T) - - 1.117033e-4 * T ** 2 + - 1.117033e-4 * T**2 + 0.2477538 * T - 13273.75 / T ) @@ -28,7 +28,7 @@ def HSO4_CRP94(T=298.15): log10kHSO4 = ( 562.69486 - 102.5154 * np.log(T) - - 1.117033e-4 * T ** 2 + - 1.117033e-4 * T**2 + 0.2477538 * T - 13273.75 / T ) @@ -53,10 +53,10 @@ def rhow_K75(T=298.15): return ( 0.99983952 + 16.945176e-3 * tempC - - 7.9870401e-6 * tempC ** 2 - - 46.170461e-9 * tempC ** 3 - + 105.56302e-12 * tempC ** 4 - - 280.54253e-15 * tempC ** 5 + - 7.9870401e-6 * tempC**2 + - 46.170461e-9 * tempC**3 + + 105.56302e-12 * tempC**4 + - 280.54253e-15 * tempC**5 ) / (1 + 16.879850e-3 * tempC) @@ -74,7 +74,7 @@ def H2O_M88(T=298.15): - 3.26224352e4 / T - 1.90877133e2 * np.log(T) - 5.35204850e-1 / (T - 263) - - 2.32009393e-4 * T ** 2 + - 2.32009393e-4 * T**2 + 5.20549183e1 / (680 - T) ) @@ -85,9 +85,9 @@ def H2O_MF(T=298.15): log10kH2O = ( -4.098 - 3.2452e3 / T - + 2.2362e5 / T ** 2 - - 3.984e7 / T ** 3 - + (1.3957e1 - 1.2623e3 / T + 8.5641e5 / T ** 2) * np.log10(rhow_K75(T)) + + 2.2362e5 / T**2 + - 3.984e7 / T**3 + + (1.3957e1 - 1.2623e3 / T + 8.5641e5 / T**2) * np.log10(rhow_K75(T)) ) lnkH2O = log10kH2O * ln10 return lnkH2O diff --git a/pytzer/equilibrate/components.py b/pytzer/equilibrate/components.py index 8986ae39..ddba3547 100644 --- a/pytzer/equilibrate/components.py +++ b/pytzer/equilibrate/components.py @@ -42,7 +42,7 @@ def get_CO3(h, totals, ks_constants): t["CO2"] * k["H2CO3"] * k["HCO3"] - / (h ** 2 + k["H2CO3"] * h + k["H2CO3"] * k["HCO3"]) + / (h**2 + k["H2CO3"] * h + k["H2CO3"] * k["HCO3"]) ) @@ -53,7 +53,7 @@ def get_HCO3(h, co3, ks_constants): def get_CO2(h, co3, ks_constants): k = ks_constants - return co3 * h ** 2 / (k["H2CO3"] * k["HCO3"]) + return co3 * h**2 / (k["H2CO3"] * k["HCO3"]) def get_PO4(h, totals, ks_constants): @@ -64,8 +64,8 @@ def get_PO4(h, totals, ks_constants): * k["H2PO4"] * k["HPO4"] / ( - h ** 3 - + k["H3PO4"] * h ** 2 + h**3 + + k["H3PO4"] * h**2 + k["H3PO4"] * k["H2PO4"] * h + k["H3PO4"] * k["H2PO4"] * k["HPO4"] ) @@ -81,12 +81,12 @@ def get_HPO4(h, po4, ks_constants): @get_wrap def get_H2PO4(h, po4, ks_constants): k = ks_constants - return po4 * h ** 2 / (k["H2PO4"] * k["HPO4"]) + return po4 * h**2 / (k["H2PO4"] * k["HPO4"]) def get_H3PO4(h, po4, ks_constants): k = ks_constants - return po4 * h ** 3 / (k["H3PO4"] * k["H2PO4"] * k["HPO4"]) + return po4 * h**3 / (k["H3PO4"] * k["H2PO4"] * k["HPO4"]) def get_SO4(h, totals, ks_constants): @@ -371,7 +371,7 @@ def find_solutes(totals, ks_constants, ptargets=None): @jax.jit def get_solutes(totals, ks_constants, ptargets): - targets = OrderedDict((k, 10.0 ** -v) for k, v in ptargets.items()) + targets = OrderedDict((k, 10.0**-v) for k, v in ptargets.items()) solutes = OrderedDict() totals = totals.copy() solutes.update(totals) diff --git a/pytzer/libraries/ParameterLibrary.py b/pytzer/libraries/ParameterLibrary.py index ddd029a2..02ce81da 100644 --- a/pytzer/libraries/ParameterLibrary.py +++ b/pytzer/libraries/ParameterLibrary.py @@ -3,6 +3,7 @@ from copy import deepcopy from collections import OrderedDict import numpy as np +from scipy.special import comb from .. import debyehueckel as dh, parameters as prm, convert from ..equilibrate import thermodynamic from ..meta import update_func_J @@ -317,3 +318,163 @@ def get_parameters_equilibria( ) log_kt_constants = self.get_equilibria(solutes=solutes, temperature=temperature) return parameters, log_kt_constants + + def get_matrices( + self, + solutes, + temperature=298.15, + pressure=10.1023, + verbose=True, + ): + """Assemble parameter matrices for the matrix model.""" + if verbose: + missing_coeffs = [] + + def report_missing_coeffs(*solutes): + if verbose: + solutes_list = list(solutes) + solutes_list.sort() + if solutes_list not in missing_coeffs: + print( + ( + "{} has no interaction coefficients for " + + "-".join(["{}"] * len(solutes)) + + "; using zero." + ).format(self["name"], *solutes) + ) + missing_coeffs.append(solutes_list) + + cations = [s for s in solutes if s in convert.all_cations] + anions = [s for s in solutes if s in convert.all_anions] + neutrals = [s for s in solutes if s in convert.all_neutrals] + # Set up parameters dict + parameters = {"temperature": temperature, "pressure": pressure} + TP = (temperature, pressure) + if "Aphi" in self: + parameters.update({"Aphi": self["Aphi"](*TP)[0]}) + else: + if verbose: + print( + "{} has no Aphi function; no value returned.".format(self["name"]) + ) + # Preallocate empty matrices + for p in [ + "beta0_ca", + "beta1_ca", + "beta2_ca", + "c0_ca", + "c1_ca", + "theta_xx", + "lambda_nx", + ]: + parameters[p] = np.zeros((len(solutes), len(solutes))) + for p in ["alpha1_ca", "alpha2_ca", "omega_ca"]: + parameters[p] = np.full((len(solutes), len(solutes)), -9.0) + for p in ["psi_cca", "psi_caa"]: + parameters[p] = np.zeros((int(comb(len(cations), 2)), len(anions))) + parameters["zeta_nca"] = np.zeros((len(neutrals), len(cations) * len(anions))) + parameters["mu_nnn"] = np.zeros((len(neutrals), 1)) + # Fill the matrices with coefficients: ca, ii and nx interactions + for x, solute_x in enumerate(solutes): + for y, solute_y in enumerate(solutes): + try: + params_ca = self["ca"][solute_x][solute_y](*TP)[:-1] + ( + parameters["beta0_ca"][x, y], + parameters["beta1_ca"][x, y], + parameters["beta2_ca"][x, y], + parameters["c0_ca"][x, y], + parameters["c1_ca"][x, y], + parameters["alpha1_ca"][x, y], + parameters["alpha2_ca"][x, y], + parameters["omega_ca"][x, y], + ) = ( + parameters["beta0_ca"][y, x], + parameters["beta1_ca"][y, x], + parameters["beta2_ca"][y, x], + parameters["c0_ca"][y, x], + parameters["c1_ca"][y, x], + parameters["alpha1_ca"][y, x], + parameters["alpha2_ca"][y, x], + parameters["omega_ca"][y, x], + ) = params_ca + except KeyError: + if ( + solute_x in convert.all_cations + and solute_y in convert.all_anions + ): + report_missing_coeffs(solute_x, solute_y) + try: + param_theta = self["cc"][solute_x][solute_y](*TP)[0] + parameters["theta_xx"][x, y] = parameters["theta_xx"][ + y, x + ] = param_theta + except KeyError: + if solute_x != solute_y: + if ( + solute_x in convert.all_cations + and solute_y in convert.all_cations + ): + report_missing_coeffs(solute_x, solute_y) + try: + param_theta = self["aa"][solute_x][solute_y](*TP)[0] + parameters["theta_xx"][x, y] = parameters["theta_xx"][ + y, x + ] = param_theta + except KeyError: + if solute_x != solute_y: + if ( + solute_x in convert.all_anions + and solute_y in convert.all_anions + ): + report_missing_coeffs(solute_x, solute_y) + try: + param_lambda = self["nc"][solute_x][solute_y](*TP)[0] + parameters["lambda_nx"][x, y] = parameters["lambda_nx"][ + x, y + ] = param_lambda + except KeyError: + if solute_x in convert.all_neutrals: + report_missing_coeffs(solute_x, solute_y) + try: + param_lambda = self["na"][solute_x][solute_y](*TP)[0] + parameters["lambda_nx"][x, y] = parameters["lambda_nx"][ + x, y + ] = param_lambda + except KeyError: + if solute_x in convert.all_neutrals: + report_missing_coeffs(solute_x, solute_y) + try: + param_lambda = self["nn"][solute_x][solute_y](*TP)[0] + parameters["lambda_nx"][x, y] = parameters["lambda_nx"][ + x, y + ] = param_lambda + except KeyError: + if solute_x in convert.all_neutrals: + report_missing_coeffs(solute_x, solute_y) + # Fill the matrices with coefficients: cca and caa interactions + CC = 0 + for CX, cationx in enumerate(cations): + for xCY, cationy in enumerate(cations[CX + 1 :]): + for A, anion in enumerate(anions): + parameters["psi_cca"][CC, A] = self["cca"][cationx][cationy][anion]( + *TP + )[0] + CC = CC + 1 + AA = 0 + for AX, anionx in enumerate(anions): + for xAY, aniony in enumerate(anions[AX + 1 :]): + for C, cation in enumerate(cations): + parameters["psi_caa"][AA, C] = self["caa"][cation][anionx][aniony]( + *TP + )[0] + AA = AA + 1 + # Fill the matrices with coefficients: nca and nnn interactions + for N, neutral in enumerate(neutrals): + parameters["mu_nnn"][N, 0] = self["nnn"][neutral](*TP)[0] + for C, cation in enumerate(cations): + for A, anion in enumerate(anions): + parameters["zeta_nca"][N, C * len(anions) + A] = self["nca"][ + neutral + ][cation][anion](*TP)[0] + return parameters diff --git a/pytzer/matrix.py b/pytzer/matrix.py new file mode 100644 index 00000000..ce4c9031 --- /dev/null +++ b/pytzer/matrix.py @@ -0,0 +1,182 @@ +import jax +from jax import numpy as np +from . import convert, model + + +def ionic_strength(molalities, charges): + """Calculate the ionic strength. + + Parameters + ---------- + molalities : array_like + Molality of each solute in mol/kg. + charges : array_like + Charge on each solute. + + Returns + ------- + float + Ionic strength of the solution in mol/kg. + """ + return molalities @ np.transpose(charges**2) / 2 + + +def ionic_z(molalities, charges): + """Calculate the Z function. + + Parameters + ---------- + molalities : array_like + Molality of each solute in mol/kg. + charges : array_like + Charge on each solute. + + Returns + ------- + float + Z function of the solution in mol/kg. + """ + return molalities @ np.transpose(np.abs(charges)) + + +def sum_B_CT(I, Z, beta0, beta1, beta2, alpha1, alpha2, c0, c1, omega): + """Calculate the sum of the B and CT functions following CRP94 equations (AI7) and + (AI10) respectively. + + Parameters + ---------- + I : float + Ionic strength of the solution in mol/kg. + Z : float + Z function of the solution in mol/kg. + beta0 : array_like + Beta-0 Pitzer model coefficients. + beta1 : array_like + Beta-1 Pitzer model coefficients. + beta2 : array_like + Beta-2 Pitzer model coefficients. + alpha1 : array_like + Alpha-1 Pitzer model coefficients. + alpha2 : array_like + Alpha-2 Pitzer model cofficients. + c0 : array_like + C-0 Pitzer model coefficients. + c1 : array_like + C-1 Pitzer model coefficients. + omega : array_like + Omega Pitzer model coefficients. + + Returns + ------- + array_like + Sum of the B and CT functions. + """ + return ( + beta0 + + beta1 * model.g(alpha1 * np.sqrt(I)) + + beta2 * model.g(alpha2 * np.sqrt(I)) + + (c0 + 4 * c1 * model.h(omega * np.sqrt(I))) * Z / 2 + ) + + +def xij(Aphi, I, charges): + """xij function for unsymmetrical mixing.""" + return (np.transpose(charges) @ charges) * 6 * Aphi * np.sqrt(I) + + +def xi(Aphi, I, charges): + """xi function for unsymmetrical mixing.""" + return charges**2 * 6 * Aphi * np.sqrt(I) + + +def xj(Aphi, I, zs): + """xj function for unsymmetrical mixing.""" + return np.transpose(zs**2) * 6 * Aphi * np.sqrt(I) + + +def etheta(Aphi, I, charges): + """E-theta function for unsymmetrical mixing.""" + x01 = xij(Aphi, I, charges) + x00 = xi(Aphi, I, charges) + x11 = xj(Aphi, I, charges) + func_J = jax.vmap(jax.vmap(model.func_J)) + return ( + (np.transpose(charges) @ charges) + * (func_J(x01) - (func_J(x00) + func_J(x11)) / 2) + / (4 * I) + ) + + +@jax.jit +def Gibbs_nRT( + solutes, + n_cats_triu, + n_anis_triu, + Aphi=None, + beta0_ca=None, + beta1_ca=None, + beta2_ca=None, + alpha1_ca=None, + alpha2_ca=None, + c0_ca=None, + c1_ca=None, + omega_ca=None, + theta_xx=None, + psi_cca=None, + psi_caa=None, + lambda_nx=None, + zeta_nca=None, + mu_nnn=None, + **parameters_extra +): + """Excess Gibbs energy of a solution.""" + # Get the molalities of cations, anions and neutrals in separate arrays + molalities = np.array([[m for m in solutes.values()]]) + m_cats = np.array([[m for s, m in solutes.items() if s in convert.all_cations]]) + m_anis = np.array([[m for s, m in solutes.items() if s in convert.all_anions]]) + m_neus = np.array([[m for s, m in solutes.items() if s in convert.all_neutrals]]) + # Get the charges of cations and anions in separate arrays + s2c = convert.solute_to_charge + charges = np.array([[s2c[s] for s in solutes]]) + z_cats = np.array([[s2c[s] for s in solutes if s in convert.all_cations]]) + z_anis = np.array([[s2c[s] for s in solutes if s in convert.all_anions]]) + I = ionic_strength(molalities, charges) + # if I == 0: + # Gibbs_nRT = ( + # molalities @ lambda_nx @ np.transpose(molalities) + # + m_neus @ zeta_nca @ np.transpose(m_cats_anis) + # + m_neus**3 @ mu_nnn + # ) + # else: + # # Get the products of cation and anion molalities + m_cats_anis = np.array([(np.transpose(m_cats) @ m_anis).ravel()]) + Z = ionic_z(molalities, charges) + m_cats_cats = np.array([(np.transpose(m_cats) @ m_cats)[n_cats_triu]]) + m_anis_anis = np.array([(np.transpose(m_anis) @ m_anis)[n_anis_triu]]) + Gibbs_nRT = model.Gibbs_DH(Aphi, I) + molalities @ ( + sum_B_CT( + I, + Z, + beta0_ca, + beta1_ca, + beta2_ca, + alpha1_ca, + alpha2_ca, + c0_ca, + c1_ca, + omega_ca, + ) + + theta_xx + + lambda_nx + ) @ np.transpose(molalities) + +m_cats @ etheta(Aphi, I, z_cats) @ np.transpose(m_cats) + +m_anis @ etheta(Aphi, I, z_anis) @ np.transpose(m_anis) + if psi_cca.size > 0: + Gibbs_nRT = Gibbs_nRT + m_cats_cats @ psi_cca @ np.transpose(m_anis) + if psi_caa.size > 0: + Gibbs_nRT = Gibbs_nRT + m_anis_anis @ psi_caa @ np.transpose(m_cats) + if zeta_nca.size > 0: + Gibbs_nRT = Gibbs_nRT + m_neus @ zeta_nca @ np.transpose(m_cats_anis) + if mu_nnn.size > 0: + Gibbs_nRT = Gibbs_nRT + m_neus**3 @ mu_nnn + return Gibbs_nRT[0][0] diff --git a/pytzer/model.py b/pytzer/model.py index 1da69962..869d603d 100644 --- a/pytzer/model.py +++ b/pytzer/model.py @@ -10,20 +10,31 @@ def Gibbs_DH(Aphi, I): - """The Debye-Hueckel component of the excess Gibbs energy, - following CRP94 Eq. (AI1). + """The Debye-Hueckel component of the excess Gibbs energy following CRP94 eq. (AI1). + + Parameters + ---------- + Aphi : float + Debye-Hueckel limiting slope for the osmotic coefficient. + I : float + Ionic strength of the solution in mol/kg. + + Returns + ------- + float + Debye-Hueckel component of the excess Gibbs energy. """ return -4 * Aphi * I * np.log(1 + b * np.sqrt(I)) / b def g(x): """g function, following CRP94 Eq. (AI13).""" - return 2 * (1 - (1 + x) * np.exp(-x)) / x ** 2 + return 2 * (1 - (1 + x) * np.exp(-x)) / x**2 def h(x): """h function, following CRP94 Eq. (AI15).""" - return (6 - (6 + x * (6 + 3 * x + x ** 2)) * np.exp(-x)) / x ** 4 + return (6 - (6 + x * (6 + 3 * x + x**2)) * np.exp(-x)) / x**4 def B(sqrt_I, b0, b1, b2, alph1, alph2): @@ -51,7 +62,7 @@ def etheta(Aphi, I, z0, z1, func_J=unsymmetrical.Harvie): def ionic_strength(molalities, charges): """Ionic strength.""" - return 0.5 * np.sum(molalities * charges ** 2) + return 0.5 * np.sum(molalities * charges**2) def ionic_z(molalities, charges): diff --git a/pytzer/parameters.py b/pytzer/parameters.py index 89bca47e..89474634 100644 --- a/pytzer/parameters.py +++ b/pytzer/parameters.py @@ -4058,10 +4058,10 @@ def psi_Na_CO3_Cl_TM82(T, P): def bC_Mg_Cl_dLP83(T, P): """c-a: magnesium chloride [dLP83].""" # dLP83 Eq. (11) - b0 = 5.93915e-7 * T ** 2 - 9.31654e-4 * T + 0.576066 - b1 = 2.60169e-5 * T ** 2 - 1.09438e-2 * T + 2.60135 + b0 = 5.93915e-7 * T**2 - 9.31654e-4 * T + 0.576066 + b1 = 2.60169e-5 * T**2 - 1.09438e-2 * T + 2.60135 b2 = 0 - Cphi = 3.01823e-7 * T ** 2 - 2.89125e-4 * T + 6.57867e-2 + Cphi = 3.01823e-7 * T**2 - 2.89125e-4 * T + 6.57867e-2 C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["Cl"]))) C1 = 0 alph1 = 2 @@ -4080,7 +4080,7 @@ def HM83_eq25(T, a): + a[1] * (1 / T - 1 / TR) + a[2] * np.log(T / TR) + a[3] * (T - TR) - + a[4] * (T ** 2 - TR ** 2) + + a[4] * (T**2 - TR**2) + a[5] * np.log(T - 260) ) @@ -6626,12 +6626,12 @@ def PP86ii_eq28(T, q): """PP86ii equation 28.""" Tr = PP86ii_Tr return ( - (T ** 2 - Tr ** 2) * q[0] / 2 - + (T ** 3 - Tr ** 3) * q[1] / 3 - + (T ** 4 - Tr ** 4) * q[2] / 4 - + (T ** 5 - Tr ** 5) * q[3] / 5 - + Tr ** 2 * q[4] - ) / T ** 2 + (T**2 - Tr**2) * q[0] / 2 + + (T**3 - Tr**3) * q[1] / 3 + + (T**4 - Tr**4) * q[2] / 4 + + (T**5 - Tr**5) * q[3] / 5 + + Tr**2 * q[4] + ) / T**2 def PP86ii_eq29(T, q): @@ -6649,11 +6649,11 @@ def PP86ii_eq29(T, q): # Original fourth line was: # + q[3] * (T**4/20 + Tr**5/(5*T) - Tr**4/4) return ( - q[0] * (T / 2 + Tr ** 2 / (2 * T) - Tr) - + q[1] * (T ** 2 / 6 + Tr ** 3 / (3 * T) - Tr ** 2 / 2) - + q[2] * (T ** 3 / 12 + Tr ** 4 / (4 * T) - Tr ** 3 / 3) - + q[3] * (t ** 5 + 4 - 5 * t) * Tr ** 5 / (20 * T) - + q[4] * (Tr - Tr ** 2 / T) + q[0] * (T / 2 + Tr**2 / (2 * T) - Tr) + + q[1] * (T**2 / 6 + Tr**3 / (3 * T) - Tr**2 / 2) + + q[2] * (T**3 / 12 + Tr**4 / (4 * T) - Tr**3 / 3) + + q[3] * (t**5 + 4 - 5 * t) * Tr**5 / (20 * T) + + q[4] * (Tr - Tr**2 / T) + q[5] ) @@ -6718,12 +6718,12 @@ def HM86_eq8(T, a): # Typo in a[5] term in HM86 has been corrected here return ( a[0] - + a[1] * (TR - TR ** 2 / T) - + a[2] * (T ** 2 + 2 * TR ** 3 / T - 3 * TR ** 2) - + a[3] * (T + TR ** 2 / T - 2 * TR) + + a[1] * (TR - TR**2 / T) + + a[2] * (T**2 + 2 * TR**3 / T - 3 * TR**2) + + a[3] * (T + TR**2 / T - 2 * TR) + a[4] * (np.log(T / TR) + TR / T - 1) - + a[5] * (1 / (T - 263) + (263 * T - TR ** 2) / (T * (TR - 263) ** 2)) - + a[6] * (1 / (680 - T) + (TR ** 2 - 680 * T) / (T * (680 - TR) ** 2)) + + a[5] * (1 / (T - 263) + (263 * T - TR**2) / (T * (TR - 263) ** 2)) + + a[6] * (1 / (680 - T) + (TR**2 - 680 * T) / (T * (680 - TR) ** 2)) ) @@ -6863,8 +6863,8 @@ def PP87i_eqNaOH(T, P, a): + a[4] * np.log(T) + a[5] * T + a[6] * T * P - + a[7] * T ** 2 - + a[8] * T ** 2 * P + + a[7] * T**2 + + a[8] * T**2 * P + a[9] / (T - 227) + a[10] / (647 - T) + a[11] * P / (647 - T) @@ -6941,7 +6941,7 @@ def bC_Na_OH_PP87i(T, P): def bC_Mg_Cl_PP87i(T, P): """c-a: magnesium chloride [PP87i].""" b0, b1, b2, _, C1, alph1, alph2, omega, _ = bC_Mg_Cl_dLP83(T, P) - Cphi = 2.41831e-7 * T ** 2 - 2.49949e-4 * T + 5.95320e-2 + Cphi = 2.41831e-7 * T**2 - 2.49949e-4 * T + 5.95320e-2 C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["Cl"]))) valid = (T >= 298.15) & (T <= 473.15) return b0, b1, b2, C0, C1, alph1, alph2, omega, valid @@ -7410,7 +7410,7 @@ def M88_eq13(T, a): + a[2] / T + a[3] * np.log(T) + a[4] / (T - 263) - + a[5] * T ** 2 + + a[5] * T**2 + a[6] / (680 - T) + a[7] / (T - 227) ) @@ -7655,7 +7655,7 @@ def psi_Na_Cl_SO4_M88(T, P): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clegg & Brimblecombe (1989) ~~~~~ def lambd_NH3_NH3_CB89(T, P): """n-n: ammonia ammonia [CB89].""" - lambd = 0.033161 - 21.12816 / T + 4665.1461 / T ** 2 + lambd = 0.033161 - 21.12816 / T + 4665.1461 / T**2 valid = (T >= 273.15) & (T <= 313.15) return lambd, valid @@ -8324,28 +8324,28 @@ def A92ii_eq36(T, P, a): # a[5] and a[6] multipliers are corrected for typos in A92ii return ( a[0] - + a[1] * 10 ** -3 * T - + a[2] * 4e-6 * T ** 2 + + a[1] * 10**-3 * T + + a[2] * 4e-6 * T**2 + a[3] * 1 / (T - 200) + a[4] * 1 / T + a[5] * 100 / (T - 200) ** 2 - + a[6] * 200 / T ** 2 - + a[7] * 8e-9 * T ** 3 + + a[6] * 200 / T**2 + + a[7] * 8e-9 * T**3 + a[8] * 1 / (650 - T) ** 0.5 - + a[9] * 10 ** -5 * P + + a[9] * 10**-5 * P + a[10] * 2e-4 * P / (T - 225) + a[11] * 100 * P / (650 - T) ** 3 + a[12] * 2e-8 * P * T + a[13] * 2e-4 * P / (650 - T) - + a[14] * 10 ** -7 * P ** 2 - + a[15] * 2e-6 * P ** 2 / (T - 225) - + a[16] * P ** 2 / (650 - T) ** 3 - + a[17] * 2e-10 * P ** 2 * T - + a[18] * 4e-13 * P ** 2 * T ** 2 + + a[14] * 10**-7 * P**2 + + a[15] * 2e-6 * P**2 / (T - 225) + + a[16] * P**2 / (650 - T) ** 3 + + a[17] * 2e-10 * P**2 * T + + a[18] * 4e-13 * P**2 * T**2 + a[19] * 0.04 * P / (T - 225) ** 2 - + a[20] * 4e-11 * P * T ** 2 - + a[21] * 2e-8 * P ** 3 / (T - 225) - + a[22] * 0.01 * P ** 3 / (650 - T) ** 3 + + a[20] * 4e-11 * P * T**2 + + a[21] * 2e-8 * P**3 / (T - 225) + + a[22] * 0.01 * P**3 / (650 - T) ** 3 + a[23] * 200 / (650 - T) ** 3 ) @@ -8575,7 +8575,7 @@ def psi_H_Na_Cl_CMR93(T, P): # interactions with HCO3 and CO3 (not yet coded here) def HM93_eq(T, A, B, C, D, E): """HM93 parameter equation from p. 3548.""" - return A + B * T + C * T ** 2 + D / T + E * np.log(T) + return A + B * T + C * T**2 + D / T + E * np.log(T) def lambd_CO2_H_HM93(T, P): @@ -9064,8 +9064,8 @@ def MP98_eq15(T, q): BLR = q[2] * 1e-4 return ( BR - + (BJ * (Tr ** 3 / 3) - Tr ** 2 * BLR) * (1 / T - 1 / Tr) - + (BJ / 6) * (T ** 2 - Tr ** 2) + + (BJ * (Tr**3 / 3) - Tr**2 * BLR) * (1 / T - 1 / Tr) + + (BJ / 6) * (T**2 - Tr**2) ) @@ -9128,7 +9128,7 @@ def bC_Na_Br_MP98(T, P): T, [ 0.00116, - 0.058 * 2 ** 1.5, + 0.058 * 2**1.5, -0.93, ], # more accurate following PM16 model ) @@ -10879,7 +10879,7 @@ def ZD17_eq8(T, P, b): + b[3] / (T - 215) + b[4] * 1e4 / (T - 215) ** 3 + b[5] * 1e2 / (T - 215) ** 2 - + b[6] * 2e2 / T ** 2 + + b[6] * 2e2 / T**2 + b[7] * (T / 500) ** 3 + b[8] / (650 - T) ** 0.5 + b[9] * 1e-5 * P @@ -10887,15 +10887,15 @@ def ZD17_eq8(T, P, b): + b[11] * 1e2 * P / (650 - T) ** 3 + b[12] * 1e-5 * P * T / 500 + b[13] * 2e-4 * P / (650 - T) - + b[14] * 1e-7 * P ** 2 - + b[15] * 2e-6 * P ** 2 / (T - 225) - + b[16] * P ** 2 / (650 - T) ** 3 - + b[17] * 1e-7 * P ** 2 * T / 500 - + b[18] * 1e-7 * P ** 2 * (T / 500) ** 2 + + b[14] * 1e-7 * P**2 + + b[15] * 2e-6 * P**2 / (T - 225) + + b[16] * P**2 / (650 - T) ** 3 + + b[17] * 1e-7 * P**2 * T / 500 + + b[18] * 1e-7 * P**2 * (T / 500) ** 2 + b[19] * 4e-2 * P / (T - 225) ** 2 + b[20] * 1e-5 * P * (T / 500) ** 2 - + b[21] * 2e-8 * P ** 3 / (T - 225) - + b[22] * 1e-2 * P ** 3 / (650 - T) ** 3 + + b[21] * 2e-8 * P**3 / (T - 225) + + b[22] * 1e-2 * P**3 / (650 - T) ** 3 + b[23] * 2e2 / (650 - T) ** 3 ) diff --git a/pytzer/teos10.py b/pytzer/teos10.py index fcd13f19..768c0033 100644 --- a/pytzer/teos10.py +++ b/pytzer/teos10.py @@ -65,7 +65,7 @@ def Gibbs(tempK, presPa): for j in range(8): for k in range(7): if (j, k) in Gdict.keys(): - Gsum = Gsum + Gdict[(j, k)] * ctau ** j * cpi ** k + Gsum = Gsum + Gdict[(j, k)] * ctau**j * cpi**k return Gsum diff --git a/pytzer/unsymmetrical.py b/pytzer/unsymmetrical.py index 68608627..cbd90e3a 100644 --- a/pytzer/unsymmetrical.py +++ b/pytzer/unsymmetrical.py @@ -47,7 +47,7 @@ def P75_eq46(x): Jsum = np.zeros_like(x) for k in range(6): Jsum = Jsum + C[k] * x ** -(k + 1) - return -(x ** 2) * np.log(x) * np.exp(-10 * x ** 2) / 6 + 1 / Jsum + return -(x**2) * np.log(x) * np.exp(-10 * x**2) / 6 + 1 / Jsum @jax.jit @@ -124,10 +124,10 @@ def _Harvie_raw(x): x_vec = np.full_like(akI, x) ak = np.where(x_vec < 1, akI, akII) z = np.where( - x < 1, 4 * x ** 0.2 - 2, 40 / 9 * x ** -0.1 - 22 / 9 # Eq. (B-21) # Eq. (B-25) + x < 1, 4 * x**0.2 - 2, 40 / 9 * x**-0.1 - 22 / 9 # Eq. (B-21) # Eq. (B-25) ) dz_dx = np.where( - x < 1, 4 * x ** -0.8 / 5, -4 * x ** -1.1 / 9 # Eq. (B-22) # Eq. (B-26) + x < 1, 4 * x**-0.8 / 5, -4 * x**-1.1 / 9 # Eq. (B-22) # Eq. (B-26) ) b2, b1, b0 = 0.0, 0.0, 0.0 d2, d1, d0 = 0.0, 0.0, 0.0 diff --git a/pytzer4/__init__.py b/pytzer4/__init__.py new file mode 100644 index 00000000..4a731f55 --- /dev/null +++ b/pytzer4/__init__.py @@ -0,0 +1,156 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +"""Pitzer model for chemical activities in aqueous solutions.""" +from . import ( + constants, + debyehueckel, + dissociation, + equilibrate, + io, + libraries, + matrix, + meta, + model, + parameters, + plot, + properties, + teos10, + unsymmetrical, +) + +__all__ = [ + "constants", + "debyehueckel", + "dissociation", + "equilibrate", + "io", + "libraries", + "matrix", + "meta", + "model", + "parameters", + "plot", + "properties", + "teos10", + "unsymmetrical", +] +__version__ = meta.version +__author__ = "Matthew P. Humphreys" + +from copy import deepcopy +from numpy import full_like, nan +from numpy import any as np_any + + +def blackbox(filename, prmlib=libraries.MIAMI, savefile=True): + """Import a CSV file with molality data, calculate all activity + coefficients, and save results to a new CSV file. + """ + # Import test dataset + mols, ions, tempK, pres = io.getmols(filename) + prmlib = deepcopy(prmlib) + prmlib.add_zeros(ions) # just in case + # Separate out zero ionic strengths + zs = properties.charges(ions)[0] + I = model.Istr(mols, zs) + Gex_nRT = full_like(tempK, nan) + osm = full_like(tempK, nan) + aw = full_like(tempK, nan) + acfs = full_like(mols, nan) + L = I > 0 + nargsL = (mols[:, L], ions, tempK[L], pres[L], prmlib) + nargsLx = (mols[:, ~L], ions, tempK[~L], pres[~L], prmlib) + # Do calculations + print("Calculating excess Gibbs energies...") + Gex_nRT[L] = model.Gex_nRT(*nargsL) + if np_any(~L): + Gex_nRT[~L] = model.Gex_nRT(*nargsLx, Izero=True) + print("Calculating osmotic coefficients...") + osm[L] = model.osm(*nargsL) + if np_any(~L): + osm[~L] = model.osm(*nargsLx, Izero=True) + print("Calculating water activity...") + aw[L] = model.aw(*nargsL) + if np_any(~L): + aw[~L] = model.aw(*nargsLx, Izero=True) + print("Calculating activity coefficients...") + acfs[:, L] = model.acfs(*nargsL) + if np_any(~L): + acfs[:, ~L] = model.acfs(*nargsLx, Izero=True) + # Save results, unless requested not to + if savefile: + filestem = filename.replace(".csv", "") + io.saveall(filestem + "_py.csv", mols, ions, tempK, pres, osm, aw, acfs) + print("Finished!") + return mols, ions, tempK, pres, prmlib, Gex_nRT, osm, aw, acfs + + +def blackbox_equilibrate(filename, prmlib=libraries.MIAMI, savefile=True): + """Import a CSV file with molality data, solve for equilibrium speciation, + calculate all activity coefficients, and save results to a new CSV file. + """ + # Import test dataset + tots, fixmols, eles, fixions, tempK, pres = io.gettots(filename) + allions = properties.getallions(eles, fixions) + prmlib = deepcopy(prmlib) + prmlib.add_zeros(allions) # just in case + # Solve for equilibria + q = 0 + for ele in eles: + q += len(properties._eq2ions[ele]) - 1 + eqstate_guess = [0.0 for _ in range(q)] + if q == 0: + eqstate_guess = [ + 30.0, + ] + else: + eqstate_guess.append(30.0) + allmols, allions, eqstates = equilibrate.solveloop( + eqstate_guess, tots, fixmols, eles, fixions, tempK, pres, prmlib=prmlib + ) + # Separate out zero ionic strengths + zs = properties.charges(allions)[0] + I = model.Istr(allmols, zs) + Gex_nRT = full_like(tempK, nan) + osm = full_like(tempK, nan) + aw = full_like(tempK, nan) + acfs = full_like(allmols, nan) + L = I > 0 + nargsL = (allmols[:, L], allions, tempK[L], pres[L], prmlib) + nargsLx = (allmols[:, ~L], allions, tempK[~L], pres[~L], prmlib) + # Do calculations + print("Calculating excess Gibbs energies...") + Gex_nRT[L] = model.Gex_nRT(*nargsL) + if np_any(~L): + Gex_nRT[~L] = model.Gex_nRT(*nargsLx, Izero=True) + print("Calculating osmotic coefficients...") + osm[L] = model.osm(*nargsL) + if np_any(~L): + osm[~L] = model.osm(*nargsLx, Izero=True) + print("Calculating water activity...") + aw[L] = model.aw(*nargsL) + if np_any(~L): + aw[~L] = model.aw(*nargsLx, Izero=True) + print("Calculating activity coefficients...") + acfs[:, L] = model.acfs(*nargsL) + if np_any(~L): + acfs[:, ~L] = model.acfs(*nargsLx, Izero=True) + # Save results, unless requested not to + if savefile: + filestem = filename.replace(".csv", "") + io.saveall(filestem + "_py.csv", allmols, allions, tempK, pres, osm, aw, acfs) + print("Finished!") + return (allmols, allions, tempK, pres, prmlib, Gex_nRT, osm, aw, acfs, eqstates) diff --git a/pytzer4/constants.py b/pytzer4/constants.py new file mode 100644 index 00000000..89366441 --- /dev/null +++ b/pytzer4/constants.py @@ -0,0 +1,21 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Define universal constants.""" +from autograd.numpy import float_ + +# Set constant values +Mw = float_(0.018015) # Molar mass of water in kg/mol [PubChem] +R = float_(8.3144598) # Universal gas constant in J/(mol*K) [CODATA] +F = float_(96485.33289) # Faraday constant in C/mol [CODATA] +b = float_(1.2) # Pitzer model coeff. in sqrt(kg/mol) [Pitzer 1991] +Patm_bar = float_(1.01325) # Atmospheric pressure in bar/atm +Tzero = float_(273.15) # Zero degrees Celsius in K +NA = float_(6.0221367e23) # Avogadro's constant in 1/mol + +# Unit conversion multipliers +cal2J = float_(4.184) # ENERGY: calorie to Joule +atm2Pa = float_(101325) # PRESSURE: atmosphere to Pascal +Torr2Pa = atm2Pa / 760 # PRESSURE: Torr to Pascal +mmHg2Pa = float_(133.322387415) # PRESSURE: mmHg to Pascal +dbar2Pa = 1e4 # PRESSURE: dbar to Pascal +dbar2MPa = 1e-2 # PRESSURE: dbar to mega-Pascal diff --git a/pytzer4/debyehueckel.py b/pytzer4/debyehueckel.py new file mode 100644 index 00000000..fb8716f9 --- /dev/null +++ b/pytzer4/debyehueckel.py @@ -0,0 +1,202 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Calculate Debye-Hueckel limiting slopes.""" +from autograd.numpy import exp, float_, logical_and, pi, sqrt +from . import teos10 +from .parameters import M88_eq13 +from .constants import NA, dbar2Pa, dbar2MPa + + +def Aosm_M88(tempK, pres): + """From Moller (1988).""" + Aosm = M88_eq13( + tempK, + float_( + [ + 3.36901532e-1, + -6.32100430e-4, + 9.14252359e00, + -1.35143986e-2, + 2.26089488e-3, + 1.92118597e-6, + 4.52586464e1, + 0, + ] + ), + ) + valid = logical_and(logical_and(tempK >= 273.15, tempK <= 573.15), pres == 10.1325) + return Aosm, valid + + +def Aosm_CRP94(tempK, pres): + """From Clegg et al. (1994) Appendix II.""" + # This function is long-winded to make it autograd-able w.r.t. temperature + # Transform temperature: + X = (2 * tempK - 607.3) / 139 + # Set parameters - CRP94 Table 11: + a_Aosm = [ + 0.797256081240 / 2, + 0.573389669896e-1, + 0.977632177788e-3, + 0.489973732417e-2, + -0.313151784342e-2, + 0.179145971002e-2, + -0.920584241844e-3, + 0.443862726879e-3, + -0.203661129991e-3, + 0.900924147948e-4, + -0.388189392385e-4, + 0.164245088592e-4, + -0.686031972567e-5, + 0.283455806377e-5, + -0.115641433004e-5, + 0.461489672579e-6, + -0.177069754948e-6, + 0.612464488231e-7, + -0.175689013085e-7, + ] + # Set up T "matrix" - CRP94 Eq. (AII2): + Tmx00 = 1 + Tmx01 = X + Tmx02 = 2 * X * Tmx01 - Tmx00 + Tmx03 = 2 * X * Tmx02 - Tmx01 + Tmx04 = 2 * X * Tmx03 - Tmx02 + Tmx05 = 2 * X * Tmx04 - Tmx03 + Tmx06 = 2 * X * Tmx05 - Tmx04 + Tmx07 = 2 * X * Tmx06 - Tmx05 + Tmx08 = 2 * X * Tmx07 - Tmx06 + Tmx09 = 2 * X * Tmx08 - Tmx07 + Tmx10 = 2 * X * Tmx09 - Tmx08 + Tmx11 = 2 * X * Tmx10 - Tmx09 + Tmx12 = 2 * X * Tmx11 - Tmx10 + Tmx13 = 2 * X * Tmx12 - Tmx11 + Tmx14 = 2 * X * Tmx13 - Tmx12 + Tmx15 = 2 * X * Tmx14 - Tmx13 + Tmx16 = 2 * X * Tmx15 - Tmx14 + Tmx17 = 2 * X * Tmx16 - Tmx15 + Tmx18 = 2 * X * Tmx17 - Tmx16 + # Solve for Aosm - CRP94 (E.AII1): + Aosm = ( + Tmx00 * a_Aosm[0] + + Tmx01 * a_Aosm[1] + + Tmx02 * a_Aosm[2] + + Tmx03 * a_Aosm[3] + + Tmx04 * a_Aosm[4] + + Tmx05 * a_Aosm[5] + + Tmx06 * a_Aosm[6] + + Tmx07 * a_Aosm[7] + + Tmx08 * a_Aosm[8] + + Tmx09 * a_Aosm[9] + + Tmx10 * a_Aosm[10] + + Tmx11 * a_Aosm[11] + + Tmx12 * a_Aosm[12] + + Tmx13 * a_Aosm[13] + + Tmx14 * a_Aosm[14] + + Tmx15 * a_Aosm[15] + + Tmx16 * a_Aosm[16] + + Tmx17 * a_Aosm[17] + + Tmx18 * a_Aosm[18] + ) + # Validity range: + valid = logical_and(logical_and(tempK >= 234.15, tempK <= 373.15), pres == 10.1325) + return Aosm, valid + + +def Aosm_MarChemSpec25(tempK, pres): + """For 298.15 K; value from Pitzer (1991) Chapter 3 Table 1 (page 99).""" + Aosm = 0.3915 + valid = logical_and(tempK == 298.15, pres == 10.1325) + return Aosm, valid + + +def Aosm_MarChemSpec05(tempK, pres): + """For 278.15 K; value from FastPitz.""" + Aosm = 0.3792 + valid = logical_and(tempK == 278.15, pres == 10.1325) + return Aosm, valid + + +def Aosm_MarChemSpec(tempK, pres): + """Following CRP94, but with a correction to match AW90.""" + Aosm = Aosm_CRP94(tempK, pres)[0] + 2.99e-8 + valid = logical_and(logical_and(tempK >= 234.15, tempK <= 373.15), pres == 10.1325) + return Aosm, valid + + +def _gm1drho(tempK, presMPa): + """AW90 Eq. (3): (g - 1) * rho.""" + # Produces values like in AW90 Fig. 1 + # tempK in K, pres in MPa + # AW90 Table 2: + b = [ + -4.044525e-2, + 103.6180, + 75.32165, + -23.23778, + -3.548184, + -1246.311, + 263307.7, + -6.928953e-1, + -204.4473, + ] + # AW90 Eq. (3): + gm1drho = ( + b[0] * presMPa / tempK + + b[1] / sqrt(tempK) + + b[2] / (tempK - 215) + + b[3] / sqrt(tempK - 215) + + b[4] / (tempK - 215) ** 0.25 + + exp( + b[5] / tempK + + b[6] / tempK**2 + + b[7] * presMPa / tempK + + b[8] * presMPa / tempK**2 + ) + ) + return gm1drho + + +def _g(tempK, presMPa, rho): + """Calculate g given density.""" + return _gm1drho(tempK, presMPa) * rho + 1 + + +def _D(tempK, presMPa, rho): + """Dielectric constant following Archer's DIEL().""" + # Note that Archer's code uses different values from AW90 just in this + # subroutine (so also different from in Aosm calculation below) + Mw = 18.0153 + al = 1.444e-24 + k = 1.380658e-16 + mu = 1.84e-18 + A = ( + (al + _g(tempK, presMPa, rho) * mu**2 / (3 * k * tempK)) + * 4 + * pi + * NA + * rho + / (3 * Mw) + ) + return (1 + 9 * A + 3 * sqrt(9 * A**2 + 2 * A + 1)) / 4 + + +def Aosm_AW90(tempK, pres): + """D-H limiting slope for osmotic coefficient, following dhll.for.""" + presPa = pres * dbar2Pa + presMPa = pres * dbar2MPa + # Constants from Table 1 footnote: + e = 1.6021773e-19 # charge on an electron in C + E0 = 8.8541878e-12 # permittivity of vacuum in C**2/(J*m) + # Constants from Table 2 footnote: + k = 1.380658e-23 # Boltzmann constant in J/K + rho = teos10.rho(tempK, presPa) * 1e-3 + Aosm = ( + sqrt(2e-3 * pi * rho * NA) + * (100 * e**2 / (4 * pi * _D(tempK, presMPa, rho) * E0 * k * tempK)) ** 1.5 + / 3 + ) + valid = logical_and( + logical_and(tempK >= 270.5 - presPa * 7.43e-8, tempK <= 313.15), + logical_and(presPa >= 100, presPa <= 1e8), + ) + return Aosm, valid diff --git a/pytzer4/dissociation.py b/pytzer4/dissociation.py new file mode 100644 index 00000000..8737b5fe --- /dev/null +++ b/pytzer4/dissociation.py @@ -0,0 +1,129 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Evaluate thermodynamic equilibrium constants.""" +from autograd.numpy import log, log10 + + +def HSO4_CRP94_extra(tempK): + """Bisulfate dissociation: CRP94 Eq. (21) with extra digits on constant + term (S.L. Clegg, pers. comm, 7 Feb 2019). + """ + log10kHSO4 = ( + 562.694864456 + - 102.5154 * log(tempK) + - 1.117033e-4 * tempK**2 + + 0.2477538 * tempK + - 13273.75 / tempK + ) + lnkHSO4 = log10kHSO4 * log(10) + return lnkHSO4 + + +def HSO4_CRP94(tempK): + """CRP94 Eq. (21) without extra digits on constant term.""" + # Matches Clegg's model [2019-07-02] + log10kHSO4 = ( + 562.69486 + - 102.5154 * log(tempK) + - 1.117033e-4 * tempK**2 + + 0.2477538 * tempK + - 13273.75 / tempK + ) + lnkHSO4 = log10kHSO4 * log(10) + return lnkHSO4 + + +def trisH_BH64(tempK): + """TrisH+ dissociation following BH64 Eq. (3).""" + # Matches Clegg's model [2019-07-02] + log10ktrisH = -(2981.4 / tempK - 3.5888 + 0.005571 * tempK) + lnktrisH = log10ktrisH * log(10) + return lnktrisH + + +def rhow_K75(tempK): + """Water density in g/cm**3 following Kell (1975) J. Chem. Eng. Data 20(1), + 97-105. + """ + # Matches Clegg's model [2019-07-02] + tempC = tempK - 273.15 + return ( + 0.99983952 + + 16.945176e-3 * tempC + - 7.9870401e-6 * tempC**2 + - 46.170461e-9 * tempC**3 + + 105.56302e-12 * tempC**4 + - 280.54253e-15 * tempC**5 + ) / (1 + 16.879850e-3 * tempC) + + +def H2O_M79(tempK): + """Water dissociation following M79.""" + # MP98 says this is HO58 refitted by M79 + return 148.9802 - 13847.26 / tempK - 23.6521 * log(tempK) + + +def H2O_M88(tempK): + """Water dissociation following M88.""" + return ( + 1.04031130e3 + + 4.86092851e-1 * tempK + - 3.26224352e4 / tempK + - 1.90877133e2 * log(tempK) + - 5.35204850e-1 / (tempK - 263) + - 2.32009393e-4 * tempK**2 + + 5.20549183e1 / (680 - tempK) + ) + + +def H2O_MF(tempK): + """Marshall and Frank, J. Phys. Chem. Ref. Data 10, 295-304.""" + # Matches Clegg's model [2019-07-02] + log10kH2O = ( + -4.098 + - 3.2452e3 / tempK + + 2.2362e5 / tempK**2 + - 3.984e7 / tempK**3 + + (1.3957e1 - 1.2623e3 / tempK + 8.5641e5 / tempK**2) * log10(rhow_K75(tempK)) + ) + lnkH2O = log10kH2O * log(10) + return lnkH2O + + +def MgOH_CW91_ln(tempK): + """MgOH+ formation following CW91 Eq. (244) [p392].""" + return 8.9108 - 1155 / tempK + + +def MgOH_CW91(tempK): + """MgOH+ formation following CW91 in log10 and then converted.""" + # Matches Clegg's model [2019-07-02] + log10kMg = 3.87 - 501.5 / tempK + lnkMg = log10kMg * log(10) + return lnkMg + + +def MgOH_MP98(tempK): + """MgOH+ formation following MP98.""" + log10kMg = 3.87 - 501.6 / tempK + lnkMg = log10kMg * log(10) + return lnkMg + + +def MP98_eq23(tempK, A, B, C, D): + return A + B / tempK + C * log(tempK) + D * tempK + + +def H2CO3_MP98(tempK): + """H2CO3 dissociation [MP98 following M79].""" + return MP98_eq23(tempK, 290.9097, -14554.21, -45.0575, 0) + + +def HCO3_MP98(tempK): + """HCO3 dissociation [MP98 following M79].""" + return MP98_eq23(tempK, 207.6548, -11843.79, -33.6485, 0) + + +def BOH3_M79(tempK): + """Boric acid dissociation [MP98 following M79].""" + return MP98_eq23(tempK, 148.0248, -8966.901, -24.4344, 0) diff --git a/pytzer4/equilibrate.py b/pytzer4/equilibrate.py new file mode 100644 index 00000000..83e7a7b3 --- /dev/null +++ b/pytzer4/equilibrate.py @@ -0,0 +1,505 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Solve for the equilibrium state.""" +from copy import deepcopy +from scipy.optimize import minimize +from autograd import elementwise_grad as egrad +from autograd.numpy import array, exp, full, full_like, log, nan, sqrt, transpose +from autograd.numpy import sum as np_sum +from . import libraries, matrix, properties + + +def _sig01(x): + """Numerically stable logistic sigmoid function.""" + if x < 0: + return exp(x) / (1 + exp(x)) + else: + return 1 / (1 + exp(-x)) + + +def _varmols(eqstate, tots1, fixmols1, eles, fixions, fixcharges): + """Calculate variable molalities from solver targets.""" + # Seems long-winded, but it's necessary for Autograd + q = 0 + if len(eles) > 0: + for e, ele in enumerate(eles): + if ele == "t_HSO4": + tHSO4 = tots1[e] + if tHSO4 > 0: + aHSO4 = _sig01(eqstate[q]) + mHSO4 = tHSO4 * aHSO4 + mSO4 = tHSO4 - mHSO4 + else: + mHSO4 = 0.0 + mSO4 = 0.0 + q += 1 + elif ele == "t_Mg": + tMg = tots1[e] + if tMg > 0: + aMgOH = _sig01(eqstate[q]) + mMg = tMg * aMgOH + mMgOH = tMg - mMg + else: + mMg = 0.0 + mMgOH = 0.0 + q += 1 + elif ele == "t_trisH": + ttrisH = tots1[e] + if ttrisH > 0: + atrisH = _sig01(eqstate[q]) + mtrisH = ttrisH * atrisH + mtris = ttrisH - mtrisH + else: + mtrisH = 0.0 + mtris = 0.0 + q += 1 + elif ele == "t_H2CO3": + tH2CO3 = tots1[e] + if tH2CO3 > 0: + aH2CO3 = _sig01(eqstate[q]) + aHCO3 = _sig01(eqstate[q + 1]) + mCO2 = tH2CO3 * aH2CO3 + mHCO3 = (tH2CO3 - mCO2) * aHCO3 + mCO3 = tH2CO3 - mCO2 - mHCO3 + else: + mCO2 = 0.0 + mHCO3 = 0.0 + mCO3 = 0.0 + q += 2 + elif ele == "t_BOH3": + tBOH3 = tots1[e] + if tBOH3 > 0: + aBOH3 = _sig01(eqstate[q]) + mBOH3 = tBOH3 * aBOH3 + mBOH4 = tBOH3 - mBOH3 + else: + mBOH3 = 0.0 + mBOH4 = 0.0 + q += 1 + if "t_HSO4" not in eles: + mHSO4 = 0.0 + mSO4 = 0.0 + if "t_Mg" not in eles: + mMg = 0.0 + mMgOH = 0.0 + if "t_trisH" not in eles: + mtrisH = 0.0 + mtris = 0.0 + if "t_H2CO3" not in eles: + mCO2 = 0.0 + mHCO3 = 0.0 + mCO3 = 0.0 + if "t_BOH3" not in eles: + mBOH3 = 0.0 + mBOH4 = 0.0 + else: + mHSO4 = 0.0 + mSO4 = 0.0 + mMg = 0.0 + mMgOH = 0.0 + mtrisH = 0.0 + mtris = 0.0 + mCO2 = 0.0 + mHCO3 = 0.0 + mCO3 = 0.0 + mBOH3 = 0.0 + mBOH4 = 0.0 + zbHSO4 = -mHSO4 - 2 * mSO4 + zbMg = 2 * mMg + mMgOH + zbtrisH = mtrisH + zbH2CO3 = -(mHCO3 + 2 * mCO3) + zbBOH3 = -mBOH4 + if len(fixcharges) == 0: + zbfixed = 0.0 + else: + zbfixed = np_sum(fixmols1 * fixcharges) + zbalance = zbfixed + zbHSO4 + zbMg + zbtrisH + zbH2CO3 + zbBOH3 + if len(eqstate) == q + 1: + dissociatedH2O = exp(-eqstate[-1]) + elif len(eqstate) == q: + dissociatedH2O = 0.0 + else: + print("WARNING: eqstate and tots1 dimensions are not compatible!") + mOH = (zbalance + sqrt(zbalance**2 + dissociatedH2O)) / 2 + mH = mOH - zbalance + return ( + mH, + mOH, + mHSO4, + mSO4, + mMg, + mMgOH, + mtris, + mtrisH, + mCO2, + mHCO3, + mCO3, + mBOH3, + mBOH4, + ) + + +def _GibbsH2O(lnaw, mH, lnacfH, mOH, lnacfOH, lnkH2O): + """Evaluate the Gibbs energy for water dissocation.""" + return lnacfH + log(mH) + lnacfOH + log(mOH) - lnaw - lnkH2O + + +def _GibbsHSO4(mH, lnacfH, mSO4, lnacfSO4, mHSO4, lnacfHSO4, lnkHSO4): + """Evaluate the Gibbs energy for the bisulfate-sulfate equilibrium.""" + return lnacfH + log(mH) + lnacfSO4 + log(mSO4) - lnacfHSO4 - log(mHSO4) - lnkHSO4 + + +def _GibbsMg(mMg, lnacfMg, mMgOH, lnacfMgOH, mOH, lnacfOH, lnkMg): + """Evaluate the Gibbs energy for the magnesium-MgOH+ equilibrium.""" + return lnacfMg + log(mMg) + lnacfOH + log(mOH) - lnacfMgOH - log(mMgOH) + lnkMg + + +def _GibbstrisH(mH, lnacfH, mtris, lnacftris, mtrisH, lnacftrisH, lnktrisH): + """Evaluate the Gibbs energy for the tris-trisH+ equilibrium.""" + return ( + lnacftris + log(mtris) - lnacftrisH - log(mtrisH) + lnacfH + log(mH) - lnktrisH + ) + + +def _GibbsH2CO3(lnaw, mH, lnacfH, mHCO3, lnacfHCO3, mCO2, lnacfCO2, lnkH2CO3): + """Evaluate the Gibbs energy for the H2CO3-bicarbonate equilibrium.""" + return ( + lnacfH + + log(mH) + + lnacfHCO3 + + log(mHCO3) + - lnacfCO2 + - log(mCO2) + - lnaw + - lnkH2CO3 + ) + + +def _GibbsHCO3(mH, lnacfH, mHCO3, lnacfHCO3, mCO3, lnacfCO3, lnkHCO3): + """Evaluate the Gibbs energy for the bicarbonate-carbonate equilibrium.""" + return lnacfH + log(mH) + lnacfCO3 + log(mCO3) - lnacfHCO3 - log(mHCO3) - lnkHCO3 + + +def _GibbsBOH3(lnaw, lnacfBOH4, mBOH4, lnacfBOH3, mBOH3, lnacfH, mH, lnkBOH3): + """Evaluate the Gibbs energy for the boric acid equilibrium.""" + return ( + lnacfBOH4 + + log(mBOH4) + + lnacfH + + log(mH) + - lnacfBOH3 + - log(mBOH3) + - lnaw + - lnkBOH3 + ) + + +def _GibbsComponents( + eqstate, + tots1, + fixmols1, + eles, + allions, + fixions, + fixcharges, + allmxs, + lnks, + ideal=False, +): + """Evaluate the Gibbs energy for each component equilibrium.""" + ( + mH, + mOH, + mHSO4, + mSO4, + mMg, + mMgOH, + mtris, + mtrisH, + mCO2, + mHCO3, + mCO3, + mBOH3, + mBOH4, + ) = _varmols(eqstate, tots1, fixmols1, eles, fixions, fixcharges) + allmols = deepcopy(fixmols1) + # The order in which molality values are added to allmols within each + # equilibrium in the following statements MUST comply with the order in + # which the corresponding ions were added to allions by the function + # pytzer.properties.getallions, which is defined by their order in the + # entries of the pytzer.properties._eq2ions dict. + q = 0 + for ele in eles: + if ele == "t_HSO4": + allmols = [*allmols, mHSO4, mSO4] + lnkHSO4 = lnks[q] + q += 1 + elif ele == "t_Mg": + allmols = [*allmols, mMg, mMgOH] + lnkMg = lnks[q] + q += 1 + elif ele == "t_trisH": + allmols = [*allmols, mtrisH, mtris] + lnktrisH = lnks[q] + q += 1 + elif ele == "t_H2CO3": + allmols = [*allmols, mCO2, mHCO3, mCO3] + lnkH2CO3 = lnks[q] + lnkHCO3 = lnks[q + 1] + q += 2 + elif ele == "t_BOH3": + allmols = [*allmols, mBOH3, mBOH4] + lnkBOH3 = lnks[q] + q += 1 + allmols = array([[*allmols, mH, mOH]]) + solveH2O = len(eqstate) == q + 1 + # Get activities: + if ideal: + lnaw = 0.0 + lnacfH = 0.0 + lnacfOH = 0.0 + lnacfHSO4 = 0.0 + lnacfSO4 = 0.0 + lnacfMg = 0.0 + lnacfMgOH = 0.0 + lnacftris = 0.0 + lnacftrisH = 0.0 + lnacfCO2 = 0.0 + lnacfHCO3 = 0.0 + lnacfCO3 = 0.0 + lnacfBOH3 = 0.0 + lnacfBOH4 = 0.0 + else: + lnaw = matrix.lnaw(allmols, allmxs) + lnacfs = matrix.ln_acfs(allmols, allmxs) + lnacfH = lnacfs[allions == "H"] + lnacfOH = lnacfs[allions == "OH"] + lnacfHSO4 = lnacfs[allions == "HSO4"] + lnacfSO4 = lnacfs[allions == "SO4"] + lnacfMg = lnacfs[allions == "Mg"] + lnacfMgOH = lnacfs[allions == "MgOH"] + lnacftris = lnacfs[allions == "tris"] + lnacftrisH = lnacfs[allions == "trisH"] + lnacfCO2 = lnacfs[allions == "CO2"] + lnacfHCO3 = lnacfs[allions == "HCO3"] + lnacfCO3 = lnacfs[allions == "CO3"] + lnacfBOH3 = lnacfs[allions == "BOH3"] + lnacfBOH4 = lnacfs[allions == "BOH4"] + # Evaluate equilibrium states: + if solveH2O: + lnkH2O = lnks[-1] + gH2O = _GibbsH2O(lnaw, mH, lnacfH, mOH, lnacfOH, lnkH2O) + else: + gH2O = 0.0 + if len(eles) > 0: + if tots1[eles == "t_HSO4"] > 0: + gHSO4 = _GibbsHSO4(mH, lnacfH, mSO4, lnacfSO4, mHSO4, lnacfHSO4, lnkHSO4) + else: + gHSO4 = 0.0 + if tots1[eles == "t_Mg"] > 0: + gMg = _GibbsMg(mMg, lnacfMg, mMgOH, lnacfMgOH, mOH, lnacfOH, lnkMg) + else: + gMg = 0.0 + if tots1[eles == "t_trisH"] > 0: + gtrisH = _GibbstrisH( + mH, lnacfH, mtris, lnacftris, mtrisH, lnacftrisH, lnktrisH + ) + else: + gtrisH = 0.0 + if tots1[eles == "t_H2CO3"] > 0: + gH2CO3 = _GibbsH2CO3( + lnaw, mH, lnacfH, mHCO3, lnacfHCO3, mCO2, lnacfCO2, lnkH2CO3 + ) + gHCO3 = _GibbsHCO3(mH, lnacfH, mHCO3, lnacfHCO3, mCO3, lnacfCO3, lnkHCO3) + else: + gH2CO3 = 0.0 + gHCO3 = 0.0 + if tots1[eles == "t_BOH3"] > 0: + gBOH3 = _GibbsBOH3( + lnaw, lnacfBOH4, mBOH4, lnacfBOH3, mBOH3, lnacfH, mH, lnkBOH3 + ) + else: + gBOH3 = 0.0 + else: + gHSO4 = 0.0 + gMg = 0.0 + gtrisH = 0.0 + gH2CO3 = 0.0 + gHCO3 = 0.0 + gBOH3 = 0.0 + return gH2O, gHSO4, gMg, gtrisH, gH2CO3, gHCO3, gBOH3 + + +def _Gibbs( + eqstate, + tots1, + fixmols1, + eles, + allions, + fixions, + fixcharges, + allmxs, + lnks1, + ideal=False, +): + """Evaluate the total Gibbs energy to be minimised for all equilibria.""" + gH2O, gHSO4, gMg, gtrisH, gH2CO3, gHCO3, gBOH3 = _GibbsComponents( + eqstate, + tots1, + fixmols1, + eles, + allions, + fixions, + fixcharges, + allmxs, + lnks1, + ideal, + ) + return ( + gH2O**2 + + gHSO4**2 + + gMg**2 + + gtrisH**2 + + gH2CO3**2 + + gHCO3**2 + + gBOH3**2 + ) + + +_GibbsGrad = egrad(_Gibbs) + + +def solve( + eqstate_guess, tots1, fixmols1, eles, allions, fixions, allmxs, lnks1, ideal=False +): + """Solve for the solution's equilibrium state.""" + fixcharges = transpose(properties.charges(fixions)[0]) + Gargs = (tots1, fixmols1, eles, allions, fixions, fixcharges, allmxs, lnks1, ideal) + eqstate = minimize( + lambda eqstate: _Gibbs(eqstate, *Gargs), + eqstate_guess, + method="BFGS", + jac=lambda eqstate: _GibbsGrad(eqstate, *Gargs), + ) + return eqstate + + +def solvequick(eqstate_guess, tots1, fixmols1, eles, allions, fixions, allmxs, lnks1): + """Solve ideal case first to speed up computation.""" + Sargs = (tots1, fixmols1, eles, allions, fixions, allmxs, lnks1) + eqstate_ideal = solve(eqstate_guess, *Sargs, ideal=True)["x"] + eqstate = solve(eqstate_ideal, *Sargs, ideal=False) + return eqstate + + +def _oosetup(eqstate_guess, tots, eles, fixions, tempK, pres, prmlib): + """Prepare for solveloop and solvepool.""" + eqstates = full((len(tempK), len(eqstate_guess)), 0.0) + allions = properties.getallions(eles, fixions) + allmols = full((len(tempK), len(allions)), 0.0) + lnks = full((len(eqstate_guess), len(tempK)), nan) + q = 0 + for ele in eles: + if ele == "t_HSO4": + lnks[q] = prmlib.lnk["HSO4"](tempK) + q += 1 + elif ele == "t_Mg": + lnks[q] = prmlib.lnk["MgOH"](tempK) + q += 1 + elif ele == "t_trisH": + lnks[q] = prmlib.lnk["trisH"](tempK) + q += 1 + elif ele == "t_H2CO3": + lnks[q] = prmlib.lnk["H2CO3"](tempK) + lnks[q + 1] = prmlib.lnk["HCO3"](tempK) + q += 2 + elif ele == "t_BOH3": + lnks[q] = prmlib.lnk["BOH3"](tempK) + q += 1 + if len(eqstate_guess) == q + 1: + lnks[-1] = prmlib.lnk["H2O"](tempK) + return eqstates, allmols, allions, lnks + + +def solveloop( + eqstate_guess, tots, fixmols, eles, fixions, tempK, pres, prmlib=libraries.Seawater +): + """Run solver through a loop of input data.""" + eqstates, allmols, allions, lnks = _oosetup( + eqstate_guess, tots, eles, fixions, tempK, pres, prmlib + ) + for L in range(len(tempK)): + print("Solving {} of {}...".format(L + 1, len(tempK))) + allmxs = matrix.assemble(allions, array([tempK[L]]), array([pres[L]]), prmlib) + if len(eles) > 0: + tots1 = tots[:, L] + else: + tots1 = tots + if len(fixions) > 0: + fixmols1 = fixmols[:, L] + else: + fixmols1 = fixmols + lnks1 = lnks[:, L] + Largs = (eqstate_guess, tots1, fixmols1, eles, allions, fixions, allmxs, lnks1) + if L == 0: + eqstates[L] = solvequick(*Largs)["x"] + else: + eqstates[L] = solve(*Largs)["x"] + eqstate_guess = eqstates[L] + allmols[L] = eqstate2mols(eqstates[L], tots1, fixmols1, eles, fixions)[0] + print("Solving complete!") + return transpose(allmols), allions, eqstates + + +def eqstate2mols(eqstate, tots1, fixmols1, eles, fixions): + """Convert eqstate solution to arrays required for Pytzer functions.""" + fixcharges = transpose(properties.charges(fixions)[0]) + ( + mH, + mOH, + mHSO4, + mSO4, + mMg, + mMgOH, + mtris, + mtrisH, + mCO2, + mHCO3, + mCO3, + mBOH3, + mBOH4, + ) = _varmols(eqstate, tots1, fixmols1, eles, fixions, fixcharges) + allions = properties.getallions(eles, fixions) + allmols = full_like(allions, 0.0, dtype="float64") + for i, ion in enumerate(allions): + if len(fixions) > 0: + if ion in fixions: + allmols[i] = fixmols1[fixions == ion] + if ion not in fixions: + if ion == "H": + allmols[i] = mH + elif ion == "OH": + allmols[i] = mOH + elif ion == "HSO4": + allmols[i] = mHSO4 + elif ion == "SO4": + allmols[i] = mSO4 + elif ion == "Mg": + allmols[i] = mMg + elif ion == "MgOH": + allmols[i] = mMgOH + elif ion == "tris": + allmols[i] = mtris + elif ion == "trisH": + allmols[i] = mtrisH + elif ion == "CO2": + allmols[i] = mCO2 + elif ion == "HCO3": + allmols[i] = mHCO3 + elif ion == "CO3": + allmols[i] = mCO3 + elif ion == "BOH3": + allmols[i] = mBOH3 + elif ion == "BOH4": + allmols[i] = mBOH4 + return allmols, allions diff --git a/pytzer4/io.py b/pytzer4/io.py new file mode 100644 index 00000000..aca9aaee --- /dev/null +++ b/pytzer4/io.py @@ -0,0 +1,145 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Import solution composition data, and export the results.""" +from autograd.numpy import ( + array, + concatenate, + genfromtxt, + logical_and, + nan_to_num, + savetxt, + shape, + transpose, + vstack, +) +from autograd.numpy import sum as np_sum +from .properties import _ele2ionmass, _ion2mass + + +def getmols(filename, delimiter=",", skip_top=0): + """Import molality, temperature and pressure data from a CSV file, where + all ionic concentrations are defined (i.e. no equilibration).""" + data = genfromtxt(filename, delimiter=delimiter, skip_header=skip_top + 1) + if len(shape(data)) == 1: + data = array( + [ + data, + ] + ) + head = genfromtxt( + filename, + delimiter=delimiter, + dtype="U", + skip_header=skip_top, + skip_footer=shape(data)[0], + ) + nan_to_num(data, copy=False) + TL = head == "tempK" + PL = head == "pres" + mols = transpose(data[:, logical_and(~TL, ~PL)]) + ions = head[logical_and(~TL, ~PL)] + tempK = data[:, TL].ravel() + pres = data[:, PL].ravel() + return mols, ions, tempK, pres + + +def gettots(filename, delimiter=",", skip_top=0): + """Import molality, temperature and pressure data from a CSV file, where + some total concentrations are defined (i.e. with equilibration).""" + data = genfromtxt(filename, delimiter=delimiter, skip_header=skip_top + 1) + if len(shape(data)) == 1: + data = array( + [ + data, + ] + ) + head = genfromtxt( + filename, + delimiter=delimiter, + dtype="U", + skip_header=skip_top, + skip_footer=shape(data)[0], + ) + nan_to_num(data, copy=False) + TL = head == "tempK" + PL = head == "pres" + tempK = data[:, TL].ravel() + pres = data[:, PL].ravel() + data = data[:, logical_and(~TL, ~PL)].transpose() + head = head[logical_and(~TL, ~PL)] + eles = array([ele for ele in head if "t_" in ele]) + ions = array([ion for ion in head if "t_" not in ion]) + tots = array([tot for i, tot in enumerate(data) if "t_" in head[i]]) + mols = array([mol for i, mol in enumerate(data) if "t_" not in head[i]]) + return tots, mols, eles, ions, tempK, pres + + +def saveall(filename, mols, ions, tempK, pres, osm, aw, acfs): + """Save molality, temperature, pressure, and calculated activity data + to a CSV file. + """ + savetxt( + filename, + concatenate( + ( + vstack(tempK), + vstack(pres), + transpose(mols), + vstack(osm), + vstack(aw), + transpose(acfs), + ), + axis=1, + ), + delimiter=",", + header=",".join( + concatenate( + (["tempK", "pres"], ions, ["osm", "aw"], ["g" + ion for ion in ions]) + ) + ), + comments="", + ) + + +def _u2v(mols, ions, tots, eles): + """Get approximate conversion factor for molinity (mol/kg-solution) to + molality (mol/kg-H2O). + """ + ionmasses = array([_ion2mass[ion] for ion in ions]) * mols.ravel() + elemasses = array([_ion2mass[_ele2ionmass[ele]] for ele in eles]) * tots.ravel() + totalsalts = (np_sum(ionmasses) + np_sum(elemasses)) * 1e-3 # kg + u2v = 1 + totalsalts + return u2v + + +def solution2solvent(mols, ions, tots, eles): + """Roughly convert molinity (mol/kg-solution) to molality (mol/kg-H2O).""" + u2v = _u2v(mols, ions, tots, eles) + mols = mols * u2v + tots = tots * u2v + return mols, tots + + +def solvent2solution(mols, ions, tots, eles): + """Roughly convert molality (mol/kg-H2O) to molinity (mol/kg-solution).""" + u2v = _u2v(mols, ions, tots, eles) + mols = mols / u2v + tots = tots / u2v + return mols, tots + + +def salinity2mols(salinity, MgOH=False): + """Convert salinity (g/kg-sw) to molality for typical seawater, simplified + for the WM13 tris buffer model, following MZF93. + """ + if MgOH: + mols = array([0.44516, 0.01077, 0.01058, 0.56912]) * salinity / 43.189 + ions = array(["Na", "Ca", "K", "Cl"]) + tots = array([0.02926, 0.05518]) * salinity / 43.189 + eles = array(["t_HSO4", "t_Mg"]) + else: + mols = array([0.44516, 0.05518, 0.01077, 0.01058, 0.56912]) * salinity / 43.189 + ions = array(["Na", "Mg", "Ca", "K", "Cl"]) + tots = array([0.02926]) * salinity / 43.189 + eles = array(["t_HSO4"]) + return mols, ions, tots, eles diff --git a/pytzer4/libraries/CRP94.py b/pytzer4/libraries/CRP94.py new file mode 100644 index 00000000..d4f03140 --- /dev/null +++ b/pytzer4/libraries/CRP94.py @@ -0,0 +1,17 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from .. import parameters as prm +from .. import debyehueckel, dissociation, unsymmetrical + +# Clegg et al. (1994). J. Chem. Soc., Faraday Trans. 90, 1875-1894, +# doi:10.1039/FT9949001875 +# System: H-HSO4-SO4 +name = "CRP94" +dh = {"Aosm": debyehueckel.Aosm_CRP94} +bC = {} +bC["H-HSO4"] = prm.bC_H_HSO4_CRP94 +bC["H-SO4"] = prm.bC_H_SO4_CRP94 +theta = {"HSO4-SO4": prm.theta_HSO4_SO4_CRP94} +psi = {"H-HSO4-SO4": prm.psi_H_HSO4_SO4_CRP94} +jfunc = unsymmetrical.P75_eq47 +lnk = {"HSO4": dissociation.HSO4_CRP94} diff --git a/pytzer4/libraries/GM89.py b/pytzer4/libraries/GM89.py new file mode 100644 index 00000000..eb5fd8e4 --- /dev/null +++ b/pytzer4/libraries/GM89.py @@ -0,0 +1,33 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from .. import parameters as prm +from .. import debyehueckel, unsymmetrical + +# Greenberg & Møller (1988). Geochim. Cosmochim. Acta 53, 2503-2518, +# doi:10.1016/0016-7037(89)90124-5 +# System: Na-K-Ca-Cl-SO4 +name = "GM89" +dh = {"Aosm": debyehueckel.Aosm_M88} +bC = {} +bC["Ca-Cl"] = prm.bC_Ca_Cl_GM89 +bC["Ca-SO4"] = prm.bC_Ca_SO4_M88 +bC["K-Cl"] = prm.bC_K_Cl_GM89 +bC["K-SO4"] = prm.bC_K_SO4_GM89 +bC["Na-Cl"] = prm.bC_Na_Cl_M88 +bC["Na-SO4"] = prm.bC_Na_SO4_M88 +theta = {} +theta["Ca-K"] = prm.theta_Ca_K_GM89 +theta["Ca-Na"] = prm.theta_Ca_Na_M88 +theta["K-Na"] = prm.theta_K_Na_GM89 +theta["Cl-SO4"] = prm.theta_Cl_SO4_M88 +psi = {} +psi["Ca-K-Cl"] = prm.psi_Ca_K_Cl_GM89 +psi["Ca-K-SO4"] = prm.psi_Ca_K_SO4_GM89 +psi["Ca-Na-Cl"] = prm.psi_Ca_Na_Cl_M88 +psi["Ca-Na-SO4"] = prm.psi_Ca_Na_SO4_M88 +psi["K-Na-Cl"] = prm.psi_K_Na_Cl_GM89 +psi["K-Na-SO4"] = prm.psi_K_Na_SO4_GM89 +psi["Ca-Cl-SO4"] = prm.psi_Ca_Cl_SO4_M88 +psi["K-Cl-SO4"] = prm.psi_K_Cl_SO4_GM89 +psi["Na-Cl-SO4"] = prm.psi_Na_Cl_SO4_M88 +jfunc = unsymmetrical.Harvie diff --git a/pytzer4/libraries/HMW84.py b/pytzer4/libraries/HMW84.py new file mode 100644 index 00000000..81425256 --- /dev/null +++ b/pytzer4/libraries/HMW84.py @@ -0,0 +1,266 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from .. import parameters as prm +from .. import debyehueckel, unsymmetrical + +name = "HMW84" +dh = {"Aosm": debyehueckel.Aosm_M88} +jfunc = unsymmetrical.Harvie +bC = {} +bC["Na-Cl"] = prm.bC_Na_Cl_HMW84 +bC["Na-SO4"] = prm.bC_Na_SO4_HMW84 +bC["Na-HSO4"] = prm.bC_Na_HSO4_HMW84 +bC["Na-OH"] = prm.bC_Na_OH_HMW84 +bC["Na-HCO3"] = prm.bC_Na_HCO3_HMW84 +bC["Na-CO3"] = prm.bC_Na_CO3_HMW84 +bC["K-Cl"] = prm.bC_K_Cl_HMW84 +bC["K-SO4"] = prm.bC_K_SO4_HMW84 +bC["K-HSO4"] = prm.bC_K_HSO4_HMW84 +bC["K-OH"] = prm.bC_K_OH_HMW84 +bC["K-HCO3"] = prm.bC_K_HCO3_HMW84 +bC["K-CO3"] = prm.bC_K_CO3_HMW84 +bC["Ca-Cl"] = prm.bC_Ca_Cl_HMW84 +bC["Ca-SO4"] = prm.bC_Ca_SO4_HMW84 +bC["Ca-HSO4"] = prm.bC_Ca_HSO4_HMW84 +bC["Ca-OH"] = prm.bC_Ca_OH_HMW84 +bC["Ca-HCO3"] = prm.bC_Ca_HCO3_HMW84 +bC["Ca-CO3"] = prm.bC_Ca_CO3_HMW84 +bC["Mg-Cl"] = prm.bC_Mg_Cl_HMW84 +bC["Mg-SO4"] = prm.bC_Mg_SO4_HMW84 +bC["Mg-HSO4"] = prm.bC_Mg_HSO4_HMW84 +bC["Mg-OH"] = prm.bC_Mg_OH_HMW84 +bC["Mg-HCO3"] = prm.bC_Mg_HCO3_HMW84 +bC["Mg-CO3"] = prm.bC_Mg_CO3_HMW84 +bC["MgOH-Cl"] = prm.bC_MgOH_Cl_HMW84 +bC["MgOH-SO4"] = prm.bC_MgOH_SO4_HMW84 +bC["MgOH-HSO4"] = prm.bC_MgOH_HSO4_HMW84 +bC["MgOH-OH"] = prm.bC_MgOH_OH_HMW84 +bC["MgOH-HCO3"] = prm.bC_MgOH_HCO3_HMW84 +bC["MgOH-CO3"] = prm.bC_MgOH_CO3_HMW84 +bC["H-Cl"] = prm.bC_H_Cl_HMW84 +bC["H-SO4"] = prm.bC_H_SO4_HMW84 +bC["H-HSO4"] = prm.bC_H_HSO4_HMW84 +bC["H-OH"] = prm.bC_H_OH_HMW84 +bC["H-HCO3"] = prm.bC_H_HCO3_HMW84 +bC["H-CO3"] = prm.bC_H_CO3_HMW84 +theta = {} +psi = {} +theta["Cl-SO4"] = prm.theta_Cl_SO4_HMW84 +psi["Na-Cl-SO4"] = prm.psi_Na_Cl_SO4_HMW84 +psi["K-Cl-SO4"] = prm.psi_K_Cl_SO4_HMW84 +psi["Ca-Cl-SO4"] = prm.psi_Ca_Cl_SO4_HMW84 +psi["Mg-Cl-SO4"] = prm.psi_Mg_Cl_SO4_HMW84 +psi["MgOH-Cl-SO4"] = prm.psi_MgOH_Cl_SO4_HMW84 +psi["H-Cl-SO4"] = prm.psi_H_Cl_SO4_HMW84 +theta["Cl-HSO4"] = prm.theta_Cl_HSO4_HMW84 +psi["Na-Cl-HSO4"] = prm.psi_Na_Cl_HSO4_HMW84 +psi["K-Cl-HSO4"] = prm.psi_K_Cl_HSO4_HMW84 +psi["Ca-Cl-HSO4"] = prm.psi_Ca_Cl_HSO4_HMW84 +psi["Mg-Cl-HSO4"] = prm.psi_Mg_Cl_HSO4_HMW84 +psi["MgOH-Cl-HSO4"] = prm.psi_MgOH_Cl_HSO4_HMW84 +psi["H-Cl-HSO4"] = prm.psi_H_Cl_HSO4_HMW84 +theta["Cl-OH"] = prm.theta_Cl_OH_HMW84 +psi["Na-Cl-OH"] = prm.psi_Na_Cl_OH_HMW84 +psi["K-Cl-OH"] = prm.psi_K_Cl_OH_HMW84 +psi["Ca-Cl-OH"] = prm.psi_Ca_Cl_OH_HMW84 +psi["Mg-Cl-OH"] = prm.psi_Mg_Cl_OH_HMW84 +psi["MgOH-Cl-OH"] = prm.psi_MgOH_Cl_OH_HMW84 +psi["H-Cl-OH"] = prm.psi_H_Cl_OH_HMW84 +theta["Cl-HCO3"] = prm.theta_Cl_HCO3_HMW84 +psi["Na-Cl-HCO3"] = prm.psi_Na_Cl_HCO3_HMW84 +psi["K-Cl-HCO3"] = prm.psi_K_Cl_HCO3_HMW84 +psi["Ca-Cl-HCO3"] = prm.psi_Ca_Cl_HCO3_HMW84 +psi["Mg-Cl-HCO3"] = prm.psi_Mg_Cl_HCO3_HMW84 +psi["MgOH-Cl-HCO3"] = prm.psi_MgOH_Cl_HCO3_HMW84 +psi["H-Cl-HCO3"] = prm.psi_H_Cl_HCO3_HMW84 +theta["CO3-Cl"] = prm.theta_CO3_Cl_HMW84 +psi["Na-CO3-Cl"] = prm.psi_Na_CO3_Cl_HMW84 +psi["K-CO3-Cl"] = prm.psi_K_CO3_Cl_HMW84 +psi["Ca-CO3-Cl"] = prm.psi_Ca_CO3_Cl_HMW84 +psi["Mg-CO3-Cl"] = prm.psi_Mg_CO3_Cl_HMW84 +psi["MgOH-CO3-Cl"] = prm.psi_MgOH_CO3_Cl_HMW84 +psi["H-CO3-Cl"] = prm.psi_H_CO3_Cl_HMW84 +theta["HSO4-SO4"] = prm.theta_HSO4_SO4_HMW84 +psi["Na-HSO4-SO4"] = prm.psi_Na_HSO4_SO4_HMW84 +psi["K-HSO4-SO4"] = prm.psi_K_HSO4_SO4_HMW84 +psi["Ca-HSO4-SO4"] = prm.psi_Ca_HSO4_SO4_HMW84 +psi["Mg-HSO4-SO4"] = prm.psi_Mg_HSO4_SO4_HMW84 +psi["MgOH-HSO4-SO4"] = prm.psi_MgOH_HSO4_SO4_HMW84 +psi["H-HSO4-SO4"] = prm.psi_H_HSO4_SO4_HMW84 +theta["OH-SO4"] = prm.theta_OH_SO4_HMW84 +psi["Na-OH-SO4"] = prm.psi_Na_OH_SO4_HMW84 +psi["K-OH-SO4"] = prm.psi_K_OH_SO4_HMW84 +psi["Ca-OH-SO4"] = prm.psi_Ca_OH_SO4_HMW84 +psi["Mg-OH-SO4"] = prm.psi_Mg_OH_SO4_HMW84 +psi["MgOH-OH-SO4"] = prm.psi_MgOH_OH_SO4_HMW84 +psi["H-OH-SO4"] = prm.psi_H_OH_SO4_HMW84 +theta["HCO3-SO4"] = prm.theta_HCO3_SO4_HMW84 +psi["Na-HCO3-SO4"] = prm.psi_Na_HCO3_SO4_HMW84 +psi["K-HCO3-SO4"] = prm.psi_K_HCO3_SO4_HMW84 +psi["Ca-HCO3-SO4"] = prm.psi_Ca_HCO3_SO4_HMW84 +psi["Mg-HCO3-SO4"] = prm.psi_Mg_HCO3_SO4_HMW84 +psi["MgOH-HCO3-SO4"] = prm.psi_MgOH_HCO3_SO4_HMW84 +psi["H-HCO3-SO4"] = prm.psi_H_HCO3_SO4_HMW84 +theta["CO3-SO4"] = prm.theta_CO3_SO4_HMW84 +psi["Na-CO3-SO4"] = prm.psi_Na_CO3_SO4_HMW84 +psi["K-CO3-SO4"] = prm.psi_K_CO3_SO4_HMW84 +psi["Ca-CO3-SO4"] = prm.psi_Ca_CO3_SO4_HMW84 +psi["Mg-CO3-SO4"] = prm.psi_Mg_CO3_SO4_HMW84 +psi["MgOH-CO3-SO4"] = prm.psi_MgOH_CO3_SO4_HMW84 +psi["H-CO3-SO4"] = prm.psi_H_CO3_SO4_HMW84 +theta["HSO4-OH"] = prm.theta_HSO4_OH_HMW84 +psi["Na-HSO4-OH"] = prm.psi_Na_HSO4_OH_HMW84 +psi["K-HSO4-OH"] = prm.psi_K_HSO4_OH_HMW84 +psi["Ca-HSO4-OH"] = prm.psi_Ca_HSO4_OH_HMW84 +psi["Mg-HSO4-OH"] = prm.psi_Mg_HSO4_OH_HMW84 +psi["MgOH-HSO4-OH"] = prm.psi_MgOH_HSO4_OH_HMW84 +psi["H-HSO4-OH"] = prm.psi_H_HSO4_OH_HMW84 +theta["HCO3-HSO4"] = prm.theta_HCO3_HSO4_HMW84 +psi["Na-HCO3-HSO4"] = prm.psi_Na_HCO3_HSO4_HMW84 +psi["K-HCO3-HSO4"] = prm.psi_K_HCO3_HSO4_HMW84 +psi["Ca-HCO3-HSO4"] = prm.psi_Ca_HCO3_HSO4_HMW84 +psi["Mg-HCO3-HSO4"] = prm.psi_Mg_HCO3_HSO4_HMW84 +psi["MgOH-HCO3-HSO4"] = prm.psi_MgOH_HCO3_HSO4_HMW84 +psi["H-HCO3-HSO4"] = prm.psi_H_HCO3_HSO4_HMW84 +theta["CO3-HSO4"] = prm.theta_CO3_HSO4_HMW84 +psi["Na-CO3-HSO4"] = prm.psi_Na_CO3_HSO4_HMW84 +psi["K-CO3-HSO4"] = prm.psi_K_CO3_HSO4_HMW84 +psi["Ca-CO3-HSO4"] = prm.psi_Ca_CO3_HSO4_HMW84 +psi["Mg-CO3-HSO4"] = prm.psi_Mg_CO3_HSO4_HMW84 +psi["MgOH-CO3-HSO4"] = prm.psi_MgOH_CO3_HSO4_HMW84 +psi["H-CO3-HSO4"] = prm.psi_H_CO3_HSO4_HMW84 +theta["HCO3-OH"] = prm.theta_HCO3_OH_HMW84 +psi["Na-HCO3-OH"] = prm.psi_Na_HCO3_OH_HMW84 +psi["K-HCO3-OH"] = prm.psi_K_HCO3_OH_HMW84 +psi["Ca-HCO3-OH"] = prm.psi_Ca_HCO3_OH_HMW84 +psi["Mg-HCO3-OH"] = prm.psi_Mg_HCO3_OH_HMW84 +psi["MgOH-HCO3-OH"] = prm.psi_MgOH_HCO3_OH_HMW84 +psi["H-HCO3-OH"] = prm.psi_H_HCO3_OH_HMW84 +theta["CO3-OH"] = prm.theta_CO3_OH_HMW84 +psi["Na-CO3-OH"] = prm.psi_Na_CO3_OH_HMW84 +psi["K-CO3-OH"] = prm.psi_K_CO3_OH_HMW84 +psi["Ca-CO3-OH"] = prm.psi_Ca_CO3_OH_HMW84 +psi["Mg-CO3-OH"] = prm.psi_Mg_CO3_OH_HMW84 +psi["MgOH-CO3-OH"] = prm.psi_MgOH_CO3_OH_HMW84 +psi["H-CO3-OH"] = prm.psi_H_CO3_OH_HMW84 +theta["CO3-HCO3"] = prm.theta_CO3_HCO3_HMW84 +psi["Na-CO3-HCO3"] = prm.psi_Na_CO3_HCO3_HMW84 +psi["K-CO3-HCO3"] = prm.psi_K_CO3_HCO3_HMW84 +psi["Ca-CO3-HCO3"] = prm.psi_Ca_CO3_HCO3_HMW84 +psi["Mg-CO3-HCO3"] = prm.psi_Mg_CO3_HCO3_HMW84 +psi["MgOH-CO3-HCO3"] = prm.psi_MgOH_CO3_HCO3_HMW84 +psi["H-CO3-HCO3"] = prm.psi_H_CO3_HCO3_HMW84 +theta["K-Na"] = prm.theta_K_Na_HMW84 +psi["K-Na-Cl"] = prm.psi_K_Na_Cl_HMW84 +psi["K-Na-SO4"] = prm.psi_K_Na_SO4_HMW84 +psi["K-Na-HSO4"] = prm.psi_K_Na_HSO4_HMW84 +psi["K-Na-OH"] = prm.psi_K_Na_OH_HMW84 +psi["K-Na-HCO3"] = prm.psi_K_Na_HCO3_HMW84 +psi["K-Na-CO3"] = prm.psi_K_Na_CO3_HMW84 +theta["Ca-Na"] = prm.theta_Ca_Na_HMW84 +psi["Ca-Na-Cl"] = prm.psi_Ca_Na_Cl_HMW84 +psi["Ca-Na-SO4"] = prm.psi_Ca_Na_SO4_HMW84 +psi["Ca-Na-HSO4"] = prm.psi_Ca_Na_HSO4_HMW84 +psi["Ca-Na-OH"] = prm.psi_Ca_Na_OH_HMW84 +psi["Ca-Na-HCO3"] = prm.psi_Ca_Na_HCO3_HMW84 +psi["Ca-Na-CO3"] = prm.psi_Ca_Na_CO3_HMW84 +theta["Mg-Na"] = prm.theta_Mg_Na_HMW84 +psi["Mg-Na-Cl"] = prm.psi_Mg_Na_Cl_HMW84 +psi["Mg-Na-SO4"] = prm.psi_Mg_Na_SO4_HMW84 +psi["Mg-Na-HSO4"] = prm.psi_Mg_Na_HSO4_HMW84 +psi["Mg-Na-OH"] = prm.psi_Mg_Na_OH_HMW84 +psi["Mg-Na-HCO3"] = prm.psi_Mg_Na_HCO3_HMW84 +psi["Mg-Na-CO3"] = prm.psi_Mg_Na_CO3_HMW84 +theta["MgOH-Na"] = prm.theta_MgOH_Na_HMW84 +psi["MgOH-Na-Cl"] = prm.psi_MgOH_Na_Cl_HMW84 +psi["MgOH-Na-SO4"] = prm.psi_MgOH_Na_SO4_HMW84 +psi["MgOH-Na-HSO4"] = prm.psi_MgOH_Na_HSO4_HMW84 +psi["MgOH-Na-OH"] = prm.psi_MgOH_Na_OH_HMW84 +psi["MgOH-Na-HCO3"] = prm.psi_MgOH_Na_HCO3_HMW84 +psi["MgOH-Na-CO3"] = prm.psi_MgOH_Na_CO3_HMW84 +theta["H-Na"] = prm.theta_H_Na_HMW84 +psi["H-Na-Cl"] = prm.psi_H_Na_Cl_HMW84 +psi["H-Na-SO4"] = prm.psi_H_Na_SO4_HMW84 +psi["H-Na-HSO4"] = prm.psi_H_Na_HSO4_HMW84 +psi["H-Na-OH"] = prm.psi_H_Na_OH_HMW84 +psi["H-Na-HCO3"] = prm.psi_H_Na_HCO3_HMW84 +psi["H-Na-CO3"] = prm.psi_H_Na_CO3_HMW84 +theta["Ca-K"] = prm.theta_Ca_K_HMW84 +psi["Ca-K-Cl"] = prm.psi_Ca_K_Cl_HMW84 +psi["Ca-K-SO4"] = prm.psi_Ca_K_SO4_HMW84 +psi["Ca-K-HSO4"] = prm.psi_Ca_K_HSO4_HMW84 +psi["Ca-K-OH"] = prm.psi_Ca_K_OH_HMW84 +psi["Ca-K-HCO3"] = prm.psi_Ca_K_HCO3_HMW84 +psi["Ca-K-CO3"] = prm.psi_Ca_K_CO3_HMW84 +theta["K-Mg"] = prm.theta_K_Mg_HMW84 +psi["K-Mg-Cl"] = prm.psi_K_Mg_Cl_HMW84 +psi["K-Mg-SO4"] = prm.psi_K_Mg_SO4_HMW84 +psi["K-Mg-HSO4"] = prm.psi_K_Mg_HSO4_HMW84 +psi["K-Mg-OH"] = prm.psi_K_Mg_OH_HMW84 +psi["K-Mg-HCO3"] = prm.psi_K_Mg_HCO3_HMW84 +psi["K-Mg-CO3"] = prm.psi_K_Mg_CO3_HMW84 +theta["K-MgOH"] = prm.theta_K_MgOH_HMW84 +psi["K-MgOH-Cl"] = prm.psi_K_MgOH_Cl_HMW84 +psi["K-MgOH-SO4"] = prm.psi_K_MgOH_SO4_HMW84 +psi["K-MgOH-HSO4"] = prm.psi_K_MgOH_HSO4_HMW84 +psi["K-MgOH-OH"] = prm.psi_K_MgOH_OH_HMW84 +psi["K-MgOH-HCO3"] = prm.psi_K_MgOH_HCO3_HMW84 +psi["K-MgOH-CO3"] = prm.psi_K_MgOH_CO3_HMW84 +theta["H-K"] = prm.theta_H_K_HMW84 +psi["H-K-Cl"] = prm.psi_H_K_Cl_HMW84 +psi["H-K-SO4"] = prm.psi_H_K_SO4_HMW84 +psi["H-K-HSO4"] = prm.psi_H_K_HSO4_HMW84 +psi["H-K-OH"] = prm.psi_H_K_OH_HMW84 +psi["H-K-HCO3"] = prm.psi_H_K_HCO3_HMW84 +psi["H-K-CO3"] = prm.psi_H_K_CO3_HMW84 +theta["Ca-Mg"] = prm.theta_Ca_Mg_HMW84 +psi["Ca-Mg-Cl"] = prm.psi_Ca_Mg_Cl_HMW84 +psi["Ca-Mg-SO4"] = prm.psi_Ca_Mg_SO4_HMW84 +psi["Ca-Mg-HSO4"] = prm.psi_Ca_Mg_HSO4_HMW84 +psi["Ca-Mg-OH"] = prm.psi_Ca_Mg_OH_HMW84 +psi["Ca-Mg-HCO3"] = prm.psi_Ca_Mg_HCO3_HMW84 +psi["Ca-Mg-CO3"] = prm.psi_Ca_Mg_CO3_HMW84 +theta["Ca-MgOH"] = prm.theta_Ca_MgOH_HMW84 +psi["Ca-MgOH-Cl"] = prm.psi_Ca_MgOH_Cl_HMW84 +psi["Ca-MgOH-SO4"] = prm.psi_Ca_MgOH_SO4_HMW84 +psi["Ca-MgOH-HSO4"] = prm.psi_Ca_MgOH_HSO4_HMW84 +psi["Ca-MgOH-OH"] = prm.psi_Ca_MgOH_OH_HMW84 +psi["Ca-MgOH-HCO3"] = prm.psi_Ca_MgOH_HCO3_HMW84 +psi["Ca-MgOH-CO3"] = prm.psi_Ca_MgOH_CO3_HMW84 +theta["Ca-H"] = prm.theta_Ca_H_HMW84 +psi["Ca-H-Cl"] = prm.psi_Ca_H_Cl_HMW84 +psi["Ca-H-SO4"] = prm.psi_Ca_H_SO4_HMW84 +psi["Ca-H-HSO4"] = prm.psi_Ca_H_HSO4_HMW84 +psi["Ca-H-OH"] = prm.psi_Ca_H_OH_HMW84 +psi["Ca-H-HCO3"] = prm.psi_Ca_H_HCO3_HMW84 +psi["Ca-H-CO3"] = prm.psi_Ca_H_CO3_HMW84 +theta["Mg-MgOH"] = prm.theta_Mg_MgOH_HMW84 +psi["Mg-MgOH-Cl"] = prm.psi_Mg_MgOH_Cl_HMW84 +psi["Mg-MgOH-SO4"] = prm.psi_Mg_MgOH_SO4_HMW84 +psi["Mg-MgOH-HSO4"] = prm.psi_Mg_MgOH_HSO4_HMW84 +psi["Mg-MgOH-OH"] = prm.psi_Mg_MgOH_OH_HMW84 +psi["Mg-MgOH-HCO3"] = prm.psi_Mg_MgOH_HCO3_HMW84 +psi["Mg-MgOH-CO3"] = prm.psi_Mg_MgOH_CO3_HMW84 +theta["H-Mg"] = prm.theta_H_Mg_HMW84 +psi["H-Mg-Cl"] = prm.psi_H_Mg_Cl_HMW84 +psi["H-Mg-SO4"] = prm.psi_H_Mg_SO4_HMW84 +psi["H-Mg-HSO4"] = prm.psi_H_Mg_HSO4_HMW84 +psi["H-Mg-OH"] = prm.psi_H_Mg_OH_HMW84 +psi["H-Mg-HCO3"] = prm.psi_H_Mg_HCO3_HMW84 +psi["H-Mg-CO3"] = prm.psi_H_Mg_CO3_HMW84 +theta["H-MgOH"] = prm.theta_H_MgOH_HMW84 +psi["H-MgOH-Cl"] = prm.psi_H_MgOH_Cl_HMW84 +psi["H-MgOH-SO4"] = prm.psi_H_MgOH_SO4_HMW84 +psi["H-MgOH-HSO4"] = prm.psi_H_MgOH_HSO4_HMW84 +psi["H-MgOH-OH"] = prm.psi_H_MgOH_OH_HMW84 +psi["H-MgOH-HCO3"] = prm.psi_H_MgOH_HCO3_HMW84 +psi["H-MgOH-CO3"] = prm.psi_H_MgOH_CO3_HMW84 +lambd = {} +lambd["CO2_H"] = prm.lambd_CO2_H_HMW84 +lambd["CO2_Na"] = prm.lambd_CO2_Na_HMW84 +lambd["CO2_K"] = prm.lambd_CO2_K_HMW84 +lambd["CO2_Ca"] = prm.lambd_CO2_Ca_HMW84 +lambd["CO2_Mg"] = prm.lambd_CO2_Mg_HMW84 +lambd["CO2_Cl"] = prm.lambd_CO2_Cl_HMW84 +lambd["CO2_SO4"] = prm.lambd_CO2_SO4_HMW84 +lambd["CO2_HSO4"] = prm.lambd_CO2_HSO4_HMW84 diff --git a/pytzer4/libraries/M88.py b/pytzer4/libraries/M88.py new file mode 100644 index 00000000..b48ef24a --- /dev/null +++ b/pytzer4/libraries/M88.py @@ -0,0 +1,25 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from .. import parameters as prm +from .. import debyehueckel, dissociation, unsymmetrical + +# Møller (1988). Geochim. Cosmochim. Acta 52, 821-837, +# doi:10.1016/0016-7037(88)90354-7 +# System: Na-Ca-Cl-SO4 +name = "M88" +dh = {"Aosm": debyehueckel.Aosm_M88} +bC = {} +bC["Ca-Cl"] = prm.bC_Ca_Cl_M88 +bC["Ca-SO4"] = prm.bC_Ca_SO4_M88 +bC["Na-Cl"] = prm.bC_Na_Cl_M88 +bC["Na-SO4"] = prm.bC_Na_SO4_M88 +theta = {} +theta["Ca-Na"] = prm.theta_Ca_Na_M88 +theta["Cl-SO4"] = prm.theta_Cl_SO4_M88 +psi = {} +psi["Ca-Na-Cl"] = prm.psi_Ca_Na_Cl_M88 +psi["Ca-Na-SO4"] = prm.psi_Ca_Na_SO4_M88 +psi["Ca-Cl-SO4"] = prm.psi_Ca_Cl_SO4_M88 +psi["Na-Cl-SO4"] = prm.psi_Na_Cl_SO4_M88 +jfunc = unsymmetrical.Harvie +lnk = {"H2O": dissociation.H2O_M88} diff --git a/pytzer4/libraries/MIAMI.py b/pytzer4/libraries/MIAMI.py new file mode 100644 index 00000000..a00f420e --- /dev/null +++ b/pytzer4/libraries/MIAMI.py @@ -0,0 +1,272 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from .. import parameters as prm +from .. import debyehueckel, dissociation, unsymmetrical + +name = "MIAMI" +dh = {"Aosm": debyehueckel.Aosm_M88} +jfunc = unsymmetrical.Harvie +bC = { + # Table A1 + "Na-Cl": prm.bC_Na_Cl_M88, + "K-Cl": prm.bC_K_Cl_GM89, + "K-SO4": prm.bC_K_SO4_GM89, + "Ca-Cl": prm.bC_Ca_Cl_GM89, + "Ca-SO4": prm.bC_Ca_SO4_M88, + "Ca-SO3": prm.bC_Ca_SO3_MP98, + "Sr-SO4": prm.bC_Sr_SO4_MP98, + # Table A2 + "Mg-Cl": prm.bC_Mg_Cl_PP87i, + "Mg-SO4": prm.bC_Mg_SO4_PP86ii, + # Table A3 + "Na-HSO4": prm.bC_Na_HSO4_MP98, + "Na-HCO3": prm.bC_Na_HCO3_MP98, + "Na-SO4": prm.bC_Na_SO4_HPR93, + "Na-CO3": prm.bC_Na_CO3_MP98, + "Na-BOH4": prm.bC_Na_BOH4_MP98, # Should be SRRJ87, conflicts with MP98. + "Na-HS": prm.bC_Na_HS_HPM88, + "Na-SCN": prm.bC_Na_SCN_SP78, + "Na-SO3": prm.bC_Na_SO3_MHJZ89, + "Na-HSO3": prm.bC_Na_HSO3_MHJZ89, + # Table A4 + "K-HCO3": prm.bC_K_HCO3_RGWW83, + "K-CO3": prm.bC_K_CO3_MP98, # Should be SRG87, but conflicts with MP98. + "K-BOH4": prm.bC_K_BOH4_MP98, # Should be SRRJ87, but conflicts with MP98. + "K-HS": prm.bC_K_HS_HPM88, + "K-H2PO4": prm.bC_K_H2PO4_SP78, + "K-SCN": prm.bC_K_SCN_SP78, + # Table A5 + "Mg-Br": prm.bC_Mg_Br_SP78, + "Mg-BOH4": prm.bC_Mg_BOH4_SRM87, + "Mg-ClO4": prm.bC_Mg_ClO4_SP78, + "Ca-Br": prm.bC_Ca_Br_SP78, + "Ca-BOH4": prm.bC_Ca_BOH4_SRM87, + "Ca-ClO4": prm.bC_Ca_ClO4_SP78, + # Table A6 + "Sr-Br": prm.bC_Sr_Br_SP78, + "Sr-Cl": prm.bC_Sr_Cl_SP78, # Not in table but in text §4.6 + "Sr-NO3": prm.bC_Sr_NO3_SP78, + "Sr-ClO4": prm.bC_Sr_ClO4_SP78, + # 'Sr-HSO3': prm.bC_Sr_HSO3_MP98, # Interaction also appears in Table A8?! + "Sr-BOH4": prm.bC_Sr_BOH4_MP98, + # Table A7 + "Na-I": prm.bC_Na_I_MP98, + "Na-Br": prm.bC_Na_Br_MP98, + "Na-F": prm.bC_Na_F_MP98, + "K-Br": prm.bC_K_Br_MP98, + "K-F": prm.bC_K_F_MP98, + "K-OH": prm.bC_K_OH_MP98, + "K-I": prm.bC_K_I_MP98, + "Na-ClO3": prm.bC_Na_ClO3_MP98, + "K-ClO3": prm.bC_K_ClO3_MP98, + "Na-ClO4": prm.bC_Na_ClO4_MP98, + "Na-BrO3": prm.bC_Na_BrO3_MP98, + "K-BrO3": prm.bC_K_BrO3_MP98, + "Na-NO3": prm.bC_Na_NO3_MP98, + "K-NO3": prm.bC_K_NO3_MP98, + "Mg-NO3": prm.bC_Mg_NO3_MP98, + "Ca-NO3": prm.bC_Ca_NO3_MP98, + "H-Br": prm.bC_H_Br_MP98, + "Sr-Cl": prm.bC_Sr_Cl_MP98, + "NH4-Cl": prm.bC_NH4_Cl_MP98, + "NH4-Br": prm.bC_NH4_Br_MP98typo, + "NH4-F": prm.bC_NH4_F_MP98, + # Table A8 + "Sr-I": prm.bC_Sr_I_PM73, + "Na-NO2": prm.bC_Na_NO2_PM73, + "Na-H2PO4": prm.bC_Na_H2PO4_PM73, + "Na-HPO4": prm.bC_Na_HPO4_PM73, + "Na-PO4": prm.bC_Na_PO4_PM73, + "Na-H2AsO4": prm.bC_Na_H2AsO4_PM73, + "K-H2AsO4": prm.bC_K_H2AsO4_PM73, + "Na-HAsO4": prm.bC_Na_HAsO4_PM73, + "Na-AsO4": prm.bC_Na_AsO4_PM73, + "Na-acetate": prm.bC_Na_acetate_PM73, + "K-HSO4": prm.bC_K_HSO4_MP98, # MP98 mis-citation based on PM16 code. + "K-NO2": prm.bC_K_NO2_PM73, + "K-HPO4": prm.bC_K_HPO4_PM73, + "K-PO4": prm.bC_K_PO4_PM73, + "K-HAsO4": prm.bC_K_HAsO4_PM73, + "K-AsO4": prm.bC_K_AsO4_PM73, # Not in table, but presumably should be? + "K-acetate": prm.bC_K_acetate_PM73, + "Mg-HSO4": prm.bC_Mg_HSO4_MP98, # MP98 mis-citation based on PM16 code. + "Mg-HCO3": prm.bC_Mg_HCO3_MP98, + "Mg-HS": prm.bC_Mg_HS_HPM88, + "Mg-I": prm.bC_Mg_I_PM73, + "Mg-HSO3": prm.bC_Mg_HSO3_RZM91, + "Mg-SO3": prm.bC_Mg_SO3_RZM91, + "Ca-HSO4": prm.bC_Ca_HSO4_HMW84, + "Ca-HCO3": prm.bC_Ca_HCO3_HMW84, + "Ca-HSO3": prm.bC_Ca_HSO3_MP98, + "Ca-HS": prm.bC_Ca_HS_HPM88, + "Ca-OH": prm.bC_Ca_OH_HMW84, + "Ca-I": prm.bC_Ca_I_PM73, + "Sr-HSO4": prm.bC_Sr_HSO4_MP98, + "Sr-HCO3": prm.bC_Sr_HCO3_MP98, + "Sr-HSO3": prm.bC_Sr_HSO3_MP98, + "Sr-OH": prm.bC_Sr_OH_MP98, + "NH4-SO4": prm.bC_NH4_SO4_PM73, + "MgOH-Cl": prm.bC_MgOH_Cl_HMW84, + # Table A9 + "H-Cl": prm.bC_H_Cl_CMR93, + "H-SO4": prm.bC_H_SO4_MP98, # Cited paper not published. + "H-HSO4": prm.bC_H_HSO4_MP98, # Cited paper not published, & no equation + # provided, but this interaction is too + # critical to skip? + # Not in MP98 tables (I think!) but should be, based on PM code. + "Na-OH": prm.bC_Na_OH_PP87i, +} # end of bC dict +theta = { + # Table A10 + "H-Sr": prm.theta_H_Sr_RGRG86, + "H-Na": prm.theta_H_Na_MP98, # Should be CMR93, but conflicts with MP98 + "H-K": prm.theta_H_K_MP98, # Should be CMR93, but conflicts with MP98 + "H-Mg": prm.theta_H_Mg_MP98, # Should be RGB80, but has not temp. term + "Ca-H": prm.theta_Ca_H_MP98, # Should be RGO81, see notes in parameters + "K-Na": prm.theta_K_Na_GM89, + "Mg-Na": prm.theta_Mg_Na_PP87ii, + "Ca-Na": prm.theta_Ca_Na_M88, + "K-Mg": prm.theta_K_Mg_PP87ii, + "Ca-K": prm.theta_Ca_K_GM89, + "Cl-SO4": prm.theta_Cl_SO4_M88, + "CO3-Cl": prm.theta_CO3_Cl_PP82, + "Cl-HCO3": prm.theta_Cl_HCO3_PP82, + "BOH4-Cl": prm.theta_BOH4_Cl_MP98typo, # Typo in PM code replicated here + "CO3-HCO3": prm.theta_CO3_HCO3_MP98, + "HSO4-SO4": prm.theta_HSO4_SO4_MP98, # Cited paper not published + "Cl-OH": prm.theta_Cl_OH_MP98, + # Table A11 + "Na-Sr": prm.theta_Na_Sr_MP98, # Unclear where MP98 got this from + "K-Sr": prm.theta_K_Sr_MP98, # Unclear where MP98 got this from + "Ca-Mg": prm.theta_Ca_Mg_HMW84, + "Cl-F": prm.theta_Cl_F_MP98, + "CO3-SO4": prm.theta_CO3_SO4_HMW84, + "HCO3-SO4": prm.theta_HCO3_SO4_HMW84, + "BOH4-SO4": prm.theta_BOH4_SO4_FW86, + "Cl-HSO4": prm.theta_Cl_HSO4_HMW84, + "OH-SO4": prm.theta_OH_SO4_HMW84, # MP98 incorrect citation. + "Br-OH": prm.theta_Br_OH_PK74, + "Cl-NO3": prm.theta_Cl_NO3_PK74, + "Cl-H2PO4": prm.theta_Cl_H2PO4_HFM89, + "Cl-HPO4": prm.theta_Cl_HPO4_HFM89, + "Cl-PO4": prm.theta_Cl_PO4_HFM89, + "Cl-H2AsO4": prm.theta_Cl_H2AsO4_M83, # Shouldn't have unsymmetrical term. + "Cl-HAsO4": prm.theta_Cl_HAsO4_M83, # Shouldn't have unsymmetrical term. + "AsO4-Cl": prm.theta_AsO4_Cl_M83, # Shouldn't have unsymmetrical term. + "Cl-SO3": prm.theta_Cl_SO3_MHJZ89, + "acetate-Cl": prm.theta_acetate_Cl_M83, # Shouldn't have unsymm. term. +} # end of theta dict +psi = { + # Table A10 + "K-Na-Cl": prm.psi_K_Na_Cl_GM89, + "K-Na-SO4": prm.psi_K_Na_SO4_GM89, + "Mg-Na-Cl": prm.psi_Mg_Na_Cl_PP87ii, + "Ca-Na-Cl": prm.psi_Ca_Na_Cl_M88, + "Ca-Na-SO4": prm.psi_Ca_Na_SO4_M88, + "K-Mg-Cl": prm.psi_K_Mg_Cl_PP87ii, + "Ca-K-Cl": prm.psi_Ca_K_Cl_MP98typo, # Typo in PM code replicated here. + "Ca-K-SO4": prm.psi_Ca_K_SO4_GM89, + "Na-Cl-SO4": prm.psi_Na_Cl_SO4_M88, + "K-Cl-SO4": prm.psi_K_Cl_SO4_MP98, # Should be GM89, conflicts with MP98. + "Ca-Cl-SO4": prm.psi_Ca_Cl_SO4_M88, + "Na-CO3-Cl": prm.psi_Na_CO3_Cl_TM82, + "Na-Cl-HCO3": prm.psi_Na_Cl_HCO3_PP82, # MP98 incorrect citation. + "Na-BOH4-Cl": prm.psi_Na_BOH4_Cl_MP98, + "Mg-BOH4-Cl": prm.psi_Mg_BOH4_Cl_MP98, + "Ca-BOH4-Cl": prm.psi_Ca_BOH4_Cl_MP98, + "H-Sr-Cl": prm.psi_H_Sr_Cl_MP98, # Cites M85 book but can't find it there. + "H-Mg-Cl": prm.psi_H_Mg_Cl_MP98, # Should be RGB80, but that doesn't + # include MP98 temperature term. + "Ca-H-Cl": prm.psi_Ca_H_Cl_MP98, # Should be RGO81, but that doesn't + # include MP98 temperature term. + "Na-HSO4-SO4": prm.psi_Na_HSO4_SO4_MP98, # Cited paper not published. + "Na-CO3-HCO3": prm.psi_Na_CO3_HCO3_MP98, + "K-CO3-HCO3": prm.psi_K_CO3_HCO3_MP98, + # Table A11 + "Na-Sr-Cl": prm.psi_Na_Sr_Cl_MP98, # Couldn't find in PK74 as cited. + "K-Sr-Cl": prm.psi_K_Sr_Cl_MP98, + "K-Na-Br": prm.psi_K_Na_Br_PK74, + "Mg-Na-SO4": prm.psi_Mg_Na_SO4_HMW84, + "K-Mg-SO4": prm.psi_K_Mg_SO4_HMW84, + "Ca-Mg-Cl": prm.psi_Ca_Mg_Cl_HMW84, + "Ca-Mg-SO4": prm.psi_Ca_Mg_SO4_HMW84, + "H-Na-Cl": prm.psi_H_Na_Cl_PMR97, + "H-Na-SO4": prm.psi_H_Na_SO4_PMR97, + "H-Na-Br": prm.psi_H_Na_Br_PK74, + "H-K-Cl": prm.psi_H_K_Cl_HMW84, + "H-K-SO4": prm.psi_H_K_SO4_HMW84, + "H-K-Br": prm.psi_H_K_Br_MP98, # No function in HMW84 (no Br!). + "H-Mg-Br": prm.psi_H_Mg_Br_MP98, # Couldn't find in PK74 as cited. + "Mg-MgOH-Cl": prm.psi_Mg_MgOH_Cl_HMW84, + "Mg-Cl-SO4": prm.psi_Mg_Cl_SO4_HMW84, + "Mg-Cl-HCO3": prm.psi_Mg_Cl_HCO3_HMW84, + "Na-Cl-F": prm.psi_Na_Cl_F_MP98, + "Na-CO3-SO4": prm.psi_Na_CO3_SO4_HMW84, + "K-CO3-SO4": prm.psi_K_CO3_SO4_HMW84, + "Na-HCO3-SO4": prm.psi_Na_HCO3_SO4_HMW84, + "Mg-HCO3-SO4": prm.psi_Mg_HCO3_SO4_HMW84, + "Na-Cl-HSO4": prm.psi_Na_Cl_HSO4_HMW84, + "K-HSO4-SO4": prm.psi_K_HSO4_SO4_HMW84, + "Na-Cl-OH": prm.psi_Na_Cl_OH_HMW84, # Ref. presumably mislabelled by MP98. + "K-Cl-OH": prm.psi_K_Cl_OH_HMW84, # Ref. presumably mislabelled by MP98. + "Ca-Cl-OH": prm.psi_Ca_Cl_OH_HMW84, # Ref. presum. mislabelled by MP98. + "Na-OH-SO4": prm.psi_Na_OH_SO4_HMW84, # Ref. presumably mislabelled by MP98. + "K-OH-SO4": prm.psi_K_OH_SO4_HMW84, # Ref. presumably mislabelled by MP98. + "Na-Br-OH": prm.psi_Na_Br_OH_PK74, + "K-Br-OH": prm.psi_K_Br_OH_PK74, + "Na-Cl-NO3": prm.psi_Na_Cl_NO3_PK74, + "K-Cl-NO3": prm.psi_K_Cl_NO3_PK74, + "Na-Cl-H2PO4": prm.psi_Na_Cl_H2PO4_HFM89, + "K-Cl-H2PO4": prm.psi_K_Cl_H2PO4_MP98, # Can't find cited PS76 paper. + "Na-Cl-HPO4": prm.psi_Na_Cl_HPO4_HFM89, + "Na-Cl-PO4": prm.psi_Na_Cl_PO4_HFM89, + "Na-Cl-H2AsO4": prm.psi_Na_Cl_H2AsO4_M83, + "Na-Cl-HAsO4": prm.psi_Na_Cl_HAsO4_M83, + "Na-AsO4-Cl": prm.psi_Na_AsO4_Cl_M83, + "Na-Cl-SO3": prm.psi_Na_Cl_SO3_MHJZ89, +} # end of psi dict +lambd = { # all from Table A12 + "CO2-Na": prm.lambd_CO2_Na_HM93, + "CO2-K": prm.lambd_CO2_K_HM93, + "CO2-Ca": prm.lambd_CO2_Ca_HM93, + "CO2-Mg": prm.lambd_CO2_Mg_HM93, + "CO2-Cl": prm.lambd_CO2_Cl_HM93, + "CO2-SO4": prm.lambd_CO2_SO4_HM93, + "BOH3-Na": prm.lambd_BOH3_Na_FW86, + "BOH3-K": prm.lambd_BOH3_K_FW86, + "BOH3-Cl": prm.lambd_BOH3_Cl_FW86, + "BOH3-SO4": prm.lambd_BOH3_SO4_FW86, + "NH3-Na": prm.lambd_NH3_Na_CB89, + "NH3-K": prm.lambd_NH3_K_CB89, # Also includes CB89 temperature term. + "NH3-Mg": prm.lambd_NH3_Mg_CB89, + "NH3-Ca": prm.lambd_NH3_Ca_CB89, + "NH3-Sr": prm.lambd_NH3_Sr_CB89, + "H3PO4-H": prm.lambd_H3PO4_H_PS76, + "H3PO4-K": prm.lambd_H3PO4_K_PS76, + "SO2-Cl": prm.lambd_SO2_Cl_MHJZ89, + "SO2-Na": prm.lambd_SO2_Na_MHJZ89, + "SO2-Mg": prm.lambd_SO2_Mg_RZM91, + "HF-Cl": prm.lambd_HF_Cl_MP98, + "HF-Na": prm.lambd_HF_Na_MP98, +} # end of lambd dict +zeta = { # all from Table A12 + "CO2-H-Cl": prm.zeta_CO2_H_Cl_HM93, + "CO2-Na-Cl": prm.zeta_CO2_Na_Cl_HM93, + "CO2-K-Cl": prm.zeta_CO2_K_Cl_HM93, + "CO2-Ca-Cl": prm.zeta_CO2_Ca_Cl_HM93, + "CO2-Mg-Cl": prm.zeta_CO2_Mg_Cl_HM93, + "CO2-Na-SO4": prm.zeta_CO2_Na_SO4_HM93, + "CO2-K-SO4": prm.zeta_CO2_K_SO4_HM93, + "CO2-Mg-SO4": prm.zeta_CO2_Mg_SO4_HM93, + "BOH3-Na-SO4": prm.zeta_BOH3_Na_SO4_FW86, + "NH3-Ca-Cl": prm.zeta_NH3_Ca_Cl_CB89, + "H3PO4-Na-Cl": prm.zeta_H3PO4_Na_Cl_MP98, # PS76 don't have this term... +} # end of zeta dict +lnk = { + "BOH3": dissociation.BOH3_M79, + "MgOH": dissociation.MgOH_MP98, + "H2O": dissociation.H2O_M79, + "HSO4": dissociation.HSO4_CRP94, + "H2CO3": dissociation.H2CO3_MP98, + "HCO3": dissociation.HCO3_MP98, +} # end of lnks dict diff --git a/pytzer4/libraries/MarChemSpec.py b/pytzer4/libraries/MarChemSpec.py new file mode 100644 index 00000000..0620676a --- /dev/null +++ b/pytzer4/libraries/MarChemSpec.py @@ -0,0 +1,23 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from copy import deepcopy +from .. import debyehueckel, dissociation + +# MarChemSpec project +from . import MarChemSpec25 + +name = "MarChemSpec" +dh = {"Aosm": debyehueckel.Aosm_MarChemSpec} +jfunc = deepcopy(MarChemSpec25.jfunc) +bC = deepcopy(MarChemSpec25.bC) +theta = deepcopy(MarChemSpec25.theta) +psi = deepcopy(MarChemSpec25.psi) +lambd = deepcopy(MarChemSpec25.lambd) +zeta = deepcopy(MarChemSpec25.zeta) +mu = deepcopy(MarChemSpec25.mu) +# Add equilibrium constants +lnk = {} +lnk["H2O"] = dissociation.H2O_MF +lnk["HSO4"] = dissociation.HSO4_CRP94 +lnk["MgOH"] = dissociation.MgOH_CW91 +lnk["trisH"] = dissociation.trisH_BH64 diff --git a/pytzer4/libraries/MarChemSpec05.py b/pytzer4/libraries/MarChemSpec05.py new file mode 100644 index 00000000..c005d5b8 --- /dev/null +++ b/pytzer4/libraries/MarChemSpec05.py @@ -0,0 +1,20 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from copy import deepcopy +from .. import debyehueckel + +# Waters and Millero (2013). Mar. Chem. 149, 8-22, +# doi:10.1016/j.marchem.2012.11.003 +from . import MarChemSpec25 + +name = "MarChemSpec05" +dh = debyehueckel.Aosm_MarChemSpec05 +jfunc = deepcopy(MarChemSpec25.jfunc) +# Begin with MarChemSpec25 with Aosm fixed at 5 degC +# Add parameters from GT17 Supp. Info. Table S6 (simultaneous optimisation) +bC = deepcopy(MarChemSpec25.bC) +theta = deepcopy(MarChemSpec25.theta) +psi = deepcopy(MarChemSpec25.psi) +lambd = deepcopy(MarChemSpec25.lambd) +zeta = deepcopy(MarChemSpec25.zeta) +mu = deepcopy(MarChemSpec25.mu) diff --git a/pytzer4/libraries/MarChemSpec25.py b/pytzer4/libraries/MarChemSpec25.py new file mode 100644 index 00000000..12316b13 --- /dev/null +++ b/pytzer4/libraries/MarChemSpec25.py @@ -0,0 +1,31 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from copy import deepcopy +from .. import parameters as prm + +# Waters and Millero (2013). Mar. Chem. 149, 8-22, +# doi:10.1016/j.marchem.2012.11.003 +from . import WM13_MarChemSpec25 + +name = "MarChemSpec25" +dh = deepcopy(WM13_MarChemSpec25.dh) +jfunc = deepcopy(WM13_MarChemSpec25.jfunc) +# Begin with WM13_MarChemSpec25 with Aosm fixed at 25 degC +# Add parameters from GT17 Supp. Info. Table S6 (simultaneous optimisation) +bC = deepcopy(WM13_MarChemSpec25.bC) +# bC['Na-Cl'] = prm.bC_Na_Cl_GT17simopt +bC["trisH-SO4"] = prm.bC_trisH_SO4_GT17simopt +bC["trisH-Cl"] = prm.bC_trisH_Cl_GT17simopt +theta = deepcopy(WM13_MarChemSpec25.theta) +theta["H-trisH"] = prm.theta_H_trisH_GT17simopt +psi = deepcopy(WM13_MarChemSpec25.psi) +psi["H-trisH-Cl"] = prm.psi_H_trisH_Cl_GT17simopt +lambd = {} +lambd["tris-trisH"] = prm.lambd_tris_trisH_GT17simopt +lambd["tris-Na"] = prm.lambd_tris_Na_GT17simopt +lambd["tris-K"] = prm.lambd_tris_K_GT17simopt +lambd["tris-Mg"] = prm.lambd_tris_Mg_GT17simopt +lambd["tris-Ca"] = prm.lambd_tris_Ca_GT17simopt +lambd["tris-tris"] = prm.lambd_tris_tris_MarChemSpec25 +zeta = {"tris-Na-Cl": prm.zeta_tris_Na_Cl_MarChemSpec25} +mu = {"tris-tris-tris": prm.mu_tris_tris_tris_MarChemSpec25} diff --git a/pytzer4/libraries/ParameterLibrary.py b/pytzer4/libraries/ParameterLibrary.py new file mode 100644 index 00000000..99b4393a --- /dev/null +++ b/pytzer4/libraries/ParameterLibrary.py @@ -0,0 +1,249 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from autograd.numpy import array, concatenate, unique +from .. import parameters as prm +from .. import properties +from ..meta import version + + +class ParameterLibrary: + def __init__( + self, + module=None, + name="", + dh={}, + bC={}, + theta={}, + jfunc=[], + psi={}, + lambd={}, + zeta={}, + mu={}, + lnk={}, + ions=array([]), + srcs=array([]), + ): + self.name = name + self.dh = dh # Aosm + self.bC = bC # c-a + self.theta = theta # c-c' and a-a' + self.jfunc = jfunc # unsymmetrical mixing + self.psi = psi # c-c'-a and c-a-a' + self.lambd = lambd # # n-c, n-a, n-n and n-n' + self.zeta = zeta # n-c-a + self.mu = mu # n-n-n + self.lnk = lnk # thermodynamic equilibrium constants + self.ions = ions + self.srcs = srcs + if module is not None: + if "name" in dir(module): + self.name = module.name + if "dh" in dir(module): + self.dh = module.dh + if "bC" in dir(module): + self.bC = module.bC + if "theta" in dir(module): + self.theta = module.theta + if "jfunc" in dir(module): + self.jfunc = module.jfunc + if "psi" in dir(module): + self.psi = module.psi + if "lambd" in dir(module): + self.lambd = module.lambd + if "zeta" in dir(module): + self.zeta = module.zeta + if "mu" in dir(module): + self.mu = module.mu + if "lnk" in dir(module): + self.lnk = module.lnk + if "ions" in dir(module): + self.ions = module.ions + if "srcs" in dir(module): + self.srcs = module.srcs + + def add_zeros(self, ions): + """Add zero-functions for missing combinations of solutes.""" + _, cations, anions, neutrals = properties.charges(ions) + cations.sort() + anions.sort() + neutrals.sort() + # betas and Cs + for cation in cations: + for anion in anions: + istr = "-".join((cation, anion)) + if istr not in self.bC.keys(): + self.bC[istr] = prm.bC_none + # c-c'-a thetas and psis + for C0, cation0 in enumerate(cations): + for cation1 in cations[C0 + 1 :]: + istr = "-".join((cation0, cation1)) + if istr not in self.theta.keys(): + self.theta[istr] = prm.theta_none + for anion in anions: + istr = "-".join((cation0, cation1, anion)) + if istr not in self.psi.keys(): + self.psi[istr] = prm.psi_none + # c-a-a' thetas and psis + for A0, anion0 in enumerate(anions): + for anion1 in anions[A0 + 1 :]: + istr = "-".join((anion0, anion1)) + if istr not in self.theta.keys(): + self.theta[istr] = prm.theta_none + for cation in cations: + istr = "-".join((cation, anion0, anion1)) + if istr not in self.psi.keys(): + self.psi[istr] = prm.psi_none + # Neutral interactions + for N0, neutral0 in enumerate(neutrals): + # n-c lambdas + for cation in cations: + inc = "-".join((neutral0, cation)) + if inc not in self.lambd.keys(): + self.lambd[inc] = prm.lambd_none + # n-c-a zetas + for anion in anions: + inca = "-".join((neutral0, cation, anion)) + if inca not in self.zeta.keys(): + self.zeta[inca] = prm.zeta_none + # n-a lambdas + for anion in anions: + ina = "-".join((neutral0, anion)) + if ina not in self.lambd.keys(): + self.lambd[ina] = prm.lambd_none + # n-n' lambdas including n-n + for neutral1 in neutrals[N0:]: + inn = "-".join((neutral0, neutral1)) + if inn not in self.lambd.keys(): + self.lambd[inn] = prm.lambd_none + # n-n-n mus + innn = "-".join((neutral0, neutral0, neutral0)) + if innn not in self.mu.keys(): + self.mu[innn] = prm.mu_none + + def print_parameters(self, T, P, filename): + """Print all parameter values at a given temperature and pressure + to a text file. + """ + f = open(filename, "w") + f.write("Parameter library: {} [pytzer-v{}]\n\n".format(self.name, version)) + ionslist = "Ions: " + (len(self.ions) - 1) * "{}, " + "{}\n\n" + f.write(ionslist.format(*self.ions)) + # srcslist = 'Sources: ' + (len(self.srcs)-1)*'{}, ' + '{}\n\n' + # f.write(srcslist.format(*self.srcs)) + f.write("Temperature: {} K\n".format(T)) + f.write(" Pressure: {} dbar\n\n".format(P)) + # Debye-Hueckel slope + f.write("Debye-Hueckel limiting slope\n") + f.write("============================\n") + eval_Aosm = self.dh["Aosm"](T, P)[0] + src = self.dh["Aosm"].__name__.split("_")[-1] + f.write("{:^12} {:15}\n".format("Aosm", "source")) + f.write("{:>12.9f} {:15}\n".format(eval_Aosm, src)) + # Write cation-anion parameters (betas and Cs) + f.write("\n") + f.write("c-a pairs (betas and Cs)\n") + f.write("========================\n") + bChead = 2 * "{:7}" + 5 * "{:^13}" + 3 * "{:>6}" + " {:15}\n" + bCvals = 2 * "{:7}" + 5 * "{:>13.5e}" + 3 * "{:>6.1f}" + " {:15}\n" + f.write( + bChead.format( + "cat", + "ani", + "b0", + "b1", + "b2", + "C0", + "C1", + "al1", + "al2", + "omg", + "source", + ) + ) + for bC in self.bC.keys(): + cation, anion = bC.split("-") + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = self.bC[bC](T, P) + src = self.bC[bC].__name__.split("_")[-1] + f.write( + bCvals.format( + cation, anion, b0, b1, b2, C0, C1, alph1, alph2, omega, src + ) + ) + # Write same charge ion-ion parameters (thetas) + f.write("\n") + f.write("c-c' and a-a' pairs (thetas)\n") + f.write("============================\n") + thetaHead = 2 * "{:7}" + "{:^13}" + " {:15}\n" + thetaVals = 2 * "{:7}" + "{:>13.5e}" + " {:15}\n" + f.write(thetaHead.format("ion1", "ion2", "theta", "source")) + for theta in self.theta.keys(): + ion0, ion1 = theta.split("-") + eval_theta = self.theta[theta](T, P)[0] + src = self.theta[theta].__name__.split("_")[-1] + f.write(thetaVals.format(ion0, ion1, eval_theta, src)) + # Write ion triplet parameters (psis) + f.write("\n") + f.write("c-c'-a and c-a-a' triplets (psis)\n") + f.write("=================================\n") + psiHead = 3 * "{:7}" + "{:^12}" + " {:15}\n" + psiVals = 3 * "{:7}" + "{:>12.5e}" + " {:15}\n" + f.write(psiHead.format("ion1", "ion2", "ion3", "psi", "source")) + for psi in self.psi.keys(): + ion0, ion1, ion2 = psi.split("-") + eval_psi = self.psi[psi](T, P)[0] + src = self.psi[psi].__name__.split("_")[-1] + f.write(psiVals.format(ion0, ion1, ion2, eval_psi, src)) + # Write neutral-ion parameters (lambdas) + f.write("\n") + f.write("n-c, n-a and n-n' pairs (lambdas)\n") + f.write("=================================\n") + lambdHead = 2 * "{:7}" + "{:^13}" + " {:15}\n" + lambdVals = 2 * "{:7}" + "{:>13.5e}" + " {:15}\n" + f.write(lambdHead.format("neut", "ion", "lambda", "source")) + for lambd in self.lambd.keys(): + neut, ion = lambd.split("-") + eval_lambd = self.lambd[lambd](T, P)[0] + src = self.lambd[lambd].__name__.split("_")[-1] + f.write(lambdVals.format(neut, ion, eval_lambd, src)) + # Write neutral-cation-anion triplet parameters (zetas) + f.write("\n") + f.write("n-c-a triplets (zetas)\n") + f.write("======================\n") + zetaHead = 3 * "{:7}" + "{:^12}" + " {:15}\n" + zetaVals = 3 * "{:7}" + "{:>12.5e}" + " {:15}\n" + f.write(zetaHead.format("neut", "cat", "ani", "zeta", "source")) + for zeta in self.zeta.keys(): + neut, cat, ani = zeta.split("-") + eval_zeta = self.zeta[zeta](T, P)[0] + src = self.zeta[zeta].__name__.split("_")[-1] + f.write(zetaVals.format(neut, cat, ani, eval_zeta, src)) + # Write neutral-neutral-neutral triplet parameters (mus) + f.write("\n") + f.write("n-n-n triplets (mus)\n") + f.write("====================\n") + muHead = 3 * "{:7}" + "{:^12}" + " {:15}\n" + muVals = 3 * "{:7}" + "{:>12.5e}" + " {:15}\n" + f.write(muHead.format("neut1", "neut2", "neut3", "mu", "source")) + for mu in self.mu.keys(): + neut1, neut2, neut3 = mu.split("-") + eval_mu = self.mu[mu](T, P)[0] + src = self.mu[mu].__name__.split("_")[-1] + f.write(muVals.format(neut1, neut2, neut3, eval_mu, src)) + + def get_contents(self): + """Get all ions and sources in the parameter library.""" + ctypes = [self.bC, self.theta, self.psi, self.lambd, self.zeta, self.mu] + ctypes = [ctype for ctype in ctypes if any(ctype)] + self.ions = unique( + concatenate([key.split("-") for ctype in ctypes for key in ctype.keys()]) + ) + self.srcs = unique( + concatenate( + [ + [ctype[key].__name__.split("_")[-1] for key in ctype.keys()] + for ctype in ctypes + ] + ) + ) + self.ions.sort() + self.srcs.sort() diff --git a/pytzer4/libraries/Seawater.py b/pytzer4/libraries/Seawater.py new file mode 100644 index 00000000..c36eb712 --- /dev/null +++ b/pytzer4/libraries/Seawater.py @@ -0,0 +1,38 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from copy import deepcopy +from .. import parameters as prm +from .. import debyehueckel # , dissociation + +# Start from MIAMI plus MarChemSpec equilibria and mu +from . import MarChemSpec, MIAMI + +name = "Seawater" +# Copy MIAMI/MarChemSpec: +jfunc = deepcopy(MIAMI.jfunc) +bC = deepcopy(MIAMI.bC) +theta = deepcopy(MIAMI.theta) +psi = deepcopy(MIAMI.psi) +lambd = deepcopy(MIAMI.lambd) +zeta = deepcopy(MIAMI.zeta) +mu = deepcopy(MarChemSpec.mu) +lnk = deepcopy(MIAMI.lnk) +# Overwrite MIAMI/MarChemSpec: +dh = {"Aosm": debyehueckel.Aosm_AW90} +bC["Na-Cl"] = prm.bC_Na_Cl_A92ii +bC["K-Cl"] = prm.bC_K_Cl_ZD17 +bC["Na-HCO3"] = prm.bC_Na_HCO3_HM93 +bC["K-HCO3"] = prm.bC_K_HCO3_HM93 +bC["Mg-HCO3"] = prm.bC_Mg_HCO3_HM93 +bC["Ca-HCO3"] = prm.bC_Ca_HCO3_HM93 +bC["Na-CO3"] = prm.bC_Na_CO3_HM93 +bC["K-CO3"] = prm.bC_K_CO3_HM93 +bC["Mg-CO3"] = prm.bC_Mg_CO3_HM93 +bC["Ca-CO3"] = prm.bC_Ca_CO3_HM93 +bC["H-Br"] = prm.bC_H_Br_JESS +bC["H-Cl"] = prm.bC_H_Cl_JESS +bC["K-Br"] = prm.bC_K_Br_JESS +bC["K-Cl"] = prm.bC_K_Cl_JESS +bC["K-OH"] = prm.bC_K_OH_JESS +bC["Na-Br"] = prm.bC_Na_Br_JESS +# Extend MIAMI/MarChemSpec: diff --git a/pytzer4/libraries/WM13.py b/pytzer4/libraries/WM13.py new file mode 100644 index 00000000..f2274250 --- /dev/null +++ b/pytzer4/libraries/WM13.py @@ -0,0 +1,112 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from .. import parameters as prm +from .. import debyehueckel, unsymmetrical + +# Waters and Millero (2013). Mar. Chem. 149, 8-22, +# doi:10.1016/j.marchem.2012.11.003 +name = "WM13" +dh = {"Aosm": debyehueckel.Aosm_M88} +jfunc = unsymmetrical.Harvie +bC = {} +theta = {} +psi = {} +# Table A1: Na salts +bC["Na-Cl"] = prm.bC_Na_Cl_M88 +bC["Na-SO4"] = prm.bC_Na_SO4_HM86 +bC["Na-HSO4"] = prm.bC_Na_HSO4_HPR93 +bC["Na-OH"] = prm.bC_Na_OH_PP87i +# Table A2: Mg salts +bC["Mg-Cl"] = prm.bC_Mg_Cl_dLP83 +bC["Mg-SO4"] = prm.bC_Mg_SO4_PP86ii +bC["Mg-HSO4"] = prm.bC_Mg_HSO4_RC99 +# Table A3: Ca salts +bC["Ca-Cl"] = prm.bC_Ca_Cl_GM89 +bC["Ca-SO4"] = prm.bC_Ca_SO4_WM13 +bC["Ca-HSO4"] = prm.bC_Ca_HSO4_WM13 +bC["Ca-OH"] = prm.bC_Ca_OH_HMW84 +# Table A4: K salts +bC["K-Cl"] = prm.bC_K_Cl_GM89 +bC["K-SO4"] = prm.bC_K_SO4_HM86 +bC["K-HSO4"] = prm.bC_K_HSO4_WM13 +bC["K-OH"] = prm.bC_K_OH_HMW84 +# Table A5: H+ interactions +bC["H-Cl"] = prm.bC_H_Cl_CMR93 +bC["H-SO4"] = prm.bC_H_SO4_CRP94 +bC["H-HSO4"] = prm.bC_H_HSO4_CRP94 +# Table A6: MgOH+ interactions +bC["MgOH-Cl"] = prm.bC_MgOH_Cl_HMW84 +# Table A7: cation-cation interactions +theta["H-Na"] = prm.theta_H_Na_CMR93 +theta["H-Mg"] = prm.theta_H_Mg_RGB80 +theta["Ca-H"] = prm.theta_Ca_H_RGO81 # WM13 citation error +theta["H-K"] = prm.theta_H_K_CMR93 +theta["Mg-Na"] = prm.theta_Mg_Na_HMW84 +theta["Ca-Na"] = prm.theta_Ca_Na_HMW84 +theta["K-Na"] = prm.theta_K_Na_HMW84 +theta["Ca-Mg"] = prm.theta_Ca_Mg_HMW84 +theta["K-Mg"] = prm.theta_K_Mg_HMW84 +theta["Ca-K"] = prm.theta_Ca_K_HMW84 +# Table A7: anion-anion interactions +theta["Cl-SO4"] = prm.theta_Cl_SO4_HMW84 +theta["Cl-HSO4"] = prm.theta_Cl_HSO4_HMW84 +theta["Cl-OH"] = prm.theta_Cl_OH_HMW84 +theta["HSO4-SO4"] = prm.theta_HSO4_SO4_WM13 +theta["OH-SO4"] = prm.theta_OH_SO4_HMW84 +# Table A8: c-a-a' triplets +psi["H-Cl-SO4"] = prm.psi_H_Cl_SO4_WM13 # agrees with HMW84 +psi["Na-Cl-SO4"] = prm.psi_Na_Cl_SO4_HMW84 +psi["Mg-Cl-SO4"] = prm.psi_Mg_Cl_SO4_HMW84 +psi["Ca-Cl-SO4"] = prm.psi_Ca_Cl_SO4_HMW84 +psi["K-Cl-SO4"] = prm.psi_K_Cl_SO4_HMW84 +psi["H-Cl-HSO4"] = prm.psi_H_Cl_HSO4_HMW84 +psi["Na-Cl-HSO4"] = prm.psi_Na_Cl_HSO4_HMW84 +psi["Mg-Cl-HSO4"] = prm.psi_Mg_Cl_HSO4_HMW84 +psi["Ca-Cl-HSO4"] = prm.psi_Ca_Cl_HSO4_HMW84 +psi["K-Cl-HSO4"] = prm.psi_K_Cl_HSO4_HMW84 +psi["H-Cl-OH"] = prm.psi_H_Cl_OH_WM13 # agrees with HMW84 +psi["Na-Cl-OH"] = prm.psi_Na_Cl_OH_HMW84 +psi["Mg-Cl-OH"] = prm.psi_Mg_Cl_OH_WM13 # agrees with HMW84 +psi["Ca-Cl-OH"] = prm.psi_Ca_Cl_OH_HMW84 +psi["K-Cl-OH"] = prm.psi_K_Cl_OH_HMW84 +psi["H-HSO4-SO4"] = prm.psi_H_HSO4_SO4_HMW84 +psi["Na-HSO4-SO4"] = prm.psi_Na_HSO4_SO4_HMW84 +psi["Mg-HSO4-SO4"] = prm.psi_Mg_HSO4_SO4_RC99 +psi["Ca-HSO4-SO4"] = prm.psi_Ca_HSO4_SO4_WM13 # agrees with HMW84 +psi["K-HSO4-SO4"] = prm.psi_K_HSO4_SO4_HMW84 +psi["H-OH-SO4"] = prm.psi_H_OH_SO4_WM13 # agrees with HMW84 +psi["Na-OH-SO4"] = prm.psi_Na_OH_SO4_HMW84 +psi["Mg-OH-SO4"] = prm.psi_Mg_OH_SO4_WM13 # agrees with HMW84 +psi["Ca-OH-SO4"] = prm.psi_Ca_OH_SO4_WM13 # agrees with HMW84 +psi["K-OH-SO4"] = prm.psi_K_OH_SO4_HMW84 +# Table A9: c-c'-a triplets +psi["H-Na-Cl"] = prm.psi_H_Na_Cl_HMW84 +psi["H-Na-SO4"] = prm.psi_H_Na_SO4_WM13 # agrees with HMW84 +psi["H-Na-HSO4"] = prm.psi_H_Na_HSO4_HMW84 +psi["H-Mg-Cl"] = prm.psi_H_Mg_Cl_HMW84 +psi["H-Mg-SO4"] = prm.psi_H_Mg_SO4_RC99 +psi["H-Mg-HSO4"] = prm.psi_H_Mg_HSO4_RC99 +psi["Ca-H-Cl"] = prm.psi_Ca_H_Cl_HMW84 +psi["Ca-H-SO4"] = prm.psi_Ca_H_SO4_WM13 # agrees with HMW84 +psi["Ca-H-HSO4"] = prm.psi_Ca_H_HSO4_WM13 # agrees with HMW84 +psi["H-K-Cl"] = prm.psi_H_K_Cl_HMW84 +psi["H-K-SO4"] = prm.psi_H_K_SO4_HMW84 +psi["H-K-HSO4"] = prm.psi_H_K_HSO4_HMW84 +psi["Mg-Na-Cl"] = prm.psi_Mg_Na_Cl_HMW84 +psi["Mg-Na-SO4"] = prm.psi_Mg_Na_SO4_HMW84 +psi["Mg-Na-HSO4"] = prm.psi_Mg_Na_HSO4_WM13 # agrees with HMW84 +psi["Ca-Na-Cl"] = prm.psi_Ca_Na_Cl_HMW84 +psi["Ca-Na-SO4"] = prm.psi_Ca_Na_SO4_HMW84 +psi["Ca-Na-HSO4"] = prm.psi_Ca_Na_HSO4_WM13 # agrees with HMW84 +psi["K-Na-Cl"] = prm.psi_K_Na_Cl_HMW84 +psi["K-Na-SO4"] = prm.psi_K_Na_SO4_HMW84 +psi["K-Na-HSO4"] = prm.psi_K_Na_HSO4_WM13 # agrees with HMW84 +psi["Ca-Mg-Cl"] = prm.psi_Ca_Mg_Cl_HMW84 +psi["Ca-Mg-SO4"] = prm.psi_Ca_Mg_SO4_HMW84 +psi["Ca-Mg-HSO4"] = prm.psi_Ca_Mg_HSO4_WM13 # agrees with HMW84 +psi["K-Mg-Cl"] = prm.psi_K_Mg_Cl_HMW84 +psi["K-Mg-SO4"] = prm.psi_K_Mg_SO4_HMW84 +psi["K-Mg-HSO4"] = prm.psi_K_Mg_HSO4_WM13 # agrees with HMW84 +psi["Ca-K-Cl"] = prm.psi_Ca_K_Cl_HMW84 +psi["Ca-K-SO4"] = prm.psi_Ca_K_SO4_WM13 # agrees with HMW84 +psi["Ca-K-HSO4"] = prm.psi_Ca_K_HSO4_WM13 # agrees with HMW84 diff --git a/pytzer4/libraries/WM13_MarChemSpec25.py b/pytzer4/libraries/WM13_MarChemSpec25.py new file mode 100644 index 00000000..a5495a59 --- /dev/null +++ b/pytzer4/libraries/WM13_MarChemSpec25.py @@ -0,0 +1,20 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +from copy import deepcopy +from .. import parameters as prm +from .. import debyehueckel, unsymmetrical + +# Waters and Millero (2013). Mar. Chem. 149, 8-22, +# doi:10.1016/j.marchem.2012.11.003 +from . import WM13 + +name = "WM13_MarChemSpec25" +dh = {"Aosm": debyehueckel.Aosm_MarChemSpec25} +jfunc = unsymmetrical.P75_eq47 +bC = deepcopy(WM13.bC) +theta = deepcopy(WM13.theta) +theta["H-Na"] = prm.theta_H_Na_MarChemSpec25 +theta["H-K"] = prm.theta_H_K_MarChemSpec25 +theta["Ca-H"] = prm.theta_Ca_H_MarChemSpec +psi = deepcopy(WM13.psi) +psi["Mg-MgOH-Cl"] = prm.psi_Mg_MgOH_Cl_HMW84 diff --git a/pytzer4/libraries/__init__.py b/pytzer4/libraries/__init__.py new file mode 100644 index 00000000..b64ad3ba --- /dev/null +++ b/pytzer4/libraries/__init__.py @@ -0,0 +1,86 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Assemble dicts of Pitzer model interaction parameter functions into +parameter libraries. +""" +from autograd.numpy import array +from .ParameterLibrary import ParameterLibrary +from . import ( + CRP94, + GM89, + HMW84, + M88, + MarChemSpec, + MarChemSpec05, + MarChemSpec25, + MIAMI, + Seawater, + WM13, + WM13_MarChemSpec25, +) + +__all__ = [ + "CRP94", + "GM89", + "HMW84", + "M88", + "MarChemSpec", + "MarChemSpec05", + "MarChemSpec25", + "MIAMI", + "Seawater", + "WM13", + "WM13_MarChemSpec25", +] + +MarChemSpecSolutes = array( + ["H", "Na", "Mg", "Ca", "K", "MgOH", "trisH", "Cl", "SO4", "HSO4", "OH", "tris"] +) + +# Clegg et al. (1994) +CRP94 = ParameterLibrary(module=CRP94) +CRP94.get_contents() + +# Greenberg & Møller (1989) +GM89 = ParameterLibrary(module=GM89) +GM89.get_contents() + +# Harvie, Møller & Weare (1984) +HMW84 = ParameterLibrary(module=HMW84) +HMW84.get_contents() + +# Møller (1988) +M88 = ParameterLibrary(module=M88) +M88.get_contents() + +# Begin with WM13_MarChemSpec25, switch to CRP94 corrected Aosm, T-variable +MarChemSpec = ParameterLibrary(module=MarChemSpec) +MarChemSpec.add_zeros(MarChemSpecSolutes) +MarChemSpec.get_contents() + +# MarChemSpec project (i.e. WM13 plus tris) with Aosm at 5 degC +MarChemSpec05 = ParameterLibrary(module=MarChemSpec05) +MarChemSpec05.add_zeros(MarChemSpecSolutes) +MarChemSpec05.get_contents() + +# MarChemSpec project (i.e. WM13 plus tris) with Aosm at 25 degC +MarChemSpec25 = ParameterLibrary(module=MarChemSpec25) +MarChemSpec25.add_zeros(MarChemSpecSolutes) +MarChemSpec25.get_contents() + +# Millero & Pierrot 1998 aka MIAMI - WORK IN PROGRESS! +MIAMI = ParameterLibrary(module=MIAMI) +MIAMI.get_contents() + +# Seawater: MarChemSpec with pressure +Seawater = ParameterLibrary(module=Seawater) +Seawater.add_zeros(MarChemSpecSolutes) +Seawater.get_contents() + +# Waters & Millero (2013) +WM13 = ParameterLibrary(module=WM13) +WM13.get_contents() + +# Waters & Millero (2013) with Aosm at 25 degC +WM13_MarChemSpec25 = ParameterLibrary(module=WM13_MarChemSpec25) +WM13_MarChemSpec25.get_contents() diff --git a/pytzer4/matrix.py b/pytzer4/matrix.py new file mode 100644 index 00000000..ca01f973 --- /dev/null +++ b/pytzer4/matrix.py @@ -0,0 +1,274 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Pitzer model implemented using matrix notation.""" +from scipy.special import comb +from autograd import elementwise_grad as egrad +from autograd.numpy import ( + array, + exp, + log, + ones, + size, + sqrt, + transpose, + triu_indices, + zeros, +) +from autograd.numpy import abs as np_abs +from autograd.numpy import sum as np_sum +from . import properties +from .libraries import MarChemSpec +from .constants import b, Mw +from .model import g, h +from .unsymmetrical import P75_eq47 as jfunc + + +def Istr(mols, zs): + """Ionic strength.""" + return mols @ transpose(zs**2) / 2 + + +def Zstr(mols, zs): + """Z function.""" + return mols @ transpose(np_abs(zs)) + + +def fG(Aosm, I): + """Debye-Hueckel component of the excess Gibbs energy.""" + return -4 * I * Aosm * log(1 + b * sqrt(I)) / b + + +def BCT(I, Z, b0, b1, b2, alph1, alph2, C0, C1, omega): + """Combined B and CT terms.""" + return ( + b0 + + b1 * g(alph1 * sqrt(I)) + + b2 * g(alph2 * sqrt(I)) + + (C0 + 4 * C1 * h(omega * sqrt(I))) * Z / 2 + ) + + +def xij(Aosm, I, zs): + """xij function for unsymmetrical mixing.""" + return (transpose(zs) @ zs) * 6 * Aosm * sqrt(I) + + +def xi(Aosm, I, zs): + """xi function for unsymmetrical mixing.""" + return zs**2 * 6 * Aosm * sqrt(I) + + +def xj(Aosm, I, zs): + """xj function for unsymmetrical mixing.""" + return transpose(zs**2) * 6 * Aosm * sqrt(I) + + +def etheta(Aosm, I, zs): + """E-theta function for unsymmetrical mixing.""" + x01 = xij(Aosm, I, zs) + x00 = xi(Aosm, I, zs) + x11 = xj(Aosm, I, zs) + return (transpose(zs) @ zs) * (jfunc(x01) - (jfunc(x00) + jfunc(x11)) / 2) / (4 * I) + + +def Gex_nRT(mols, allmxs): + """Excess Gibbs energy of a solution.""" + ( + zs, + Aosm, + b0mx, + b1mx, + b2mx, + C0mx, + C1mx, + alph1mx, + alph2mx, + omegamx, + thetamx, + lambdamx, + psimxcca, + psimxcaa, + zetamx, + mumx, + ) = allmxs + I = Istr(mols, zs) + cats = array([mols[zs > 0]]) + anis = array([mols[zs < 0]]) + neus = array([mols[zs == 0]]) + catsanis = array([(transpose(cats) @ anis).ravel()]) + if I == 0: + Gex_nRT = ( + mols @ lambdamx @ transpose(mols) + + neus @ zetamx @ transpose(catsanis) + + neus**3 @ mumx + )[0] + else: + Z = Zstr(mols, zs) + zcats = array([zs[zs > 0]]) + zanis = array([zs[zs < 0]]) + catscats = array([(transpose(cats) @ cats)[triu_indices(len(cats[0]), k=1)]]) + anisanis = array([(transpose(anis) @ anis)[triu_indices(len(anis[0]), k=1)]]) + Gex_nRT = ( + fG(Aosm, I) + + mols + @ ( + BCT(I, Z, b0mx, b1mx, b2mx, alph1mx, alph2mx, C0mx, C1mx, omegamx) + + thetamx + + lambdamx + ) + @ transpose(mols) + + cats @ etheta(Aosm, I, zcats) @ transpose(cats) + + anis @ etheta(Aosm, I, zanis) @ transpose(anis) + + catscats @ psimxcca @ transpose(anis) + + anisanis @ psimxcaa @ transpose(cats) + + neus @ zetamx @ transpose(catsanis) + + neus**3 @ mumx + ) + return Gex_nRT[0] + + +def ln_acfs(mols, allmxs): + """Natural logarithms of the activity coefficients of all solutes.""" + return egrad(Gex_nRT)(mols, allmxs)[0] + + +def acfs(mols, allmxs): + """Activity coefficients of all solutes.""" + return exp(ln_acfs(mols, allmxs)) + + +def lnaw(mols, allmxs): + """Natural log of the water activity.""" + ww = 1.0 + return ( + egrad(lambda ww: ww * Gex_nRT(mols / ww, allmxs))(ww) - np_sum(mols, axis=1) + ) * Mw + + +def aw(mols, allmxs): + """Water activity.""" + return exp(lnaw(mols, allmxs)) + + +def osm(mols, allmxs): + """Calculate the osmotic coefficient.""" + ww = 1.0 + return 1.0 - egrad(lambda ww: ww * Gex_nRT(mols / ww, allmxs))(ww) / np_sum(mols) + + +def assemble(ions, tempK, pres, prmlib=MarChemSpec): + """Assemble parameter matrices.""" + zs, cations, anions, neutrals = properties.charges(ions) + zs = transpose(zs) + Aosm = prmlib.dh["Aosm"](tempK, pres)[0][0] + iisize = (size(ions), size(ions)) + b0mx = zeros(iisize) + b1mx = zeros(iisize) + b2mx = zeros(iisize) + C0mx = zeros(iisize) + C1mx = zeros(iisize) + alph1mx = -9 * ones(iisize) + alph2mx = -9 * ones(iisize) + omegamx = -9 * ones(iisize) + thetamx = zeros(iisize) + lambdamx = zeros(iisize) + psimxcca = zeros((int(comb(size(cations), 2)), size(anions))) + psimxcaa = zeros((int(comb(size(anions), 2)), size(cations))) + zetamx = zeros((size(neutrals), size(cations) * size(anions))) + mumx = zeros((size(neutrals), 1)) + # Pairwise matrices: + for IX, ionx in enumerate(ions): + for IY, iony in enumerate(ions): + if ionx in cations and iony in anions: + iset = "-".join((ionx, iony)) + ( + b0mx[IX, IY], + b1mx[IX, IY], + b2mx[IX, IY], + C0mx[IX, IY], + C1mx[IX, IY], + alph1mx[IX, IY], + alph2mx[IX, IY], + omegamx[IX, IY], + _, + ) = prmlib.bC[iset](tempK, pres) + elif ionx in anions and iony in cations: + iset = "-".join((iony, ionx)) + ( + b0mx[IX, IY], + b1mx[IX, IY], + b2mx[IX, IY], + C0mx[IX, IY], + C1mx[IX, IY], + alph1mx[IX, IY], + alph2mx[IX, IY], + omegamx[IX, IY], + _, + ) = prmlib.bC[iset](tempK, pres) + elif ( + (ionx in cations and iony in cations) + or (ionx in anions and iony in anions) + ) and ionx != iony: + iset = [ionx, iony] + iset.sort() + iset = "-".join(iset) + thetamx[IX, IY] = prmlib.theta[iset](tempK, pres)[0] + elif ionx in neutrals: + iset = [ionx, iony] + if iony in neutrals: + iset.sort() + iset = "-".join(iset) + lambdamx[IX, IY] = prmlib.lambd[iset](tempK, pres)[0] + elif iony in neutrals: + iset = [iony, ionx] + if ionx in neutrals: + iset.sort() + iset = "-".join(iset) + lambdamx[IX, IY] = prmlib.lambd[iset](tempK, pres)[0] + # Ionic triplet interactions: + CC = 0 + for CX, cationx in enumerate(cations): + for xCY, cationy in enumerate(cations[CX + 1 :]): + iset = [cationx, cationy] + iset.sort() + iset = "-".join(iset) + for A, anion in enumerate(anions): + iset3 = "-".join((iset, anion)) + psimxcca[CC, A] = prmlib.psi[iset3](tempK, pres)[0] + CC = CC + 1 + AA = 0 + for AX, anionx in enumerate(anions): + for xAY, aniony in enumerate(anions[AX + 1 :]): + iset = [anionx, aniony] + iset.sort() + iset = "-".join(iset) + for C, cation in enumerate(cations): + iset3 = "-".join((cation, iset)) + psimxcaa[AA, C] = prmlib.psi[iset3](tempK, pres)[0] + AA = AA + 1 + # Neutral triplets: + for N, neutral in enumerate(neutrals): + iset3 = "-".join((neutral, neutral, neutral)) + mumx[N, 0] = prmlib.mu[iset3](tempK, pres)[0] + for C, cation in enumerate(cations): + for A, anion in enumerate(anions): + iset3 = "-".join((neutral, cation, anion)) + zetamx[N, C * size(anions) + A] = prmlib.zeta[iset3](tempK, pres)[0] + return ( + zs, + Aosm, + b0mx, + b1mx, + b2mx, + C0mx, + C1mx, + alph1mx, + alph2mx, + omegamx, + thetamx, + lambdamx, + psimxcca, + psimxcaa, + zetamx, + mumx, + ) diff --git a/pytzer4/meta.py b/pytzer4/meta.py new file mode 100644 index 00000000..7163bee6 --- /dev/null +++ b/pytzer4/meta.py @@ -0,0 +1,48 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Define module metadata.""" +from . import parameters + +version = "0.4.3" + + +def getprmfuncs(): + """Generate dict containing all interaction parameter functions.""" + functypes = ("bC", "theta", "psi", "lambd", "zeta", "mu") + functypes_ = tuple(["{}_".format(functype) for functype in functypes]) + allnames = [ + name + for name in dir(parameters) + if name.startswith(functypes_) and not name.endswith("_none") + ] + prmfuncs = { + functype: { + name: getattr(parameters, name) + for name in allnames + if name.startswith("{}_".format(functype)) + } + for functype in functypes + } + return prmfuncs + + +def getifuncs(itype, ions): + """Extract all interaction functions for a particular interaction.""" + prmfuncs = getprmfuncs() + ifuncs = { + name: prmfuncs[itype][name] + for name in prmfuncs[itype].keys() + if name.startswith(((1 + len(ions)) * "{}_").format(itype, *ions)) + } + return ifuncs + + +def evalifuncs(ifuncs, tempK, pres): + """Evaluate interaction parameters under given conditions.""" + ivals = {name: ifuncs[name](tempK, pres) for name in ifuncs.keys()} + return ivals + + +def getirefs(ifuncs): + """Generate a list of literature sources for the interaction functions.""" + return [name.split("_")[-1] for name in ifuncs.keys()] diff --git a/pytzer4/model.py b/pytzer4/model.py new file mode 100644 index 00000000..88cb1efc --- /dev/null +++ b/pytzer4/model.py @@ -0,0 +1,256 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Calculate solution properties using the Pitzer model.""" +from autograd.numpy import exp, full_like, log, sqrt, vstack, zeros_like +from autograd.numpy import abs as np_abs +from autograd.numpy import any as np_any +from autograd.numpy import sum as np_sum +from autograd import elementwise_grad as egrad +from .constants import b, Mw +from .libraries import Seawater +from . import properties + +# Debye-Hueckel slope +def fG(tempK, pres, I, prmlib): # from CRP94 Eq. (AI1) + """Calculate the Debye-Hueckel component of the excess Gibbs energy.""" + return -4 * prmlib.dh["Aosm"](tempK, pres)[0] * I * log(1 + b * sqrt(I)) / b + + +# Pitzer model subfunctions +def g(x): + """g function following CRP94 Eq. (AI13).""" + return 2 * (1 - (1 + x) * exp(-x)) / x**2 + + +def h(x): + """h function following CRP94 Eq. (AI15).""" + return (6 - (6 + x * (6 + 3 * x + x**2)) * exp(-x)) / x**4 + + +def B(I, b0, b1, b2, alph1, alph2): + """B function following CRP94 Eq. (AI7).""" + return b0 + b1 * g(alph1 * sqrt(I)) + b2 * g(alph2 * sqrt(I)) + + +def CT(I, C0, C1, omega): + """CT function following CRP94 Eq. (AI10).""" + return C0 + 4 * C1 * h(omega * sqrt(I)) + + +# Unsymmetrical mixing terms +def xij(tempK, pres, I, z0, z1, prmlib): + """xij function for unsymmetrical mixing.""" + return 6 * z0 * z1 * prmlib.dh["Aosm"](tempK, pres)[0] * sqrt(I) + + +def etheta(tempK, pres, I, z0, z1, prmlib): + """etheta function for unsymmetrical mixing.""" + x00 = xij(tempK, pres, I, z0, z0, prmlib) + x01 = xij(tempK, pres, I, z0, z1, prmlib) + x11 = xij(tempK, pres, I, z1, z1, prmlib) + etheta = ( + z0 + * z1 + * (prmlib.jfunc(x01) - 0.5 * (prmlib.jfunc(x00) + prmlib.jfunc(x11))) + / (4 * I) + ) + return etheta + + +# Ionic strength +def Istr(mols, zs): + """Calculate the ionic strength.""" + return 0.5 * np_sum(mols * zs**2, axis=0) + + +def Zstr(mols, zs): + """Calculate the Z function.""" + return np_sum(mols * np_abs(zs), axis=0) + + +# Excess Gibbs energy +def Gex_nRT(mols, ions, tempK, pres, prmlib=Seawater, Izero=False): + """Calculate the excess Gibbs energy of a solution.""" + # Note that oceanographers record ocean pressure as only due to the water, + # so at the sea surface pressure = 0 dbar, but the atmospheric pressure + # should also be taken into account for this model + # Ionic strength etc. + zs, cations, anions, neutrals = properties.charges(ions) + zs = vstack(zs) + I = Istr(mols, zs) + Z = Zstr(mols, zs) + # Split up concentrations + if np_any(zs == 0): + neus = vstack([mols[N] for N, _ in enumerate(zs) if zs[N] == 0]) + else: + neus = [] + if np_any(zs > 0): + cats = vstack([mols[C] for C, _ in enumerate(zs) if zs[C] > 0]) + else: + cats = [] + if np_any(zs < 0): + anis = vstack([mols[A] for A, _ in enumerate(zs) if zs[A] < 0]) + else: + anis = [] + # Initialise with zeros + Gex_nRT = zeros_like(tempK) + # Don't do ionic calculations if Izero is requested + if not Izero: + # Split up charges + zCs = vstack(zs[zs > 0]) + zAs = vstack(zs[zs < 0]) + # Begin with Debye-Hueckel component + Gex_nRT = Gex_nRT + fG(tempK, pres, I, prmlib) + # Loop through cations + for CX, cationx in enumerate(cations): + # Add c-a interactions + for A, anion in enumerate(anions): + iset = "-".join((cationx, anion)) + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = prmlib.bC[iset]( + tempK, pres + ) + Gex_nRT = Gex_nRT + cats[CX] * anis[A] * ( + 2 * B(I, b0, b1, b2, alph1, alph2) + Z * CT(I, C0, C1, omega) + ) + # Add c-c' interactions + for xCY, cationy in enumerate(cations[CX + 1 :]): + CY = xCY + CX + 1 + iset = [cationx, cationy] + iset.sort() + iset = "-".join(iset) + Gex_nRT = ( + Gex_nRT + + cats[CX] * cats[CY] * 2 * prmlib.theta[iset](tempK, pres)[0] + ) + # Unsymmetrical mixing terms + if zCs[CX] != zCs[CY]: + Gex_nRT = Gex_nRT + cats[CX] * cats[CY] * 2 * etheta( + tempK, pres, I, zCs[CX], zCs[CY], prmlib + ) + # Add c-c'-a interactions + for A, anion in enumerate(anions): + itri = "-".join((iset, anion)) + Gex_nRT = ( + Gex_nRT + + cats[CX] + * cats[CY] + * anis[A] + * prmlib.psi[itri](tempK, pres)[0] + ) + # Loop through anions + for AX, anionx in enumerate(anions): + # Add a-a' interactions + for xAY, aniony in enumerate(anions[AX + 1 :]): + AY = xAY + AX + 1 + iset = [anionx, aniony] + iset.sort() + iset = "-".join(iset) + Gex_nRT = ( + Gex_nRT + + anis[AX] * anis[AY] * 2 * prmlib.theta[iset](tempK, pres)[0] + ) + # Unsymmetrical mixing terms + if zAs[AX] != zAs[AY]: + Gex_nRT = Gex_nRT + anis[AX] * anis[AY] * 2 * etheta( + tempK, pres, I, zAs[AX], zAs[AY], prmlib + ) + # Add c-a-a' interactions + for C, cation in enumerate(cations): + itri = "-".join((cation, iset)) + Gex_nRT = ( + Gex_nRT + + anis[AX] + * anis[AY] + * cats[C] + * prmlib.psi[itri](tempK, pres)[0] + ) + # Add neutral interactions + for NX, neutralx in enumerate(neutrals): + # Add n-c interactions + for C, cation in enumerate(cations): + inc = "-".join((neutralx, cation)) + Gex_nRT = ( + Gex_nRT + neus[NX] * cats[C] * 2 * prmlib.lambd[inc](tempK, pres)[0] + ) + # Add n-c-a interactions + for A, anion in enumerate(anions): + inca = "-".join((inc, anion)) + Gex_nRT = ( + Gex_nRT + + neus[NX] * cats[C] * anis[A] * prmlib.zeta[inca](tempK, pres)[0] + ) + # Add n-a interactions + for A, anion in enumerate(anions): + ina = "-".join((neutralx, anion)) + Gex_nRT = ( + Gex_nRT + neus[NX] * anis[A] * 2 * prmlib.lambd[ina](tempK, pres)[0] + ) + # n-n' excluding n-n + for xNY, neutraly in enumerate(neutrals[NX + 1 :]): + NY = xNY + NX + 1 + inn = [neutralx, neutraly] + inn.sort() + inn = "-".join(inn) + Gex_nRT = ( + Gex_nRT + neus[NX] * neus[NY] * 2 * prmlib.lambd[inn](tempK, pres)[0] + ) + # n-n + inn = "-".join((neutralx, neutralx)) + Gex_nRT = Gex_nRT + neus[NX] ** 2 * prmlib.lambd[inn](tempK, pres)[0] + # n-n-n + innn = "-".join((neutralx, neutralx, neutralx)) + Gex_nRT = Gex_nRT + neus[NX] ** 3 * prmlib.mu[innn](tempK, pres)[0] + return Gex_nRT + + +# Solute activity coefficients +def ln_acfs(mols, ions, tempK, pres, prmlib=Seawater, Izero=False): + """Calculate the natural logarithms of the activity coefficients + of all solutes. + """ + return egrad(Gex_nRT)(mols, ions, tempK, pres, prmlib, Izero) + + +def acfs(mols, ions, tempK, pres, prmlib=Seawater, Izero=False): + """Calculate the activity coefficients of all solutes.""" + return exp(ln_acfs(mols, ions, tempK, pres, prmlib, Izero)) + + +def ln_acf2ln_acf_MX(ln_acfM, ln_acfX, nM, nX): + """Calculate the mean activity coefficient for an electrolyte.""" + return (nM * ln_acfM + nX * ln_acfX) / (nM + nX) + + +# Osmotic coefficient +def osm(mols, ions, tempK, pres, prmlib=Seawater, Izero=False): + """Calculate the osmotic coefficient.""" + ww = full_like(tempK, 1.0) + return 1 - egrad( + lambda ww: ww * Gex_nRT(mols / ww, ions, tempK, pres, prmlib, Izero) + )(ww) / np_sum(mols, axis=0) + + +# Water activity +def lnaw(mols, ions, tempK, pres, prmlib=Seawater, Izero=False): + """Calculate the natural log of the water activity.""" + ww = full_like(tempK, 1.0) + return ( + egrad(lambda ww: ww * Gex_nRT(mols / ww, ions, tempK, pres, prmlib, Izero))(ww) + - np_sum(mols, axis=0) + ) * Mw + + +def aw(mols, ions, tempK, pres, prmlib=Seawater, Izero=False): + """Calculate the water activity.""" + return exp(lnaw(mols, ions, tempK, pres, prmlib, Izero)) + + +# Conversions +def osm2aw(mols, osm): + """Convert osmotic coefficient to water activity.""" + return exp(-osm * Mw * np_sum(mols, axis=0)) + + +def aw2osm(mols, aw): + """Convert water activity to osmotic coefficient.""" + return -log(aw) / (Mw * np_sum(mols, axis=0)) diff --git a/pytzer4/parameters.py b/pytzer4/parameters.py new file mode 100644 index 00000000..17094784 --- /dev/null +++ b/pytzer4/parameters.py @@ -0,0 +1,12337 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Evaluate Pitzer model interaction parameters.""" +from autograd.numpy import array, float_, log, logical_and, sqrt +from autograd.numpy import abs as np_abs +from .constants import Tzero +from . import properties +from .properties import _ion2charge as i2c + +# Note that variable T in this module is equivalent to tempK elsewhere (in K), +# and P is equivalent to pres (in dbar), for convenience +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Zero functions ~~~~~ +def bC_none(T, P): + """c-a: no interaction effect.""" + b0 = 0 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = T > 0 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_none(T, P): + """i-i': no interaction effect.""" + theta = 0 + valid = T > 0 + return theta, valid + + +def psi_none(T, P): + """i-i'-j: no interaction effect.""" + psi = 0 + valid = T > 0 + return psi, valid + + +def lambd_none(T, P): + """n-s: no interaction effect.""" + lambd = 0 + valid = T > 0 + return lambd, valid + + +def zeta_none(T, P): + """n-c-a: no interaction effect.""" + valid = T > 0 + zeta = 0 + return zeta, valid + + +def mu_none(T, P): + """n-n-n: no interaction effect.""" + mu = 0 + valid = T > 0 + return mu, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pitzer & Margoya (1973) ~~~~~ +def bC_H_Cl_PM73(T, P): + """ "c-a: hydrogen chloride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1775 + b1 = 0.2945 + b2 = 0 + Cphi = 0.0008 + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_Br_PM73(T, P): + """ "c-a: hydrogen bromide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.196 + b1 = 0.3564 + b2 = 0 + Cphi = 0.00827 + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_I_PM73(T, P): + """ "c-a: hydrogen iodide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.2362 + b1 = 0.392 + b2 = 0 + Cphi = 0.0011 + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_ClO4_PM73(T, P): + """ "c-a: hydrogen perchlorate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1747 + b1 = 0.2931 + b2 = 0 + Cphi = 0.00819 + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_NO3_PM73(T, P): + """ "c-a: hydrogen nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1119 + b1 = 0.3206 + b2 = 0 + Cphi = 0.001 + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_Cl_PM73(T, P): + """ "c-a: lithium chloride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1494 + b1 = 0.3074 + b2 = 0 + Cphi = 0.00359 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_Br_PM73(T, P): + """ "c-a: lithium bromide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1748 + b1 = 0.2547 + b2 = 0 + Cphi = 0.0053 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_I_PM73(T, P): + """ "c-a: lithium iodide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.2104 + b1 = 0.373 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_OH_PM73(T, P): + """ "c-a: lithium hydroxide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.015 + b1 = 0.14 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_ClO4_PM73(T, P): + """ "c-a: lithium perchlorate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1973 + b1 = 0.3996 + b2 = 0 + Cphi = 0.0008 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_NO2_PM73(T, P): + """ "c-a: lithium nitrite [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1336 + b1 = 0.325 + b2 = 0 + Cphi = -0.0053 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["NO2"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_NO3_PM73(T, P): + """ "c-a: lithium nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.142 + b1 = 0.278 + b2 = 0 + Cphi = -0.00551 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_F_PM73(T, P): + """ "c-a: sodium fluoride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0215 + b1 = 0.2107 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Cl_PM73(T, P): + """ "c-a: sodium chloride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0765 + b1 = 0.2664 + b2 = 0 + Cphi = 0.00127 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Br_PM73(T, P): + """ "c-a: sodium bromide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0973 + b1 = 0.2791 + b2 = 0 + Cphi = 0.00116 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_I_PM73(T, P): + """ "c-a: sodium iodide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1195 + b1 = 0.3439 + b2 = 0 + Cphi = 0.0018 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_OH_PM73(T, P): + """ "c-a: sodium hydroxide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0864 + b1 = 0.253 + b2 = 0 + Cphi = 0.0044 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_ClO3_PM73(T, P): + """ "c-a: sodium chlorate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0249 + b1 = 0.2455 + b2 = 0 + Cphi = 0.0004 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["ClO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_ClO4_PM73(T, P): + """ "c-a: sodium perchlorate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0554 + b1 = 0.2755 + b2 = 0 + Cphi = -0.00118 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_BrO3_PM73(T, P): + """ "c-a: sodium bromate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0205 + b1 = 0.191 + b2 = 0 + Cphi = 0.0059 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["BrO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_SCN_PM73(T, P): + """ "c-a: sodium thiocyanate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1005 + b1 = 0.3582 + b2 = 0 + Cphi = -0.00303 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["SCN"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_NO2_PM73(T, P): + """ "c-a: sodium nitrite [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0641 + b1 = 0.1015 + b2 = 0 + Cphi = -0.0049 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["NO2"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_NO3_PM73(T, P): + """ "c-a: sodium nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0068 + b1 = 0.1783 + b2 = 0 + Cphi = -0.00072 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_H2PO4_PM73(T, P): + """ "c-a: sodium dihydrogen-phosphate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0533 + b1 = 0.0396 + b2 = 0 + Cphi = 0.00795 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["H2PO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_H2AsO4_PM73(T, P): + """ "c-a: sodium dihydrogen-arsenate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0442 + b1 = 0.2895 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["H2AsO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_BO2_PM73(T, P): + """ "c-a: sodium oxido(oxo)borane [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0526 + b1 = 0.1104 + b2 = 0 + Cphi = 0.0154 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["BO2"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_BF4_PM73(T, P): + """ "c-a: sodium tetrafluoroborate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0252 + b1 = 0.1824 + b2 = 0 + Cphi = 0.0021 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["BF4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_F_PM73(T, P): + """ "c-a: potassium fluoride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.08089 + b1 = 0.2021 + b2 = 0 + Cphi = 0.00093 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["F"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Cl_PM73(T, P): + """ "c-a: potassium chloride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.04835 + b1 = 0.2122 + b2 = 0 + Cphi = -0.00084 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Br_PM73(T, P): + """ "c-a: potassium bromide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0569 + b1 = 0.2212 + b2 = 0 + Cphi = -0.0018 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_I_PM73(T, P): + """ "c-a: potassium iodide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0746 + b1 = 0.2517 + b2 = 0 + Cphi = -0.00414 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_OH_PM73(T, P): + """ "c-a: potassium hydroxide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1298 + b1 = 0.32 + b2 = 0 + Cphi = 0.0041 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_ClO3_PM73(T, P): + """ "c-a: potassium chlorate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.096 + b1 = 0.2481 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["ClO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_BrO3_PM73(T, P): + """ "c-a: potassium bromate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.129 + b1 = 0.2565 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["BrO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_SCN_PM73(T, P): + """ "c-a: potassium thiocyanate [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0416 + b1 = 0.2302 + b2 = 0 + Cphi = -0.00252 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["SCN"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_NO2_PM73(T, P): + """ "c-a: potassium nitrite [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0151 + b1 = 0.015 + b2 = 0 + Cphi = 0.0007 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["NO2"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_NO3_PM73(T, P): + """ "c-a: potassium nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0816 + b1 = 0.0494 + b2 = 0 + Cphi = 0.0066 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_H2PO4_PM73(T, P): + """ "c-a: potassium dihydrogen-phosphate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0678 + b1 = -0.1042 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["H2PO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_H2AsO4_PM73(T, P): + """ "c-a: potassium dihydrogen-arsenate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0584 + b1 = 0.0626 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["H2AsO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_PtF6_PM73(T, P): + """ "c-a: potassium platinum-hexafluoride [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.163 + b1 = -0.282 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["PtF6"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_F_PM73(T, P): + """ "c-a: rubidium fluoride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1141 + b1 = 0.2842 + b2 = 0 + Cphi = -0.0105 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Rb"] * i2c["F"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_Cl_PM73(T, P): + """ "c-a: rubidium chloride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0441 + b1 = 0.1483 + b2 = 0 + Cphi = -0.00101 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Rb"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_Br_PM73(T, P): + """ "c-a: rubidium bromide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0396 + b1 = 0.153 + b2 = 0 + Cphi = -0.00144 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Rb"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_I_PM73(T, P): + """ "c-a: rubidium iodide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0397 + b1 = 0.133 + b2 = 0 + Cphi = -0.00108 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Rb"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_NO2_PM73(T, P): + """ "c-a: rubidium nitrite [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0269 + b1 = -0.1553 + b2 = 0 + Cphi = -0.00366 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Rb"] * i2c["NO2"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_NO3_PM73(T, P): + """ "c-a: rubidium nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0789 + b1 = -0.0172 + b2 = 0 + Cphi = 0.00529 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Rb"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_F_PM73(T, P): + """ "c-a: caesium fluoride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.1306 + b1 = 0.257 + b2 = 0 + Cphi = -0.0043 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["F"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_Cl_PM73(T, P): + """ "c-a: caesium chloride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.03 + b1 = 0.0558 + b2 = 0 + Cphi = 0.00038 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_Br_PM73(T, P): + """ "c-a: caesium bromide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0279 + b1 = 0.0139 + b2 = 0 + Cphi = 4e-05 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_I_PM73(T, P): + """ "c-a: caesium iodide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0244 + b1 = 0.0262 + b2 = 0 + Cphi = -0.00365 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_OH_PM73(T, P): + """ "c-a: caesium hydroxide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.15 + b1 = 0.3 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_NO3_PM73(T, P): + """ "c-a: caesium nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0758 + b1 = -0.0669 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_NO2_PM73(T, P): + """ "c-a: caesium nitrite [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0427 + b1 = 0.06 + b2 = 0 + Cphi = -0.0051 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["NO2"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ag_NO3_PM73(T, P): + """ "c-a: silver nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0856 + b1 = 0.0025 + b2 = 0 + Cphi = 0.00591 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ag"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Tl_ClO4_PM73(T, P): + """ "c-a: thallium perchlorate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.087 + b1 = -0.023 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Tl"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Tl_NO3_PM73(T, P): + """ "c-a: thallium nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.105 + b1 = -0.378 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Tl"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_Cl_PM73(T, P): + """ "c-a: ammonium chloride [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0522 + b1 = 0.1918 + b2 = 0 + Cphi = -0.00301 + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_Br_PM73(T, P): + """ "c-a: ammonium bromide [PM73].""" + # Coefficients from PM73 Table I + b0 = 0.0624 + b1 = 0.1947 + b2 = 0 + Cphi = -0.00436 + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_ClO4_PM73(T, P): + """ "c-a: ammonium perchlorate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0103 + b1 = -0.0194 + b2 = 0 + Cphi = 0.0 + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_NO3_PM73(T, P): + """ "c-a: ammonium nitrate [PM73].""" + # Coefficients from PM73 Table I + b0 = -0.0154 + b1 = 0.112 + b2 = 0 + Cphi = -3e-05 + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_Cl_PM73(T, P): + """ "c-a: magnesium chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4698 * 3 / 4 + b1 = 2.242 * 3 / 4 + b2 = 0 + Cphi = 0.00979 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_Br_PM73(T, P): + """ "c-a: magnesium bromide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.5769 * 3 / 4 + b1 = 2.337 * 3 / 4 + b2 = 0 + Cphi = 0.00589 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_I_PM73(T, P): + """ "c-a: magnesium iodide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.6536 * 3 / 4 + b1 = 2.4055 * 3 / 4 + b2 = 0 + Cphi = 0.01496 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_ClO4_PM73(T, P): + """ "c-a: magnesium perchlorate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.6615 * 3 / 4 + b1 = 2.678 * 3 / 4 + b2 = 0 + Cphi = 0.01806 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_NO3_PM73(T, P): + """ "c-a: magnesium nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4895 * 3 / 4 + b1 = 2.113 * 3 / 4 + b2 = 0 + Cphi = -0.03889 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_Cl_PM73(T, P): + """ "c-a: calcium chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4212 * 3 / 4 + b1 = 2.152 * 3 / 4 + b2 = 0 + Cphi = -0.00064 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_Br_PM73(T, P): + """ "c-a: calcium bromide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.5088 * 3 / 4 + b1 = 2.151 * 3 / 4 + b2 = 0 + Cphi = -0.00485 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_I_PM73(T, P): + """ "c-a: calcium iodide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.5839 * 3 / 4 + b1 = 2.409 * 3 / 4 + b2 = 0 + Cphi = -0.00158 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_ClO4_PM73(T, P): + """ "c-a: calcium perchlorate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.6015 * 3 / 4 + b1 = 2.342 * 3 / 4 + b2 = 0 + Cphi = -0.00943 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_NO3_PM73(T, P): + """ "c-a: calcium nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.2811 * 3 / 4 + b1 = 1.879 * 3 / 4 + b2 = 0 + Cphi = -0.03798 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_Cl_PM73(T, P): + """ "c-a: strontium chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.381 * 3 / 4 + b1 = 2.223 * 3 / 4 + b2 = 0 + Cphi = -0.00246 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sr"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_Br_PM73(T, P): + """ "c-a: strontium bromide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4415 * 3 / 4 + b1 = 2.282 * 3 / 4 + b2 = 0 + Cphi = 0.00231 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sr"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_I_PM73(T, P): + """ "c-a: strontium iodide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.535 * 3 / 4 + b1 = 2.48 * 3 / 4 + b2 = 0 + Cphi = 0.00501 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sr"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_ClO4_PM73(T, P): + """ "c-a: strontium perchlorate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.5692 * 3 / 4 + b1 = 2.089 * 3 / 4 + b2 = 0 + Cphi = -0.02472 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sr"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_NO3_PM73(T, P): + """ "c-a: strontium nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.1795 * 3 / 4 + b1 = 1.84 * 3 / 4 + b2 = 0 + Cphi = -0.03757 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sr"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_Cl_PM73(T, P): + """ "c-a: barium chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.3504 * 3 / 4 + b1 = 1.995 * 3 / 4 + b2 = 0 + Cphi = -0.03654 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ba"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_Br_PM73(T, P): + """ "c-a: barium bromide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4194 * 3 / 4 + b1 = 2.093 * 3 / 4 + b2 = 0 + Cphi = -0.03009 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ba"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_I_PM73(T, P): + """ "c-a: barium iodide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.5625 * 3 / 4 + b1 = 2.249 * 3 / 4 + b2 = 0 + Cphi = -0.03286 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ba"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_OH_PM73(T, P): + """ "c-a: barium hydroxide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.229 * 3 / 4 + b1 = 1.6 * 3 / 4 + b2 = 0 + Cphi = 0.0 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ba"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_ClO4_PM73(T, P): + """ "c-a: barium perchlorate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4819 * 3 / 4 + b1 = 2.101 * 3 / 4 + b2 = 0 + Cphi = -0.05894 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ba"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_NO3_PM73(T, P): + """ "c-a: barium nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = -0.043 * 3 / 4 + b1 = 1.07 * 3 / 4 + b2 = 0 + Cphi = 0.0 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ba"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mnjj_Cl_PM73(T, P): + """ "c-a: manganese(II) chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.1363 * 3 / 4 + b1 = 2.067 * 3 / 4 + b2 = 0 + Cphi = -0.03865 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mnjj"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Fejj_Cl_PM73(T, P): + """ "c-a: iron(II) chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4479 * 3 / 4 + b1 = 2.043 * 3 / 4 + b2 = 0 + Cphi = -0.01623 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Fejj"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cojj_Cl_PM73(T, P): + """ "c-a: cobalt(II) chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4857 * 3 / 4 + b1 = 1.936 * 3 / 4 + b2 = 0 + Cphi = -0.02869 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cojj"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cojj_Br_PM73(T, P): + """ "c-a: cobalt(II) bromide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.5693 * 3 / 4 + b1 = 2.213 * 3 / 4 + b2 = 0 + Cphi = -0.00127 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cojj"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cojj_I_PM73(T, P): + """ "c-a: cobalt(II) iodide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.695 * 3 / 4 + b1 = 2.23 * 3 / 4 + b2 = 0 + Cphi = -0.0088 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cojj"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cojj_NO3_PM73(T, P): + """ "c-a: cobalt(II) nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4159 * 3 / 4 + b1 = 2.254 * 3 / 4 + b2 = 0 + Cphi = -0.01436 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cojj"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Nijj_Cl_PM73(T, P): + """ "c-a: nickel(II) chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4639 * 3 / 4 + b1 = 2.108 * 3 / 4 + b2 = 0 + Cphi = -0.00702 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Nijj"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cujj_Cl_PM73(T, P): + """ "c-a: copper(II) chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4107 * 3 / 4 + b1 = 1.835 * 3 / 4 + b2 = 0 + Cphi = -0.07624 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cujj"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cujj_NO3_PM73(T, P): + """ "c-a: copper(II) nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4224 * 3 / 4 + b1 = 1.907 * 3 / 4 + b2 = 0 + Cphi = -0.04136 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cujj"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Znjj_Cl_PM73(T, P): + """ "c-a: zinc(II) chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.3469 * 3 / 4 + b1 = 2.19 * 3 / 4 + b2 = 0 + Cphi = -0.1659 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Znjj"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Znjj_Br_PM73(T, P): + """ "c-a: zinc(II) bromide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.6213 * 3 / 4 + b1 = 2.179 * 3 / 4 + b2 = 0 + Cphi = -0.2035 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Znjj"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Znjj_I_PM73(T, P): + """ "c-a: zinc(II) iodide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.6428 * 3 / 4 + b1 = 2.594 * 3 / 4 + b2 = 0 + Cphi = -0.0269 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Znjj"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Znjj_ClO4_PM73(T, P): + """ "c-a: zinc(II) perchlorate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.6747 * 3 / 4 + b1 = 2.396 * 3 / 4 + b2 = 0 + Cphi = 0.02134 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Znjj"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Znjj_NO3_PM73(T, P): + """ "c-a: zinc(II) nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4641 * 3 / 4 + b1 = 2.255 * 3 / 4 + b2 = 0 + Cphi = -0.02955 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Znjj"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cdjj_NO3_PM73(T, P): + """ "c-a: cadmium(II) nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.382 * 3 / 4 + b1 = 2.224 * 3 / 4 + b2 = 0 + Cphi = -0.04836 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cdjj"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Pbjj_ClO4_PM73(T, P): + """ "c-a: lead(II) perchlorate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.4443 * 3 / 4 + b1 = 2.296 * 3 / 4 + b2 = 0 + Cphi = -0.01667 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Pbjj"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Pbjj_NO3_PM73(T, P): + """ "c-a: lead(II) nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = -0.0482 * 3 / 4 + b1 = 0.38 * 3 / 4 + b2 = 0 + Cphi = 0.01005 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Pbjj"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_UO2_Cl_PM73(T, P): + """ "c-a: uranium-dioxide chloride [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.5698 * 3 / 4 + b1 = 2.192 * 3 / 4 + b2 = 0 + Cphi = -0.06951 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["UO2"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_UO2_ClO4_PM73(T, P): + """ "c-a: uranium-dioxide perchlorate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.8151 * 3 / 4 + b1 = 2.859 * 3 / 4 + b2 = 0 + Cphi = 0.04089 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["UO2"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_UO2_NO3_PM73(T, P): + """ "c-a: uranium-dioxide nitrate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.6143 * 3 / 4 + b1 = 2.151 * 3 / 4 + b2 = 0 + Cphi = -0.05948 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["UO2"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_SO4_PM73(T, P): + """ "c-a: lithium sulfate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.1817 * 3 / 4 + b1 = 1.694 * 3 / 4 + b2 = 0 + Cphi = -0.00753 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_SO4_PM73(T, P): + """ "c-a: sodium sulfate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.0261 * 3 / 4 + b1 = 1.484 * 3 / 4 + b2 = 0 + Cphi = 0.00938 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_S2O3_PM73(T, P): + """ "c-a: sodium thiosulfate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.0882 * 3 / 4 + b1 = 1.701 * 3 / 4 + b2 = 0 + Cphi = 0.00705 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["S2O3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_CrO4_PM73(T, P): + """ "c-a: sodium chromate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.125 * 3 / 4 + b1 = 1.826 * 3 / 4 + b2 = 0 + Cphi = -0.00407 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["CrO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_CO3_PM73(T, P): + """ "c-a: sodium carbonate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.253 * 3 / 4 + b1 = 1.128 * 3 / 4 + b2 = 0 + Cphi = -0.09057 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HPO4_PM73(T, P): + """ "c-a: sodium hydrogen-phosphate [PM73].""" + # Coefficients from PM73 Table VI + b0 = -0.0777 * 3 / 4 + b1 = 1.954 * 3 / 4 + b2 = 0 + Cphi = 0.0554 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["HPO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HAsO4_PM73(T, P): + """ "c-a: sodium hydrogen-arsenate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.0407 * 3 / 4 + b1 = 2.173 * 3 / 4 + b2 = 0 + Cphi = 0.0034 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["HAsO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_SO4_PM73(T, P): + """ "c-a: potassium sulfate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.0666 * 3 / 4 + b1 = 1.039 * 3 / 4 + b2 = 0 + Cphi = 0.0 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_CrO4_PM73(T, P): + """ "c-a: potassium chromate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.1011 * 3 / 4 + b1 = 1.652 * 3 / 4 + b2 = 0 + Cphi = -0.00147 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["CrO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_PtCN4_PM73(T, P): + """ "c-a: potassium platinocyanide [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.0881 * 3 / 4 + b1 = 3.164 * 3 / 4 + b2 = 0 + Cphi = 0.0247 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["PtCN4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HPO4_PM73(T, P): + """ "c-a: potassium hydrogen-phosphate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.033 * 3 / 4 + b1 = 1.699 * 3 / 4 + b2 = 0 + Cphi = 0.0309 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["HPO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HAsO4_PM73(T, P): + """ "c-a: potassium hydrogen-arsenate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.1728 * 3 / 4 + b1 = 2.198 * 3 / 4 + b2 = 0 + Cphi = -0.0336 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["HAsO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_SO4_PM73(T, P): + """ "c-a: rubidium sulfate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.0772 * 3 / 4 + b1 = 1.481 * 3 / 4 + b2 = 0 + Cphi = -0.00019 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Rb"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_SO4_PM73(T, P): + """ "c-a: caesium sulfate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.1184 * 3 / 4 + b1 = 1.481 * 3 / 4 + b2 = 0 + Cphi = -0.01131 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_SO4_PM73(T, P): + """ "c-a: ammonium sulfate [PM73].""" + # Coefficients from PM73 Table VI + b0 = 0.0545 * 3 / 4 + b1 = 0.878 * 3 / 4 + b2 = 0 + Cphi = -0.00219 * 3 / 2 ** (5 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Aljjj_Cl_PM73(T, P): + """ "c-a: aluminium(III) chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 1.049 * 2 / 3 + b1 = 8.767 * 2 / 3 + b2 = 0 + Cphi = 0.0071 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Aljjj"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Srjjj_Cl_PM73(T, P): + """ "c-a: strontium(III) chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 1.05 * 2 / 3 + b1 = 7.978 * 2 / 3 + b2 = 0 + Cphi = -0.084 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Srjjj"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Y_Cl_PM73(T, P): + """ "c-a: yttrium chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.9599 * 2 / 3 + b1 = 8.166 * 2 / 3 + b2 = 0 + Cphi = -0.0587 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Y"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_La_Cl_PM73(T, P): + """ "c-a: lanthanum chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.9158 * 2 / 3 + b1 = 8.231 * 2 / 3 + b2 = 0 + Cphi = -0.0831 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["La"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ce_Cl_PM73(T, P): + """ "c-a: cerium chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.9187 * 2 / 3 + b1 = 8.227 * 2 / 3 + b2 = 0 + Cphi = -0.0809 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ce"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Pr_Cl_PM73(T, P): + """ "c-a: praeseodymium chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.903 * 2 / 3 + b1 = 8.181 * 2 / 3 + b2 = 0 + Cphi = -0.0727 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Pr"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Nd_Cl_PM73(T, P): + """ "c-a: neodymium chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.9175 * 2 / 3 + b1 = 8.104 * 2 / 3 + b2 = 0 + Cphi = -0.0737 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Nd"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sm_Cl_PM73(T, P): + """ "c-a: samarium chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.933 * 2 / 3 + b1 = 8.273 * 2 / 3 + b2 = 0 + Cphi = -0.0728 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sm"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Eu_Cl_PM73(T, P): + """ "c-a: europium chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.937 * 2 / 3 + b1 = 8.385 * 2 / 3 + b2 = 0 + Cphi = -0.0687 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Eu"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cr_Cl_PM73(T, P): + """ "c-a: chromium chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 1.1046 * 2 / 3 + b1 = 7.883 * 2 / 3 + b2 = 0 + Cphi = -0.1172 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cr"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cr_NO3_PM73(T, P): + """ "c-a: chromium nitrate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 1.056 * 2 / 3 + b1 = 7.777 * 2 / 3 + b2 = 0 + Cphi = -0.1533 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cr"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ga_ClO4_PM73(T, P): + """ "c-a: gallium perchlorate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 1.2381 * 2 / 3 + b1 = 9.794 * 2 / 3 + b2 = 0 + Cphi = 0.0904 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ga"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_In_Cl_PM73(T, P): + """ "c-a: indium chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = -1.68 * 2 / 3 + b1 = -3.85 * 2 / 3 + b2 = 0 + Cphi = 0.0 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["In"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_PO4_PM73(T, P): + """ "c-a: sodium phosphate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.2672 * 2 / 3 + b1 = 5.777 * 2 / 3 + b2 = 0 + Cphi = -0.1339 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["PO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_AsO4_PM73(T, P): + """ "c-a: sodium arsenate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.3582 * 2 / 3 + b1 = 5.895 * 2 / 3 + b2 = 0 + Cphi = -0.124 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["AsO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_PO4_PM73(T, P): + """ "c-a: potassium phosphate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.5594 * 2 / 3 + b1 = 5.958 * 2 / 3 + b2 = 0 + Cphi = -0.2255 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["PO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_P3O9_PM73(T, P): + """ "c-a: potassium trimetaphosphate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.4867 * 2 / 3 + b1 = 8.349 * 2 / 3 + b2 = 0 + Cphi = -0.0886 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["P3O9"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_AsO4_PM73(T, P): + """ "c-a: potassium arsenate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.7491 * 2 / 3 + b1 = 6.511 * 2 / 3 + b2 = 0 + Cphi = -0.3376 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["AsO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_FejjjCN6_PM73(T, P): + """ "c-a: potassium ferricyanide [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.5035 * 2 / 3 + b1 = 7.121 * 2 / 3 + b2 = 0 + Cphi = -0.1176 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["FejjjCN6"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_CoCN6_PM73(T, P): + """ "c-a: potassium Co(CN)6 [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.5603 * 2 / 3 + b1 = 5.815 * 2 / 3 + b2 = 0 + Cphi = -0.1603 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["CoCN6"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Coen3_Cl_PM73(T, P): + """ "c-a: tris(ethylenediamine)cobalt(III) chloride [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.2603 * 2 / 3 + b1 = 3.563 * 2 / 3 + b2 = 0 + Cphi = -0.0916 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Coen3"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Coen3_NO3_PM73(T, P): + """ "c-a: tris(ethylenediamine)cobalt(III) nitrate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.1882 * 2 / 3 + b1 = 3.935 * 2 / 3 + b2 = 0 + Cphi = 0.0 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Coen3"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Coen3_ClO4_PM73(T, P): + """ "c-a: tris(ethylenediamine)cobalt(III) perchlorate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.1619 * 2 / 3 + b1 = 5.395 * 2 / 3 + b2 = 0 + Cphi = 0.0 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Coen3"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Copn3_ClO4_PM73(T, P): + """ "c-a: Copn3 perchlorate [PM73].""" + # Coefficients from PM73 Table VIII + b0 = 0.2022 * 2 / 3 + b1 = 3.976 * 2 / 3 + b2 = 0 + Cphi = 0.0 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Copn3"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Th_Cl_PM73(T, P): + """ "c-a: thorium chloride [PM73].""" + # Coefficients from PM73 Table IX + b0 = 1.622 * 2 / 3 + b1 = 21.33 * 2 / 3 + b2 = 0 + Cphi = -0.3309 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Th"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Th_NO3_PM73(T, P): + """ "c-a: thorium nitrate [PM73].""" + # Coefficients from PM73 Table IX + b0 = 1.546 * 2 / 3 + b1 = 18.22 * 2 / 3 + b2 = 0 + Cphi = -0.5906 * 2 / 3 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Th"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_P2O7_PM73(T, P): + """ "c-a: sodium diphosphate [PM73].""" + # Coefficients from PM73 Table IX + b0 = 0.699 * 5 / 8 + b1 = 17.16 * 5 / 8 + b2 = 0 + Cphi = 0.0 * 5 / 16 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["P2O7"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_P2O7_PM73(T, P): + """ "c-a: potassium diphosphate [PM73].""" + # Coefficients from PM73 Table IX + b0 = 0.977 * 5 / 8 + b1 = 17.88 * 5 / 8 + b2 = 0 + Cphi = -0.2418 * 5 / 16 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["P2O7"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_FejjCN6_PM73(T, P): + """ "c-a: potassium ferrocyanide [PM73].""" + # Coefficients from PM73 Table IX + b0 = 1.021 * 5 / 8 + b1 = 16.23 * 5 / 8 + b2 = 0 + Cphi = -0.5579 * 5 / 16 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["FejjCN6"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_MoCN8_PM73(T, P): + """ "c-a: potassium Mo(CN)8 [PM73].""" + # Coefficients from PM73 Table IX + b0 = 0.854 * 5 / 8 + b1 = 18.53 * 5 / 8 + b2 = 0 + Cphi = -0.3499 * 5 / 16 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["MoCN8"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_WCN8_PM73(T, P): + """ "c-a: potassium W(CN)8 [PM73].""" + # Coefficients from PM73 Table IX + b0 = 1.032 * 5 / 8 + b1 = 18.49 * 5 / 8 + b2 = 0 + Cphi = -0.4937 * 5 / 16 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["WCN8"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MeN_MoCN8_PM73(T, P): + """ "c-a: MeN Mo(CN)8 [PM73].""" + # Coefficients from PM73 Table IX + b0 = 0.938 * 5 / 8 + b1 = 15.91 * 5 / 8 + b2 = 0 + Cphi = -0.333 * 5 / 16 + C0 = Cphi / (2 * sqrt(np_abs(i2c["MeN"] * i2c["MoCN8"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_P3O10_PM73(T, P): + """ "c-a: sodium triphosphate-pentaanion [PM73].""" + # Coefficients from PM73 Table IX + b0 = 1.869 * 3 / 5 + b1 = 36.1 * 3 / 5 + b2 = 0 + Cphi = -0.163 * 3 / 5 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["P3O10"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_P3O10_PM73(T, P): + """ "c-a: potassium triphosphate-pentaanion [PM73].""" + # Coefficients from PM73 Table IX + b0 = 1.939 * 3 / 5 + b1 = 39.64 * 3 / 5 + b2 = 0 + Cphi = -0.1055 * 3 / 5 ** (3 / 2) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["P3O10"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# Manual additions - not from funcgen! +def bC_Na_acetate_PM73(T, P): + """c-a: sodium acetate [PM73].""" + # Coefficients from PM73 Table II + b0 = 0.1426 + b1 = 0.3237 + b2 = 0 + Cphi = -0.00629 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["acetate"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_acetate_PM73(T, P): + """c-a: potassium acetate [PM73].""" + # Coefficients from PM73 Table II + b0 = 0.1587 + b1 = 0.3251 + b2 = 0 + Cphi = -0.00660 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["acetate"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pitzer and Kim (1974) ~~~~~ +def theta_Mg_Na_PK74(T, P): + """c-c': magnesium sodium [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_Ca_Na_PK74(T, P): + """c-c': calcium sodium [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_K_Na_PK74(T, P): + """c-c': potassium sodium [PK74].""" + theta = -0.012 + valid = T == 298.15 + return theta, valid + + +def theta_Li_Na_PK74(T, P): + """c-c': lithium sodium [PK74].""" + theta = 0.012 + valid = T == 298.15 + return theta, valid + + +def theta_Ba_Na_PK74(T, P): + """c-c': barium sodium [PK74].""" + theta = -0.003 + valid = T == 298.15 + return theta, valid + + +def theta_Na_Znjj_PK74(T, P): + """c-c': sodium zinc(II) [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_Mnjj_Na_PK74(T, P): + """c-c': manganese(II) sodium [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_Cs_Na_PK74(T, P): + """c-c': caesium sodium [PK74].""" + theta = -0.033 + valid = T == 298.15 + return theta, valid + + +def theta_H_Na_PK74(T, P): + """c-c': hydrogen sodium [PK74].""" + theta = 0.036 + valid = T == 298.15 + return theta, valid + + +def theta_Ca_Mg_PK74(T, P): + """c-c': calcium magnesium [PK74].""" + theta = 0.01 + valid = T == 298.15 + return theta, valid + + +def theta_Ca_K_PK74(T, P): + """c-c': calcium potassium [PK74].""" + theta = -0.04 + valid = T == 298.15 + return theta, valid + + +def theta_K_Li_PK74(T, P): + """c-c': potassium lithium [PK74].""" + theta = -0.022 + valid = T == 298.15 + return theta, valid + + +def theta_Ba_K_PK74(T, P): + """c-c': barium potassium [PK74].""" + theta = -0.072 + valid = T == 298.15 + return theta, valid + + +def theta_Cs_K_PK74(T, P): + """c-c': caesium potassium [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_H_K_PK74(T, P): + """c-c': hydrogen potassium [PK74].""" + theta = 0.005 + valid = T == 298.15 + return theta, valid + + +def theta_H_Sr_PK74(T, P): + """c-c': hydrogen strontium [PK74].""" + theta = -0.02 + valid = T == 298.15 + return theta, valid + + +def theta_Ba_Li_PK74(T, P): + """c-c': barium lithium [PK74].""" + theta = -0.07 + valid = T == 298.15 + return theta, valid + + +def theta_Cs_Li_PK74(T, P): + """c-c': caesium lithium [PK74].""" + theta = -0.095 + valid = T == 298.15 + return theta, valid + + +def theta_H_Li_PK74(T, P): + """c-c': hydrogen lithium [PK74].""" + theta = 0.015 + valid = T == 298.15 + return theta, valid + + +def theta_H_NH4_PK74(T, P): + """c-c': hydrogen ammonium [PK74].""" + theta = -0.016 + valid = T == 298.15 + return theta, valid + + +def theta_Ba_Cs_PK74(T, P): + """c-c': barium caesium [PK74].""" + theta = -0.15 + valid = T == 298.15 + return theta, valid + + +def theta_Ba_H_PK74(T, P): + """c-c': barium hydrogen [PK74].""" + theta = -0.036 + valid = T == 298.15 + return theta, valid + + +def theta_H_Mnjj_PK74(T, P): + """c-c': hydrogen manganese(II) [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_Cs_H_PK74(T, P): + """c-c': caesium hydrogen [PK74].""" + theta = -0.044 + valid = T == 298.15 + return theta, valid + + +def theta_Et4N_H_PK74(T, P): + """c-c': tetraethylammonium hydrogen [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_H_Me4N_PK74(T, P): + """c-c': hydrogen tetramethylammonium [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_Cl_SO4_PK74(T, P): + """a-a': chloride sulfate [PK74].""" + theta = -0.035 + valid = T == 298.15 + return theta, valid + + +def theta_Br_Cl_PK74(T, P): + """a-a': bromide chloride [PK74].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def theta_Cl_NO3_PK74(T, P): + """a-a': chloride nitrate [PK74].""" + theta = 0.016 + valid = T == 298.15 + return theta, valid + + +def theta_Cl_OH_PK74(T, P): + """a-a': chloride hydroxide [PK74].""" + theta = -0.05 + valid = T == 298.15 + return theta, valid + + +def theta_Br_OH_PK74(T, P): + """a-a': bromide hydroxide [PK74].""" + theta = -0.065 + valid = T == 298.15 + return theta, valid + + +def psi_Mg_Na_Cl_PK74(T, P): + """c-c'-a: magnesium sodium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Na_Cl_PK74(T, P): + """c-c'-a: calcium sodium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_Cl_PK74(T, P): + """c-c'-a: potassium sodium chloride [PK74].""" + psi = -0.0018 + valid = T == 298.15 + return psi, valid + + +def psi_Li_Na_Cl_PK74(T, P): + """c-c'-a: lithium sodium chloride [PK74].""" + psi = -0.003 + valid = T == 298.15 + return psi, valid + + +def psi_Ba_Na_Cl_PK74(T, P): + """c-c'-a: barium sodium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mnjj_Na_Cl_PK74(T, P): + """c-c'-a: manganese(II) sodium chloride [PK74].""" + psi = -0.003 + valid = T == 298.15 + return psi, valid + + +def psi_Cs_Na_Cl_PK74(T, P): + """c-c'-a: caesium sodium chloride [PK74].""" + psi = -0.003 + valid = T == 298.15 + return psi, valid + + +def psi_H_Na_Cl_PK74(T, P): + """c-c'-a: hydrogen sodium chloride [PK74].""" + psi = -0.004 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Mg_Cl_PK74(T, P): + """c-c'-a: calcium magnesium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_K_Cl_PK74(T, P): + """c-c'-a: calcium potassium chloride [PK74].""" + psi = -0.015 + valid = T == 298.15 + return psi, valid + + +def psi_K_Li_Cl_PK74(T, P): + """c-c'-a: potassium lithium chloride [PK74].""" + psi = -0.01 + valid = T == 298.15 + return psi, valid + + +def psi_Ba_K_Cl_PK74(T, P): + """c-c'-a: barium potassium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Cs_K_Cl_PK74(T, P): + """c-c'-a: caesium potassium chloride [PK74].""" + psi = -0.0013 + valid = T == 298.15 + return psi, valid + + +def psi_H_K_Cl_PK74(T, P): + """c-c'-a: hydrogen potassium chloride [PK74].""" + psi = -0.007 + valid = T == 298.15 + return psi, valid + + +def psi_H_Sr_Cl_PK74(T, P): + """c-c'-a: hydrogen strontium chloride [PK74].""" + psi = 0.018 + valid = T == 298.15 + return psi, valid + + +def psi_Ba_Li_Cl_PK74(T, P): + """c-c'-a: barium lithium chloride [PK74].""" + psi = 0.019 + valid = T == 298.15 + return psi, valid + + +def psi_Cs_Li_Cl_PK74(T, P): + """c-c'-a: caesium lithium chloride [PK74].""" + psi = -0.0094 + valid = T == 298.15 + return psi, valid + + +def psi_H_Li_Cl_PK74(T, P): + """c-c'-a: hydrogen lithium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_NH4_Cl_PK74(T, P): + """c-c'-a: hydrogen ammonium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ba_Cs_Cl_PK74(T, P): + """c-c'-a: barium caesium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ba_H_Cl_PK74(T, P): + """c-c'-a: barium hydrogen chloride [PK74].""" + psi = 0.024 + valid = T == 298.15 + return psi, valid + + +def psi_H_Mnjj_Cl_PK74(T, P): + """c-c'-a: hydrogen manganese(II) chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Cs_H_Cl_PK74(T, P): + """c-c'-a: caesium hydrogen chloride [PK74].""" + psi = -0.019 + valid = T == 298.15 + return psi, valid + + +def psi_Et4N_H_Cl_PK74(T, P): + """c-c'-a: tetraethylammonium hydrogen chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Me4N_Cl_PK74(T, P): + """c-c'-a: hydrogen tetramethylammonium chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Na_SO4_PK74(T, P): + """c-c'-a: magnesium sodium sulfate [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_SO4_PK74(T, P): + """c-c'-a: potassium sodium sulfate [PK74].""" + psi = -0.01 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_Br_PK74(T, P): + """c-c'-a: potassium sodium bromide [PK74].""" + psi = -0.0022 + valid = T == 298.15 + return psi, valid + + +def psi_Na_Znjj_Br_PK74(T, P): + """c-c'-a: sodium zinc(II) bromide [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Na_Br_PK74(T, P): + """c-c'-a: hydrogen sodium bromide [PK74].""" + psi = -0.012 + valid = T == 298.15 + return psi, valid + + +def psi_H_K_Br_PK74(T, P): + """c-c'-a: hydrogen potassium bromide [PK74].""" + psi = -0.021 + valid = T == 298.15 + return psi, valid + + +def psi_H_Li_Br_PK74(T, P): + """c-c'-a: hydrogen lithium bromide [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_NO3_PK74(T, P): + """c-c'-a: potassium sodium nitrate [PK74].""" + psi = -0.0012 + valid = T == 298.15 + return psi, valid + + +def psi_Li_Na_NO3_PK74(T, P): + """c-c'-a: lithium sodium nitrate [PK74].""" + psi = -0.0072 + valid = T == 298.15 + return psi, valid + + +def psi_Li_Na_ClO4_PK74(T, P): + """c-c'-a: lithium sodium perchlorate [PK74].""" + psi = -0.008 + valid = T == 298.15 + return psi, valid + + +def psi_H_Na_ClO4_PK74(T, P): + """c-c'-a: hydrogen sodium perchlorate [PK74].""" + psi = -0.016 + valid = T == 298.15 + return psi, valid + + +def psi_H_Li_ClO4_PK74(T, P): + """c-c'-a: hydrogen lithium perchlorate [PK74].""" + psi = -0.0017 + valid = T == 298.15 + return psi, valid + + +def psi_Li_Na_OAc_PK74(T, P): + """c-c'-a: lithium sodium OAc [PK74].""" + psi = -0.0043 + valid = T == 298.15 + return psi, valid + + +def psi_Na_Cl_SO4_PK74(T, P): + """c-a-a': sodium chloride sulfate [PK74].""" + psi = 0.007 + valid = T == 298.15 + return psi, valid + + +def psi_Na_Br_Cl_PK74(T, P): + """c-a-a': sodium bromide chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Na_Cl_NO3_PK74(T, P): + """c-a-a': sodium chloride nitrate [PK74].""" + psi = -0.006 + valid = T == 298.15 + return psi, valid + + +def psi_Na_Cl_OH_PK74(T, P): + """c-a-a': sodium chloride hydroxide [PK74].""" + psi = -0.006 + valid = T == 298.15 + return psi, valid + + +def psi_Na_Br_OH_PK74(T, P): + """c-a-a': sodium bromide hydroxide [PK74].""" + psi = -0.018 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Cl_SO4_PK74(T, P): + """c-a-a': magnesium chloride sulfate [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Cl_NO3_PK74(T, P): + """c-a-a': magnesium chloride nitrate [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Cl_NO3_PK74(T, P): + """c-a-a': calcium chloride nitrate [PK74].""" + psi = -0.017 + valid = T == 298.15 + return psi, valid + + +def psi_K_Cl_SO4_PK74(T, P): + """c-a-a': potassium chloride sulfate [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Br_Cl_PK74(T, P): + """c-a-a': potassium bromide chloride [PK74].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Cl_NO3_PK74(T, P): + """c-a-a': potassium chloride nitrate [PK74].""" + psi = -0.006 + valid = T == 298.15 + return psi, valid + + +def psi_K_Cl_OH_PK74(T, P): + """c-a-a': potassium chloride hydroxide [PK74].""" + psi = -0.008 + valid = T == 298.15 + return psi, valid + + +def psi_K_Br_OH_PK74(T, P): + """c-a-a': potassium bromide hydroxide [PK74].""" + psi = -0.014 + valid = T == 298.15 + return psi, valid + + +def psi_Li_Cl_NO3_PK74(T, P): + """c-a-a': lithium chloride nitrate [PK74].""" + psi = -0.003 + valid = T == 298.15 + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pitzer and Silvester (1976) ~~~~~ +def lambd_H3PO4_H3PO4_PS76(T, P): + """n-n: phosphoric-acid phosphoric-acid [PS76].""" + lambd = 0.05031 + valid = T == 298.15 + return lambd, valid + + +def lambd_H3PO4_H2PO4_PS76(T, P): + """n-a: phosphoric-acid dihydrogen-phosphate [PS76].""" + lambd = -0.400 + valid = T == 298.15 + return lambd, valid + + +def lambd_H3PO4_K_PS76(T, P): + """n-c: phosphoric-acid potassium [PS76].""" + lambd = -0.070 + valid = T == 298.15 + return lambd, valid + + +def lambd_H3PO4_H_PS76(T, P): + """n-c: phosphoric-acid hydrogen [PS76].""" + lambd = 0.290 + valid = T == 298.15 + return lambd, valid + + +def lambd_H3PO4_Cl_PS76(T, P): + """n-a: phosphoric-acid chloride [PS76].""" + lambd = 0 + valid = T == 298.15 + return lambd, valid + + +def mu_H3PO4_H3PO4_H3PO4_PS76(T, P): + """n-n-n: phosphoric-acid phosphoric-acid phosphoric-acid [PS76].""" + mu = 0.01095 + valid = T == 298.15 + return mu, valid + + +def theta_Cl_H2PO4_PS76(T, P): + """a-a': chloride dihydrogen-phosphate [PS76].""" + theta = 0.10 + valid = T == 298.15 + return theta, valid + + +def psi_K_Cl_H2PO4_PS76(T, P): + """c-a-a': potassium chloride dihydrogen-phosphate [PS76].""" + psi = -0.0105 + valid = T == 298.15 + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mackaskill et al. (1978) ~~~~~ +def bC_Sr_Cl_MWRB78(T, P): + """c-a: strontium chloride [MWRB78].""" + # Valid up to ionic strength of 6, different set provided for up to 9 + # This set should be 'better' for values under 6 + b0 = 0.28994 + b1 = 1.5795 + b2 = 0 + Cphi = -0.003755 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sr"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_Cl_MWRB78hi(T, P): + """c-a: strontium chloride [MWRB78].""" + # Valid up to ionic strength of 9, different set provided for up to 6 + b0 = 0.27948 + b1 = 1.6745 + b2 = 0 + Cphi = 0.0003532 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sr"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_Na_Sr_MWRB78(T, P): + """c-c': sodium strontium [MWRB78].""" + theta = -0.0076 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Sr_Cl_MWRB78(T, P): + """c-c'-a: sodium strontium chloride [MWRB78].""" + psi = -0.0052 + valid = T == 298.15 + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Silvester and Pitzer (1978) ~~~~~ +# Auto-generated functions +# General procedure: +# - Inherit 298.15 K value from PM73; +# - Add temperature derivative correction from SP78. +def bC_H_Cl_SP78(T, P): + """ "c-a: hydrogen chloride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_H_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * -3.081e-4 + b1 = b1 + (T - 298.15) * 1.419e-4 + C0 = C0 + (T - 298.15) * 6.213e-5 / 2 * sqrt(np_abs(i2c["H"] * i2c["Cl"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_Br_SP78(T, P): + """ "c-a: hydrogen bromide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_H_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * -2.049e-4 + b1 = b1 + (T - 298.15) * 4.467e-4 + C0 = C0 + (T - 298.15) * -5.685e-5 / 2 * sqrt(np_abs(i2c["H"] * i2c["Br"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_I_SP78(T, P): + """ "c-a: hydrogen iodide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_H_I_PM73(T, P) + b0 = b0 + (T - 298.15) * -0.23e-4 + b1 = b1 + (T - 298.15) * 8.86e-4 + C0 = C0 + (T - 298.15) * -7.32e-5 / 2 * sqrt(np_abs(i2c["H"] * i2c["I"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_ClO4_SP78(T, P): + """ "c-a: hydrogen perchlorate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_H_ClO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 4.905e-4 + b1 = b1 + (T - 298.15) * 19.31e-4 + C0 = C0 + (T - 298.15) * -11.77e-5 / 2 * sqrt(np_abs(i2c["H"] * i2c["ClO4"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_Cl_SP78(T, P): + """ "c-a: lithium chloride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Li_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * -1.685e-4 + b1 = b1 + (T - 298.15) * 5.366e-4 + C0 = C0 + (T - 298.15) * -4.52e-5 / 2 * sqrt(np_abs(i2c["Li"] * i2c["Cl"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_Br_SP78(T, P): + """ "c-a: lithium bromide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Li_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * -1.819e-4 + b1 = b1 + (T - 298.15) * 6.636e-4 + C0 = C0 + (T - 298.15) * -2.813e-5 / 2 * sqrt(np_abs(i2c["Li"] * i2c["Br"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_ClO4_SP78(T, P): + """ "c-a: lithium perchlorate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Li_ClO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.386e-4 + b1 = b1 + (T - 298.15) * 7.009e-4 + C0 = C0 + (T - 298.15) * -7.712e-5 / 2 * sqrt(np_abs(i2c["Li"] * i2c["ClO4"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_F_SP78(T, P): + """ "c-a: sodium fluoride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_F_PM73(T, P) + b0 = b0 + (T - 298.15) * 5.361e-4 + b1 = b1 + (T - 298.15) * 8.7e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Cl_SP78(T, P): + """ "c-a: sodium chloride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * 7.159e-4 + b1 = b1 + (T - 298.15) * 7.005e-4 + C0 = C0 + (T - 298.15) * -10.54e-5 / 2 * sqrt(np_abs(i2c["Na"] * i2c["Cl"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Br_SP78(T, P): + """ "c-a: sodium bromide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * 7.692e-4 + b1 = b1 + (T - 298.15) * 10.79e-4 + C0 = C0 + (T - 298.15) * -9.3e-5 / 2 * sqrt(np_abs(i2c["Na"] * i2c["Br"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_I_SP78(T, P): + """ "c-a: sodium iodide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_I_PM73(T, P) + b0 = b0 + (T - 298.15) * 8.355e-4 + b1 = b1 + (T - 298.15) * 8.28e-4 + C0 = C0 + (T - 298.15) * -8.35e-5 / 2 * sqrt(np_abs(i2c["Na"] * i2c["I"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_OH_SP78(T, P): + """ "c-a: sodium hydroxide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_OH_PM73(T, P) + b0 = b0 + (T - 298.15) * 7.0e-4 + b1 = b1 + (T - 298.15) * 1.34e-4 + C0 = C0 + (T - 298.15) * -18.94e-5 / 2 * sqrt(np_abs(i2c["Na"] * i2c["OH"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_ClO3_SP78(T, P): + """ "c-a: sodium chlorate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_ClO3_PM73(T, P) + b0 = b0 + (T - 298.15) * 10.35e-4 + b1 = b1 + (T - 298.15) * 19.07e-4 + C0 = C0 + (T - 298.15) * -9.29e-5 / 2 * sqrt(np_abs(i2c["Na"] * i2c["ClO3"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_ClO4_SP78(T, P): + """ "c-a: sodium perchlorate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_ClO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 12.96e-4 + b1 = b1 + (T - 298.15) * 22.97e-4 + C0 = C0 + (T - 298.15) * -16.23e-5 / 2 * sqrt(np_abs(i2c["Na"] * i2c["ClO4"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_BrO3_SP78(T, P): + """ "c-a: sodium bromate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_BrO3_PM73(T, P) + b0 = b0 + (T - 298.15) * 5.59e-4 + b1 = b1 + (T - 298.15) * 34.37e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# bC_Na_IO3_SP78: no corresponding PM73 function + + +def bC_Na_SCN_SP78(T, P): + """ "c-a: sodium thiocyanate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_SCN_PM73(T, P) + b0 = b0 + (T - 298.15) * 7.8e-4 + b1 = b1 + (T - 298.15) * 20.0e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_NO3_SP78(T, P): + """ "c-a: sodium nitrate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_NO3_PM73(T, P) + b0 = b0 + (T - 298.15) * 12.66e-4 + b1 = b1 + (T - 298.15) * 20.6e-4 + C0 = C0 + (T - 298.15) * -23.16e-5 / 2 * sqrt(np_abs(i2c["Na"] * i2c["NO3"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_F_SP78(T, P): + """ "c-a: potassium fluoride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_F_PM73(T, P) + b0 = b0 + (T - 298.15) * 2.14e-4 + b1 = b1 + (T - 298.15) * 5.44e-4 + C0 = C0 + (T - 298.15) * -5.95e-5 / 2 * sqrt(np_abs(i2c["K"] * i2c["F"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Cl_SP78(T, P): + """ "c-a: potassium chloride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * 5.794e-4 + b1 = b1 + (T - 298.15) * 10.71e-4 + C0 = C0 + (T - 298.15) * -5.095e-5 / 2 * sqrt(np_abs(i2c["K"] * i2c["Cl"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Br_SP78(T, P): + """ "c-a: potassium bromide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * 7.39e-4 + b1 = b1 + (T - 298.15) * 17.4e-4 + C0 = C0 + (T - 298.15) * -7.004e-5 / 2 * sqrt(np_abs(i2c["K"] * i2c["Br"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_I_SP78(T, P): + """ "c-a: potassium iodide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_I_PM73(T, P) + b0 = b0 + (T - 298.15) * 9.914e-4 + b1 = b1 + (T - 298.15) * 11.86e-4 + C0 = C0 + (T - 298.15) * -9.44e-5 / 2 * sqrt(np_abs(i2c["K"] * i2c["I"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_ClO3_SP78(T, P): + """ "c-a: potassium chlorate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_ClO3_PM73(T, P) + b0 = b0 + (T - 298.15) * 19.87e-4 + b1 = b1 + (T - 298.15) * 31.8e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# bC_K_ClO4_SP78: no corresponding PM73 function + + +def bC_K_SCN_SP78(T, P): + """ "c-a: potassium thiocyanate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_SCN_PM73(T, P) + b0 = b0 + (T - 298.15) * 6.87e-4 + b1 = b1 + (T - 298.15) * 37.0e-4 + C0 = C0 + (T - 298.15) * 0.43e-5 / 2 * sqrt(np_abs(i2c["K"] * i2c["SCN"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_NO3_SP78(T, P): + """ "c-a: potassium nitrate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_NO3_PM73(T, P) + b0 = b0 + (T - 298.15) * 2.06e-4 + b1 = b1 + (T - 298.15) * 64.5e-4 + C0 = C0 + (T - 298.15) * 39.7e-5 / 2 * sqrt(np_abs(i2c["K"] * i2c["NO3"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_H2PO4_SP78(T, P): + """ "c-a: potassium dihydrogen-phosphate [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_H2PO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 6.045e-4 + b1 = b1 + (T - 298.15) * 28.6e-4 + C0 = C0 + (T - 298.15) * -10.11e-5 / 2 * sqrt(np_abs(i2c["K"] * i2c["H2PO4"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_F_SP78(T, P): + """ "c-a: rubidium fluoride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Rb_F_PM73(T, P) + b0 = b0 + (T - 298.15) * -0.76e-4 + b1 = b1 + (T - 298.15) * 14.7e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_Cl_SP78(T, P): + """ "c-a: rubidium chloride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Rb_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * 5.522e-4 + b1 = b1 + (T - 298.15) * 15.06e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_Br_SP78(T, P): + """ "c-a: rubidium bromide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Rb_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * 6.78e-4 + b1 = b1 + (T - 298.15) * 20.35e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_I_SP78(T, P): + """ "c-a: rubidium iodide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Rb_I_PM73(T, P) + b0 = b0 + (T - 298.15) * 8.578e-4 + b1 = b1 + (T - 298.15) * 23.83e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_F_SP78(T, P): + """ "c-a: caesium fluoride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Cs_F_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.95e-4 + b1 = b1 + (T - 298.15) * 5.97e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_Cl_SP78(T, P): + """ "c-a: caesium chloride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Cs_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * 8.28e-4 + b1 = b1 + (T - 298.15) * 15.0e-4 + C0 = C0 + (T - 298.15) * -12.25e-5 / 2 * sqrt(np_abs(i2c["Cs"] * i2c["Cl"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_Br_SP78(T, P): + """ "c-a: caesium bromide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Cs_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * 7.8e-4 + b1 = b1 + (T - 298.15) * 28.44e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_I_SP78(T, P): + """ "c-a: caesium iodide [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Cs_I_PM73(T, P) + b0 = b0 + (T - 298.15) * 9.75e-4 + b1 = b1 + (T - 298.15) * 34.77e-4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_Cl_SP78(T, P): + """ "c-a: ammonium chloride [SP78].""" + # Coefficients from SP78 Table I + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_NH4_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.779e-4 + b1 = b1 + (T - 298.15) * 12.58e-4 + C0 = C0 + (T - 298.15) * 2.1e-5 / 2 * sqrt(np_abs(i2c["NH4"] * i2c["Cl"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# bC_NH4_H2PO4_SP78: no corresponding PM73 function +# bC_Me4N_F_SP78: no corresponding PM73 function +# bC_Et4N_F_SP78: no corresponding PM73 function +# bC_Pr4N_F_SP78: no corresponding PM73 function +# bC_Bu4N_F_SP78: no corresponding PM73 function +# bC_MeH3N_Cl_SP78: no corresponding PM73 function +# bC_Me2H2N_Cl_SP78: no corresponding PM73 function +# bC_Me3HN_Cl_SP78: no corresponding PM73 function +# bC_Me4N_Cl_SP78: no corresponding PM73 function +# bC_Et4N_Cl_SP78: no corresponding PM73 function +# bC_Pr4N_Cl_SP78: no corresponding PM73 function +# bC_Bu4N_Cl_SP78: no corresponding PM73 function +# bC_Me4N_Br_SP78: no corresponding PM73 function +# bC_Et4N_Br_SP78: no corresponding PM73 function +# bC_Pr4N_Br_SP78: no corresponding PM73 function +# bC_Bu4N_Br_SP78: no corresponding PM73 function +# bC_Me4N_I_SP78: no corresponding PM73 function +# bC_Et4N_I_SP78: no corresponding PM73 function +# bC_Pr4N_I_SP78: no corresponding PM73 function + + +def bC_Mg_Cl_SP78(T, P): + """ "c-a: magnesium chloride [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Mg_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * -0.259e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 3.7e-3 * 3 / 4 + C0 = C0 + (T - 298.15) * -3.11e-4 * 3 / 2 ** (5 / 2) / 2 * sqrt( + np_abs(i2c["Mg"] * i2c["Cl"]) + ) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_Br_SP78(T, P): + """ "c-a: magnesium bromide [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Mg_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * -0.075e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 5.15e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_ClO4_SP78(T, P): + """ "c-a: magnesium perchlorate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Mg_ClO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.697e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 6.0e-3 * 3 / 4 + C0 = C0 + (T - 298.15) * -6.65e-4 * 3 / 2 ** (5 / 2) / 2 * sqrt( + np_abs(i2c["Mg"] * i2c["ClO4"]) + ) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_NO3_SP78(T, P): + """ "c-a: magnesium nitrate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Mg_NO3_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.687e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 5.99e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_Cl_SP78(T, P): + """ "c-a: calcium chloride [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Ca_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * -0.23e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 5.2e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_Br_SP78(T, P): + """ "c-a: calcium bromide [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Ca_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * -0.697e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 8.05e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_NO3_SP78(T, P): + """ "c-a: calcium nitrate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Ca_NO3_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.706e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 12.25e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_ClO4_SP78(T, P): + """ "c-a: calcium perchlorate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Ca_ClO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 1.106e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 6.77e-3 * 3 / 4 + C0 = C0 + (T - 298.15) * -5.83e-4 * 3 / 2 ** (5 / 2) / 2 * sqrt( + np_abs(i2c["Ca"] * i2c["ClO4"]) + ) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_Cl_SP78(T, P): + """ "c-a: strontium chloride [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Sr_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.956e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 3.79e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_Br_SP78(T, P): + """ "c-a: strontium bromide [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Sr_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * -0.437e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 8.71e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_NO3_SP78(T, P): + """ "c-a: strontium nitrate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Sr_NO3_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.236e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 16.63e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_ClO4_SP78(T, P): + """ "c-a: strontium perchlorate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Sr_ClO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 1.524e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 7.19e-3 * 3 / 4 + C0 = C0 + (T - 298.15) * -5.86e-4 * 3 / 2 ** (5 / 2) / 2 * sqrt( + np_abs(i2c["Sr"] * i2c["ClO4"]) + ) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_Cl_SP78(T, P): + """ "c-a: barium chloride [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Ba_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.854e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 4.31e-3 * 3 / 4 + C0 = C0 + (T - 298.15) * -2.9e-4 * 3 / 2 ** (5 / 2) / 2 * sqrt( + np_abs(i2c["Ba"] * i2c["Cl"]) + ) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_Br_SP78(T, P): + """ "c-a: barium bromide [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Ba_Br_PM73(T, P) + b0 = b0 + (T - 298.15) * -0.451e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 9.04e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ba_NO3_SP78(T, P): + """ "c-a: barium nitrate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Ba_NO3_PM73(T, P) + b0 = b0 + (T - 298.15) * -3.88e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 38.8e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# bC_Mnjj_ClO4_SP78: no corresponding PM73 function +# bC_Cojj_ClO4_SP78: no corresponding PM73 function +# bC_Nijj_ClO4_SP78: no corresponding PM73 function + + +def bC_Cujj_Cl_SP78(T, P): + """ "c-a: copper(II) chloride [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Cujj_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * -3.62e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 11.3e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Znjj_ClO4_SP78(T, P): + """ "c-a: zinc(II) perchlorate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Znjj_ClO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.795e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 6.79e-3 * 3 / 4 + C0 = C0 + (T - 298.15) * -7.27e-4 * 3 / 2 ** (5 / 2) / 2 * sqrt( + np_abs(i2c["Znjj"] * i2c["ClO4"]) + ) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_SO4_SP78(T, P): + """ "c-a: lithium sulfate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Li_SO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.674e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 1.88e-3 * 3 / 4 + C0 = C0 + (T - 298.15) * -4.4e-4 * 3 / 2 ** (5 / 2) / 2 * sqrt( + np_abs(i2c["Li"] * i2c["SO4"]) + ) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_SO4_SP78(T, P): + """ "c-a: sodium sulfate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Na_SO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 3.156e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 7.51e-3 * 3 / 4 + C0 = C0 + (T - 298.15) * -9.2e-4 * 3 / 2 ** (5 / 2) / 2 * sqrt( + np_abs(i2c["Na"] * i2c["SO4"]) + ) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_SO4_SP78(T, P): + """ "c-a: potassium sulfate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_K_SO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 1.92e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 8.93e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Rb_SO4_SP78(T, P): + """ "c-a: rubidium sulfate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Rb_SO4_PM73(T, P) + b0 = b0 + (T - 298.15) * 1.25e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 11.52e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Cs_SO4_SP78(T, P): + """ "c-a: caesium sulfate [SP78].""" + # Coefficients from SP78 Table II + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Cs_SO4_PM73(T, P) + b0 = b0 + (T - 298.15) * -1.19e-3 * 3 / 4 + b1 = b1 + (T - 298.15) * 19.31e-3 * 3 / 4 + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_La_Cl_SP78(T, P): + """ "c-a: lanthanum chloride [SP78].""" + # Coefficients from SP78 Table III + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_La_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * 0.253e-3 + b1 = b1 + (T - 298.15) * 0.798e-2 + C0 = C0 + (T - 298.15) * -0.371e-3 / 2 * sqrt(np_abs(i2c["La"] * i2c["Cl"])) + # Validity range follows typical values assigned by MP98 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# bC_La_ClO4_SP78: no corresponding PM73 function +# bC_La_NO3_SP78: no corresponding PM73 function +# bC_Na_FejjjCN6_SP78: no corresponding PM73 function +# bC_K_FejjjCN6_SP78: no corresponding PM73 function +# bC_K_FejjCN6_SP78: no corresponding PM73 function +# bC_Mg_SO4_SP78: no corresponding PM73 function +# bC_Ca_SO4_SP78: no corresponding PM73 function +# bC_Cujj_SO4_SP78: no corresponding PM73 function +# bC_Znjj_SO4_SP78: no corresponding PM73 function +# bC_Cdjj_SO4_SP78: no corresponding PM73 function + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Roy et al. (1980) ~~~~~ +def theta_H_Mg_RGB80(T, P): + """c-c': hydrogen magnesium [RGB80].""" + # RGB80 do provide theta values at 5, 15, 25, 35 and 45 degC, but no + # equation to interpolate between them. + # This function just returns the 25 degC value. + theta = 0.0620 + valid = T == 298.15 + return theta, valid + + +def psi_H_Mg_Cl_RGB80(T, P): + """c-c': hydrogen magnesium chloride [RGB80].""" + # RGB80 do provide theta values at 5, 15, 25, 35 and 45 degC, but no + # equation to interpolate between them. + # This function just returns the 25 degC value. + theta = 0.0010 + valid = T == 298.15 + return theta, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rard and Miller (1981i) ~~~~~ +def bC_Mg_SO4_RM81i(T, P): + """c-a: magnesium sulfate [RM81i].""" + b0 = 0.21499 + b1 = 3.3646 + b2 = -32.743 + Cphi = 0.02797 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["SO4"]))) + C1 = 0 + alph1 = 1.4 + alph2 = 12 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Peiper and Pitzer (1982) ~~~~~ +def PP82_eqMPH(T, q): + """PP82 equation derived by MP Humphreys.""" + Tr = 298.15 + return q[0] + q[1] * (T - Tr) + q[2] * (T - Tr) ** 2 / 2 + + +def bC_Na_CO3_PP82(T, P): + """c-a: sodium carbonate [PP82].""" + # I have no idea where MP98 got their T**2 parameters from + # or why they are so small. + b0 = PP82_eqMPH( + T, + float_( + [ + 0.0362, + 1.79e-3, + -4.22e-5, + ] + ), + ) + b1 = PP82_eqMPH( + T, + float_( + [ + 1.51, + 2.05e-3, + -16.8e-5, + ] + ), + ) + b2 = 0 + Cphi = 0.0052 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HCO3_PP82(T, P): + """c-a: sodium bicarbonate [PP82].""" + # I have no idea where MP98 got their T**2 parameters from + # or why they are so small. + b0 = PP82_eqMPH( + T, + float_( + [ + 0.028, + 1.00e-3, + -2.6e-5, + ] + ), + ) + b1 = PP82_eqMPH( + T, + float_( + [ + 0.044, + 1.10e-3, + -4.3e-5, + ] + ), + ) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_Cl_HCO3_PP82(T, P): + """a-a': chloride bicarbonate [PP82].""" + theta = 0.0359 + valid = T == 298.15 + return theta, valid + + +def theta_CO3_Cl_PP82(T, P): + """a-a': carbonate chloride [PP82].""" + theta = -0.053 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_HCO3_PP82(T, P): + """c-a-a': sodium chloride bicarbonate [PP82].""" + psi = -0.0143 + valid = T == 298.15 + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Roy et al. (1981) ~~~~~ +def theta_Ca_H_RGO81(T, P): + """c-c': calcium hydrogen [RGO81].""" + theta = 0.0612 + valid = T == 298.15 + return theta, valid + + +def psi_Ca_H_Cl_RGO81(T, P): + """c-c': calcium hydrogen chloride [RGO81].""" + theta = 0.0008 + valid = T == 298.15 + return theta, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Thurmond & Millero (1982) ~~~~~ +def psi_Na_CO3_Cl_TM82(T, P): + """c-a-a': sodium carbonate chloride [TM82].""" + psi = 0.016 + valid = T == 298.15 + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ de Lima & Pitzer (1983) ~~~~~ +def bC_Mg_Cl_dLP83(T, P): + """c-a: magnesium chloride [dLP83].""" + # dLP83 Eq. (11) + b0 = 5.93915e-7 * T**2 - 9.31654e-4 * T + 0.576066 + b1 = 2.60169e-5 * T**2 - 1.09438e-2 * T + 2.60135 + b2 = 0 + Cphi = 3.01823e-7 * T**2 - 2.89125e-4 * T + 6.57867e-2 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 298.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Holmes and Mesmer (1983) ~~~~~ +def HM83_eq25(T, a): + """HM83 equation 25.""" + TR = 298.15 + return ( + a[0] + + a[1] * (1 / T - 1 / TR) + + a[2] * log(T / TR) + + a[3] * (T - TR) + + a[4] * (T**2 - TR**2) + + a[5] * log(T - 260) + ) + + +def bC_Cs_Cl_HM83(T, P): + """c-a: caesium chloride [HM83].""" + b0 = HM83_eq25( + T, + float_( + [ + 0.03352, + -1290.0, + -8.4279, + 0.018502, + -6.7942e-6, + 0, + ] + ), + ) + b1 = HM83_eq25( + T, + float_( + [ + 0.0429, + -38.0, + 0, + 0.001306, + 0, + 0, + ] + ), + ) + b2 = 0 + Cphi = HM83_eq25( + T, + float_( + [ + -2.62e-4, + 157.13, + 1.0860, + -0.0025242, + 9.840e-7, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Cs"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Cl_HM83(T, P): + """c-a: potassium chloride [HM83].""" + b0 = HM83_eq25( + T, + float_( + [ + 0.04808, + -758.48, + -4.7062, + 0.010072, + -3.7599e-6, + 0, + ] + ), + ) + b1 = HM83_eq25( + T, + float_( + [ + 0.0476, + 303.09, + 1.066, + 0, + 0, + 0.0470, + ] + ), + ) + b2 = 0 + Cphi = HM83_eq25( + T, + float_( + [ + -7.88e-4, + 91.270, + 0.58643, + -0.0012980, + 4.9567e-7, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_Cl_HM83(T, P): + """c-a: lithium chloride [HM83].""" + b0 = HM83_eq25( + T, + float_( + [ + 0.14847, + 0, + 0, + -1.546e-4, + 0, + 0, + ] + ), + ) + b1 = HM83_eq25( + T, + float_( + [ + 0.307, + 0, + 0, + 6.36e-4, + 0, + 0, + ] + ), + ) + b2 = 0 + Cphi = HM83_eq25( + T, + float_( + [ + 0.003710, + 4.115, + 0, + 0, + -3.71e-9, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Millero (1983) ~~~~~ +def theta_Cl_H2AsO4_M83(T, P): + """a-a': chloride dihydrogen-arsenate [M83].""" + # NOTE: this coefficient is for use only WITHOUT unsymmetrical mixing! + theta = 0.228 + valid = T == 298.15 + return theta, valid + + +def theta_Cl_HAsO4_M83(T, P): + """a-a': chloride hydrogen-arsenate [M83].""" + # NOTE: this coefficient is for use only WITHOUT unsymmetrical mixing! + theta = 0.122 + valid = T == 298.15 + return theta, valid + + +def theta_AsO4_Cl_M83(T, P): + """a-a': arsenate chloride [M83].""" + # NOTE: this coefficient is for use only WITHOUT unsymmetrical mixing! + theta = 0.060 + valid = T == 298.15 + return theta, valid + + +def theta_acetate_Cl_M83(T, P): + """a-a': acetate chloride [M83].""" + # NOTE: this coefficient is for use only WITHOUT unsymmetrical mixing! + theta = -0.017 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_H2AsO4_M83(T, P): + """c-a-a': sodium chloride dihydrogen-arsenate [M83].""" + # NOTE: this coefficient is for use only WITHOUT unsymmetrical mixing! + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Na_Cl_HAsO4_M83(T, P): + """c-a-a': sodium chloride hydrogen-arsenate [M83].""" + # NOTE: this coefficient is for use only WITHOUT unsymmetrical mixing! + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Na_AsO4_Cl_M83(T, P): + """c-a-a': sodium arsenate chloride [M83].""" + # NOTE: this coefficient is for use only WITHOUT unsymmetrical mixing! + psi = 0 + valid = T == 298.15 + return psi, valid + + +def theta_Na_acetate_Cl_M83(T, P): + """c-a-a': sodium acetate chloride [M83].""" + # NOTE: this coefficient is for use only WITHOUT unsymmetrical mixing! + theta = 0 + valid = T == 298.15 + return theta, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Roy et al. (1983) ~~~~~ +def bC_K_HCO3_RGWW83(T, P): + """c-a: potassium bicarbonate [RGWW83].""" + b0 = -0.022 + 0.996e-3 * (T - 298.15) # +/- 0.014 on constant term + b1 = 0.09 + 1.104e-3 * (T - 298.15) # +/- 0.04 on constant term + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + # Validity range declared by MP98, but they have different equations! + valid = logical_and(T >= 278.15, T <= 318.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Harvie et al. (1984) ~~~~~ +# c-a functions auto-generated by HMW84_funcgen_bC.py +# c-a-a' functions auto-generated by HMW84_funcgen_caa.py +# c-c'-a functions auto-generated by HMW84_funcgen_cca.py +# n-x functions written out manually +def bC_Na_Cl_HMW84(T, P): + """c-a: sodium chloride [HMW84].""" + b0 = 0.0765 + b1 = 0.2644 + b2 = 0.0 + Cphi = 0.00127 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_SO4_HMW84(T, P): + """c-a: sodium sulfate [HMW84].""" + b0 = 0.01958 + b1 = 1.113 + b2 = 0.0 + Cphi = 0.00497 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HSO4_HMW84(T, P): + """c-a: sodium bisulfate [HMW84].""" + b0 = 0.0454 + b1 = 0.398 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_OH_HMW84(T, P): + """c-a: sodium hydroxide [HMW84].""" + b0 = 0.0864 + b1 = 0.253 + b2 = 0.0 + Cphi = 0.0044 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HCO3_HMW84(T, P): + """c-a: sodium bicarbonate [HMW84].""" + b0 = 0.0277 + b1 = 0.0411 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_CO3_HMW84(T, P): + """c-a: sodium carbonate [HMW84].""" + b0 = 0.0399 + b1 = 1.389 + b2 = 0.0 + Cphi = 0.0044 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Cl_HMW84(T, P): + """c-a: potassium chloride [HMW84].""" + b0 = 0.04835 + b1 = 0.2122 + b2 = 0.0 + Cphi = -0.00084 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_SO4_HMW84(T, P): + """c-a: potassium sulfate [HMW84].""" + b0 = 0.04995 + b1 = 0.7793 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HSO4_HMW84(T, P): + """c-a: potassium bisulfate [HMW84].""" + b0 = -0.0003 + b1 = 0.1735 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_OH_HMW84(T, P): + """c-a: potassium hydroxide [HMW84].""" + b0 = 0.1298 + b1 = 0.32 + b2 = 0.0 + Cphi = 0.0041 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HCO3_HMW84(T, P): + """c-a: potassium bicarbonate [HMW84].""" + b0 = 0.0296 + b1 = -0.013 + b2 = 0.0 + Cphi = -0.008 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["HCO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_CO3_HMW84(T, P): + """c-a: potassium carbonate [HMW84].""" + b0 = 0.1488 + b1 = 1.43 + b2 = 0.0 + Cphi = -0.0015 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_Cl_HMW84(T, P): + """c-a: calcium chloride [HMW84].""" + b0 = 0.3159 + b1 = 1.614 + b2 = 0.0 + Cphi = -0.00034 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_SO4_HMW84(T, P): + """c-a: calcium sulfate [HMW84].""" + b0 = 0.2 + b1 = 3.1973 + b2 = -54.24 + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = 12 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HSO4_HMW84(T, P): + """c-a: calcium bisulfate [HMW84].""" + b0 = 0.2145 + b1 = 2.53 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_OH_HMW84(T, P): + """c-a: calcium hydroxide [HMW84].""" + b0 = -0.1747 + b1 = -0.2303 + b2 = -5.72 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = 12 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HCO3_HMW84(T, P): + """c-a: calcium bicarbonate [HMW84].""" + b0 = 0.4 + b1 = 2.977 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_CO3_HMW84(T, P): + """c-a: calcium carbonate [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_Cl_HMW84(T, P): + """c-a: magnesium chloride [HMW84].""" + b0 = 0.35235 + b1 = 1.6815 + b2 = 0.0 + Cphi = 0.00519 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_SO4_HMW84(T, P): + """c-a: magnesium sulfate [HMW84].""" + b0 = 0.221 + b1 = 3.343 + b2 = -37.23 + Cphi = 0.025 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["SO4"]))) + C1 = 0 + alph1 = 1.4 + alph2 = 12 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_HSO4_HMW84(T, P): + """c-a: magnesium bisulfate [HMW84].""" + b0 = 0.4746 + b1 = 1.729 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_OH_HMW84(T, P): + """c-a: magnesium hydroxide [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_HCO3_HMW84(T, P): + """c-a: magnesium bicarbonate [HMW84].""" + b0 = 0.329 + b1 = 0.6072 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_CO3_HMW84(T, P): + """c-a: magnesium carbonate [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MgOH_Cl_HMW84(T, P): + """c-a: magnesium-hydroxide chloride [HMW84].""" + b0 = -0.1 + b1 = 1.658 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MgOH_SO4_HMW84(T, P): + """c-a: magnesium-hydroxide sulfate [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MgOH_HSO4_HMW84(T, P): + """c-a: magnesium-hydroxide bisulfate [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MgOH_OH_HMW84(T, P): + """c-a: magnesium-hydroxide hydroxide [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MgOH_HCO3_HMW84(T, P): + """c-a: magnesium-hydroxide bicarbonate [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MgOH_CO3_HMW84(T, P): + """c-a: magnesium-hydroxide carbonate [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_Cl_HMW84(T, P): + """c-a: hydrogen chloride [HMW84].""" + b0 = 0.1775 + b1 = 0.2945 + b2 = 0.0 + Cphi = 0.0008 + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_SO4_HMW84(T, P): + """c-a: hydrogen sulfate [HMW84].""" + b0 = 0.0298 + b1 = 0.0 + b2 = 0.0 + Cphi = 0.0438 + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_HSO4_HMW84(T, P): + """c-a: hydrogen bisulfate [HMW84].""" + b0 = 0.2065 + b1 = 0.5556 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_OH_HMW84(T, P): + """c-a: hydrogen hydroxide [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_HCO3_HMW84(T, P): + """c-a: hydrogen bicarbonate [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_CO3_HMW84(T, P): + """c-a: hydrogen carbonate [HMW84].""" + b0 = 0.0 + b1 = 0.0 + b2 = 0.0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_Cl_SO4_HMW84(T, P): + """a-a': chloride sulfate [HMW84].""" + theta = 0.02 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_SO4_HMW84(T, P): + """c-a-a': sodium chloride sulfate [HMW84].""" + psi = 0.0014 + valid = T == 298.15 + return psi, valid + + +def psi_K_Cl_SO4_HMW84(T, P): + """c-a-a': potassium chloride sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Cl_SO4_HMW84(T, P): + """c-a-a': calcium chloride sulfate [HMW84].""" + psi = -0.018 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Cl_SO4_HMW84(T, P): + """c-a-a': magnesium chloride sulfate [HMW84].""" + psi = -0.004 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Cl_SO4_HMW84(T, P): + """c-a-a': magnesium-hydroxide chloride sulfate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Cl_SO4_HMW84(T, P): + """c-a-a': hydrogen chloride sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_Cl_HSO4_HMW84(T, P): + """a-a': chloride bisulfate [HMW84].""" + theta = -0.006 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_HSO4_HMW84(T, P): + """c-a-a': sodium chloride bisulfate [HMW84].""" + psi = -0.006 + valid = T == 298.15 + return psi, valid + + +def psi_K_Cl_HSO4_HMW84(T, P): + """c-a-a': potassium chloride bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Cl_HSO4_HMW84(T, P): + """c-a-a': calcium chloride bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Cl_HSO4_HMW84(T, P): + """c-a-a': magnesium chloride bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Cl_HSO4_HMW84(T, P): + """c-a-a': magnesium-hydroxide chloride bisulfate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Cl_HSO4_HMW84(T, P): + """c-a-a': hydrogen chloride bisulfate [HMW84].""" + psi = 0.013 + valid = T == 298.15 + return psi, valid + + +def theta_Cl_OH_HMW84(T, P): + """a-a': chloride hydroxide [HMW84].""" + theta = -0.05 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_OH_HMW84(T, P): + """c-a-a': sodium chloride hydroxide [HMW84].""" + psi = -0.006 + valid = T == 298.15 + return psi, valid + + +def psi_K_Cl_OH_HMW84(T, P): + """c-a-a': potassium chloride hydroxide [HMW84].""" + psi = -0.006 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Cl_OH_HMW84(T, P): + """c-a-a': calcium chloride hydroxide [HMW84].""" + psi = -0.025 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Cl_OH_HMW84(T, P): + """c-a-a': magnesium chloride hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Cl_OH_HMW84(T, P): + """c-a-a': magnesium-hydroxide chloride hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Cl_OH_HMW84(T, P): + """c-a-a': hydrogen chloride hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_Cl_HCO3_HMW84(T, P): + """a-a': chloride bicarbonate [HMW84].""" + theta = 0.03 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_HCO3_HMW84(T, P): + """c-a-a': sodium chloride bicarbonate [HMW84].""" + psi = -0.15 + valid = T == 298.15 + return psi, valid + + +def psi_K_Cl_HCO3_HMW84(T, P): + """c-a-a': potassium chloride bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Cl_HCO3_HMW84(T, P): + """c-a-a': calcium chloride bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Cl_HCO3_HMW84(T, P): + """c-a-a': magnesium chloride bicarbonate [HMW84].""" + psi = -0.096 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Cl_HCO3_HMW84(T, P): + """c-a-a': magnesium-hydroxide chloride bicarbonate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Cl_HCO3_HMW84(T, P): + """c-a-a': hydrogen chloride bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_CO3_Cl_HMW84(T, P): + """a-a': carbonate chloride [HMW84].""" + theta = -0.02 + valid = T == 298.15 + return theta, valid + + +def psi_Na_CO3_Cl_HMW84(T, P): + """c-a-a': sodium carbonate chloride [HMW84].""" + psi = 0.0085 + valid = T == 298.15 + return psi, valid + + +def psi_K_CO3_Cl_HMW84(T, P): + """c-a-a': potassium carbonate chloride [HMW84].""" + psi = 0.004 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_CO3_Cl_HMW84(T, P): + """c-a-a': calcium carbonate chloride [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_CO3_Cl_HMW84(T, P): + """c-a-a': magnesium carbonate chloride [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_CO3_Cl_HMW84(T, P): + """c-a-a': magnesium-hydroxide carbonate chloride [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_CO3_Cl_HMW84(T, P): + """c-a-a': hydrogen carbonate chloride [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_HSO4_SO4_HMW84(T, P): + """a-a': bisulfate sulfate [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_Na_HSO4_SO4_HMW84(T, P): + """c-a-a': sodium bisulfate sulfate [HMW84].""" + psi = -0.0094 + valid = T == 298.15 + return psi, valid + + +def psi_K_HSO4_SO4_HMW84(T, P): + """c-a-a': potassium bisulfate sulfate [HMW84].""" + psi = -0.0677 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_HSO4_SO4_HMW84(T, P): + """c-a-a': calcium bisulfate sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_HSO4_SO4_HMW84(T, P): + """c-a-a': magnesium bisulfate sulfate [HMW84].""" + psi = -0.0425 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_HSO4_SO4_HMW84(T, P): + """c-a-a': magnesium-hydroxide bisulfate sulfate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_HSO4_SO4_HMW84(T, P): + """c-a-a': hydrogen bisulfate sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_OH_SO4_HMW84(T, P): + """a-a': hydroxide sulfate [HMW84].""" + theta = -0.013 + valid = T == 298.15 + return theta, valid + + +def psi_Na_OH_SO4_HMW84(T, P): + """c-a-a': sodium hydroxide sulfate [HMW84].""" + psi = -0.009 + valid = T == 298.15 + return psi, valid + + +def psi_K_OH_SO4_HMW84(T, P): + """c-a-a': potassium hydroxide sulfate [HMW84].""" + psi = -0.05 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_OH_SO4_HMW84(T, P): + """c-a-a': calcium hydroxide sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_OH_SO4_HMW84(T, P): + """c-a-a': magnesium hydroxide sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_OH_SO4_HMW84(T, P): + """c-a-a': magnesium-hydroxide hydroxide sulfate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_OH_SO4_HMW84(T, P): + """c-a-a': hydrogen hydroxide sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_HCO3_SO4_HMW84(T, P): + """a-a': bicarbonate sulfate [HMW84].""" + theta = 0.01 + valid = T == 298.15 + return theta, valid + + +def psi_Na_HCO3_SO4_HMW84(T, P): + """c-a-a': sodium bicarbonate sulfate [HMW84].""" + psi = -0.005 + valid = T == 298.15 + return psi, valid + + +def psi_K_HCO3_SO4_HMW84(T, P): + """c-a-a': potassium bicarbonate sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_HCO3_SO4_HMW84(T, P): + """c-a-a': calcium bicarbonate sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_HCO3_SO4_HMW84(T, P): + """c-a-a': magnesium bicarbonate sulfate [HMW84].""" + psi = -0.161 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_HCO3_SO4_HMW84(T, P): + """c-a-a': magnesium-hydroxide bicarbonate sulfate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_HCO3_SO4_HMW84(T, P): + """c-a-a': hydrogen bicarbonate sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_CO3_SO4_HMW84(T, P): + """a-a': carbonate sulfate [HMW84].""" + theta = 0.02 + valid = T == 298.15 + return theta, valid + + +def psi_Na_CO3_SO4_HMW84(T, P): + """c-a-a': sodium carbonate sulfate [HMW84].""" + psi = -0.005 + valid = T == 298.15 + return psi, valid + + +def psi_K_CO3_SO4_HMW84(T, P): + """c-a-a': potassium carbonate sulfate [HMW84].""" + psi = -0.009 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_CO3_SO4_HMW84(T, P): + """c-a-a': calcium carbonate sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_CO3_SO4_HMW84(T, P): + """c-a-a': magnesium carbonate sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_CO3_SO4_HMW84(T, P): + """c-a-a': magnesium-hydroxide carbonate sulfate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_CO3_SO4_HMW84(T, P): + """c-a-a': hydrogen carbonate sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_HSO4_OH_HMW84(T, P): + """a-a': bisulfate hydroxide [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_Na_HSO4_OH_HMW84(T, P): + """c-a-a': sodium bisulfate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_HSO4_OH_HMW84(T, P): + """c-a-a': potassium bisulfate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_HSO4_OH_HMW84(T, P): + """c-a-a': calcium bisulfate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_HSO4_OH_HMW84(T, P): + """c-a-a': magnesium bisulfate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_HSO4_OH_HMW84(T, P): + """c-a-a': magnesium-hydroxide bisulfate hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_HSO4_OH_HMW84(T, P): + """c-a-a': hydrogen bisulfate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_HCO3_HSO4_HMW84(T, P): + """a-a': bicarbonate bisulfate [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_Na_HCO3_HSO4_HMW84(T, P): + """c-a-a': sodium bicarbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_HCO3_HSO4_HMW84(T, P): + """c-a-a': potassium bicarbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_HCO3_HSO4_HMW84(T, P): + """c-a-a': calcium bicarbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_HCO3_HSO4_HMW84(T, P): + """c-a-a': magnesium bicarbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_HCO3_HSO4_HMW84(T, P): + """c-a-a': magnesium-hydroxide bicarbonate bisulfate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_HCO3_HSO4_HMW84(T, P): + """c-a-a': hydrogen bicarbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_CO3_HSO4_HMW84(T, P): + """a-a': carbonate bisulfate [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_Na_CO3_HSO4_HMW84(T, P): + """c-a-a': sodium carbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_CO3_HSO4_HMW84(T, P): + """c-a-a': potassium carbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_CO3_HSO4_HMW84(T, P): + """c-a-a': calcium carbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_CO3_HSO4_HMW84(T, P): + """c-a-a': magnesium carbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_CO3_HSO4_HMW84(T, P): + """c-a-a': magnesium-hydroxide carbonate bisulfate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_CO3_HSO4_HMW84(T, P): + """c-a-a': hydrogen carbonate bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_HCO3_OH_HMW84(T, P): + """a-a': bicarbonate hydroxide [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_Na_HCO3_OH_HMW84(T, P): + """c-a-a': sodium bicarbonate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_HCO3_OH_HMW84(T, P): + """c-a-a': potassium bicarbonate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_HCO3_OH_HMW84(T, P): + """c-a-a': calcium bicarbonate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_HCO3_OH_HMW84(T, P): + """c-a-a': magnesium bicarbonate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_HCO3_OH_HMW84(T, P): + """c-a-a': magnesium-hydroxide bicarbonate hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_HCO3_OH_HMW84(T, P): + """c-a-a': hydrogen bicarbonate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_CO3_OH_HMW84(T, P): + """a-a': carbonate hydroxide [HMW84].""" + theta = 0.1 + valid = T == 298.15 + return theta, valid + + +def psi_Na_CO3_OH_HMW84(T, P): + """c-a-a': sodium carbonate hydroxide [HMW84].""" + psi = -0.017 + valid = T == 298.15 + return psi, valid + + +def psi_K_CO3_OH_HMW84(T, P): + """c-a-a': potassium carbonate hydroxide [HMW84].""" + psi = -0.01 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_CO3_OH_HMW84(T, P): + """c-a-a': calcium carbonate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_CO3_OH_HMW84(T, P): + """c-a-a': magnesium carbonate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_CO3_OH_HMW84(T, P): + """c-a-a': magnesium-hydroxide carbonate hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_CO3_OH_HMW84(T, P): + """c-a-a': hydrogen carbonate hydroxide [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_CO3_HCO3_HMW84(T, P): + """a-a': carbonate bicarbonate [HMW84].""" + theta = -0.04 + valid = T == 298.15 + return theta, valid + + +def psi_Na_CO3_HCO3_HMW84(T, P): + """c-a-a': sodium carbonate bicarbonate [HMW84].""" + psi = 0.002 + valid = T == 298.15 + return psi, valid + + +def psi_K_CO3_HCO3_HMW84(T, P): + """c-a-a': potassium carbonate bicarbonate [HMW84].""" + psi = 0.012 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_CO3_HCO3_HMW84(T, P): + """c-a-a': calcium carbonate bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_CO3_HCO3_HMW84(T, P): + """c-a-a': magnesium carbonate bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_CO3_HCO3_HMW84(T, P): + """c-a-a': magnesium-hydroxide carbonate bicarbonate [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_CO3_HCO3_HMW84(T, P): + """c-a-a': hydrogen carbonate bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_K_Na_HMW84(T, P): + """c-c': potassium sodium [HMW84].""" + theta = -0.012 + valid = T == 298.15 + return theta, valid + + +def psi_K_Na_Cl_HMW84(T, P): + """c-c'-a: potassium sodium chloride [HMW84].""" + psi = -0.0018 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_SO4_HMW84(T, P): + """c-c'-a: potassium sodium sulfate [HMW84].""" + psi = -0.01 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_HSO4_HMW84(T, P): + """c-c'-a: potassium sodium bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_OH_HMW84(T, P): + """c-c'-a: potassium sodium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_HCO3_HMW84(T, P): + """c-c'-a: potassium sodium bicarbonate [HMW84].""" + psi = -0.003 + valid = T == 298.15 + return psi, valid + + +def psi_K_Na_CO3_HMW84(T, P): + """c-c'-a: potassium sodium carbonate [HMW84].""" + psi = 0.003 + valid = T == 298.15 + return psi, valid + + +def theta_Ca_Na_HMW84(T, P): + """c-c': calcium sodium [HMW84].""" + theta = 0.07 + valid = T == 298.15 + return theta, valid + + +def psi_Ca_Na_Cl_HMW84(T, P): + """c-c'-a: calcium sodium chloride [HMW84].""" + psi = -0.007 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Na_SO4_HMW84(T, P): + """c-c'-a: calcium sodium sulfate [HMW84].""" + psi = -0.055 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Na_HSO4_HMW84(T, P): + """c-c'-a: calcium sodium bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Na_OH_HMW84(T, P): + """c-c'-a: calcium sodium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Na_HCO3_HMW84(T, P): + """c-c'-a: calcium sodium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Na_CO3_HMW84(T, P): + """c-c'-a: calcium sodium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_Mg_Na_HMW84(T, P): + """c-c': magnesium sodium [HMW84].""" + theta = 0.07 + valid = T == 298.15 + return theta, valid + + +def psi_Mg_Na_Cl_HMW84(T, P): + """c-c'-a: magnesium sodium chloride [HMW84].""" + psi = -0.012 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Na_SO4_HMW84(T, P): + """c-c'-a: magnesium sodium sulfate [HMW84].""" + psi = -0.015 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Na_HSO4_HMW84(T, P): + """c-c'-a: magnesium sodium bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Na_OH_HMW84(T, P): + """c-c'-a: magnesium sodium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Na_HCO3_HMW84(T, P): + """c-c'-a: magnesium sodium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_Na_CO3_HMW84(T, P): + """c-c'-a: magnesium sodium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_MgOH_Na_HMW84(T, P): + """c-c': magnesium-hydroxide sodium [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_MgOH_Na_Cl_HMW84(T, P): + """c-c'-a: magnesium-hydroxide sodium chloride [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Na_SO4_HMW84(T, P): + """c-c'-a: magnesium-hydroxide sodium sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Na_HSO4_HMW84(T, P): + """c-c'-a: magnesium-hydroxide sodium bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Na_OH_HMW84(T, P): + """c-c'-a: magnesium-hydroxide sodium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Na_HCO3_HMW84(T, P): + """c-c'-a: magnesium-hydroxide sodium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_MgOH_Na_CO3_HMW84(T, P): + """c-c'-a: magnesium-hydroxide sodium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_H_Na_HMW84(T, P): + """c-c': hydrogen sodium [HMW84].""" + theta = 0.036 + valid = T == 298.15 + return theta, valid + + +def psi_H_Na_Cl_HMW84(T, P): + """c-c'-a: hydrogen sodium chloride [HMW84].""" + psi = -0.004 + valid = T == 298.15 + return psi, valid + + +def psi_H_Na_SO4_HMW84(T, P): + """c-c'-a: hydrogen sodium sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Na_HSO4_HMW84(T, P): + """c-c'-a: hydrogen sodium bisulfate [HMW84].""" + psi = -0.0129 + valid = T == 298.15 + return psi, valid + + +def psi_H_Na_OH_HMW84(T, P): + """c-c'-a: hydrogen sodium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Na_HCO3_HMW84(T, P): + """c-c'-a: hydrogen sodium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Na_CO3_HMW84(T, P): + """c-c'-a: hydrogen sodium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_Ca_K_HMW84(T, P): + """c-c': calcium potassium [HMW84].""" + theta = 0.032 + valid = T == 298.15 + return theta, valid + + +def psi_Ca_K_Cl_HMW84(T, P): + """c-c'-a: calcium potassium chloride [HMW84].""" + psi = -0.025 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_K_SO4_HMW84(T, P): + """c-c'-a: calcium potassium sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_K_HSO4_HMW84(T, P): + """c-c'-a: calcium potassium bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_K_OH_HMW84(T, P): + """c-c'-a: calcium potassium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_K_HCO3_HMW84(T, P): + """c-c'-a: calcium potassium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_K_CO3_HMW84(T, P): + """c-c'-a: calcium potassium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_K_Mg_HMW84(T, P): + """c-c': potassium magnesium [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_K_Mg_Cl_HMW84(T, P): + """c-c'-a: potassium magnesium chloride [HMW84].""" + psi = -0.022 + valid = T == 298.15 + return psi, valid + + +def psi_K_Mg_SO4_HMW84(T, P): + """c-c'-a: potassium magnesium sulfate [HMW84].""" + psi = -0.048 + valid = T == 298.15 + return psi, valid + + +def psi_K_Mg_HSO4_HMW84(T, P): + """c-c'-a: potassium magnesium bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Mg_OH_HMW84(T, P): + """c-c'-a: potassium magnesium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Mg_HCO3_HMW84(T, P): + """c-c'-a: potassium magnesium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_Mg_CO3_HMW84(T, P): + """c-c'-a: potassium magnesium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_K_MgOH_HMW84(T, P): + """c-c': potassium magnesium-hydroxide [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_K_MgOH_Cl_HMW84(T, P): + """c-c'-a: potassium magnesium-hydroxide chloride [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_MgOH_SO4_HMW84(T, P): + """c-c'-a: potassium magnesium-hydroxide sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_MgOH_HSO4_HMW84(T, P): + """c-c'-a: potassium magnesium-hydroxide bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_MgOH_OH_HMW84(T, P): + """c-c'-a: potassium magnesium-hydroxide hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_K_MgOH_HCO3_HMW84(T, P): + """c-c'-a: potassium magnesium-hydroxide bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_K_MgOH_CO3_HMW84(T, P): + """c-c'-a: potassium magnesium-hydroxide carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_H_K_HMW84(T, P): + """c-c': hydrogen potassium [HMW84].""" + theta = 0.005 + valid = T == 298.15 + return theta, valid + + +def psi_H_K_Cl_HMW84(T, P): + """c-c'-a: hydrogen potassium chloride [HMW84].""" + psi = -0.011 + valid = T == 298.15 + return psi, valid + + +def psi_H_K_SO4_HMW84(T, P): + """c-c'-a: hydrogen potassium sulfate [HMW84].""" + psi = 0.197 + valid = T == 298.15 + return psi, valid + + +def psi_H_K_HSO4_HMW84(T, P): + """c-c'-a: hydrogen potassium bisulfate [HMW84].""" + psi = -0.0265 + valid = T == 298.15 + return psi, valid + + +def psi_H_K_OH_HMW84(T, P): + """c-c'-a: hydrogen potassium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_K_HCO3_HMW84(T, P): + """c-c'-a: hydrogen potassium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_K_CO3_HMW84(T, P): + """c-c'-a: hydrogen potassium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_Ca_Mg_HMW84(T, P): + """c-c': calcium magnesium [HMW84].""" + theta = 0.007 + valid = T == 298.15 + return theta, valid + + +def psi_Ca_Mg_Cl_HMW84(T, P): + """c-c'-a: calcium magnesium chloride [HMW84].""" + psi = -0.012 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Mg_SO4_HMW84(T, P): + """c-c'-a: calcium magnesium sulfate [HMW84].""" + psi = 0.024 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Mg_HSO4_HMW84(T, P): + """c-c'-a: calcium magnesium bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Mg_OH_HMW84(T, P): + """c-c'-a: calcium magnesium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Mg_HCO3_HMW84(T, P): + """c-c'-a: calcium magnesium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_Mg_CO3_HMW84(T, P): + """c-c'-a: calcium magnesium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_Ca_MgOH_HMW84(T, P): + """c-c': calcium magnesium-hydroxide [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_Ca_MgOH_Cl_HMW84(T, P): + """c-c'-a: calcium magnesium-hydroxide chloride [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_MgOH_SO4_HMW84(T, P): + """c-c'-a: calcium magnesium-hydroxide sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_MgOH_HSO4_HMW84(T, P): + """c-c'-a: calcium magnesium-hydroxide bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_MgOH_OH_HMW84(T, P): + """c-c'-a: calcium magnesium-hydroxide hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_MgOH_HCO3_HMW84(T, P): + """c-c'-a: calcium magnesium-hydroxide bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_MgOH_CO3_HMW84(T, P): + """c-c'-a: calcium magnesium-hydroxide carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_Ca_H_HMW84(T, P): + """c-c': calcium hydrogen [HMW84].""" + theta = 0.092 + valid = T == 298.15 + return theta, valid + + +def psi_Ca_H_Cl_HMW84(T, P): + """c-c'-a: calcium hydrogen chloride [HMW84].""" + psi = -0.015 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_H_SO4_HMW84(T, P): + """c-c'-a: calcium hydrogen sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_H_HSO4_HMW84(T, P): + """c-c'-a: calcium hydrogen bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_H_OH_HMW84(T, P): + """c-c'-a: calcium hydrogen hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_H_HCO3_HMW84(T, P): + """c-c'-a: calcium hydrogen bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Ca_H_CO3_HMW84(T, P): + """c-c'-a: calcium hydrogen carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_Mg_MgOH_HMW84(T, P): + """c-c': magnesium magnesium-hydroxide [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_Mg_MgOH_Cl_HMW84(T, P): + """c-c'-a: magnesium magnesium-hydroxide chloride [HMW84].""" + psi = 0.028 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_MgOH_SO4_HMW84(T, P): + """c-c'-a: magnesium magnesium-hydroxide sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_MgOH_HSO4_HMW84(T, P): + """c-c'-a: magnesium magnesium-hydroxide bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_MgOH_OH_HMW84(T, P): + """c-c'-a: magnesium magnesium-hydroxide hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_MgOH_HCO3_HMW84(T, P): + """c-c'-a: magnesium magnesium-hydroxide bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_MgOH_CO3_HMW84(T, P): + """c-c'-a: magnesium magnesium-hydroxide carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_H_Mg_HMW84(T, P): + """c-c': hydrogen magnesium [HMW84].""" + theta = 0.1 + valid = T == 298.15 + return theta, valid + + +def psi_H_Mg_Cl_HMW84(T, P): + """c-c'-a: hydrogen magnesium chloride [HMW84].""" + psi = -0.011 + valid = T == 298.15 + return psi, valid + + +def psi_H_Mg_SO4_HMW84(T, P): + """c-c'-a: hydrogen magnesium sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Mg_HSO4_HMW84(T, P): + """c-c'-a: hydrogen magnesium bisulfate [HMW84].""" + psi = -0.0178 + valid = T == 298.15 + return psi, valid + + +def psi_H_Mg_OH_HMW84(T, P): + """c-c'-a: hydrogen magnesium hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Mg_HCO3_HMW84(T, P): + """c-c'-a: hydrogen magnesium bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_Mg_CO3_HMW84(T, P): + """c-c'-a: hydrogen magnesium carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def theta_H_MgOH_HMW84(T, P): + """c-c': hydrogen magnesium-hydroxide [HMW84].""" + theta = 0.0 + valid = T == 298.15 + return theta, valid + + +def psi_H_MgOH_Cl_HMW84(T, P): + """c-c'-a: hydrogen magnesium-hydroxide chloride [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_MgOH_SO4_HMW84(T, P): + """c-c'-a: hydrogen magnesium-hydroxide sulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_MgOH_HSO4_HMW84(T, P): + """c-c'-a: hydrogen magnesium-hydroxide bisulfate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_MgOH_OH_HMW84(T, P): + """c-c'-a: hydrogen magnesium-hydroxide hydroxide [HMW84].""" + psi = 0 + valid = T == 298.15 + return psi, valid + + +def psi_H_MgOH_HCO3_HMW84(T, P): + """c-c'-a: hydrogen magnesium-hydroxide bicarbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def psi_H_MgOH_CO3_HMW84(T, P): + """c-c'-a: hydrogen magnesium-hydroxide carbonate [HMW84].""" + psi = 0.0 + valid = T == 298.15 + return psi, valid + + +def lambd_CO2_H_HMW84(T, P): + """n-c: carbon-dioxide hydrogen [HMW84].""" + lambd = 0.0 + valid = T == 298.15 + return lambd, valid + + +def lambd_CO2_Na_HMW84(T, P): + """n-c: carbon-dioxide sodium [HMW84].""" + lambd = 0.1 + valid = T == 298.15 + return lambd, valid + + +def lambd_CO2_K_HMW84(T, P): + """n-c: carbon-dioxide potassium [HMW84].""" + lambd = 0.051 + valid = T == 298.15 + return lambd, valid + + +def lambd_CO2_Ca_HMW84(T, P): + """n-c: carbon-dioxide calcium [HMW84].""" + lambd = 0.183 + valid = T == 298.15 + return lambd, valid + + +def lambd_CO2_Mg_HMW84(T, P): + """n-c: carbon-dioxide magnesium [HMW84].""" + lambd = 0.183 + valid = T == 298.15 + return lambd, valid + + +def lambd_CO2_Cl_HMW84(T, P): + """n-a: carbon-dioxide chloride [HMW84].""" + lambd = -0.005 + valid = T == 298.15 + return lambd, valid + + +def lambd_CO2_SO4_HMW84(T, P): + """n-a: carbon-dioxide sulfate [HMW84].""" + lambd = 0.097 + valid = T == 298.15 + return lambd, valid + + +def lambd_CO2_HSO4_HMW84(T, P): + """n-c: carbon-dioxide bisulfate [HMW84].""" + lambd = -0.003 + valid = T == 298.15 + return lambd, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pitzer et al. (1985) ~~~~~ +def bC_Mg_HCO3_POS85(T, P): + """c-a: magnesium bicarbonate [POS85].""" + b0 = 0.033 + b1 = 0.85 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HCO3_POS85(T, P): + """c-a: calcium bicarbonate [POS85].""" + b0 = 0.28 + b1 = 0.3 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Felmy & Weare (1986) ~~~~~ +def bC_Na_BOH4_FW86(T, P): + """c-a: sodium borate [FW86].""" + b0 = -0.0427 + b1 = 0.089 + b2 = 0 + Cphi = 0.0114 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["BOH4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_B3O3OH4_FW86(T, P): + """c-a: sodium triborate [FW86].""" + b0 = -0.056 + b1 = -0.910 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_B4O5OH4_FW86(T, P): + """c-a: sodium tetraborate [FW86].""" + b0 = -0.11 + b1 = -0.40 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_BOH4_FW86(T, P): + """c-a: potassium borate [FW86].""" + b0 = 0.035 + b1 = 0.14 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_B3O3OH4_FW86(T, P): + """c-a: potassium triborate [FW86].""" + b0 = -0.13 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_B4O5OH4_FW86(T, P): + """c-a: potassium tetraborate [FW86].""" + b0 = -0.022 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_MgBOH4_Cl_FW86(T, P): + """c-a: magnesium-borate chloride [FW86].""" + b0 = 0.16 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_CaBOH4_Cl_FW86(T, P): + """c-a: calcium-borate chloride [FW86].""" + b0 = 0.12 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_BOH4_Cl_FW86(T, P): + """a-a': borate chloride [FW86].""" + theta = -0.065 + valid = T == 298.15 + return theta, valid + + +def psi_Na_BOH4_Cl_FW86(T, P): + """c-a-a': sodium borate chloride [FW86].""" + psi = -0.0073 + valid = T == 298.15 + return psi, valid + + +def theta_BOH4_SO4_FW86(T, P): + """a-a': borate sulfate [FW86].""" + theta = -0.012 + valid = T == 298.15 + return theta, valid + + +def theta_B3O3OH4_Cl_FW86(T, P): + """a-a': triborate chloride [FW86].""" + theta = 0.12 + valid = T == 298.15 + return theta, valid + + +def psi_Na_B3O3OH4_Cl_FW86(T, P): + """c-a-a': sodium triborate chloride [FW86].""" + psi = -0.024 + valid = T == 298.15 + return psi, valid + + +def theta_B3O3OH4_SO4_FW86(T, P): + """a-a': triborate sulfate [FW86].""" + theta = 0.10 + valid = T == 298.15 + return theta, valid + + +def theta_B3O3OH4_HCO3_FW86(T, P): + """a-a': triborate bicarbonate [FW86].""" + theta = -0.10 + valid = T == 298.15 + return theta, valid + + +def theta_B4O5OH4_Cl_FW86(T, P): + """a-a': tetraborate chloride [FW86].""" + theta = 0.074 + valid = T == 298.15 + return theta, valid + + +def psi_Na_B4O5OH4_Cl_FW86(T, P): + """c-a-a': sodium tetraborate chloride [FW86].""" + psi = 0.026 + valid = T == 298.15 + return psi, valid + + +def theta_B4O5OH4_SO4_FW86(T, P): + """a-a': tetraborate sulfate [FW86].""" + theta = 0.12 + valid = T == 298.15 + return theta, valid + + +def theta_B4O5OH4_HCO3_FW86(T, P): + """a-a': tetraborate bicarbonate [FW86].""" + theta = -0.087 + valid = T == 298.15 + return theta, valid + + +def lambd_BOH3_Cl_FW86(T, P): + """n-a: boric-acid chloride [FW86].""" + lambd = 0.091 + valid = T == 298.15 + return lambd, valid + + +def lambd_BOH3_SO4_FW86(T, P): + """n-a: boric-acid sulfate [FW86].""" + lambd = 0.018 + valid = T == 298.15 + return lambd, valid + + +def lambd_BOH3_B3O3OH4_FW86(T, P): + """n-a: boric-acid triborate [FW86].""" + lambd = -0.20 + valid = T == 298.15 + return lambd, valid + + +def lambd_BOH3_Na_FW86(T, P): + """n-c: boric-acid sodium [FW86].""" + lambd = -0.097 + valid = T == 298.15 + return lambd, valid + + +def lambd_BOH3_K_FW86(T, P): + """n-c: boric-acid potassium [FW86].""" + lambd = -0.14 + valid = T == 298.15 + return lambd, valid + + +def zeta_BOH3_H_Cl_FW86(T, P): + """n-c-a: boric-acid hydrogen chloride [FW86].""" + zeta = -0.0102 + valid = T == 298.15 + return zeta, valid + + +def zeta_BOH3_Na_SO4_FW86(T, P): + """n-c-a: boric-acid sodium sulfate [FW86].""" + zeta = 0.046 + valid = T == 298.15 + return zeta, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Phutela & Pitzer (1986) ~~~~~ +PP86ii_Tr = 298.15 + + +def PP86ii_eq28(T, q): + """PP86ii equation 28.""" + Tr = PP86ii_Tr + return ( + (T**2 - Tr**2) * q[0] / 2 + + (T**3 - Tr**3) * q[1] / 3 + + (T**4 - Tr**4) * q[2] / 4 + + (T**5 - Tr**5) * q[3] / 5 + + Tr**2 * q[4] + ) / T**2 + + +def PP86ii_eq29(T, q): + """PP86ii equation 29.""" + # q[x] b0 b1 b2 C0 + # 0 q6 q10 q12 q15 + # 1 q7 q11 q13 q16 + # 2 q8 0 q14 q17 + # 3 q9 0 0 q18 + # 4 b0L(Tr) b1L(Tr) b2L(Tr) C0L(Tr) + # 5 b0(Tr) b1(Tr) b2(Tr) C0(Tr) from RM81 + Tr = PP86ii_Tr + # Substitution to avoid 'difference of two large numbers' error + t = T / Tr + # Original fourth line was: + # + q[3] * (T**4/20 + Tr**5/(5*T) - Tr**4/4) + return ( + q[0] * (T / 2 + Tr**2 / (2 * T) - Tr) + + q[1] * (T**2 / 6 + Tr**3 / (3 * T) - Tr**2 / 2) + + q[2] * (T**3 / 12 + Tr**4 / (4 * T) - Tr**3 / 3) + + q[3] * (t**5 + 4 - 5 * t) * Tr**5 / (20 * T) + + q[4] * (Tr - Tr**2 / T) + + q[5] + ) + + +def bC_Mg_SO4_PP86ii(T, P): + """c-a: magnesium sulfate [PP86ii].""" + b0r, b1r, b2r, C0r, C1, alph1, alph2, omega, _ = bC_Mg_SO4_RM81i(T, P) + b0 = PP86ii_eq29( + T, + float_( + [ + -1.0282, + 8.4790e-3, + -2.3366e-5, + 2.1575e-8, + 6.8402e-4, + b0r, + ] + ), + ) + b1 = PP86ii_eq29( + T, + float_( + [ + -2.9596e-1, + 9.4564e-4, + 0, + 0, + 1.1028e-2, + b1r, + ] + ), + ) + b2 = PP86ii_eq29( + T, + float_( + [ + -1.3764e1, + 1.2121e-1, + -2.7642e-4, + 0, + -2.1515e-1, + b2r, + ] + ), + ) + C0 = PP86ii_eq29( + T, + float_( + [ + 1.0541e-1, + -8.9316e-4, + 2.5100e-6, + -2.3436e-9, + -8.7899e-5, + C0r, + ] + ), + ) + valid = T <= 473 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Holmes and Mesmer (1986) ~~~~~ +# Note that HM86 use alph1 of 1.4 even where there is no beta2 term (p. 502) +# Also HM86 contains functions for caesium and lithium sulfates, not yet coded +def HM86_eq8(T, a): + """HM86 equation 8.""" + TR = 298.15 + # Typo in a[5] term in HM86 has been corrected here + return ( + a[0] + + a[1] * (TR - TR**2 / T) + + a[2] * (T**2 + 2 * TR**3 / T - 3 * TR**2) + + a[3] * (T + TR**2 / T - 2 * TR) + + a[4] * (log(T / TR) + TR / T - 1) + + a[5] * (1 / (T - 263) + (263 * T - TR**2) / (T * (TR - 263) ** 2)) + + a[6] * (1 / (680 - T) + (TR**2 - 680 * T) / (T * (680 - TR) ** 2)) + ) + + +def bC_K_SO4_HM86(T, P): + """c-a: potassium sulfate [HM86].""" + b0 = HM86_eq8( + T, + float_( + [ + 0, + 7.476e-4, + 0, + 4.265e-3, + -3.088, + 0, + 0, + ] + ), + ) + b1 = HM86_eq8( + T, + float_( + [ + 0.6179, + 6.85e-3, + 5.576e-5, + -5.841e-2, + 0, + -0.90, + 0, + ] + ), + ) + b2 = 0 + Cphi = HM86_eq8( + T, + float_( + [ + 9.15467e-3, + 0, + 0, + -1.81e-4, + 0, + 0, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["SO4"]))) + C1 = 0 + alph1 = 1.4 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 298.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_SO4_HM86(T, P): + """c-a: sodium sulfate [HM86].""" + b0 = HM86_eq8( + T, + float_( + [ + -1.727e-2, + 1.7828e-3, + 9.133e-6, + 0, + -6.552, + 0, + -96.90, + ] + ), + ) + b1 = HM86_eq8( + T, + float_( + [ + 0.7534, + 5.61e-3, + -5.7513e-4, + 1.11068, + -378.82, + 0, + 1861.3, + ] + ), + ) + b2 = 0 + Cphi = HM86_eq8( + T, + float_( + [ + 1.1745e-2, + -3.3038e-4, + 1.85794e-5, + -3.9200e-2, + 14.2130, + 0, + -24.950, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["SO4"]))) + C1 = 0 + alph1 = 1.4 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 298.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Roy et al. (1986) ~~~~~ +def bC_Sr_Cl_RGRG86(T, P): + """c-a: strontium chloride [RGRG86].""" + b0, b1, b2, C0, C1, alph1, alph2, omega, _ = bC_Sr_Cl_PM73(T, P) + b0 = b0 + (T - 298.15) * -3.073e-4 + b1 = b1 + (T - 298.15) * 122.379e-4 + C0 = C0 + (T - 298.15) * -6.688e-4 / 2 * sqrt(np_abs(i2c["Sr"] * i2c["Cl"])) + valid = logical_and(T >= 278.15, T <= 318.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_H_Sr_RGRG86(T, P): + """c-c': hydrogen strontium [RGRG86].""" + theta = 0.0591 + (T - 298.15) * 0.00045 + valid = logical_and(T >= 278.15, T <= 318.15) + return theta, valid + + +def psi_H_Sr_Cl_RGRG86(T, P): + """c-c'-a: hydrogen strontium chloride [RGRG86].""" + psi = 0.0054 + (T - 298.15) * 0.00021 + valid = logical_and(T >= 278.15, T <= 318.15) + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pabalan and Pitzer (1987i) ~~~~~ +# Note that there are two Pabalan & Pitzer (1987)'s: one compiling a suite of +# electrolytes (PP87ii), and one just for NaOH (PP87i). +# There are also a bunch of Phutela & Pitzer papers in similar years, so take +# care with reference codes! +def PP87i_eqNaOH(T, P, a): + """PP87i equation for sodium hydroxide, with pressure in bar.""" + return ( + a[0] + + a[1] * P + + a[2] / T + + a[3] * P / T + + a[4] * log(T) + + a[5] * T + + a[6] * T * P + + a[7] * T**2 + + a[8] * T**2 * P + + a[9] / (T - 227) + + a[10] / (647 - T) + + a[11] * P / (647 - T) + ) + + +def bC_Na_OH_PP87i(T, P): + """c-a: sodium hydroxide [PP87i].""" + P_bar = P / 10 # convert dbar to bar + b0 = PP87i_eqNaOH( + T, + P_bar, + [ + 2.7682478e2, + -2.8131778e-3, + -7.3755443e3, + 3.7012540e-1, + -4.9359970e1, + 1.0945106e-1, + 7.1788733e-6, + -4.0218506e-5, + -5.8847404e-9, + 1.1931122e1, + 2.4824963e00, + -4.8217410e-3, + ], + ) + b1 = PP87i_eqNaOH( + T, + P_bar, + [ + 4.6286977e2, + 0, + -1.0294181e4, + 0, + -8.5960581e1, + 2.3905969e-1, + 0, + -1.0795894e-4, + 0, + 0, + 0, + 0, + ], + ) + b2 = 0 + Cphi = PP87i_eqNaOH( + T, + P_bar, + [ + -1.6686897e01, + 4.0534778e-04, + 4.5364961e02, + -5.1714017e-02, + 2.9680772e000, + -6.5161667e-03, + -1.0553037e-06, + 2.3765786e-06, + 8.9893405e-10, + -6.8923899e-01, + -8.1156286e-02, + 0, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 298.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_Cl_PP87i(T, P): + """c-a: magnesium chloride [PP87i].""" + b0, b1, b2, _, C1, alph1, alph2, omega, _ = bC_Mg_Cl_dLP83(T, P) + Cphi = 2.41831e-7 * T**2 - 2.49949e-4 * T + 5.95320e-2 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["Cl"]))) + valid = logical_and(T >= 298.15, T <= 473.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pabalan and Pitzer (1987ii) ~~~~~ +def theta_K_Na_PP87ii(T, P): + """c-c': potassium sodium [PP87ii].""" + theta = -0.012 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return theta, valid + + +def theta_Mg_Na_PP87ii(T, P): + """c-c': magnesium sodium [PP87ii].""" + theta = 0.07 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return theta, valid + + +def theta_K_Mg_PP87ii(T, P): + """c-c': potassium magnesium [PP87ii].""" + theta = 0 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return theta, valid + + +def theta_Cl_SO4_PP87ii(T, P): + """a-a': chloride sulfate [PP87ii].""" + theta = 0.030 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return theta, valid + + +def theta_Cl_OH_PP87ii(T, P): + """a-a': chloride hydroxide [PP87ii].""" + theta = -0.050 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return theta, valid + + +def theta_OH_SO4_PP87ii(T, P): + """a-a': hydroxide sulfate [PP87ii].""" + theta = -0.013 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return theta, valid + + +def psi_K_Na_Cl_PP87ii(T, P): + """c-c'-a: potassium sodium chloride [PP87ii].""" + psi = -6.81e-3 + 1.68e-5 * T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return psi, valid + + +def psi_Mg_Na_Cl_PP87ii(T, P): + """c-c'-a: magnesium sodium chloride [PP87ii].""" + psi = 1.99e-2 - 9.51 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return psi, valid + + +def psi_K_Mg_Cl_PP87ii(T, P): + """c-c'-a: potassium magnesium chloride [PP87ii].""" + psi = 2.586e-2 - 14.27 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return psi, valid + + +def psi_Na_Cl_SO4_PP87ii(T, P): + """c-a-a': sodium chloride sulfate [PP87ii].""" + psi = 0 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return psi, valid + + +def psi_K_Cl_SO4_PP87ii(T, P): + """c-a-a': potassium chloride sulfate [PP87ii].""" + psi = -5e-3 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return psi, valid + + +def psi_Mg_Cl_SO4_PP87ii(T, P): + """c-a-a': magnesium chloride sulfate [PP87ii].""" + psi = -1.174e-1 + 32.63 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return psi, valid + + +def psi_Na_Cl_OH_PP87ii(T, P): + """c-a-a': sodium chloride hydroxide [PP87ii].""" + psi = 2.73e-2 - 9.93 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return psi, valid + + +def psi_Na_OH_SO4_PP87ii(T, P): + """c-a-a': sodium hydroxide sulfate [PP87ii].""" + psi = 3.02e-2 - 11.69 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = logical_and(T >= 298.15, T <= 523.25) + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Simonson, Roy & Gibbons (1987) ~~~~~ +def bC_K_CO3_SRG87(T, P): + """c-a: potassium carbonate [SRG87].""" + b0 = 0.1288 + 1.1e-3 * (T - 298.15) - 5.1e-6 * (T - 298.15) ** 2 + b1 = 1.433 + 4.36e-3 * (T - 298.15) + 2.07e-5 * (T - 298.15) ** 2 + b2 = 0 + # MP98 declare Cphi = 0.0005, but I can't find that anywhere in SRG87 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 368.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Simonson et al. (1987) ~~~~~ +def SRRJ87_eq7(T, a): + """SRRJ87 equation 7.""" + Tr = 298.15 + return a[0] + a[1] * 1e-3 * (T - Tr) + a[2] * 1e-5 * (T - Tr) ** 2 + + +def bC_K_Cl_SRRJ87(T, P): + """c-a: potassium chloride [SRRJ87].""" + # Parameters from SRRJ87 Table III + b0 = SRRJ87_eq7( + T, + float_( + [ + 0.0481, + 0.592, + -0.562, + ] + ), + ) + b1 = SRRJ87_eq7( + T, + float_( + [ + 0.2188, + 1.500, + -1.085, + ] + ), + ) + b2 = 0 + Cphi = ( + SRRJ87_eq7( + T, + float_( + [ + -0.790, + -0.639, + 0.613, + ] + ), + ) + * 1e-3 + ) # *1e-3 presumably? + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Cl_SRRJ87(T, P): + """c-a: sodium chloride [SRRJ87].""" + # Parameters from SRRJ87 Table III + b0 = SRRJ87_eq7( + T, + float_( + [ + 0.0754, + 0.792, + -0.935, + ] + ), + ) + b1 = SRRJ87_eq7( + T, + float_( + [ + 0.2770, + 1.006, + -0.756, + ] + ), + ) + b2 = 0 + Cphi = ( + SRRJ87_eq7( + T, + float_( + [ + 1.40, + -1.20, + 1.15, + ] + ), + ) + * 1e-3 + ) # *1e-3 presumably? + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_BOH4_SRRJ87(T, P): + """c-a: potassium borate [SRRJ87].""" + # Parameters from SRRJ87 Table III + b0 = SRRJ87_eq7( + T, + [ + 0.1469, + 2.881, + 0, + ], + ) + b1 = SRRJ87_eq7( + T, + [ + -0.0989, + -6.876, + 0, + ], + ) + b2 = 0 + Cphi = ( + SRRJ87_eq7( + T, + [ + -56.43, + -9.56, + 0, + ], + ) + * 1e-3 + ) # *1e-3 presumably? + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["BOH4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_BOH4_SRRJ87(T, P): + """c-a: sodium borate [SRRJ87].""" + # Parameters from SRRJ87 Table III + b0 = SRRJ87_eq7( + T, + float_( + [ + -0.0510, + 5.264, + 0, + ] + ), + ) + b1 = SRRJ87_eq7( + T, + float_( + [ + 0.0961, + -10.68, + 0, + ] + ), + ) + b2 = 0 + Cphi = ( + SRRJ87_eq7( + T, + float_( + [ + 14.98, + -15.7, + 0, + ] + ), + ) + * 1e-3 + ) # *1e-3 presumably? + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["BOH4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_BOH4_Cl_SRRJ87(T, P): + """a-a': borate chloride [SRRJ87].""" + # Parameter from SRRJ87 Table III + theta = -0.056 + valid = logical_and(T >= 278.15, T <= 328.15) + return theta, valid + + +def psi_K_BOH4_Cl_SRRJ87(T, P): + """c-a-a': potassium borate chloride [SRRJ87].""" + psi = 0 + valid = logical_and(T >= 278.15, T <= 328.15) + return psi, valid + + +def psi_Na_BOH4_Cl_SRRJ87(T, P): + """c-a-a': sodium borate chloride [SRRJ87].""" + # Parameter from SRRJ87 Table III + psi = -0.019 + valid = logical_and(T >= 278.15, T <= 328.15) + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Simonson et al. (1987b) ~~~~~ +def SRM87_eqTableIII(T, abc): + """SRM87 equation from Table III.""" + return abc[0] + abc[1] * 1e-3 * (T - 298.15) + abc[2] * 1e-3 * (T - 303.15) ** 2 + + +def bC_Mg_BOH4_SRM87(T, P): + """c-a: magnesium borate [SRM87].""" + b0 = SRM87_eqTableIII( + T, + [ + -0.6230, + 6.496, + 0, + ], + ) + b1 = SRM87_eqTableIII( + T, + [ + 0.2515, + -17.13, + 0, + ], + ) + b2 = SRM87_eqTableIII( + T, + [ + -11.47, + 0, + -3.240, + ], + ) + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = 6 + omega = -9 + valid = logical_and(T >= 278.15, T <= 528.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_BOH4_SRM87(T, P): + """c-a: calcium borate [SRM87].""" + b0 = SRM87_eqTableIII( + T, + [ + -0.4462, + 5.393, + 0, + ], + ) + b1 = SRM87_eqTableIII( + T, + [ + -0.8680, + -18.20, + 0, + ], + ) + b2 = SRM87_eqTableIII( + T, + [ + -15.88, + 0, + -2.858, + ], + ) + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = 6 + omega = -9 + valid = logical_and(T >= 278.15, T <= 528.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Hershey et al. (1988) ~~~~~ +def bC_Na_HS_HPM88(T, P): + """c-a: sodium bisulfide [HPM88].""" + b0 = 3.66e-1 - 6.75e1 / T + b1 = 0 + b2 = 0 + Cphi = -1.27e-2 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["HS"]))) + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 318.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HS_HPM88(T, P): + """c-a: potassium bisulfide [HPM88].""" + b0 = 6.37e-1 - 1.40e2 / T + b1 = 0 + b2 = 0 + Cphi = -1.94e-1 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["HS"]))) + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 298.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_HS_HPM88(T, P): + """c-a: magnesium bisulfide [HPM88].""" + b0 = 1.70e-1 + b1 = 2.78 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HS_HPM88(T, P): + """c-a: calcium bisulfide [HPM88].""" + b0 = -1.05e-1 + b1 = 3.43 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Møller (1988) ~~~~~ +def M88_eq13(T, a): + """M88 equation 13.""" + return ( + a[0] + + a[1] * T + + a[2] / T + + a[3] * log(T) + + a[4] / (T - 263) + + a[5] * T**2 + + a[6] / (680 - T) + + a[7] / (T - 227) + ) + + +def b0_Ca_Cl_M88(T, P): + """beta0: calcium chloride [M88].""" + return M88_eq13( + T, + float_( + [ + -9.41895832e1, + -4.04750026e-2, + 2.34550368e3, + 1.70912300e1, + -9.22885841e-1, + 1.51488122e-5, + -1.39082000e00, + 0, + ] + ), + ) + + +def b1_Ca_Cl_M88(T, P): + """beta1: calcium chloride [M88].""" + return M88_eq13( + T, + float_( + [ + 3.47870000e00, + -1.54170000e-2, + 0, + 0, + 0, + 3.17910000e-5, + 0, + 0, + ] + ), + ) + + +def Cphi_Ca_Cl_M88(T, P): + """Cphi: calcium chloride [M88].""" + return M88_eq13( + T, + float_( + [ + -3.03578731e1, + -1.36264728e-2, + 7.64582238e2, + 5.50458061e00, + -3.27377782e-1, + 5.69405869e-6, + -5.36231106e-1, + 0, + ] + ), + ) + + +def bC_Ca_Cl_M88(T, P): + """c-a: calcium chloride [M88].""" + b0 = b0_Ca_Cl_M88(T, P) + b1 = b1_Ca_Cl_M88(T, P) + b2 = 0 + Cphi = Cphi_Ca_Cl_M88(T, P) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 298.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_SO4_M88(T, P): + """c-a: calcium sulfate [M88].""" + b0 = 0.15 + b1 = 3.00 + b2 = M88_eq13( + T, + float_( + [ + -1.29399287e2, + 4.00431027e-1, + 0, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = 12 + omega = -9 + valid = logical_and(T >= 298.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Cl_M88(T, P): + """c-a: sodium chloride [M88].""" + b0 = M88_eq13( + T, + float_( + [ + 1.43783204e1, + 5.60767406e-3, + -4.22185236e2, + -2.51226677e00, + 0, + -2.61718135e-6, + 4.43854508e00, + -1.70502337e00, + ] + ), + ) + b1 = M88_eq13( + T, + float_( + [ + -4.83060685e-1, + 1.40677479e-3, + 1.19311989e2, + 0, + 0, + 0, + 0, + -4.23433299e00, + ] + ), + ) + b2 = 0 + Cphi = M88_eq13( + T, + float_( + [ + -1.00588714e-1, + -1.80529413e-5, + 8.61185543e00, + 1.24880954e-2, + 0, + 3.41172108e-8, + 6.83040995e-2, + 2.93922611e-1, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 573.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_SO4_M88(T, P): + """c-a: sodium sulfate [M88].""" + b0 = M88_eq13( + T, + float_( + [ + 8.16920027e1, + 3.01104957e-2, + -2.32193726e3, + -1.43780207e1, + -6.66496111e-1, + -1.03923656e-5, + 0, + 0, + ] + ), + ) + b1 = M88_eq13( + T, + float_( + [ + 1.00463018e3, + 5.77453682e-1, + -2.18434467e4, + -1.89110656e2, + -2.03550548e-1, + -3.23949532e-4, + 1.46772243e3, + 0, + ] + ), + ) + b2 = 0 + Cphi = M88_eq13( + T, + float_( + [ + -8.07816886e1, + -3.54521126e-2, + 2.02438830e3, + 1.46197730e1, + -9.16974740e-2, + 1.43946005e-5, + -2.42272049e00, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 573.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_Ca_Na_M88(T, P): + """c-c': calcium sodium [M88].""" + theta = 0.05 + valid = logical_and(T >= 298.15, T <= 523.15) + return theta, valid + + +def theta_Cl_SO4_M88(T, P): + """a-a': chloride sulfate [M88].""" + theta = 0.07 + valid = logical_and(T >= 298.15, T <= 423.15) + return theta, valid + + +def psi_Ca_Na_Cl_M88(T, P): + """c-c'-a: calcium sodium chloride [M88].""" + psi = -0.003 + valid = logical_and(T >= 298.15, T <= 523.15) + return psi, valid + + +def psi_Ca_Na_SO4_M88(T, P): + """c-c'-a: calcium sodium sulfate [M88].""" + psi = -0.012 + valid = logical_and(T >= 298.15, T <= 523.15) + return psi, valid + + +def psi_Ca_Cl_SO4_M88(T, P): + """c-a-a': calcium chloride sulfate [M88].""" + psi = -0.018 + valid = logical_and(T >= 298.15, T <= 523.15) + return psi, valid + + +def psi_Na_Cl_SO4_M88(T, P): + """c-a-a': sodium chloride sulfate [M88].""" + psi = -0.009 + valid = logical_and(T >= 298.15, T <= 423.15) + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clegg & Brimblecombe (1989) ~~~~~ +def lambd_NH3_NH3_CB89(T, P): + """n-n: ammonia ammonia [CB89].""" + lambd = 0.033161 - 21.12816 / T + 4665.1461 / T**2 + valid = logical_and(T >= 273.15, T <= 313.15) + return lambd, valid + + +def lambd_NH3_Mg_CB89(T, P): + """n-c: ammonia magnesium [CB89].""" + lambd = -0.21 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_Ca_CB89(T, P): + """n-c: ammonia calcium [CB89].""" + lambd = -0.081 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_Sr_CB89(T, P): + """n-c: ammonia strontium [CB89].""" + lambd = -0.041 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_Ba_CB89(T, P): + """n-c: ammonia barium [CB89].""" + lambd = -0.021 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_Li_CB89(T, P): + """n-c: ammonia lithium [CB89].""" + lambd = -0.038 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_Na_CB89(T, P): + """n-c: ammonia sodium [CB89].""" + lambd = 0.0175 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_K_CB89(T, P): + """n-c: ammonia potassium [CB89].""" + lambd = 0.0454 + (T - 298.15) * -0.000141 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_NH4_CB89(T, P): + """n-c: ammonia ammonium [CB89].""" + lambd = 0 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_F_CB89(T, P): + """n-a: ammonia fluoride [CB89].""" + lambd = 0.091 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_Cl_CB89(T, P): + """n-a: ammonia chloride [CB89].""" + lambd = 0 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_Br_CB89(T, P): + """n-a: ammonia bromide [CB89].""" + lambd = -0.022 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_I_CB89(T, P): + """n-a: ammonia iodide [CB89].""" + lambd = -0.051 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_OH_CB89(T, P): + """n-a: ammonia hydroxide [CB89].""" + lambd = 0.103 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_ClO3_CB89(T, P): + """n-a: ammonia chlorate [CB89].""" + lambd = -0.004 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_ClO4_CB89(T, P): + """n-a: ammonia perchlorate [CB89].""" + lambd = -0.056 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_NO2_CB89(T, P): + """n-a: ammonia nitrite [CB89].""" + lambd = -0.003 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_NO3_CB89(T, P): + """n-a: ammonia nitrate [CB89].""" + lambd = -0.01 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_SCN_CB89(T, P): + """n-a: ammonia thiocyanide [CB89].""" + lambd = -0.017 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_S_CB89(T, P): + """n-a: ammonia sulfide [CB89].""" + lambd = 0.174 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_SO3_CB89(T, P): + """n-a: ammonia sulfite [CB89].""" + lambd = 0.158 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_SO4_CB89(T, P): + """n-a: ammonia sulfate [CB89].""" + lambd = 0.140 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_CO3_CB89(T, P): + """n-a: ammonia carbonate [CB89].""" + lambd = 0.180 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_HCOO_CB89(T, P): + """n-a: ammonia methanoate [CB89].""" + lambd = 0.048 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_CH3COO_CB89(T, P): + """n-a: ammonia ethanoate [CB89].""" + lambd = 0.036 + valid = T == 298.15 + return lambd, valid + + +def lambd_NH3_COO2_CB89(T, P): + """n-a: ammonia oxalate [CB89].""" + lambd = 0.012 + valid = T == 298.15 + return lambd, valid + + +def mun2i_NH3_NH3_Na_CB89(T, P): + """n-n-c: ammonia ammonia sodium [CB89].""" + mun2i = -0.000311 + valid = T == 298.15 + return mun2i, valid + + +def mun2i_NH3_NH3_K_CB89(T, P): + """n-n-c: ammonia ammonia potassium [CB89].""" + mun2i = -0.000321 + valid = T == 298.15 + return mun2i, valid + + +def mun2i_NH3_NH3_NH4_CB89(T, P): + """n-n-c: ammonia ammonia ammonium [CB89].""" + mun2i = -0.00075 + valid = T == 298.15 + return mun2i, valid + + +def mun2i_NH3_NH3_Cl_CB89(T, P): + """n-n-a: ammonia ammonia chloride [CB89].""" + mun2i = 0 + valid = T == 298.15 + return mun2i, valid + + +def mun2i_NH3_NH3_NO3_CB89(T, P): + """n-n-a: ammonia ammonia nitrate [CB89].""" + mun2i = -0.000437 + valid = T == 298.15 + return mun2i, valid + + +def mun2i_NH3_NH3_CO3_CB89(T, P): + """n-n-a: ammonia ammonia carbonate [CB89].""" + mun2i = 0.000625 + valid = T == 298.15 + return mun2i, valid + + +def zeta_NH3_Ca_Cl_CB89(T, P): + """n-c-a: ammonia calcium chloride [CB89].""" + zeta = -0.00134 + valid = T == 298.15 + return zeta, valid + + +def zeta_NH3_K_OH_CB89(T, P): + """n-c-a: ammonia potassium hydroxide [CB89].""" + zeta = 0.00385 + valid = T == 298.15 + return zeta, valid + + +def munii_NH3_NH4_SO4_CB89(T, P): + """n-a-a': ammonia ammonium sulfate [CB89].""" + munii = -0.00153 + valid = T == 298.15 + return munii, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Greenberg & Møller (1989) ~~~~~ +def GM89_eq3(T, a): + """GM89 equation 3.""" + return M88_eq13(T, a) + + +def Cphi_Ca_Cl_GM89(T, P): + """Cphi: calcium chloride [GM89].""" + return GM89_eq3( + T, + float_( + [ + 1.93056024e1, + 9.77090932e-3, + -4.28383748e2, + -3.57996343e00, + 8.82068538e-2, + -4.62270238e-6, + 9.91113465e00, + 0, + ] + ), + ) + + +def bC_Ca_Cl_GM89(T, P): + """c-a: calcium chloride [GM89].""" + b0, b1, b2, _, C1, alph1, alph2, omega, valid = bC_Ca_Cl_M88(T, P) + Cphi = Cphi_Ca_Cl_GM89(T, P) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["Cl"]))) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Cl_GM89(T, P): + """c-a: potassium chloride [GM89].""" + b0 = GM89_eq3( + T, + float_( + [ + 2.67375563e1, + 1.00721050e-2, + -7.58485453e2, + -4.70624175e00, + 0, + -3.75994338e-6, + 0, + 0, + ] + ), + ) + b1 = GM89_eq3( + T, + float_( + [ + -7.41559626e00, + 0, + 3.22892989e2, + 1.16438557e00, + 0, + 0, + 0, + -5.94578140e00, + ] + ), + ) + b2 = 0 + Cphi = GM89_eq3( + T, + float_( + [ + -3.30531334e00, + -1.29807848e-3, + 9.12712100e1, + 5.86450181e-1, + 0, + 4.95713573e-7, + 0, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_SO4_GM89(T, P): + """c-a: potassium sulfate [GM89].""" + b0 = GM89_eq3( + T, + float_( + [ + 4.07908797e1, + 8.26906675e-3, + -1.41842998e3, + -6.74728848e00, + 0, + 0, + 0, + 0, + ] + ), + ) + b1 = GM89_eq3( + T, + float_( + [ + -1.31669651e1, + 2.35793239e-2, + 2.06712594e3, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + b2 = 0 + Cphi = -0.0188 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_Ca_K_GM89(T, P): + """c-c': calcium potassium [GM89].""" + theta = 0.1156 + valid = logical_and(T >= 273.15, T <= 523.15) + return theta, valid + + +def theta_K_Na_GM89(T, P): + """c-c': potassium sodium [GM89].""" + theta = GM89_eq3( + T, + float_( + [ + -5.02312111e-2, + 0, + 1.40213141e1, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + valid = logical_and(T >= 273.15, T <= 523.15) + return theta, valid + + +def psi_Ca_K_Cl_GM89(T, P): + """c-c'-a: calcium potassium chloride [GM89].""" + psi = GM89_eq3( + T, + float_( + [ + 4.76278977e-2, + 0, + -2.70770507e1, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + valid = logical_and(T >= 273.15, T <= 523.15) + return psi, valid + + +def psi_Ca_K_SO4_GM89(T, P): + """c-c'-a: calcium potassium sulfate [GM89].""" + psi = 0 + valid = logical_and(T >= 273.15, T <= 523.15) + return psi, valid + + +def psi_K_Na_Cl_GM89(T, P): + """c-c'-a: potassium sodium chloride [GM89].""" + psi = GM89_eq3( + T, + float_( + [ + 1.34211308e-2, + 0, + -5.10212917e00, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + valid = logical_and(T >= 273.15, T <= 523.15) + return psi, valid + + +def psi_K_Na_SO4_GM89(T, P): + """c-c'-a: potassium sodium sulfate [GM89].""" + psi = GM89_eq3( + T, + float_( + [ + 3.48115174e-2, + 0, + -8.21656777e00, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + valid = logical_and(T >= 273.15, T <= 423.15) + return psi, valid + + +def psi_K_Cl_SO4_GM89(T, P): + """c-a-a': potassium chloride sulfate [GM89].""" + psi = GM89_eq3( + T, + float_( + [ + -2.12481475e-1, + 2.84698333e-4, + 3.75619614e1, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + valid = logical_and(T >= 273.15, T <= 523.15) + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Hershey et al. (1989) ~~~~~ +def bC_Mg_H2PO4_HFM89(T, P): + """c-a: magnesium dihydrogen-phosphate [HFM89].""" + b0 = -3.55 + b1 = 16.9 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_HPO4_HFM89(T, P): + """c-a: magnesium hydrogen-phosphate [HFM89].""" + b0 = -17.5 + b1 = 27.4 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_Cl_H2PO4_HFM89(T, P): + """a-a': chloride dihydrogen-phosphate [HFM89].""" + theta = 0.10 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_H2PO4_HFM89(T, P): + """c-a-a': sodium chloride dihydrogen-phosphate [HFM89].""" + psi = -0.028 + valid = T == 298.15 + return psi, valid + + +def theta_Cl_HPO4_HFM89(T, P): + """a-a': chloride hydrogen-phosphate [HFM89].""" + theta = -0.105 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_HPO4_HFM89(T, P): + """c-a-a': sodium chloride hydrogen-phosphate [HFM89].""" + psi = -0.003 + valid = T == 298.15 + return psi, valid + + +def theta_Cl_PO4_HFM89(T, P): + """a-a': chloride phosphate [HFM89].""" + theta = -0.59 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_PO4_HFM89(T, P): + """c-a-a': sodium chloride phosphate [HFM89].""" + psi = 0.110 + valid = T == 298.15 + return psi, valid + + +def lambd_H3PO4_Na_HFM89(T, P): + """n-c: phosphoric-acid sodium [HFM89].""" + lambd = 0.075 + valid = T == 298.15 + return lambd, valid + + +def lambd_H3PO4_Cl_HFM89(T, P): + """n-a: phosphoric-acid chloride [HFM89].""" + lambd = 0 + valid = T == 298.15 + return lambd, valid + + +def lambd_MgHPO4_Na_HFM89(T, P): + """n-n': magnesium-hydrogen-phosphate sodium [HFM89].""" + lambd = -0.124 + valid = T == 298.15 + return lambd, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Millero et al. (1989) ~~~~~ +def bC_Na_SO3_MHJZ89(T, P): + """c-a: sodium sulfite [MHJZ89].""" + b0 = 5.88444 - 1730.55 / T # Eq. (36) + b1 = -19.4549 + 6153.78 / T # Eq. (37) + b2 = 0 + Cphi = -1.2355 + 367.07 / T # Eq. (38) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["SO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HSO3_MHJZ89(T, P): + """c-a: sodium hydrogen-sulfite [MHJZ89].""" + b0 = 4.3407 - 1248.66 / T # Eq. (29) + b1 = -13.146 + 4014.80 / T # Eq. (30) + b2 = 0 + Cphi = 0.9565 + 277.85 / T # Eq. (31), note difference from MP98 Table A3 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["HSO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_Cl_SO3_MHJZ89(T, P): + """a-a': chloride sulfite [MHJZ89].""" + theta = 0.099 # +/- 0.004 + valid = logical_and(T >= 273.15, T <= 323.15) + return theta, valid + + +def psi_Na_Cl_SO3_MHJZ89(T, P): + """c-a-a': sodium chloride sulfite [MHJZ89].""" + psi = -0.0156 # +/- 0.001 + valid = logical_and(T >= 273.15, T <= 323.15) + return psi, valid + + +def lambd_SO2_Na_MHJZ89(T, P): + """n-c: sulfur-dioxide sodium [MHJZ89].""" + # RZM93 and MP98 both cite MHJZ89 but can't find this value therein + lambd = 0.0283 + valid = T == 298.15 + return lambd, valid + + +def lambd_SO2_Cl_MHJZ89(T, P): + """n-a: sulfur-dioxide chloride [MHJZ89].""" + # RZM93 and MP98 both cite MHJZ89 but can't find this value therein + lambd = 0 + valid = T == 298.15 + return lambd, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Roy et al. (1991) ~~~~~ +def bC_Mg_HSO3_RZM91(T, P): + """c-a: magnesium bisulfite [RZM91].""" + b0 = 0.35 + b1 = 1.22 + b2 = 0 + Cphi = -0.072 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["HSO3"]))) + C1 = 0 + alph1 = 2.0 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_SO3_RZM91(T, P): + """c-a: magnesium sulfite [RZM91].""" + b0 = -2.8 + b1 = 12.9 + b2 = -201 + C0 = 0 + C1 = 0 + alph1 = 1.4 + alph2 = 12 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def lambd_SO2_Mg_RZM91(T, P): + """n-c: sulfur-dioxide magnesium [RZM91].""" + lambd = 0.085 + valid = T == 298.15 + return lambd, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Archer (1992) ~~~~~ +def A92ii_eq36(T, P, a): + """A92ii equation 36, with pressure in MPa.""" + # a[5] and a[6] multipliers are corrected for typos in A92ii + return ( + a[0] + + a[1] * 10**-3 * T + + a[2] * 4e-6 * T**2 + + a[3] * 1 / (T - 200) + + a[4] * 1 / T + + a[5] * 100 / (T - 200) ** 2 + + a[6] * 200 / T**2 + + a[7] * 8e-9 * T**3 + + a[8] * 1 / (650 - T) ** 0.5 + + a[9] * 10**-5 * P + + a[10] * 2e-4 * P / (T - 225) + + a[11] * 100 * P / (650 - T) ** 3 + + a[12] * 2e-8 * P * T + + a[13] * 2e-4 * P / (650 - T) + + a[14] * 10**-7 * P**2 + + a[15] * 2e-6 * P**2 / (T - 225) + + a[16] * P**2 / (650 - T) ** 3 + + a[17] * 2e-10 * P**2 * T + + a[18] * 4e-13 * P**2 * T**2 + + a[19] * 0.04 * P / (T - 225) ** 2 + + a[20] * 4e-11 * P * T**2 + + a[21] * 2e-8 * P**3 / (T - 225) + + a[22] * 0.01 * P**3 / (650 - T) ** 3 + + a[23] * 200 / (650 - T) ** 3 + ) + + +def bC_Na_Cl_A92ii(T, P): + """c-a: sodium chloride [A92ii].""" + P_MPa = P / 100 # Convert dbar to MPa + # Parameters from A92ii Table 2, with noted corrections + b0 = A92ii_eq36( + T, + P_MPa, + [ + 0.242408292826506, + 0, + -0.162683350691532, + 1.38092472558595, + 0, + 0, + -67.2829389568145, + 0, + 0.625057580755179, + -21.2229227815693, + 81.8424235648693, + -1.59406444547912, + 0, + 0, + 28.6950512789644, + -44.3370250373270, + 1.92540008303069, + -32.7614200872551, + 0, + 0, + 30.9810098813807, + 2.46955572958185, + -0.725462987197141, + 10.1525038212526, + ], + ) + b1 = A92ii_eq36( + T, + P_MPa, + [ + -1.90196616618343, + 5.45706235080812, + 0, + -40.5376417191367, + 0, + 0, + 4.85065273169753 * 1e2, + -0.661657744698137, + 0, + 0, + 2.42206192927009 * 1e2, + 0, + -99.0388993875343, + 0, + 0, + -59.5815563506284, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + ) + b2 = 0 + C0 = A92ii_eq36( + T, + P_MPa, + [ + 0, + -0.0412678780636594, + 0.0193288071168756, + -0.338020294958017, # typo in A92ii + 0, + 0.0426735015911910, + 4.14522615601883, + -0.00296587329276653, + 0, + 1.39697497853107, + -3.80140519885645, + 0.06622025084, # typo in A92ii - "Rard's letter" + 0, + -16.8888941636379, + -2.49300473562086, + 3.14339757137651, + 0, + 2.79586652877114, + 0, + 0, + 0, + 0, + 0, + -0.502708980699711, + ], + ) + C1 = A92ii_eq36( + T, + P_MPa, + [ + 0.788987974218570, + -3.67121085194744, + 1.12604294979204, + 0, + 0, + -10.1089172644722, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 16.6503495528290, + ], + ) + alph1 = 2 + alph2 = -9 + omega = 2.5 + valid = logical_and(T >= 250, T <= 600) + valid = logical_and(valid, P_MPa <= 100) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Campbell et al. (1993) ~~~~~ +def CMR93_eq31(T, a): + """CMR93 equation 31.""" + return M88_eq13(T, a) + + +def bC_H_Cl_CMR93(T, P): + """c-a: hydrogen chloride [CMR93].""" + # b0 a[1] term corrected here for typo, following WM13 + b0 = CMR93_eq31( + T, + float_( + [ + 1.2859, + -2.1197e-3, + -142.5877, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + b1 = CMR93_eq31( + T, + float_( + [ + -4.4474, + 8.425698e-3, + 665.7882, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + b2 = 0 + Cphi = CMR93_eq31( + T, + float_( + [ + -0.305156, + 5.16e-4, + 45.52154, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_H_K_CMR93(T, P): + """c-c': hydrogen potassium [CMR93].""" + # assuming CMR93's lowercase t means temperature in degC + theta = 0.005 - 0.0002275 * (T - Tzero) + valid = logical_and(T >= 273.15, T <= 328.15) + return theta, valid + + +def theta_H_Na_CMR93(T, P): + """c-c': hydrogen sodium [CMR93].""" + # assuming CMR93's lowercase t means temperature in degC + theta = 0.0342 - 0.000209 * (T - Tzero) + valid = logical_and(T >= 273.15, T <= 328.15) + return theta, valid + + +def psi_H_K_Cl_CMR93(T, P): + """c-c'-a: hydrogen potassium chloride [CMR93].""" + psi = 0 + valid = logical_and(T >= 273.15, T <= 523.15) + return psi, valid + + +def psi_H_Na_Cl_CMR93(T, P): + """c-c'-a: hydrogen sodium chloride [CMR93].""" + psi = 0 + valid = logical_and(T >= 273.15, T <= 523.15) + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ He & Morse (1993) ~~~~~ +# Note that HM93 also contains beta/C equations for Na, K, Mg and Ca +# interactions with HCO3 and CO3 (not yet coded here) +def HM93_eq(T, A, B, C, D, E): + """HM93 parameter equation from p. 3548.""" + return A + B * T + C * T**2 + D / T + E * log(T) + + +def lambd_CO2_H_HM93(T, P): + """n-c: carbon-dioxide hydrogen [HM93].""" + lambd = 0 + valid = logical_and(T >= 273.15, T <= 363.15) + return lambd, valid + + +def lambd_CO2_Na_HM93(T, P): + """n-c: carbon-dioxide sodium [HM93].""" + lambd = HM93_eq( + T, + -5496.38465, + -3.326566, + 0.0017532, + 109399.341, + 1047.021567, + ) + valid = logical_and(T >= 273.15, T <= 363.15) + return lambd, valid + + +def lambd_CO2_K_HM93(T, P): + """n-c: carbon-dioxide potassium [HM93].""" + lambd = HM93_eq( + T, + 2856.528099, + 1.7670079, + -0.0009487, + -55954.1929, + -546.074467, + ) + valid = logical_and(T >= 273.15, T <= 363.15) + return lambd, valid + + +def lambd_CO2_Ca_HM93(T, P): + """n-c: carbon-dioxide calcium [HM93].""" + lambd = HM93_eq( + T, + -12774.6472, + -8.101555, + 0.00442472, + 245541.5435, + 2452.509720, + ) + valid = logical_and(T >= 273.15, T <= 363.15) + return lambd, valid + + +def lambd_CO2_Mg_HM93(T, P): + """n-c: carbon-dioxide magnesium [HM93].""" + lambd = HM93_eq( + T, + -479.362533, + -0.541843, + 0.00038812, + 3589.474052, + 104.3452732, + ) + valid = logical_and(T >= 273.15, T <= 363.15) + return lambd, valid + + +def lambd_CO2_Cl_HM93(T, P): + """n-a: carbon-dioxide chloride [HM93].""" + lambd = HM93_eq(T, 1659.944942, 0.9964326, -0.00052122, -33159.6177, -315.827883) + valid = logical_and(T >= 273.15, T <= 363.15) + return lambd, valid + + +def lambd_CO2_SO4_HM93(T, P): + """n-a: carbon-dioxide sulfate [HM93].""" + lambd = HM93_eq( + T, + 2274.656591, + 1.8270948, + -0.00114272, + -33927.7625, + -457.015738, + ) + valid = logical_and(T >= 273.15, T <= 363.15) + return lambd, valid + + +def zeta_CO2_H_Cl_HM93(T, P): + """n-c-a: carbon-dioxide hydrogen chloride [HM93].""" + zeta = HM93_eq(T, -804.121738, -0.470474, 0.000240526, 16334.38917, 152.3838752) + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def zeta_CO2_Na_Cl_HM93(T, P): + """n-c-a: carbon-dioxide sodium chloride [HM93].""" + zeta = HM93_eq(T, -379.459185, -0.258005, 0.000147823, 6879.030871, 73.74511574) + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def zeta_CO2_K_Cl_HM93(T, P): + """n-c-a: carbon-dioxide potassium chloride [HM93].""" + zeta = HM93_eq(T, -379.686097, -0.257891, 0.000147333, 6853.264129, 73.79977116) + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def zeta_CO2_Ca_Cl_HM93(T, P): + """n-c-a: carbon-dioxide calcium chloride [HM93].""" + zeta = HM93_eq(T, -166.065290, -0.018002, -2.47349e-5, 5256.844332, 27.377452415) + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def zeta_CO2_Mg_Cl_HM93(T, P): + """n-c-a: carbon-dioxide magnesium chloride [HM93].""" + zeta = HM93_eq(T, -1342.60256, -0.772286, 0.000391603, 27726.80974, 253.62319406) + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def zeta_CO2_H_SO4_HM93(T, P): + """n-c-a: carbon-dioxide hydrogen sulfate [HM93].""" + zeta = 0 + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def zeta_CO2_Na_SO4_HM93(T, P): + """n-c-a: carbon-dioxide sodium sulfate [HM93].""" + zeta = HM93_eq(T, 67030.02482, 37.930519, -0.01894730, -1399082.37, -12630.27457) + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def zeta_CO2_K_SO4_HM93(T, P): + """n-c-a: carbon-dioxide potassium sulfate [HM93].""" + zeta = HM93_eq(T, -2907.03326, -2.860763, 0.001951086, 30756.86749, 611.37560512) + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def zeta_CO2_Mg_SO4_HM93(T, P): + """n-c-a: carbon-dioxide magnesium sulfate [HM93].""" + zeta = HM93_eq(T, -7374.24392, -4.608331, 0.002489207, 143162.6076, 1412.302898) + valid = logical_and(T >= 273.15, T <= 363.15) + return zeta, valid + + +def bC_Na_HCO3_HM93(T, P): + """c-a: sodium bicarbonate [HM93].""" + b0 = HM93_eq(T, -37.2624193, -0.01445932, 0, 682.885977, 6.8995857) + b1 = HM93_eq(T, -61.4635193, -0.02446734, 0, 1129.389146, 11.4108589) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HCO3_HM93(T, P): + """c-a: potassium bicarbonate [HM93].""" + b0 = HM93_eq(T, -0.3088232, 0.001, 0, -0.00069869, -4.701488e-6) + b1 = HM93_eq(T, -0.2802, 0.00109999, 0, 0.000936932, 6.15660566e-6) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_HCO3_HM93(T, P): + """c-a: magnesium bicarbonate [HM93].""" + b0 = HM93_eq(T, 13697.10, 8.250840, -0.00434, -273406.1716, -2607.115202) + b1 = HM93_eq(T, -157839.8351, -92.7779354, 0.0477642, 3203209.6948, 29927.151503) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HCO3_HM93(T, P): + """c-a: calcium bicarbonate [HM93].""" + b0 = HM93_eq(T, 29576.53405, 18.447305, -0.009989, -576520.5185, -5661.1237) + b1 = HM93_eq(T, -1028.8510522, -0.3725876718, 8.9691e-5, 26492.240303, 183.13155672) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_CO3_HM93(T, P): + """c-a: sodium carbonate [HM93].""" + b0 = HM93_eq(T, -60.5387702, -0.023301655, 0, 1108.3760518, 11.19855531) + b1 = HM93_eq(T, -237.5156616, -0.09989121, 0, 4412.511973, 44.5820703) + b2 = 0 + Cphi = 0.0052 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_CO3_HM93(T, P): + """c-a: potassium carbonate [HM93].""" + b0 = HM93_eq(T, -0.1991649, 0.00110, 0, 1.8063362e-5, 0) + b1 = HM93_eq(T, 0.1330579, 0.00436, 0, 0.0011899, 0) + b2 = 0 + Cphi = 0.0005 + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_CO3_HM93(T, P): + """c-a: magnesium carbonate [HM93].""" + b0 = 0 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_CO3_HM93(T, P): + """c-a: calcium carbonate [HM93].""" + b0 = 0 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Hovey et al. (1993) ~~~~~ +def HPR93_eq36(T, a): + """HPR93 equation 36.""" + Tref = 298.15 + return a[0] + a[1] * (1 / T - 1 / Tref) + a[2] * log(T / Tref) + + +def bC_Na_SO4_HPR93(T, P): + """c-a: sodium sulfate [HPR93].""" + b0 = HPR93_eq36( + T, + float_( + [ + 0.006536438, + -30.197349, + -0.20084955, + ] + ), + ) + b1 = HPR93_eq36( + T, + float_( + [ + 0.87426420, + -70.014123, + 0.2962095, + ] + ), + ) + b2 = 0 + Cphi = HPR93_eq36( + T, + float_( + [ + 0.007693706, + 4.5879201, + 0.019471746, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["SO4"]))) + C1 = 0 + alph1 = 1.7 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.0, T <= 373.0) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HSO4_HPR93(T, P): + """c-a: sodium bisulfate, low ionic strengths [HPR93].""" + # Parameters from HPR93 Table 3 for low ionic strengths + b0 = 0.0670967 + b1 = 0.3826401 + b2 = 0 + Cphi = -0.0039056 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["HSO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clegg et al. (1994) ~~~~~ +CRP94_Tr = 328.15 # K + + +def CRP94_eq24(T, q): + return q[0] + 1e-3 * ( + (T - CRP94_Tr) * q[1] + + (T - CRP94_Tr) ** 2 * q[2] / 2 + + (T - CRP94_Tr) ** 3 * q[3] / 6 + ) + + +def bC_H_HSO4_CRP94(T, P): + """c-a: hydrogen bisulfate [CRP94].""" + # Parameters from CRP94 Table 6 + b0 = CRP94_eq24( + T, + float_( + [ + 0.227784933, + -3.78667718, + -0.124645729, + -0.00235747806, + ] + ), + ) + b1 = CRP94_eq24( + T, + float_( + [ + 0.372293409, + 1.50, + 0.207494846, + 0.00448526492, + ] + ), + ) + b2 = 0 + C0 = CRP94_eq24( + T, + float_( + [ + -0.00280032520, + 0.216200279, + 0.0101500824, + 0.000208682230, + ] + ), + ) + C1 = CRP94_eq24( + T, + float_( + [ + -0.025, + 18.1728946, + 0.382383535, + 0.0025, + ] + ), + ) + alph1 = 2 + alph2 = -9 + omega = 2.5 + valid = logical_and(T >= 273.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_SO4_CRP94(T, P): + """c-a: hydrogen sulfate [CRP94].""" + # Evaluate parameters from CRP94 Table 6 + b0 = CRP94_eq24( + T, + float_( + [ + 0.0348925351, + 4.97207803, + 0.317555182, + 0.00822580341, + ] + ), + ) + b1 = CRP94_eq24( + T, + float_( + [ + -1.06641231, + -74.6840429, + -2.26268944, + -0.0352968547, + ] + ), + ) + b2 = 0 + C0 = CRP94_eq24( + T, + float_( + [ + 0.00764778951, + -0.314698817, + -0.0211926525, + -0.000586708222, + ] + ), + ) + C1 = CRP94_eq24( + T, + float_( + [ + 0, + -0.176776695, + -0.731035345, + 0, + ] + ), + ) + alph1 = 2 - 1842.843 * (1 / T - 1 / 298.15) + alph2 = -9 + omega = 2.5 + valid = logical_and(T >= 273.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_HSO4_SO4_CRP94(T, P): + """a-a': bisulfate sulfate [CRP94].""" + theta = 0 + valid = logical_and(T >= 273.15, T <= 328.15) + return theta, valid + + +def psi_H_HSO4_SO4_CRP94(T, P): + """c-a-a': hydrogen bisulfate sulfate [CRP94].""" + psi = 0 + valid = logical_and(T >= 273.15, T <= 328.15) + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pierrot et al. (1997) ~~~~~ +def bC_Na_HSO4_PMR97(T, P): + """c-a: sodium bisulfate [PMR97].""" + b0 = 0.030101 - 0.362e-3 * (T - 298.15) # Eq. (26) + b1 = 0.818686 - 0.019671 * (T - 298.15) # Eq. (27) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def psi_H_Na_Cl_PMR97(T, P): + """c-c'-a: hydrogen sodium chloride [PMR97].""" + psi = 0.0002 + valid = logical_and(T >= 273.15, T <= 323.15) + return psi, valid + + +def psi_H_Na_SO4_PMR97(T, P): + """c-c'-a: hydrogen sodium sulfate [PMR97].""" + psi = 0 + valid = logical_and(T >= 273.15, T <= 323.15) + return psi, valid + + +def psi_H_Na_HSO4_PMR97(T, P): + """c-c'-a: hydrogen sodium bisulfate [PMR97].""" + psi = 0 + valid = logical_and(T >= 273.15, T <= 323.15) + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Millero and Pierrot (1998) ~~~~~ +def MP98_eq15(T, q): + # Note typo in location of first BJ w.r.t. brackets in MP98 vs PM16 model + # Here we use the PM16 model equation + Tr = 298.15 + BR = q[0] + BJ = q[1] * 1e-5 + BLR = q[2] * 1e-4 + return ( + BR + + (BJ * (298.15**3 / 3) - 298.15**2 * BLR) * (1 / T - 1 / 298.15) + + (BJ / 6) * (T**2 - 298.15**2) + ) + + +def bC_Na_I_MP98(T, P): + """c-a: sodium iodide [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.1195, + -1.01, + 8.355, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.3439, + -2.54, + 8.28, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0.0018, + 0, + -0.835, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Br_MP98(T, P): + """c-a: sodium bromide [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.0973, + -1.3, + 7.692, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.2791, + -1.06, + 10.79, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0.00116, + 0.058 * 2**1.5, # more accurate following PM16 model + -0.93, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_F_MP98(T, P): + """c-a: sodium fluoride [MP98].""" + b0 = MP98_eq15( + T, + [ + 0.0215, # typo in MP98 Table A7 vs PM16 code + -2.37, + 5.361, # *1e-4 in MP98 Table A7 presumably a typo vs PM16 code + ], + ) + b1 = MP98_eq15( + T, + [ + 0.2107, + 0, + 8.7, # *1e-4 in MP98 Table A7 presumably a typo vs PM16 code + ], + ) + b2 = 0 + Cphi = MP98_eq15( + T, + [ + 0, + 0, + -0.93, # 0 in MP98 Table A7 presumably a typo vs PM16 code + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["F"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Br_MP98(T, P): + """c-a: potassium bromide [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.0569, + -1.43, + 7.39, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.2122, + -0.762, + 1.74, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.0018, + 0.216, + -0.7004, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_F_MP98(T, P): + """c-a: potassium fluoride [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.08089, + -1.39, + 2.14, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.2021, + 0, + 5.44, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0.00093, + 0, + -0.595, # typo in MP98 table vs PM16 model (latter has -, former +) + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["F"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_OH_MP98(T, P): + """c-a: potassium hydroxide [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.1298, + -0.946, + 9.914, # copy of KI + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.32, + -2.59, + 11.86, # copy of KI + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0.0041, + 0.0638, + -0.944, # copy of KI + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_I_MP98(T, P): + """c-a: potassium iodide [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.0746, + -0.748, + 9.914, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.2517, + -1.8, + 11.86, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.00414, + 0, + -0.944, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_ClO3_MP98(T, P): + """c-a: sodium chlorate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.0249, + -1.56, + 10.35, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.2455, + -2.69, + 19.07, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0.0004, + 0.222, + 9.29, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["ClO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_ClO3_MP98(T, P): + """c-a: potassium chlorate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + -0.096, + 15.1, + 19.87, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.2841, + -27, + 31.8, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0, + -19.1, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["ClO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_ClO4_MP98(T, P): + """c-a: sodium perchlorate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.0554, + -0.611, + 12.96, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.2755, + -6.35, + 22.97, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.00118, + 0.0562, + -1.623, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_BrO3_MP98(T, P): + """c-a: sodium bromate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + -0.0205, + -6.5, + 5.59, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.191, + 5.45, + 34.37, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0.0059, + 2.5, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["BrO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_BrO3_MP98(T, P): + """c-a: potassium bromate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + -0.129, + 9.17, + 5.59, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.2565, + -20.2, + 34.37, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0, + -26.6, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["BrO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_NO3_MP98(T, P): + """c-a: sodium nitrate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.0068, + -2.24, + 12.66, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.1783, + -2.96, + 20.6, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.00072, + 0.594, + -2.316, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_NO3_MP98(T, P): + """c-a: potassium nitrate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + -0.0816, + -0.785, + 2.06, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.0494, + -8.26, + 64.5, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0.0066, + 0, + 3.97, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_NO3_MP98(T, P): + """c-a: magnesium nitrate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.367125, + -1.2322, + 5.15, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 1.58475, + 4.0492, + 44.925, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.020625, + 0, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_NO3_MP98(T, P): + """c-a: calcium nitrate [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.210825, + 4.0248, + 5.295, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 1.40925, + -13.289, + 91.875, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.020142, + -15.435, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Ca"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_Br_MP98(T, P): + """c-a: hydrogen bromide [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.196, + -0.357, + -2.049, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.3564, + -0.913, + 4.467, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + 0.00827, + 0.01272, + -0.5685, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Sr_Cl_MP98(T, P): + """c-a: strontium chloride [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.28575, + -0.18367, + 9.56 * 3 / 4, # from Pierrot_2018_Interaction_Model.xlsm + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 1.66725, + 0, + 37.9 * 3 / 4, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.0013, + 0, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Sr"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_Cl_MP98(T, P): + """c-a: ammonium chloride [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.0522, + -0.597, + 0.779, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.1918, + 0.444, + 12.58, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.00301, + 0.0578, + 0.21, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_Br_MP98(T, P): + """c-a: ammonium bromide [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.0624, + -0.597, + 0.779, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.1947, + 0, + 12.58, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.00436, + 0, + 0.21, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_Br_MP98typo(T, P): + """c-a: ammonium bromide [MP98typo].""" + # PM16 model is missing 1e-5 multiplier on final Cphi term + b0 = MP98_eq15( + T, + float_( + [ + 0.0624, + -0.597, + 0.779, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.1947, + 0, + 12.58, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.00436, + 0, + 0.21 * 1e5, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_NH4_F_MP98(T, P): + """c-a: ammonium fluoride [MP98].""" + b0 = MP98_eq15( + T, + float_( + [ + 0.1306, + 1.09, + 0.95, + ] + ), + ) + b1 = MP98_eq15( + T, + float_( + [ + 0.257, + 0, + 5.97, + ] + ), + ) + b2 = 0 + Cphi = MP98_eq15( + T, + float_( + [ + -0.0043, + 0, + 0, + ] + ), + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["NH4"] * i2c["F"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def MP98_eqTableA3(T, abc): + """MP98 equation for Table A3.""" + Tr = 298.15 + return abc[0] + abc[1] * (T - Tr) + abc[2] * (T - Tr) ** 2 + + +def bC_Na_HSO4_MP98(T, P): + """c-a: sodium bisulfate [MP98].""" + # MP98 cite Pierrot et al. (1997) J Solution Chem 26(1), + # but their equations look quite different, and there is no Cphi there. + # This equation is therefore directly from MP98. + b0 = MP98_eqTableA3( + T, + float_( + [ + 0.0544, # MP98 typo vs PM16 model + -1.8478e-3, + 5.3937e-5, + ] + ), + ) + b1 = MP98_eqTableA3( + T, + float_( + [ + 0.3826401, + -1.8431e-2, + 0, + ] + ), + ) + b2 = 0 + Cphi = -0.0039056 # from PM16 code this should be negative (MP98 typo) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["HSO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_SO3_MP98(T, P): + """c-a: calcium sulfite [MP98].""" + return bC_Ca_SO4_M88(T, P) + + +def bC_Sr_SO4_MP98(T, P): + """c-a: strontium sulfate [MP98].""" + return bC_Ca_SO4_M88(T, P) + + +def bC_Sr_BOH4_MP98(T, P): + """c-a: strontium borate [MP98].""" + return bC_Ca_BOH4_SRM87(T, P) + + +def bC_Ca_HSO3_MP98(T, P): + """c-a: calcium sulfite [MP98].""" + return bC_Ca_HSO4_HMW84(T, P) + + +def bC_Sr_HSO4_MP98(T, P): + """c-a: strontium bisulfate [MP98].""" + return bC_Ca_HSO4_HMW84(T, P) + + +def bC_Sr_HCO3_MP98(T, P): + """c-a: strontium bicarbonate [MP98].""" + return bC_Ca_HCO3_HMW84(T, P) + + +def bC_Sr_HSO3_MP98(T, P): + """c-a: strontium sulfite [MP98].""" + return bC_Ca_HSO3_MP98(T, P) + + +def bC_Sr_OH_MP98(T, P): + """c-a: strontium hydroxide [MP98].""" + return bC_Ca_OH_HMW84(T, P) + + +def theta_Cl_F_MP98(T, P): + """a-a': chloride fluoride [MP98].""" + # MP98 state value is "determined from CB88 data" + theta = 0.01 + valid = T == 298.15 + return theta, valid + + +def psi_Na_Cl_F_MP98(T, P): + """c-a-a': sodium chloride fluoride [MP98].""" + # MP98 state value is "determined from CB88 data" + psi = 0.0023 + valid = T == 298.15 + return psi, valid + + +def theta_CO3_HCO3_MP98(T, P): + """a-a': carbonate bicarbonate [MP98].""" + theta = 0 + valid = logical_and(T >= 273.15, T <= 333.15) + return theta, valid + + +def psi_Na_CO3_HCO3_MP98(T, P): + """c-a-a': sodium carbonate bicarbonate [MP98].""" + psi = 0 + valid = logical_and(T >= 273.15, T <= 333.15) + return psi, valid + + +def psi_K_CO3_HCO3_MP98(T, P): + """c-a-a': potassium carbonate bicarbonate [MP98].""" + psi = 0 + valid = logical_and(T >= 273.15, T <= 333.15) + return psi, valid + + +def psi_Na_BOH4_Cl_MP98(T, P): + """c-a-a': sodium borate chloride [MP98].""" + # MP98 say "determined from OK43 and Hershey et al. (1986b) data" + psi = -0.0132 + valid = logical_and(T >= 273.15, T <= 318.15) + return psi, valid + + +def psi_Mg_BOH4_Cl_MP98(T, P): + """c-a-a': magnesium borate chloride [MP98].""" + # MP98 say "determined from Hershey et al. (1986b) and Simonson et al. + # (1987b) data" + psi = -0.235 + valid = logical_and(T >= 273.15, T <= 318.15) + return psi, valid + + +def psi_Ca_BOH4_Cl_MP98(T, P): + """c-a-a': calcium borate chloride [MP98].""" + # MP98 say "determined from Hershey et al. (1986b) and Simonson et al. + # (1987b) data" + psi = -0.8 + valid = logical_and(T >= 273.15, T <= 318.15) + return psi, valid + + +def theta_Cl_OH_MP98(T, P): + """a-a': chloride hydroxide [MP98].""" + # MP98 say "determined from HO58 data" + theta = -0.05 + (T - 298.15) * 3.125e-4 + (T - 298.15) ** 2 * -8.362e-6 + # MP98 don't give validity range + valid = logical_and(T >= 273.15, T <= 323.15) + return theta, valid + + +def theta_BOH4_Cl_MP98(T, P): + """a-a': borate chloride [MP98].""" + # MP98 say "determined from OK43 and Hershey et al. (1986b) data" + theta = -0.0323 + (T - 298.15) * -0.42333e-4 + (T - 298.15) ** 2 * -21.926e-6 + valid = logical_and(T >= 273.15, T <= 318.15) + return theta, valid + + +def theta_BOH4_Cl_MP98typo(T, P): + """a-a': borate chloride [MP98typo].""" + # This replicates a typo in the Pierrot_2018_Interaction_Model.xlsm code + # (298.25 instead of 298.15 in the T**2 term). + # For proper modelling, should use theta_BOH4_Cl_MP98 instead. + theta = -0.0323 + (T - 298.15) * -0.42333e-4 + (T - 298.25) ** 2 * -21.926e-6 + valid = logical_and(T >= 273.15, T <= 318.15) + return theta, valid + + +def psi_Ca_K_Cl_MP98typo(T, P): + """c-c'-a: calcium potassium chloride [MP98typo].""" + # This replicates a typo in the Pierrot_2018_Interaction_Model.xlsm code + # (in the first term). + # For proper modelling, should use psi_Ca_K_Cl_GM89 instead. + psi = 0.047627877 - 27.0770507 / T + valid = logical_and(T >= 273.15, T <= 523.15) + return psi, valid + + +def bC_Mg_HCO3_MP98(T, P): + """c-a: magnesium bicarbonate [MP98].""" + # MP98 say "re-determined from TM82." + b0 = 0.03 + b1 = 0.8 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def MP98_eqTableA9_2(T, a): + """MP98 equation (2) from Table A9.""" + return a[0] + (T - 328.15) * 1e-3 * ( + a[1] + (T - 328.15) * (a[2] / 2 + (T - 328.15) * a[3] / 6) + ) + + +def bC_H_SO4_MP98(T, P): + """c-a: hydrogen sulfate [MP98].""" + # MP98 cite Pierrot et al. (1998, submitted), but that doesn't appear to + # have been published, so these values are directly from MP98 Table A9 + # (with noted typo corrections). + b0 = MP98_eqTableA9_2( + T, + [ + 0.0065, # typo in MP98 table (vs 2016 VB model) + 0.134945, + 0.022374, + 7.2e-5, + ], + ) + b1 = MP98_eqTableA9_2( + T, + [ + -0.15009, # typo in MP98 table (vs 2016 VB model) + -2.405945, + 0.335839, + -0.004379, + ], + ) + b2 = 0 + C0 = MP98_eqTableA9_2( + T, + [ + 0.008073, + -0.113106, + -0.003553, + 3.57e-5, + ], + ) + C1 = MP98_eqTableA9_2( + T, + [ + -0.050799, + 3.472545, + -0.311463, + 0.004037, + ], + ) + alph1 = 2 + alph2 = -9 + omega = 2.5 + valid = logical_and(T >= 273.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_HSO4_MP98(T, P): + """c-a: hydrogen bisulfate [MP98].""" + # MP98 cite Pierrot et al. (1998, submitted), but that doesn't appear to + # have been published, so these values are directly from the MP98 VB model. + # HOWEVER, this interaction is mysteriously commented out in that model... + b0 = MP98_eqTableA9_2( + T, + [ + 0.239786, + -1.209539, + -0.004345, + 0.000185, + ], + ) + b1 = MP98_eqTableA9_2( + T, + [ + 0.352843, + 0.087537, + 0.038379, + -0.000744, + ], + ) + b2 = 0 + C0 = MP98_eqTableA9_2( + T, + [ + -0.003234, + 0.045792, + 0.000793, + -0.0000222, + ], + ) + C1 = MP98_eqTableA9_2( + T, + [ + -0.098973, + 3.127618, + -0.020184, + -0.000316, + ], + ) + alph1 = 2 + alph2 = -9 + omega = 2.5 + valid = logical_and(T >= 273.15, T <= 523.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_HSO4_SO4_MP98(T, P): + """a-a': bisulfate sulfate [MP98].""" + # MP98 cite Pierrot et al. (1998, submitted), but that doesn't appear to + # have been published, so these values are directly from MP98. + theta = 0 + valid = logical_and(T >= 273.15, T <= 473.15) + return theta, valid + + +def psi_Na_HSO4_SO4_MP98(T, P): + """c-a-a': sodium bisulfate sulfate [MP98].""" + # MP98 cite Pierrot et al. (1998, submitted), but that doesn't appear to + # have been published, so these values are directly from MP98. + psi = 0 + valid = logical_and(T >= 273.15, T <= 473.15) + return psi, valid + + +def theta_Na_Sr_MP98(T, P): + """c-c': sodium strontium [MP98].""" + # MP98 cite PK74 but I can't find this value in there + theta = 0.07 + valid = T == 298.15 + return theta, valid + + +def theta_K_Sr_MP98(T, P): + """c-c': potassium strontium [MP98].""" + # MP98 say this is set equal to the sodium value (i.e. theta_Na_Sr_MP98?) + # but then state a different number (0.01)... 0.07 is used in the program + # Pierrot_2018_Interaction_Model.xlsm + theta = 0.07 + valid = T == 298.15 + return theta, valid + + +def psi_H_Sr_Cl_MP98(T, P): + """c-c'-a: hydrogen strontium chloride [MP98].""" + # MP98 cite M85 book but can't find it there so this is from MP98 Table A10 + psi = 0.0054 - 2.1e-4 * (T - 298.15) + valid = logical_and(T >= 273.15, T <= 323.15) + return psi, valid + + +def psi_Na_Sr_Cl_MP98(T, P): + """c-c'-a: sodium strontium chloride [MP98].""" + # MP98 cite PK74 but I can't find this value in there + psi = -0.015 + valid = T == 298.15 + return psi, valid + + +def psi_K_Sr_Cl_MP98(T, P): + """c-c'-a: potassium strontium chloride [MP98].""" + return psi_Na_Sr_Cl_MP98(T, P) + + +def psi_H_K_Br_MP98(T, P): + """c-c'-a: hydrogen potassium bromide [MP98].""" + # MP98 cite HMW84 but I can't find this value in there + psi = -0.021 + valid = T == 298.15 + return psi, valid + + +def psi_H_Mg_Br_MP98(T, P): + """c-c'-a: hydrogen magnesium bromide [MP98].""" + # MP98 cite PK74 but I can't find this value in there + psi = -0.005 + valid = T == 298.15 + return psi, valid + + +def psi_K_Cl_H2PO4_MP98(T, P): + """c-a-a': potassium chloride dihydrogen-phosphate [MP98].""" + # MP98 cite Pitzer & Silvester (1976) but I can't find that paper + psi = -0.0105 + valid = T == 298.15 + return psi, valid + + +def lambd_HF_Cl_MP98(T, P): + """n-a: hydrogen-fluoride chloride [MP98].""" + # MP98 Table A12 says this is derived "from CB88 data" + lambd = 0 + valid = T == 298.15 + return lambd, valid + + +def lambd_HF_Na_MP98(T, P): + """n-c: hydrogen-fluoride sodium [MP98].""" + # MP98 Table A12 says this is derived "from CB88 data" + lambd = 0.011 + valid = T == 298.15 + return lambd, valid + + +def zeta_H3PO4_Na_Cl_MP98(T, P): + """phosphoric-acid sodium chloride [MP98].""" + # MP98 say this comes from PS76 but there's no sodium in there + zeta = 0 + valid = T == 298.15 + return zeta, valid + + +def theta_H_K_MP98(T, P): + """c-c': hydrogen potassium [MP98].""" + # Direct from Pierrot_2018_Interaction_Model.xlsm, conflicts with CMR93 + theta = 0.005 - 0.0002275 * (T - 298.15) + valid = logical_and(T >= 273.15, T <= 328.15) + return theta, valid + + +def theta_H_Na_MP98(T, P): + """c-c': hydrogen sodium [MP98].""" + # Direct from Pierrot_2018_Interaction_Model.xlsm, conflicts with CMR93 + theta = 0.03416 - 0.000209 * (T - Tzero) + valid = logical_and(T >= 273.15, T <= 328.15) + return theta, valid + + +def bC_K_CO3_MP98(T, P): + """c-a: potassium carbonate [MP98].""" + # Direct from Pierrot_2018_Interaction_Model.xlsm, conflicts with SRG87 + b0 = 0.1288 + 1.1e-3 * (T - 298.15) - 5.1e-6 * (T - 298.15) ** 2 + b1 = 1.433 + 4.36e-3 * (T - 298.15) + 2.07e-5 * (T - 298.15) ** 2 + b2 = 0 + Cphi = 0.0005 # not in SRG87! + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 368.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_H_Mg_MP98(T, P): + """c-c': hydrogen magnesium [MP98].""" + # RGB80 has no temperature term, as declared by MP98 + theta = 0.0620 + 0.0003275 * (T - 298.15) + valid = T == 298.15 + return theta, valid + + +def psi_H_Mg_Cl_MP98(T, P): + """c-c': hydrogen magnesium chloride [MP98].""" + # RGB80 has no temperature term, as declared by MP98 + theta = 0.001 - 0.0007325 * (T - 298.15) + valid = T == 298.15 + return theta, valid + + +def theta_Ca_H_MP98(T, P): + """c-c': calcium hydrogen [MP98].""" + # MP98 have really messed this one up? (see notes on theta_Ca_H_RGO81) + theta = 0.0612 + 0.0003275 * (T - 298.15) + valid = T == 298.15 + return theta, valid + + +def psi_Ca_H_Cl_MP98(T, P): + """c-c': calcium hydrogen chloride [MP98].""" + # RGO81 has no temperature term, as declared by MP98 + theta = 0.0008 - 0.000725 * (T - 298.15) + valid = T == 298.15 + return theta, valid + + +def psi_K_Cl_SO4_MP98(T, P): + """c-a-a': potassium chloride sulfate [MP98].""" + # MP98 say this is GM89 but don't use full precision for the first + # constant in the PM program + psi = GM89_eq3( + T, + float_( + [ + -2.12481e-1, + 2.84698333e-4, + 3.75619614e1, + 0, + 0, + 0, + 0, + 0, + ] + ), + ) + valid = logical_and(T >= 273.15, T <= 523.15) + return psi, valid + + +def bC_Na_CO3_MP98(T, P): + """c-a: sodium carbonate [MP98].""" + # I have no idea where MP98 got their T**2 terms from + b0 = 0.0362 + 0.00179 * (T - 298.15) + 1.694e-21 * (T - 298.15) ** 2 + b1 = 1.51 + 0.00205 * (T - 298.15) + 1.626e-19 * (T - 298.15) ** 2 + b2 = 0 + Cphi = 0.0052 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HCO3_MP98(T, P): + """c-a: sodium bicarbonate [MP98].""" + # I have no idea where MP98 got their T**2 terms from + b0 = 0.028 + 0.001 * (T - 298.15) + 5.082001e-21 * (T - 298.15) ** 2 + b1 = 0.044 + 0.0011 * (T - 298.15) - 3.88e-21 * (T - 298.15) ** 2 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 273.15, T <= 323.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HSO4_MP98(T, P): + """c-a: potassium bisulfate [MP98].""" + # MP98 cite Pierrot & Millero (1997) in the PM16 code for this + b0 = -1.8949 - 0.00059751 * (T - 298.15) + b1 = 5.0284 - 0.0284 * (T - 298.15) + b2 = 0.0 + Cphi = 0.9246 + 0.0039751 * (T - 298.15) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["HSO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_HSO4_MP98(T, P): + """c-a: magnesium bisulfate [MP98].""" + # MP98 cite Pierrot & Millero (1997) in the PM16 code for this + b0 = -0.61656 - 0.00075174 * (T - 298.15) + b1 = 7.716066 - 0.0164302 * (T - 298.15) + b2 = 0.0 + Cphi = 0.43026 + 0.00199601 * (T - 298.15) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Mg"] * i2c["HSO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_BOH4_MP98(T, P): + """c-a: potassium borate [MP98].""" + # MP98 say this is SRRJ87 but then use different coefficients for Cphi + b0 = SRRJ87_eq7( + T, + [ + 0.1469, + 2.881, + 0, + ], + ) + b1 = SRRJ87_eq7( + T, + [ + -0.0989, + -6.876, + 0, + ], + ) + b2 = 0 + Cphi = SRRJ87_eq7( + T, + [ + -56.43e-3, + -0.956, + 0, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["BOH4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_BOH4_MP98(T, P): + """c-a: sodium borate [MP98].""" + # MP98 say this is SRRJ87 but then use different coefficients for Cphi + b0 = SRRJ87_eq7( + T, + [ + -0.0510, + 5.264, + 0, + ], + ) + b1 = SRRJ87_eq7( + T, + [ + 0.0961, + -10.68, + 0, + ], + ) + b2 = 0 + Cphi = SRRJ87_eq7( + T, + [ + 14.98e-3, + -1.57, + 0, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["BOH4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 278.15, T <= 328.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Archer (1999) ~~~~~ +def A99_eq22(T, a): + """A99 equation 22.""" + Tref = 298.15 + return ( + a[0] + + a[1] * (T - Tref) * 1e-2 + + a[2] * (T - Tref) ** 2 * 1e-5 + + a[3] * 1e2 / (T - 225) + + a[4] * 1e3 / T + + a[5] * 1e6 / (T - 225) ** 3 + ) + + +def bC_K_Cl_A99(T, P): + """c-a: potassium chloride [A99].""" + # KCl T parameters from A99 Table 4 + b0 = A99_eq22( + T, + [ + 0.413229483398493, + -0.0870121476114027, + 0.101413736179231, + -0.0199822538522801, + -0.0998120581680816, + 0, + ], + ) + b1 = A99_eq22( + T, + [ + 0.206691413598171, + 0.102544606022162, + 0, + 0, + 0, + -0.00188349608000903, + ], + ) + b2 = 0 + C0 = A99_eq22( + T, + [ + -0.00133515934994478, + 0, + 0, + 0.00234117693834228, + -0.00075896583546707, + 0, + ], + ) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = logical_and(T >= 260, T <= 420) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rard and Clegg (1999) ~~~~~ +def bC_Mg_HSO4_RC99(T, P): + """c-a: magnesium bisulfate [RC99].""" + # RC99 Table 6, left column + b0 = 0.40692 + b1 = 1.6466 + b2 = 0 + C0 = 0.024293 + C1 = -0.127194 + alph1 = 2 + alph2 = -9 + omega = 1 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def psi_H_Mg_HSO4_RC99(T, P): + """c-c'-a: hydrogen magnesium bisulfate [RC99].""" + # RC99 Table 6, left column + psi = -0.027079 + valid = T == 298.15 + return psi, valid + + +def psi_H_Mg_SO4_RC99(T, P): + """c-c'-a: hydrogen magnesium sulfate [RC99].""" + # RC99 Table 6, left column + psi = -0.047368 + valid = T == 298.15 + return psi, valid + + +def psi_Mg_HSO4_SO4_RC99(T, P): + """c-a-a': magnesium bisulfate sulfate [RC99].""" + # RC99 Table 6, left column + psi = -0.078418 + valid = T == 298.15 + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Miladinović et al. (2008) ~~~~~ +def bC_Mg_Cl_MNTR08(T, P): + """c-a: magnesium chloride [MNTR08].""" + b0 = 0.68723 + b1 = 1.56760 + b2 = 0 + C0 = -0.0007594 + C1 = -0.35497 + alph1 = 3.0 + alph2 = -9 + omega = 1.0 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_SO4_MNTR08(T, P): + """c-a: magnesium sulfate [MNTR08].""" + b0 = -0.03089 + b1 = 3.7687 + b2 = -37.3659 + C0 = 0.016406 + C1 = 0.34549 + alph1 = 1.4 + alph2 = 12.0 + omega = 1.0 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_Cl_SO4_MNTR08( + T, +): + """a-a': chloride sulfate [MNTR08].""" + theta = -0.07122 + valid = T == 298.15 + return theta, valid + + +def psi_Mg_Cl_SO4_MNTR08( + T, +): + """c-a-a': magnesium chloride sulfate [MNTR08].""" + psi = -0.038505 + valid = T == 298.15 + return psi, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Waters and Millero (2013) ~~~~~ +# Some are functions that WM13 declared came from another source, but I +# couldn't find them there, so copied directly from WM13 instead. +# Others were just declared by WM13 as zero. These all seem to agree with +# HMW84; it's unclear why HMW84 wasn't cited by WM13 for these. +# First, a few functions that WM13 constructed by taking 298.15 K parameters +# from HMW84, and correcting for temperature using derivatives from P91. + + +def bC_Ca_SO4_WM13(T, P): + """c-a: calcium sulfate [WM13].""" + TR = 298.15 + b0, b1, b2, C0, C1, alph1, alph2, omega, valid = bC_Ca_SO4_HMW84(T, P) + # WM13 use temperature derivatives from P91 + # The b0 temperature correction in P91 is zero + b1 = b1 + (T - TR) * 5.460e-2 + b2 = b2 + (T - TR) * -5.16e-1 + # The C0 temperature correction in P91 is zero + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HSO4_WM13(T, P): + """c-a: calcium bisulfate [WM13].""" + TR = 298.15 + b0, b1, b2, C0, C1, alph1, alph2, omega, valid = bC_Ca_HSO4_HMW84(T, P) + # WM13 use temperature derivatives for Ca-ClO4 from P91, but with typos + b0 = b0 + (T - TR) * 0.830e-3 + b1 = b1 + (T - TR) * 5.08e-3 + C0 = C0 + (T - TR) * -1.090e-4 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HSO4_WM13(T, P): + """c-a: potassium bisulfate [WM13].""" + TR = 298.15 + b0, b1, b2, C0, C1, alph1, alph2, omega, valid = bC_K_HSO4_HMW84(T, P) + # WM13 use temperature derivatives for K-ClO4 from P91 + b0 = b0 + (T - TR) * 0.600e-4 + b1 = b1 + (T - TR) * 100.700e-4 + # The Cphi temperature correction in P91 is zero + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_HSO4_HPR93viaWM13(T, P): + """c-a: sodium sulfate [HPR93 via WM13].""" + # WM13 Table A1 - can't find where HPR93 state this + return bC_none(T, P) + + +def theta_HSO4_SO4_WM13(T, P): + """a-a': bisulfate sulfate [WM13].""" + return theta_none(T, P) # WM13 Table A7 + + +def psi_H_Cl_SO4_WM13(T, P): + """c-a-a': hydrogen chloride sulfate [WM13].""" + return psi_none(T, P) # WM13 Table A8 + + +def psi_H_Cl_OH_WM13(T, P): + """c-a-a': hydrogen chloride hydroxide [WM13].""" + return psi_none(T, P) # WM13 Table A8 + + +def psi_Mg_Cl_OH_WM13(T, P): + """c-a-a': magnesium chloride hydroxide [WM13].""" + return psi_none(T, P) # WM13 Table A8 + + +def psi_Ca_HSO4_SO4_WM13(T, P): + """c-a-a': calcium bisulfate sulfate [WM13].""" + return psi_none(T, P) # WM13 Table A8 + + +def psi_H_OH_SO4_WM13(T, P): + """c-a-a': hydrogen hydroxide sulfate [WM13].""" + return psi_none(T, P) # WM13 Table A8 + + +def psi_Mg_OH_SO4_WM13(T, P): + """c-a-a': magnesium hydroxide sulfate [WM13].""" + return psi_none(T, P) # WM13 Table A8 + + +def psi_Ca_OH_SO4_WM13(T, P): + """c-a-a': calcium hydroxide sulfate [WM13].""" + return psi_none(T, P) # WM13 Table A8 + + +def psi_H_Na_SO4_WM13(T, P): + """c-c'-a: hydrogen sodium sulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_Ca_H_SO4_WM13(T, P): + """c-c'-a: calcium hydrogen sulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_Ca_H_HSO4_WM13(T, P): + """c-c'-a: calcium hydrogen bisulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_Mg_Na_HSO4_WM13(T, P): + """c-c'-a: magnesium sodium bisulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_Ca_Na_HSO4_WM13(T, P): + """c-c'-a: calcium sodium bisulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_K_Na_HSO4_WM13(T, P): + """c-c'-a: potassium sodium bisulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_Ca_Mg_HSO4_WM13(T, P): + """c-c'-a: calcium magnesium bisulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_K_Mg_HSO4_WM13(T, P): + """c-c'-a: potassium magnesium bisulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_Ca_K_SO4_WM13(T, P): + """c-c'-a: calcium potassium sulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +def psi_Ca_K_HSO4_WM13(T, P): + """c-c'-a: calcium potassium bisulfate [WM13].""" + return psi_none(T, P) # WM13 Table A9 + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Gallego-Urrea and Turner (2017) ~~~~~ +# From G17 Supp. Info. Table S6, 'simultaneous optimisation'. +def bC_Na_Cl_GT17simopt(T, P): + """c-a: sodium chloride [GT17simopt].""" + b0 = 0.07722 + b1 = 0.26768 + b2 = 0 + Cphi = 0.001628 + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_trisH_Cl_GT17simopt(T, P): + """c-a: trisH+ chloride [GT17simopt].""" + b0 = 0.04181 + b1 = 0.16024 + b2 = 0 + Cphi = -0.00132 + C0 = Cphi / (2 * sqrt(np_abs(i2c["trisH"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_trisH_SO4_GT17simopt(T, P): + """c-a: trisH+ sulfate [GT17simopt].""" + b0 = 0.09746 + b1 = 0.52936 + b2 = 0 + Cphi = -0.004957 + C0 = Cphi / (2 * sqrt(np_abs(i2c["trisH"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_H_trisH_GT17simopt(T, P): + """c-c': hydrogen trisH [GT17simopt].""" + theta = -0.00575 + valid = T == 298.15 + return theta, valid + + +def psi_H_trisH_Cl_GT17simopt(T, P): + """c-c'-a: hydrogen trisH chloride [GT17simopt].""" + psi = -0.00700 + valid = T == 298.15 + return psi, valid + + +def lambd_tris_trisH_GT17simopt(T, P): + """n-c: tris trisH [GT17simopt].""" + lambd = 0.06306 + valid = T == 298.15 + return lambd, valid + + +def lambd_tris_Na_GT17simopt(T, P): + """n-c: tris sodium [GT17simopt].""" + lambd = 0.01580 + valid = T == 298.15 + return lambd, valid + + +def lambd_tris_K_GT17simopt(T, P): + """n-c: tris potassium [GT17simopt].""" + lambd = 0.02895 + valid = T == 298.15 + return lambd, valid + + +def lambd_tris_Mg_GT17simopt(T, P): + """n-c: tris magnesium [GT17simopt].""" + lambd = -0.14505 + valid = T == 298.15 + return lambd, valid + + +def lambd_tris_Ca_GT17simopt(T, P): + """n-c: tris calcium [GT17simopt].""" + lambd = -0.31081 + valid = T == 298.15 + return lambd, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Zezin and Driesner (2017) ~~~~~ +def ZD17_eq8(T, P, b): + """ZD17 equation 8, pressure in MPa.""" + return ( + b[0] + + b[1] * T / 1000 + + b[2] * (T / 500) ** 2 + + b[3] / (T - 215) + + b[4] * 1e4 / (T - 215) ** 3 + + b[5] * 1e2 / (T - 215) ** 2 + + b[6] * 2e2 / T**2 + + b[7] * (T / 500) ** 3 + + b[8] / (650 - T) ** 0.5 + + b[9] * 1e-5 * P + + b[10] * 2e-4 * P / (T - 225) + + b[11] * 1e2 * P / (650 - T) ** 3 + + b[12] * 1e-5 * P * T / 500 + + b[13] * 2e-4 * P / (650 - T) + + b[14] * 1e-7 * P**2 + + b[15] * 2e-6 * P**2 / (T - 225) + + b[16] * P**2 / (650 - T) ** 3 + + b[17] * 1e-7 * P**2 * T / 500 + + b[18] * 1e-7 * P**2 * (T / 500) ** 2 + + b[19] * 4e-2 * P / (T - 225) ** 2 + + b[20] * 1e-5 * P * (T / 500) ** 2 + + b[21] * 2e-8 * P**3 / (T - 225) + + b[22] * 1e-2 * P**3 / (650 - T) ** 3 + + b[23] * 2e2 / (650 - T) ** 3 + ) + + +def bC_K_Cl_ZD17(T, P): + """c-a: potassium chloride [ZD17].""" + P_MPa = P / 100 # Convert dbar to MPa + # KCl T and P parameters from ZD17 Table 2 + b0 = ZD17_eq8( + T, + P_MPa, + [ + 0.0263285, + 0.0713524, + -0.008957, + -1.3320169, + -0.6454779, + -0.758977, + 9.4585163, + -0.0186077, + 0.211171, + 0, + 22.686075, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + ) + b1 = ZD17_eq8( + T, + P_MPa, + [ + -0.1191678, + 0.7216226, + 0, + 8.5388026, + 4.3794936, + -11.743658, + -25.744757, + -0.1638556, + 3.444429, + 0, + 0.7549375, + -7.2651892, + 0, + 0, + 0, + 0, + 4.0457998, + 0, + 0, + -162.81428, + 296.7078, + 0, + -0.7343191, + 46.340392, + ], + ) + b2 = 0 + C0 = ZD17_eq8( + T, + P_MPa, + [ + -0.0005981, + 0.002905, + -0.0028921, + -0.1711606, + 0.0479309, + 0.141835, + 0, + 0.0009746, + 0.0084333, + 0, + 10.518644, + 0, + 1.1917209, + -9.3262105, + 0, + 0, + 0, + 0, + 0, + -5.4129002, + 0, + 0, + 0, + 0, + ], + ) + C1 = ZD17_eq8( + T, + P_MPa, + [ + 0, + 1.0025605, + 0, + 0, + 3.0805818, + 0, + -86.99429, + -0.3005514, + 0, + -47.235583, + -901.18412, + -2.326187, + 0, + -504.46628, + 0, + 0, + -4.7090241, + 0, + 0, + 542.1083, + 0, + 0, + 1.6548655, + 59.165704, + ], + ) + alph1 = 2 + alph2 = -9 + omega = 2.5 + valid = T <= 600 + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MarChemSpec project ~~~~~ +def theta_Ca_H_MarChemSpec(T, P): + """c-c': calcium hydrogen [MarChemSpec].""" + # 1. WM13 cite the wrong reference for this (they say RXX80) + # 2. The equation given by WM13 doesn't match RGO81 + # 3. RGO81 give a 25degC value but no temperature parameter + # So MarChemSpec uses RGO81's 25degC value plus the WM13 temperature cxn + thetar = theta_Ca_H_RGO81(T, P)[0] + theta = thetar + 3.275e-4 * (T - 298.15) + valid = logical_and(T >= 273.15, T <= 323.15) + return theta, valid + + +def theta_H_Na_MarChemSpec25(T, P): + """c-c': hydrogen sodium [MarChemSpec].""" + theta = 0.036 + valid = T == 298.15 + return theta, valid + + +def theta_H_K_MarChemSpec25(T, P): + """c-c': hydrogen potassium [MarChemSpec].""" + theta = 0.005 + valid = T == 298.15 + return theta, valid + + +def lambd_tris_tris_MarChemSpec25(T, P): + """n-n: tris tris [MarChemSpec].""" + # Temporary value from "MODEL PARAMETERS FOR TRIS Tests.docx" (2019-01-31) + lambd = -0.006392 + valid = T == 298.15 + return lambd, valid + + +def zeta_tris_Na_Cl_MarChemSpec25(T, P): + """n-c-a: tris sodium chloride [MarChemSpec].""" + # Temporary value from "MODEL PARAMETERS FOR TRIS Tests.docx" (2019-01-31) + zeta = -0.003231 + valid = T == 298.15 + return zeta, valid + + +def mu_tris_tris_tris_MarChemSpec25(T, P): + """n-n-n: tris tris tris [MarChemSpec].""" + # Temporary value from "MODEL PARAMETERS FOR TRIS Tests.docx" (2019-01-31) + mu = 0.0009529 + valid = T == 298.15 + return mu, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JESS ~~~~~ +# Ref. JESS = parameters obtained from http://jess.murdoch.edu.au/vewbel.shtml +def JESS_eq(T, P, j): + Tr = 298.15 + Pr = 10 + return ( + j[0] + + j[1] * (1 / T - 1 / Tr) * 1e3 + + j[2] * log(T / Tr) + + j[3] * (P - Pr) * 0.0001 + ) + + +def bC_H_Br_JESS(T, P): + """c-a: hydrogen bromide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.210904, + -0.0111577, + -0.0965749, + -0.00485161, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.324833, + -0.141250, + -0.287944, + -0.0209720, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.00113432, + -0.0110028, + -0.0542243, + 0.000704627, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_Cl_JESS(T, P): + """c-a: hydrogen chloride [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.178627, + 0.209336, + 0.580887, + 0.000743741, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.288278, + -0.757685, + -2.38033, + -0.00662854, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.000259560, + -0.0628809, + -0.219810, + 1.46066e-5, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_ClO4_JESS(T, P): + """c-a: hydrogen perchlorate [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.177990, + -0.126144, + -0.278470, + -0.000346259, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.282791, + -0.469348, + -0.990997, + -0.0550796, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.00754498, + 0.0103387, + 0.000000, + -0.00157682, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_I_JESS(T, P): + """c-a: hydrogen iodide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.231988, + -0.138301, + -0.470802, + -0.0212351, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.419989, + -0.344954, + -0.859537, + 0.0477403, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.00286688, + 0.00703988, + 0.000000, + 0.00346557, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_NO3_JESS(T, P): + """c-a: hydrogen nitrate [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.116523, + -0.0848453, + -0.216476, + -0.0109287, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.351089, + -0.830710, + -2.43129, + 0.0206574, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.00531372, + -0.0289539, + -0.123911, + 0.00299856, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["H"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Br_JESS(T, P): + """c-a: potassium bromide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.0547434, + -0.420409, + -1.13677, + 0.00766319, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.238709, + -0.160445, + -0.235802, + 0.0172136, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.00145317, + 0.0658735, + 0.185412, + -0.000339080, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_Cl_JESS(T, P): + """c-a: potassium chloride [JESS].""" + # Coefficients obtained online [2019-08-08] + b0 = JESS_eq( + T, + P, + [ + 0.0478024, + -0.359514, + -1.00809, + 0.0104416, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.220310, + -0.158289, + -0.228114, + 0.0198966, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.000751880, + 0.0516663, + 0.149612, + -0.000853398, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_I_JESS(T, P): + """c-a: potassium iodide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.0706420, + -0.176246, + -0.291178, + 0.0103160, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.279022, + -1.11921, + -3.31506, + -0.0125590, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.00335865, + 0.000000, + -0.0301254, + -0.00160355, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_NO3_JESS(T, P): + """c-a: potassium nitrate [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + -0.0763632, + -0.582629, + -1.49134, + -0.000422651, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.0435708, + -1.90996, + -4.95256, + 0.0795007, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.00526553, + 0.101479, + 0.274296, + 0.00254839, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_OH_JESS(T, P): + """c-a: potassium hydroxide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.153478, + -0.519124, + -1.69587, + 0.0274921, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.184252, + 0.107673, + 0.539154, + 0.000813086, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.000479227, + 0.0899943, + 0.295729, + -0.00264638, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["K"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_Br_JESS(T, P): + """c-a: lithium bromide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.173865, + 0.174090, + 0.523963, + 0.00576938, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.287573, + -0.908258, + -2.72816, + -0.0110614, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.00505045, + -0.0474007, + -0.165446, + -0.00114107, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_Cl_JESS(T, P): + """c-a: lithium chloride [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.148491, + 0.0993795, + 0.288338, + 0.00616159, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.305863, + -0.534953, + -1.57812, + 0.00327985, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.00363693, + -0.0309516, + -0.118649, + -0.000747312, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_ClO4_JESS(T, P): + """c-a: lithium perchlorate [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.194332, + 0.0519232, + 0.179439, + -0.000735779, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.435514, + -0.694923, + -2.09437, + 0.00524685, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.00160986, + -0.0229881, + -0.0977900, + 0.000703517, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_I_JESS(T, P): + """c-a: lithium iodide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.176338, + 0.000000, + -0.129076, + -0.00291167, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.523319, + 0.0858259, + 0.810061, + -0.000530723, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.0109604, + -0.0457470, + -0.125706, + 0.000223867, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_NO3_JESS(T, P): + """c-a: lithium nitrate [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.140963, + -0.285745, + -0.959602, + -0.00269645, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.286879, + 0.763311, + 2.87993, + 0.0225144, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.00543304, + 0.00233974, + 0.000000, + 0.000892616, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Li_OH_JESS(T, P): + """c-a: lithium hydroxide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.0544861, + -0.245358, + -0.865967, + 0.00588145, + ], + ) + b1 = JESS_eq( + T, + P, + [ + -0.139320, + -0.725360, + -2.44668, + 0.0583334, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.00433424, + 0.0208725, + 0.0579693, + 0.00152371, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Li"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Br_JESS(T, P): + """c-a: sodium bromide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.0987329, + -0.428710, + -1.19150, + 0.00937076, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.285551, + -0.452514, + -1.24784, + 0.000698698, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.000736067, + 0.0467849, + 0.124757, + -0.00113162, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Br"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_Cl_JESS(T, P): + """c-a: sodium chloride [JESS].""" + # Coefficients obtained online [2019-08-08] + b0 = JESS_eq( + T, + P, + [ + 0.0779802, + -0.429500, + -1.21510, + 0.0108697, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.269983, + -0.379473, + -1.03405, + 0.00877337, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.000918109, + 0.0518882, + 0.139812, + -0.000952450, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_ClO4_JESS(T, P): + """c-a: sodium perchlorate [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.0557192, + -0.519285, + -1.35911, + 0.00925914, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.280349, + -1.02206, + -2.73189, + 0.0158837, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.00126494, + 0.0944381, + 0.269364, + -0.000962511, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["ClO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_I_JESS(T, P): + """c-a: sodium iodide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.124139, + -0.149852, + -0.225275, + 0.00691965, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.317353, + -1.47625, + -4.67803, + -0.0109580, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.000609691, + -0.0485681, + -0.197132, + -0.000968575, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["I"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_NO3_JESS(T, P): + """c-a: sodium nitrate [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.00500042, + -0.708908, + -1.99654, + 0.00501474, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.200360, + -0.879277, + -2.23652, + 0.0625764, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + -0.000347888, + 0.153367, + 0.461828, + 0.000540176, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["NO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_OH_JESS(T, P): + """c-a: sodium hydroxide [JESS].""" + # Coefficients obtained online [2019-08-09] + b0 = JESS_eq( + T, + P, + [ + 0.0857078, + -0.618667, + -1.90371, + 0.0278606, + ], + ) + b1 = JESS_eq( + T, + P, + [ + 0.276706, + -0.443782, + -1.30232, + 0.0242386, + ], + ) + b2 = 0 + Cphi = JESS_eq( + T, + P, + [ + 0.00418666, + 0.0982562, + 0.285252, + -0.00224765, + ], + ) + C0 = Cphi / (2 * sqrt(np_abs(i2c["Na"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = T == 298.15 # unknown validity + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +# def bC___JESS(T, P): +# """c-a: [JESS].""" +# # Coefficients obtained online [2019-08-08] +# b0 = JESS_eq(T, P, [ +# , +# , +# , +# , +# ]) +# b1 = JESS_eq(T, P, [ +# , +# , +# , +# , +# ]) +# b2 = 0 +# Cphi = JESS_eq(T, P, [ +# , +# , +# , +# , +# ]) +# C0 = Cphi/(2*sqrt(np_abs(i2c['']*i2c['']))) +# C1 = 0 +# alph1 = 2 +# alph2 = -9 +# omega = -9 +# valid = T == 298.15 # unknown validity +# return b0, b1, b2, C0, C1, alph1, alph2, omega, valid diff --git a/pytzer4/plot.py b/pytzer4/plot.py new file mode 100644 index 00000000..7e5892e0 --- /dev/null +++ b/pytzer4/plot.py @@ -0,0 +1,92 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Visualise different parameter sets and calculations.""" +from autograd.numpy import array, full, full_like, linspace, nan, sqrt +from autograd.numpy import min as np_min +from autograd.numpy import max as np_max +from . import libraries, meta, model, properties + + +def _bC_plot(ax, xtype, tots, mols, ele, ions, tempK, pres, prmlib_base, varout): + ifuncs = meta.getifuncs("bC", ions) + fvar = full((len(ifuncs), len(tempK)), nan) + fvarfuncs = { + "acf_anion": ( + lambda mols, ions, tempK, pres, prmlib: model.acfs( + mols, ions, tempK, pres, prmlib=prmlib + )[1], + "{} activity coefficient in {}".format(ions[1], ele), + ), + "act_anion": ( + lambda mols, ions, tempK, pres, prmlib: mols[1] + * model.acfs(mols, ions, tempK, pres, prmlib=prmlib)[1], + "{} activity in {}".format(ions[1], ele), + ), + "acf_cation": ( + lambda mols, ions, tempK, pres, prmlib: model.acfs( + mols, ions, tempK, pres, prmlib=prmlib + )[0], + "{} activity coefficient in {}".format(ions[0], ele), + ), + "act_cation": ( + lambda mols, ions, tempK, pres, prmlib: mols[0] + * model.acfs(mols, ions, tempK, pres, prmlib=prmlib)[0], + "{} activity in {}".format(ions[0], ele), + ), + "aw": (model.aw, "Water activity in {}".format(ele)), + "osm": (model.osm, "Osmotic coefficient in {}".format(ele)), + } + for i, ifunc in enumerate(ifuncs): + prmlib_base.bC["-".join(ions)] = ifuncs[ifunc] + fvar[i] = fvarfuncs[varout][0](mols, ions, tempK, pres, prmlib=prmlib_base) + xtypes = { + "tot": (sqrt(tots), "sqrt(Molality / mol/kg)"), + "tempK": (tempK, "Temperature / K"), + "pres": (pres, "Pressure / dbar"), + } + xvar = xtypes[xtype][0] + for i, ifunc in enumerate(ifuncs): + ax.plot(xvar, fvar[i], label=ifunc.split("_")[-1]) + ax.legend() + ax.set_xlabel(xtypes[xtype][1]) + ax.set_ylabel(fvarfuncs[varout][1]) + ax.set_xlim([np_min(xvar), np_max(xvar)]) + return fvar + + +def bC_pres( + ax, tot, ele, tempK, pres0, pres1, prmlib_base=libraries.Seawater, varout="osm" +): + ions, nus = properties._ele2ions[ele] + pres = linspace(pres0, pres1, 100) + tots = full_like(pres, tot) + mols = array([tots * nus[0], tots * nus[1]]) + tempK = full_like(pres, tempK) + fvar = _bC_plot(ax, "pres", tots, mols, ele, ions, tempK, pres, prmlib_base, varout) + return fvar + + +def bC_tempK( + ax, tot, ele, tempK0, tempK1, pres, prmlib_base=libraries.Seawater, varout="osm" +): + ions, nus = properties._ele2ions[ele] + tempK = linspace(tempK0, tempK1, 100) + tots = full_like(tempK, tot) + mols = array([tots * nus[0], tots * nus[1]]) + pres = full_like(tempK, pres) + fvar = _bC_plot( + ax, "tempK", tots, mols, ele, ions, tempK, pres, prmlib_base, varout + ) + return fvar + + +def bC_tot( + ax, tot0, tot1, ele, tempK, pres, prmlib_base=libraries.Seawater, varout="osm" +): + ions, nus = properties._ele2ions[ele] + tots = linspace(sqrt(tot0), sqrt(tot1), 100) ** 2 + mols = array([tots * nus[0], tots * nus[1]]) + tempK = full_like(tots, tempK) + pres = full_like(tots, pres) + fvar = _bC_plot(ax, "tot", tots, mols, ele, ions, tempK, pres, prmlib_base, varout) + return fvar diff --git a/pytzer4/properties.py b/pytzer4/properties.py new file mode 100644 index 00000000..02d07832 --- /dev/null +++ b/pytzer4/properties.py @@ -0,0 +1,325 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Define solute properties.""" +from autograd.numpy import concatenate, float_, unique, vstack + +# Define dict of charges. +# Order: neutrals, cations, then anions, and alphabetical within each group. +_ion2charge = { + # Neutrals + "BOH3": 0, + "CO2": 0, + "H2S": 0, + "H3PO4": 0, + "HF": 0, + "glycerol": 0, + "NH3": 0, + "SO2": 0, + "sucrose": 0, + "tris": 0, + "urea": 0, + # Cations + "Ba": +2, + "Ca": +2, + "Cdjj": +2, + "Cojj": +2, + "Cs": +1, + "Cujj": +2, + "Fejj": +2, + "Fejjj": +3, + "H": +1, + "K": +1, + "La": +3, + "Li": +1, + "Mg": +2, + "MgOH": +1, + "Na": +1, + "NH4": +1, + "Rb": +1, + "Sr": +2, + "trisH": +1, + "UO2": +2, + "Znjj": +2, + # Anions + "acetate": -1, + "AsO4": -2, + "BOH4": -1, + "Br": -1, + "BrO3": -1, + "Cl": -1, + "ClO3": -1, + "ClO4": -1, + "CO3": -2, + "F": -1, + "H2AsO4": -1, + "H2PO4": -1, + "HAsO4": -2, + "HCO3": -1, + "HPO4": -2, + "HS": -1, + "HSO3": -1, + "HSO4": -1, + "I": -1, + "NO2": -1, + "NO3": -1, + "OH": -1, + "PO4": -3, + "S2O3": -2, + "SCN": -1, + "SO3": -2, + "SO4": -2, +} + +_ion2name = { + "Ag": "silver", + "Aljjj": "aluminium(III)", + "AsO4": "arsenate", + "BF4": "tetrafluoroborate", + "BO2": "oxido(oxo)borane", + "Ba": "barium", + "Br": "bromide", + "BrO3": "bromate", + "Bu4N": "tetrabutylammonium", + "CO3": "carbonate", + "Ca": "calcium", + "Cdjj": "cadmium(II)", + "Ce": "cerium", + "Cl": "chloride", + "ClO3": "chlorate", + "ClO4": "perchlorate", + "CoCN6": "Co(CN)6", + "Co(CN)6": "Co(CN)6", + "Coen3": "tris(ethylenediamine)cobalt(III)", + "Cojj": "cobalt(II)", + "Copn3": "Copn3", + "Cr": "chromium", + "CrO4": "chromate", + "Cs": "caesium", + "Cujj": "copper(II)", + "Et4N": "tetraethylammonium", + "Eu": "europium", + "F": "fluoride", + "Fejj": "iron(II)", + "FejjCN6": "ferrocyanide", + "Fejj(CN)6": "ferrocyanide", + "FejjjCN6": "ferricyanide", + "Fejjj(CN)6": "ferricyanide", + "Ga": "gallium", + "H": "hydrogen", + "H2AsO4": "dihydrogen-arsenate", + "H2PO4": "dihydrogen-phosphate", + "HAsO4": "hydrogen-arsenate", + "HCO3": "bicarbonate", + "HPO4": "hydrogen-phosphate", + "HSO4": "bisulfate", + "I": "iodide", + "IO3": "iodate", + "In": "indium", + "K": "potassium", + "La": "lanthanum", + "Li": "lithium", + "Me2H2N": "Me2H2N", + "Me3HN": "Me3HN", + "MeH3N": "MeH3N", + "MeN": "MeN", + "Me4N": "tetramethylammonium", + "Mg": "magnesium", + "MgOH": "magnesium-hydroxide", + "Mnjj": "manganese(II)", + "MoCN8": "Mo(CN)8", + "Mo(CN)8": "Mo(CN)8", + "NH4": "ammonium", + "NO2": "nitrite", + "NO3": "nitrate", + "Na": "sodium", + "Nd": "neodymium", + "Nijj": "nickel(II)", + "OAc": "OAc", + "OH": "hydroxide", + "P2O7": "diphosphate", + "P3O10": "triphosphate-pentaanion", + "P3O9": "trimetaphosphate", + "PO4": "phosphate", + "Pbjj": "lead(II)", + "Pr": "praeseodymium", + "Pr4N": "tetrapropylammonium", + "PtCN4": "platinocyanide", + "Pt(CN)4": "platinocyanide", + "PtF6": "platinum-hexafluoride", + "Rb": "rubidium", + "S2O3": "thiosulfate", + "SCN": "thiocyanate", + "SO4": "sulfate", + "Sm": "samarium", + "Sr": "strontium", + "Srjjj": "strontium(III)", + "Th": "thorium", + "Tl": "thallium", + "UO2": "uranium-dioxide", + "WCN8": "W(CN)8", + "W(CN)8": "W(CN)8", + "Y": "yttrium", + "Znjj": "zinc(II)", +} + +# Define general electrolyte to ions conversion dict +_ele2ions = { + "Ba(NO3)2": (("Ba", "NO3"), (1, 2)), + "CaCl2": (("Ca", "Cl"), (1, 2)), + "Cd(NO3)2": (("Cdjj", "NO3"), (1, 2)), + "Co(NO3)2": (("Cojj", "NO3"), (1, 2)), + "CsCl": (("Cs", "Cl"), (1, 1)), + "CuCl2": (("Cujj", "Cl"), (1, 2)), + "Cu(NO3)2": (("Cujj", "NO3"), (1, 2)), + "CuSO4": (("Cujj", "SO4"), (1, 1)), + "glycerol": (("glycerol",), (1,)), + "H2SO4": (("HSO4", "SO4", "H", "OH"), (0.5, 0.5, 1.5, 0.0)), + "HBr": (("H", "Br"), (1, 1)), + "HCl": (("H", "Cl"), (1, 1)), + "HClO4": (("H", "ClO4"), (1, 1)), + "HI": (("H", "I"), (1, 1)), + "HNO3": (("H", "NO3"), (1, 1)), + "KB(OH)4": (("K", "BOH4"), (1, 1)), + "K2CO3": (("K", "CO3"), (2, 1)), + "K2SO4": (("K", "SO4"), (2, 1)), + "KBr": (("K", "Br"), (1, 1)), + "KCl": (("K", "Cl"), (1, 1)), + "KF": (("K", "F"), (1, 1)), + "KI": (("K", "I"), (1, 1)), + "KNO3": (("K", "NO3"), (1, 1)), + "KOH": (("K", "OH"), (1, 1)), + "LaCl3": (("La", "Cl"), (1, 3)), + "Li2SO4": (("Li", "SO4"), (2, 1)), + "LiBr": (("Li", "Br"), (1, 1)), + "LiCl": (("Li", "Cl"), (1, 1)), + "LiClO4": (("Li", "ClO4"), (1, 1)), + "LiI": (("Li", "I"), (1, 1)), + "LiNO3": (("Li", "NO3"), (1, 1)), + "LiOH": (("Li", "OH"), (1, 1)), + "MgCl2": (("Mg", "Cl"), (1, 2)), + "Mg(ClO4)2": (("Mg", "ClO4"), (1, 2)), + "Mg(NO3)2": (("Mg", "NO3"), (1, 2)), + "MgSO4": (("Mg", "SO4"), (1, 1)), + "Na2S2O3": (("Na", "S2O3"), (2, 1)), + "Na2SO4": (("Na", "SO4"), (2, 1)), + "NaB(OH)4": (("Na", "BOH4"), (1, 1)), + "NaBr": (("Na", "Br"), (1, 1)), + "NaCl": (("Na", "Cl"), (1, 1)), + "NaClO4": (("Na", "ClO4"), (1, 1)), + "NaF": (("Na", "F"), (1, 1)), + "NaI": (("Na", "I"), (1, 1)), + "NaOH": (("Na", "OH"), (1, 1)), + "NaNO3": (("Na", "NO3"), (1, 1)), + "RbCl": (("Rb", "Cl"), (1, 1)), + "SrCl2": (("Sr", "Cl"), (1, 2)), + "Sr(NO3)2": (("Sr", "NO3"), (1, 2)), + "sucrose": (("sucrose",), (1,)), + "tris": (("tris",), (1,)), + "(trisH)2SO4": (("trisH", "SO4"), (2, 1)), + "trisHCl": (("trisH", "Cl"), (1, 1)), + "UO2(NO3)2": (("UO2", "NO3"), (1, 2)), + "urea": (("urea",), (1,)), + "Zn(ClO4)2": (("Znjj", "ClO4"), (1, 2)), + "Zn(NO3)2": (("Znjj", "NO3"), (1, 2)), +} + +# Define electrolyte to ions conversion dict for equilibria +_eq2ions = { + "t_H2CO3": ("CO2", "HCO3", "CO3"), + "t_HSO4": ("HSO4", "SO4"), + "t_Mg": ("Mg", "MgOH"), + "t_trisH": ("trisH", "tris"), + "t_BOH3": ("BOH3", "BOH4"), +} + +# Relative ionic masses in g/mol +_ion2mass = { + "H": 1.00794, + "Li": 6.941, + "Na": 22.98977, + "K": 39.0983, + "Rb": 85.4678, + "Cs": 132.90545, + "NH4": 18.03846, + "Mg": 24.3050, + "Ca": 40.078, + "Sr": 87.62, + "MgF": 43.3034, + "CaF": 59.0764, + "SrF": 106.6184, + "Ba": 137.327, + "TrisH": 122.14298, + "MgOH": 41.31234, + "Fejj": 55.845, + "Fejjj": 55.845, + "Cdjj": 112.411, + "Ni": 58.6934, + "Cuj": 63.546, + "Cujj": 63.546, + "Zn": 65.409, + "F": 18.99840, + "Cl": 35.453, + "Br": 79.904, + "I": 126.90447, + "NO3": 62.00490, + "OH": 17.00734, + "HSO4": 97.07054, + "SO4": 96.06260, + "HCO3": 61.01684, + "CO3": 60.00890, + "BOH4": 78.84036, + "NH3": 17.03052, + "CO2": 44.00950, + "BOH3": 61.83302, + "Tris": 121.13504, + "HF": 20.00634, + "MgCO3": 83.3139, + "CaCO3": 100.0869, + "SrCO3": 147.6289, +} + +# Select which ionic mass to use for molinity to molality conversion of eles +_ele2ionmass = { + "t_HSO4": "SO4", + "t_trisH": "tris", + "t_Mg": "Mg", + "t_BOH3": "BOH3", + "t_H2CO3": "HCO3", +} + + +def charges(ions): + """Find the charges on each of a list of ions.""" + if len(ions) == 0: + zs = float_([]) + cations = [] + anions = [] + neutrals = [] + else: + zs = vstack([float_(_ion2charge[ion]) for ion in ions]) + cations = [ion for ion in ions if _ion2charge[ion] > 0] + anions = [ion for ion in ions if _ion2charge[ion] < 0] + neutrals = [ion for ion in ions if _ion2charge[ion] == 0] + return zs, cations, anions, neutrals + + +def getallions(eles, fixions): + """Get all ions given list of electrolytes for equilibria.""" + if len(eles) == 0: + allions = concatenate([fixions, ["H", "OH"]]) + else: + allions = concatenate( + [ + fixions, + concatenate([_eq2ions[ele] for ele in eles]), + ["H", "OH"], + ] + ) + if len(unique(allions)) < len(allions): + allions = list(allions) + allions.reverse() + seen = set() + seen_add = seen.add + allions = [ion for ion in allions if not (ion in seen or seen_add(ion))] + allions.reverse() + return allions diff --git a/pytzer4/teos10.py b/pytzer4/teos10.py new file mode 100644 index 00000000..23a882a7 --- /dev/null +++ b/pytzer4/teos10.py @@ -0,0 +1,147 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Calculate properties of pure water.""" +from autograd.numpy import sqrt +from autograd import elementwise_grad as egrad + +# Properties of pure water +# Source: http://www.teos-10.org/pubs/IAPWS-2009-Supplementary.pdf +# Validity: 100 < presPa < 1e8 Pa; (270.5 - presPa*7.43e-8) < tempK < 313.15 K +# Seawater available from http://www.teos-10.org/pubs/IAPWS-08.pdf + + +def Gibbs(tempK, presPa): + """Gibbs energy function.""" + # Coefficients of the Gibbs function as defined in Table 2: + Gdict = { + (0, 0): 0.101342743139674e3, + (3, 2): 0.499360390819152e3, + (0, 1): 0.100015695367145e6, + (3, 3): -0.239545330654412e3, + (0, 2): -0.254457654203630e4, + (3, 4): 0.488012518593872e2, + (0, 3): 0.284517778446287e3, + (3, 5): -0.166307106208905e1, + (0, 4): -0.333146754253611e2, + (4, 0): -0.148185936433658e3, + (0, 5): 0.420263108803084e1, + (4, 1): 0.397968445406972e3, + (0, 6): -0.546428511471039, + (4, 2): -0.301815380621876e3, + (1, 0): 0.590578347909402e1, + (4, 3): 0.152196371733841e3, + (1, 1): -0.270983805184062e3, + (4, 4): -0.263748377232802e2, + (1, 2): 0.776153611613101e3, + (5, 0): 0.580259125842571e2, + (1, 3): -0.196512550881220e3, + (5, 1): -0.194618310617595e3, + (1, 4): 0.289796526294175e2, + (5, 2): 0.120520654902025e3, + (1, 5): -0.213290083518327e1, + (5, 3): -0.552723052340152e2, + (2, 0): -0.123577859330390e5, + (5, 4): 0.648190668077221e1, + (2, 1): 0.145503645404680e4, + (6, 0): -0.189843846514172e2, + (2, 2): -0.756558385769359e3, + (6, 1): 0.635113936641785e2, + (2, 3): 0.273479662323528e3, + (6, 2): -0.222897317140459e2, + (2, 4): -0.555604063817218e2, + (6, 3): 0.817060541818112e1, + (2, 5): 0.434420671917197e1, + (7, 0): 0.305081646487967e1, + (3, 0): 0.736741204151612e3, + (7, 1): -0.963108119393062e1, + (3, 1): -0.672507783145070e3, + } + # Convert temperature and pressure: + ctau = (tempK - 273.15) / 40 + cpi = (presPa - 101325) / 1e8 + # Initialise with zero and increment following Eq. (1): + Gsum = 0 + for j in range(8): + for k in range(7): + if (j, k) in Gdict.keys(): + Gsum = Gsum + Gdict[(j, k)] * ctau**j * cpi**k + return Gsum + + +# Get differentials +gt = egrad(Gibbs, argnum=0) +gp = egrad(Gibbs, argnum=1) +gtt = egrad(gt, argnum=0) +gtp = egrad(gt, argnum=1) +gpp = egrad(gp, argnum=1) + +# Define functions for solution properties +def rho(tempK, presPa): + """Density in kg/m**3.""" + # Table 3, Eq. (4) + return 1 / gp(tempK, presPa) + + +def s(tempK, presPa): + """Specific entropy in J/(kg*K).""" + # Table 3, Eq. (5) + return -gt(tempK, presPa) + + +def cp(tempK, presPa): + """Specific isobaric heat capacity in J/(kg*K).""" + # Table 3, Eq. (6) + return -tempK * gtt(tempK, presPa) + + +def h(tempK, presPa): + """Specific enthalpy in J/kg.""" + # Table 3, Eq. (7) + return Gibbs(tempK, presPa) + tempK * s(tempK, presPa) + + +def u(tempK, presPa): + """Specific internal energy in J/kg.""" + # Table 3, Eq. (8) + return Gibbs(tempK, presPa) + tempK * s(tempK, presPa) - presPa * gp(tempK, presPa) + + +def f(tempK, presPa): + """Specific Helmholtz energy in J/kg.""" + # Table 3, Eq. (9) + return Gibbs(tempK, presPa) - presPa * gp(tempK, presPa) + + +def alpha(tempK, presPa): + """Thermal expansion coefficient in 1/K.""" + # Table 3, Eq. (10) + return gtp(tempK, presPa) / gp(tempK, presPa) + + +def bs(tempK, presPa): + """Isentropic temp.-presPas. coefficient, adiabatic lapse rate in K/Pa.""" + # Table 3, Eq. (11) + return -gtp(tempK, presPa) / gp(tempK, presPa) + + +def kt(tempK, presPa): + """Isothermal compresPasibility in 1/Pa.""" + # Table 3, Eq. (12) + return -gpp(tempK, presPa) / gp(tempK, presPa) + + +def ks(tempK, presPa): + """Isentropic compresPasibility in 1/Pa.""" + # Table 3, Eq. (13) + return (gtp(tempK, presPa) ** 2 - gtt(tempK, presPa) * gpp(tempK, presPa)) / ( + gp(tempK, presPa) * gtt(tempK, presPa) + ) + + +def w(tempK, presPa): + """Speed of sound in m/s.""" + # Table 3, Eq. (14) + return gp(tempK, presPa) * sqrt( + gtt(tempK, presPa) + / (gtp(tempK, presPa) ** 2 - gtt(tempK, presPa) * gpp(tempK, presPa)) + ) diff --git a/pytzer4/unsymmetrical.py b/pytzer4/unsymmetrical.py new file mode 100644 index 00000000..f25029d4 --- /dev/null +++ b/pytzer4/unsymmetrical.py @@ -0,0 +1,175 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019 Matthew Paul Humphreys (GNU GPLv3) +"""Unsymmetrical mixing functions.""" +from autograd.numpy import ( + errstate, + exp, + float_, + full_like, + inf, + log, + nan, + size, + zeros, + zeros_like, +) +from autograd.extend import primitive, defvjp +from scipy.integrate import quad + + +def none(x): + """Ignore unsymmetrical mixing.""" + return zeros_like(x) + + +def numint(x): + """Evaluate unsymmetrical mixing function by numerical integration.""" + # Cannot yet be automatically differentiated + # P91 Chapter 3 Eq. (B-12) [p123] + q = lambda x, y: -(x / y) * exp(-y) + J = full_like(x, nan) + for i, xi in enumerate(x): + # P91 Chapter 3 Eq. (B-13) [p123] + J[i] = ( + quad( + lambda y: (1 + q(xi, y) + q(xi, y) ** 2 / 2 - exp(q(xi, y))) * y**2, + 0, + inf, + )[0] + / xi + ) + return J + + +def P75_eq46(x): + """Evaluate unsymmetrical mixing function following Pitzer (1975), + equation (46). + """ + # P75 Table III + C = float_( + [ + 4.118, + 7.247, + -4.408, + 1.837, + -0.251, + 0.0164, + ] + ) + Jsum = zeros_like(x) + for k in range(6): + Jsum = Jsum + C[k] * x ** -(k + 1) + return -(x**2) * log(x) * exp(-10 * x**2) / 6 + 1 / Jsum + + +def P75_eq47(x): + """Evaluate unsymmetrical mixing function following Pitzer (1975), + equation (47). + """ + C = float_( + [ + 4.0, + 4.581, + 0.7237, + 0.0120, + 0.528, + ] + ) + with errstate(divide="ignore"): + J = x / (C[0] + C[1] * x ** -C[2] * exp(-C[3] * x ** C[4])) + return J + + +# ~~~~~~~ Harvie's method as described by Pitzer (1991) Ch. 3, pp. 124-125 ~~~~~ +# Define the raw function - doesn't work in Pytzer (not autograd-able) +# Use Harvie() instead (code comes afterwards) +def _Harvie_raw(x): + J = full_like(x, nan, dtype="float64") + Jp = full_like(x, nan, dtype="float64") + for s, xs in enumerate(x): + if xs < 1.0: + # Values from Table B-1, middle column (akI) + ak = float_( + [ + 1.925154014814667, + -0.060076477753119, + -0.029779077456514, + -0.007299499690937, + 0.000388260636404, + 0.000636874599598, + 0.000036583601823, + -0.000045036975204, + -0.000004537895710, + 0.000002937706971, + 0.000000396566462, + -0.000000202099617, + -0.000000025267769, + 0.000000013522610, + 0.000000001229405, + -0.000000000821969, + -0.000000000050847, + 0.000000000046333, + 0.000000000001943, + -0.000000000002563, + -0.000000000010991, + ] + ) + z = 4 * xs**0.2 - 2 # Eq. (B-21) + dz_dx = 4 * xs**-0.8 / 5 # Eq. (B-22) + bk = zeros(size(ak) + 2, dtype="float64") + dk = zeros(size(ak) + 2, dtype="float64") + for i in reversed(range(21)): + bk[i] = z * bk[i + 1] - bk[i + 2] + ak[i] # Eq. (B-23) + dk[i] = bk[i + 1] + z * dk[i + 1] - dk[i + 2] # Eq. (B-24) + else: + # Values from Table B-1, final column (akII) + ak = float_( + [ + 0.628023320520852, + 0.462762985338493, + 0.150044637187895, + -0.028796057604906, + -0.036552745910311, + -0.001668087945272, + 0.006519840398744, + 0.001130378079086, + -0.000887171310131, + -0.000242107641309, + 0.000087294451594, + 0.000034682122751, + -0.000004583768938, + -0.000003548684306, + -0.000000250453880, + 0.000000216991779, + 0.000000080779570, + 0.000000004558555, + -0.000000006944757, + -0.000000002849257, + 0.000000000237816, + ] + ) + z = 40 / 9 * xs**-0.1 - 22 / 9 # Eq. (B-25) + dz_dx = -4 * xs**-1.1 / 9 # Eq. (B-26) + bk = zeros(size(ak) + 2, dtype="float64") + dk = zeros(size(ak) + 2, dtype="float64") + for i in reversed(range(21)): + bk[i] = z * bk[i + 1] - bk[i + 2] + ak[i] # Eq. (B-27) + dk[i] = bk[i + 1] + z * dk[i + 1] - dk[i + 2] # Eq. (B-28) + J[s] = 0.25 * xs - 1 + 0.5 * (bk[0] - bk[2]) # Eq. (B-29) + Jp[s] = 0.25 + 0.5 * dz_dx * (dk[0] - dk[2]) # Eq. (B-30) + return J, Jp + + +# Define the function to use in the model +@primitive +def Harvie(x): + """Evaluate unsymmetrical mixing function using Harvie's method.""" + return _Harvie_raw(x)[0] + + +# Set up its derivative for autograd +def _Harvie_vjp(ans, x): + return lambda g: g * _Harvie_raw(x)[1] + + +defvjp(Harvie, _Harvie_vjp) diff --git a/tests/test_convert.py b/tests/test_convert.py index c9289cd4..2204832f 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -21,9 +21,9 @@ # Manual approach - pks_constants mol_kg = unit.mol / unit.kg pks_H2O_molality = 14 -ks_H2O_molality = 10 ** -pks_H2O_molality * mol_kg ** 2 -ks_H2O_content = ks_H2O_molality * mass_H2O ** 2 / mass_total ** 2 -pks_H2O_content = -np.log10(ks_H2O_content / mol_kg ** 2).magnitude +ks_H2O_molality = 10**-pks_H2O_molality * mol_kg**2 +ks_H2O_content = ks_H2O_molality * mass_H2O**2 / mass_total**2 +pks_H2O_content = -np.log10(ks_H2O_content / mol_kg**2).magnitude def test_molinity_conversion(): diff --git a/tests/test_matrix.py b/tests/test_matrix.py new file mode 100644 index 00000000..729b8de0 --- /dev/null +++ b/tests/test_matrix.py @@ -0,0 +1,58 @@ +from jax import numpy as np +from autograd import numpy as anp +import pytzer as pz +import pytzer4 as pz4 + +molalities = np.array([[1.0, 1.0, 1.0, 1.5, 1.5]]) +charges = np.array([[+1, +1, -2, +3, -3]]) + +ionic_strength_model = pz.model.ionic_strength(molalities, charges) +ionic_strength = pz.matrix.ionic_strength(molalities, charges) +# print(ionic_strength, ionic_strength_model) + +ionic_zfunc_model = pz.model.ionic_z(molalities, charges) +ionic_zfunc = pz.matrix.ionic_z(molalities, charges) +# print(ionic_zfunc, ionic_zfunc_model) + +solutes = pz.odict() +solutes["Na"] = 1.0 +solutes["Cl"] = 1.0 +solutes["Mg"] = 1.0 +solutes["SO4"] = 1.0 + +prmlib = pz.libraries.Seawater +mparams = prmlib.get_matrices(solutes) +params = prmlib.get_parameters(solutes) + +print("GO") + +n_cats_triu = np.triu_indices(2, k=1) +n_anis_triu = np.triu_indices(2, k=1) +gexnrt = pz.matrix.Gibbs_nRT(solutes, n_cats_triu, n_anis_triu, **mparams) +print(gexnrt) + +gexnrt_model = pz.model.Gibbs_nRT(solutes, **params) +print(gexnrt_model) + +gexnrt_v4 = pz4.model.Gex_nRT( + anp.vstack([1.0, 1.0, 1.0, 1.0]), ["Na", "Cl", "Mg", "SO4"], 298.15, 10.10325 +)[0] +print(gexnrt_v4) + +#%% +m_cats = molalities +m_cats_cats = np.array( + [(np.transpose(m_cats) @ m_cats)[np.triu_indices(len(m_cats[0]), k=1)]] +) + +#%% +import jax + +uns = pz.unsymmetrical.Harvie(3.2) +print(uns) + +uns2 = jax.vmap(pz.unsymmetrical.Harvie, in_axes=0, out_axes=0)(np.array([3.2, 3.2])) +print(uns2) + +uns3 = jax.vmap(jax.vmap(pz.unsymmetrical.Harvie))(np.array([[3.2, 3.2], [3.2, 3.2]])) +print(uns3) diff --git a/tests/test_stoichiometric.py b/tests/test_stoichiometric.py index d0f3f4ae..75b868a3 100644 --- a/tests/test_stoichiometric.py +++ b/tests/test_stoichiometric.py @@ -10,7 +10,7 @@ def test_pure_water(): """Can we solve pure water?""" totals = pz.odict() - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -22,7 +22,7 @@ def test_pure_water(): def test_NaCl(): """Can we solve NaCl?""" totals = pz.odict(Na=1.5, Cl=1.5) - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -36,7 +36,7 @@ def test_NaCl(): def test_NaCl_HCl(): """Can we solve NaCl + HCl?""" totals = pz.odict(Na=1.5, Cl=3.5) - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -52,7 +52,7 @@ def test_NaCl_HCl(): def test_NaCl_SO4_only(): """Can we solve NaCl + SO4 without the HSO4 equilibrium?""" totals = pz.odict(Na=1.5, Cl=1.5, SO4=1.0) - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -71,7 +71,7 @@ def test_NaCl_SO4_only(): def test_NaCl_H2SO4(): """Can we solve NaCl + SO4 with the HSO4 equilibrium?""" totals = pz.odict(Na=1.5, Cl=1.5, SO4=1.0) - ks_constants = {"H2O": 10 ** -14, "HSO4": 10 ** -1} + ks_constants = {"H2O": 10**-14, "HSO4": 10**-1} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) assert len(ptargets) == 1 @@ -94,9 +94,9 @@ def test_NaCl_H2CO3(): """Can we solve NaCl + CO2 with the H2CO3 equilibria?""" totals = pz.odict(Na=1.5, Cl=1.5, CO2=0.1) ks_constants = { - "H2O": 10 ** -14, - "H2CO3": 10 ** -5, - "HCO3": 10 ** -9, + "H2O": 10**-14, + "H2CO3": 10**-5, + "HCO3": 10**-9, } ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) @@ -125,9 +125,9 @@ def test_CaCl_H2CO3(): """Can we solve CaCl + CO2 with the H2CO3 equilibria but no CaCO3?""" totals = pz.odict(Ca=0.75, Cl=1.5, CO2=0.1) ks_constants = { - "H2O": 10 ** -14, - "H2CO3": 10 ** -5, - "HCO3": 10 ** -9, + "H2O": 10**-14, + "H2CO3": 10**-5, + "HCO3": 10**-9, } ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) @@ -156,10 +156,10 @@ def test_CaCl_H2CO3_CaCO3(): """Can we solve CaCl + CO2 with the H2CO3 and CaCO3 equilibria?""" totals = pz.odict(Ca=0.75, Cl=1.5, CO2=0.1) ks_constants = { - "H2O": 10 ** -14, - "H2CO3": 10 ** -5, - "HCO3": 10 ** -9, - "CaCO3": 10 ** -4, + "H2O": 10**-14, + "H2CO3": 10**-5, + "HCO3": 10**-9, + "CaCO3": 10**-4, } ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) @@ -195,16 +195,16 @@ def test_all_ptargets(): """Can we solve with all ptargets active?""" totals = pz.odict(Ca=2.0, Cl=4.0, CO2=0.1, PO4=0.5, F=1.0) ks_constants = { - "H2O": 10 ** -14, - "H2CO3": 10 ** -5, - "HCO3": 10 ** -9, - "HF": 10 ** -2, - "H3PO4": 10 ** -11, - "H2PO4": 10 ** -6, - "HPO4": 10 ** -3, - "CaCO3": 10 ** -4, - "CaF": 10 ** 1, - "CaH2PO4": 10 ** -7, + "H2O": 10**-14, + "H2CO3": 10**-5, + "HCO3": 10**-9, + "HF": 10**-2, + "H3PO4": 10**-11, + "H2PO4": 10**-6, + "HPO4": 10**-3, + "CaCO3": 10**-4, + "CaF": 10**1, + "CaH2PO4": 10**-7, } ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) @@ -234,7 +234,7 @@ def test_get_constants_zero(): """ # Solve without DIC and HF totals = pz.odict(Na=1.5, Cl=3.5) - ks_constants = {"H2O": 10 ** -14} + ks_constants = {"H2O": 10**-14} ptargets = eq.stoichiometric.solve(totals, ks_constants) solutes = eq.components.get_solutes(totals, ks_constants, ptargets) # Get DIC and HF equilibria diff --git a/tests/untitled0.py b/tests/untitled0.py new file mode 100644 index 00000000..dd6e5edd --- /dev/null +++ b/tests/untitled0.py @@ -0,0 +1,28 @@ +import PyCO2SYS as pyco2 + +result = pyco2.sys( + # par1=df.alkalinity.to_numpy(), + par1=2300, + par2=2150, + par1_type=1, # 1 means alkalinity + par2_type=2, # 2 means DIC + salinity=30, + temperature=12.5, +) + +pCO2 = result["pCO2"] + + +result_pH = pyco2.sys( + par1=2300, + par2=8.1, + par1_type=1, + par2_type=3, # 3 means pH + temperature=25, # lab + temperature_out=6, # in the ocean +) + +pCO2_in_the_ocean = result_pH["pCO2_out"] +pH_in_the_ocean = result_pH["pH_out"] + +# https://pyco2sys.readthedocs.io/en/latest/ From d1b6713123f6c87c033a22059e09f32505e7dc5b Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Sat, 19 Feb 2022 00:29:37 +0100 Subject: [PATCH 11/58] Fix MgOH equilibrium --- pytzer/equilibrate/components.py | 2 +- pytzer/equilibrate/thermodynamic.py | 2 +- pytzer/libraries/Waters13.py | 4 + pytzer/libraries/Waters13_Clegg22.py | 129 +++++++++++++++++++++++ pytzer/libraries/Waters13_Humphreys22.py | 119 +++++++++++++++++++++ pytzer/libraries/__init__.py | 4 + pytzer/parameters.py | 9 +- tests/test_H22.py | 76 +++++++++++++ 8 files changed, 342 insertions(+), 3 deletions(-) create mode 100644 pytzer/libraries/Waters13_Clegg22.py create mode 100644 pytzer/libraries/Waters13_Humphreys22.py create mode 100644 tests/test_H22.py diff --git a/pytzer/equilibrate/components.py b/pytzer/equilibrate/components.py index ddba3547..d6e15842 100644 --- a/pytzer/equilibrate/components.py +++ b/pytzer/equilibrate/components.py @@ -224,7 +224,7 @@ def get_MgOH(h, f, co3, po4, totals, ks_constants): Mg = get_Mg(h, f, co3, po4, totals, ks_constants) OH = get_OH(h, ks_constants) k = ks_constants - return k["MgOH"] * Mg * OH + return Mg * OH / k["MgOH"] def get_MgF(h, f, co3, po4, totals, ks_constants): diff --git a/pytzer/equilibrate/thermodynamic.py b/pytzer/equilibrate/thermodynamic.py index 62ebcd9d..6b77e3e1 100644 --- a/pytzer/equilibrate/thermodynamic.py +++ b/pytzer/equilibrate/thermodynamic.py @@ -59,7 +59,7 @@ def Gibbs_HF(log_kt_HF, log_ks_HF, log_acfs, log_aH2O): def Gibbs_MgOH(log_kt_MgOH, log_ks_MgOH, log_acfs, log_aH2O): """Evaluate the Gibbs energy for the magnesium-MgOH+ equilibrium.""" return ( - log_acfs["Mg"] + log_acfs["OH"] - log_acfs["MgOH"] - log_ks_MgOH + log_kt_MgOH + log_acfs["MgOH"] - log_acfs["Mg"] - log_acfs["OH"] - log_ks_MgOH + log_kt_MgOH ) diff --git a/pytzer/libraries/Waters13.py b/pytzer/libraries/Waters13.py index f9621e3e..8faa3add 100644 --- a/pytzer/libraries/Waters13.py +++ b/pytzer/libraries/Waters13.py @@ -109,3 +109,7 @@ Waters13.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) Waters13.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_WM13) # agrees with HMW84 Waters13.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_WM13) # agrees with HMW84 +# Add equilibria +Waters13.update_equilibrium("HSO4", k.HSO4_CRP94) +Waters13.update_equilibrium("MgOH", k.MgOH_CW91_ln) +Waters13.update_equilibrium("H2O", k.H2O_M79) diff --git a/pytzer/libraries/Waters13_Clegg22.py b/pytzer/libraries/Waters13_Clegg22.py new file mode 100644 index 00000000..70155a61 --- /dev/null +++ b/pytzer/libraries/Waters13_Clegg22.py @@ -0,0 +1,129 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""Waters & Millero (2013). +*Marine Chemistry* 149, 8--22. +doi:10.1016/j.marchem.2012.11.003 +according to Clegg et al. (2022) +""" +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +Waters13_Clegg22 = ParameterLibrary(name="Waters13_Clegg22") +Waters13_Clegg22.update_Aphi(debyehueckel.Aosm_M88) +Waters13_Clegg22.assign_func_J(unsymmetrical.Harvie) +# Table A1: Na salts +Waters13_Clegg22.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +Waters13_Clegg22.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) +Waters13_Clegg22.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +Waters13_Clegg22.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +# Table A2: Mg salts +Waters13_Clegg22.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +Waters13_Clegg22.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +Waters13_Clegg22.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +# Table A3: Ca salts +Waters13_Clegg22.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +Waters13_Clegg22.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +Waters13_Clegg22.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +Waters13_Clegg22.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +# Table A4: K salts +Waters13_Clegg22.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +Waters13_Clegg22.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +Waters13_Clegg22.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +Waters13_Clegg22.update_ca("K", "OH", prm.bC_K_OH_HMW84) +# Table A5: H+ interactions +Waters13_Clegg22.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +Waters13_Clegg22.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +Waters13_Clegg22.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +# Table A6: MgOH+ interactions +Waters13_Clegg22.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +# Table A7: cation-cation interactions +Waters13_Clegg22.update_cc("H", "Na", prm.theta_H_Na_HCW22) # different from WM13 +Waters13_Clegg22.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +Waters13_Clegg22.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +Waters13_Clegg22.update_cc("H", "K", prm.theta_H_K_CMR93) +Waters13_Clegg22.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +Waters13_Clegg22.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +Waters13_Clegg22.update_cc("K", "Na", prm.theta_K_Na_HMW84) +Waters13_Clegg22.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +Waters13_Clegg22.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +Waters13_Clegg22.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +# Table A7: anion-anion interactions +Waters13_Clegg22.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +Waters13_Clegg22.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +Waters13_Clegg22.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +Waters13_Clegg22.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +Waters13_Clegg22.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +# Table A8: c-a-a' triplets +Waters13_Clegg22.update_caa("H", "Cl", "SO4", prm.psi_H_Cl_SO4_WM13) +Waters13_Clegg22.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +Waters13_Clegg22.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +Waters13_Clegg22.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +Waters13_Clegg22.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_HMW84) +Waters13_Clegg22.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("Mg", "Cl", "HSO4", prm.psi_Mg_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("Ca", "Cl", "HSO4", prm.psi_Ca_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("K", "Cl", "HSO4", prm.psi_K_Cl_HSO4_HMW84) +Waters13_Clegg22.update_caa("H", "Cl", "OH", prm.psi_H_Cl_OH_WM13) +Waters13_Clegg22.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +Waters13_Clegg22.update_caa("Mg", "Cl", "OH", prm.psi_Mg_Cl_OH_WM13) +Waters13_Clegg22.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +Waters13_Clegg22.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +Waters13_Clegg22.update_caa("H", "HSO4", "SO4", prm.psi_H_HSO4_SO4_HMW84) +Waters13_Clegg22.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +Waters13_Clegg22.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +Waters13_Clegg22.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_WM13) +Waters13_Clegg22.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +Waters13_Clegg22.update_caa("H", "OH", "SO4", prm.psi_H_OH_SO4_WM13) +Waters13_Clegg22.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) +Waters13_Clegg22.update_caa("Mg", "OH", "SO4", prm.psi_Mg_OH_SO4_WM13) +Waters13_Clegg22.update_caa("Ca", "OH", "SO4", prm.psi_Ca_OH_SO4_WM13) +Waters13_Clegg22.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +# Table A9: c-c'-a triplets +Waters13_Clegg22.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +Waters13_Clegg22.update_cca("H", "Na", "SO4", prm.psi_H_Na_SO4_WM13) +Waters13_Clegg22.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +Waters13_Clegg22.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +Waters13_Clegg22.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +Waters13_Clegg22.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +Waters13_Clegg22.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +Waters13_Clegg22.update_cca("Ca", "H", "SO4", prm.psi_Ca_H_SO4_WM13) +Waters13_Clegg22.update_cca("Ca", "H", "HSO4", prm.psi_Ca_H_HSO4_WM13) +Waters13_Clegg22.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +Waters13_Clegg22.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +Waters13_Clegg22.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +Waters13_Clegg22.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +Waters13_Clegg22.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) +Waters13_Clegg22.update_cca("Mg", "Na", "HSO4", prm.psi_Mg_Na_HSO4_WM13) +Waters13_Clegg22.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +Waters13_Clegg22.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +Waters13_Clegg22.update_cca("Ca", "Na", "HSO4", prm.psi_Ca_Na_HSO4_WM13) +Waters13_Clegg22.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +Waters13_Clegg22.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +Waters13_Clegg22.update_cca("K", "Na", "HSO4", prm.psi_K_Na_HSO4_WM13) +Waters13_Clegg22.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +Waters13_Clegg22.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +Waters13_Clegg22.update_cca("Ca", "Mg", "HSO4", prm.psi_Ca_Mg_HSO4_WM13) +Waters13_Clegg22.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +Waters13_Clegg22.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +Waters13_Clegg22.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_WM13) +Waters13_Clegg22.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +Waters13_Clegg22.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_WM13) +Waters13_Clegg22.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_WM13) +Waters13_Clegg22.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) # not in WM13 +# Add equilibria +Waters13_Clegg22.update_equilibrium("HSO4", k.HSO4_CRP94) +Waters13_Clegg22.update_equilibrium("MgOH", k.MgOH_CW91_ln) +Waters13_Clegg22.update_equilibrium("H2O", k.H2O_M79) +# Extras from Clegg22 (all before this point is from Humphreys22) +Waters13_Clegg22.update_equilibrium("trisH", k.trisH_BH64) +Waters13_Clegg22.update_ca("trisH", "Cl", prm.bC_trisH_Cl_CHW21) +Waters13_Clegg22.update_ca("trisH", "SO4", prm.bC_trisH_SO4_CHW21) +Waters13_Clegg22.update_nc("tris", "Ca", prm.lambd_tris_Ca_CHW21) +Waters13_Clegg22.update_nc("tris", "K", prm.lambd_tris_K_CHW21) +Waters13_Clegg22.update_nc("tris", "Mg", prm.lambd_tris_Mg_CHW21) +Waters13_Clegg22.update_nc("tris", "Na", prm.lambd_tris_Na_CHW21) +Waters13_Clegg22.update_nc("tris", "trisH", prm.lambd_tris_trisH_LTA21) +Waters13_Clegg22.update_na("tris", "SO4", prm.lambd_tris_SO4_LTA21) +Waters13_Clegg22.update_nn("tris", "tris", prm.lambd_tris_tris_LTA21) +Waters13_Clegg22.update_nnn("tris", prm.mu_tris_tris_tris_LTA21) diff --git a/pytzer/libraries/Waters13_Humphreys22.py b/pytzer/libraries/Waters13_Humphreys22.py new file mode 100644 index 00000000..5e641a19 --- /dev/null +++ b/pytzer/libraries/Waters13_Humphreys22.py @@ -0,0 +1,119 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""Waters & Millero (2013). +*Marine Chemistry* 149, 8--22. +doi:10.1016/j.marchem.2012.11.003 +according to Humphreys et al. (2022) +""" +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +Waters13_Humphreys22 = ParameterLibrary(name="Waters13_Humphreys22") +Waters13_Humphreys22.update_Aphi(debyehueckel.Aosm_M88) +Waters13_Humphreys22.assign_func_J(unsymmetrical.Harvie) +# Table A1: Na salts +Waters13_Humphreys22.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +Waters13_Humphreys22.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) +Waters13_Humphreys22.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +Waters13_Humphreys22.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +# Table A2: Mg salts +Waters13_Humphreys22.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +Waters13_Humphreys22.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +Waters13_Humphreys22.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +# Table A3: Ca salts +Waters13_Humphreys22.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +Waters13_Humphreys22.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +Waters13_Humphreys22.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +Waters13_Humphreys22.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +# Table A4: K salts +Waters13_Humphreys22.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +Waters13_Humphreys22.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +Waters13_Humphreys22.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +Waters13_Humphreys22.update_ca("K", "OH", prm.bC_K_OH_HMW84) +# Table A5: H+ interactions +Waters13_Humphreys22.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +Waters13_Humphreys22.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +Waters13_Humphreys22.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +# Table A6: MgOH+ interactions +Waters13_Humphreys22.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +# Table A7: cation-cation interactions +Waters13_Humphreys22.update_cc("H", "Na", prm.theta_H_Na_HCW22) # different from WM13 +Waters13_Humphreys22.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +Waters13_Humphreys22.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +Waters13_Humphreys22.update_cc("H", "K", prm.theta_H_K_CMR93) +Waters13_Humphreys22.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +Waters13_Humphreys22.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +Waters13_Humphreys22.update_cc("K", "Na", prm.theta_K_Na_HMW84) +Waters13_Humphreys22.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +Waters13_Humphreys22.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +Waters13_Humphreys22.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +# Table A7: anion-anion interactions +Waters13_Humphreys22.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +Waters13_Humphreys22.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +Waters13_Humphreys22.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +Waters13_Humphreys22.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +# Table A8: c-a-a' triplets +Waters13_Humphreys22.update_caa("H", "Cl", "SO4", prm.psi_H_Cl_SO4_WM13) +Waters13_Humphreys22.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +Waters13_Humphreys22.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +Waters13_Humphreys22.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +Waters13_Humphreys22.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_HMW84) +Waters13_Humphreys22.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("Mg", "Cl", "HSO4", prm.psi_Mg_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("Ca", "Cl", "HSO4", prm.psi_Ca_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("K", "Cl", "HSO4", prm.psi_K_Cl_HSO4_HMW84) +Waters13_Humphreys22.update_caa("H", "Cl", "OH", prm.psi_H_Cl_OH_WM13) +Waters13_Humphreys22.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +Waters13_Humphreys22.update_caa("Mg", "Cl", "OH", prm.psi_Mg_Cl_OH_WM13) +Waters13_Humphreys22.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +Waters13_Humphreys22.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +Waters13_Humphreys22.update_caa("H", "HSO4", "SO4", prm.psi_H_HSO4_SO4_HMW84) +Waters13_Humphreys22.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +Waters13_Humphreys22.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +Waters13_Humphreys22.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_WM13) +Waters13_Humphreys22.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +Waters13_Humphreys22.update_caa("H", "OH", "SO4", prm.psi_H_OH_SO4_WM13) +Waters13_Humphreys22.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) +Waters13_Humphreys22.update_caa("Mg", "OH", "SO4", prm.psi_Mg_OH_SO4_WM13) +Waters13_Humphreys22.update_caa("Ca", "OH", "SO4", prm.psi_Ca_OH_SO4_WM13) +Waters13_Humphreys22.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +# Table A9: c-c'-a triplets +Waters13_Humphreys22.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +Waters13_Humphreys22.update_cca("H", "Na", "SO4", prm.psi_H_Na_SO4_WM13) +Waters13_Humphreys22.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +Waters13_Humphreys22.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +Waters13_Humphreys22.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +Waters13_Humphreys22.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +Waters13_Humphreys22.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +Waters13_Humphreys22.update_cca("Ca", "H", "SO4", prm.psi_Ca_H_SO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "H", "HSO4", prm.psi_Ca_H_HSO4_WM13) +Waters13_Humphreys22.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +Waters13_Humphreys22.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +Waters13_Humphreys22.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +Waters13_Humphreys22.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +Waters13_Humphreys22.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) +Waters13_Humphreys22.update_cca("Mg", "Na", "HSO4", prm.psi_Mg_Na_HSO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +Waters13_Humphreys22.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +Waters13_Humphreys22.update_cca("Ca", "Na", "HSO4", prm.psi_Ca_Na_HSO4_WM13) +Waters13_Humphreys22.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +Waters13_Humphreys22.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +Waters13_Humphreys22.update_cca("K", "Na", "HSO4", prm.psi_K_Na_HSO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +Waters13_Humphreys22.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +Waters13_Humphreys22.update_cca("Ca", "Mg", "HSO4", prm.psi_Ca_Mg_HSO4_WM13) +Waters13_Humphreys22.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +Waters13_Humphreys22.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +Waters13_Humphreys22.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +Waters13_Humphreys22.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_WM13) +Waters13_Humphreys22.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_WM13) +Waters13_Humphreys22.update_cca( + "Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84 +) # not in WM13 +# Add equilibria +Waters13_Humphreys22.update_equilibrium("HSO4", k.HSO4_CRP94) +Waters13_Humphreys22.update_equilibrium("MgOH", k.MgOH_CW91_ln) +Waters13_Humphreys22.update_equilibrium("H2O", k.H2O_M79) diff --git a/pytzer/libraries/__init__.py b/pytzer/libraries/__init__.py index 0266aa6b..ef65c75d 100644 --- a/pytzer/libraries/__init__.py +++ b/pytzer/libraries/__init__.py @@ -11,6 +11,8 @@ from .Moller88 import Moller88 from .Seawater import Seawater from .Waters13 import Waters13 +from .Waters13_Humphreys22 import Waters13_Humphreys22 +from .Waters13_Clegg22 import Waters13_Clegg22 from .Waters13_MarChemSpec25 import Waters13_MarChemSpec25 # Aliases for convenience @@ -22,6 +24,8 @@ MP98 = MIAMI = Millero98 M88 = Moller88 WM13 = Waters13 +WM13_C22 = Waters13_Clegg22 +WM13_H22 = Waters13_Humphreys22 WM13_MCS25 = Waters13_MarChemSpec25 # solutes_MarChemSpec = np.array( diff --git a/pytzer/parameters.py b/pytzer/parameters.py index 89474634..bfdaca7b 100644 --- a/pytzer/parameters.py +++ b/pytzer/parameters.py @@ -11083,7 +11083,7 @@ def mu_tris_tris_tris_MarChemSpec25(T, P): return mu, valid -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clegg et al. (2021) ~~~~~ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Clegg et al. (2022) ~~~~~ def bC_trisH_Cl_CHW21(T, P): """c-a: trisH+ chloride [CHW21].""" b0 = 0.03468 @@ -12132,3 +12132,10 @@ def psi_K_Mg_Cl_A15(T, P): psi = -0.022 - 14.27 * (1 / T - 1 / 298.15) valid = (273.15 <= T) & (T <= 473.15) return psi, valid + + +def theta_H_Na_HCW22(T, P): + """c-c': hydrogen sodium [HCW22].""" + theta = 0.0306 - 0.000418 * (T - 298.15) + valid = (T >= 278.15) & (T <= 318.15) + return theta, valid diff --git a/tests/test_H22.py b/tests/test_H22.py new file mode 100644 index 00000000..ee886ff3 --- /dev/null +++ b/tests/test_H22.py @@ -0,0 +1,76 @@ +import numpy as np +import pytzer as pz, pytzer4 as pz4 + +prmlib = pz.libraries.Waters13_Clegg22 + +totals = pz.odict() +totals["Na"] = 0.4861818 +totals["Mg"] = 0.0547402 +totals["Ca"] = 0.01075004 +totals["K"] = 0.01058004 +totals["Cl"] = 0.5692021 +totals["SO4"] = 0.02927011 +totals["tris"] = 0.04 + +solutes, pks = pz.solve(totals, library=prmlib, temperature=278.15) +params = prmlib.get_parameters(solutes, temperature=278.15, verbose=False) +acfs = pz.activity_coefficients(solutes, **params) +aw = pz.activity_water(solutes, **params) + +waterk = (solutes["H"] * solutes["OH"] * acfs["H"] * acfs["OH"] / aw).item() +waterk_paper = 8.2481e-8 * 5.0620e-8 * 0.76188 * 0.57223 / 0.98142 +waterk_official = np.exp(prmlib["equilibria"]["H2O"](278.15)) + +sulfk = ( + solutes["H"] + * solutes["SO4"] + * acfs["H"] + * acfs["SO4"] + / (solutes["HSO4"] * acfs["HSO4"]) +).item() +sulfk_paper = 0.02927 * 8.2481e-8 * 0.76188 * 0.0972 / (0.72148 * 1.3286e-8) +sulfk_official = np.exp(prmlib["equilibria"]["HSO4"](278.15)) + +mgk = ( + solutes["Mg"] + * acfs["Mg"] + * solutes["OH"] + * acfs["OH"] + / (solutes["MgOH"] * acfs["MgOH"]) +).item() +mgk_paper = 0.05474 * 0.22054 * 5.062e-8 * 0.57223 / (4.5149e-8 * 0.90276) +mgk_official = np.exp(prmlib["equilibria"]["MgOH"](278.15)) +# this was upside down - and all the other formation constants probably are too! +# need to change in both pz.components (rearrange get_X equations) +# AND in pz.thermodynamic (swap signs of log_kt and log_ks terms) + +solutes_paper = pz.odict() +solutes_paper["H"] = 8.2481e-8 +solutes_paper["Ca"] = 0.01075 +solutes_paper["Cl"] = 0.56920 +solutes_paper["K"] = 0.01058 +solutes_paper["Mg"] = 0.05474 +solutes_paper["Na"] = 0.48618 +solutes_paper["SO4"] = 0.02927 +solutes_paper["OH"] = 5.0620e-8 +solutes_paper["HSO4"] = 1.3286e-8 +solutes_paper["MgOH"] = 4.5149e-8 +params = prmlib.get_parameters(solutes_paper, temperature=273.15, verbose=False) +# params = pz.libraries.GM89.get_parameters(solutes_paper, temperature=273.15, verbose=False) + +osm_paper = pz.osmotic_coefficient(solutes_paper, **params) +aw_paper = pz.activity_water(solutes_paper, **params) +acfs_paper = pz.activity_coefficients(solutes_paper, **params) +print(osm_paper, aw_paper) + +mols = np.vstack([v for v in solutes_paper.values()]) +ions = np.array([k for k in solutes_paper.keys()]) +prmlib_v4 = pz4.libraries.GM89 +prmlib_v4.add_zeros(ions) +acfs_paper_v4 = pz4.model.acfs(mols, ions, 273.15, 10.10325, prmlib=prmlib_v4).ravel() + +Gex_v4 = pz4.model.Gex_nRT(mols, ions, 273.15, 10.10325, prmlib=prmlib_v4)[0] +Gex_v5 = pz.Gibbs_nRT(solutes_paper, **params).item() + +for m, i in zip(acfs_paper_v4, ions): + print("{}: {} vs {}".format(i, acfs_paper[i], m)) From 400f0b25de3e88a478d0540b090b61b199d5cf6f Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Sun, 20 Feb 2022 09:41:45 +0100 Subject: [PATCH 12/58] Add tris --- docs/refs.md | 17 +++++++++++------ pytzer/dissociation.py | 8 +++++--- pytzer/equilibrate/components.py | 18 +++++++++++++++++- pytzer/equilibrate/stoichiometric.py | 2 ++ pytzer/equilibrate/thermodynamic.py | 2 +- pytzer/libraries/MarChemSpec.py | 2 +- pytzer/libraries/Waters13_Clegg22.py | 2 +- pytzer4/dissociation.py | 4 ++-- pytzer4/libraries/MarChemSpec.py | 2 +- tests/test_H22.py | 7 +++++-- 10 files changed, 46 insertions(+), 18 deletions(-) diff --git a/docs/refs.md b/docs/refs.md index f893a518..d00dbd9d 100644 --- a/docs/refs.md +++ b/docs/refs.md @@ -11,6 +11,11 @@ ??? citation "AW90: Archer & Wang (1990) *J. Phys. Chem. Ref. Data*" Archer, D. G., and Wang, P. (1990). The Dielectric Constant of Water and Debye‐Hückel Limiting Law Slopes. *Journal of Physical and Chemical Reference Data* 19, 371–411. [doi:10.1063/1.555853](https://doi.org/10.1063/1.555853) +### B + +??? citation "BH61: Bates & Hetzer (1961) *J. Phys. Chem.*" + Bates, R. G., and Hetzer, H. B. (1961). Dissociation constant of the protonated acid form of 2-amino-2-(hydroxymethyl)-1, 3-propanediol \[tris-hydroxymethyl\]-aminomethane and related thermodynamic quantities from 0 to 50°. *Journal of Physical Chemistry* 65(4), 667–671. [doi:10.1021/j100822a017](https://doi.org/10.1021/j100822a017) + ### C ??? citation "CB90: Clegg & Brimblecombe (1989) *J. Phys. Chem.*" @@ -24,13 +29,13 @@ ### D -??? note "D90: Dickson (1990) *J. Chem. Thermodyn.*" +??? citation "D90: Dickson (1990) *J. Chem. Thermodyn.*" Dickson, A. G. (1990). Standard potential of the reaction: AgCl(s) + 0.5 H2(g) = Ag(s) + HCl(aq), and the standard acidity constant of the ion HSO4 in synthetic sea water from 273.15 to 318.15 K. *Journal of Chemical Thermodynamics* 22, 113–127. doi:10.1016/0021-9614(90)90074-Z. ??? citation "dLP83: de Lima & Pitzer (1983) *J. Solution Chem.*" de Lima, M. C. P., and Pitzer, K. S. (1983). Thermodynamics of saturated electrolyte mixtures of NaCl with Na2SO4 and with MgCl2. *Journal of Solution Chemistry* 12, 187–199. [doi:10.1007/BF00648056](https://doi.org/10.1007/BF00648056) -??? note "DR79: Dickson & Riley (1979) *Mar. Chem.*" +??? citation "DR79: Dickson & Riley (1979) *Mar. Chem.*" Dickson, A. G., and Riley, J. P. (1979). The estimation of acid dissociation constants in sea-water media from potentiometric titrations with strong base. II. The dissociation of phosphoric acid. *Marine Chemistry* 7, 101–109. doi:10.1016/0304-4203(79)90002-1. ### F @@ -44,7 +49,7 @@ ??? citation "GM89: Greenberg & Møller (1989) *Geochim. Cosmochim. Acta*" Greenberg, J. P., and Møller, N. (1989). The prediction of mineral solubilities in natural waters: A chemical equilibrium model for the Na-K-Ca-Cl-SO4-H2O system to high concentration from 0 to 250°C. *Geochimica et Cosmochimica Acta* 53, 2503–2518. [doi:10.1016/0016-7037(89)90124-5](https://doi.org/10.1016/0016-7037(89)90124-5) -??? note "GP89: Goyet & Poisson (1989) *Deep-Sea Res. Pt. A*" +??? citation "GP89: Goyet & Poisson (1989) *Deep-Sea Res. Pt. A*" Goyet, C., and Poisson, A. (1989). New determination of carbonic acid dissociation constants in seawater as a function of temperature and salinity. *Deep-Sea Research Part A* 36, 1635–1654. doi:10.1016/0198-0149(89)90064-2. ??? citation "GT17: Gallego-Urrea & Turner (2017) *Mar. Chem.*" @@ -52,7 +57,7 @@ ### H -??? note "H73: Hansson (1973) *Deep-Sea Res.*" +??? citation "H73: Hansson (1973) *Deep-Sea Res.*" Hansson, I. (1973). A new set of acidity constants for carbonic acid and boric acid in sea water. *Deep-Sea Research* 20, 461–478. doi:10.1016/0011-7471(73)90100-9. ??? citation "HFM89: Hershey et al. (1989) *J. Solution Chem.*" @@ -83,7 +88,7 @@ ### K -??? note "KRCB77: Khoo et al. (1977) *Anal. Chem.*" +??? citation "KRCB77: Khoo et al. (1977) *Anal. Chem.*" Khoo, K. H., Ramette, R. W., Culberson, C. H., and Bates, R. G. (1977). Determination of hydrogen ion concentrations in seawater from 5 to 40C: standard potentials at salinities from 20 to 45 per mille. *Analytical Chemistry* 49, 29–34. [doi:10.1021/ac50009a016](https://doi.org/10.1021/ac50009a016). ### L @@ -157,7 +162,7 @@ ??? citation "RM81i: Rard & Miller (1981) *J. Chem. Eng. Data*" Rard, J. A., and Miller, D. G. (1981). Isopiestic Determination of the Osmotic Coefficients of Aqueous Na2SO4, MgSO4, and Na2SO4-MgSO4 at 25 °C. *Journal of Chemical & Engineering Data* 26, 33–38. [doi:10.1021/je00023a013](https://doi.org/10.1021/je00023a013) -??? note "RRV93: Roy et al. (1993) *Mar. Chem.*" +??? citation "RRV93: Roy et al. (1993) *Mar. Chem.*" Roy, R. N., Roy, L. N., Vogel, K. M., Porter-Moore, C., Pearson, T., Good, C. E., et al. (1993). The dissociation constants of carbonic acid in seawater at salinities 5 to 45 and temperatures 0 to 45°C. *Marine Chemistry* 44, 249–267. doi:10.1016/0304-4203(93)90207-5. ??? citation "RZM91: Roy et al. (1991) *J. Solution Chem.*" diff --git a/pytzer/dissociation.py b/pytzer/dissociation.py index f1331ac1..7a6deaac 100644 --- a/pytzer/dissociation.py +++ b/pytzer/dissociation.py @@ -36,8 +36,8 @@ def HSO4_CRP94(T=298.15): return lnkHSO4 -def trisH_BH64(T=298.15): - """TrisH+ dissociation following BH64 Eq. (3).""" +def trisH_BH61(T=298.15): + """TrisH+ dissociation following BH61 Eq. (3).""" # Matches Clegg's model [2019-07-02] log10ktrisH = -(2981.4 / T - 3.5888 + 0.005571 * T) lnktrisH = log10ktrisH * ln10 @@ -292,7 +292,7 @@ def pK_CaPO4(T=298.15): "HSO4": HSO4_CRP94, # "MgOH": lambda T=298.15: np.log(10.0 ** -pK_MgOH(T)), "MgOH": MgOH_MP98, - "trisH": trisH_BH64, + "trisH": trisH_BH61, } @@ -338,6 +338,8 @@ def assemble(temperature=298.15, exclude_equilibria=None, totals=None): kt_constants["CaPO4"] = np.exp(CaPO4_MP98_MR97(T=temperature)) if "Sr" in totals and "CO2" in totals: kt_constants["SrCO3"] = np.exp(SrCO3_MP98_MR97(T=temperature)) + if "tris" in totals: + kt_constants["trisH"] = np.exp(trisH_BH61(T=temperature)) if exclude_equilibria is not None: for eq in exclude_equilibria: if eq in kt_constants: diff --git a/pytzer/equilibrate/components.py b/pytzer/equilibrate/components.py index d6e15842..a5f0736b 100644 --- a/pytzer/equilibrate/components.py +++ b/pytzer/equilibrate/components.py @@ -149,6 +149,16 @@ def get_BOH3(h, totals, ks_constants): return h * t["BOH3"] / (h + k["BOH3"]) +def get_tris(h, totals, ks_constants): + t, k = totals, ks_constants + return k["trisH"] * t["tris"] / (h + k["trisH"]) + + +def get_trisH(h, totals, ks_constants): + t, k = totals, ks_constants + return h * t["tris"] / (h + k["trisH"]) + + def get_Ca(h, f, co3, po4, totals, ks_constants): H2PO4 = get_H2PO4(h, po4, ks_constants) HPO4 = get_HPO4(h, po4, ks_constants) @@ -206,7 +216,7 @@ def get_Mg(h, f, co3, po4, totals, ks_constants): t, k = totals, ks_constants denom = 1.0 if "MgOH" in k: - denom = denom + k["MgOH"] * OH + denom = denom + OH / k["MgOH"] if "MgF" in k: denom = denom + k["MgF"] * f if "MgCO3" in k: @@ -315,6 +325,9 @@ def find_solutes(totals, ks_constants, ptargets=None): if "NO2" in totals and "HNO2" in ks_constants: solutes.append("HNO2") solutes.append("NO2") + if "tris" in totals and "trisH" in ks_constants: + solutes.append("tris") + solutes.append("trisH") if "F" in targets and "F" in totals: if "Ca" in totals and "CaF" in ks_constants: solutes.append("CaF") @@ -417,6 +430,9 @@ def get_solutes(totals, ks_constants, ptargets): if "NO2" in totals and "HNO2" in ks_constants: solutes["HNO2"] = get_HNO2(h, totals, ks_constants) solutes["NO2"] = get_NO2(h, totals, ks_constants) + if "tris" in totals and "trisH" in ks_constants: + solutes["tris"] = get_tris(h, totals, ks_constants) + solutes["trisH"] = get_trisH(h, totals, ks_constants) if "F" in targets and "F" in totals: if "Ca" in totals and "CaF" in ks_constants: solutes["CaF"] = get_CaF(h, f, co3, po4, totals, ks_constants) diff --git a/pytzer/equilibrate/stoichiometric.py b/pytzer/equilibrate/stoichiometric.py index f48f43e3..aa366d10 100644 --- a/pytzer/equilibrate/stoichiometric.py +++ b/pytzer/equilibrate/stoichiometric.py @@ -92,6 +92,7 @@ def add_if_in(key): + add_if_in("NH3") + add_if_in("H3SiO4") - add_if_in("HNO2") + + add_if_in("tris") ) @@ -117,6 +118,7 @@ def add_if_in(key): - add_if_in("SO4") * 2 + add_if_in("NH3") - add_if_in("NO2") + + add_if_in("tris") ) diff --git a/pytzer/equilibrate/thermodynamic.py b/pytzer/equilibrate/thermodynamic.py index 6b77e3e1..03728224 100644 --- a/pytzer/equilibrate/thermodynamic.py +++ b/pytzer/equilibrate/thermodynamic.py @@ -59,7 +59,7 @@ def Gibbs_HF(log_kt_HF, log_ks_HF, log_acfs, log_aH2O): def Gibbs_MgOH(log_kt_MgOH, log_ks_MgOH, log_acfs, log_aH2O): """Evaluate the Gibbs energy for the magnesium-MgOH+ equilibrium.""" return ( - log_acfs["MgOH"] - log_acfs["Mg"] - log_acfs["OH"] - log_ks_MgOH + log_kt_MgOH + log_acfs["Mg"] + log_acfs["OH"] - log_acfs["MgOH"] + log_ks_MgOH - log_kt_MgOH ) diff --git a/pytzer/libraries/MarChemSpec.py b/pytzer/libraries/MarChemSpec.py index 768eeef3..f55fa21b 100644 --- a/pytzer/libraries/MarChemSpec.py +++ b/pytzer/libraries/MarChemSpec.py @@ -129,4 +129,4 @@ MarChemSpec.update_equilibrium("H2O", k.H2O_MF) MarChemSpec.update_equilibrium("HSO4", k.HSO4_CRP94) MarChemSpec.update_equilibrium("MgOH", k.MgOH_CW91) -MarChemSpec.update_equilibrium("trisH", k.trisH_BH64) +MarChemSpec.update_equilibrium("trisH", k.trisH_BH61) diff --git a/pytzer/libraries/Waters13_Clegg22.py b/pytzer/libraries/Waters13_Clegg22.py index 70155a61..d44eef95 100644 --- a/pytzer/libraries/Waters13_Clegg22.py +++ b/pytzer/libraries/Waters13_Clegg22.py @@ -116,7 +116,7 @@ Waters13_Clegg22.update_equilibrium("MgOH", k.MgOH_CW91_ln) Waters13_Clegg22.update_equilibrium("H2O", k.H2O_M79) # Extras from Clegg22 (all before this point is from Humphreys22) -Waters13_Clegg22.update_equilibrium("trisH", k.trisH_BH64) +Waters13_Clegg22.update_equilibrium("trisH", k.trisH_BH61) Waters13_Clegg22.update_ca("trisH", "Cl", prm.bC_trisH_Cl_CHW21) Waters13_Clegg22.update_ca("trisH", "SO4", prm.bC_trisH_SO4_CHW21) Waters13_Clegg22.update_nc("tris", "Ca", prm.lambd_tris_Ca_CHW21) diff --git a/pytzer4/dissociation.py b/pytzer4/dissociation.py index 8737b5fe..0912d2cd 100644 --- a/pytzer4/dissociation.py +++ b/pytzer4/dissociation.py @@ -33,8 +33,8 @@ def HSO4_CRP94(tempK): return lnkHSO4 -def trisH_BH64(tempK): - """TrisH+ dissociation following BH64 Eq. (3).""" +def trisH_BH61(tempK): + """TrisH+ dissociation following BH61 Eq. (3).""" # Matches Clegg's model [2019-07-02] log10ktrisH = -(2981.4 / tempK - 3.5888 + 0.005571 * tempK) lnktrisH = log10ktrisH * log(10) diff --git a/pytzer4/libraries/MarChemSpec.py b/pytzer4/libraries/MarChemSpec.py index 0620676a..79707bba 100644 --- a/pytzer4/libraries/MarChemSpec.py +++ b/pytzer4/libraries/MarChemSpec.py @@ -20,4 +20,4 @@ lnk["H2O"] = dissociation.H2O_MF lnk["HSO4"] = dissociation.HSO4_CRP94 lnk["MgOH"] = dissociation.MgOH_CW91 -lnk["trisH"] = dissociation.trisH_BH64 +lnk["trisH"] = dissociation.trisH_BH61 diff --git a/tests/test_H22.py b/tests/test_H22.py index ee886ff3..2506b33f 100644 --- a/tests/test_H22.py +++ b/tests/test_H22.py @@ -10,7 +10,7 @@ totals["K"] = 0.01058004 totals["Cl"] = 0.5692021 totals["SO4"] = 0.02927011 -totals["tris"] = 0.04 +# totals["tris"] = 0.04 solutes, pks = pz.solve(totals, library=prmlib, temperature=278.15) params = prmlib.get_parameters(solutes, temperature=278.15, verbose=False) @@ -21,6 +21,9 @@ waterk_paper = 8.2481e-8 * 5.0620e-8 * 0.76188 * 0.57223 / 0.98142 waterk_official = np.exp(prmlib["equilibria"]["H2O"](278.15)) +# trisk = (solutes["tris"] * solutes["H"] / solutes["trisH"]).item() +# trisk_official = np.exp(prmlib["equilibria"]["trisH"](278.15)) + sulfk = ( solutes["H"] * solutes["SO4"] @@ -40,7 +43,7 @@ ).item() mgk_paper = 0.05474 * 0.22054 * 5.062e-8 * 0.57223 / (4.5149e-8 * 0.90276) mgk_official = np.exp(prmlib["equilibria"]["MgOH"](278.15)) -# this was upside down - and all the other formation constants probably are too! +# this was upside down - and all the other formation constants might be too! # need to change in both pz.components (rearrange get_X equations) # AND in pz.thermodynamic (swap signs of log_kt and log_ks terms) From ce99a2de04842fcd1a0e58d28b979c791b70409a Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Sun, 20 Feb 2022 09:54:45 +0100 Subject: [PATCH 13/58] Update --- tests/test_H22.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/test_H22.py b/tests/test_H22.py index 2506b33f..af851020 100644 --- a/tests/test_H22.py +++ b/tests/test_H22.py @@ -4,15 +4,16 @@ prmlib = pz.libraries.Waters13_Clegg22 totals = pz.odict() -totals["Na"] = 0.4861818 +totals["Na"] = 0.4861818 #- 0.04 totals["Mg"] = 0.0547402 totals["Ca"] = 0.01075004 totals["K"] = 0.01058004 -totals["Cl"] = 0.5692021 +totals["Cl"] = 0.5692021 #+ 0.04 totals["SO4"] = 0.02927011 # totals["tris"] = 0.04 solutes, pks = pz.solve(totals, library=prmlib, temperature=278.15) +pH = -np.log10(solutes["H"]) params = prmlib.get_parameters(solutes, temperature=278.15, verbose=False) acfs = pz.activity_coefficients(solutes, **params) aw = pz.activity_water(solutes, **params) @@ -22,7 +23,7 @@ waterk_official = np.exp(prmlib["equilibria"]["H2O"](278.15)) # trisk = (solutes["tris"] * solutes["H"] / solutes["trisH"]).item() -# trisk_official = np.exp(prmlib["equilibria"]["trisH"](278.15)) +trisk_official = np.exp(prmlib["equilibria"]["trisH"](278.15)) sulfk = ( solutes["H"] @@ -64,7 +65,7 @@ osm_paper = pz.osmotic_coefficient(solutes_paper, **params) aw_paper = pz.activity_water(solutes_paper, **params) acfs_paper = pz.activity_coefficients(solutes_paper, **params) -print(osm_paper, aw_paper) +# print(osm_paper, aw_paper) mols = np.vstack([v for v in solutes_paper.values()]) ions = np.array([k for k in solutes_paper.keys()]) @@ -75,5 +76,5 @@ Gex_v4 = pz4.model.Gex_nRT(mols, ions, 273.15, 10.10325, prmlib=prmlib_v4)[0] Gex_v5 = pz.Gibbs_nRT(solutes_paper, **params).item() -for m, i in zip(acfs_paper_v4, ions): - print("{}: {} vs {}".format(i, acfs_paper[i], m)) +# for m, i in zip(acfs_paper_v4, ions): +# print("{}: {} vs {}".format(i, acfs_paper[i], m)) From 4da55d7aa0051b062b5df8514aa08e95f3a80b6c Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Sun, 20 Feb 2022 10:21:57 +0100 Subject: [PATCH 14/58] Update --- tests/test_H22.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_H22.py b/tests/test_H22.py index af851020..c17503cb 100644 --- a/tests/test_H22.py +++ b/tests/test_H22.py @@ -8,11 +8,11 @@ totals["Mg"] = 0.0547402 totals["Ca"] = 0.01075004 totals["K"] = 0.01058004 -totals["Cl"] = 0.5692021 #+ 0.04 +totals["Cl"] = 0.5692021 #+ 0.02 totals["SO4"] = 0.02927011 # totals["tris"] = 0.04 -solutes, pks = pz.solve(totals, library=prmlib, temperature=278.15) +solutes, pks = pz.solve(totals, library=prmlib, temperature=298.15) pH = -np.log10(solutes["H"]) params = prmlib.get_parameters(solutes, temperature=278.15, verbose=False) acfs = pz.activity_coefficients(solutes, **params) From f92b4a4eaac919bd3177eb7b768a8b72c85f0ddb Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Mon, 21 Feb 2022 15:49:18 +0100 Subject: [PATCH 15/58] Towards HM93 model --- pytzer/libraries/HeMorse93.py | 265 ++++++++++++++++++++++++++ pytzer/libraries/MilleroThurmond83.py | 25 +++ pytzer/parameters.py | 123 ++++++++++++ tests/test_H22.py | 4 +- tests/test_TM83.py | 50 +++++ 5 files changed, 465 insertions(+), 2 deletions(-) create mode 100644 pytzer/libraries/HeMorse93.py create mode 100644 pytzer/libraries/MilleroThurmond83.py create mode 100644 tests/test_TM83.py diff --git a/pytzer/libraries/HeMorse93.py b/pytzer/libraries/HeMorse93.py new file mode 100644 index 00000000..effd83a4 --- /dev/null +++ b/pytzer/libraries/HeMorse93.py @@ -0,0 +1,265 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +HeMorse93 = ParameterLibrary(name="HeMorse93") +HeMorse93.update_Aphi(debyehueckel.Aosm_M88) +HeMorse93.assign_func_J(unsymmetrical.Harvie) +# beta and C +HeMorse93.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +HeMorse93.update_ca("Na", "SO4", prm.bC_Na_SO4_M88) +HeMorse93.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HMW84) +HeMorse93.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +HeMorse93.update_ca("Na", "HCO3", prm.bC_Na_HCO3_HMW84) +HeMorse93.update_ca("Na", "CO3", prm.bC_Na_CO3_HMW84) +HeMorse93.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +HeMorse93.update_ca("K", "SO4", prm.bC_K_SO4_GM89) +HeMorse93.update_ca("K", "HSO4", prm.bC_K_HSO4_HMW84) +HeMorse93.update_ca("K", "OH", prm.bC_K_OH_HMW84) +HeMorse93.update_ca("K", "HCO3", prm.bC_K_HCO3_HMW84) +HeMorse93.update_ca("K", "CO3", prm.bC_K_CO3_HMW84) +HeMorse93.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +HeMorse93.update_ca("Ca", "SO4", prm.bC_Ca_SO4_M88) +HeMorse93.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_HMW84) +HeMorse93.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +HeMorse93.update_ca("Ca", "HCO3", prm.bC_Ca_HCO3_HMW84) +HeMorse93.update_ca("Ca", "CO3", prm.bC_Ca_CO3_HMW84) +HeMorse93.update_ca("Mg", "Cl", prm.bC_Mg_Cl_SMW90) +HeMorse93.update_ca("Mg", "SO4", prm.bC_Mg_SO4_SMW90) +HeMorse93.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_HMW84) +HeMorse93.update_ca("Mg", "OH", prm.bC_Mg_OH_HMW84) +HeMorse93.update_ca("Mg", "HCO3", prm.bC_Mg_HCO3_HMW84) +HeMorse93.update_ca("Mg", "CO3", prm.bC_Mg_CO3_HMW84) +HeMorse93.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +HeMorse93.update_ca("MgOH", "SO4", prm.bC_MgOH_SO4_HMW84) +HeMorse93.update_ca("MgOH", "HSO4", prm.bC_MgOH_HSO4_HMW84) +HeMorse93.update_ca("MgOH", "OH", prm.bC_MgOH_OH_HMW84) +HeMorse93.update_ca("MgOH", "HCO3", prm.bC_MgOH_HCO3_HMW84) +HeMorse93.update_ca("MgOH", "CO3", prm.bC_MgOH_CO3_HMW84) +HeMorse93.update_ca("H", "Cl", prm.bC_H_Cl_HMW84) +HeMorse93.update_ca("H", "SO4", prm.bC_H_SO4_HMW84) +HeMorse93.update_ca("H", "HSO4", prm.bC_H_HSO4_HMW84) +HeMorse93.update_ca("H", "OH", prm.bC_H_OH_HMW84) +HeMorse93.update_ca("H", "HCO3", prm.bC_H_HCO3_HMW84) +HeMorse93.update_ca("H", "CO3", prm.bC_H_CO3_HMW84) +# theta and psi +HeMorse93.update_aa("Cl", "SO4", prm.theta_Cl_SO4_M88) +HeMorse93.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_M88) +HeMorse93.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_GM89) +HeMorse93.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_M88) +HeMorse93.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HM93) +HeMorse93.update_caa("MgOH", "Cl", "SO4", prm.psi_MgOH_Cl_SO4_HMW84) +HeMorse93.update_caa("H", "Cl", "SO4", prm.psi_H_Cl_SO4_HMW84) +HeMorse93.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +HeMorse93.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +HeMorse93.update_caa("K", "Cl", "HSO4", prm.psi_K_Cl_HSO4_HMW84) +HeMorse93.update_caa("Ca", "Cl", "HSO4", prm.psi_Ca_Cl_HSO4_HMW84) +HeMorse93.update_caa("Mg", "Cl", "HSO4", prm.psi_Mg_Cl_HSO4_HMW84) +HeMorse93.update_caa("MgOH", "Cl", "HSO4", prm.psi_MgOH_Cl_HSO4_HMW84) +HeMorse93.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +HeMorse93.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +HeMorse93.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_PP87ii) +HeMorse93.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +HeMorse93.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +HeMorse93.update_caa("Mg", "Cl", "OH", prm.psi_Mg_Cl_OH_HMW84) +HeMorse93.update_caa("MgOH", "Cl", "OH", prm.psi_MgOH_Cl_OH_HMW84) +HeMorse93.update_caa("H", "Cl", "OH", prm.psi_H_Cl_OH_HMW84) +HeMorse93.update_aa("Cl", "HCO3", prm.theta_Cl_HCO3_HMW84) +HeMorse93.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_HMW84) +HeMorse93.update_caa("K", "Cl", "HCO3", prm.psi_K_Cl_HCO3_HMW84) +HeMorse93.update_caa("Ca", "Cl", "HCO3", prm.psi_Ca_Cl_HCO3_HMW84) +HeMorse93.update_caa("Mg", "Cl", "HCO3", prm.psi_Mg_Cl_HCO3_HMW84) +HeMorse93.update_caa("MgOH", "Cl", "HCO3", prm.psi_MgOH_Cl_HCO3_HMW84) +HeMorse93.update_caa("H", "Cl", "HCO3", prm.psi_H_Cl_HCO3_HMW84) +HeMorse93.update_aa("CO3", "Cl", prm.theta_CO3_Cl_HMW84) +HeMorse93.update_caa("Na", "CO3", "Cl", prm.psi_Na_CO3_Cl_HMW84) +HeMorse93.update_caa("K", "CO3", "Cl", prm.psi_K_CO3_Cl_HMW84) +HeMorse93.update_caa("Ca", "CO3", "Cl", prm.psi_Ca_CO3_Cl_HMW84) +HeMorse93.update_caa("Mg", "CO3", "Cl", prm.psi_Mg_CO3_Cl_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "Cl", prm.psi_MgOH_CO3_Cl_HMW84) +HeMorse93.update_caa("H", "CO3", "Cl", prm.psi_H_CO3_Cl_HMW84) +HeMorse93.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_HMW84) +HeMorse93.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +HeMorse93.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +HeMorse93.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_HMW84) +HeMorse93.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_HMW84) +HeMorse93.update_caa("MgOH", "HSO4", "SO4", prm.psi_MgOH_HSO4_SO4_HMW84) +HeMorse93.update_caa("H", "HSO4", "SO4", prm.psi_H_HSO4_SO4_HMW84) +HeMorse93.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +HeMorse93.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_PP87ii) +HeMorse93.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +HeMorse93.update_caa("Ca", "OH", "SO4", prm.psi_Ca_OH_SO4_HMW84) +HeMorse93.update_caa("Mg", "OH", "SO4", prm.psi_Mg_OH_SO4_HMW84) +HeMorse93.update_caa("MgOH", "OH", "SO4", prm.psi_MgOH_OH_SO4_HMW84) +HeMorse93.update_caa("H", "OH", "SO4", prm.psi_H_OH_SO4_HMW84) +HeMorse93.update_aa("HCO3", "SO4", prm.theta_HCO3_SO4_HMW84) +HeMorse93.update_caa("Na", "HCO3", "SO4", prm.psi_Na_HCO3_SO4_HMW84) +HeMorse93.update_caa("K", "HCO3", "SO4", prm.psi_K_HCO3_SO4_HMW84) +HeMorse93.update_caa("Ca", "HCO3", "SO4", prm.psi_Ca_HCO3_SO4_HMW84) +HeMorse93.update_caa("Mg", "HCO3", "SO4", prm.psi_Mg_HCO3_SO4_HMW84) +HeMorse93.update_caa("MgOH", "HCO3", "SO4", prm.psi_MgOH_HCO3_SO4_HMW84) +HeMorse93.update_caa("H", "HCO3", "SO4", prm.psi_H_HCO3_SO4_HMW84) +HeMorse93.update_aa("CO3", "SO4", prm.theta_CO3_SO4_HMW84) +HeMorse93.update_caa("Na", "CO3", "SO4", prm.psi_Na_CO3_SO4_HMW84) +HeMorse93.update_caa("K", "CO3", "SO4", prm.psi_K_CO3_SO4_HMW84) +HeMorse93.update_caa("Ca", "CO3", "SO4", prm.psi_Ca_CO3_SO4_HMW84) +HeMorse93.update_caa("Mg", "CO3", "SO4", prm.psi_Mg_CO3_SO4_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "SO4", prm.psi_MgOH_CO3_SO4_HMW84) +HeMorse93.update_caa("H", "CO3", "SO4", prm.psi_H_CO3_SO4_HMW84) +HeMorse93.update_aa("HSO4", "OH", prm.theta_HSO4_OH_HMW84) +HeMorse93.update_caa("Na", "HSO4", "OH", prm.psi_Na_HSO4_OH_HMW84) +HeMorse93.update_caa("K", "HSO4", "OH", prm.psi_K_HSO4_OH_HMW84) +HeMorse93.update_caa("Ca", "HSO4", "OH", prm.psi_Ca_HSO4_OH_HMW84) +HeMorse93.update_caa("Mg", "HSO4", "OH", prm.psi_Mg_HSO4_OH_HMW84) +HeMorse93.update_caa("MgOH", "HSO4", "OH", prm.psi_MgOH_HSO4_OH_HMW84) +HeMorse93.update_caa("H", "HSO4", "OH", prm.psi_H_HSO4_OH_HMW84) +HeMorse93.update_aa("HCO3", "HSO4", prm.theta_HCO3_HSO4_HMW84) +HeMorse93.update_caa("Na", "HCO3", "HSO4", prm.psi_Na_HCO3_HSO4_HMW84) +HeMorse93.update_caa("K", "HCO3", "HSO4", prm.psi_K_HCO3_HSO4_HMW84) +HeMorse93.update_caa("Ca", "HCO3", "HSO4", prm.psi_Ca_HCO3_HSO4_HMW84) +HeMorse93.update_caa("Mg", "HCO3", "HSO4", prm.psi_Mg_HCO3_HSO4_HMW84) +HeMorse93.update_caa("MgOH", "HCO3", "HSO4", prm.psi_MgOH_HCO3_HSO4_HMW84) +HeMorse93.update_caa("H", "HCO3", "HSO4", prm.psi_H_HCO3_HSO4_HMW84) +HeMorse93.update_aa("CO3", "HSO4", prm.theta_CO3_HSO4_HMW84) +HeMorse93.update_caa("Na", "CO3", "HSO4", prm.psi_Na_CO3_HSO4_HMW84) +HeMorse93.update_caa("K", "CO3", "HSO4", prm.psi_K_CO3_HSO4_HMW84) +HeMorse93.update_caa("Ca", "CO3", "HSO4", prm.psi_Ca_CO3_HSO4_HMW84) +HeMorse93.update_caa("Mg", "CO3", "HSO4", prm.psi_Mg_CO3_HSO4_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "HSO4", prm.psi_MgOH_CO3_HSO4_HMW84) +HeMorse93.update_caa("H", "CO3", "HSO4", prm.psi_H_CO3_HSO4_HMW84) +HeMorse93.update_aa("HCO3", "OH", prm.theta_HCO3_OH_HMW84) +HeMorse93.update_caa("Na", "HCO3", "OH", prm.psi_Na_HCO3_OH_HMW84) +HeMorse93.update_caa("K", "HCO3", "OH", prm.psi_K_HCO3_OH_HMW84) +HeMorse93.update_caa("Ca", "HCO3", "OH", prm.psi_Ca_HCO3_OH_HMW84) +HeMorse93.update_caa("Mg", "HCO3", "OH", prm.psi_Mg_HCO3_OH_HMW84) +HeMorse93.update_caa("MgOH", "HCO3", "OH", prm.psi_MgOH_HCO3_OH_HMW84) +HeMorse93.update_caa("H", "HCO3", "OH", prm.psi_H_HCO3_OH_HMW84) +HeMorse93.update_aa("CO3", "OH", prm.theta_CO3_OH_HMW84) +HeMorse93.update_caa("Na", "CO3", "OH", prm.psi_Na_CO3_OH_HMW84) +HeMorse93.update_caa("K", "CO3", "OH", prm.psi_K_CO3_OH_HMW84) +HeMorse93.update_caa("Ca", "CO3", "OH", prm.psi_Ca_CO3_OH_HMW84) +HeMorse93.update_caa("Mg", "CO3", "OH", prm.psi_Mg_CO3_OH_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "OH", prm.psi_MgOH_CO3_OH_HMW84) +HeMorse93.update_caa("H", "CO3", "OH", prm.psi_H_CO3_OH_HMW84) +HeMorse93.update_aa("CO3", "HCO3", prm.theta_CO3_HCO3_HMW84) +HeMorse93.update_caa("Na", "CO3", "HCO3", prm.psi_Na_CO3_HCO3_HMW84) +HeMorse93.update_caa("K", "CO3", "HCO3", prm.psi_K_CO3_HCO3_HMW84) +HeMorse93.update_caa("Ca", "CO3", "HCO3", prm.psi_Ca_CO3_HCO3_HMW84) +HeMorse93.update_caa("Mg", "CO3", "HCO3", prm.psi_Mg_CO3_HCO3_HMW84) +HeMorse93.update_caa("MgOH", "CO3", "HCO3", prm.psi_MgOH_CO3_HCO3_HMW84) +HeMorse93.update_caa("H", "CO3", "HCO3", prm.psi_H_CO3_HCO3_HMW84) +HeMorse93.update_cc("K", "Na", prm.theta_K_Na_GM89) +HeMorse93.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_GM89) +HeMorse93.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_GM89) +HeMorse93.update_cca("K", "Na", "HSO4", prm.psi_K_Na_HSO4_HMW84) +HeMorse93.update_cca("K", "Na", "OH", prm.psi_K_Na_OH_HMW84) +HeMorse93.update_cca("K", "Na", "HCO3", prm.psi_K_Na_HCO3_HMW84) +HeMorse93.update_cca("K", "Na", "CO3", prm.psi_K_Na_CO3_HMW84) +HeMorse93.update_cc("Ca", "Na", prm.theta_Ca_Na_M88) +HeMorse93.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_M88) +HeMorse93.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_M88) +HeMorse93.update_cca("Ca", "Na", "HSO4", prm.psi_Ca_Na_HSO4_HMW84) +HeMorse93.update_cca("Ca", "Na", "OH", prm.psi_Ca_Na_OH_HMW84) +HeMorse93.update_cca("Ca", "Na", "HCO3", prm.psi_Ca_Na_HCO3_HMW84) +HeMorse93.update_cca("Ca", "Na", "CO3", prm.psi_Ca_Na_CO3_HMW84) +HeMorse93.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +HeMorse93.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_PP87ii) +HeMorse93.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) +HeMorse93.update_cca("Mg", "Na", "HSO4", prm.psi_Mg_Na_HSO4_HMW84) +HeMorse93.update_cca("Mg", "Na", "OH", prm.psi_Mg_Na_OH_HMW84) +HeMorse93.update_cca("Mg", "Na", "HCO3", prm.psi_Mg_Na_HCO3_HMW84) +HeMorse93.update_cca("Mg", "Na", "CO3", prm.psi_Mg_Na_CO3_HMW84) +HeMorse93.update_cc("MgOH", "Na", prm.theta_MgOH_Na_HMW84) +HeMorse93.update_cca("MgOH", "Na", "Cl", prm.psi_MgOH_Na_Cl_HMW84) +HeMorse93.update_cca("MgOH", "Na", "SO4", prm.psi_MgOH_Na_SO4_HMW84) +HeMorse93.update_cca("MgOH", "Na", "HSO4", prm.psi_MgOH_Na_HSO4_HMW84) +HeMorse93.update_cca("MgOH", "Na", "OH", prm.psi_MgOH_Na_OH_HMW84) +HeMorse93.update_cca("MgOH", "Na", "HCO3", prm.psi_MgOH_Na_HCO3_HMW84) +HeMorse93.update_cca("MgOH", "Na", "CO3", prm.psi_MgOH_Na_CO3_HMW84) +HeMorse93.update_cc("H", "Na", prm.theta_H_Na_HMW84) +HeMorse93.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +HeMorse93.update_cca("H", "Na", "SO4", prm.psi_H_Na_SO4_HMW84) +HeMorse93.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +HeMorse93.update_cca("H", "Na", "OH", prm.psi_H_Na_OH_HMW84) +HeMorse93.update_cca("H", "Na", "HCO3", prm.psi_H_Na_HCO3_HMW84) +HeMorse93.update_cca("H", "Na", "CO3", prm.psi_H_Na_CO3_HMW84) +HeMorse93.update_cc("Ca", "K", prm.theta_Ca_K_GM89) +HeMorse93.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_GM89) +HeMorse93.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_GM89) +HeMorse93.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_HMW84) +HeMorse93.update_cca("Ca", "K", "OH", prm.psi_Ca_K_OH_HMW84) +HeMorse93.update_cca("Ca", "K", "HCO3", prm.psi_Ca_K_HCO3_HMW84) +HeMorse93.update_cca("Ca", "K", "CO3", prm.psi_Ca_K_CO3_HMW84) +HeMorse93.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +HeMorse93.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_PP87ii) +HeMorse93.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +HeMorse93.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_HMW84) +HeMorse93.update_cca("K", "Mg", "OH", prm.psi_K_Mg_OH_HMW84) +HeMorse93.update_cca("K", "Mg", "HCO3", prm.psi_K_Mg_HCO3_HMW84) +HeMorse93.update_cca("K", "Mg", "CO3", prm.psi_K_Mg_CO3_HMW84) +HeMorse93.update_cc("K", "MgOH", prm.theta_K_MgOH_HMW84) +HeMorse93.update_cca("K", "MgOH", "Cl", prm.psi_K_MgOH_Cl_HMW84) +HeMorse93.update_cca("K", "MgOH", "SO4", prm.psi_K_MgOH_SO4_HMW84) +HeMorse93.update_cca("K", "MgOH", "HSO4", prm.psi_K_MgOH_HSO4_HMW84) +HeMorse93.update_cca("K", "MgOH", "OH", prm.psi_K_MgOH_OH_HMW84) +HeMorse93.update_cca("K", "MgOH", "HCO3", prm.psi_K_MgOH_HCO3_HMW84) +HeMorse93.update_cca("K", "MgOH", "CO3", prm.psi_K_MgOH_CO3_HMW84) +HeMorse93.update_cc("H", "K", prm.theta_H_K_HMW84) +HeMorse93.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +HeMorse93.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +HeMorse93.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +HeMorse93.update_cca("H", "K", "OH", prm.psi_H_K_OH_HMW84) +HeMorse93.update_cca("H", "K", "HCO3", prm.psi_H_K_HCO3_HMW84) +HeMorse93.update_cca("H", "K", "CO3", prm.psi_H_K_CO3_HMW84) +HeMorse93.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +HeMorse93.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +HeMorse93.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +HeMorse93.update_cca("Ca", "Mg", "HSO4", prm.psi_Ca_Mg_HSO4_HMW84) +HeMorse93.update_cca("Ca", "Mg", "OH", prm.psi_Ca_Mg_OH_HMW84) +HeMorse93.update_cca("Ca", "Mg", "HCO3", prm.psi_Ca_Mg_HCO3_HMW84) +HeMorse93.update_cca("Ca", "Mg", "CO3", prm.psi_Ca_Mg_CO3_HMW84) +HeMorse93.update_cc("Ca", "MgOH", prm.theta_Ca_MgOH_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "Cl", prm.psi_Ca_MgOH_Cl_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "SO4", prm.psi_Ca_MgOH_SO4_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "HSO4", prm.psi_Ca_MgOH_HSO4_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "OH", prm.psi_Ca_MgOH_OH_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "HCO3", prm.psi_Ca_MgOH_HCO3_HMW84) +HeMorse93.update_cca("Ca", "MgOH", "CO3", prm.psi_Ca_MgOH_CO3_HMW84) +HeMorse93.update_cc("Ca", "H", prm.theta_Ca_H_HMW84) +HeMorse93.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +HeMorse93.update_cca("Ca", "H", "SO4", prm.psi_Ca_H_SO4_HMW84) +HeMorse93.update_cca("Ca", "H", "HSO4", prm.psi_Ca_H_HSO4_HMW84) +HeMorse93.update_cca("Ca", "H", "OH", prm.psi_Ca_H_OH_HMW84) +HeMorse93.update_cca("Ca", "H", "HCO3", prm.psi_Ca_H_HCO3_HMW84) +HeMorse93.update_cca("Ca", "H", "CO3", prm.psi_Ca_H_CO3_HMW84) +HeMorse93.update_cc("Mg", "MgOH", prm.theta_Mg_MgOH_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "SO4", prm.psi_Mg_MgOH_SO4_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "HSO4", prm.psi_Mg_MgOH_HSO4_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "OH", prm.psi_Mg_MgOH_OH_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "HCO3", prm.psi_Mg_MgOH_HCO3_HMW84) +HeMorse93.update_cca("Mg", "MgOH", "CO3", prm.psi_Mg_MgOH_CO3_HMW84) +HeMorse93.update_cc("H", "Mg", prm.theta_H_Mg_HMW84) +HeMorse93.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +HeMorse93.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_HMW84) +HeMorse93.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_HMW84) +HeMorse93.update_cca("H", "Mg", "OH", prm.psi_H_Mg_OH_HMW84) +HeMorse93.update_cca("H", "Mg", "HCO3", prm.psi_H_Mg_HCO3_HMW84) +HeMorse93.update_cca("H", "Mg", "CO3", prm.psi_H_Mg_CO3_HMW84) +HeMorse93.update_cc("H", "MgOH", prm.theta_H_MgOH_HMW84) +HeMorse93.update_cca("H", "MgOH", "Cl", prm.psi_H_MgOH_Cl_HMW84) +HeMorse93.update_cca("H", "MgOH", "SO4", prm.psi_H_MgOH_SO4_HMW84) +HeMorse93.update_cca("H", "MgOH", "HSO4", prm.psi_H_MgOH_HSO4_HMW84) +HeMorse93.update_cca("H", "MgOH", "OH", prm.psi_H_MgOH_OH_HMW84) +HeMorse93.update_cca("H", "MgOH", "HCO3", prm.psi_H_MgOH_HCO3_HMW84) +HeMorse93.update_cca("H", "MgOH", "CO3", prm.psi_H_MgOH_CO3_HMW84) +# lambda +HeMorse93.update_nc("CO2", "H", prm.lambd_CO2_H_HMW84) +HeMorse93.update_nc("CO2", "Na", prm.lambd_CO2_Na_HMW84) +HeMorse93.update_nc("CO2", "K", prm.lambd_CO2_K_HMW84) +HeMorse93.update_nc("CO2", "Ca", prm.lambd_CO2_Ca_HMW84) +HeMorse93.update_nc("CO2", "Mg", prm.lambd_CO2_Mg_HMW84) +HeMorse93.update_na("CO2", "Cl", prm.lambd_CO2_Cl_HMW84) +HeMorse93.update_na("CO2", "SO4", prm.lambd_CO2_SO4_HMW84) +HeMorse93.update_na("CO2", "HSO4", prm.lambd_CO2_HSO4_HMW84) diff --git a/pytzer/libraries/MilleroThurmond83.py b/pytzer/libraries/MilleroThurmond83.py new file mode 100644 index 00000000..da14b356 --- /dev/null +++ b/pytzer/libraries/MilleroThurmond83.py @@ -0,0 +1,25 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +MilleroThurmond83 = ParameterLibrary(name="MilleroThurmond83") +MilleroThurmond83.update_Aphi(debyehueckel.Aosm_M88) +MilleroThurmond83.assign_func_J(unsymmetrical.Harvie) +# Table III, part 1 +MilleroThurmond83.update_ca("H", "Cl", prm.bC_H_Cl_PM73) +MilleroThurmond83.update_ca("Na", "Cl", prm.bC_Na_Cl_PM73) +MilleroThurmond83.update_ca("Mg", "Cl", prm.bC_Mg_Cl_PM73) +MilleroThurmond83.update_ca("Na", "HCO3", prm.bC_Na_HCO3_PP82) +MilleroThurmond83.update_ca("Na", "CO3", prm.bC_Na_CO3_PP82) +# Table III, part 2 +MilleroThurmond83.update_cc("H", "Na", prm.theta_H_Na_PK74) +MilleroThurmond83.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_RGB80) +MilleroThurmond83.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +MilleroThurmond83.update_cca("H", "Mg", "Cl", prm.psi_H_Na_Cl_PK74) +MilleroThurmond83.update_aa("Cl", "HCO3", prm.theta_HCO3_Cl_PP82) +MilleroThurmond83.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_PP82) +MilleroThurmond83.update_aa("Cl", "CO3", prm.theta_CO3_Cl_PP82) +MilleroThurmond83.update_caa("Na", "Cl", "CO3", prm.psi_Na_CO3_Cl_TM82) +MilleroThurmond83.update_cc("Na", "Mg", prm.theta_Mg_Na_HMW84) +MilleroThurmond83.update_cca("Na", "Mg", "Cl", prm.psi_Mg_Na_Cl_HMW84) diff --git a/pytzer/parameters.py b/pytzer/parameters.py index bfdaca7b..abadf13f 100644 --- a/pytzer/parameters.py +++ b/pytzer/parameters.py @@ -12139,3 +12139,126 @@ def theta_H_Na_HCW22(T, P): theta = 0.0306 - 0.000418 * (T - 298.15) valid = (T >= 278.15) & (T <= 318.15) return theta, valid + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Spencer et al. (1990) ~~~~~ +def SMW90_eq2(T, a): + """a contains the coefficients [a1, a2, a6, a9, a3, a4].""" + return a[0] + a[1] * T + a[2] * T**2 + a[3] * T**3 + a[4] / T + a[5] * np.log(T) + + +def bC_Mg_Cl_SMW90(T, P): + """c-a: magnesium chloride [SMW90].""" + b0 = SMW90_eq2( + T, + [ + 3.13852913e2, + 2.61769099e-1, + -2.46268460e-4, + 1.15764787e-7, + -5.53133381e3, + -6.21616862e1, + ], + ) + b1 = SMW90_eq2( + T, + [ + -3.18432525e4, + -2.86710358e1, + 2.78892838e-2, + -1.3279705e-5, + 5.24032958e5, + 6.40770396e3, + ], + ) + b2 = 0 + Cphi = SMW90_eq2( + T, + [ + 5.9532e-2, + -2.49949e-4, + 2.41831e-7, + 0, + 0, + 0, + 0, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T > 273.15 - 54) & (T <= 298.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_SO4_SMW90(T, P): + """c-a: magnesium sulfate [SMW90].""" + b0 = SMW90_eq2( + T, + [ + 5.40007849e3, + 4.90576884e0, + -4.80489750e-3, + 2.31126994e-6, + -8.80664146e4, + -1.08839565e3, + ], + ) + b1 = SMW90_eq2( + T, + [ + 2.78730869e0, + 4.30077440e-3, + 0, + 0, + 0, + 0, + ], + ) + b2 = 0 + Cphi = SMW90_eq2( + T, + [ + -5.88623653e2, + -5.05522880e-1, + 4.8277657e-4, + -2.3029838e-7, + 1.02002016e4, + 1.17303808e2, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T > 273.15 - 54) & (T <= 298.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def psi_Mg_Cl_SO4_SMW90(T, P): + """c-a-a': magnesium chloride sulfate [SMW90].""" + psi = SMW90_eq2( + T, + [ + -1.839158e-1, + 1.429444e-4, + 0, + 0, + 3.263e1, + 0, + ], + ) + valid = (T > 273.15 - 54) & (T <= 298.15) + return psi, valid + + +def psi_Mg_Cl_SO4_HM93(T, P): + """c-a-a': magnesium chloride sulfate [HM93].""" + psi = np.where( + T < 298.15, psi_Mg_Cl_SO4_SMW90(T, P)[0], psi_Mg_Cl_SO4_PP87ii(T, P)[0] + ) + valid = (T > 273.15 - 54) & (T < 523.25) + return psi, valid diff --git a/tests/test_H22.py b/tests/test_H22.py index c17503cb..bb8ac066 100644 --- a/tests/test_H22.py +++ b/tests/test_H22.py @@ -4,11 +4,11 @@ prmlib = pz.libraries.Waters13_Clegg22 totals = pz.odict() -totals["Na"] = 0.4861818 #- 0.04 +totals["Na"] = 0.4861818 # - 0.04 totals["Mg"] = 0.0547402 totals["Ca"] = 0.01075004 totals["K"] = 0.01058004 -totals["Cl"] = 0.5692021 #+ 0.02 +totals["Cl"] = 0.5692021 # + 0.02 totals["SO4"] = 0.02927011 # totals["tris"] = 0.04 diff --git a/tests/test_TM83.py b/tests/test_TM83.py new file mode 100644 index 00000000..c2098f20 --- /dev/null +++ b/tests/test_TM83.py @@ -0,0 +1,50 @@ +import pandas as pd, numpy as np +from matplotlib import pyplot as plt +import pytzer as pz + +# Import data from Table 1 +table1 = pd.DataFrame( + { + "Na": [0.485, 0.959, 1.96, 2.86, 3.83, 3.81, 4.76, 5.235, 5.222], + "Mg": [0.025, 0.05, 0.05, 0.15, 0.18, 0.2, 0.25, 0.275, 0.29], + "Cl": [0.525, 1.05, 2.05, 3.15, 4.182, 4.2, 5.25, 5.775, 5.79], + "HCO3": [ + 0.0015, + 0.00075, + 0.00043, + 0.00042, + 0.00063, + 0.00063, + 0.00067, + 0.00065, + 0.00066, + ], + "CO3": [0.0034, 0.0039, 0.0046, 0.0045, 0.0043, 0.0043, 0.0043, 0.0042, 0.0042], + "pks1": [5.973, 5.931, 5.946, 5.993, 6.071, 6.063, 6.152, 6.205, 6.22], + "pks2": [9.33, 9.15, 9.17, 8.95, 8.93, 8.93, 8.88, 8.93, 8.87], + } +) +table1["ionic_strength"] = ( + table1.Na + 4 * table1.Mg + table1.Cl + table1.HCO3 + 4 * table1.CO3 +) / 2 +table1["sqrt_is"] = np.sqrt(table1.ionic_strength) + +fig, ax = plt.subplots(dpi=300) +ax.scatter("sqrt_is", "pks1", c="Mg", data=table1) + +# # Calculate total salts +# table1["MgCl2"] = table1.Mg.copy() +# table1["NaCl"] = table1.Cl - 2 * table1.MgCl2 +# table1["NaCO3"] = table1.Na - table1.NaCl +# table1["dic"] = table1.NaCO3 / 2 + +# # Solve +# totals = pz.odict() +# totals["Na"] = table1.loc[0, "Na"] +# totals["Mg"] = table1.loc[0, "Mg"] +# totals["Cl"] = table1.loc[0, "Cl"] +# totals["CO2"] = table1.loc[0, "dic"] +# solutes, pks = pz.solve(totals) +# pH = 10 ** -solutes["H"].item() + +# test = pz.solve_df(table1[["Na", "Mg", "Cl", "dic"]].rename(columns={"dic": "CO2"})) From 35c707c71e227c5c5d2570fe56bb45d191c3edf8 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 22 Feb 2022 12:45:26 +0100 Subject: [PATCH 16/58] Testing and fixes --- docs/refs.md | 15 + pytzer/dissociation.py | 23 + pytzer/libraries/HeMorse93.py | 52 +- pytzer/libraries/MyMarChemSpecCO2.py | 261 ++++++++ pytzer/libraries/__init__.py | 4 + .../{parameters.py => parameters/__init__.py} | 560 ++---------------- pytzer/parameters/heMorse1993.py | 285 +++++++++ pytzer/parameters/holmes1987.py | 5 + pytzer/parameters/holmesMesmer1992.py | 89 +++ pytzer/parameters/pabalanPitzer1987.py | 117 ++++ pytzer/parameters/spencer1990.py | 123 ++++ tests/test_H22.py | 1 + tests/test_HM93.py | 8 + tests/test_PB82.py | 30 + tests/test_TM82.py | 66 +++ tests/untitled0.py | 28 - 16 files changed, 1113 insertions(+), 554 deletions(-) create mode 100644 pytzer/libraries/MyMarChemSpecCO2.py rename pytzer/{parameters.py => parameters/__init__.py} (95%) create mode 100644 pytzer/parameters/heMorse1993.py create mode 100644 pytzer/parameters/holmes1987.py create mode 100644 pytzer/parameters/holmesMesmer1992.py create mode 100644 pytzer/parameters/pabalanPitzer1987.py create mode 100644 pytzer/parameters/spencer1990.py create mode 100644 tests/test_HM93.py create mode 100644 tests/test_PB82.py create mode 100644 tests/test_TM82.py diff --git a/docs/refs.md b/docs/refs.md index d00dbd9d..93a1ab6d 100644 --- a/docs/refs.md +++ b/docs/refs.md @@ -60,6 +60,9 @@ ??? citation "H73: Hansson (1973) *Deep-Sea Res.*" Hansson, I. (1973). A new set of acidity constants for carbonic acid and boric acid in sea water. *Deep-Sea Research* 20, 461–478. doi:10.1016/0011-7471(73)90100-9. +??? citation "HBS87: Holmes et al. (1987) *J. Chem. Thermodyn.*" + Holmes, H. F., Busey, R. H., Simonson, J. M., Mesmer, R. E., Archer, D. G., and Wood, R. H. (1987). The enthalpy of dilution of HCl(aq) to 648 K and 40 MPa thermodynamic properties. *Journal of Chemical Thermodynamics* 19(8), 863-890. [doi:10.1016/0021-9614(87)90033-4](https://doi.org/10.1016/0021-9614(87)90033-4) + ??? citation "HFM89: Hershey et al. (1989) *J. Solution Chem.*" Hershey, J. P., Fernandez, M., and Millero, F. J. (1989). The dissociation of phosphoric acid in NaCl and NaMgCl solutions at 25°C. *Journal of Solution Chemistry* 18(9), 875–891. [doi:10.1007/BF00685063](https://doi.org/10.1007/BF00685063) @@ -75,6 +78,12 @@ ??? citation "HM86: Holmes & Mesmer (1986) *J. Solution Chem.*" Holmes, H. F., and Mesmer, R. E. (1986). Thermodynamics of aqueous solutions of the alkali metal sulfates. *Journal of Solution Chemistry* 15, 495–517. [doi:10.1007/BF00644892](https://doi.org/10.1007/BF00644892) +??? citation "HM92: Holmes & Mesmer (1992) *J. Chem. Thermodyn.*" + Holmes, H. F., and Mesmer, R. E. (1992). Isopiestic studies of H2SO4(aq) at elevated temperatures: Thermodynamic properties. *Journal of Chemical Thermodynamics* 24(3), 317-328. [doi:10.1016/S0021-9614(05)80072-2](https://doi.org/10.1016/S0021-9614(05)80072-2) + +??? citation "HM93: He & Morse (1993) *Geochim. Cosmochim. Acta*" + He, S., and Morse, J. W. (1993). The carbonic acid system and calcite solubility in aqueous Na-K-Ca-Mg-Cl-SO4 solutions from 0 to 90°C. *Geochimica et Cosmochimica Acta* 57(15), 3533-3554. [doi:10.1016/0016-7037(93)90137-L](https://doi.org/10.1016/0016-7037(93)90137-L) + ??? citation "HPM88: Hershey et al. (1988) *Geochim. Cosmochim. Acta*" Hershey, J. P., Plese, T., and Millero, F. J. (1988). The p*K*1\* for the dissociation of H2S in various ionic media. *Geochimica et Cosmochimica Acta* 52, 2047–2051. [doi:10.1016/0016-7037(88)90183-4](https://doi.org/10.1016/0016-7037(88)90183-4) @@ -130,6 +139,9 @@ ??? citation "P91: Pitzer (1991) *Activity Coefficients in Electrolyte Solutions*" Pitzer, K. S. (1991). “Ion Interaction Approach: Theory and Data Correlation,” in *Activity Coefficients in Electrolyte Solutions, 2nd Edition*, ed. K. S. Pitzer (CRC Press, Florida, USA), 75–153. +??? citation "PB82: Plummer & Busenberg (1982) *Geochim. Cosmochim. Acta*" + Plummer, L. N., and Busenberg, E. (1982). The solubilities of calcite, aragonite and vaterite in CO2-H2O solutions between 0 and 90°C, and an evaluation of the aqueous model for the system CaCO3-CO2-H2O. *Geochimica et Cosmochimica Acta* 46(6), 1011-1040. [doi:10.1016/0016-7037(82)90056-4](https://doi.org/10.1016/0016-7037(82)90056-4) + ??? citation "PMR97: Pierrot et al. (1997) *J. Solution Chem.*" Pierrot, D., Millero, F. J., Roy, L. N., Roy, R. N., Doneski, A., and Niederschmidt, J. (1997). The activity coefficients of HCl in HCl−Na2SO4 solutions from 0 to 50°C and ionic strengths up to 6 molal. *Journal of Solution Chemistry* 26(1), 31–45. [doi:10.1007/BF02439442](https://doi.org/10.1007/BF02439442) @@ -170,6 +182,9 @@ ### S +??? citation "SMW90: Spencer et al. (1990) *Geochim. Cosmochim. Acta*" + Spencer, R. J., Møller, N., and Weare, J. H. (1990). The prediction of mineral solubilities in natural waters: A chemical equilibrium model for the Na-K-Ca-Mg-Cl-SO4-H2O system at temperatures below 25°C. *Geochimica et Cosmochimica Acta* 54(3), 575-590. [doi:10.1016/0016-7037(90)90354-N](https://doi.org/10.1016/0016-7037(90)90354-N) + ??? citation "SRG87: Simonson et al. (1987) *J. Chem. Eng. Data*" Simonson, J. M., Roy, R. N., and Gibbons, J. J. (1987). Thermodynamics of Aqueous Mixed Potassium Carbonate, Bicarbonate, and Chloride Solutions to 368 K. *Journal of Chemical & Engineering Data* 32(1), 41–45. [doi:10.1021/je00047a011](https://doi.org/10.1021/je00047a011) diff --git a/pytzer/dissociation.py b/pytzer/dissociation.py index 7a6deaac..59d49357 100644 --- a/pytzer/dissociation.py +++ b/pytzer/dissociation.py @@ -148,6 +148,29 @@ def HCO3_MP98(T=298.15): return _MP98_eq23(T, A=207.6548, B=-11843.79, C=-33.6485) +def _PB82_eq(T, A, B, C, D, E): + """Returns log10(K).""" + return A + B * T + C / T + D * np.log10(T) + E / T**2 + + +def H2CO3_PB82(T=298.15): + """H2CO3 dissociation [PB82].""" + log10_kH2CO3 = _PB82_eq(T, -356.3094, -0.06091964, 21834.37, 126.8339, -1684915) + return ln10 * log10_kH2CO3 + + +def HCO3_PB82(T=298.15): + """HCO3 dissociation [PB82].""" + log10_kHCO3 = _PB82_eq(T, -107.8871, -0.03252849, 5151.79, 38.9256, -563713.9) + return ln10 * log10_kHCO3 + + +def CO2_PB82(T=298.15): + """CO2 solubility (Henry's law constant) [PB82].""" + log10_kCO2 = _PB82_eq(T, 108.3865, 0.01985076, -6919.53, -40.4515, 669365) + return ln10 * log10_kCO2 + + def H3PO4_MP98(T=298.15): """H3PO4 dissociation [MP98 following B51].""" return _MP98_eq23(T, A=115.54, B=-4576.7518, C=-18.453) diff --git a/pytzer/libraries/HeMorse93.py b/pytzer/libraries/HeMorse93.py index effd83a4..16267195 100644 --- a/pytzer/libraries/HeMorse93.py +++ b/pytzer/libraries/HeMorse93.py @@ -1,5 +1,9 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. # Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""He & Morse (1993) Geochim. Cosmochim. Acta 57(15), 3533-3554. +https://doi.org/10.1016/0016-7037(93)90137-L +""" + from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical @@ -11,26 +15,26 @@ HeMorse93.update_ca("Na", "SO4", prm.bC_Na_SO4_M88) HeMorse93.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HMW84) HeMorse93.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) -HeMorse93.update_ca("Na", "HCO3", prm.bC_Na_HCO3_HMW84) -HeMorse93.update_ca("Na", "CO3", prm.bC_Na_CO3_HMW84) +HeMorse93.update_ca("Na", "HCO3", prm.bC_Na_HCO3_HM93) +HeMorse93.update_ca("Na", "CO3", prm.bC_Na_CO3_HM93) HeMorse93.update_ca("K", "Cl", prm.bC_K_Cl_GM89) HeMorse93.update_ca("K", "SO4", prm.bC_K_SO4_GM89) HeMorse93.update_ca("K", "HSO4", prm.bC_K_HSO4_HMW84) HeMorse93.update_ca("K", "OH", prm.bC_K_OH_HMW84) -HeMorse93.update_ca("K", "HCO3", prm.bC_K_HCO3_HMW84) -HeMorse93.update_ca("K", "CO3", prm.bC_K_CO3_HMW84) +HeMorse93.update_ca("K", "HCO3", prm.bC_K_HCO3_HM93) +HeMorse93.update_ca("K", "CO3", prm.bC_K_CO3_HM93) HeMorse93.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) HeMorse93.update_ca("Ca", "SO4", prm.bC_Ca_SO4_M88) HeMorse93.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_HMW84) HeMorse93.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) -HeMorse93.update_ca("Ca", "HCO3", prm.bC_Ca_HCO3_HMW84) -HeMorse93.update_ca("Ca", "CO3", prm.bC_Ca_CO3_HMW84) +HeMorse93.update_ca("Ca", "HCO3", prm.bC_Ca_HCO3_HM93) +HeMorse93.update_ca("Ca", "CO3", prm.bC_Ca_CO3_HM93) HeMorse93.update_ca("Mg", "Cl", prm.bC_Mg_Cl_SMW90) HeMorse93.update_ca("Mg", "SO4", prm.bC_Mg_SO4_SMW90) HeMorse93.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_HMW84) HeMorse93.update_ca("Mg", "OH", prm.bC_Mg_OH_HMW84) -HeMorse93.update_ca("Mg", "HCO3", prm.bC_Mg_HCO3_HMW84) -HeMorse93.update_ca("Mg", "CO3", prm.bC_Mg_CO3_HMW84) +HeMorse93.update_ca("Mg", "HCO3", prm.bC_Mg_HCO3_HM93) +HeMorse93.update_ca("Mg", "CO3", prm.bC_Mg_CO3_HM93) HeMorse93.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) HeMorse93.update_ca("MgOH", "SO4", prm.bC_MgOH_SO4_HMW84) HeMorse93.update_ca("MgOH", "HSO4", prm.bC_MgOH_HSO4_HMW84) @@ -38,8 +42,8 @@ HeMorse93.update_ca("MgOH", "HCO3", prm.bC_MgOH_HCO3_HMW84) HeMorse93.update_ca("MgOH", "CO3", prm.bC_MgOH_CO3_HMW84) HeMorse93.update_ca("H", "Cl", prm.bC_H_Cl_HMW84) -HeMorse93.update_ca("H", "SO4", prm.bC_H_SO4_HMW84) -HeMorse93.update_ca("H", "HSO4", prm.bC_H_HSO4_HMW84) +HeMorse93.update_ca("H", "SO4", prm.bC_H_SO4_HM92) +HeMorse93.update_ca("H", "HSO4", prm.bC_H_HSO4_HM92) HeMorse93.update_ca("H", "OH", prm.bC_H_OH_HMW84) HeMorse93.update_ca("H", "HCO3", prm.bC_H_HCO3_HMW84) HeMorse93.update_ca("H", "CO3", prm.bC_H_CO3_HMW84) @@ -79,7 +83,7 @@ HeMorse93.update_caa("Mg", "CO3", "Cl", prm.psi_Mg_CO3_Cl_HMW84) HeMorse93.update_caa("MgOH", "CO3", "Cl", prm.psi_MgOH_CO3_Cl_HMW84) HeMorse93.update_caa("H", "CO3", "Cl", prm.psi_H_CO3_Cl_HMW84) -HeMorse93.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_HMW84) +HeMorse93.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_HM92) HeMorse93.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) HeMorse93.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) HeMorse93.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_HMW84) @@ -255,11 +259,23 @@ HeMorse93.update_cca("H", "MgOH", "HCO3", prm.psi_H_MgOH_HCO3_HMW84) HeMorse93.update_cca("H", "MgOH", "CO3", prm.psi_H_MgOH_CO3_HMW84) # lambda -HeMorse93.update_nc("CO2", "H", prm.lambd_CO2_H_HMW84) -HeMorse93.update_nc("CO2", "Na", prm.lambd_CO2_Na_HMW84) -HeMorse93.update_nc("CO2", "K", prm.lambd_CO2_K_HMW84) -HeMorse93.update_nc("CO2", "Ca", prm.lambd_CO2_Ca_HMW84) -HeMorse93.update_nc("CO2", "Mg", prm.lambd_CO2_Mg_HMW84) -HeMorse93.update_na("CO2", "Cl", prm.lambd_CO2_Cl_HMW84) -HeMorse93.update_na("CO2", "SO4", prm.lambd_CO2_SO4_HMW84) +HeMorse93.update_nc("CO2", "H", prm.lambd_CO2_H_HM93) +HeMorse93.update_nc("CO2", "Na", prm.lambd_CO2_Na_HM93) +HeMorse93.update_nc("CO2", "K", prm.lambd_CO2_K_HM93) +HeMorse93.update_nc("CO2", "Ca", prm.lambd_CO2_Ca_HM93) +HeMorse93.update_nc("CO2", "Mg", prm.lambd_CO2_Mg_HM93) +HeMorse93.update_na("CO2", "Cl", prm.lambd_CO2_Cl_HM93) +HeMorse93.update_na("CO2", "SO4", prm.lambd_CO2_SO4_HM93) HeMorse93.update_na("CO2", "HSO4", prm.lambd_CO2_HSO4_HMW84) +# zeta +HeMorse93.update_nca("CO2", "H", "Cl", prm.zeta_CO2_H_Cl_HM93) +HeMorse93.update_nca("CO2", "Na", "Cl", prm.zeta_CO2_Na_Cl_HM93) +HeMorse93.update_nca("CO2", "K", "Cl", prm.zeta_CO2_K_Cl_HM93) +HeMorse93.update_nca("CO2", "Mg", "Cl", prm.zeta_CO2_Mg_Cl_HM93) +HeMorse93.update_nca("CO2", "Ca", "Cl", prm.zeta_CO2_Ca_Cl_HM93) +HeMorse93.update_nca("CO2", "H", "SO4", prm.zeta_CO2_H_SO4_HM93) +HeMorse93.update_nca("CO2", "Na", "SO4", prm.zeta_CO2_Na_SO4_HM93) +HeMorse93.update_nca("CO2", "K", "SO4", prm.zeta_CO2_K_SO4_HM93) +HeMorse93.update_nca("CO2", "Mg", "SO4", prm.zeta_CO2_Mg_SO4_HM93) +# Equilibria +HeMorse93.update_equilibrium("H2O", k.H2O_MF) diff --git a/pytzer/libraries/MyMarChemSpecCO2.py b/pytzer/libraries/MyMarChemSpecCO2.py new file mode 100644 index 00000000..5a7a2243 --- /dev/null +++ b/pytzer/libraries/MyMarChemSpecCO2.py @@ -0,0 +1,261 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""Waters & Millero (2013). +*Marine Chemistry* 149, 8--22. +doi:10.1016/j.marchem.2012.11.003 +according to Clegg et al. (2022) +with CO2-system terms added +""" +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +MyMarChemSpecCO2 = ParameterLibrary(name="MyMarChemSpecCO2") +MyMarChemSpecCO2.update_Aphi(debyehueckel.Aosm_M88) +MyMarChemSpecCO2.assign_func_J(unsymmetrical.Harvie) +# Table A1: Na salts +MyMarChemSpecCO2.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +# MyMarChemSpecCO2.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) +# MyMarChemSpecCO2.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +MyMarChemSpecCO2.update_ca("Na", "OH", prm.bC_Na_OH_PP87i) +# # Table A2: Mg salts +# MyMarChemSpecCO2.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +# MyMarChemSpecCO2.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +# MyMarChemSpecCO2.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +# # Table A3: Ca salts +# MyMarChemSpecCO2.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +# MyMarChemSpecCO2.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +# MyMarChemSpecCO2.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +# MyMarChemSpecCO2.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +# # Table A4: K salts +# MyMarChemSpecCO2.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +# MyMarChemSpecCO2.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +# MyMarChemSpecCO2.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +# MyMarChemSpecCO2.update_ca("K", "OH", prm.bC_K_OH_HMW84) +# Table A5: H+ interactions +MyMarChemSpecCO2.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +# MyMarChemSpecCO2.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +# MyMarChemSpecCO2.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +# # Table A6: MgOH+ interactions +# MyMarChemSpecCO2.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +# Table A7: cation-cation interactions +MyMarChemSpecCO2.update_cc("H", "Na", prm.theta_H_Na_HCW22) # different from WM13 +# MyMarChemSpecCO2.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +# MyMarChemSpecCO2.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +# MyMarChemSpecCO2.update_cc("H", "K", prm.theta_H_K_CMR93) +# MyMarChemSpecCO2.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +# MyMarChemSpecCO2.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +# MyMarChemSpecCO2.update_cc("K", "Na", prm.theta_K_Na_HMW84) +# MyMarChemSpecCO2.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +# MyMarChemSpecCO2.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +# MyMarChemSpecCO2.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +# # Table A7: anion-anion interactions +# MyMarChemSpecCO2.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +MyMarChemSpecCO2.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +# MyMarChemSpecCO2.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +# MyMarChemSpecCO2.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +# Table A8: c-a-a' triplets +# MyMarChemSpecCO2.update_caa("H", "Cl", "SO4", prm.psi_H_Cl_SO4_WM13) +# MyMarChemSpecCO2.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "Cl", "SO4", prm.psi_K_Cl_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "Cl", "HSO4", prm.psi_Mg_Cl_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "Cl", "HSO4", prm.psi_Ca_Cl_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "Cl", "HSO4", prm.psi_K_Cl_HSO4_HMW84) +MyMarChemSpecCO2.update_caa("H", "Cl", "OH", prm.psi_H_Cl_OH_WM13) +MyMarChemSpecCO2.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "Cl", "OH", prm.psi_Mg_Cl_OH_WM13) +# MyMarChemSpecCO2.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +# MyMarChemSpecCO2.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +# MyMarChemSpecCO2.update_caa("H", "HSO4", "SO4", prm.psi_H_HSO4_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +# MyMarChemSpecCO2.update_caa("Ca", "HSO4", "SO4", prm.psi_Ca_HSO4_SO4_WM13) +# MyMarChemSpecCO2.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "OH", "SO4", prm.psi_H_OH_SO4_WM13) +# MyMarChemSpecCO2.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "OH", "SO4", prm.psi_Mg_OH_SO4_WM13) +# MyMarChemSpecCO2.update_caa("Ca", "OH", "SO4", prm.psi_Ca_OH_SO4_WM13) +# MyMarChemSpecCO2.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +# Table A9: c-c'-a triplets +MyMarChemSpecCO2.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Na", "SO4", prm.psi_H_Na_SO4_WM13) +# MyMarChemSpecCO2.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +# MyMarChemSpecCO2.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +# MyMarChemSpecCO2.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "H", "SO4", prm.psi_Ca_H_SO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "H", "HSO4", prm.psi_Ca_H_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "HSO4", prm.psi_Mg_Na_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "HSO4", prm.psi_Ca_Na_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Na", "HSO4", prm.psi_K_Na_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "HSO4", prm.psi_Ca_Mg_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Mg", "HSO4", prm.psi_K_Mg_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "K", "SO4", prm.psi_Ca_K_SO4_WM13) +# MyMarChemSpecCO2.update_cca("Ca", "K", "HSO4", prm.psi_Ca_K_HSO4_WM13) +# MyMarChemSpecCO2.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) # not in WM13 +# Add equilibria +# MyMarChemSpecCO2.update_equilibrium("HSO4", k.HSO4_CRP94) +# MyMarChemSpecCO2.update_equilibrium("MgOH", k.MgOH_CW91_ln) +MyMarChemSpecCO2.update_equilibrium("H2O", k.H2O_M79) +# # Extras from Clegg22 (all before this point is from Humphreys22) +# MyMarChemSpecCO2.update_equilibrium("trisH", k.trisH_BH61) +# MyMarChemSpecCO2.update_ca("trisH", "Cl", prm.bC_trisH_Cl_CHW21) +# MyMarChemSpecCO2.update_ca("trisH", "SO4", prm.bC_trisH_SO4_CHW21) +# MyMarChemSpecCO2.update_nc("tris", "Ca", prm.lambd_tris_Ca_CHW21) +# MyMarChemSpecCO2.update_nc("tris", "K", prm.lambd_tris_K_CHW21) +# MyMarChemSpecCO2.update_nc("tris", "Mg", prm.lambd_tris_Mg_CHW21) +# MyMarChemSpecCO2.update_nc("tris", "Na", prm.lambd_tris_Na_CHW21) +# MyMarChemSpecCO2.update_nc("tris", "trisH", prm.lambd_tris_trisH_LTA21) +# MyMarChemSpecCO2.update_na("tris", "SO4", prm.lambd_tris_SO4_LTA21) +# MyMarChemSpecCO2.update_nn("tris", "tris", prm.lambd_tris_tris_LTA21) +# MyMarChemSpecCO2.update_nnn("tris", prm.mu_tris_tris_tris_LTA21) + +MyMarChemSpecCO2.update_equilibrium("H2CO3", k.H2CO3_PB82) +MyMarChemSpecCO2.update_equilibrium("HCO3", k.HCO3_PB82) +# still needs CaCO3, MgCO3 formation! + +# Added CO2 system from HM93 +MyMarChemSpecCO2.update_ca("Na", "HCO3", prm.bC_Na_HCO3_HM93) +MyMarChemSpecCO2.update_ca("Na", "CO3", prm.bC_Na_CO3_HM93) +# MyMarChemSpecCO2.update_ca("K", "HCO3", prm.bC_K_HCO3_HM93) +# MyMarChemSpecCO2.update_ca("K", "CO3", prm.bC_K_CO3_HM93) +# MyMarChemSpecCO2.update_ca("Ca", "HCO3", prm.bC_Ca_HCO3_HM93) +# MyMarChemSpecCO2.update_ca("Ca", "CO3", prm.bC_Ca_CO3_HM93) +# MyMarChemSpecCO2.update_ca("Mg", "HCO3", prm.bC_Mg_HCO3_HM93) +# MyMarChemSpecCO2.update_ca("Mg", "CO3", prm.bC_Mg_CO3_HM93) +# MyMarChemSpecCO2.update_ca("MgOH", "HCO3", prm.bC_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_ca("MgOH", "CO3", prm.bC_MgOH_CO3_HMW84) +MyMarChemSpecCO2.update_ca("H", "HCO3", prm.bC_H_HCO3_HMW84) +MyMarChemSpecCO2.update_ca("H", "CO3", prm.bC_H_CO3_HMW84) +# thetas and psis +MyMarChemSpecCO2.update_aa("Cl", "HCO3", prm.theta_Cl_HCO3_HMW84) +MyMarChemSpecCO2.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("K", "Cl", "HCO3", prm.psi_K_Cl_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "Cl", "HCO3", prm.psi_Ca_Cl_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "Cl", "HCO3", prm.psi_Mg_Cl_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "Cl", "HCO3", prm.psi_MgOH_Cl_HCO3_HMW84) +MyMarChemSpecCO2.update_caa("H", "Cl", "HCO3", prm.psi_H_Cl_HCO3_HMW84) +MyMarChemSpecCO2.update_aa("CO3", "Cl", prm.theta_CO3_Cl_HMW84) +MyMarChemSpecCO2.update_caa("Na", "CO3", "Cl", prm.psi_Na_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "Cl", prm.psi_K_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "Cl", prm.psi_Ca_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "Cl", prm.psi_Mg_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "Cl", prm.psi_MgOH_CO3_Cl_HMW84) +MyMarChemSpecCO2.update_caa("H", "CO3", "Cl", prm.psi_H_CO3_Cl_HMW84) +# MyMarChemSpecCO2.update_aa("HCO3", "SO4", prm.theta_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "HCO3", "SO4", prm.psi_Na_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "HCO3", "SO4", prm.psi_K_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "HCO3", "SO4", prm.psi_Ca_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "HCO3", "SO4", prm.psi_Mg_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "HCO3", "SO4", prm.psi_MgOH_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "HCO3", "SO4", prm.psi_H_HCO3_SO4_HMW84) +# MyMarChemSpecCO2.update_aa("CO3", "SO4", prm.theta_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "CO3", "SO4", prm.psi_Na_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "SO4", prm.psi_K_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "SO4", prm.psi_Ca_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "SO4", prm.psi_Mg_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "SO4", prm.psi_MgOH_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "CO3", "SO4", prm.psi_H_CO3_SO4_HMW84) +# MyMarChemSpecCO2.update_aa("HCO3", "HSO4", prm.theta_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "HCO3", "HSO4", prm.psi_Na_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "HCO3", "HSO4", prm.psi_K_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "HCO3", "HSO4", prm.psi_Ca_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "HCO3", "HSO4", prm.psi_Mg_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "HCO3", "HSO4", prm.psi_MgOH_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "HCO3", "HSO4", prm.psi_H_HCO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_aa("CO3", "HSO4", prm.theta_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Na", "CO3", "HSO4", prm.psi_Na_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "HSO4", prm.psi_K_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "HSO4", prm.psi_Ca_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "HSO4", prm.psi_Mg_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "HSO4", prm.psi_MgOH_CO3_HSO4_HMW84) +# MyMarChemSpecCO2.update_caa("H", "CO3", "HSO4", prm.psi_H_CO3_HSO4_HMW84) +MyMarChemSpecCO2.update_aa("HCO3", "OH", prm.theta_HCO3_OH_HMW84) +MyMarChemSpecCO2.update_caa("Na", "HCO3", "OH", prm.psi_Na_HCO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("K", "HCO3", "OH", prm.psi_K_HCO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "HCO3", "OH", prm.psi_Ca_HCO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "HCO3", "OH", prm.psi_Mg_HCO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "HCO3", "OH", prm.psi_MgOH_HCO3_OH_HMW84) +MyMarChemSpecCO2.update_caa("H", "HCO3", "OH", prm.psi_H_HCO3_OH_HMW84) +MyMarChemSpecCO2.update_aa("CO3", "OH", prm.theta_CO3_OH_HMW84) +MyMarChemSpecCO2.update_caa("Na", "CO3", "OH", prm.psi_Na_CO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "OH", prm.psi_K_CO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "OH", prm.psi_Ca_CO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "OH", prm.psi_Mg_CO3_OH_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "OH", prm.psi_MgOH_CO3_OH_HMW84) +MyMarChemSpecCO2.update_caa("H", "CO3", "OH", prm.psi_H_CO3_OH_HMW84) +MyMarChemSpecCO2.update_aa("CO3", "HCO3", prm.theta_CO3_HCO3_HMW84) +MyMarChemSpecCO2.update_caa("Na", "CO3", "HCO3", prm.psi_Na_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("K", "CO3", "HCO3", prm.psi_K_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("Ca", "CO3", "HCO3", prm.psi_Ca_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("Mg", "CO3", "HCO3", prm.psi_Mg_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_caa("MgOH", "CO3", "HCO3", prm.psi_MgOH_CO3_HCO3_HMW84) +MyMarChemSpecCO2.update_caa("H", "CO3", "HCO3", prm.psi_H_CO3_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Na", "HCO3", prm.psi_K_Na_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Na", "CO3", prm.psi_K_Na_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "HCO3", prm.psi_Ca_Na_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Na", "CO3", prm.psi_Ca_Na_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "HCO3", prm.psi_Mg_Na_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "Na", "CO3", prm.psi_Mg_Na_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("MgOH", "Na", "HCO3", prm.psi_MgOH_Na_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("MgOH", "Na", "CO3", prm.psi_MgOH_Na_CO3_HMW84) +MyMarChemSpecCO2.update_cca("H", "Na", "HCO3", prm.psi_H_Na_HCO3_HMW84) +MyMarChemSpecCO2.update_cca("H", "Na", "CO3", prm.psi_H_Na_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "K", "HCO3", prm.psi_Ca_K_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "K", "CO3", prm.psi_Ca_K_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Mg", "HCO3", prm.psi_K_Mg_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "Mg", "CO3", prm.psi_K_Mg_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "MgOH", "HCO3", prm.psi_K_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("K", "MgOH", "CO3", prm.psi_K_MgOH_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "K", "HCO3", prm.psi_H_K_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "K", "CO3", prm.psi_H_K_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "HCO3", prm.psi_Ca_Mg_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "Mg", "CO3", prm.psi_Ca_Mg_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "MgOH", "HCO3", prm.psi_Ca_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "MgOH", "CO3", prm.psi_Ca_MgOH_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "H", "HCO3", prm.psi_Ca_H_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Ca", "H", "CO3", prm.psi_Ca_H_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "MgOH", "HCO3", prm.psi_Mg_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("Mg", "MgOH", "CO3", prm.psi_Mg_MgOH_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Mg", "HCO3", prm.psi_H_Mg_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "Mg", "CO3", prm.psi_H_Mg_CO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "MgOH", "HCO3", prm.psi_H_MgOH_HCO3_HMW84) +# MyMarChemSpecCO2.update_cca("H", "MgOH", "CO3", prm.psi_H_MgOH_CO3_HMW84) +# lambda +MyMarChemSpecCO2.update_nc("CO2", "H", prm.lambd_CO2_H_HM93) +MyMarChemSpecCO2.update_nc("CO2", "Na", prm.lambd_CO2_Na_HM93) +# MyMarChemSpecCO2.update_nc("CO2", "K", prm.lambd_CO2_K_HM93) +# MyMarChemSpecCO2.update_nc("CO2", "Ca", prm.lambd_CO2_Ca_HM93) +# MyMarChemSpecCO2.update_nc("CO2", "Mg", prm.lambd_CO2_Mg_HM93) +MyMarChemSpecCO2.update_na("CO2", "Cl", prm.lambd_CO2_Cl_HM93) +# MyMarChemSpecCO2.update_na("CO2", "SO4", prm.lambd_CO2_SO4_HM93) +# MyMarChemSpecCO2.update_na("CO2", "HSO4", prm.lambd_CO2_HSO4_HMW84) +# zeta +MyMarChemSpecCO2.update_nca("CO2", "H", "Cl", prm.zeta_CO2_H_Cl_HM93) +MyMarChemSpecCO2.update_nca("CO2", "Na", "Cl", prm.zeta_CO2_Na_Cl_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "K", "Cl", prm.zeta_CO2_K_Cl_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "Mg", "Cl", prm.zeta_CO2_Mg_Cl_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "Ca", "Cl", prm.zeta_CO2_Ca_Cl_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "H", "SO4", prm.zeta_CO2_H_SO4_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "Na", "SO4", prm.zeta_CO2_Na_SO4_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "K", "SO4", prm.zeta_CO2_K_SO4_HM93) +# MyMarChemSpecCO2.update_nca("CO2", "Mg", "SO4", prm.zeta_CO2_Mg_SO4_HM93) diff --git a/pytzer/libraries/__init__.py b/pytzer/libraries/__init__.py index ef65c75d..13cb4b16 100644 --- a/pytzer/libraries/__init__.py +++ b/pytzer/libraries/__init__.py @@ -5,10 +5,12 @@ from .Clegg94 import Clegg94 from .Greenberg89 import Greenberg89 from .Harvie84 import Harvie84 +from .HeMorse93 import HeMorse93 from .MarChemSpec import MarChemSpec from .MarChemSpec25 import MarChemSpec25 from .Millero98 import Millero98 from .Moller88 import Moller88 +from .MyMarChemSpecCO2 import MyMarChemSpecCO2 from .Seawater import Seawater from .Waters13 import Waters13 from .Waters13_Humphreys22 import Waters13_Humphreys22 @@ -19,6 +21,8 @@ CRP94 = Clegg94 GM89 = Greenberg89 HMW84 = Harvie84 +HM93 = HeMorse93 +myMCS = MyMarChemSpecCO2 MCS = MarChemSpec MCS25 = MarChemSpec25 MP98 = MIAMI = Millero98 diff --git a/pytzer/parameters.py b/pytzer/parameters/__init__.py similarity index 95% rename from pytzer/parameters.py rename to pytzer/parameters/__init__.py index abadf13f..5291ab64 100644 --- a/pytzer/parameters.py +++ b/pytzer/parameters/__init__.py @@ -2,8 +2,57 @@ # Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) """Evaluate Pitzer model interaction parameters.""" from jax import numpy as np -from .constants import Tzero -from .convert import solute_to_charge as i2c +from ..constants import Tzero +from ..convert import solute_to_charge as i2c +from .heMorse1993 import ( + bC_Ca_CO3_HM93, + bC_Ca_HCO3_HM93, + bC_K_CO3_HM93, + bC_K_HCO3_HM93, + bC_Mg_CO3_HM93, + bC_Mg_HCO3_HM93, + bC_Na_CO3_HM93, + bC_Na_HCO3_HM93, + psi_Mg_Cl_SO4_HM93, + lambd_CO2_Ca_HM93, + lambd_CO2_Cl_HM93, + lambd_CO2_H_HM93, + lambd_CO2_K_HM93, + lambd_CO2_Mg_HM93, + lambd_CO2_Na_HM93, + lambd_CO2_SO4_HM93, + zeta_CO2_Ca_Cl_HM93, + zeta_CO2_H_Cl_HM93, + zeta_CO2_H_SO4_HM93, + zeta_CO2_K_Cl_HM93, + zeta_CO2_K_SO4_HM93, + zeta_CO2_Mg_Cl_HM93, + zeta_CO2_Mg_SO4_HM93, + zeta_CO2_Na_Cl_HM93, + zeta_CO2_Na_SO4_HM93, +) +from .holmesMesmer1992 import bC_H_HSO4_HM92, bC_H_SO4_HM92, theta_HSO4_SO4_HM92 +from .pabalanPitzer1987 import ( + theta_K_Na_PP87ii, + theta_Mg_Na_PP87ii, + theta_K_Mg_PP87ii, + theta_Cl_SO4_PP87ii, + theta_Cl_OH_PP87ii, + theta_OH_SO4_PP87ii, + psi_K_Na_Cl_PP87ii, + psi_Mg_Na_Cl_PP87ii, + psi_K_Mg_Cl_PP87ii, + psi_Na_Cl_SO4_PP87ii, + psi_K_Cl_SO4_PP87ii, + psi_Mg_Cl_SO4_PP87ii, + psi_Na_Cl_OH_PP87ii, + psi_Na_OH_SO4_PP87ii, +) +from .spencer1990 import ( + bC_Mg_Cl_SMW90, + bC_Mg_SO4_SMW90, + psi_Mg_Cl_SO4_SMW90, +) # Tolerances for np.isclose() assessment of temperature/pressure validity temperature_tol = dict(atol=1e-8, rtol=0) # K @@ -4979,7 +5028,7 @@ def theta_Cl_HCO3_HMW84(T, P): def psi_Na_Cl_HCO3_HMW84(T, P): """c-a-a': sodium chloride bicarbonate [HMW84].""" - psi = -0.15 + psi = -0.015 valid = np.isclose(T, 298.15, **temperature_tol) return psi, valid @@ -6947,119 +6996,6 @@ def bC_Mg_Cl_PP87i(T, P): return b0, b1, b2, C0, C1, alph1, alph2, omega, valid -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pabalan and Pitzer (1987ii) ~~~~~ -def theta_K_Na_PP87ii(T, P): - """c-c': potassium sodium [PP87ii].""" - theta = -0.012 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_Mg_Na_PP87ii(T, P): - """c-c': magnesium sodium [PP87ii].""" - theta = 0.07 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_K_Mg_PP87ii(T, P): - """c-c': potassium magnesium [PP87ii].""" - theta = 0 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_Cl_SO4_PP87ii(T, P): - """a-a': chloride sulfate [PP87ii].""" - theta = 0.030 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_Cl_OH_PP87ii(T, P): - """a-a': chloride hydroxide [PP87ii].""" - theta = -0.050 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def theta_OH_SO4_PP87ii(T, P): - """a-a': hydroxide sulfate [PP87ii].""" - theta = -0.013 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return theta, valid - - -def psi_K_Na_Cl_PP87ii(T, P): - """c-c'-a: potassium sodium chloride [PP87ii].""" - psi = -6.81e-3 + 1.68e-5 * T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Mg_Na_Cl_PP87ii(T, P): - """c-c'-a: magnesium sodium chloride [PP87ii].""" - psi = 1.99e-2 - 9.51 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_K_Mg_Cl_PP87ii(T, P): - """c-c'-a: potassium magnesium chloride [PP87ii].""" - psi = 2.586e-2 - 14.27 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Na_Cl_SO4_PP87ii(T, P): - """c-a-a': sodium chloride sulfate [PP87ii].""" - psi = 0 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_K_Cl_SO4_PP87ii(T, P): - """c-a-a': potassium chloride sulfate [PP87ii].""" - psi = -5e-3 - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Mg_Cl_SO4_PP87ii(T, P): - """c-a-a': magnesium chloride sulfate [PP87ii].""" - psi = -1.174e-1 + 32.63 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Na_Cl_OH_PP87ii(T, P): - """c-a-a': sodium chloride hydroxide [PP87ii].""" - psi = 2.73e-2 - 9.93 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - -def psi_Na_OH_SO4_PP87ii(T, P): - """c-a-a': sodium hydroxide sulfate [PP87ii].""" - psi = 3.02e-2 - 11.69 / T - # Validity range declared by MP98 for theta(Na, Mg) from this study - valid = (T >= 298.15) & (T <= 523.25) - return psi, valid - - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Simonson, Roy & Gibbons (1987) ~~~~~ def bC_K_CO3_SRG87(T, P): """c-a: potassium carbonate [SRG87].""" @@ -8570,275 +8506,6 @@ def psi_H_Na_Cl_CMR93(T, P): return psi, valid -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ He & Morse (1993) ~~~~~ -# Note that HM93 also contains beta/C equations for Na, K, Mg and Ca -# interactions with HCO3 and CO3 (not yet coded here) -def HM93_eq(T, A, B, C, D, E): - """HM93 parameter equation from p. 3548.""" - return A + B * T + C * T**2 + D / T + E * np.log(T) - - -def lambd_CO2_H_HM93(T, P): - """n-c: carbon-dioxide hydrogen [HM93].""" - lambd = 0 - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_Na_HM93(T, P): - """n-c: carbon-dioxide sodium [HM93].""" - lambd = HM93_eq( - T, - -5496.38465, - -3.326566, - 0.0017532, - 109399.341, - 1047.021567, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_K_HM93(T, P): - """n-c: carbon-dioxide potassium [HM93].""" - lambd = HM93_eq( - T, - 2856.528099, - 1.7670079, - -0.0009487, - -55954.1929, - -546.074467, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_Ca_HM93(T, P): - """n-c: carbon-dioxide calcium [HM93].""" - lambd = HM93_eq( - T, - -12774.6472, - -8.101555, - 0.00442472, - 245541.5435, - 2452.509720, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_Mg_HM93(T, P): - """n-c: carbon-dioxide magnesium [HM93].""" - lambd = HM93_eq( - T, - -479.362533, - -0.541843, - 0.00038812, - 3589.474052, - 104.3452732, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_Cl_HM93(T, P): - """n-a: carbon-dioxide chloride [HM93].""" - lambd = HM93_eq(T, 1659.944942, 0.9964326, -0.00052122, -33159.6177, -315.827883) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def lambd_CO2_SO4_HM93(T, P): - """n-a: carbon-dioxide sulfate [HM93].""" - lambd = HM93_eq( - T, - 2274.656591, - 1.8270948, - -0.00114272, - -33927.7625, - -457.015738, - ) - valid = (T >= 273.15) & (T <= 363.15) - return lambd, valid - - -def zeta_CO2_H_Cl_HM93(T, P): - """n-c-a: carbon-dioxide hydrogen chloride [HM93].""" - zeta = HM93_eq(T, -804.121738, -0.470474, 0.000240526, 16334.38917, 152.3838752) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Na_Cl_HM93(T, P): - """n-c-a: carbon-dioxide sodium chloride [HM93].""" - zeta = HM93_eq(T, -379.459185, -0.258005, 0.000147823, 6879.030871, 73.74511574) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_K_Cl_HM93(T, P): - """n-c-a: carbon-dioxide potassium chloride [HM93].""" - zeta = HM93_eq(T, -379.686097, -0.257891, 0.000147333, 6853.264129, 73.79977116) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Ca_Cl_HM93(T, P): - """n-c-a: carbon-dioxide calcium chloride [HM93].""" - zeta = HM93_eq(T, -166.065290, -0.018002, -2.47349e-5, 5256.844332, 27.377452415) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Mg_Cl_HM93(T, P): - """n-c-a: carbon-dioxide magnesium chloride [HM93].""" - zeta = HM93_eq(T, -1342.60256, -0.772286, 0.000391603, 27726.80974, 253.62319406) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_H_SO4_HM93(T, P): - """n-c-a: carbon-dioxide hydrogen sulfate [HM93].""" - zeta = 0 - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Na_SO4_HM93(T, P): - """n-c-a: carbon-dioxide sodium sulfate [HM93].""" - zeta = HM93_eq(T, 67030.02482, 37.930519, -0.01894730, -1399082.37, -12630.27457) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_K_SO4_HM93(T, P): - """n-c-a: carbon-dioxide potassium sulfate [HM93].""" - zeta = HM93_eq(T, -2907.03326, -2.860763, 0.001951086, 30756.86749, 611.37560512) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def zeta_CO2_Mg_SO4_HM93(T, P): - """n-c-a: carbon-dioxide magnesium sulfate [HM93].""" - zeta = HM93_eq(T, -7374.24392, -4.608331, 0.002489207, 143162.6076, 1412.302898) - valid = (T >= 273.15) & (T <= 363.15) - return zeta, valid - - -def bC_Na_HCO3_HM93(T, P): - """c-a: sodium bicarbonate [HM93].""" - b0 = HM93_eq(T, -37.2624193, -0.01445932, 0, 682.885977, 6.8995857) - b1 = HM93_eq(T, -61.4635193, -0.02446734, 0, 1129.389146, 11.4108589) - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_K_HCO3_HM93(T, P): - """c-a: potassium bicarbonate [HM93].""" - b0 = HM93_eq(T, -0.3088232, 0.001, 0, -0.00069869, -4.701488e-6) - b1 = HM93_eq(T, -0.2802, 0.00109999, 0, 0.000936932, 6.15660566e-6) - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Mg_HCO3_HM93(T, P): - """c-a: magnesium bicarbonate [HM93].""" - b0 = HM93_eq(T, 13697.10, 8.250840, -0.00434, -273406.1716, -2607.115202) - b1 = HM93_eq(T, -157839.8351, -92.7779354, 0.0477642, 3203209.6948, 29927.151503) - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Ca_HCO3_HM93(T, P): - """c-a: calcium bicarbonate [HM93].""" - b0 = HM93_eq(T, 29576.53405, 18.447305, -0.009989, -576520.5185, -5661.1237) - b1 = HM93_eq(T, -1028.8510522, -0.3725876718, 8.9691e-5, 26492.240303, 183.13155672) - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Na_CO3_HM93(T, P): - """c-a: sodium carbonate [HM93].""" - b0 = HM93_eq(T, -60.5387702, -0.023301655, 0, 1108.3760518, 11.19855531) - b1 = HM93_eq(T, -237.5156616, -0.09989121, 0, 4412.511973, 44.5820703) - b2 = 0 - Cphi = 0.0052 - C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["CO3"]))) - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_K_CO3_HM93(T, P): - """c-a: potassium carbonate [HM93].""" - b0 = HM93_eq(T, -0.1991649, 0.00110, 0, 1.8063362e-5, 0) - b1 = HM93_eq(T, 0.1330579, 0.00436, 0, 0.0011899, 0) - b2 = 0 - Cphi = 0.0005 - C0 = Cphi / (2 * np.sqrt(np.abs(i2c["K"] * i2c["CO3"]))) - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Mg_CO3_HM93(T, P): - """c-a: magnesium carbonate [HM93].""" - b0 = 0 - b1 = 0 - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = -9 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Ca_CO3_HM93(T, P): - """c-a: calcium carbonate [HM93].""" - b0 = 0 - b1 = 0 - b2 = 0 - C0 = 0 - C1 = 0 - alph1 = -9 - alph2 = -9 - omega = -9 - valid = (T >= 273.15) & (T <= 363.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Hovey et al. (1993) ~~~~~ def HPR93_eq36(T, a): """HPR93 equation 36.""" @@ -12139,126 +11806,3 @@ def theta_H_Na_HCW22(T, P): theta = 0.0306 - 0.000418 * (T - 298.15) valid = (T >= 278.15) & (T <= 318.15) return theta, valid - - -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Spencer et al. (1990) ~~~~~ -def SMW90_eq2(T, a): - """a contains the coefficients [a1, a2, a6, a9, a3, a4].""" - return a[0] + a[1] * T + a[2] * T**2 + a[3] * T**3 + a[4] / T + a[5] * np.log(T) - - -def bC_Mg_Cl_SMW90(T, P): - """c-a: magnesium chloride [SMW90].""" - b0 = SMW90_eq2( - T, - [ - 3.13852913e2, - 2.61769099e-1, - -2.46268460e-4, - 1.15764787e-7, - -5.53133381e3, - -6.21616862e1, - ], - ) - b1 = SMW90_eq2( - T, - [ - -3.18432525e4, - -2.86710358e1, - 2.78892838e-2, - -1.3279705e-5, - 5.24032958e5, - 6.40770396e3, - ], - ) - b2 = 0 - Cphi = SMW90_eq2( - T, - [ - 5.9532e-2, - -2.49949e-4, - 2.41831e-7, - 0, - 0, - 0, - 0, - ], - ) - C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["SO4"]))) - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T > 273.15 - 54) & (T <= 298.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def bC_Mg_SO4_SMW90(T, P): - """c-a: magnesium sulfate [SMW90].""" - b0 = SMW90_eq2( - T, - [ - 5.40007849e3, - 4.90576884e0, - -4.80489750e-3, - 2.31126994e-6, - -8.80664146e4, - -1.08839565e3, - ], - ) - b1 = SMW90_eq2( - T, - [ - 2.78730869e0, - 4.30077440e-3, - 0, - 0, - 0, - 0, - ], - ) - b2 = 0 - Cphi = SMW90_eq2( - T, - [ - -5.88623653e2, - -5.05522880e-1, - 4.8277657e-4, - -2.3029838e-7, - 1.02002016e4, - 1.17303808e2, - ], - ) - C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["SO4"]))) - C1 = 0 - alph1 = 2 - alph2 = -9 - omega = -9 - valid = (T > 273.15 - 54) & (T <= 298.15) - return b0, b1, b2, C0, C1, alph1, alph2, omega, valid - - -def psi_Mg_Cl_SO4_SMW90(T, P): - """c-a-a': magnesium chloride sulfate [SMW90].""" - psi = SMW90_eq2( - T, - [ - -1.839158e-1, - 1.429444e-4, - 0, - 0, - 3.263e1, - 0, - ], - ) - valid = (T > 273.15 - 54) & (T <= 298.15) - return psi, valid - - -def psi_Mg_Cl_SO4_HM93(T, P): - """c-a-a': magnesium chloride sulfate [HM93].""" - psi = np.where( - T < 298.15, psi_Mg_Cl_SO4_SMW90(T, P)[0], psi_Mg_Cl_SO4_PP87ii(T, P)[0] - ) - valid = (T > 273.15 - 54) & (T < 523.25) - return psi, valid diff --git a/pytzer/parameters/heMorse1993.py b/pytzer/parameters/heMorse1993.py new file mode 100644 index 00000000..907ffc93 --- /dev/null +++ b/pytzer/parameters/heMorse1993.py @@ -0,0 +1,285 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""HM93: He & Morse (1993) Geochim. Cosmochim. Acta 57(15), 3533-3554. +https://doi.org/10.1016/0016-7037(93)90137-L +""" + +from jax import numpy as np +from ..convert import solute_to_charge as i2c +from .spencer1990 import psi_Mg_Cl_SO4_SMW90 +from .pabalanPitzer1987 import psi_Mg_Cl_SO4_PP87ii + + +def HM93_eq(T, A, B, C, D, E): + """HM93 parameter equation from p. 3548.""" + return A + B * T + C * T**2 + D / T + E * np.log(T) + + +def bC_Na_HCO3_HM93(T, P): + """c-a: sodium bicarbonate [HM93].""" + b0 = HM93_eq(T, -37.2624193, -0.01445932, 0, 682.885977, 6.8995857) + b1 = HM93_eq(T, -61.4635193, -0.02446734, 0, 1129.389146, 11.4108589) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_HCO3_HM93(T, P): + """c-a: potassium bicarbonate [HM93].""" + b0 = HM93_eq(T, -0.3088232, 0.001, 0, -0.00069869, -4.701488e-6) + b1 = HM93_eq(T, -0.2802, 0.00109999, 0, 0.000936932, 6.15660566e-6) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_HCO3_HM93(T, P): + """c-a: magnesium bicarbonate [HM93].""" + b0 = HM93_eq(T, 13697.10, 8.250840, -0.00434, -273406.1716, -2607.115202) + b1 = HM93_eq(T, -157839.8351, -92.7779354, 0.0477642, 3203209.6948, 29927.151503) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_HCO3_HM93(T, P): + """c-a: calcium bicarbonate [HM93].""" + b0 = HM93_eq(T, 29576.53405, 18.447305, -0.009989, -576520.5185, -5661.1237) + b1 = HM93_eq(T, -1028.8510522, -0.3725876718, 8.9691e-5, 26492.240303, 183.13155672) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Na_CO3_HM93(T, P): + """c-a: sodium carbonate [HM93].""" + b0 = HM93_eq(T, -60.5387702, -0.023301655, 0, 1108.3760518, 11.19855531) + b1 = HM93_eq(T, -237.5156616, -0.09989121, 0, 4412.511973, 44.5820703) + b2 = 0 + Cphi = 0.0052 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_K_CO3_HM93(T, P): + """c-a: potassium carbonate [HM93].""" + b0 = HM93_eq(T, -0.1991649, 0.00110, 0, 1.8063362e-5, 0) + b1 = HM93_eq(T, 0.1330579, 0.00436, 0, 0.0011899, 0) + b2 = 0 + Cphi = 0.0005 + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["K"] * i2c["CO3"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_CO3_HM93(T, P): + """c-a: magnesium carbonate [HM93].""" + b0 = 0 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Ca_CO3_HM93(T, P): + """c-a: calcium carbonate [HM93].""" + b0 = 0 + b1 = 0 + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = (T >= 273.15) & (T <= 363.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def psi_Mg_Cl_SO4_HM93(T, P): + """c-a-a': magnesium chloride sulfate [HM93].""" + psi = np.where( + T < 298.15, psi_Mg_Cl_SO4_SMW90(T, P)[0], psi_Mg_Cl_SO4_PP87ii(T, P)[0] + ) + valid = (T > 273.15 - 54) & (T < 523.25) + return psi, valid + + +def lambd_CO2_H_HM93(T, P): + """n-c: carbon-dioxide hydrogen [HM93].""" + lambd = 0 + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_Na_HM93(T, P): + """n-c: carbon-dioxide sodium [HM93].""" + lambd = HM93_eq( + T, + -5496.38465, + -3.326566, + 0.0017532, + 109399.341, + 1047.021567, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_K_HM93(T, P): + """n-c: carbon-dioxide potassium [HM93].""" + lambd = HM93_eq( + T, + 2856.528099, + 1.7670079, + -0.0009487, + -55954.1929, + -546.074467, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_Ca_HM93(T, P): + """n-c: carbon-dioxide calcium [HM93].""" + lambd = HM93_eq( + T, + -12774.6472, + -8.101555, + 0.00442472, + 245541.5435, + 2452.509720, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_Mg_HM93(T, P): + """n-c: carbon-dioxide magnesium [HM93].""" + lambd = HM93_eq( + T, + -479.362533, + -0.541843, + 0.00038812, + 3589.474052, + 104.3452732, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_Cl_HM93(T, P): + """n-a: carbon-dioxide chloride [HM93].""" + lambd = HM93_eq(T, 1659.944942, 0.9964326, -0.00052122, -33159.6177, -315.827883) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def lambd_CO2_SO4_HM93(T, P): + """n-a: carbon-dioxide sulfate [HM93].""" + lambd = HM93_eq( + T, + 2274.656591, + 1.8270948, + -0.00114272, + -33927.7625, + -457.015738, + ) + valid = (T >= 273.15) & (T <= 363.15) + return lambd, valid + + +def zeta_CO2_H_Cl_HM93(T, P): + """n-c-a: carbon-dioxide hydrogen chloride [HM93].""" + zeta = HM93_eq(T, -804.121738, -0.470474, 0.000240526, 16334.38917, 152.3838752) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Na_Cl_HM93(T, P): + """n-c-a: carbon-dioxide sodium chloride [HM93].""" + zeta = HM93_eq(T, -379.459185, -0.258005, 0.000147823, 6879.030871, 73.74511574) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_K_Cl_HM93(T, P): + """n-c-a: carbon-dioxide potassium chloride [HM93].""" + zeta = HM93_eq(T, -379.686097, -0.257891, 0.000147333, 6853.264129, 73.79977116) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Ca_Cl_HM93(T, P): + """n-c-a: carbon-dioxide calcium chloride [HM93].""" + zeta = HM93_eq(T, -166.065290, -0.018002, -2.47349e-5, 5256.844332, 27.377452415) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Mg_Cl_HM93(T, P): + """n-c-a: carbon-dioxide magnesium chloride [HM93].""" + zeta = HM93_eq(T, -1342.60256, -0.772286, 0.000391603, 27726.80974, 253.62319406) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_H_SO4_HM93(T, P): + """n-c-a: carbon-dioxide hydrogen sulfate [HM93].""" + zeta = 0 + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Na_SO4_HM93(T, P): + """n-c-a: carbon-dioxide sodium sulfate [HM93].""" + zeta = HM93_eq(T, 67030.02482, 37.930519, -0.01894730, -1399082.37, -12630.27457) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_K_SO4_HM93(T, P): + """n-c-a: carbon-dioxide potassium sulfate [HM93].""" + zeta = HM93_eq(T, -2907.03326, -2.860763, 0.001951086, 30756.86749, 611.37560512) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid + + +def zeta_CO2_Mg_SO4_HM93(T, P): + """n-c-a: carbon-dioxide magnesium sulfate [HM93].""" + zeta = HM93_eq(T, -7374.24392, -4.608331, 0.002489207, 143162.6076, 1412.302898) + valid = (T >= 273.15) & (T <= 363.15) + return zeta, valid diff --git a/pytzer/parameters/holmes1987.py b/pytzer/parameters/holmes1987.py new file mode 100644 index 00000000..1c7e0765 --- /dev/null +++ b/pytzer/parameters/holmes1987.py @@ -0,0 +1,5 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""HBS87: Holmes et al. (1987) J. Chem. Thermodyn. 19(8), 863-890. +https://doi.org/10.1016/0021-9614(87)90033-4 +""" diff --git a/pytzer/parameters/holmesMesmer1992.py b/pytzer/parameters/holmesMesmer1992.py new file mode 100644 index 00000000..c5eb28cf --- /dev/null +++ b/pytzer/parameters/holmesMesmer1992.py @@ -0,0 +1,89 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""HM92: Holmes & Mesmer (1992) J. Chem. Thermodyn. 24(3), 317-328. +https://doi.org/10.1016/S0021-9614(05)80072-2 +""" + +from jax import numpy as np +from ..convert import solute_to_charge as i2c + + +def HM92_eq26(T, p): + Tn = T - 298.15 + return p[0] + p[1] * Tn + p[2] * Tn**2 + p[3] * Tn**3 + + +def bC_H_HSO4_HM92(T, P): + """c-a: hydrogen bisulfate [HM92].""" + b0 = HM92_eq26( + T, + [ + 0.2118, + -0.6157e-3, + 0.29193e-5, + -1.4153e-8, + ], + ) + b1 = HM92_eq26( + T, + [ + 0.4177, + 0, + -0.178e-5, + 0, + ], + ) + b2 = 0 + C0 = 0 + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T >= 298.15) & (T <= 473.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_H_SO4_HM92(T, P): + """c-a: hydrogen sulfate [HM92].""" + b0 = HM92_eq26( + T, + [ + 0.0819, + -1.214e-3, + 0, + 7.63e-8, + ], + ) + b1 = 0 + b2 = 0 + Cphi = HM92_eq26( + T, + [ + 0.0637, + 0.353e-3, + -1.530e-5, + 5.27e-8, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["H"] * i2c["SO4"]))) + C1 = 0 + alph1 = -9 + alph2 = -9 + omega = -9 + valid = (T >= 298.15) & (T <= 473.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_HSO4_SO4_HM92(T, P): + """a-a': bisulfate sulfate [HM92].""" + theta = HM92_eq26( + T, + [ + -0.1756, + 3.146e-3, + -2.862e-5, + 6.786e-8, + ], + ) + valid = (T >= 298.15) & (T <= 473.15) + return theta, valid diff --git a/pytzer/parameters/pabalanPitzer1987.py b/pytzer/parameters/pabalanPitzer1987.py new file mode 100644 index 00000000..5dc21a65 --- /dev/null +++ b/pytzer/parameters/pabalanPitzer1987.py @@ -0,0 +1,117 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""PP87ii: Pabalan & Pitzer (1987) Geochim. Cosmochim. Acta 51(9), 2429-2443. +https://doi.org/10.1016/0016-7037(87)90295-X +""" + + +def theta_K_Na_PP87ii(T, P): + """c-c': potassium sodium [PP87ii].""" + theta = -0.012 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_Mg_Na_PP87ii(T, P): + """c-c': magnesium sodium [PP87ii].""" + theta = 0.07 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_K_Mg_PP87ii(T, P): + """c-c': potassium magnesium [PP87ii].""" + theta = 0 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_Cl_SO4_PP87ii(T, P): + """a-a': chloride sulfate [PP87ii].""" + theta = 0.030 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_Cl_OH_PP87ii(T, P): + """a-a': chloride hydroxide [PP87ii].""" + theta = -0.050 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def theta_OH_SO4_PP87ii(T, P): + """a-a': hydroxide sulfate [PP87ii].""" + theta = -0.013 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return theta, valid + + +def psi_K_Na_Cl_PP87ii(T, P): + """c-c'-a: potassium sodium chloride [PP87ii].""" + psi = -6.81e-3 + 1.68e-5 * T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Mg_Na_Cl_PP87ii(T, P): + """c-c'-a: magnesium sodium chloride [PP87ii].""" + psi = 1.99e-2 - 9.51 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_K_Mg_Cl_PP87ii(T, P): + """c-c'-a: potassium magnesium chloride [PP87ii].""" + psi = 2.586e-2 - 14.27 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Na_Cl_SO4_PP87ii(T, P): + """c-a-a': sodium chloride sulfate [PP87ii].""" + psi = 0 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_K_Cl_SO4_PP87ii(T, P): + """c-a-a': potassium chloride sulfate [PP87ii].""" + psi = -5e-3 + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Mg_Cl_SO4_PP87ii(T, P): + """c-a-a': magnesium chloride sulfate [PP87ii].""" + psi = -1.174e-1 + 32.63 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Na_Cl_OH_PP87ii(T, P): + """c-a-a': sodium chloride hydroxide [PP87ii].""" + psi = 2.73e-2 - 9.93 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid + + +def psi_Na_OH_SO4_PP87ii(T, P): + """c-a-a': sodium hydroxide sulfate [PP87ii].""" + psi = 3.02e-2 - 11.69 / T + # Validity range declared by MP98 for theta(Na, Mg) from this study + valid = (T >= 298.15) & (T <= 523.25) + return psi, valid diff --git a/pytzer/parameters/spencer1990.py b/pytzer/parameters/spencer1990.py new file mode 100644 index 00000000..28719a9e --- /dev/null +++ b/pytzer/parameters/spencer1990.py @@ -0,0 +1,123 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +"""SMW90: Spencer et al. (1990) Geochim. Cosmochim. Acta 54(3), 575-590. +https://doi.org/10.1016/0016-7037(90)90354-N + +Not all parameters in the paper have yet been added here! +""" + +from jax import numpy as np +from ..convert import solute_to_charge as i2c + + +def SMW90_eq2(T, a): + """a contains the coefficients [a1, a2, a6, a9, a3, a4].""" + return a[0] + a[1] * T + a[2] * T**2 + a[3] * T**3 + a[4] / T + a[5] * np.log(T) + + +def bC_Mg_Cl_SMW90(T, P): + """c-a: magnesium chloride [SMW90].""" + b0 = SMW90_eq2( + T, + [ + 3.13852913e2, + 2.61769099e-1, + -2.46268460e-4, + 1.15764787e-7, + -5.53133381e3, + -6.21616862e1, + ], + ) + b1 = SMW90_eq2( + T, + [ + -3.18432525e4, + -2.86710358e1, + 2.78892838e-2, + -1.3279705e-5, + 5.24032958e5, + 6.40770396e3, + ], + ) + b2 = 0 + Cphi = SMW90_eq2( + T, + [ + 5.9532e-2, + -2.49949e-4, + 2.41831e-7, + 0, + 0, + 0, + 0, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["Cl"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T > 273.15 - 54) & (T <= 298.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def bC_Mg_SO4_SMW90(T, P): + """c-a: magnesium sulfate [SMW90].""" + b0 = SMW90_eq2( + T, + [ + 5.40007849e3, + 4.90576884e0, + -4.80489750e-3, + 2.31126994e-6, + -8.80664146e4, + -1.08839565e3, + ], + ) + b1 = SMW90_eq2( + T, + [ + 2.78730869e0, + 4.30077440e-3, + 0, + 0, + 0, + 0, + ], + ) + b2 = 0 + Cphi = SMW90_eq2( + T, + [ + -5.88623653e2, + -5.05522880e-1, + 4.8277657e-4, + -2.3029838e-7, + 1.02002016e4, + 1.17303808e2, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Mg"] * i2c["SO4"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = (T > 273.15 - 54) & (T <= 298.15) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def psi_Mg_Cl_SO4_SMW90(T, P): + """c-a-a': magnesium chloride sulfate [SMW90].""" + psi = SMW90_eq2( + T, + [ + -1.839158e-1, + 1.429444e-4, + 0, + 0, + 3.263e1, + 0, + ], + ) + valid = (T > 273.15 - 54) & (T <= 298.15) + return psi, valid diff --git a/tests/test_H22.py b/tests/test_H22.py index bb8ac066..fd4bf074 100644 --- a/tests/test_H22.py +++ b/tests/test_H22.py @@ -2,6 +2,7 @@ import pytzer as pz, pytzer4 as pz4 prmlib = pz.libraries.Waters13_Clegg22 +# prmlib = pz.libraries.HeMorse93 totals = pz.odict() totals["Na"] = 0.4861818 # - 0.04 diff --git a/tests/test_HM93.py b/tests/test_HM93.py new file mode 100644 index 00000000..11178b4a --- /dev/null +++ b/tests/test_HM93.py @@ -0,0 +1,8 @@ +import pytzer as pz + + +prmlib = pz.libraries.HeMorse93 + +totals = pz.odict() +totals["Na"] = 1.0 +totals["Cl"] = 1.0 diff --git a/tests/test_PB82.py b/tests/test_PB82.py new file mode 100644 index 00000000..981e0c41 --- /dev/null +++ b/tests/test_PB82.py @@ -0,0 +1,30 @@ +import numpy as np +from matplotlib import pyplot as plt +import pytzer as pz + +temperature = np.linspace(0, 350, num=1000) +ln_kCO2 = pz.dissociation.CO2_PB82(T=temperature + 273.15) +ln_kH2CO3_PB82 = pz.dissociation.H2CO3_PB82(T=temperature + 273.15) +ln_kHCO3_PB82 = pz.dissociation.HCO3_PB82(T=temperature + 273.15) +ln_kH2CO3_MP98 = pz.dissociation.H2CO3_MP98(T=temperature + 273.15) +ln_kHCO3_MP98 = pz.dissociation.HCO3_MP98(T=temperature + 273.15) +ln10 = np.log(10) + +fig, axs = plt.subplots(nrows=2, ncols=2, dpi=300) +# for ax in axs.ravel(): +# ax.set_xlim([0, 50]) +ax = axs[0, 0] +ax.plot(temperature, ln_kCO2 / ln10) +ax.set_xlabel("Temperature / °C") +ax.set_ylabel("log$_{10}$ $K_\mathrm{H}$") +ax = axs[0, 1] +ax.plot(temperature, ln_kH2CO3_PB82 / ln10) +# ax.plot(temperature, ln_kH2CO3_MP98 / ln10) +ax.set_xlabel("Temperature / °C") +ax.set_ylabel("log$_{10}$ $K_1$") +ax = axs[1, 0] +ax.plot(temperature, ln_kHCO3_PB82 / ln10) +# ax.plot(temperature, ln_kHCO3_MP98 / ln10) +ax.set_xlabel("Temperature / °C") +ax.set_ylabel("log$_{10}$ $K_2$") +plt.tight_layout() diff --git a/tests/test_TM82.py b/tests/test_TM82.py new file mode 100644 index 00000000..ef475de6 --- /dev/null +++ b/tests/test_TM82.py @@ -0,0 +1,66 @@ +from copy import deepcopy +import pytzer as pz, numpy as np, pandas as pd +from pytzer import parameters as prm, dissociation as k + +# Import data from Thurmond & Millero (1982) Table IV +table4 = pd.DataFrame( + { + "Cl": [0.5, 0.7, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5.5, 6], + "pks1_meas": [ + 5.997, + 5.984, + 5.97, + 5.964, + 5.968, + 5.992, + np.nan, + 6.046, + 6.092, + 6.13, + 6.227, + 6.264, + ], + "pks2_meas": [ + 9.58, + 9.53, + 9.48, + 9.44, + 9.41, + 9.43, + 9.46, + 9.46, + 9.53, + 9.56, + 9.67, + 9.71, + ], + } +) + +table4["dic"] = 5e-3 +table4["Na"] = table4.Cl + table4.dic * 2 +table4["pks1_pz"] = np.nan +table4["pks2_pz"] = np.nan +table4 = table4[["Na", "Cl", "dic", "pks1_meas", "pks1_pz", "pks2_meas", "pks2_pz"]] + +# Use Pytzer to determine pK1* and pK2* +prmlib = deepcopy(pz.libraries.myMCS) +# prmlib.update_ca("Na", "Cl", prm.bC_Na_Cl_A92ii) +# prmlib.update_ca("H", "Cl", prm.bC_H_Cl_JESS) +# prmlib.update_cc("H", "Na", prm.theta_H_Na_MP98) +# prmlib.update_aa("Cl", "OH", prm.theta_Cl_OH_MP98) +# prmlib.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_PMR97) +# prmlib.update_equilibrium("H2O", k.H2O_M88) +# prmlib.update_equilibrium("H2CO3", k.H2CO3_MP98) +# prmlib.update_equilibrium("HCO3", k.HCO3_MP98) +# prmlib.update_aa("Cl", "HCO3", prm.theta_Cl_HCO3_PP82) +prmlib.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_PP82) + +# i = 11 +# row = table4.loc[i] +for i, row in table4.iterrows(): + totals = pz.odict({"Na": row.Na, "Cl": row.Cl, "CO2": row.dic}) + solutes, pks = pz.solve(totals, library=prmlib) + pH = -np.log10(solutes["H"]) + table4.loc[i, "pks1_pz"] = pks["H2CO3"] + table4.loc[i, "pks2_pz"] = pks["HCO3"] diff --git a/tests/untitled0.py b/tests/untitled0.py index dd6e5edd..e69de29b 100644 --- a/tests/untitled0.py +++ b/tests/untitled0.py @@ -1,28 +0,0 @@ -import PyCO2SYS as pyco2 - -result = pyco2.sys( - # par1=df.alkalinity.to_numpy(), - par1=2300, - par2=2150, - par1_type=1, # 1 means alkalinity - par2_type=2, # 2 means DIC - salinity=30, - temperature=12.5, -) - -pCO2 = result["pCO2"] - - -result_pH = pyco2.sys( - par1=2300, - par2=8.1, - par1_type=1, - par2_type=3, # 3 means pH - temperature=25, # lab - temperature_out=6, # in the ocean -) - -pCO2_in_the_ocean = result_pH["pCO2_out"] -pH_in_the_ocean = result_pH["pH_out"] - -# https://pyco2sys.readthedocs.io/en/latest/ From 3f2d84b5f54db29901ce297c78aaab551f155dec Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 22 Feb 2022 16:47:24 +0100 Subject: [PATCH 17/58] test --- tests/test_TM82.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/tests/test_TM82.py b/tests/test_TM82.py index ef475de6..04f5ba2c 100644 --- a/tests/test_TM82.py +++ b/tests/test_TM82.py @@ -1,4 +1,5 @@ from copy import deepcopy +from matplotlib import pyplot as plt import pytzer as pz, numpy as np, pandas as pd from pytzer import parameters as prm, dissociation as k @@ -44,7 +45,7 @@ table4 = table4[["Na", "Cl", "dic", "pks1_meas", "pks1_pz", "pks2_meas", "pks2_pz"]] # Use Pytzer to determine pK1* and pK2* -prmlib = deepcopy(pz.libraries.myMCS) +prmlib = deepcopy(pz.libraries.Seawater) # prmlib.update_ca("Na", "Cl", prm.bC_Na_Cl_A92ii) # prmlib.update_ca("H", "Cl", prm.bC_H_Cl_JESS) # prmlib.update_cc("H", "Na", prm.theta_H_Na_MP98) @@ -54,13 +55,35 @@ # prmlib.update_equilibrium("H2CO3", k.H2CO3_MP98) # prmlib.update_equilibrium("HCO3", k.HCO3_MP98) # prmlib.update_aa("Cl", "HCO3", prm.theta_Cl_HCO3_PP82) -prmlib.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_PP82) +# prmlib.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_PP82) -# i = 11 -# row = table4.loc[i] for i, row in table4.iterrows(): totals = pz.odict({"Na": row.Na, "Cl": row.Cl, "CO2": row.dic}) solutes, pks = pz.solve(totals, library=prmlib) pH = -np.log10(solutes["H"]) table4.loc[i, "pks1_pz"] = pks["H2CO3"] table4.loc[i, "pks2_pz"] = pks["HCO3"] + +f_sqrt_Cl = np.linspace(0, 2.5, num=1000) +f_Cl = f_sqrt_Cl**2 +t_CO2 = 5e-3 +f_Na = f_Cl + t_CO2 * 2 +pks1 = np.zeros_like(f_Cl) +pks1[0] = prmlib['equilibria']['H2CO3']() / -np.log(10) +pks2 = np.zeros_like(f_Cl) +pks2[0] = prmlib['equilibria']['HCO3']() / -np.log(10) +for i in range(1, len(f_Cl)): + totals = pz.odict({"Na": f_Na[i], "Cl": f_Cl[i], "CO2": t_CO2}) + solutes, pks = pz.solve(totals, library=prmlib) + # pH = -np.log10(solutes["H"]) + pks1[i] = pks["H2CO3"] + pks2[i] = pks["HCO3"] + +fig, axs = plt.subplots(nrows=2, dpi=300) +ax = axs[0] +ax.plot(f_Cl, pks1) +ax.scatter("Cl", "pks1_meas", data=table4) +ax = axs[1] +ax.plot(f_Cl, pks2) +ax.scatter("Cl", "pks2_meas", data=table4) +plt.tight_layout() From 62f832ff4c452f635eb5e324e32e4eddbf26ee8f Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Wed, 23 Feb 2022 16:36:49 +0100 Subject: [PATCH 18/58] Move to separate repo --- tests/test_H22.py | 81 ----------------------------------------- tests/test_HM93.py | 8 ----- tests/test_TM82.py | 89 ---------------------------------------------- tests/test_TM83.py | 50 -------------------------- tests/untitled0.py | 0 5 files changed, 228 deletions(-) delete mode 100644 tests/test_H22.py delete mode 100644 tests/test_HM93.py delete mode 100644 tests/test_TM82.py delete mode 100644 tests/test_TM83.py delete mode 100644 tests/untitled0.py diff --git a/tests/test_H22.py b/tests/test_H22.py deleted file mode 100644 index fd4bf074..00000000 --- a/tests/test_H22.py +++ /dev/null @@ -1,81 +0,0 @@ -import numpy as np -import pytzer as pz, pytzer4 as pz4 - -prmlib = pz.libraries.Waters13_Clegg22 -# prmlib = pz.libraries.HeMorse93 - -totals = pz.odict() -totals["Na"] = 0.4861818 # - 0.04 -totals["Mg"] = 0.0547402 -totals["Ca"] = 0.01075004 -totals["K"] = 0.01058004 -totals["Cl"] = 0.5692021 # + 0.02 -totals["SO4"] = 0.02927011 -# totals["tris"] = 0.04 - -solutes, pks = pz.solve(totals, library=prmlib, temperature=298.15) -pH = -np.log10(solutes["H"]) -params = prmlib.get_parameters(solutes, temperature=278.15, verbose=False) -acfs = pz.activity_coefficients(solutes, **params) -aw = pz.activity_water(solutes, **params) - -waterk = (solutes["H"] * solutes["OH"] * acfs["H"] * acfs["OH"] / aw).item() -waterk_paper = 8.2481e-8 * 5.0620e-8 * 0.76188 * 0.57223 / 0.98142 -waterk_official = np.exp(prmlib["equilibria"]["H2O"](278.15)) - -# trisk = (solutes["tris"] * solutes["H"] / solutes["trisH"]).item() -trisk_official = np.exp(prmlib["equilibria"]["trisH"](278.15)) - -sulfk = ( - solutes["H"] - * solutes["SO4"] - * acfs["H"] - * acfs["SO4"] - / (solutes["HSO4"] * acfs["HSO4"]) -).item() -sulfk_paper = 0.02927 * 8.2481e-8 * 0.76188 * 0.0972 / (0.72148 * 1.3286e-8) -sulfk_official = np.exp(prmlib["equilibria"]["HSO4"](278.15)) - -mgk = ( - solutes["Mg"] - * acfs["Mg"] - * solutes["OH"] - * acfs["OH"] - / (solutes["MgOH"] * acfs["MgOH"]) -).item() -mgk_paper = 0.05474 * 0.22054 * 5.062e-8 * 0.57223 / (4.5149e-8 * 0.90276) -mgk_official = np.exp(prmlib["equilibria"]["MgOH"](278.15)) -# this was upside down - and all the other formation constants might be too! -# need to change in both pz.components (rearrange get_X equations) -# AND in pz.thermodynamic (swap signs of log_kt and log_ks terms) - -solutes_paper = pz.odict() -solutes_paper["H"] = 8.2481e-8 -solutes_paper["Ca"] = 0.01075 -solutes_paper["Cl"] = 0.56920 -solutes_paper["K"] = 0.01058 -solutes_paper["Mg"] = 0.05474 -solutes_paper["Na"] = 0.48618 -solutes_paper["SO4"] = 0.02927 -solutes_paper["OH"] = 5.0620e-8 -solutes_paper["HSO4"] = 1.3286e-8 -solutes_paper["MgOH"] = 4.5149e-8 -params = prmlib.get_parameters(solutes_paper, temperature=273.15, verbose=False) -# params = pz.libraries.GM89.get_parameters(solutes_paper, temperature=273.15, verbose=False) - -osm_paper = pz.osmotic_coefficient(solutes_paper, **params) -aw_paper = pz.activity_water(solutes_paper, **params) -acfs_paper = pz.activity_coefficients(solutes_paper, **params) -# print(osm_paper, aw_paper) - -mols = np.vstack([v for v in solutes_paper.values()]) -ions = np.array([k for k in solutes_paper.keys()]) -prmlib_v4 = pz4.libraries.GM89 -prmlib_v4.add_zeros(ions) -acfs_paper_v4 = pz4.model.acfs(mols, ions, 273.15, 10.10325, prmlib=prmlib_v4).ravel() - -Gex_v4 = pz4.model.Gex_nRT(mols, ions, 273.15, 10.10325, prmlib=prmlib_v4)[0] -Gex_v5 = pz.Gibbs_nRT(solutes_paper, **params).item() - -# for m, i in zip(acfs_paper_v4, ions): -# print("{}: {} vs {}".format(i, acfs_paper[i], m)) diff --git a/tests/test_HM93.py b/tests/test_HM93.py deleted file mode 100644 index 11178b4a..00000000 --- a/tests/test_HM93.py +++ /dev/null @@ -1,8 +0,0 @@ -import pytzer as pz - - -prmlib = pz.libraries.HeMorse93 - -totals = pz.odict() -totals["Na"] = 1.0 -totals["Cl"] = 1.0 diff --git a/tests/test_TM82.py b/tests/test_TM82.py deleted file mode 100644 index 04f5ba2c..00000000 --- a/tests/test_TM82.py +++ /dev/null @@ -1,89 +0,0 @@ -from copy import deepcopy -from matplotlib import pyplot as plt -import pytzer as pz, numpy as np, pandas as pd -from pytzer import parameters as prm, dissociation as k - -# Import data from Thurmond & Millero (1982) Table IV -table4 = pd.DataFrame( - { - "Cl": [0.5, 0.7, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5.5, 6], - "pks1_meas": [ - 5.997, - 5.984, - 5.97, - 5.964, - 5.968, - 5.992, - np.nan, - 6.046, - 6.092, - 6.13, - 6.227, - 6.264, - ], - "pks2_meas": [ - 9.58, - 9.53, - 9.48, - 9.44, - 9.41, - 9.43, - 9.46, - 9.46, - 9.53, - 9.56, - 9.67, - 9.71, - ], - } -) - -table4["dic"] = 5e-3 -table4["Na"] = table4.Cl + table4.dic * 2 -table4["pks1_pz"] = np.nan -table4["pks2_pz"] = np.nan -table4 = table4[["Na", "Cl", "dic", "pks1_meas", "pks1_pz", "pks2_meas", "pks2_pz"]] - -# Use Pytzer to determine pK1* and pK2* -prmlib = deepcopy(pz.libraries.Seawater) -# prmlib.update_ca("Na", "Cl", prm.bC_Na_Cl_A92ii) -# prmlib.update_ca("H", "Cl", prm.bC_H_Cl_JESS) -# prmlib.update_cc("H", "Na", prm.theta_H_Na_MP98) -# prmlib.update_aa("Cl", "OH", prm.theta_Cl_OH_MP98) -# prmlib.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_PMR97) -# prmlib.update_equilibrium("H2O", k.H2O_M88) -# prmlib.update_equilibrium("H2CO3", k.H2CO3_MP98) -# prmlib.update_equilibrium("HCO3", k.HCO3_MP98) -# prmlib.update_aa("Cl", "HCO3", prm.theta_Cl_HCO3_PP82) -# prmlib.update_caa("Na", "Cl", "HCO3", prm.psi_Na_Cl_HCO3_PP82) - -for i, row in table4.iterrows(): - totals = pz.odict({"Na": row.Na, "Cl": row.Cl, "CO2": row.dic}) - solutes, pks = pz.solve(totals, library=prmlib) - pH = -np.log10(solutes["H"]) - table4.loc[i, "pks1_pz"] = pks["H2CO3"] - table4.loc[i, "pks2_pz"] = pks["HCO3"] - -f_sqrt_Cl = np.linspace(0, 2.5, num=1000) -f_Cl = f_sqrt_Cl**2 -t_CO2 = 5e-3 -f_Na = f_Cl + t_CO2 * 2 -pks1 = np.zeros_like(f_Cl) -pks1[0] = prmlib['equilibria']['H2CO3']() / -np.log(10) -pks2 = np.zeros_like(f_Cl) -pks2[0] = prmlib['equilibria']['HCO3']() / -np.log(10) -for i in range(1, len(f_Cl)): - totals = pz.odict({"Na": f_Na[i], "Cl": f_Cl[i], "CO2": t_CO2}) - solutes, pks = pz.solve(totals, library=prmlib) - # pH = -np.log10(solutes["H"]) - pks1[i] = pks["H2CO3"] - pks2[i] = pks["HCO3"] - -fig, axs = plt.subplots(nrows=2, dpi=300) -ax = axs[0] -ax.plot(f_Cl, pks1) -ax.scatter("Cl", "pks1_meas", data=table4) -ax = axs[1] -ax.plot(f_Cl, pks2) -ax.scatter("Cl", "pks2_meas", data=table4) -plt.tight_layout() diff --git a/tests/test_TM83.py b/tests/test_TM83.py deleted file mode 100644 index c2098f20..00000000 --- a/tests/test_TM83.py +++ /dev/null @@ -1,50 +0,0 @@ -import pandas as pd, numpy as np -from matplotlib import pyplot as plt -import pytzer as pz - -# Import data from Table 1 -table1 = pd.DataFrame( - { - "Na": [0.485, 0.959, 1.96, 2.86, 3.83, 3.81, 4.76, 5.235, 5.222], - "Mg": [0.025, 0.05, 0.05, 0.15, 0.18, 0.2, 0.25, 0.275, 0.29], - "Cl": [0.525, 1.05, 2.05, 3.15, 4.182, 4.2, 5.25, 5.775, 5.79], - "HCO3": [ - 0.0015, - 0.00075, - 0.00043, - 0.00042, - 0.00063, - 0.00063, - 0.00067, - 0.00065, - 0.00066, - ], - "CO3": [0.0034, 0.0039, 0.0046, 0.0045, 0.0043, 0.0043, 0.0043, 0.0042, 0.0042], - "pks1": [5.973, 5.931, 5.946, 5.993, 6.071, 6.063, 6.152, 6.205, 6.22], - "pks2": [9.33, 9.15, 9.17, 8.95, 8.93, 8.93, 8.88, 8.93, 8.87], - } -) -table1["ionic_strength"] = ( - table1.Na + 4 * table1.Mg + table1.Cl + table1.HCO3 + 4 * table1.CO3 -) / 2 -table1["sqrt_is"] = np.sqrt(table1.ionic_strength) - -fig, ax = plt.subplots(dpi=300) -ax.scatter("sqrt_is", "pks1", c="Mg", data=table1) - -# # Calculate total salts -# table1["MgCl2"] = table1.Mg.copy() -# table1["NaCl"] = table1.Cl - 2 * table1.MgCl2 -# table1["NaCO3"] = table1.Na - table1.NaCl -# table1["dic"] = table1.NaCO3 / 2 - -# # Solve -# totals = pz.odict() -# totals["Na"] = table1.loc[0, "Na"] -# totals["Mg"] = table1.loc[0, "Mg"] -# totals["Cl"] = table1.loc[0, "Cl"] -# totals["CO2"] = table1.loc[0, "dic"] -# solutes, pks = pz.solve(totals) -# pH = 10 ** -solutes["H"].item() - -# test = pz.solve_df(table1[["Na", "Mg", "Cl", "dic"]].rename(columns={"dic": "CO2"})) diff --git a/tests/untitled0.py b/tests/untitled0.py deleted file mode 100644 index e69de29b..00000000 From 5ad0f1d2e8f28d31af5c42f0e0d948f0ed6d490e Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Thu, 24 Feb 2022 11:27:30 +0100 Subject: [PATCH 19/58] Update HE93 --- docs/refs.md | 3 +++ pytzer/dissociation.py | 24 +++++++++++++++++++++++- pytzer/libraries/HeMorse93.py | 4 ++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/refs.md b/docs/refs.md index 93a1ab6d..4778e68d 100644 --- a/docs/refs.md +++ b/docs/refs.md @@ -142,6 +142,9 @@ ??? citation "PB82: Plummer & Busenberg (1982) *Geochim. Cosmochim. Acta*" Plummer, L. N., and Busenberg, E. (1982). The solubilities of calcite, aragonite and vaterite in CO2-H2O solutions between 0 and 90°C, and an evaluation of the aqueous model for the system CaCO3-CO2-H2O. *Geochimica et Cosmochimica Acta* 46(6), 1011-1040. [doi:10.1016/0016-7037(82)90056-4](https://doi.org/10.1016/0016-7037(82)90056-4) +??? citation "PPFD88: Plummer et al. (1988) *PHRQPITZ manual*" + Plummer, L. N., Parkhurst, D. L., Fleming, G. W., and Dunkle, S. A. (1988). A computer program incorporating Pitzer's equations for calculation of geochemical reactions in brines. Water-Resources Investigations Report 88-4153, U.S. Geological Survey. pp. 309. [doi:10.3133/wri884153](https://doi.org/10.3133/wri884153) + ??? citation "PMR97: Pierrot et al. (1997) *J. Solution Chem.*" Pierrot, D., Millero, F. J., Roy, L. N., Roy, R. N., Doneski, A., and Niederschmidt, J. (1997). The activity coefficients of HCl in HCl−Na2SO4 solutions from 0 to 50°C and ionic strengths up to 6 molal. *Journal of Solution Chemistry* 26(1), 31–45. [doi:10.1007/BF02439442](https://doi.org/10.1007/BF02439442) diff --git a/pytzer/dissociation.py b/pytzer/dissociation.py index 59d49357..15de9edd 100644 --- a/pytzer/dissociation.py +++ b/pytzer/dissociation.py @@ -1,6 +1,8 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. # Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) -"""Evaluate thermodynamic equilibrium constants.""" +"""Evaluate thermodynamic equilibrium constants. +All functions return ln(K) values. +""" from collections import OrderedDict from jax import numpy as np @@ -201,6 +203,26 @@ def CaF_MP98_MR97(T=298.15): return -_MP98_eq24(T, A=3.014, B=-501.6) * ln10 +def MgCO3_PPFD88(T=298.15): + """MgCO3 formation [PPFD88 table 1].""" + log10_kMgCO3 = -32.225 + 1093.486 / T + 12.72433 * np.log10(T) + return log10_kMgCO3 * ln10 + + +def CaCO3_PB82(T=298.15): + """CaCO3 formation [PB82 eq. (53)] between 5 and 80 °C. + PB82 eq. (44): K(CaCO3) = a(CaCO3) / (a(Ca) * a(CO3)). + """ + log10_kCaCO3 = -1228.732 - 0.299444 * T + 35512.75 / T + 485.818 * np.log10(T) + return log10_kCaCO3 * ln10 + + +def CaCO3_PPFD88(T=298.15): + """CaCO3 formation [PPFD88]. Slightly different from PB82.""" + log10_kCaCO3 = -1228.806 - 0.299440 * T + 35512.75 / T + 485.818 * np.log10(T) + return log10_kCaCO3 * ln10 + + def MgCO3_MP98_MR97(T=298.15): """MgCO3 formation [MP98 following MR97].""" return -_MP98_eq24(T, A=1.028, C=0.0066154) * ln10 diff --git a/pytzer/libraries/HeMorse93.py b/pytzer/libraries/HeMorse93.py index 16267195..7cd55298 100644 --- a/pytzer/libraries/HeMorse93.py +++ b/pytzer/libraries/HeMorse93.py @@ -279,3 +279,7 @@ HeMorse93.update_nca("CO2", "Mg", "SO4", prm.zeta_CO2_Mg_SO4_HM93) # Equilibria HeMorse93.update_equilibrium("H2O", k.H2O_MF) +HeMorse93.update_equilibrium("H2CO3", k.H2CO3_PB82) +HeMorse93.update_equilibrium("HCO3", k.HCO3_PB82) +HeMorse93.update_equilibrium("MgCO3", k.MgCO3_PPFD88) +HeMorse93.update_equilibrium("CaCO3", k.CaCO3_PPFD88) From b4d6e232a2a15d23d6c274ad3a0b6b441160bec7 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 13 Dec 2022 16:46:45 +0100 Subject: [PATCH 20/58] Testing vs HWT22 --- pytzer/libraries/Humphreys22.py | 89 ++++++++++++++++ pytzer/libraries/__init__.py | 2 + pytzer/parameters/__init__.py | 76 ++++++++++++++ tests/data/Humphreys22-SI21.xlsx | Bin 0 -> 6272 bytes tests/data/Humphreys22-SI7.xlsx | Bin 0 -> 13249 bytes tests/test_HWT22_params.py | 174 +++++++++++++++++++++++++++++++ tests/test_HWT22_solver.py | 138 ++++++++++++++++++++++++ 7 files changed, 479 insertions(+) create mode 100644 pytzer/libraries/Humphreys22.py create mode 100644 tests/data/Humphreys22-SI21.xlsx create mode 100644 tests/data/Humphreys22-SI7.xlsx create mode 100644 tests/test_HWT22_params.py create mode 100644 tests/test_HWT22_solver.py diff --git a/pytzer/libraries/Humphreys22.py b/pytzer/libraries/Humphreys22.py new file mode 100644 index 00000000..83dcf8f4 --- /dev/null +++ b/pytzer/libraries/Humphreys22.py @@ -0,0 +1,89 @@ +# Pytzer: Pitzer model for chemical activities in aqueous solutions. +# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +from . import ParameterLibrary +from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical + +# Following Supp. Info. part 6 +Humphreys22 = ParameterLibrary(name="Humphreys22") +Humphreys22.assign_func_J(unsymmetrical.P75_eq47) + +# Table S6 (Aphi and equilibria) +Humphreys22.update_Aphi(debyehueckel.Aosm_M88) +Humphreys22.update_equilibrium("H2O", k.H2O_MF) +Humphreys22.update_equilibrium("HSO4", k.HSO4_CRP94) +Humphreys22.update_equilibrium("MgOH", k.MgOH_CW91) + +# Tables S7-S11 (beta and C coefficients) +Humphreys22.update_ca("Ca", "Cl", prm.bC_Ca_Cl_GM89) +Humphreys22.update_ca("Ca", "HSO4", prm.bC_Ca_HSO4_WM13) +Humphreys22.update_ca("Ca", "OH", prm.bC_Ca_OH_HMW84) +Humphreys22.update_ca("Ca", "SO4", prm.bC_Ca_SO4_WM13) +Humphreys22.update_ca("H", "Cl", prm.bC_H_Cl_CMR93) +Humphreys22.update_ca("H", "HSO4", prm.bC_H_HSO4_CRP94) +Humphreys22.update_ca("H", "SO4", prm.bC_H_SO4_CRP94) +Humphreys22.update_ca("K", "Cl", prm.bC_K_Cl_GM89) +Humphreys22.update_ca("K", "HSO4", prm.bC_K_HSO4_WM13) +Humphreys22.update_ca("K", "OH", prm.bC_K_OH_HMW84) +Humphreys22.update_ca("K", "SO4", prm.bC_K_SO4_HM86) +Humphreys22.update_ca("Mg", "Cl", prm.bC_Mg_Cl_dLP83) +Humphreys22.update_ca("Mg", "HSO4", prm.bC_Mg_HSO4_RC99) +Humphreys22.update_ca("Mg", "SO4", prm.bC_Mg_SO4_PP86ii) +Humphreys22.update_ca("MgOH", "Cl", prm.bC_MgOH_Cl_HMW84) +Humphreys22.update_ca("Na", "Cl", prm.bC_Na_Cl_M88) +Humphreys22.update_ca("Na", "HSO4", prm.bC_Na_HSO4_HPR93) +Humphreys22.update_ca("Na", "OH", prm.bC_Na_OH_HWT22) +Humphreys22.update_ca("Na", "SO4", prm.bC_Na_SO4_HM86) + +# Table S12 (cc theta and psi coefficients) +Humphreys22.update_cc("Ca", "H", prm.theta_Ca_H_RGO81) +Humphreys22.update_cca("Ca", "H", "Cl", prm.psi_Ca_H_Cl_HMW84) +Humphreys22.update_cc("Ca", "K", prm.theta_Ca_K_HMW84) +Humphreys22.update_cca("Ca", "K", "Cl", prm.psi_Ca_K_Cl_HMW84) +Humphreys22.update_cc("Ca", "Mg", prm.theta_Ca_Mg_HMW84) +Humphreys22.update_cca("Ca", "Mg", "Cl", prm.psi_Ca_Mg_Cl_HMW84) +Humphreys22.update_cca("Ca", "Mg", "SO4", prm.psi_Ca_Mg_SO4_HMW84) +Humphreys22.update_cc("Ca", "Na", prm.theta_Ca_Na_HMW84) +Humphreys22.update_cca("Ca", "Na", "Cl", prm.psi_Ca_Na_Cl_HMW84) +Humphreys22.update_cca("Ca", "Na", "SO4", prm.psi_Ca_Na_SO4_HMW84) +Humphreys22.update_cc("H", "K", prm.theta_H_K_HWT22) +Humphreys22.update_cca("H", "K", "Cl", prm.psi_H_K_Cl_HMW84) +Humphreys22.update_cca("H", "K", "HSO4", prm.psi_H_K_HSO4_HMW84) +Humphreys22.update_cca("H", "K", "SO4", prm.psi_H_K_SO4_HMW84) +Humphreys22.update_cc("H", "Mg", prm.theta_H_Mg_RGB80) +Humphreys22.update_cca("H", "Mg", "Cl", prm.psi_H_Mg_Cl_HMW84) +Humphreys22.update_cca("H", "Mg", "HSO4", prm.psi_H_Mg_HSO4_RC99) +Humphreys22.update_cca("H", "Mg", "SO4", prm.psi_H_Mg_SO4_RC99) +Humphreys22.update_cc("H", "Na", prm.theta_H_Na_HWT22) +Humphreys22.update_cca("H", "Na", "Cl", prm.psi_H_Na_Cl_HMW84) +Humphreys22.update_cca("H", "Na", "HSO4", prm.psi_H_Na_HSO4_HMW84) +Humphreys22.update_cc("K", "Mg", prm.theta_K_Mg_HMW84) +Humphreys22.update_cca("K", "Mg", "Cl", prm.psi_K_Mg_Cl_HMW84) +Humphreys22.update_cca("K", "Mg", "SO4", prm.psi_K_Mg_SO4_HMW84) +Humphreys22.update_cc("K", "Na", prm.theta_K_Na_HMW84) +Humphreys22.update_cca("K", "Na", "Cl", prm.psi_K_Na_Cl_HMW84) +Humphreys22.update_cca("K", "Na", "SO4", prm.psi_K_Na_SO4_HMW84) +Humphreys22.update_cc("Mg", "MgOH", prm.theta_Mg_MgOH_HMW84) +Humphreys22.update_cca("Mg", "MgOH", "Cl", prm.psi_Mg_MgOH_Cl_HMW84) +Humphreys22.update_cc("Mg", "Na", prm.theta_Mg_Na_HMW84) +Humphreys22.update_cca("Mg", "Na", "Cl", prm.psi_Mg_Na_Cl_HMW84) +Humphreys22.update_cca("Mg", "Na", "SO4", prm.psi_Mg_Na_SO4_HMW84) + +# Table S13 (aa theta and psi coefficients) +Humphreys22.update_aa("Cl", "HSO4", prm.theta_Cl_HSO4_HMW84) +Humphreys22.update_caa("Na", "Cl", "HSO4", prm.psi_Na_Cl_HSO4_HMW84) +Humphreys22.update_caa("H", "Cl", "HSO4", prm.psi_H_Cl_HSO4_HMW84) +Humphreys22.update_aa("Cl", "OH", prm.theta_Cl_OH_HMW84) +Humphreys22.update_caa("Ca", "Cl", "OH", prm.psi_Ca_Cl_OH_HMW84) +Humphreys22.update_caa("K", "Cl", "OH", prm.psi_K_Cl_OH_HMW84) +Humphreys22.update_caa("Na", "Cl", "OH", prm.psi_Na_Cl_OH_HMW84) +Humphreys22.update_aa("Cl", "SO4", prm.theta_Cl_SO4_HMW84) +Humphreys22.update_caa("Ca", "Cl", "SO4", prm.psi_Ca_Cl_SO4_HMW84) +Humphreys22.update_caa("Mg", "Cl", "SO4", prm.psi_Mg_Cl_SO4_HMW84) +Humphreys22.update_caa("Na", "Cl", "SO4", prm.psi_Na_Cl_SO4_HMW84) +Humphreys22.update_aa("HSO4", "SO4", prm.theta_HSO4_SO4_WM13) +Humphreys22.update_caa("K", "HSO4", "SO4", prm.psi_K_HSO4_SO4_HMW84) +Humphreys22.update_caa("Mg", "HSO4", "SO4", prm.psi_Mg_HSO4_SO4_RC99) +Humphreys22.update_caa("Na", "HSO4", "SO4", prm.psi_Na_HSO4_SO4_HMW84) +Humphreys22.update_aa("OH", "SO4", prm.theta_OH_SO4_HMW84) +Humphreys22.update_caa("K", "OH", "SO4", prm.psi_K_OH_SO4_HMW84) +Humphreys22.update_caa("Na", "OH", "SO4", prm.psi_Na_OH_SO4_HMW84) diff --git a/pytzer/libraries/__init__.py b/pytzer/libraries/__init__.py index 13cb4b16..c454c1c4 100644 --- a/pytzer/libraries/__init__.py +++ b/pytzer/libraries/__init__.py @@ -6,6 +6,7 @@ from .Greenberg89 import Greenberg89 from .Harvie84 import Harvie84 from .HeMorse93 import HeMorse93 +from .Humphreys22 import Humphreys22 from .MarChemSpec import MarChemSpec from .MarChemSpec25 import MarChemSpec25 from .Millero98 import Millero98 @@ -22,6 +23,7 @@ GM89 = Greenberg89 HMW84 = Harvie84 HM93 = HeMorse93 +HWT22 = Humphreys22 myMCS = MyMarChemSpecCO2 MCS = MarChemSpec MCS25 = MarChemSpec25 diff --git a/pytzer/parameters/__init__.py b/pytzer/parameters/__init__.py index 5291ab64..b8dcd0bd 100644 --- a/pytzer/parameters/__init__.py +++ b/pytzer/parameters/__init__.py @@ -11806,3 +11806,79 @@ def theta_H_Na_HCW22(T, P): theta = 0.0306 - 0.000418 * (T - 298.15) valid = (T >= 278.15) & (T <= 318.15) return theta, valid + + +def HWT22_eqS5_7(T, q): + return ( + q[0] + + q[1] / T + + q[2] * np.log(T) + + q[3] * T + + q[4] * T**2 + + q[5] / (T - 227) + + q[6] / (647 - T) + ) + + +def bC_Na_OH_HWT22(T, P): + """c-a: sodium hydroxide [HWT22].""" + # This is PP87i but with P set to 1 bar and then the coefficients rounded off + b0 = HWT22_eqS5_7( + T, + [ + 2.76821967e2, + -7.37517417e3, + -4.93599700e1, + 1.09458239e-1, + -4.02243907e-5, + 1.19311220e1, + 2.47767456, + ], + ) + b1 = HWT22_eqS5_7( + T, + [ + 4.62869770e2, + -1.02941810e4, + -8.59605810e1, + 2.39059690e-1, + -1.0795894e-4, + 0, + 0, + ], + ) + b2 = 0 + Cphi = HWT22_eqS5_7( + T, + [ + -1.66864917e1, + 4.53597896e2, + 2.96807720, + -6.51722200e-3, + 2.37747753e-6, + -6.89238990e-1, + -8.1156286e-2, + ], + ) + C0 = Cphi / (2 * np.sqrt(np.abs(i2c["Na"] * i2c["OH"]))) + C1 = 0 + alph1 = 2 + alph2 = -9 + omega = -9 + valid = np.isclose(P, 1, **pressure_tol) + return b0, b1, b2, C0, C1, alph1, alph2, omega, valid + + +def theta_H_K_HWT22(T, P): + """c-c': hydrogen potassium [HWT22].""" + # assuming CMR93's lowercase t means temperature minus 298.15 K + theta = 0.005 - 0.0002275 * (T - 298.15) + valid = (T >= 273.15) & (T <= 328.15) + return theta, valid + + +def theta_H_Na_HWT22(T, P): + """c-c': hydrogen sodium [HWT22].""" + theta = 0.0306 - 4.18e-4 * (T - 298.15) + valid = (T >= 273.15) & (T <= 328.15) + return theta, valid diff --git a/tests/data/Humphreys22-SI21.xlsx b/tests/data/Humphreys22-SI21.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..187ce3fc48e1d0268a5b6eea9f630e60fbcb3d39 GIT binary patch literal 6272 zcmaJ_1zc3!wuhkxWatp78S*2f8z~im8IVT0Q^bM`*?Z6W@3mL_)nHiI6c|7t5X06dRvY7*+(6x%xL7&3^75eD z%EXR`U3`RLd)`r;C&Kfxz}%u1WyKbV5W`y*1nuj{{O;g`;+*~bFU<=V zlo8wud~7h|NNv4H0FuqZx43)Y(%F+&WGK(?9jTathT}a>muITbqroM){sM2ecqqY_ zLlxK<=7z<#C5Du2xQmgtyTGMo#CnL{b_|)bjZWT2f9%!}6}Y`HLWz;iOImRG5mOT6 zX)jbc-=|otl?-GRM&P+%<=Zsyc`uoWhLBHDh4ckveYcltq9G3QGkM@^YAShi)4Ge3 z`4R3=D_IDijhnX$v#+A^ZZ;*opb0cuKkH&(om>ru2MkRYO5a6+Fbu%JQ2Vbi5u<+L z;lS(e=wff~=xER50e6VioO7AwBk|pPhQ z@$;n0Dx+vZ`UtZC`DJ@%er0W_DP=+MCRcrwo)}>&9_MtZ+Igz4w<4b4y54Hpq6SyQ z3=VgT9?~GIUffcj@s3xu!ysq3_0qXWbTHH|j2+Y2Ok8@C=l**LC_-`MDSNDrf2krARozevTzeCT< z_XV;T<5ZwC{9H}-vavd6N37>W;u;Eu&~-{WNCw`D^cpcRHd)E4cSeE%Cu4ih!(O7> z0Nx#~)4Rqas^6cQD{fp)s!nm*&eZZ$jrdL-^6-L1D_502pVDaIlj`mn3qgf#;KZ22 zr*nkdHdo9HcZR~?y{!3$;HVjv9GgNuDkIYH&e9~C9Ir}w(5a(@i{zH7YExkI3p3dB z;g%py$xLu)Rw!i}%R6hxU#7cJy^v$RNyNiLYGBv_xv$oJh=VxIUou~Vz*8YlW7~N) z9y`i1u_tzcft^&;!#~FIB&#(N(|7&*l%fV@*}=uE>-4b^GtW*YY|{se#=!dF`EoZA z?7_tO`>cQ$qQrh zauc-O2&F$WJjcYqaKid0y8-=eH?D4;4py#ctJ%>ta(u~0;rqF|=AsQ?m;Q!a?MY_p zv4FNcr*``BVgP3OrR2c zK0rQI`3D}P9dn)s`-Ff((h(9$I)$2d1jgNrcMI*K9HBA7d<>0Irln85_Z@2Kn} zw1fjnS8mc!V>++OV6j1*&p*=c;&tbG0f-}Ru?GsP;!u+Hnv-_0?7z$o6*vEwW(0v! zCF=4i#Ei~%B!w9=l@7kjY-ekZ=8qC`@#Kh{n05cM2SVC8TmlP?F4;ygopm9VwX2ad z0dHigxeiGhO9?iLYR{veK-B4#A9{rp@jFxBwJst!PoT#Z2qNepMOHGUGMDjf=kP8k zRCkCKh)ut%Ws$ctxXn2tF{aNqq37ygyKxF9m94{KDuHQsR|AN*{Z`yA~o$X3DT*^6xb&~Hf<87o03uo4FioaEZ4d0WrG~n zdx$=5kcQ%crQzH%$Lzd~2}61Tl}mKE?8@^?h>(kMOp!ulSrcZ<5m}aS;7|r9>(Ys9 zLOf!&pmfs`gLB+Fqf$PFMQ}2!u%TZe?LgF%;OUTNxobv=^rw-@X4!>jseN*TH_V?d z7~t{$`)Y|uW7wOJSrhumB|L%D5S(Eb-ni0@nU-m5>GHXvYv1DcdoJ^6VfygF*S#I( ztFn5WxryV=k(?{Aow0#Gvbw*D%BCh9;4Mnhv3D#TdVKIkm#hrmoq11u3Cb5Xb==Vx z;B>)+d2!_bq+ljMXb!3mjr7!a&zQipIb$CNPt63lH^;iiT0PE^QxIoV`()I^mS$bk zbQa~0g*N|rYg*B6l*^PM|0nam`P*%}+FDt;x$^${;zyqZWSWudtOQBe-bnSgA8j`e zDaSD-Kp{mSY%;LraHe^5P9*%a7m#>y#@vTH_?Uf1KIvt53gh1UmKNNK;f5DtE^o9f zW7v(RtF?^6*)WOq4kn*aA1=Lkvt^mc0*Umv+p^0w^vMzFFCod3RVQ3Hu8x~nu~k*5 z-0o#eRbi+6ia^yaud1RkB2ue(xo<#2PRSM##ayjZ`KC3srhDkN52e3(aJ3G14iW9wDSJPV_JwwQcy~!cX+i^MNRp;|pXN!+$ch>b_uDC5WZZDq4WjYMG-=kb( zW13kg(Yt`?ikahUmuomg^+>jD9e#oK<(`%MESZ$K&G7<{>vf#tzCan2p$B65q#zd1 zz=?{8fW|}X>V4*CM7VdGnO-Vxk|ay=9B&y=I!~+Amm~=EY3}5y<}0#qNd#K^bDmd* zZM8Zxi~z_uN-rM2cJs49gqQ12l6tPuGQ*s;pLH{DjCd){Rc>meao6{9jIC(iUy`_A ziTKK&zT)Xup7irk@|vzNywRtXcWCq|meV6QM8mA_Zqsh_4z%2N>W*Rofs6d>Pn^qM z@+!wKIlKJ|#!Kv+FRNhf#y^gH2TM)tvU~$3eDkE! z?U3UFXLqf^j(FHM;})wz1IOuNRbXJ!K5-2?+`Tq40a{9!=A ztrfhWfOm~|Nk(tVzzc|OtxyMHtW}X>3%vu%z5N)An$9~IwE%t)#*<(bL~^q2 zgCy8mUUA@@@f#>D7np%+?sm+#b9S+Ue*8ERk@obWojM8%G7|DTADgSG3pPn5#rCs! zLu&6qicQ2D^ma*}M66Y@F-OTC0vuhtB`5oU85@%ZrJbc)Fc_R48JiKvhCZ<3!Pcn| zplz5q3Pox($mn&+Q0o!{$2*Hf{oil5i*~(k7w?KVbocl0uSd0FKB%_+1l?xOG48Z} z?;A#r!)CQ=?myJ1Q&_9u7<*~|ekZATWeVRgP2JNYb`ZyVC6Yxwn=LVF9JX7V9^lqMx6N6~oa8=V+RF+%6KtZm9XRCcM0!!z-x$Jp39J%~?v(yHwQ)b%)j z;%F+R&$m^*bb;WQY2YvB(gbNp=!7@* z_?$W!J}r7k>|KSt!bFD}dbLDlR$L5>2Ks*rHMjl_HGkJK*Yoth>zV`=`(JgGi8aHX*9}Mfxk@#^?F*K}gN8Ku%IbxA9{?H|)o-U><0!pZ z|FL$V_*V{UYvy8Qsp;lohp_pTiavid5H~AJ(z?MFzZcWuy})HkTpk;r2MT9lTzqRO z+bOc2s(o-m)5}_1A_kCeDlMy`(HUt!J6x7hSra1K3ZoQ`7TSK_W!Jm4J~#brV3fQ6 z6DWN54w2pb#lu3+1s~n#0=%1#!e1fc4t+cy&%KfX^NT@V=wW(ClA?bxVc@3I^HQExx8M~QbwkNPnUrHi%BLoChUYusd ziBC^$#i^Z=hh$853hJ)#k13`t-dunF7elAM{6k<$?DLdG(?<0a6`!}sH$R&CB^_uJ zC%>?$PX!kke*4xc0?cn^`hal5jeMAItw0<;;YFG}eS`L+DA}HA1w>g;XRO6wR!vM{ z!>my|E7p(YEJb+GZ$zLmMB84)bY%Wjh16zlbj4C)xmEP~7b+{U0SRDh@qOH^X@kI) zpgRgjgZO~McV$>bX*xPdmHTp~v7QBcAdmG)dVKy?9vWDDDSk7x7;g0yWkuJ_o@CyB z+q9EAzMY4vQ9aQP4{d#pco~PwH$r{7X4Thw_?aCNduG0`N!?DEaQMh52M8}kDhr;@ zVM*TAwg{_fn_{yQOKUTZt`Bo%q&S2(G4@IM5!qv%NWJ%hg}5@BwZnz!ZZqdDF3}Lm zUt|RvKX$aik{3InTgoK*esC~C2%e2R)q>vg8kXd@qfB!r|P-oq$IDWAolp`G1s8u6A$QT*c` z^3I&|!Hn@_2T}b}EVmk+iW)|uNX$T)EN{8IM>N19(y{=-Lh%Iycc{NSqbx?`R+d}7 ztN{_5(}QtKElOL9%6>i(H>{x4UXB9h=~$}nX01oMq-XM+Z~H6-dH~#J-DKOKd%_ZV z`K?VI-|L4jvMy4s$$Me^%BF-m|PD&AN&H`74FGS18MJ1zuDpjGjTON3_ffO0MSP> zACDvy`4#-|Dd@;4uP}T6^D|dc)tA(>s-fc*@{%2eTjbOR2>UNfkc&gc0Y~%(jfV_y znWM_uxqoyiB-b~{%*hG8Kbi3=j-6=g=$ul!`?U&(L8;oUdb?SCJ4rX&22Pk^Z!#|{ z2j`U^rqJS@?Ct3(i*wd3rSfeIX+?W|Azo;5;F6AFo&A{2Ns8!SHxg(%l7&a}n6c}N zh*!G|@T8$YJ*L#rJl_~ZsPm%tC^tnZT*IcuxGoji-u3h*OZcM!1rXbE8Mi&5CN{I| z>Mp^3>g7$6s~eOl*}FI9cE6B4OC+k-wE@IeVwuXOMlJTlDDr>7h@8hdg4 z&CfXSMNghC)dvUWA+hf!D)ZCNX69wHjelS=?B``5V>BXLnSL-lWpd=znK;!{FA^iZ zu*3drSlEt+4K{MW{}csEItse~&LW{|rE7Nm#MR9a{tLO`T7phKiqNI`V&Kf27GA=5 zeYBXQ)=B)r8%$TnUX^HHZ|0!gxNt`4hZ9mi?^Te@kUnnW<>J7&4I*N{?fA1$OsS)9 z(Uc)1XAPIT<>|B`GfqSwW;8e0Uc8v%apA||MbHaz3m#^9M~y6J4WYQ<&a~}i%p?h| z59%|aRt>)p<441Ni>%&h2;$kmQx^N1l+Q+Cbmr$cfxjN1#njC<8H6#%*Dk>Tx zrW06zazUJ01aQ{xX7(`izYNC7de=OB}SzYVjsS{;}u}vL;R`GWY|eoM5>DHozX>=sg@@gY^h8&(n7k2+YC{G zm}Yf8G3bD#X>Ku=5`tER*&rT^cZ{Gf(|v4Pd?vgi&#RI5RH#Eu-wGS_VRQ`Z=6uq| zFrI4Et1Y-oKj!Xd5KOC&g#5gBfV-$zr;IC7yCSokPk(YrcWHN2l}GiXu3^cSSUS*m zSDF!1reU`6o1m`Pe7E~<#6uM@U`zh$i+fby+4dyKX9+yNG7$su>b04J+e51R>JQRQ zyw32^o3t$1Kx~OJyh$ANCSd|7Fn)8r*Xd0(*ZZGxjrsj^;B|fr&3^tCcGOaTaG`$= zzRnJyDX`ySf}+b%gMSlZe-6E#?V;&|-(rl)0spn`{~;6poaK6Egw70qOCRB{S^i6& z_~$&=;}trO`YkIcz0ivMnN|Hc!*z#>j%&Z=Im(OvpD6d|@av8R?R9^P2-&sa|MJ0q zj=p|;(az_$z)_FC7yn;Z^ydWEP3u1=kVnDs|D1U>7!GQiFfa&ER{$!8Y*M11{s-?% Blo9{{ literal 0 HcmV?d00001 diff --git a/tests/data/Humphreys22-SI7.xlsx b/tests/data/Humphreys22-SI7.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..0963fd78417db37a0037bd3e053a953645d36332 GIT binary patch literal 13249 zcmbWebyQxvx;>0rf#U93+}+*X-L1Gg6nA%bC{|pH^A;%X?(XjT!9HhvyJ!FIJ%8MX zfxLrcuH;$CoLR|S@=~B+C_qq9P(UJ%Q7S-x#HaVa^&CvB9O-C3epbeJ%l6X42A_F` zQ{J(x@I&Pl|CAR0Nyv=XMPh^95LN&PxV#lcMuLs1?Txng@qINcT9vk;UZp3K(hXD5 z2m@&+Gx9D0487XB)3J`^`}85Qiz(U)Q98uPNnQ_c2n-f_I>k!D>|e=9O#ts19UBAj z@P|0)sJJq|8i(!%Y8*!**_)~6&-;S41 znFPbQubOzb46U6d!eheHi_0LU5bmB1piMPJ6TT!49i*lrx3=s$*co0!jI<#I(wjMX z$`E^tOP}VT;xg$;MrdX~5A7n$OF=>fr8B3Wz9(T61PDm}e@)Zp_Y!Vabgs4zmWH;r zmb7lxR#D1J(Tns5-e+pUJ|WBBK!_^LflegbEf!9Bxkdw<*m6$yHa z8;%WgIF4=G=s};M)^A9XksLz+Kz}Qb?r;*WWhZA5UPKl#mIz9S4*UhoY=X}mM?<#8UYaSn+9hjKOsA4tp$TO zz7S;>Ef^_%54;8qMAgPV%4A0iPiq5tloDSyKFBfI_HcRhm_$vS@IfYr!EYw_P+kk+u{foS@8e*vboHsJyTC`;@_WvWe`;#So_}3ammG_I!5;7{Un$j} zR}W6;qcN|Sn^85a=`DW53YVi43&%`8{qBq1yX6hvqi7||2IXJ95!C)-Uh#yNBKn0} zk0yFOE!ah6c^1L8++EP817A46i9M8af;y7Rpn2bw7trow)}l^pFFNVYsrlLi=TKqf zHOcB@#PSM{m#2f=~=`D5WkNtO|btqzTo~f zz8sz0txOz0M%RhDj%@}#iuYPo^>fFiLV6>zymMCSEu)GhrAqqk`ZwV6KG8l4A>S7( zSg`&6R;NkDur_`CHOI3JeH^1VD-s7T=8;yDh2BP>vUQ!r-ZgJV+GM|Sc1q5+-Xje;6D3*mz85G`C}v$Snl zmVuQZnUJ{Wk5Snhc)L2D5pf$MzxcE#_zo3T2=Esv16{nWrJWJd|EikGEVGQC&*b;D zp9c#eJ)-RACXqs2b-5Q57ZeGYNhYC(4g|eOeNS~r$GPXMU!I&jrHY|It+pO19Zi<7 zr0#do{)r-)-6j>F5o`qhv~o;t3O3xQxdzuSbF7I|48_-y$TpKF0gWm_GLQGxMlxbF zFpmrkG6|(8xwVDP0B0nM*=BHFHbUb4%=k!DHzYTTWDFem|>8Ie7DKN*lq|_EL$EvC6XEbm0r8#a@mMer(PWcU26a*Y@EpAe-D(G5&TwL0MCWYk7$TONjVsBD zp*Vsyu_!q=lDBTyeoP7m`!j~c_ep_<_TMH2#^0ptXl`QSvrYX%&B%_NWCHrL&jaq=O<(Uj9_d-5q+4swf{AvSu9D1lOCIp23dHql zarY+Wfj6y8PYb1aHC1;{+_p_|^W`-U&2Sv2YoGZ!)qyBt}@}u>kzUmDBXp4XDRI=&3k!X2ktkbFXVHo z%8w{3@@T4tF7JKQJ-3z%R=DRUg55#Nsh8jPDeSbu&8k`QF{(FxeA*4iR^kDBS(=+X zYlDo1PC0n)13bT9G}A-cVO5g*=k_H6O~7(&SG>R6U@7y)WuHJcY^Px!1qV|Wi#tVw ze-_gDZsCS?^c}3X!=eouk;lX4`y!xqWpIzr(baqguH9Ad7w_57!4JF;azfpDiT;zX z>6eU70my1GqZX*e8;TKgkD_*_K@DJs6tV7xat9y~(zU_HTSoUEeLUX@Kfq+2h&je%|;A2}c zS?+HkxD%L-n@#=f(daZ8eLQmvCS+Y!dm3RUCh`l@K|-Jprvd>Hy=eTr*d7cK@*Uej zbQ>7l`cX|Cr+#>I-5ZSo00B-1F``aFE+*?@%o5Q1Vgz(Ns|(!(g|h4my+REGU50>R41R*P7WXG?8`nb} zuZwL5ZJe_yu;_5Ch2ws)|tAC^kiCCV2NVG~;nP zQSV~1F$NkQy>Fn8U&jen8KZCo;UXV2>>^*@fP<8K-b+H)w*%MjUl9xFpMt}^O4~>6 zm;B*+Yr%G#{fv9DzOufT_d+eAKi5g@`KHlXM2|ec8UNn)wj)*q$9Wc(kOrDP`U=a) zaXD2uFx*-BiM-1^4l;W4=(z6z)RxBf-zCQ*i7-QSrtH<11mSx%0pB4Ph?wC4szNj& zgCVOPP_Q0H0uJyyL8~6QAI-iO0+F3j+^e$g4mKD8z6xQu*Q(1i71{}4WDoM=WEZN1 z+X=dr+uxCIAbgFLS8AAku+&O5P|xdnHh_ICugPN-0$>SEMD_5`L=n0NU;4LV|0~n+ z=JPC3eKuMJH8o%T?uqI5-#>hxK&a{47xM%O@M#dkdI$Dt5-Wq-2wK&Po$C`Vi&EjR zNGKGb#*cpnmZSWLYI=xLAQ-zXP zs~x=ZdIE?q2bRQiV~^czR5<9<@a?&B9sp$Vhm3TK^Mtqy-Cgu>w$8Zl_`XxlIA%hW z4Ll!j4@(PEDzU|W-N-v?_lkbW`N^Lw1_{UKOjUBtjTih0@jxgwjn@o)F5M#mjH#|9 z#pQJO*Jc>Wx|vJFkBUnO44>+ivgm#X)WQW)6$_v9mz@p9jH}Y~m(9RD4}QwI!`e{w z)S;uVj5jsh-JEZqKQvoK=O>E|BoGid)&D`W8ULl(OYs@(2=8m!T(_}r=R77{4Hx%< z+zS#XBpGGiM*Mh60fG=-(N9Koq2~&$VT7z1<9l~KYiDj1;RNww z*^@gZOY{9a5M@Q*<+4)`dTxazqN=B+r@4_Pd|kPR<9$ZC;i`G1FnwNw)YTyU{&|mE%jiYI~!v z)o(n{r$@gFwi8ZZYY^s1@ODPn1Nl?4%Q0*`@hkKLL!~zMfhrDqYnS(S(Ys*VQ}nJA zMz%Ckw(w!Tq4lSQs{#g$6;n^jVLHH+O4^sUy#(v_ z54rqr#kp-*Bf8t92Rqn*ub5^c z#&tzzAtO`+(Lq6}`=#iNpQ1811DXlVgz@Neo$p{G+LJYoS4A)-kAAV~p_T#u^|B&b8I;#Ef8{gc{E000ve- z^X?jmKljtZ-rqtB@OMOftawsm$F3hF$R0CjG z(NAfEfLa8W&Iv!!mRbVfwa8rDGSp!OqzW$<5Cl-1`@7a&iu^A{G( zasDM=5Vc?}1$1k@2?eWZW0|@pFZQdp+kul@K>tNMF*lyaSc5P^Dk#{Bu*&&eKFXbc z2aii4=mnAm7-P@I(h0iz4Sfmn8!``TsTOhTc1Ce;2}Ixh>`_^s%;{?#K@VGwn93I^ zpeHaZA3|uzU@8Pcfe-*o#1QP{NDw3*L%2LH2fN*1I!A&z+ep@1%|3z64+9Mh>T@iM zu}2n^2o*@83=^oVTsRVI!y`@@Z}x?a`BNN!?+*&*3hS_7140lb@qNtw@;Uh;Lc^O0 zN=f~3N*Iw8(w!hx1rSizf@$*)`ArY^!t~7AY6Qm#Hh~$o2Zat{nYIg6hi$Zz_0K(& z@$bU3knmr(l@8vm+Ky0i0dM=WMCb^1v`Ws0B;--%Y&c=cZ17_w)iGbQ2!=C^!Xt8mT!EdXc-|$ ze702c5T%i3i@rio9|qbP)SDZdl0%vI`-B3oXVlPwD2UWrSxt)67W9tLZ4le!(U6-jeftK@AVF*dZb zj#kfY@60RFfXe8FUUQj`8H1XVWTXK}tFpfZscH{f(K1|UQHu%Q6{cD?K0Dyr&+RV_QyYN7ohU?#Z=v|t#dHKQtTd3IxeDvD@*Sr*crGqEcR@4sXN34eN3D72Z?OIAqHkd zow`+^-SLxA;@$mh7; z1(=@l{~*9je+h7^jO`LTLh#uW71)YpSn_sEkBb7AeJg(}1?vggJT~zJ1ER!qeErJy z+*#~nwKQXcTnAuse`oldkOk4~_CPJp)3XQMWM^3{VEj%ztu``w%<--N?j|Jc3_5HG zcCUiO@hu7JZE7=S!S4dShE&*NJr~8%m&)XZ0ZO=)6dVmyH4Z7;3WKgXQ0o;ZG#oke zKtKc!w$}~?B{kXSWP`X90J&skE@`9QN+nKVNuIf_F8F9DMK$5^l%%sww{;JsWPNo| zSGD2eNRhhz+*0ZzP1+&X?aJz{cs{`%~w&-Bj7P)h)HgDed%|hXWgPTKUje9(ZqwMJgYCrce`IsAkuZK+XjX&55<#pB4jK+};=+H_v5Imm+ zS(BqLBZf=@6kI|yGW8I8ey-5s1d#3tn|k!@WS1$+zGp2t$G$VKH}-wi9(rb=-Y`(v zxG(A|j#_?`|ADNyDzp2HRDF?#sHB-XZe3TWzV~`c@}t^-T7xi*%LznKKwO^^I=iZh3&(K_F^uA^|i-q^bBpU)oaPf}(sstbw*b%Rtqfn&*EeeC(tRypkxP>KWE})u<9G$8st?{!!)e)USqz;Emr;XY$!%br@ za5e8!E5^(zv5-RATG9HIGT{UkAqpXr(g)QPEtCF30QqhxM;p`50k4_{6Wex+vIVx9 zSlxK~Mk|Dj_3)9C0r)2bA=~;y5^&6D@@NrF&0+UGV^Y|Q&gbY*_B9AT87q#2PWU%G5-3u&0(oVsZN059lYp9Lk#YQ zI{-eaAxw_B)9?7)#9Ml~RXFV7Wj2g+bkyJshkblz%=Ok_VEMaLh^bZ9*?3Sc?jDmR z7njIxi4HlZzv$UCq|=EbPVJZstBRJ9?b@dp2Y9{Py-X!zg$7y2QG>V|?*QGB{LT8r z&q+3V9$Nk?Yd7<{p1h5-(nG{?I>bTtkA0G1SEv-E8|{rl*>)02PXh96Fr9|4(u8(D zuEwlj}dkMGy&5#u9 z7Cn_RW^(H&WikhO!x-&J)1SEg5RO__K&?Dg&F$x*q`)3sKCPK9CN)SYxkw|gq+to9 zE6RpVpgYL2vx!m0#Am#4@_LU%V@f@A=t5x?yULXq&8NBd1>?{XRKTfd5IEilqj=0 za`=QzaXts#cNjjh6ODne2Lw`sp~;Bw61$(GC$+E{qdL=gyw-sG7l`h|EQN!towAE0 zve|wsG5Ig%I;ziXZ84u47sg|kYwS|urIlsbC91z&N2KnGY@N7H59t9efP)verz9?Z ze6@HX)VoTVjIHyx1`rrqWTo>CmNM~Rnql2aQ2%;%PVoil=YTy8B2#Wl;#iE(ICzF^ zVr51Q^ff{p9)chT_iMzl{hc0~E@XLR z>+w5`fOwKHoC@n8#V7K6{D;PyQT0}Mdywz3M=qDBKF2Y1WYysKI@e|7HE^J{TgPTJqKq@}C0*y#6IBJppa zM+tK`kq1mLpO4du~k;b!=oWQMb`GmBXQ?q!h8u*ZS#((ROF0llCo7vAyICo}s zRbT%VSr-7#M96Ul(>*CU9n9VrV}TM^Vf}p?pG4Ud)G=kfEw;Qs<310Te6Qh4f#BZ1 ziFFju0nT!yQedm4B)#YdW;W%iwC;H6?rP#lsj*3Hq#WtzU~SP#0Pr}?$wrdJ=bLR* zu%=ewqWWXW+OJ+yzk$GE?1bp$^4x7F-C!<6x0tuG*<)T8SU~MkJUzAxY*9TuQp#JTa}r+l^R+UrPyDL9QcW?(fBTNFzk&=y2BRO) zr{=1bAi5xoC!O9k?B!*$yEQcI9M&ij`NS~CL#VexB#o8SB2j=xB%RL0*YZ0lO^%jn zj&xC!@t|M(E)c|-n89K?3Q(v}>yw(fP+Fn}!QI|0wS0(VtswUVJj;{E&r_Vne3+kI z#??@oV5{3b(0<#{+a5WeJArl)whKA{p||*ZW0eGEx>u9xD+l(^tQNc6^0l+;q1aY= zTe$QZmrfxb0qj$=MF-aKX-93UcVacWeJ55=oXIMFP8FR3y0vUIjsUtBb~6+U<%Xrq znhaN)obQJ^_~Ur5IrZi1vL({-j_F|~ZPa?24BfS-9u*bVF)A!GwPg9Fj=v(OT$7AOFGnQfz!=?{!(X(wNAYkeCB zBXr%53Kp6R;l=I?Z24^wk??bQ&|daFy(8h$R^5rx)?}iVRxj_dp;CPz+35l>w2#PT zJjU=lTR*WYM+w7N11fuoW6R%&lHdX?q)M-LUrky>3$lSInro&nmgIMQQEk5VfWLtY z$PI0Y-9<_%3v*0z>`o%{QB{5|C9pc;iq$taGSx)%e)-A=ity9BewK#RnlELPMb-SA zW9RDb6~iZvY#42gJNLhQKPVP;Tm}pG|4Okee^IQO%m>B(bu1La0Fl6M;`wzmW?m)j zW}57SVKD<0LuJrXZnL*S< z3kIfdUb?<54K#!bXoQ1|+;w_2)t#enso9vmh|qnLApX+B$HIfpqxQn7>nLHsL-r6< z3|kcO^gEDZ+c*W{wvwexSn#0aA|!R6g1LO)AR~;BHc3ClP>dQ2^e~7Z^`Jxl7Ws9{ z)f!H>xeqH=xoHvDOs)Erckb-Gh-6#3S{+_6IXTZ+j>Dd;(y@4h#jhx|6X%MKKeKn^ zHW2Bd%&2}(N#->`iy;r`>Wmsh$50qNxB&bwcw-^vxqdb5#*`5R2sJPxV2{=8MG}R7?6$NBP!V`A@)+fY_)y zZs5aWmcwS^AcdYI_SY6Cn!g27z>`L6+PH{GbPr8gwwl$OhT26&E0Tp_mC7K}=@l6jalI%_7t0x7=l18J3g2&V+Yq(xejEL{nMMJ`R4HH6bJT z)G1Dqkmk(=MP@XH8+AnO_XWE`5njL()NRg|K-7dnX(XJPZxgxr+uR1Tb(db|s6`81 zfd*07uF~iz+LydbFO>Kq@b5167df$CdNkVQbJw87#XuJo5+jCgQssnpWDj8OdO%yu z8i9^1P9b_r9sSjNksS5(m(lvHjnH(4zelOxR=YtAl|dTu&+3H!z8nv_-(oeM3W~H{ zjI~C0*qT9r+%99m_O3N8ut|0K)8VNVkG&fpdz zb)4#Bwpw#tiSK$chHi@?-4_(yEx7oRklU}Zj*WC}0Gr)lMslBLn_wRq)nf7VTAWPz zN?yL{TOoQOoGB_{3I>=lh(<`Ls)kkMH6~dr<)%f{}?=$heF|_~ZPLVqv1SS7}a~*_!Q(sygWEoqAobioG<=uqN94Mwgrx2~w^Vi9%j6iQ~ zN0}f^fHSM5vPs(QBalM>{3JVJ?Phmj9K`fq|Brm{u>?_LRD}o%~cBD7IhgrL8=Qj02ft4z2P?uFyU@o0`W~6<6 zVt_w}I9tVXuYJnFWe}7w=c%rz`?{= z$;rXO#_TV9Oj6p2&5|lY(49AopQnQ3-YaBnEtEXimr3eHULd2oM&JlV5l-{94k5~j zAK_;nAi7DK>0$z1Pfb zI>i@xPiC1vV@h(OuiB1}OQxR3+o^|cdN=6#IwJQBPU+_CYi(cKmPdOH@omRK9z3u^ zN*+vbQm&Q+L?$=5+hkWxFD`j$KI@E+pRAV5b*}cy-MuyA{G77);lXX{_e!nmE#O%> z9^N{6n$N-u`NhqPmppY*-SY~`DUH$+xp(A-oqV?xdcM|Yf)MG1Q3~}C#`B2md3x^R z?MG`Pzq_@=&HH&+2Fg>2{-7Zc1!4AvB3#&9O<3vsFk{5T-dYEvK7BOD-Fv$^{PZ+R?}ptiSi+`%z1<+ z-peA@<6u|9>dS{q>8;rMYQv`R;Z3Z}BoK<89)eQF3h1C%q|r=>N++NS@Wc&Z3m+Z0 zG?U@GQTO?C&q{A6Z5kDdq=vneJqQcGz4Nlu@AVH!7V=!G((3eIVQDy}zXF`IYkM=5 zPzE=+q-MXn!JBBBmHQ~l9nCGylTcq7I&-#26Q=+mc@1hG1%HLHO^7X!NZC*SNb;Nz z6e^+ZVlZRuYmz4Jj@p~E2A6sqr#eN-un#kpv+PqbAeRE43(_o5j0q4IBE0a#Me_K<;}rtxmktW6gSdb&(~eg4ufM6WnwpVdFW zZkH0eso_W9TCH~%rt=zaV)5eUEJ1{S1U>0pgaPZ9Gj&mnp`m7d_tf=YQ)o=1D0r)g z);}#lfiJW;?Z<;qR2 z;=GWBX%FJ2iaqV!3&*)OU)rZx(-Mg0yD{{`TdU)>ob~fnTjneH2Ma9De%bIp?_=NU{CSRrtbLKb!yBCko!@gD8AaRxKV?h}D- zkpuqd!}g7WYK!z-3C_|Zz8>45{yiJzoT1xNj9hLWR>4$=uX*R0zz0Kc!>bJpmI^hl!o7>HNgQd1d~ zbg;{gs&JuUzs_?g<;$ly%%@qA*i`r^;qy;_jGl295%spI+Hkv2j0>z?D(C=#p^ zm=$x>#gk{%xDdZLW-b*1!kTG^AbL@{p%7Yrf=mQ8a{}H3gLX=udK$S}0R@GiCnyp8 z&>cltQPR$epq1rh&~x$JTqPuC4DNz#mrK1*?$Ej@SB47Hby3V))4ntr9qz-Y5Rcb@ z&*!0gJI5x8lG`lZch$)5o(vhPaw2J)+~;$|_q$Xte+}}We66XESi?0*^^g3l{E z#q%Omfv|x1wS|s~0*D3X$jfdIGNZu=_$M0nKzPPsJEaz54>mF$>5(b<;b{8QYK$VF%VLP) z#f-EOC_FM}n^MepH}MCO0a0F6^%Rs@Q)+?gs{XlXRB)4O4klpEK9(@~6d4mB1J!Gt z1kw_alfP)~aupmvIkMDfTXi0{8h(Tn?0c-B7b*%j{9rE_O_BH>FPiB$*a(EqxMYv+ z%ifEpaW@}t>3P}ipZqHt2%S)a-Bz^it9kG=c#Qk`oV6RoL?D){T#zln7$I~w?w*CB zrs}p#+CqdP)3VPA+*ismjsWSJmU9HF2H^Asq^>ZSIV!ZoA^ht~EfxKrs#OxcacvOl zigW?dGFJC@*9_c9_$6YSTgT#FnQsX(H|+C1CBDp9RuXW=F{AenYY(4Rc5SXUE|3fA zZ}>v|USzy>;rG=&iRh!7VuGXcOL*B?0y_x;tn{o|n`FZRcIKG%etANd`d&r;f@2c=#`EN(`Kdb)fNBMAy{vDYR|NnLWAK&OdQT{ws`%e^k`2P{*FDJ`C zQU2T;{!f$%)c+CXuj9CXqWro2@t-L2*#9HSU%SfxMEUb^wTuzcx<(iSp<2 z{NvH(@30{K3*~=#kohOhp924}nEyL+$o|4{{O8jCp9p`7&&NXG?pMS1^=x6 zCk1~f)ZZaR{YUkG>(xJN|4DQoH2rr3()>~TZ_@rJz@Jm@KLNC9fq?!8c9fR_e;>X; RK=AKhsqb?Dnf~L`{|9<5jer0E literal 0 HcmV?d00001 diff --git a/tests/test_HWT22_params.py b/tests/test_HWT22_params.py new file mode 100644 index 00000000..64ef28f2 --- /dev/null +++ b/tests/test_HWT22_params.py @@ -0,0 +1,174 @@ +import pandas as pd, numpy as np +import pytzer as pz + +# Select parameter library +prmlib = pz.libraries.Humphreys22 + + +def compare_ca(sheet_name, tempK): + # Import coefficient values from paper + ca = pd.read_excel("tests/data/Humphreys22-SI7.xlsx", sheet_name=sheet_name) + for v in ["alpha1", "alpha2", "omega"]: + ca[v] = ca[v].fillna(-9) + ca = ca.fillna(0) + # Get coefficient values from parameter library + ca_pz = ca.copy() + ca_test = ca.copy() + for i, row in ca.iterrows(): + try: + res = prmlib["ca"][row.cation][row.anion](T=tempK, P=1)[:-1] + except KeyError: + print(row.cation, row.anion, "not found in prmlib") + res = 0, 0, 0, 0, 0, -9, -9, -9 + beta0, beta1, beta2, C0, C1, alpha1, alpha2, omega = res + # Rounding + beta0 = np.round(beta0, decimals=5) + beta1 = np.round(beta1, decimals=5) + beta2 = np.round(beta2, decimals=3) + C0 = np.round(C0, decimals=7) + C1 = np.round(C1, decimals=5) + alpha1 = np.round(alpha1, decimals=5) + # Fill parameter library values + ca_pz.loc[i, "beta0"] = beta0 + ca_pz.loc[i, "beta1"] = beta1 + ca_pz.loc[i, "beta2"] = beta2 + ca_pz.loc[i, "C0"] = C0 + ca_pz.loc[i, "C1"] = C1 + ca_pz.loc[i, "alpha1"] = alpha1 + ca_pz.loc[i, "alpha2"] = alpha2 + ca_pz.loc[i, "omega"] = omega + # Compute differences + ca_test.loc[i, "beta0"] = np.round(beta0 - row.beta0, decimals=5) + ca_test.loc[i, "beta1"] = np.round(beta1 - row.beta1, decimals=5) + ca_test.loc[i, "beta2"] = np.round(beta2 - row.beta2, decimals=3) + ca_test.loc[i, "C0"] = np.round(C0 - row.C0, decimals=7) + ca_test.loc[i, "C1"] = np.round(C1 - row.C1, decimals=5) + ca_test.loc[i, "alpha1"] = np.round(alpha1 - row.alpha1, decimals=5) + ca_test.loc[i, "alpha2"] = alpha2 - row.alpha2 + ca_test.loc[i, "omega"] = omega - row.omega + return ca, ca_pz, ca_test + + +def compare_cc(sheet_name, tempK): + cc = pd.read_excel("tests/data/Humphreys22-SI7.xlsx", sheet_name=sheet_name) + cc = cc.fillna(0) + cc_pz = cc.copy() + cc_test = cc.copy() + for i, row in cc.iterrows(): + try: + theta = prmlib["cc"][row.cation1][row.cation2](T=tempK, P=1)[0] + except KeyError: + print(row.cation1, row.cation2, "not found in prmlib") + theta = 0 + psi_Cl = prmlib["cca"][row.cation1][row.cation2]["Cl"](T=tempK, P=1)[0] + try: + psi_HSO4 = prmlib["cca"][row.cation1][row.cation2]["HSO4"](T=tempK, P=1)[0] + except KeyError: + print(row.cation1, row.cation2, "HSO4", "not found in prmlib") + psi_HSO4 = 0 + try: + psi_SO4 = prmlib["cca"][row.cation1][row.cation2]["SO4"](T=tempK, P=1)[0] + except KeyError: + print(row.cation1, row.cation2, "SO4", "not found in prmlib") + psi_SO4 = 0 + cc_pz.loc[i, "theta"] = np.round(theta, decimals=4) + cc_pz.loc[i, "Cl"] = np.round(psi_Cl, decimals=4) + cc_pz.loc[i, "HSO4"] = np.round(psi_HSO4, decimals=5) + cc_pz.loc[i, "SO4"] = np.round(psi_SO4, decimals=5) + cc_test.loc[i, "theta"] = np.round(theta - row.theta, decimals=4) + cc_test.loc[i, "Cl"] = np.round(psi_Cl - row.Cl, decimals=4) + cc_test.loc[i, "HSO4"] = np.round(psi_HSO4 - row.HSO4, decimals=5) + cc_test.loc[i, "SO4"] = np.round(psi_SO4 - row.SO4, decimals=5) + return cc, cc_pz, cc_test + + +def compare_aa(): + aa = pd.read_excel("tests/data/Humphreys22-SI7.xlsx", sheet_name="aa") + aa = aa.fillna(0) + aa_pz = aa.copy() + aa_test = aa.copy() + for i, row in aa.iterrows(): + try: + theta = prmlib["aa"][row.anion1][row.anion2](T=298.15, P=1)[0] + except KeyError: + print(row.anion1, row.anion2, "not found in prmlib") + theta = 0 + psi = {} + for c in ["Ca", "H", "K", "Mg", "Na"]: + try: + psi[c] = prmlib["caa"][c][row.anion1][row.anion2](T=298.15, P=1)[0] + except KeyError: + print(c, row.anion1, row.anion2, "not found in prmlib") + psi[c] = 0 + aa_pz.loc[i, "theta"] = np.round(theta, decimals=3) + aa_test.loc[i, "theta"] = np.round(theta - row.theta, decimals=3) + for c, ps in psi.items(): + aa_pz.loc[i, c] = np.round(ps, decimals=6) + aa_test.loc[i, c] = np.round(ps - row[c], decimals=6) + + return aa, aa_pz, aa_test + + +# Run comparisons +ca5, ca5_pz, ca5_test = compare_ca("ca5", 278.15) +ca25, ca25_pz, ca25_test = compare_ca("ca25", 298.15) +cc5, cc5_pz, cc5_test = compare_cc("cc5", 278.15) +cc25, cc25_pz, cc25_test = compare_cc("cc25", 298.15) +aa, aa_pz, aa_test = compare_aa() +# Define columns to check are zero +ca_cols = ["beta0", "beta1", "beta2", "C0", "C1", "alpha1", "alpha2", "omega"] +cc_cols = ["theta", "Cl", "HSO4", "SO4"] +aa_cols = ["theta", "Ca", "H", "K", "Mg", "Na"] + +# Eliminate differences that have been identified and understood +# -------------------------------------------------------------- +# +# It looks like the C0 value for Na-Cl at 25 °C in HWT22 Table S17 is actually a Cphi +# value - if you divide it by 2, then it agrees with Pytzer. Testing of the data in +# HWT22 Table S21 suggests that this is a fault only in Table S17 and thus that the +# HWT22 model code does correctly convert it to C0. +l = (ca25.cation == "Na") & (ca25.anion == "Cl") +ca25.loc[l, "C0"] /= 2 +ca25_test.loc[l, "C0"] = np.round(ca25_pz.loc[l, "C0"] - ca25.loc[l, "C0"], decimals=6) +# +# The final digit of the C0 value for H-SO4 at 25 °C in HWT22 Table S17 is one away from +# the Pytzer value - we assume this is a rounding error. +l = (ca25.cation == "H") & (ca25.anion == "SO4") +ca25.loc[l, "C0"] -= 1e-7 +ca25_test.loc[l, "C0"] = ca25_pz.loc[l, "C0"] - ca25.loc[l, "C0"] +# +# The psi value for Ca-Mg-SO4 is in the wrong place in HWT22 Table S19 - it is in the +# spot for the Ca-H-SO4 value, which should be zero. +l0 = (cc25.cation1 == "Ca") & (cc25.cation2 == "H") +l1 = (cc25.cation1 == "Ca") & (cc25.cation2 == "Mg") +cc25.loc[l1, "SO4"] = cc25.loc[l0, "SO4"].values +cc25.loc[l0, "SO4"] = 0 +cc25_test.loc[l0, "SO4"] = cc25_pz.loc[l0, "SO4"] - cc25.loc[l0, "SO4"] +cc25_test.loc[l1, "SO4"] = cc25_pz.loc[l1, "SO4"] - cc25.loc[l1, "SO4"] + + +def test_ca5(): + assert (ca5_test[ca_cols] == 0).all().all() + + +def test_ca25(): + assert (ca25_test[ca_cols] == 0).all().all() + + +def test_cc5(): + assert (cc5_test[cc_cols] == 0).all().all() + + +def test_cc25(): + assert (cc25_test[cc_cols] == 0).all().all() + + +def test_aa(): + assert (aa_test[aa_cols] == 0).all().all() + + +# test_ca5() +# test_ca25() +# test_cc5() +# test_cc25() +# test_aa() diff --git a/tests/test_HWT22_solver.py b/tests/test_HWT22_solver.py new file mode 100644 index 00000000..748996c6 --- /dev/null +++ b/tests/test_HWT22_solver.py @@ -0,0 +1,138 @@ +from collections import OrderedDict +import pandas as pd, numpy as np +import pytzer as pz + +# Select parameter library +prmlib = pz.libraries.Humphreys22 +pz = prmlib.set_func_J(pz) + +# Import data and run comparison, first without the solver (just using concentrations +# from in the table) +data = pd.read_excel("tests/data/Humphreys22-SI21.xlsx") +data_ns_pz = data.copy() +data_ns_test = data.copy() +data_eq_pz = data.copy() +data_eq_test = data.copy() +data_eq_pct = data.copy() +for i, row in data.iterrows(): + solutes = OrderedDict((s[1:], v) for s, v in row.items() if s.startswith("m")) + params = prmlib.get_parameters( + solutes=solutes, temperature=273.15 + row.temperature, verbose=False + ) + aH2O = pz.activity_water(solutes, **params) + data_ns_pz.loc[i, "aH2O"] = aH2O + data_ns_test.loc[i, "aH2O"] = np.round(aH2O - row.aH2O, decimals=5) + phi = pz.osmotic_coefficient(solutes, **params) + data_ns_pz.loc[i, "phi"] = phi + data_ns_test.loc[i, "phi"] = np.round(phi - row.phi, decimals=5) + acfs = pz.activity_coefficients(solutes, **params) + for s, v in acfs.items(): + data_ns_pz.loc[i, "g" + s] = v + data_ns_test.loc[i, "g" + s] = np.round(v - row["g" + s], decimals=5) + +# Now do it again but with the equilibrium solver too +# Number 1 +totals = OrderedDict( + ( + ("Na", 0.4861818), + ("Mg", 0.05474020), + ("Ca", 0.01075004), + ("K", 0.01058004), + ("Cl", 0.5692021), + ("SO4", 0.02927011), + ) +) +solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=278.15, +) +for s, v in solutes_eq.items(): + data_eq_pz.loc[0, "m" + s] = v + if s in ["OH", "HSO4", "MgOH", "H"]: + d = 12 + else: + d = 5 + data_eq_test.loc[0, "m" + s] = np.round(v - data.loc[0, "m" + s], decimals=d) + data_eq_pct.loc[0, "m" + s] = 100 * v / data.loc[0, "m" + s] +# Number 2 +solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=298.15, +) +for s, v in solutes_eq.items(): + data_eq_pz.loc[1, "m" + s] = v + if s in ["OH", "HSO4", "MgOH", "H"]: + d = 12 + else: + d = 5 + data_eq_test.loc[1, "m" + s] = np.round(v - data.loc[1, "m" + s], decimals=d) + data_eq_pct.loc[1, "m" + s] = 100 * v / data.loc[1, "m" + s] +# Number 3 +totals = OrderedDict( + ( + ("Na", 0.4861818 - 0.04), + ("Mg", 0.05474020), + ("Ca", 0.01075004), + ("K", 0.01058004), + ("Cl", 0.5692021), + ("SO4", 0.02927011), + ) +) +solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=278.15, +) +for s, v in solutes_eq.items(): + data_eq_pz.loc[2, "m" + s] = v + if s in ["HSO4", "H"]: + d = 8 + elif s in ["OH", "MgOH"]: + d = 18 + else: + d = 5 + data_eq_test.loc[2, "m" + s] = np.round(v - data.loc[2, "m" + s], decimals=d) + data_eq_pct.loc[2, "m" + s] = 100 * v / data.loc[2, "m" + s] +# Number 4 +solutes_eq, pks_constants = pz.solve( + totals, + library=prmlib, + temperature=298.15, +) +for s, v in solutes_eq.items(): + data_eq_pz.loc[3, "m" + s] = v + if s in ["HSO4", "H"]: + d = 8 + elif s in ["OH", "MgOH"]: + d = 18 + else: + d = 5 + data_eq_test.loc[3, "m" + s] = np.round(v - data.loc[3, "m" + s], decimals=d) + data_eq_pct.loc[3, "m" + s] = 100 * v / data.loc[3, "m" + s] + +# Eliminate differences that have been identified and understood +# -------------------------------------------------------------- +# +# The final digit of the gMgOH value at point 3 in HWT22 Table S21 is one away from +# the Pytzer value - so we assume this is a rounding error. +l = data.number == 3 +data.loc[l, "gMgOH"] -= 1e-5 +data_ns_test.loc[l, "gMgOH"] = np.round( + data_ns_pz.loc[l, "gMgOH"] - data.loc[l, "gMgOH"], decimals=5 +) + +# Identify columns to test +test_cols_ns = [ + c + for c in data.columns + if c not in ["number", "temperature"] and not c.startswith("m") +] + + +def test_data_ns(): + assert (data_ns_test[test_cols_ns] == 0).all().all() + + +# test_data_ns() From 0f4a894a324bbe834a52f6725e14623f267a8a07 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 13 Dec 2022 18:21:38 +0100 Subject: [PATCH 21/58] Rename io to get --- pytzer/__init__.py | 4 ++-- pytzer/{io.py => get.py} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename pytzer/{io.py => get.py} (100%) diff --git a/pytzer/__init__.py b/pytzer/__init__.py index 1afbd91d..7be8df4c 100644 --- a/pytzer/__init__.py +++ b/pytzer/__init__.py @@ -20,7 +20,7 @@ debyehueckel, dissociation, equilibrate, - io, + get, libraries, matrix, meta, @@ -40,7 +40,7 @@ from .equilibrate.components import find_solutes from .equilibrate.stoichiometric import solve as solve_stoichiometric from .equilibrate.thermodynamic import solve as solve_thermodynamic -from .io import solve_df +from .get import solve_df from .libraries import ParameterLibrary from .meta import hello, update_func_J from .model import ( diff --git a/pytzer/io.py b/pytzer/get.py similarity index 100% rename from pytzer/io.py rename to pytzer/get.py From abe48a9781015339afc4822bfaa18fc6f274dd92 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 13 Dec 2022 18:21:56 +0100 Subject: [PATCH 22/58] Increment version number --- pytzer/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytzer/meta.py b/pytzer/meta.py index dc8d6a01..7a48528d 100644 --- a/pytzer/meta.py +++ b/pytzer/meta.py @@ -3,7 +3,7 @@ """Define package metadata.""" import importlib -version = "0.5.2" +version = "0.5.3" author = "Matthew P. Humphreys and Abigail J. Schiller" From 79ca44efe013693c4cfa8beaa4b0c7c2c375a01b Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 13 Dec 2022 18:22:09 +0100 Subject: [PATCH 23/58] Update docs for GitHub pages --- .github/workflows/docs.yml | 17 +++++++++++++++++ README.md | 7 +++---- docs/index.md | 7 +++---- docs/refs.md | 3 +++ docs/requirements.txt | 2 +- docs/versions.md | 6 ++++++ mkdocs.yml | 6 +++--- 7 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..378a2342 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,17 @@ +name: docs +on: + push: + branches: + - develop +permissions: + contents: write +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - run: pip install mkdocs-material + - run: mkdocs gh-deploy --force diff --git a/README.md b/README.md index 5d6cfd0d..67a88e3f 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,10 @@ [![Coverage](https://github.com/mvdh7/pytzer/blob/master/.misc/coverage.svg)](https://github.com/mvdh7/pytzer/blob/master/.misc/coverage.txt) [![pypi badge](https://img.shields.io/pypi/v/pytzer.svg?style=popout)](https://pypi.org/project/pytzer/) [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.2637914-informational)](https://doi.org/10.5281/zenodo.2637914) -[![Docs](https://readthedocs.org/projects/pytzer/badge/?version=latest&style=flat)](https://pytzer.readthedocs.io/en/latest/) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) -Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91](https://pytzer.readthedocs.io/en/jax/refs/#p)] plus solvers to determine the equilibrium state of the system. +Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91](https://mvdh.xyz/pytzer/refs/#p)] plus solvers to determine the equilibrium state of the system. **Pytzer is in beta! Use at your own peril.** @@ -45,11 +44,11 @@ Then, fork and/or clone this repo to somewhere that your Python can see it. ## Documentation -A work in progress at [pytzer.readthedocs.io](https://pytzer.readthedocs.io/en/latest/). +A work in progress at [mvdh.xyz/pytzer](https://mvdh.xyz/pytzer). ## Citation -Pytzer is maintained by [Dr Matthew P. Humphreys](https://humphreys.science) at the [NIOZ Royal Netherlands Institute for Sea Research](https://www.nioz.nl/en) (Texel, the Netherlands). +Pytzer is maintained by [Dr Matthew P. Humphreys](https://seaco2.group) at the [NIOZ Royal Netherlands Institute for Sea Research](https://www.nioz.nl/en) (Texel, the Netherlands). For now, the appropriate citation is: diff --git a/docs/index.md b/docs/index.md index a374e099..ea6da34f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,12 +1,11 @@ # Pytzer -![Tests](https://github.com/mvdh7/pytzer/workflows/Tests/badge.svg) + Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91](refs/#p)] plus solvers to determine the equilibrium state of the system. @@ -33,7 +32,7 @@ pz.hello() ## Acknowledgements -Pytzer is maintained by [Dr Matthew P. Humphreys](https://humphreys.science) at the NIOZ Royal Netherlands Institute for Sea Research (Texel, the Netherlands). Its initial development at the University of East Anglia was funded indirectly by the Natural Environment Research Council (NERC, UK). +Pytzer is maintained by [Dr Matthew P. Humphreys](https://seaco2.group) at the NIOZ Royal Netherlands Institute for Sea Research (Texel, the Netherlands). Its initial development at the University of East Anglia was funded indirectly by the Natural Environment Research Council (NERC, UK). Pytzer contains many functions and coefficients representing the effects of different solute interactions on solution properties that have been empirically determined from painstaking experiments and data compilations by hundreds of researchers over the course at least a century. We have done our best to list the small selection of this enormous body of work brought together here in the [references](refs). diff --git a/docs/refs.md b/docs/refs.md index 4778e68d..41462339 100644 --- a/docs/refs.md +++ b/docs/refs.md @@ -90,6 +90,9 @@ ??? citation "HPR93: Hovey et al. (1993) *J. Chem. Thermodyn.*" Hovey, J. K., Pitzer, K. S., and Rard, J. A. (1993). Thermodynamics of Na2SO4(aq) at temperatures *T* from 273 K to 373 K and of {(1-*y*)H2SO4+*y*Na2SO4}(aq) at *T* = 298.15 K. *Journal of Chemical Thermodynamics* 25(1), 173–192. [doi:10.1006/jcht.1993.1016](https://doi.org/10.1006/jcht.1993.1016) +??? citation "HWT22: Humphreys et al. (2022) *Mar. Chem.*" + Humphreys, M. P., Waters, J. F., Turner, D. R., Dickson, A. G., and Clegg, S. L. (2022). Chemical speciation models based upon the Pitzer activity coefficient equations, including the propagation of uncertainties. I. Artificial seawater from 0 to 45 °C. *Marine Chemistry* 244, 104095. [doi:10.1016/j.marchem.2022.104095](https://doi.org/10.1016/j.marchem.2022.104095) + ### J ??? citation "JESS: May et al. (2011) *J. Chem. Eng. Data*" diff --git a/docs/requirements.txt b/docs/requirements.txt index d00dc16b..076ba5dc 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1 @@ -mkdocs-material==7.1.0 +mkdocs-material==8.5.11 diff --git a/docs/versions.md b/docs/versions.md index 0046cb5a..74cfc1ee 100644 --- a/docs/versions.md +++ b/docs/versions.md @@ -4,6 +4,12 @@ Switches from Autograd to [JAX](https://jax.readthedocs.io/en/latest/) for faster automatic differentiation and JIT compilation. +### 0.5.3 (forthcoming) + +!!! new-version "Changes in v0.5.3" + * Created new `Humphreys22` parameter library and validated its calculations against [HWT22](../refs/#h). + * Renamed `io` module to `get`. + ### 0.5.2 (31 Aug 2021) !!! new-version "Changes in v0.5.2" diff --git a/mkdocs.yml b/mkdocs.yml index 012e68ad..dbb42825 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,7 +1,7 @@ site_name: Pytzer site_author: Matthew P. Humphreys site_description: "Pytzer: the Pitzer model for chemical activities in aqueous solutions in Python" -copyright: Copyright © 2019–2021 Matthew P. Humphreys (GNU GPLv3). +copyright: Copyright © 2019–2022 Matthew P. Humphreys (GNU GPLv3). repo_url: https://github.com/mvdh7/pytzer repo_name: mvdh7/pytzer @@ -10,7 +10,7 @@ theme: language: en palette: scheme: default - primary: blue grey + primary: pink accent: teal font: text: Roboto Slab @@ -36,7 +36,7 @@ nav: # - Example workflows: workflows.md # - Conventions: name-conventions.md # - Main Pytzer modules: - # - .io – import and export data: modules/io.md + # - .get – import and export data: modules/io.md # - .model – the Pitzer model: modules/model.md # - .equilibrate - equilibrium solvers: modules/equilibrate.md # - Behind the scenes: From 8645c6082a1e3db959e2a1e4fee9a69b6cf51eb3 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 13 Dec 2022 18:26:33 +0100 Subject: [PATCH 24/58] Adjust link --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index ea6da34f..43a063fa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,7 +7,7 @@ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) --> -Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91](refs/#p)] plus solvers to determine the equilibrium state of the system. +Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91]](refs/#p) plus solvers to determine the equilibrium state of the system. ## Installation From 18c52ecd02c60224c5aba7dac188a233ebb14d4a Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 13 Dec 2022 18:27:25 +0100 Subject: [PATCH 25/58] Update copyright to 2022 --- pytzer/__init__.py | 2 +- pytzer/constants.py | 2 +- pytzer/convert.py | 2 +- pytzer/debyehueckel.py | 2 +- pytzer/dissociation.py | 2 +- pytzer/equilibrate/__init__.py | 2 +- pytzer/equilibrate/components.py | 2 +- pytzer/equilibrate/stoichiometric.py | 2 +- pytzer/equilibrate/thermodynamic.py | 2 +- pytzer/get.py | 2 +- pytzer/libraries/Clegg94.py | 2 +- pytzer/libraries/Greenberg89.py | 2 +- pytzer/libraries/Harvie84.py | 2 +- pytzer/libraries/HeMorse93.py | 2 +- pytzer/libraries/Humphreys22.py | 2 +- pytzer/libraries/MarChemSpec.py | 2 +- pytzer/libraries/MarChemSpec25.py | 2 +- pytzer/libraries/Millero98.py | 2 +- pytzer/libraries/MilleroThurmond83.py | 2 +- pytzer/libraries/Moller88.py | 2 +- pytzer/libraries/MyMarChemSpecCO2.py | 2 +- pytzer/libraries/ParameterLibrary.py | 2 +- pytzer/libraries/Seawater.py | 2 +- pytzer/libraries/Waters13.py | 2 +- pytzer/libraries/Waters13_Clegg22.py | 2 +- pytzer/libraries/Waters13_Humphreys22.py | 2 +- pytzer/libraries/Waters13_MarChemSpec25.py | 2 +- pytzer/libraries/__init__.py | 2 +- pytzer/meta.py | 2 +- pytzer/model.py | 2 +- pytzer/parameters/__init__.py | 2 +- pytzer/parameters/heMorse1993.py | 2 +- pytzer/parameters/holmes1987.py | 2 +- pytzer/parameters/holmesMesmer1992.py | 2 +- pytzer/parameters/pabalanPitzer1987.py | 2 +- pytzer/parameters/spencer1990.py | 2 +- pytzer/prepare.py | 2 +- pytzer/properties.py | 2 +- pytzer/teos10.py | 2 +- pytzer/unsymmetrical.py | 2 +- 40 files changed, 40 insertions(+), 40 deletions(-) diff --git a/pytzer/__init__.py b/pytzer/__init__.py index 7be8df4c..424d5665 100644 --- a/pytzer/__init__.py +++ b/pytzer/__init__.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/pytzer/constants.py b/pytzer/constants.py index f22bba2c..7e54db00 100644 --- a/pytzer/constants.py +++ b/pytzer/constants.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Define universal constants.""" # Set constant values diff --git a/pytzer/convert.py b/pytzer/convert.py index 8d25f0c2..861150a6 100644 --- a/pytzer/convert.py +++ b/pytzer/convert.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from collections import OrderedDict from jax import numpy as np from . import constants, properties diff --git a/pytzer/debyehueckel.py b/pytzer/debyehueckel.py index 00df3cf7..72d3fd44 100644 --- a/pytzer/debyehueckel.py +++ b/pytzer/debyehueckel.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Calculate Debye-Hueckel limiting slopes.""" from jax import numpy as np from . import teos10 diff --git a/pytzer/dissociation.py b/pytzer/dissociation.py index 15de9edd..69e0b994 100644 --- a/pytzer/dissociation.py +++ b/pytzer/dissociation.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Evaluate thermodynamic equilibrium constants. All functions return ln(K) values. """ diff --git a/pytzer/equilibrate/__init__.py b/pytzer/equilibrate/__init__.py index a8b2f526..0fa75b67 100644 --- a/pytzer/equilibrate/__init__.py +++ b/pytzer/equilibrate/__init__.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Solve for equilibrium.""" from collections import OrderedDict diff --git a/pytzer/equilibrate/components.py b/pytzer/equilibrate/components.py index a5f0736b..862c3612 100644 --- a/pytzer/equilibrate/components.py +++ b/pytzer/equilibrate/components.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Calculate molality of each solution component.""" from collections import OrderedDict diff --git a/pytzer/equilibrate/stoichiometric.py b/pytzer/equilibrate/stoichiometric.py index aa366d10..888fb833 100644 --- a/pytzer/equilibrate/stoichiometric.py +++ b/pytzer/equilibrate/stoichiometric.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Solve for stoichiometric equilibrium.""" from collections import OrderedDict diff --git a/pytzer/equilibrate/thermodynamic.py b/pytzer/equilibrate/thermodynamic.py index 03728224..86d59bd5 100644 --- a/pytzer/equilibrate/thermodynamic.py +++ b/pytzer/equilibrate/thermodynamic.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Solve for thermodynamic equilibrium.""" import copy diff --git a/pytzer/get.py b/pytzer/get.py index 68773ed5..f206bb98 100644 --- a/pytzer/get.py +++ b/pytzer/get.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Import solution composition data, and export the results.""" from collections import OrderedDict diff --git a/pytzer/libraries/Clegg94.py b/pytzer/libraries/Clegg94.py index 4e8aec34..5ae1e2bb 100644 --- a/pytzer/libraries/Clegg94.py +++ b/pytzer/libraries/Clegg94.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Clegg et al. (1994). System: H-HSO4-SO4. *Journal of the Chemical Society, Faraday Transactions* 90, 1875--1894. doi:10.1039/FT9949001875 diff --git a/pytzer/libraries/Greenberg89.py b/pytzer/libraries/Greenberg89.py index bb625d49..5f28ebfe 100644 --- a/pytzer/libraries/Greenberg89.py +++ b/pytzer/libraries/Greenberg89.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Greenberg & Møller (1988). System: Na-K-Ca-Cl-SO4. *Geochimica et Cosmochimica Acta* 53, 2503--2518. doi:10.1016/0016-7037(89)90124-5 diff --git a/pytzer/libraries/Harvie84.py b/pytzer/libraries/Harvie84.py index feda3c76..07ac4106 100644 --- a/pytzer/libraries/Harvie84.py +++ b/pytzer/libraries/Harvie84.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/HeMorse93.py b/pytzer/libraries/HeMorse93.py index 7cd55298..751056f3 100644 --- a/pytzer/libraries/HeMorse93.py +++ b/pytzer/libraries/HeMorse93.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """He & Morse (1993) Geochim. Cosmochim. Acta 57(15), 3533-3554. https://doi.org/10.1016/0016-7037(93)90137-L """ diff --git a/pytzer/libraries/Humphreys22.py b/pytzer/libraries/Humphreys22.py index 83dcf8f4..94892f0a 100644 --- a/pytzer/libraries/Humphreys22.py +++ b/pytzer/libraries/Humphreys22.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/MarChemSpec.py b/pytzer/libraries/MarChemSpec.py index f55fa21b..68620312 100644 --- a/pytzer/libraries/MarChemSpec.py +++ b/pytzer/libraries/MarChemSpec.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/MarChemSpec25.py b/pytzer/libraries/MarChemSpec25.py index 0c87c538..60ffb467 100644 --- a/pytzer/libraries/MarChemSpec25.py +++ b/pytzer/libraries/MarChemSpec25.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/Millero98.py b/pytzer/libraries/Millero98.py index 39de73f3..c7941d9d 100644 --- a/pytzer/libraries/Millero98.py +++ b/pytzer/libraries/Millero98.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/MilleroThurmond83.py b/pytzer/libraries/MilleroThurmond83.py index da14b356..56125088 100644 --- a/pytzer/libraries/MilleroThurmond83.py +++ b/pytzer/libraries/MilleroThurmond83.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/Moller88.py b/pytzer/libraries/Moller88.py index e47e6e92..6508951c 100644 --- a/pytzer/libraries/Moller88.py +++ b/pytzer/libraries/Moller88.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Møller (1988). System: Na-Ca-Cl-SO4. *Geochimica et Cosmochimica Acta* 52, 821--837. doi:10.1016/0016-7037(88)90354-7 diff --git a/pytzer/libraries/MyMarChemSpecCO2.py b/pytzer/libraries/MyMarChemSpecCO2.py index 5a7a2243..d2c64727 100644 --- a/pytzer/libraries/MyMarChemSpecCO2.py +++ b/pytzer/libraries/MyMarChemSpecCO2.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Waters & Millero (2013). *Marine Chemistry* 149, 8--22. doi:10.1016/j.marchem.2012.11.003 diff --git a/pytzer/libraries/ParameterLibrary.py b/pytzer/libraries/ParameterLibrary.py index 02ce81da..7a7a7f19 100644 --- a/pytzer/libraries/ParameterLibrary.py +++ b/pytzer/libraries/ParameterLibrary.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from copy import deepcopy from collections import OrderedDict import numpy as np diff --git a/pytzer/libraries/Seawater.py b/pytzer/libraries/Seawater.py index 8e0b5be2..0016d886 100644 --- a/pytzer/libraries/Seawater.py +++ b/pytzer/libraries/Seawater.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/Waters13.py b/pytzer/libraries/Waters13.py index 8faa3add..6bc1027e 100644 --- a/pytzer/libraries/Waters13.py +++ b/pytzer/libraries/Waters13.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Waters & Millero (2013). *Marine Chemistry* 149, 8--22. doi:10.1016/j.marchem.2012.11.003 diff --git a/pytzer/libraries/Waters13_Clegg22.py b/pytzer/libraries/Waters13_Clegg22.py index d44eef95..cd99e8c6 100644 --- a/pytzer/libraries/Waters13_Clegg22.py +++ b/pytzer/libraries/Waters13_Clegg22.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Waters & Millero (2013). *Marine Chemistry* 149, 8--22. doi:10.1016/j.marchem.2012.11.003 diff --git a/pytzer/libraries/Waters13_Humphreys22.py b/pytzer/libraries/Waters13_Humphreys22.py index 5e641a19..4fdfe5d3 100644 --- a/pytzer/libraries/Waters13_Humphreys22.py +++ b/pytzer/libraries/Waters13_Humphreys22.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Waters & Millero (2013). *Marine Chemistry* 149, 8--22. doi:10.1016/j.marchem.2012.11.003 diff --git a/pytzer/libraries/Waters13_MarChemSpec25.py b/pytzer/libraries/Waters13_MarChemSpec25.py index f3d25f40..7299ccd8 100644 --- a/pytzer/libraries/Waters13_MarChemSpec25.py +++ b/pytzer/libraries/Waters13_MarChemSpec25.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from . import ParameterLibrary from .. import debyehueckel, dissociation as k, parameters as prm, unsymmetrical diff --git a/pytzer/libraries/__init__.py b/pytzer/libraries/__init__.py index c454c1c4..3989629c 100644 --- a/pytzer/libraries/__init__.py +++ b/pytzer/libraries/__init__.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Assemble parameter libraries.""" from .ParameterLibrary import ParameterLibrary from .Clegg94 import Clegg94 diff --git a/pytzer/meta.py b/pytzer/meta.py index 7a48528d..e3d00b74 100644 --- a/pytzer/meta.py +++ b/pytzer/meta.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Define package metadata.""" import importlib diff --git a/pytzer/model.py b/pytzer/model.py index 869d603d..a7dead75 100644 --- a/pytzer/model.py +++ b/pytzer/model.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Calculate solution properties using the Pitzer model.""" import itertools, jax from collections import OrderedDict diff --git a/pytzer/parameters/__init__.py b/pytzer/parameters/__init__.py index b8dcd0bd..ecf30758 100644 --- a/pytzer/parameters/__init__.py +++ b/pytzer/parameters/__init__.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Evaluate Pitzer model interaction parameters.""" from jax import numpy as np from ..constants import Tzero diff --git a/pytzer/parameters/heMorse1993.py b/pytzer/parameters/heMorse1993.py index 907ffc93..9da1e483 100644 --- a/pytzer/parameters/heMorse1993.py +++ b/pytzer/parameters/heMorse1993.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """HM93: He & Morse (1993) Geochim. Cosmochim. Acta 57(15), 3533-3554. https://doi.org/10.1016/0016-7037(93)90137-L """ diff --git a/pytzer/parameters/holmes1987.py b/pytzer/parameters/holmes1987.py index 1c7e0765..775a6583 100644 --- a/pytzer/parameters/holmes1987.py +++ b/pytzer/parameters/holmes1987.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """HBS87: Holmes et al. (1987) J. Chem. Thermodyn. 19(8), 863-890. https://doi.org/10.1016/0021-9614(87)90033-4 """ diff --git a/pytzer/parameters/holmesMesmer1992.py b/pytzer/parameters/holmesMesmer1992.py index c5eb28cf..98d5c542 100644 --- a/pytzer/parameters/holmesMesmer1992.py +++ b/pytzer/parameters/holmesMesmer1992.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """HM92: Holmes & Mesmer (1992) J. Chem. Thermodyn. 24(3), 317-328. https://doi.org/10.1016/S0021-9614(05)80072-2 """ diff --git a/pytzer/parameters/pabalanPitzer1987.py b/pytzer/parameters/pabalanPitzer1987.py index 5dc21a65..510b1cfe 100644 --- a/pytzer/parameters/pabalanPitzer1987.py +++ b/pytzer/parameters/pabalanPitzer1987.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """PP87ii: Pabalan & Pitzer (1987) Geochim. Cosmochim. Acta 51(9), 2429-2443. https://doi.org/10.1016/0016-7037(87)90295-X """ diff --git a/pytzer/parameters/spencer1990.py b/pytzer/parameters/spencer1990.py index 28719a9e..fefd6020 100644 --- a/pytzer/parameters/spencer1990.py +++ b/pytzer/parameters/spencer1990.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """SMW90: Spencer et al. (1990) Geochim. Cosmochim. Acta 54(3), 575-590. https://doi.org/10.1016/0016-7037(90)90354-N diff --git a/pytzer/prepare.py b/pytzer/prepare.py index 664ee01d..5093f9df 100644 --- a/pytzer/prepare.py +++ b/pytzer/prepare.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) from collections import OrderedDict import numpy as np from . import convert diff --git a/pytzer/properties.py b/pytzer/properties.py index ad9fb8f0..63a4034a 100644 --- a/pytzer/properties.py +++ b/pytzer/properties.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Define solute properties.""" from . import convert diff --git a/pytzer/teos10.py b/pytzer/teos10.py index 768c0033..ad9d4908 100644 --- a/pytzer/teos10.py +++ b/pytzer/teos10.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Calculate properties of pure water.""" import jax from jax import numpy as np diff --git a/pytzer/unsymmetrical.py b/pytzer/unsymmetrical.py index cbd90e3a..9c97adeb 100644 --- a/pytzer/unsymmetrical.py +++ b/pytzer/unsymmetrical.py @@ -1,5 +1,5 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. -# Copyright (C) 2019--2021 Matthew P. Humphreys (GNU GPLv3) +# Copyright (C) 2019--2022 Matthew P. Humphreys (GNU GPLv3) """Unsymmetrical mixing functions.""" import jax from jax import numpy as np From f580d3c143d475062fb4bd2e9759ab8196f58c88 Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 13 Dec 2022 18:29:34 +0100 Subject: [PATCH 26/58] Fix typo --- docs/versions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/versions.md b/docs/versions.md index 74cfc1ee..f902199f 100644 --- a/docs/versions.md +++ b/docs/versions.md @@ -8,7 +8,7 @@ Switches from Autograd to [JAX](https://jax.readthedocs.io/en/latest/) for faste !!! new-version "Changes in v0.5.3" * Created new `Humphreys22` parameter library and validated its calculations against [HWT22](../refs/#h). - * Renamed `io` module to `get`. + * Renamed `io` module as `get`. ### 0.5.2 (31 Aug 2021) From 8b04fd6fb2c1191b30c718a1fbbd53630f26ebbe Mon Sep 17 00:00:00 2001 From: "Matthew P. Humphreys" Date: Tue, 13 Dec 2022 18:34:40 +0100 Subject: [PATCH 27/58] Rename master branch as main --- README.md | 4 ++-- docs/index.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 67a88e3f..06f343b3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Pytzer ![Tests](https://github.com/mvdh7/pytzer/workflows/Tests/badge.svg) -[![Coverage](https://github.com/mvdh7/pytzer/blob/master/.misc/coverage.svg)](https://github.com/mvdh7/pytzer/blob/master/.misc/coverage.txt) +[![Coverage](https://github.com/mvdh7/pytzer/blob/main/.misc/coverage.svg)](https://github.com/mvdh7/pytzer/blob/main/.misc/coverage.txt) [![pypi badge](https://img.shields.io/pypi/v/pytzer.svg?style=popout)](https://pypi.org/project/pytzer/) [![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.2637914-informational)](https://doi.org/10.5281/zenodo.2637914) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) @@ -36,7 +36,7 @@ Once installed, you will need to set the environment variable `JAX_ENABLE_X64=Tr ### For development -Use the [environment.yml](https://github.com/mvdh7/pytzer/blob/master/environment.yml) file to create a new environment with Conda: +Use the [environment.yml](https://github.com/mvdh7/pytzer/blob/main/environment.yml) file to create a new environment with Conda: conda env create -f environment.yml diff --git a/docs/index.md b/docs/index.md index 43a063fa..e72ecea4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ # Pytzer -Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions [[P91]](refs/#p) plus solvers to determine the equilibrium state of the system. +Pytzer is a Python implementation of the Pitzer model for chemical activities in aqueous solutions ([P91](refs/#p)) plus an equilibrium solver. ## Installation @@ -21,7 +21,7 @@ Pytzer is in beta. Tests of the accuracy of its parameters and equations are un A manuscript describing Pytzer is in preparation. In the meantime, please cite: -> Humphreys, Matthew P. and Schiller, Abigail J. (2021). Pytzer: the Pitzer model for chemical activities and equilibria in aqueous solutions in Python (beta). *Zenodo.* [doi:10.5281/zenodo.2637914](https://doi.org/10.5281/zenodo.2637914). +> Humphreys, Matthew P. and Schiller, Abigail J. (2023). Pytzer: the Pitzer model for chemical activities and equilibria in aqueous solutions in Python (beta). *Zenodo.* [doi:10.5281/zenodo.2637914](https://doi.org/10.5281/zenodo.2637914). Please report the version you are using. You can find this in Python with: diff --git a/docs/versions.md b/docs/versions.md index e624bfbb..c4c211e2 100644 --- a/docs/versions.md +++ b/docs/versions.md @@ -4,11 +4,11 @@ Switches from Autograd to [JAX](https://jax.readthedocs.io/en/latest/) for faster automatic differentiation and JIT compilation. -### 0.5.3 (forthcoming) +### 0.5.3 (24 Oct 2023) !!! new-version "Changes in v0.5.3" * Created new `Humphreys22` parameter library and validated its calculations against [HWT22](../refs/#h). - * Created new `Clegg22` parameter library and validated its calculations against [CHW22](../refs/#c). + * Created new `Clegg22` parameter library (but its calculations against [CHW22](../refs/#c) still need validating). * Created new `Clegg23` parameter library and validated its calculations against [CWTD23](../refs/#c). * Renamed `io` module as `get`. diff --git a/pytzer/__init__.py b/pytzer/__init__.py index a9ddd0b8..5bd5f8a0 100644 --- a/pytzer/__init__.py +++ b/pytzer/__init__.py @@ -13,7 +13,12 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -"""Pitzer model for chemical activities in aqueous solutions.""" +""" +Pytzer +====== +Pytzer is an implementation of the Pitzer model for chemical activities in aqueous +solutions in Python, including an equilibrium solver. +""" from . import ( constants, convert, diff --git a/pytzer/meta.py b/pytzer/meta.py index a0f6135e..f0ca589b 100644 --- a/pytzer/meta.py +++ b/pytzer/meta.py @@ -1,6 +1,6 @@ # Pytzer: Pitzer model for chemical activities in aqueous solutions. # Copyright (C) 2019--2023 Matthew P. Humphreys (GNU GPLv3) -"""Define package metadata.""" +"""Pytzer package metadata.""" import importlib version = "0.5.3" @@ -18,7 +18,7 @@ def update_func_J(pytzer, func_J): def hello(): print( - """ + r""" ____ __ / __ \ __ __ / /_ ____ ___ _____ / /_/ // / / // __//_ / / _ \ / ___/ diff --git a/pytzer/prepare.py b/pytzer/prepare.py index 93405622..80bfe3d8 100644 --- a/pytzer/prepare.py +++ b/pytzer/prepare.py @@ -76,7 +76,9 @@ def salinity_to_molalities_MFWM08(salinity=35): def salinity_to_totals_MFWM08(salinity=35): - """Convert salinity (g/kg-sw) to total molality for standard seawater following MFWM08.""" + """Convert salinity (g/kg-sw) to total molality for standard seawater following + MFWM08. + """ total_molalities = OrderedDict() total_molalities.update( { @@ -135,7 +137,9 @@ def salinity_to_totals_MFWM08(salinity=35): def salinity_to_totals_RRV93(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following RRV93.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + RRV93. + """ global salt_to_solutes salt_molalities = OrderedDict() salt_molalities.update( @@ -167,7 +171,9 @@ def salinity_to_totals_RRV93(salinity=35): def salinity_to_totals_GP89(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following GP89.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + GP89. + """ global salt_to_solutes gravimetric_salts = ( OrderedDict() @@ -188,7 +194,8 @@ def salinity_to_totals_GP89(salinity=35): ) # Concentrations given in mol/kg solution in the paper volumetric_salts.update({"MgCl2": 0.05327, "CaCl2": 0.01033, "SrCl2": 9e-05}) - # Formula weights are provided in the paper for the gravimetric salts, the rest are taken from PubChem + # Formula weights are provided in the paper for the gravimetric salts, the rest are + # taken from PubChem formula_weights = OrderedDict() formula_weights.update( { @@ -245,7 +252,9 @@ def salinity_to_totals_GP89(salinity=35): def salinity_to_totals_H73(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following H73.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + H73. + """ ion_concentrations = OrderedDict( # given in mMol/kg of solution in the paper {"Na": 478, "Mg": 54, "Ca": 10, "Cl": 550, "SO4": 28, "HCO3": 1.3, "CO3": 0.7} ) @@ -297,7 +306,9 @@ def salinity_to_totals_H73(salinity=35): def salinity_to_totals_D90(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following D90.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + D90. + """ global salt_to_solutes salt_molalities = OrderedDict() salt_molalities.update( @@ -327,7 +338,9 @@ def salinity_to_totals_D90(salinity=35): def salinity_to_totals_KRCB77(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following KRCB77.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + KRCB77. + """ global salt_to_solutes salt_molalities = OrderedDict() salt_molalities.update( @@ -357,7 +370,9 @@ def salinity_to_totals_KRCB77(salinity=35): def salinity_to_totals_DR79(salinity=35): - """Convert salinity (g/kg-sw) to total molality for synthetic seawater following DR79.""" + """Convert salinity (g/kg-sw) to total molality for synthetic seawater following + DR79. + """ total_molalities = OrderedDict() total_molalities.update( diff --git a/tests/test_pKs.py b/tests/test_pKs.py new file mode 100644 index 00000000..2491070e --- /dev/null +++ b/tests/test_pKs.py @@ -0,0 +1,25 @@ +import numpy as np +import pytzer as pz + +prmlib = pz.libraries.Clegg23 +totals = pz.prepare.salinity_to_totals_MFWM08(35) +solutes_per_kgH2O, pks_per_kgH2O = pz.solve(totals, temperature=298.15, library=prmlib) +totals_g_per_kgH2O = np.sum( + [pz.properties.ion_to_mass[k] * v for k, v in totals.items()] +) +kgH2O_per_kg = 1000 / (1000 + totals_g_per_kgH2O) + +solutes = {k: v * kgH2O_per_kg for k, v in solutes_per_kgH2O.items()} + +# K1 = [HCO3][H]/[CO2] +pk1_per_kgH2O = pks_per_kgH2O["H2CO3"] +pk1_per_kg = pk1_per_kgH2O - np.log10(kgH2O_per_kg) +pk1_PyCO2SYS = 5.957401472372938 +# AWESOME + + +def test_pK1_PyCO2SYS(): + assert np.abs(pk1_per_kg - pk1_PyCO2SYS) < 0.02 + + +# test_pK1_PyCO2SYS() From aaf767a41c1e1a823f171aba28b201ecbdfe414d Mon Sep 17 00:00:00 2001 From: Matthew Humphreys Date: Tue, 24 Oct 2023 11:44:52 +0200 Subject: [PATCH 57/58] Calkulate => pytzer --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3db1bfa1..92cf79cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ requires = [ build-backend = "setuptools.build_meta" [project] -name = "Calkulate" +name = "pytzer" description = "The Pitzer model for chemical activities and equilibria in aqueous solutions in Python" readme = "README.md" dependencies = [ From 43500f430f8dbb0dd89d3cf4d4c36269b8b0a00f Mon Sep 17 00:00:00 2001 From: Matthew Humphreys Date: Tue, 24 Oct 2023 11:47:20 +0200 Subject: [PATCH 58/58] Add jaxlib --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 92cf79cb..5d0afc40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,7 @@ requires = [ "setuptools", "pytzer", "jax", + "jaxlib", "numpy", "scipy", ] @@ -15,6 +16,7 @@ readme = "README.md" dependencies = [ "pytzer", "jax", + "jaxlib", "numpy", "scipy", ]