pyEQL 1.0.3__py3-none-any.whl → 1.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pyEQL/__init__.py CHANGED
@@ -37,11 +37,8 @@ ureg = UnitRegistry(cache_folder=":auto:")
37
37
  # convert "offset units" so that, e.g. Quantity('25 degC') works without error
38
38
  # see https://pint.readthedocs.io/en/0.22/user/nonmult.html?highlight=offset#temperature-conversion
39
39
  ureg.autoconvert_offset_to_baseunit = True
40
- # append custom unit definitions and contexts
41
- fname = files("pyEQL") / "pint_custom_units.txt"
42
- ureg.load_definitions(fname)
43
40
  # activate the "chemistry" context globally
44
- ureg.enable_contexts("chem")
41
+ ureg.enable_contexts("chemistry")
45
42
  # set the default string formatting for pint quantities
46
43
  ureg.default_format = "P~"
47
44
 
@@ -6698,7 +6698,7 @@
6698
6698
  "n_elements": 1,
6699
6699
  "size": {
6700
6700
  "radius_ionic": {
6701
- "value": "0.755",
6701
+ "value": "0.755",
6702
6702
  "reference": "pymatgen",
6703
6703
  "data_type": "experimental"
6704
6704
  },
@@ -24663,7 +24663,7 @@
24663
24663
  "n_elements": 1,
24664
24664
  "size": {
24665
24665
  "radius_ionic": {
24666
- "value": "0.83",
24666
+ "value": "0.83",
24667
24667
  "reference": "pymatgen",
24668
24668
  "data_type": "experimental"
24669
24669
  },
pyEQL/engines.py CHANGED
@@ -11,7 +11,7 @@ import os
11
11
  import warnings
12
12
  from abc import ABC, abstractmethod
13
13
  from pathlib import Path
14
- from typing import Literal
14
+ from typing import TYPE_CHECKING, Literal
15
15
 
16
16
  from phreeqpython import PhreeqPython
17
17
 
@@ -26,6 +26,9 @@ SPECIAL_ELEMENTS = ["S", "C", "N", "Cu", "Fe", "Mn"]
26
26
 
27
27
  logger = logging.getLogger(__name__)
28
28
 
29
+ if TYPE_CHECKING:
30
+ from pyEQL import Solution
31
+
29
32
 
30
33
  class EOS(ABC):
31
34
  """
@@ -38,7 +41,7 @@ class EOS(ABC):
38
41
  """
39
42
 
40
43
  @abstractmethod
41
- def get_activity_coefficient(self, solution, solute):
44
+ def get_activity_coefficient(self, solution: "Solution", solute: str) -> ureg.Quantity:
42
45
  """
43
46
  Return the *molal scale* activity coefficient of solute, given a Solution
44
47
  object.
@@ -55,7 +58,7 @@ class EOS(ABC):
55
58
  """
56
59
 
57
60
  @abstractmethod
58
- def get_osmotic_coefficient(self, solution):
61
+ def get_osmotic_coefficient(self, solution: "Solution") -> ureg.Quantity:
59
62
  """
60
63
  Return the *molal scale* osmotic coefficient of a Solution.
61
64
 
@@ -70,7 +73,7 @@ class EOS(ABC):
70
73
  """
71
74
 
72
75
  @abstractmethod
73
- def get_solute_volume(self):
76
+ def get_solute_volume(self, solution: "Solution") -> ureg.Quantity:
74
77
  """
75
78
  Return the volume of only the solutes.
76
79
 
@@ -85,7 +88,7 @@ class EOS(ABC):
85
88
  """
86
89
 
87
90
  @abstractmethod
88
- def equilibrate(self, solution):
91
+ def equilibrate(self, solution: "Solution") -> None:
89
92
  """
90
93
  Adjust the speciation and pH of a Solution object to achieve chemical equilibrium.
91
94
 
@@ -105,25 +108,25 @@ class EOS(ABC):
105
108
  class IdealEOS(EOS):
106
109
  """Ideal solution equation of state engine."""
107
110
 
108
- def get_activity_coefficient(self, solution, solute):
111
+ def get_activity_coefficient(self, solution: "Solution", solute: str) -> ureg.Quantity:
109
112
  """
110
113
  Return the *molal scale* activity coefficient of solute, given a Solution
111
114
  object.
112
115
  """
113
116
  return ureg.Quantity(1, "dimensionless")
114
117
 
115
- def get_osmotic_coefficient(self, solution):
118
+ def get_osmotic_coefficient(self, solution: "Solution") -> ureg.Quantity:
116
119
  """
117
120
  Return the *molal scale* osmotic coefficient of solute, given a Solution
118
121
  object.
119
122
  """
120
123
  return ureg.Quantity(1, "dimensionless")
121
124
 
122
- def get_solute_volume(self, solution):
125
+ def get_solute_volume(self, solution: "Solution") -> ureg.Quantity:
123
126
  """Return the volume of the solutes."""
124
127
  return ureg.Quantity(0, "L")
125
128
 
126
- def equilibrate(self, solution):
129
+ def equilibrate(self, solution: "Solution") -> None:
127
130
  """Adjust the speciation of a Solution object to achieve chemical equilibrium."""
128
131
  warnings.warn("equilibrate() has no effect in IdealEOS!")
129
132
  return
@@ -138,7 +141,9 @@ class NativeEOS(EOS):
138
141
 
139
142
  def __init__(
140
143
  self,
141
- phreeqc_db: Literal["vitens.dat", "wateq4f_PWN.dat", "pitzer.dat", "llnl.dat", "geothermal.dat"] = "llnl.dat",
144
+ phreeqc_db: Literal[
145
+ "phreeqc.dat", "vitens.dat", "wateq4f_PWN.dat", "pitzer.dat", "llnl.dat", "geothermal.dat"
146
+ ] = "llnl.dat",
142
147
  ) -> None:
143
148
  """
144
149
  Args:
@@ -172,7 +177,7 @@ class NativeEOS(EOS):
172
177
  # store the solution composition to see whether we need to re-instantiate the solution
173
178
  self._stored_comp = None
174
179
 
175
- def _setup_ppsol(self, solution):
180
+ def _setup_ppsol(self, solution: "Solution") -> None:
176
181
  """Helper method to set up a PhreeqPython solution for subsequent analysis."""
177
182
  self._stored_comp = solution.components.copy()
178
183
  solv_mass = solution.solvent_mass.to("kg").magnitude
@@ -244,13 +249,13 @@ class NativeEOS(EOS):
244
249
 
245
250
  self.ppsol = ppsol
246
251
 
247
- def _destroy_ppsol(self):
248
- """Remove the PhreeqPython solution from memory"""
252
+ def _destroy_ppsol(self) -> None:
253
+ """Remove the PhreeqPython solution from memory."""
249
254
  if self.ppsol is not None:
250
255
  self.ppsol.forget()
251
256
  self.ppsol = None
252
257
 
253
- def get_activity_coefficient(self, solution, solute):
258
+ def get_activity_coefficient(self, solution: "Solution", solute: str):
254
259
  r"""
255
260
  Whenever the appropriate parameters are available, the Pitzer model [may]_ is used.
256
261
  If no Pitzer parameters are available, then the appropriate equations are selected
@@ -329,7 +334,7 @@ class NativeEOS(EOS):
329
334
 
330
335
  # show an error if no salt can be found that contains the solute
331
336
  if salt is None:
332
- logger.error("No salts found that contain solute %s. Returning unit activity coefficient." % solute)
337
+ logger.error(f"No salts found that contain solute {solute}. Returning unit activity coefficient.")
333
338
  return ureg.Quantity(1, "dimensionless")
334
339
 
335
340
  # use the Pitzer model for higher ionic strength, if the parameters are available
@@ -344,14 +349,14 @@ class NativeEOS(EOS):
344
349
  # alpha1 and alpha2 based on charge
345
350
  if salt.nu_cation >= 2 and salt.nu_anion <= -2:
346
351
  if salt.nu_cation >= 3 or salt.nu_anion <= -3:
347
- alpha1 = 2
348
- alpha2 = 50
352
+ alpha1 = 2.0
353
+ alpha2 = 50.0
349
354
  else:
350
355
  alpha1 = 1.4
351
356
  alpha2 = 12
352
357
  else:
353
- alpha1 = 2
354
- alpha2 = 0
358
+ alpha1 = 2.0
359
+ alpha2 = 0.0
355
360
 
356
361
  # determine the average molality of the salt
357
362
  # this is necessary for solutions inside e.g. an ion exchange
@@ -427,7 +432,7 @@ class NativeEOS(EOS):
427
432
 
428
433
  return molal
429
434
 
430
- def get_osmotic_coefficient(self, solution):
435
+ def get_osmotic_coefficient(self, solution: "Solution") -> ureg.Quantity:
431
436
  r"""
432
437
  Return the *molal scale* osmotic coefficient of solute, given a Solution
433
438
  object.
@@ -574,7 +579,7 @@ class NativeEOS(EOS):
574
579
  # this means the solution is empty
575
580
  return 1
576
581
 
577
- def get_solute_volume(self, solution):
582
+ def get_solute_volume(self, solution: "Solution") -> ureg.Quantity:
578
583
  """Return the volume of the solutes."""
579
584
  # identify the predominant salt in the solution
580
585
  salt = solution.get_salt()
@@ -596,14 +601,14 @@ class NativeEOS(EOS):
596
601
  # alpha1 and alpha2 based on charge
597
602
  if salt.nu_cation >= 2 and salt.nu_anion >= 2:
598
603
  if salt.nu_cation >= 3 or salt.nu_anion >= 3:
599
- alpha1 = 2
600
- alpha2 = 50
604
+ alpha1 = 2.0
605
+ alpha2 = 50.0
601
606
  else:
602
607
  alpha1 = 1.4
603
608
  alpha2 = 12
604
609
  else:
605
- alpha1 = 2
606
- alpha2 = 0
610
+ alpha1 = 2.0
611
+ alpha2 = 0.0
607
612
 
608
613
  apparent_vol = ac.get_apparent_volume_pitzer(
609
614
  solution.ionic_strength,
@@ -633,7 +638,7 @@ class NativeEOS(EOS):
633
638
 
634
639
  pitzer_calc = True
635
640
 
636
- logger.debug("Updated solution volume using Pitzer model for solute %s" % salt.formula)
641
+ logger.debug(f"Updated solution volume using Pitzer model for solute {salt.formula}")
637
642
 
638
643
  # add the partial molar volume of any other solutes, except for water
639
644
  # or the parent salt, which is already accounted for by the Pitzer parameters
@@ -649,7 +654,7 @@ class NativeEOS(EOS):
649
654
  part_vol = solution.get_property(solute, "size.molar_volume")
650
655
  if part_vol is not None:
651
656
  solute_vol += part_vol * ureg.Quantity(mol, "mol")
652
- logger.debug("Updated solution volume using direct partial molar volume for solute %s" % solute)
657
+ logger.debug(f"Updated solution volume using direct partial molar volume for solute {solute}")
653
658
 
654
659
  else:
655
660
  logger.warning(
@@ -658,7 +663,7 @@ class NativeEOS(EOS):
658
663
 
659
664
  return solute_vol.to("L")
660
665
 
661
- def equilibrate(self, solution):
666
+ def equilibrate(self, solution: "Solution") -> None:
662
667
  """Adjust the speciation of a Solution object to achieve chemical equilibrium."""
663
668
  if self.ppsol is not None:
664
669
  self.ppsol.forget()
@@ -699,7 +704,7 @@ class NativeEOS(EOS):
699
704
  if solution.balance_charge is None:
700
705
  pass
701
706
  elif solution.balance_charge == "pH":
702
- solution.components["H+"] += charge_adjust.magnitude
707
+ solution.components["H+"] += charge_adjust
703
708
  elif solution.balance_charge == "pE":
704
709
  raise NotImplementedError
705
710
  else:
@@ -734,7 +739,7 @@ class PhreeqcEOS(NativeEOS):
734
739
  def __init__(
735
740
  self,
736
741
  phreeqc_db: Literal[
737
- "vitens.dat", "wateq4f_PWN.dat", "pitzer.dat", "llnl.dat", "geothermal.dat"
742
+ "phreeqc.dat", "vitens.dat", "wateq4f_PWN.dat", "pitzer.dat", "llnl.dat", "geothermal.dat"
738
743
  ] = "phreeqc.dat",
739
744
  ) -> None:
740
745
  """
@@ -751,12 +756,12 @@ class PhreeqcEOS(NativeEOS):
751
756
  """
752
757
  super().__init__(phreeqc_db=phreeqc_db)
753
758
 
754
- def get_activity_coefficient(self, solution, solute):
759
+ def get_activity_coefficient(self, solution: "Solution", solute: str) -> ureg.Quantity:
755
760
  """
756
761
  Return the *molal scale* activity coefficient of solute, given a Solution
757
762
  object.
758
763
  """
759
- if self.ppsol is None or solution.components != self._stored_comp:
764
+ if (self.ppsol is None) or (solution.components != self._stored_comp):
760
765
  self._destroy_ppsol()
761
766
  self._setup_ppsol(solution)
762
767
 
@@ -775,7 +780,7 @@ class PhreeqcEOS(NativeEOS):
775
780
 
776
781
  return ureg.Quantity(act, "dimensionless")
777
782
 
778
- def get_osmotic_coefficient(self, solution):
783
+ def get_osmotic_coefficient(self, solution: "Solution") -> ureg.Quantity:
779
784
  """
780
785
  Return the *molal scale* osmotic coefficient of solute, given a Solution
781
786
  object.
@@ -787,7 +792,7 @@ class PhreeqcEOS(NativeEOS):
787
792
  # TODO - find a way to access or calculate osmotic coefficient
788
793
  return ureg.Quantity(1, "dimensionless")
789
794
 
790
- def get_solute_volume(self, solution):
795
+ def get_solute_volume(self, solution: "Solution") -> ureg.Quantity:
791
796
  """Return the volume of the solutes."""
792
797
  # TODO - phreeqc seems to have no concept of volume, but it does calculate density
793
798
  return ureg.Quantity(0, "L")
pyEQL/solution.py CHANGED
@@ -92,11 +92,15 @@ class Solution(MSONable):
92
92
  -7 to +14. The default value corresponds to a pE value typical of natural
93
93
  waters in equilibrium with the atmosphere.
94
94
  balance_charge: The strategy for balancing charge during init and equilibrium calculations. Valid options
95
- are 'pH', which will adjust the solution pH to balance charge, 'pE' which will adjust the
96
- redox equilibrium to balance charge, or the name of a dissolved species e.g. 'Ca+2' or 'Cl-'
97
- that will be added/subtracted to balance charge. If set to None, no charge balancing will be
98
- performed either on init or when equilibrate() is called. Note that in this case, equilibrate()
99
- can distort the charge balance!
95
+ are
96
+ - 'pH', which will adjust the solution pH to balance charge,
97
+ - 'auto' which will use the majority cation or anion (i.e., that with the largest concentration)
98
+ as needed,
99
+ - 'pE' (not currently implemented) which will adjust the redox equilibrium to balance charge, or
100
+ the name of a dissolved species e.g. 'Ca+2' or 'Cl-' that will be added/subtracted to balance
101
+ charge.
102
+ - None (default), in which case no charge balancing will be performed either on init or when
103
+ equilibrate() is called. Note that in this case, equilibrate() can distort the charge balance!
100
104
  solvent: Formula of the solvent. Solvents other than water are not supported at this time.
101
105
  engine: Electrolyte modeling engine to use. See documentation for details on the available engines.
102
106
  database: path to a .json file (str or Path) or maggma Store instance that
@@ -171,7 +175,7 @@ class Solution(MSONable):
171
175
  self._pE = pE
172
176
  self._pH = pH
173
177
  self.pE = self._pE
174
- if isinstance(balance_charge, str) and balance_charge not in ["pH", "pE"]:
178
+ if isinstance(balance_charge, str) and balance_charge not in ["pH", "pE", "auto"]:
175
179
  self.balance_charge = standardize_formula(balance_charge)
176
180
  else:
177
181
  self.balance_charge = balance_charge #: Standardized formula of the species used for charge balancing.
@@ -273,13 +277,19 @@ class Solution(MSONable):
273
277
  raise NotImplementedError("Balancing charge via redox (pE) is not yet implemented!")
274
278
  else:
275
279
  ions = set().union(*[self.cations, self.anions]) # all ions
280
+ if self.balance_charge == "auto":
281
+ # add the most abundant ion of the opposite charge
282
+ if cb <= 0:
283
+ self.balance_charge = max(self.cations, key=self.cations.get)
284
+ elif cb > 0:
285
+ self.balance_charge = max(self.anions, key=self.anions.get)
276
286
  if self.balance_charge not in ions:
277
287
  raise ValueError(
278
288
  f"Charge balancing species {self.balance_charge} was not found in the solution!. "
279
289
  f"Species {ions} were found."
280
290
  )
281
- z = self.get_property(balance_charge, "charge")
282
- self.components[balance_charge] += -1 * cb / z * self.volume.to("L").magnitude
291
+ z = self.get_property(self.balance_charge, "charge")
292
+ self.components[self.balance_charge] += -1 * cb / z * self.volume.to("L").magnitude
283
293
  balanced = True
284
294
 
285
295
  if not balanced:
@@ -1282,81 +1292,12 @@ class Solution(MSONable):
1282
1292
  Returns:
1283
1293
  Nothing. The concentration of solute is modified.
1284
1294
  """
1285
- # if units are given on a per-volume basis,
1286
- # iteratively solve for the amount of solute that will preserve the
1287
- # original volume and result in the desired concentration
1288
- if ureg.Quantity(amount).dimensionality in (
1289
- "[substance]/[length]**3",
1290
- "[mass]/[length]**3",
1291
- ):
1292
- # store the original volume for later
1293
- orig_volume = self.volume
1294
-
1295
- # change the amount of the solute present to match the desired amount
1296
- self.components[solute] += (
1297
- ureg.Quantity(amount)
1298
- .to(
1299
- "moles",
1300
- "chem",
1301
- mw=self.get_property(solute, "molecular_weight"),
1302
- volume=self.volume,
1303
- solvent_mass=self.solvent_mass,
1304
- )
1305
- .magnitude
1306
- )
1307
-
1308
- # set the amount to zero and log a warning if the desired amount
1309
- # change would result in a negative concentration
1310
- if self.get_amount(solute, "mol").magnitude < 0:
1311
- self.logger.error(
1312
- "Attempted to set a negative concentration for solute %s. Concentration set to 0" % solute
1313
- )
1314
- self.set_amount(solute, "0 mol")
1315
-
1316
- # calculate the volume occupied by all the solutes
1317
- solute_vol = self._get_solute_volume()
1318
-
1319
- # determine the volume of solvent that will preserve the original volume
1320
- target_vol = orig_volume - solute_vol
1321
-
1322
- # adjust the amount of solvent
1323
- # volume in L, density in kg/m3 = g/L
1324
- target_mass = target_vol * ureg.Quantity(self.water_substance.rho, "g/L")
1325
-
1326
- mw = self.get_property(self.solvent, "molecular_weight")
1327
- target_mol = target_mass / mw
1328
- self.components[self.solvent] = target_mol.magnitude
1329
-
1330
- else:
1331
- # change the amount of the solute present
1332
- self.components[solute] += (
1333
- ureg.Quantity(amount)
1334
- .to(
1335
- "moles",
1336
- "chem",
1337
- mw=self.get_property(solute, "molecular_weight"),
1338
- volume=self.volume,
1339
- solvent_mass=self.solvent_mass,
1340
- )
1341
- .magnitude
1342
- )
1343
-
1344
- # set the amount to zero and log a warning if the desired amount
1345
- # change would result in a negative concentration
1346
- if self.get_amount(solute, "mol").magnitude < 0:
1347
- self.logger.error(
1348
- "Attempted to set a negative concentration for solute %s. Concentration set to 0" % solute
1349
- )
1350
- self.set_amount(solute, "0 mol")
1351
-
1352
- # update the volume to account for the space occupied by all the solutes
1353
- # make sure that there is still solvent present in the first place
1354
- if self.solvent_mass <= ureg.Quantity(0, "kg"):
1355
- self.logger.error("All solvent has been depleted from the solution")
1356
- return
1357
-
1358
- # set the volume recalculation flag
1359
- self.volume_update_required = True
1295
+ # Get the current amount of the solute
1296
+ current_amt = self.get_amount(solute, amount.split(" ")[1])
1297
+ if current_amt.magnitude == 0:
1298
+ self.logger.warning(f"Add new solute {solute} to the solution")
1299
+ new_amt = ureg.Quantity(amount) + current_amt
1300
+ self.set_amount(solute, new_amt)
1360
1301
 
1361
1302
  def set_amount(self, solute: str, amount: str):
1362
1303
  """
@@ -2465,7 +2406,7 @@ class Solution(MSONable):
2465
2406
  """
2466
2407
  str_filename = str(filename)
2467
2408
  if not ("yaml" in str_filename.lower() or "json" in str_filename.lower()):
2468
- self.logger.error("Invalid file extension entered - %s" % str_filename)
2409
+ self.logger.error("Invalid file extension entered - {str_filename}")
2469
2410
  raise ValueError("File extension must be .json or .yaml")
2470
2411
  if "yaml" in str_filename.lower():
2471
2412
  solution_dict = self.as_dict()
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyEQL
3
- Version: 1.0.3
4
- Summary: A python interace for solution chemistry
3
+ Version: 1.1.1
4
+ Summary: A python interface for solution chemistry
5
5
  Author-email: Ryan Kingsbury <kingsbury@princeton.edu>
6
6
  Project-URL: Docs, https://pyeql.readthedocs.io/
7
7
  Project-URL: Repo, https://github.com/KingsburyLab/pyEQL
@@ -25,7 +25,7 @@ Requires-Dist: numpy <2
25
25
  Requires-Dist: scipy
26
26
  Requires-Dist: pymatgen ==2024.5.1
27
27
  Requires-Dist: iapws
28
- Requires-Dist: monty
28
+ Requires-Dist: monty >=2024.7.12
29
29
  Requires-Dist: maggma >=0.67.0
30
30
  Requires-Dist: phreeqpython
31
31
  Provides-Extra: docs
@@ -1,27 +1,26 @@
1
- pyEQL/__init__.py,sha256=JErflmaJVP373dm3-YGHUomFu05dgX0iXWS-Z5AgSTU,2118
1
+ pyEQL/__init__.py,sha256=OCp_PiQEPyVoi1VX0ursBzHJWN6nDS1Id6bTBOgqCYs,1999
2
2
  pyEQL/activity_correction.py,sha256=eOixjgTd5hTrTRD5s6aPCCG12lAIH7-lRN0Z1qHu678,37151
3
- pyEQL/engines.py,sha256=b9ay7FYqmnINmhSMyNpVmENAtZVW-gyBfXUPf1PEUoY,34946
3
+ pyEQL/engines.py,sha256=9Pfo6YATahB9EUdBpUkE3xBAyDQqp1MjG9LO-zD4fAg,35517
4
4
  pyEQL/equilibrium.py,sha256=YCtoAJSgn1WC9NJnc3H4FTJdKQvogsvCuj7HqlKMtww,8307
5
5
  pyEQL/functions.py,sha256=nc-Hc61MmW-ELBR1PByJvQnELxM7PZexMHbU_O5-Bnw,10584
6
- pyEQL/pint_custom_units.txt,sha256=XHmcMlwVvqF9nEW7_e9Xgyq-xWEr-cDYqieas11T3eY,2882
7
6
  pyEQL/salt_ion_match.py,sha256=0nCZXmeo67VqcyYWQpPx-81hjSvnsg8HFB3fIyfjW_k,4070
8
7
  pyEQL/solute.py,sha256=no00Rc3tRfHmyht4wm2UXA1KZhKC45tWMO5QEkZY6yg,5140
9
- pyEQL/solution.py,sha256=XwtQmll3gPwdnnkXpQsnO7QebwTjplmlfhbEIU8rHDo,115940
8
+ pyEQL/solution.py,sha256=WET68HPDaleEsIxK2ObtAlNR7oolunNU5mNjxNeGG8U,113696
10
9
  pyEQL/utils.py,sha256=DWLtNm71qw5j4-jqBp5v3LssEjWgJnVvI6a_H60c5ic,6670
11
10
  pyEQL/database/geothermal.dat,sha256=kksnfcBtWdOTpNn4CLXU1Mz16cwas2WuVKpuMU8CaVI,234230
12
11
  pyEQL/database/llnl.dat,sha256=jN-a0kfUFbQlYMn2shTVRg1JX_ZhLa-tJ0lLw2YSpLU,751462
13
12
  pyEQL/database/phreeqc_license.txt,sha256=8W1r8VxC2kVptIMSU9sDFNASYqN7MdwKEtIWWfjTQuM,2906
14
- pyEQL/database/pyeql_db.json,sha256=TQKKofds7QBNd-Hw5QQuPwP6rQ8YWh_hHlRAtoQX0m8,1080793
13
+ pyEQL/database/pyeql_db.json,sha256=-7Z8tpAddXhPlvpxms7cFQKL_DSSbemzOzxm6L5vaVk,1080801
15
14
  pyEQL/presets/Ringers lactate.yaml,sha256=vtSnuvgALHR27XEjpDzC0xyw5-E6b2FSsF1EUEBiWpw,413
16
15
  pyEQL/presets/normal saline.yaml,sha256=i2znhnIeXfNx1iMFFSif7crMRCFRP6xN1m7Wp7USduM,318
17
16
  pyEQL/presets/rainwater.yaml,sha256=S0WHZNDfCJyjSSFxNFdkypjn2s3P0jJGCiYIxvi1ibA,337
18
17
  pyEQL/presets/seawater.yaml,sha256=oryc1CkhRz20RpWE6uiGiT93HoZnqlB0s-0PmBWr3-U,843
19
18
  pyEQL/presets/urine.yaml,sha256=0Njtc-H1fFRo7UhquHdiSTT4z-8VZJ1utDCk02qk28M,679
20
19
  pyEQL/presets/wastewater.yaml,sha256=jTTFBpmKxczaEtkCZb0xUULIPZt7wfC8eAJ6rthGnmw,502
21
- pyEQL-1.0.3.dist-info/AUTHORS.md,sha256=K9ZLhKFwZ2zLlFXwN62VuUYCpr5T6n4mOUCUHlytTUs,415
22
- pyEQL-1.0.3.dist-info/COPYING,sha256=Ww2oUywfFTn242v9ksCgQdIVSpcMXJiKKePn0GFm25E,7649
23
- pyEQL-1.0.3.dist-info/LICENSE.txt,sha256=2Zf1F7RzbpeposgIxUydpurqNCMoMgDi2gAB65_GjwQ,969
24
- pyEQL-1.0.3.dist-info/METADATA,sha256=Wqt01mnze6MZtohFvUr3W_PXgGxbt1ZGo6akCvivWFI,6083
25
- pyEQL-1.0.3.dist-info/WHEEL,sha256=rWxmBtp7hEUqVLOnTaDOPpR-cZpCDkzhhcBce-Zyd5k,91
26
- pyEQL-1.0.3.dist-info/top_level.txt,sha256=QMOaZjCAm_lS4Njsjh4L0B5aWnJFGQMYKhuH88CG1co,6
27
- pyEQL-1.0.3.dist-info/RECORD,,
20
+ pyEQL-1.1.1.dist-info/AUTHORS.md,sha256=K9ZLhKFwZ2zLlFXwN62VuUYCpr5T6n4mOUCUHlytTUs,415
21
+ pyEQL-1.1.1.dist-info/COPYING,sha256=Ww2oUywfFTn242v9ksCgQdIVSpcMXJiKKePn0GFm25E,7649
22
+ pyEQL-1.1.1.dist-info/LICENSE.txt,sha256=2Zf1F7RzbpeposgIxUydpurqNCMoMgDi2gAB65_GjwQ,969
23
+ pyEQL-1.1.1.dist-info/METADATA,sha256=5EWAVR_RKxcnBz3XHpl-OOCBfUo2sJMMOyJATkAZXIw,6096
24
+ pyEQL-1.1.1.dist-info/WHEEL,sha256=Wyh-_nZ0DJYolHNn1_hMa4lM7uDedD_RGVwbmTjyItk,91
25
+ pyEQL-1.1.1.dist-info/top_level.txt,sha256=QMOaZjCAm_lS4Njsjh4L0B5aWnJFGQMYKhuH88CG1co,6
26
+ pyEQL-1.1.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (71.0.4)
2
+ Generator: setuptools (71.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,52 +0,0 @@
1
- # Units definition file for pint library
2
-
3
- # This file defines additional units and contexts to enable the pint
4
- # library to process solution chemistry units such as mol/L and mol/kg.
5
-
6
- @context(mw=0,volume=0,solvent_mass=0) chemistry = chem
7
- # mw is the molecular weight of the species
8
- # volume is the volume of the solution
9
- # solvent_mass is the mass of solvent in the solution
10
-
11
- # moles -> mass require the molecular weight
12
- [substance] -> [mass]: value * mw
13
- [mass] -> [substance]: value / mw
14
-
15
- # moles/volume -> mass/volume and moles/mass -> mass / mass
16
- # require the molecular weight
17
- [substance] / [volume] -> [mass] / [volume]: value * mw
18
- [mass] / [volume] -> [substance] / [volume]: value / mw
19
- [substance] / [mass] -> [mass] / [mass]: value * mw
20
- [mass] / [mass] -> [substance] / [mass]: value / mw
21
-
22
- # moles/volume -> moles requires the solution volume
23
- [substance] / [volume] -> [substance]: value * volume
24
- [substance] -> [substance] / [volume]: value / volume
25
-
26
- # moles/mass -> moles requires the solvent (usually water) mass
27
- [substance] / [mass] -> [substance]: value * solvent_mass
28
- [substance] -> [substance] / [mass]: value / solvent_mass
29
-
30
- # moles/mass -> moles/volume require the solvent mass and the volume
31
- [substance] / [mass] -> [substance]/[volume]: value * solvent_mass / volume
32
- [substance] / [volume] -> [substance] / [mass]: value / solvent_mass * volume
33
-
34
- @end
35
-
36
- @context electricity = elec
37
- [length] ** 2 * [mass] / [current] ** 2 / [time] ** 3 <-> [length] ** -2 * [mass] **-1 / [current] ** -2 / [time] ** -3: 1 / value
38
- @end
39
-
40
-
41
- #From the pint documentation:
42
-
43
- #@context(n=1) spectroscopy = sp
44
- # # n index of refraction of the medium.
45
- # [length] <-> [frequency]: speed_of_light / n / value
46
- # [frequency] -> [energy]: planck_constant * value
47
- # [energy] -> [frequency]: value / planck_constant
48
- #@end
49
-
50
- # The @context directive indicates the beginning of the transformations which are finished by the @end statement. You can optionally specify parameters for the context in parenthesis. All parameters are named and default values are mandatory. Multiple parameters are separated by commas (like in a python function definition). Finally, you provide the name of the context (e.g. spectroscopy) and, optionally, a short version of the name (e.g. sp) separated by an equal sign.
51
- # Conversions rules are specified by providing source and destination dimensions separated using a colon (:) from the equation. A special variable named value will be replaced by the source quantity. Other names will be looked first in the context arguments and then in registry.
52
- # A single forward arrow (->) indicates that the equations is used to transform from the first dimension to the second one. A double arrow (<->) is used to indicate that the transformation operates both ways.
File without changes