pychnosz 1.1.1__cp310-cp310-win_amd64.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.
Files changed (128) hide show
  1. pychnosz/__init__.py +129 -0
  2. pychnosz/biomolecules/__init__.py +29 -0
  3. pychnosz/biomolecules/ionize_aa.py +197 -0
  4. pychnosz/biomolecules/proteins.py +595 -0
  5. pychnosz/core/__init__.py +46 -0
  6. pychnosz/core/affinity.py +1256 -0
  7. pychnosz/core/animation.py +593 -0
  8. pychnosz/core/balance.py +334 -0
  9. pychnosz/core/basis.py +716 -0
  10. pychnosz/core/diagram.py +3336 -0
  11. pychnosz/core/equilibrate.py +813 -0
  12. pychnosz/core/equilibrium.py +554 -0
  13. pychnosz/core/info.py +821 -0
  14. pychnosz/core/retrieve.py +364 -0
  15. pychnosz/core/speciation.py +580 -0
  16. pychnosz/core/species.py +599 -0
  17. pychnosz/core/subcrt.py +1700 -0
  18. pychnosz/core/thermo.py +593 -0
  19. pychnosz/core/unicurve.py +1226 -0
  20. pychnosz/data/__init__.py +11 -0
  21. pychnosz/data/add_obigt.py +327 -0
  22. pychnosz/data/extdata/Berman/BDat17_2017.csv +2 -0
  23. pychnosz/data/extdata/Berman/Ber88_1988.csv +68 -0
  24. pychnosz/data/extdata/Berman/Ber90_1990.csv +5 -0
  25. pychnosz/data/extdata/Berman/DS10_2010.csv +6 -0
  26. pychnosz/data/extdata/Berman/FDM+14_2014.csv +2 -0
  27. pychnosz/data/extdata/Berman/Got04_2004.csv +5 -0
  28. pychnosz/data/extdata/Berman/JUN92_1992.csv +3 -0
  29. pychnosz/data/extdata/Berman/SHD91_1991.csv +12 -0
  30. pychnosz/data/extdata/Berman/VGT92_1992.csv +2 -0
  31. pychnosz/data/extdata/Berman/VPT01_2001.csv +3 -0
  32. pychnosz/data/extdata/Berman/VPV05_2005.csv +2 -0
  33. pychnosz/data/extdata/Berman/ZS92_1992.csv +11 -0
  34. pychnosz/data/extdata/Berman/sympy.R +99 -0
  35. pychnosz/data/extdata/Berman/testing/BA96.bib +12 -0
  36. pychnosz/data/extdata/Berman/testing/BA96_Berman.csv +21 -0
  37. pychnosz/data/extdata/Berman/testing/BA96_OBIGT.csv +21 -0
  38. pychnosz/data/extdata/Berman/testing/BA96_refs.csv +6 -0
  39. pychnosz/data/extdata/OBIGT/AD.csv +25 -0
  40. pychnosz/data/extdata/OBIGT/Berman_cr.csv +93 -0
  41. pychnosz/data/extdata/OBIGT/DEW.csv +211 -0
  42. pychnosz/data/extdata/OBIGT/H2O_aq.csv +4 -0
  43. pychnosz/data/extdata/OBIGT/SLOP98.csv +411 -0
  44. pychnosz/data/extdata/OBIGT/SUPCRT92.csv +178 -0
  45. pychnosz/data/extdata/OBIGT/inorganic_aq.csv +729 -0
  46. pychnosz/data/extdata/OBIGT/inorganic_cr.csv +273 -0
  47. pychnosz/data/extdata/OBIGT/inorganic_gas.csv +20 -0
  48. pychnosz/data/extdata/OBIGT/organic_aq.csv +1104 -0
  49. pychnosz/data/extdata/OBIGT/organic_cr.csv +481 -0
  50. pychnosz/data/extdata/OBIGT/organic_gas.csv +268 -0
  51. pychnosz/data/extdata/OBIGT/organic_liq.csv +533 -0
  52. pychnosz/data/extdata/OBIGT/testing/GEMSFIT.csv +43 -0
  53. pychnosz/data/extdata/OBIGT/testing/IGEM.csv +17 -0
  54. pychnosz/data/extdata/OBIGT/testing/Sandia.csv +8 -0
  55. pychnosz/data/extdata/OBIGT/testing/SiO2.csv +4 -0
  56. pychnosz/data/extdata/misc/AD03_Fig1a.csv +69 -0
  57. pychnosz/data/extdata/misc/AD03_Fig1b.csv +43 -0
  58. pychnosz/data/extdata/misc/AD03_Fig1c.csv +89 -0
  59. pychnosz/data/extdata/misc/AD03_Fig1d.csv +30 -0
  60. pychnosz/data/extdata/misc/BZA10.csv +5 -0
  61. pychnosz/data/extdata/misc/HW97_Cp.csv +90 -0
  62. pychnosz/data/extdata/misc/HWM96_V.csv +229 -0
  63. pychnosz/data/extdata/misc/LA19_test.csv +7 -0
  64. pychnosz/data/extdata/misc/Mer75_Table4.csv +42 -0
  65. pychnosz/data/extdata/misc/OBIGT_check.csv +423 -0
  66. pychnosz/data/extdata/misc/PM90.csv +7 -0
  67. pychnosz/data/extdata/misc/RH95.csv +23 -0
  68. pychnosz/data/extdata/misc/RH98_Table15.csv +17 -0
  69. pychnosz/data/extdata/misc/SC10_Rainbow.csv +19 -0
  70. pychnosz/data/extdata/misc/SK95.csv +55 -0
  71. pychnosz/data/extdata/misc/SOJSH.csv +61 -0
  72. pychnosz/data/extdata/misc/SS98_Fig5a.csv +81 -0
  73. pychnosz/data/extdata/misc/SS98_Fig5b.csv +84 -0
  74. pychnosz/data/extdata/misc/TKSS14_Fig2.csv +25 -0
  75. pychnosz/data/extdata/misc/bluered.txt +1000 -0
  76. pychnosz/data/extdata/protein/Cas/Cas_aa.csv +177 -0
  77. pychnosz/data/extdata/protein/Cas/Cas_uniprot.csv +186 -0
  78. pychnosz/data/extdata/protein/Cas/download.R +34 -0
  79. pychnosz/data/extdata/protein/Cas/mkaa.R +34 -0
  80. pychnosz/data/extdata/protein/POLG.csv +12 -0
  81. pychnosz/data/extdata/protein/TBD+05.csv +393 -0
  82. pychnosz/data/extdata/protein/TBD+05_aa.csv +393 -0
  83. pychnosz/data/extdata/protein/rubisco.csv +28 -0
  84. pychnosz/data/extdata/protein/rubisco.fasta +239 -0
  85. pychnosz/data/extdata/protein/rubisco_aa.csv +28 -0
  86. pychnosz/data/extdata/src/H2O92D.f.orig +3457 -0
  87. pychnosz/data/extdata/src/README.txt +5 -0
  88. pychnosz/data/extdata/taxonomy/names.dmp +215 -0
  89. pychnosz/data/extdata/taxonomy/nodes.dmp +63 -0
  90. pychnosz/data/extdata/thermo/Bdot_acirc.csv +60 -0
  91. pychnosz/data/extdata/thermo/buffer.csv +40 -0
  92. pychnosz/data/extdata/thermo/element.csv +135 -0
  93. pychnosz/data/extdata/thermo/groups.csv +6 -0
  94. pychnosz/data/extdata/thermo/opt.csv +2 -0
  95. pychnosz/data/extdata/thermo/protein.csv +506 -0
  96. pychnosz/data/extdata/thermo/refs.csv +343 -0
  97. pychnosz/data/extdata/thermo/stoich.csv.xz +0 -0
  98. pychnosz/data/loader.py +431 -0
  99. pychnosz/data/mod_obigt.py +322 -0
  100. pychnosz/data/obigt.py +471 -0
  101. pychnosz/data/worm.py +228 -0
  102. pychnosz/fortran/__init__.py +16 -0
  103. pychnosz/fortran/h2o92.dll +0 -0
  104. pychnosz/fortran/h2o92_interface.py +527 -0
  105. pychnosz/geochemistry/__init__.py +21 -0
  106. pychnosz/geochemistry/minerals.py +514 -0
  107. pychnosz/geochemistry/redox.py +500 -0
  108. pychnosz/models/__init__.py +47 -0
  109. pychnosz/models/archer_wang.py +165 -0
  110. pychnosz/models/berman.py +309 -0
  111. pychnosz/models/cgl.py +381 -0
  112. pychnosz/models/dew.py +997 -0
  113. pychnosz/models/hkf.py +523 -0
  114. pychnosz/models/hkf_helpers.py +222 -0
  115. pychnosz/models/iapws95.py +1113 -0
  116. pychnosz/models/supcrt92_fortran.py +238 -0
  117. pychnosz/models/water.py +480 -0
  118. pychnosz/utils/__init__.py +27 -0
  119. pychnosz/utils/expression.py +1074 -0
  120. pychnosz/utils/formula.py +830 -0
  121. pychnosz/utils/formula_ox.py +227 -0
  122. pychnosz/utils/reset.py +33 -0
  123. pychnosz/utils/units.py +259 -0
  124. pychnosz-1.1.1.dist-info/METADATA +197 -0
  125. pychnosz-1.1.1.dist-info/RECORD +128 -0
  126. pychnosz-1.1.1.dist-info/WHEEL +5 -0
  127. pychnosz-1.1.1.dist-info/licenses/LICENSE.txt +19 -0
  128. pychnosz-1.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,322 @@
1
+ """
2
+ Implementation of mod_OBIGT() function for Python CHNOSZ.
3
+
4
+ This function modifies or adds entries to the thermodynamic database,
5
+ mimicking the behavior of R CHNOSZ mod.OBIGT() function.
6
+ """
7
+
8
+ import pandas as pd
9
+ import numpy as np
10
+ from typing import Union, List, Dict, Any, Optional
11
+ import warnings
12
+
13
+ from ..core.thermo import thermo
14
+ from ..core.info import info
15
+ from ..utils.formula import makeup
16
+
17
+
18
+ def mod_OBIGT(*args, zap: bool = False, **kwargs) -> Union[int, List[int]]:
19
+ """
20
+ Add or modify species in the thermodynamic database.
21
+
22
+ This function replicates the behavior of R CHNOSZ mod.OBIGT() by allowing
23
+ modification of existing species or addition of new species to thermo().obigt.
24
+
25
+ Parameters
26
+ ----------
27
+ *args : int, str, list, or dict
28
+ If first argument is numeric: species index or indices to modify
29
+ If first argument is str: species name(s) to modify or add
30
+ If first argument is list/dict: contains all parameters
31
+ zap : bool, default False
32
+ If True, clear all properties except state and model before updating
33
+ **kwargs : any
34
+ Named properties to set (e.g., G=-100, S=50, formula="H2O")
35
+ Special properties: name, state, formula, model, E_units
36
+
37
+ Returns
38
+ -------
39
+ int or list of int
40
+ Species index or indices that were modified/added
41
+
42
+ Examples
43
+ --------
44
+ >>> import pychnosz
45
+ >>> pychnosz.reset()
46
+ >>> # Add new species
47
+ >>> i = pychnosz.mod_OBIGT("myspecies", formula="C2H6", G=-100, S=50)
48
+
49
+ >>> # Modify existing species
50
+ >>> i = pychnosz.mod_OBIGT("water", state="liq", G=-56690)
51
+
52
+ >>> # Modify by index
53
+ >>> i_h2o = pychnosz.info("water", "liq")
54
+ >>> i = pychnosz.mod_OBIGT(i_h2o, G=-56690)
55
+
56
+ >>> # Add multiple species
57
+ >>> i = pychnosz.mod_OBIGT(["X", "Y"], formula=["C12", "C13"], state=["aq", "cr"])
58
+
59
+ Notes
60
+ -----
61
+ This function modifies the thermo() object in place.
62
+ The behavior exactly matches R CHNOSZ mod.OBIGT().
63
+ """
64
+
65
+ # Get the thermo system
66
+ thermo_sys = thermo()
67
+
68
+ # Ensure the thermodynamic system is initialized
69
+ if not thermo_sys.is_initialized() or thermo_sys.obigt is None:
70
+ raise RuntimeError("Thermodynamic system not initialized. Run reset() first.")
71
+
72
+ # Process arguments
73
+ # If called with a dict as first arg (like R's list)
74
+ if len(args) == 1 and isinstance(args[0], dict):
75
+ params = args[0].copy()
76
+ elif len(args) > 0:
77
+ # First positional argument could be species index or name
78
+ first_arg = args[0]
79
+ params = kwargs.copy()
80
+
81
+ # Check if first argument is numeric (species index/indices)
82
+ if isinstance(first_arg, (int, np.integer)):
83
+ params['_index'] = first_arg
84
+ elif isinstance(first_arg, (list, tuple)) and len(first_arg) > 0:
85
+ if isinstance(first_arg[0], (int, np.integer)):
86
+ params['_index'] = list(first_arg)
87
+ else:
88
+ # First arg is list of names
89
+ params['name'] = list(first_arg)
90
+ else:
91
+ # First arg is species name
92
+ # If first arg name is not in kwargs, it's the species name
93
+ if 'name' not in params:
94
+ params['name'] = first_arg
95
+ else:
96
+ params = kwargs.copy()
97
+
98
+ # Validate we have at least a name/index and one property
99
+ if '_index' not in params and 'name' not in params:
100
+ raise ValueError("Please supply at least a species name and a property to update")
101
+
102
+ # Check that we have at least one property
103
+ # When using index: exclude _index and state from property count
104
+ # When using name: exclude name and state from property count (name is identifier, not property)
105
+ if '_index' in params:
106
+ property_keys = set(params.keys()) - {'_index', 'state'}
107
+ else:
108
+ property_keys = set(params.keys()) - {'name', 'state'}
109
+
110
+ if len(property_keys) == 0:
111
+ raise ValueError("Please supply at least a species name and a property to update")
112
+
113
+ # Get species indices
114
+ if '_index' in params:
115
+ # Working with indices
116
+ ispecies_input = params['_index']
117
+ if not isinstance(ispecies_input, list):
118
+ ispecies_input = [ispecies_input]
119
+ del params['_index']
120
+
121
+ # Get species names from indices
122
+ speciesname = []
123
+ for idx in ispecies_input:
124
+ sp_info = info(idx)
125
+ speciesname.append(sp_info['name'].iloc[0] if isinstance(sp_info, pd.DataFrame) else sp_info['name'])
126
+
127
+ ispecies = ispecies_input
128
+ else:
129
+ # Working with names
130
+ names = params.get('name')
131
+ if not isinstance(names, list):
132
+ names = [names]
133
+
134
+ states = params.get('state')
135
+ if states is not None and not isinstance(states, list):
136
+ states = [states]
137
+
138
+ speciesname = names
139
+
140
+ # Find species indices
141
+ ispecies = []
142
+ for i, name in enumerate(names):
143
+ state = states[i] if states and i < len(states) else None
144
+ try:
145
+ if state:
146
+ idx = info(name, state)
147
+ else:
148
+ idx = info(name)
149
+
150
+ # info() returns an int if found
151
+ if isinstance(idx, (int, np.integer)):
152
+ ispecies.append(int(idx))
153
+ else:
154
+ # Not found
155
+ ispecies.append(None)
156
+ except:
157
+ # Species doesn't exist - will be added
158
+ ispecies.append(None)
159
+
160
+ # Convert params to DataFrame format
161
+ # Handle list values vs single values
162
+ nspecies = len(ispecies)
163
+ param_df = {}
164
+ for key, value in params.items():
165
+ if isinstance(value, list):
166
+ if len(value) != nspecies:
167
+ raise ValueError(f"Length of '{key}' ({len(value)}) doesn't match number of species ({nspecies})")
168
+ param_df[key] = value
169
+ else:
170
+ param_df[key] = [value] * nspecies
171
+
172
+ # Create DataFrame of arguments
173
+ args_df = pd.DataFrame(param_df)
174
+
175
+ # Get column names of OBIGT (handle split names with ".")
176
+ obigt_cols = thermo_sys.obigt.columns.tolist()
177
+
178
+ # Map parameter names to column names (handle dot notation)
179
+ # e.g., "E.units" can be accessed as "E_units"
180
+ col_mapping = {}
181
+ for col in obigt_cols:
182
+ col_mapping[col] = col
183
+ col_mapping[col.replace('_', '.')] = col
184
+ # Also map first part before dot
185
+ if '_' in col:
186
+ col_mapping[col.split('_')[0]] = col
187
+
188
+ # Determine which columns we're updating
189
+ icol = []
190
+ icol_names = []
191
+ for key in args_df.columns:
192
+ if key in col_mapping:
193
+ icol_names.append(col_mapping[key])
194
+ icol.append(obigt_cols.index(col_mapping[key]))
195
+ else:
196
+ raise ValueError(f"Property '{key}' not in thermo$OBIGT")
197
+
198
+ # Separate new species from existing ones
199
+ inew = [i for i, idx in enumerate(ispecies) if idx is None]
200
+ iold = [i for i, idx in enumerate(ispecies) if idx is not None]
201
+
202
+ result_indices = []
203
+
204
+ # Add new species
205
+ if len(inew) > 0:
206
+ # Create blank rows
207
+ newrows = pd.DataFrame(index=range(len(inew)), columns=obigt_cols)
208
+ newrows[:] = np.nan
209
+
210
+ # Set defaults
211
+ default_state = thermo_sys.opt.get('state', 'aq')
212
+ default_units = thermo_sys.opt.get('E.units', 'J')
213
+
214
+ newrows['state'] = default_state
215
+ newrows['E_units'] = default_units
216
+
217
+ # Set formula from name if not provided
218
+ for i, idx in enumerate(inew):
219
+ if 'formula' in args_df.columns:
220
+ newrows.at[i, 'formula'] = args_df.iloc[idx]['formula']
221
+ else:
222
+ newrows.at[i, 'formula'] = args_df.iloc[idx]['name']
223
+
224
+ # Fill in provided columns
225
+ for i, idx in enumerate(inew):
226
+ for col_name in icol_names:
227
+ if col_name in args_df.columns:
228
+ newrows.at[i, col_name] = args_df.at[idx, col_name]
229
+
230
+ # Guess model from state
231
+ for i in range(len(newrows)):
232
+ if pd.isna(newrows.iloc[i]['model']):
233
+ if newrows.iloc[i]['state'] == 'aq':
234
+ newrows.at[i, 'model'] = 'HKF'
235
+ else:
236
+ newrows.at[i, 'model'] = 'CGL'
237
+
238
+ # Validate formulas
239
+ for i in range(len(newrows)):
240
+ formula = newrows.iloc[i]['formula']
241
+ try:
242
+ makeup(formula)
243
+ except Exception as e:
244
+ warnings.warn("Please supply a valid chemical formula as the species name or in the 'formula' argument")
245
+ raise e
246
+
247
+ # Add to OBIGT
248
+ ntotal_before = len(thermo_sys.obigt)
249
+ thermo_sys.obigt = pd.concat([thermo_sys.obigt, newrows], ignore_index=True)
250
+
251
+ # Reset index to 1-based
252
+ thermo_sys.obigt.index = range(1, len(thermo_sys.obigt) + 1)
253
+
254
+ # Update ispecies for new entries
255
+ for i, idx in enumerate(inew):
256
+ new_idx = ntotal_before + i + 1
257
+ if idx < len(ispecies):
258
+ ispecies[idx] = new_idx
259
+ result_indices.append(new_idx)
260
+
261
+ # Print message
262
+ name = newrows.iloc[i]['name']
263
+ state = newrows.iloc[i]['state']
264
+ model = newrows.iloc[i]['model']
265
+ e_units = newrows.iloc[i]['E_units']
266
+ print(f"mod_OBIGT: added {name}({state}) with {model} model and energy units of {e_units}")
267
+
268
+ # Modify existing species
269
+ if len(iold) > 0:
270
+ for i in iold:
271
+ idx = ispecies[i]
272
+
273
+ # Get old values
274
+ oldprop = thermo_sys.obigt.loc[idx, icol_names].copy()
275
+ state = thermo_sys.obigt.loc[idx, 'state']
276
+ model = thermo_sys.obigt.loc[idx, 'model']
277
+
278
+ # If zap, clear all values except state and model
279
+ if zap:
280
+ thermo_sys.obigt.loc[idx, :] = np.nan
281
+ thermo_sys.obigt.loc[idx, 'state'] = state
282
+ thermo_sys.obigt.loc[idx, 'model'] = model
283
+
284
+ # Get new properties
285
+ newprop = args_df.iloc[i][icol_names].copy()
286
+
287
+ # Check if there's any change
288
+ # Compare values element-wise, treating NaN as equal to NaN
289
+ has_change = False
290
+ for col in icol_names:
291
+ old_val = oldprop[col] if col in oldprop.index else np.nan
292
+ new_val = newprop[col] if col in newprop.index else np.nan
293
+
294
+ # Check if both are NaN
295
+ if pd.isna(old_val) and pd.isna(new_val):
296
+ continue
297
+ # Check if one is NaN and other is not
298
+ elif pd.isna(old_val) or pd.isna(new_val):
299
+ has_change = True
300
+ break
301
+ # Check if values are different
302
+ elif old_val != new_val:
303
+ has_change = True
304
+ break
305
+
306
+ if not has_change:
307
+ # No change
308
+ print(f"mod_OBIGT: no change for {speciesname[i]}({state})")
309
+ else:
310
+ # Update the data
311
+ for col_name in icol_names:
312
+ if col_name in args_df.columns:
313
+ thermo_sys.obigt.loc[idx, col_name] = args_df.iloc[i][col_name]
314
+
315
+ print(f"mod_OBIGT: updated {speciesname[i]}({state})")
316
+
317
+ result_indices.append(idx)
318
+
319
+ # Return indices
320
+ if len(result_indices) == 1:
321
+ return result_indices[0]
322
+ return result_indices