physpyx 1.0.1__tar.gz → 2.0.0__tar.gz

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.
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: physpyx
3
- Version: 1.0.1
3
+ Version: 2.0.0
4
4
  Summary: Provides a way to use python code in LaTeX
5
5
  Author: Jérôme Dufour
6
6
  Author-email: Jérôme Dufour <jerome.dufour@eduvaud.ch>
7
7
  Classifier: Programming Language :: Python :: 3
8
8
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
9
9
  Classifier: Operating System :: Unix
10
- Classifier: Environment :: X11 Applications :: Qt
11
10
  Classifier: Topic :: Education
12
11
  Classifier: Topic :: Scientific/Engineering :: Physics
13
12
  Requires-Dist: numpy>=2.3.4
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "physpyx"
3
- version = "1.0.1"
3
+ version = "2.0.0"
4
4
  authors = [
5
5
  { name="Jérôme Dufour", email="jerome.dufour@eduvaud.ch" },
6
6
  ]
@@ -9,7 +9,6 @@ classifiers = [
9
9
  "Programming Language :: Python :: 3",
10
10
  "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
11
11
  "Operating System :: Unix",
12
- "Environment :: X11 Applications :: Qt",
13
12
  "Topic :: Education",
14
13
  "Topic :: Scientific/Engineering :: Physics"
15
14
  ]
@@ -44,4 +43,3 @@ build-backend = "uv_build"
44
43
  Repository = "https://bitbucket.org/jdufour/physpyx/src/master/"
45
44
  Changelog = "https://bitbucket.org/jdufour/physpyx/src/master/CHANGELOG.md"
46
45
  Documentation = "https://physpyx.readthedocs.io/fr/latest/"
47
-
@@ -2,7 +2,7 @@ from enum import Enum
2
2
  from logging import getLogger
3
3
  from math import sqrt
4
4
  from pathlib import Path
5
- from pickle import dump, load
5
+ from pickle import dump, loads
6
6
  from tempfile import gettempdir
7
7
  from typing import Generator, Iterable, Iterator, TypedDict
8
8
 
@@ -139,11 +139,10 @@ class Radioactivity:
139
139
  self.half_life = float(data[16])
140
140
  except ValueError:
141
141
  self.half_life = 0
142
-
143
142
  self.decays = DecayChannels(data)
144
143
 
145
144
  def __str__(self) -> str:
146
- return f"T={self.half_life:.2e} -> {self.decays}"
145
+ return f"T={self.half_life:.2e}s -> {self.decays}"
147
146
 
148
147
  def __getitem__(self, c: int) -> Channel:
149
148
  return self.decays[c]
@@ -244,8 +243,7 @@ class NuclideTable:
244
243
  def _load(self) -> None:
245
244
  pk_file = Path(gettempdir()) / "physpyx-nuclides.pkl"
246
245
  if pk_file.exists():
247
- with pk_file.open("rb") as pklin:
248
- self._by_numbers = load(pklin)
246
+ self._by_numbers = loads(pk_file.read_bytes())
249
247
  else:
250
248
  with (Path(__file__).parent / "data/all-nuclides.csv").open() as csv:
251
249
  n_col = len(csv.readline().split(","))
@@ -290,7 +288,9 @@ class NuclideTable:
290
288
  return self._by_numbers[f"{A}-{A - N}"]
291
289
  if Z and N and not A:
292
290
  return self._by_numbers[f"{N + Z}-{Z}"]
293
- raise ValueError
291
+ raise ValueError(
292
+ f"Problematic argumetns combination {N=}, {Z=}, {A=} and {symbol=}"
293
+ )
294
294
 
295
295
  def range(
296
296
  self,
@@ -11,8 +11,7 @@ class PhysPyX(PTManager):
11
11
  self._out = ""
12
12
 
13
13
  def _write_successfile(self) -> None:
14
- with self._fname.open("w") as outfile:
15
- outfile.write(self._out)
14
+ self._fname.write_text(self._out)
16
15
 
17
16
  def __call__(self, data: str | Generator[str]) -> None:
18
17
  if isinstance(data, str):
@@ -4,8 +4,7 @@ import sys
4
4
  from logging import getLogger
5
5
  from pint._typing import Scalar
6
6
  from physpyx.manager import PTManager
7
- from physpyx.nuclide import NuclideTable
8
- from physpyx.quantity import SiunitxQuantity, SiunitxUnitRegistry
7
+ from physpyx.quantity import Constants, SiunitxQuantity, SiunitxUnitRegistry
9
8
 
10
9
  logger = getLogger(__name__)
11
10
 
@@ -23,25 +22,26 @@ class Qty(PTManager):
23
22
  energy and vice-versa.
24
23
  """
25
24
  super().__init__(fname)
25
+ self._constants = Constants(self._fname.parent / "physpyx_constants.json")
26
26
  self._ureg = SiunitxUnitRegistry()
27
- self._ureg.define("jour = day")
28
27
  self._ureg.define("heure = hour")
29
- self._ureg.define("an = year")
30
- self._ureg.define("ans = years")
31
- self._ureg.define("mois = month")
28
+ self._ureg.define("heures = hours")
29
+ self._ureg.define("jour = day")
30
+ self._ureg.define("jours = days")
32
31
  self._ureg.define("semaine = week")
33
32
  self._ureg.define("semaines = weeks")
33
+ self._ureg.define("mois = month")
34
+ self._ureg.define("an = year")
35
+ self._ureg.define("ans = years")
34
36
  self._ureg.define("celerity = speed_of_light")
35
37
  self._ureg.define("chf = [currency] = franc")
36
38
  self._ureg.define("ct = 0.01 * chf = centime")
37
- self._nuclide_table = NuclideTable()
38
39
  if context:
39
40
  self._ureg.enable_contexts(context)
40
41
 
41
42
  def _write_successfile(self) -> None:
42
43
  if self._fname.exists():
43
- with self._fname.open("r") as outfile:
44
- active = dict(re.findall(r"{(.*)} = {(.*)}", outfile.read()))
44
+ active = dict(re.findall(r"{(.*)} = {(.*)}", self._fname.read_text()))
45
45
  else:
46
46
  active = {}
47
47
  with self._fname.open("w") as outfile:
@@ -92,10 +92,10 @@ class Qty(PTManager):
92
92
 
93
93
  :param unit: Assigns the unit if any (ignored for constants).
94
94
  :param to: Immediately converts unit.
95
- :param fmt: Sets the amplitude "f-string" format.
95
+ :param fmt: Sets the "f-string" format of the magnitude.
96
96
  :param base: If true, converts the unit into SI units.
97
97
  :param compact: As described in the "Pint" documentation "returns a
98
- rescaled to compact, human-readable units".
98
+ rescaled, human-readable unit".
99
99
  :param preferred: If true, attempts to convert unit into simpler one.
100
100
  For instance (kg.m/s2 will be converted to N). Note that, this defaults
101
101
  to "False" only here.
@@ -103,17 +103,7 @@ class Qty(PTManager):
103
103
  if isinstance(value, str):
104
104
  if unit is not None:
105
105
  logger.warning("Units are ignored when instanciating a constant")
106
- if data := SiunitxQuantity.CONSTANTS.get(value, None):
107
- value, unit, default_fmt = data
108
- if fmt == "g":
109
- fmt = default_fmt
110
- elif n := self._nuclide_table.get(symbol=value[1:]):
111
- if fmt == "g":
112
- fmt = "f"
113
- value = n.atomic_mass
114
- unit = "amu"
115
- else:
116
- raise ValueError(f"Constant {value} not found")
106
+ value, unit, fmt = self._constants(value, fmt)
117
107
 
118
108
  q = self._ureg.Quantity(
119
109
  value, unit, fmt=fmt, base=base, compact=compact, preferred=preferred
@@ -1,9 +1,12 @@
1
- from typing import cast
2
- from numpy import cross, ndarray, linalg
3
-
1
+ from json import loads
4
2
  from logging import getLogger
5
- from pint.registry import GenericUnitRegistry, Quantity, Unit
3
+ from numpy import cross, ndarray, linalg
4
+ from pathlib import Path
6
5
  from pint._typing import Magnitude, UnitLike
6
+ from pint.registry import GenericUnitRegistry, Quantity, Unit
7
+ from typing import cast
8
+
9
+ from physpyx.nuclide import NuclideTable
7
10
 
8
11
  logger = getLogger(__name__)
9
12
 
@@ -25,6 +28,7 @@ class SiunitxQuantity(Quantity):
25
28
  "standard_atmosphere": "atm",
26
29
  "unified_atomic_mass_unit": "amu",
27
30
  "meter_Hg": "mHg",
31
+ "watt_hour": "watthour",
28
32
  }
29
33
  _preferred_units = {
30
34
  Unit(name).dimensionality: name
@@ -48,33 +52,6 @@ class SiunitxQuantity(Quantity):
48
52
  "farad",
49
53
  ]
50
54
  }
51
- CONSTANTS = {
52
- "G": (6.6743e-11, "newton meter squared per kilogram squared", ".2e"),
53
- "g": (9.81, "meter per second squared", ".2f"),
54
- "c": (299792458, "meter per second", "d"),
55
- "h": (6.62607015e-34, "joule second", ".8e"),
56
- "malpha": (4.001506179129, "amu", "f"),
57
- "mn": (1.67492750056e-27, "kilogram", ".3e"),
58
- "mp": (1.67262192595e-27, "kilogram", ".3e"),
59
- "me": (9.1093837139e-31, "kilogram", ".3e"),
60
- "qe": (1.602176634e-19, "coulomb", ".3e"),
61
- "Na": (6.02214076e23, "", ".8e"),
62
- "amu": (1.66053906892e-27, "kilogram", ".11e"),
63
- "kB": (1.380649e-23, "joule per kelvin", "e"),
64
- "R": (8.31446261815324, "joule per kelvin per mole", "f"),
65
- "mu0": (1.2566370612696005e-06, "tesla meter per ampere", "e"),
66
- "a0": (5.29177210903e-11, "meter", "e"),
67
- "k": (8.987551e9, "newton meter squared per coulomb squared", ".0e"),
68
- "ceau": (4184, "joule per kilogram per kelvin", "g"),
69
- "cglace": (2060, "joule per kilogram per kelvin", "g"),
70
- "Lveau": (2300000, "joule per kilogram", ".1e"),
71
- "Lfeau": (330000, "joule per kilogram", ".1e"),
72
- "Ms": (1.98847e30, "kilogram", ".5e"),
73
- "MTerre": (5.9722e24, "kilogram", ".4e"),
74
- "MLune": (7.34e22, "kilogram", ".2e"),
75
- "RTerre": (6371000, "meter", ".3e"),
76
- "RLune": (1737000, "meter", ".3e"),
77
- }
78
55
 
79
56
  def __new__(
80
57
  cls,
@@ -176,8 +153,6 @@ class SiunitxQuantity(Quantity):
176
153
  for unit_str, power in self.unit_items():
177
154
  if unit_str == "kilogram":
178
155
  tmp = r"\kilogram"
179
- elif unit_str.startswith("kilowatt_hour"):
180
- tmp = r"\kWh"
181
156
  else:
182
157
  tmp = ""
183
158
  for p in self._REGISTRY._prefixes.values():
@@ -252,3 +227,73 @@ class SiunitxQuantity(Quantity):
252
227
  class SiunitxUnitRegistry(GenericUnitRegistry):
253
228
  Quantity: type = SiunitxQuantity
254
229
  Unit: type = Unit
230
+
231
+
232
+ class Constants:
233
+ _CONSTANTS = {
234
+ "cesium_standard": (9192631770, "hertz", "d"), # SI defining constant
235
+ "c": (299792458, "meter per second", "d"), # SI defining constant
236
+ "h": (6.62607015e-34, "joule second", ".8e"), # SI defining constant
237
+ "qe": (1.602176634e-19, "coulomb", ".3e"), # SI defining constant
238
+ "kB": (1.380649e-23, "joule per kelvin", "e"), # SI defining constant
239
+ "Na": (6.02214076e23, "", ".8e"), # SI defining constant
240
+ "R": (8.31446261815324, "joule per kelvin per mole", "f"),
241
+ "k": (8.987551e9, "newton meter squared per coulomb squared", ".0e"),
242
+ "epsilon0": (
243
+ 8.8541878188e-12,
244
+ "coulomb squared per newton meter sauqred",
245
+ ".3e",
246
+ ),
247
+ "mu0": (1.2566370612696005e-06, "tesla meter per ampere", ".3e"),
248
+ "mn": (1.67492750056e-27, "kilogram", ".3e"),
249
+ "mp": (1.67262192595e-27, "kilogram", ".3e"),
250
+ "me": (9.1093837139e-31, "kilogram", ".3e"),
251
+ "a0": (5.29177210903e-11, "meter", "e"),
252
+ "G": (6.6743e-11, "newton meter squared per kilogram squared", ".2e"),
253
+ "g": (9.81, "meter per second squared", ".2f"),
254
+ }
255
+
256
+ def __init__(self, fname: Path | None):
257
+ self._fname = fname
258
+ self._nuclide_table = NuclideTable()
259
+ self._constants: dict[str, tuple[float, str, str]] = {}
260
+
261
+ def _get_default_constant(
262
+ self, name: str, fmt: str
263
+ ) -> tuple[float, str, str] | None:
264
+ if data := self._CONSTANTS.get(name, None):
265
+ value, unit, default_fmt = data
266
+ return value, unit, default_fmt if fmt == "g" else fmt
267
+
268
+ def _get_custom_constant(
269
+ self, name: str, fmt: str
270
+ ) -> tuple[float, str, str] | None:
271
+ if not self._constants and self._fname and self._fname.exists():
272
+ self._constants = loads(self._fname.read_bytes())
273
+
274
+ if data := self._constants.get(name, None):
275
+ value, unit, default_fmt = data
276
+ return value, unit, default_fmt if fmt == "g" else fmt
277
+
278
+ def _get_nuclide_data(self, name: str, fmt: str) -> tuple[float, str, str] | None:
279
+ try:
280
+ match name[0]:
281
+ case "m":
282
+ n = self._nuclide_table.get(symbol=name[1:])
283
+ return n.atomic_mass, "amu", "f" if fmt == "g" else fmt
284
+ case "t":
285
+ n = self._nuclide_table.get(symbol=name[1:])
286
+ if n.radioactivity.stable:
287
+ raise ValueError(f"No half-life for {n.symbol}")
288
+ return n.radioactivity.half_life, "second", "g"
289
+ except KeyError:
290
+ pass
291
+
292
+ def __call__(self, name: str, fmt: str) -> tuple[float, str, str]:
293
+ if data := (
294
+ self._get_default_constant(name, fmt)
295
+ or self._get_custom_constant(name, fmt)
296
+ or self._get_nuclide_data(name, fmt)
297
+ ):
298
+ return data
299
+ raise ValueError(f"Constant '{name}' not found")
File without changes
File without changes
File without changes
File without changes