nomogram 0.5.0__tar.gz → 0.6.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.
Files changed (31) hide show
  1. {nomogram-0.5.0 → nomogram-0.6.0}/PKG-INFO +30 -22
  2. {nomogram-0.5.0 → nomogram-0.6.0}/README.md +28 -20
  3. {nomogram-0.5.0 → nomogram-0.6.0}/pyproject.toml +19 -3
  4. {nomogram-0.5.0 → nomogram-0.6.0}/pyproject.toml.orig +13 -4
  5. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/catalog.py +1 -1
  6. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/comparison.py +38 -6
  7. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/NOTICE.md +1 -1
  8. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/catalog/atmosphere.toml +545 -7
  9. nomogram-0.6.0/src/nomogram/data/catalog/boundary-layer.toml +850 -0
  10. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/catalog/core.toml +1 -1
  11. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/catalog/moist-air.toml +372 -11
  12. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/catalog/verifications.json +20 -0
  13. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/catalog/water-vapour.toml +288 -14
  14. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/semantics.json +350 -84
  15. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/dimensions.py +8 -2
  16. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/display.py +11 -0
  17. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/expression.py +125 -13
  18. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/inversion.py +21 -11
  19. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/model.py +6 -2
  20. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/plot.py +187 -33
  21. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/relations.py +72 -16
  22. {nomogram-0.5.0 → nomogram-0.6.0}/LICENSE +0 -0
  23. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/__init__.py +0 -0
  24. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/_logo.py +0 -0
  25. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/catalog/humidity.toml +0 -0
  26. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/catalog/radio.toml +0 -0
  27. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/data/catalog/sea-water.toml +0 -0
  28. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/py.typed +0 -0
  29. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/search.py +0 -0
  30. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/semantics.py +0 -0
  31. {nomogram-0.5.0 → nomogram-0.6.0}/src/nomogram/units.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nomogram
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: Repository of scientific formulas: notations, units, validity domains
5
5
  Keywords: scientific computing,formulas,units,dimensional analysis,physics,thermodynamics,geoscience,atmospheric science,meteorology,hydrology,psychrometrics
6
6
  Author: miki4ia
@@ -22,7 +22,7 @@ Classifier: Topic :: Scientific/Engineering :: Physics
22
22
  Classifier: Typing :: Typed
23
23
  Requires-Dist: numpy>=2.0
24
24
  Requires-Dist: pint>=0.24.4
25
- Requires-Dist: sympy>=1.13
25
+ Requires-Dist: sympy>=1.14
26
26
  Requires-Dist: matplotlib>=3.10.7 ; extra == 'viz'
27
27
  Requires-Python: >=3.12
28
28
  Project-URL: Homepage, https://github.com/miki4iaml/nomogram
@@ -34,18 +34,18 @@ Description-Content-Type: text/markdown
34
34
 
35
35
  <p align="center">
36
36
  <picture>
37
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/miki4iaml/nomogram/v0.5.0/docs/images/banner-dark.svg">
38
- <img alt="nomogram" src="https://raw.githubusercontent.com/miki4iaml/nomogram/v0.5.0/docs/images/banner-light.svg" width="480">
37
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/miki4iaml/nomogram/v0.6.0/docs/images/banner-dark.svg">
38
+ <img alt="nomogram" src="https://raw.githubusercontent.com/miki4iaml/nomogram/v0.6.0/docs/images/banner-light.svg" width="480">
39
39
  </picture>
40
40
  </p>
41
41
 
42
- **English** | [Français](https://github.com/miki4iaml/nomogram/blob/v0.5.0/README.fr.md)
42
+ **English** | [Français](https://github.com/miki4iaml/nomogram/blob/v0.6.0/README.fr.md)
43
43
 
44
44
  [![CI](https://github.com/miki4iaml/nomogram/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/miki4iaml/nomogram/actions/workflows/ci.yml)
45
45
  [![CodeQL](https://github.com/miki4iaml/nomogram/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/miki4iaml/nomogram/actions/workflows/github-code-scanning/codeql)
46
46
  [![codecov](https://codecov.io/gh/miki4iaml/nomogram/graph/badge.svg?branch=develop)](https://codecov.io/gh/miki4iaml/nomogram)
47
- [![Python](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fmiki4iaml%2Fnomogram%2Fdevelop%2Fpyproject.toml)](https://github.com/miki4iaml/nomogram/blob/v0.5.0/pyproject.toml)
48
- [![License](https://img.shields.io/github/license/miki4iaml/nomogram)](https://github.com/miki4iaml/nomogram/blob/v0.5.0/LICENSE)
47
+ [![Python](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fmiki4iaml%2Fnomogram%2Fdevelop%2Fpyproject.toml)](https://github.com/miki4iaml/nomogram/blob/v0.6.0/pyproject.toml)
48
+ [![License](https://img.shields.io/github/license/miki4iaml/nomogram)](https://github.com/miki4iaml/nomogram/blob/v0.6.0/LICENSE)
49
49
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23373134.svg)](https://doi.org/10.5281/zenodo.23373134)
50
50
  [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
51
51
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
@@ -94,7 +94,7 @@ Python 3.12 or later. Plots need the `viz` extra (matplotlib):
94
94
  Every saturation vapour pressure formulation of the catalog against the
95
95
  IAPWS reference, from 0 to 60 °C and within 1 %; curves stop where a formulation leaves its
96
96
  stated validity domain, and the figure takes the option set of nomogram's
97
- documentation ([script](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/examples/saturation_vapour_pressure.py)):
97
+ documentation ([script](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/examples/saturation_vapour_pressure.py)):
98
98
 
99
99
  ```python
100
100
  import numpy as np
@@ -113,7 +113,7 @@ with nomo.display.display_options(nomo.display.DisplayOptions.DOCUMENTATION):
113
113
  nomo.plot.plot_deviations(table, xlim=(0, 60), ylim=(-1.0, 1.0)) # extra viz
114
114
  ```
115
115
 
116
- ![Deviation of saturation vapour pressure formulations from IAPWS](https://raw.githubusercontent.com/miki4iaml/nomogram/v0.5.0/docs/images/saturation-vapour-pressure.png)
116
+ ![Deviation of saturation vapour pressure formulations from IAPWS](https://raw.githubusercontent.com/miki4iaml/nomogram/v0.6.0/docs/images/saturation-vapour-pressure.png)
117
117
 
118
118
  ## Usage
119
119
 
@@ -136,7 +136,7 @@ pressures p_1 and p_2 of the levels), compares once all but one of them
136
136
  are fixed, which `compare` asks for: `partial` fixes inputs as `functools.partial` fixes arguments,
137
137
  here the two levels, and leaves a function of p alone, evaluated,
138
138
  compared and plotted like any formulation
139
- ([Humidity between two levels](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/vertical.md#humidity-between-two-levels)).
139
+ ([Humidity between two levels](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/vertical.md#humidity-between-two-levels)).
140
140
  It also fixes what is known in advance, such as the levels of a sounding,
141
141
  and names the curve in legends:
142
142
 
@@ -151,7 +151,7 @@ in_ln_p.evaluate(p=Q_(700, "hPa")).to("K") # 268.49
151
151
  ```
152
152
 
153
153
  Formulations are found by words, wildcards and fields, whatever their
154
- notation ([Finding formulations](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/search.md)):
154
+ notation ([Finding formulations](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/search.md)):
155
155
 
156
156
  ```python
157
157
  catalog.search(variable="rho*") # ρ in every notation
@@ -159,20 +159,28 @@ catalog.search(kind="VapourPressure", source="buck*")
159
159
  ```
160
160
 
161
161
  Each formulation keeps its units, validity domain, temperature scale and
162
- references. The vocabulary is mapped in [docs/rosetta.md](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/rosetta.md);
163
- [How nomogram earns trust](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/approach.md) explains what is checked and
164
- how, and [Displaying formulas](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/display.md) shows formulas in notebooks,
165
- Markdown and plots. [Sea water](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/sea-water.md) shows the salinity
162
+ references. The vocabulary is mapped in [docs/rosetta.md](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/rosetta.md),
163
+ and [Shared vocabularies](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/shared-vocabularies.md) explains how nomogram
164
+ builds on QUDT, CF and Wikidata and contributes to them;
165
+ [How nomogram earns trust](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/approach.md) explains what is checked and
166
+ how, and [Displaying formulas](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/display.md) shows formulas in notebooks,
167
+ Markdown and plots. [Sea water](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/sea-water.md) shows the salinity
166
168
  scales and the vapour pressure of sea water, and what its 2 % lowering
167
- changes at the sea surface. [The logo](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/logo.md) is a working
168
- nomogram.
169
+ changes at the sea surface. [Humidity aloft](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/humidity-aloft.md)
170
+ sets the formula of a radiosonde's producer against its users' along a
171
+ vertical profile, through the dew point, over water or over ice, and
172
+ against WMO's requirements.
173
+ [Security and compliance](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/security-and-compliance.md) gathers, for
174
+ those who approve its use on a laboratory network, how nomogram is
175
+ developed, checked and published, what remains to do, and a checklist.
176
+ [The logo](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/logo.md) is a working nomogram.
169
177
 
170
178
  ## Contributing
171
179
 
172
180
  References to integrate, information or corrections about catalog
173
181
  entries, new formulas and code are all welcome: see the
174
- [ways to contribute](https://github.com/miki4iaml/nomogram/blob/v0.5.0/.github/CONTRIBUTING.md#ways-to-contribute) and
175
- the [catalog guide](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/catalog.md).
182
+ [ways to contribute](https://github.com/miki4iaml/nomogram/blob/v0.6.0/.github/CONTRIBUTING.md#ways-to-contribute) and
183
+ the [catalog guide](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/catalog.md).
176
184
 
177
185
  ## Data sources
178
186
 
@@ -183,7 +191,7 @@ their canonical units, from the CF standard name table. The package
183
191
  bundles a subset of each source:
184
192
 
185
193
  - QUDT — Quantities, Units, Dimensions and Types, by QUDT.org
186
- (<https://qudt.org>), release 3.5.2, licensed under
194
+ (<https://qudt.org>), release 3.5.3, licensed under
187
195
  [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/);
188
196
  - the [CF standard name table](https://cfconventions.org/Data/cf-standard-names/95/build/cf-standard-name-table.html),
189
197
  version 95, [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/);
@@ -191,9 +199,9 @@ bundles a subset of each source:
191
199
  Institute, Inc., [UCUM License](https://ucum.org/license).
192
200
 
193
201
  What nomogram selects, changes and adds is listed in
194
- [NOTICE.md](https://github.com/miki4iaml/nomogram/blob/v0.5.0/src/nomogram/data/NOTICE.md).
202
+ [NOTICE.md](https://github.com/miki4iaml/nomogram/blob/v0.6.0/src/nomogram/data/NOTICE.md).
195
203
 
196
204
  ## License
197
205
 
198
- Code: [BSD-3-Clause](https://github.com/miki4iaml/nomogram/blob/v0.5.0/LICENSE). Bundled data: see
206
+ Code: [BSD-3-Clause](https://github.com/miki4iaml/nomogram/blob/v0.6.0/LICENSE). Bundled data: see
199
207
  [Data sources](#data-sources).
@@ -1,17 +1,17 @@
1
1
  <p align="center">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/miki4iaml/nomogram/v0.5.0/docs/images/banner-dark.svg">
4
- <img alt="nomogram" src="https://raw.githubusercontent.com/miki4iaml/nomogram/v0.5.0/docs/images/banner-light.svg" width="480">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/miki4iaml/nomogram/v0.6.0/docs/images/banner-dark.svg">
4
+ <img alt="nomogram" src="https://raw.githubusercontent.com/miki4iaml/nomogram/v0.6.0/docs/images/banner-light.svg" width="480">
5
5
  </picture>
6
6
  </p>
7
7
 
8
- **English** | [Français](https://github.com/miki4iaml/nomogram/blob/v0.5.0/README.fr.md)
8
+ **English** | [Français](https://github.com/miki4iaml/nomogram/blob/v0.6.0/README.fr.md)
9
9
 
10
10
  [![CI](https://github.com/miki4iaml/nomogram/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/miki4iaml/nomogram/actions/workflows/ci.yml)
11
11
  [![CodeQL](https://github.com/miki4iaml/nomogram/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/miki4iaml/nomogram/actions/workflows/github-code-scanning/codeql)
12
12
  [![codecov](https://codecov.io/gh/miki4iaml/nomogram/graph/badge.svg?branch=develop)](https://codecov.io/gh/miki4iaml/nomogram)
13
- [![Python](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fmiki4iaml%2Fnomogram%2Fdevelop%2Fpyproject.toml)](https://github.com/miki4iaml/nomogram/blob/v0.5.0/pyproject.toml)
14
- [![License](https://img.shields.io/github/license/miki4iaml/nomogram)](https://github.com/miki4iaml/nomogram/blob/v0.5.0/LICENSE)
13
+ [![Python](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fmiki4iaml%2Fnomogram%2Fdevelop%2Fpyproject.toml)](https://github.com/miki4iaml/nomogram/blob/v0.6.0/pyproject.toml)
14
+ [![License](https://img.shields.io/github/license/miki4iaml/nomogram)](https://github.com/miki4iaml/nomogram/blob/v0.6.0/LICENSE)
15
15
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.23373134.svg)](https://doi.org/10.5281/zenodo.23373134)
16
16
  [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
17
17
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
@@ -60,7 +60,7 @@ Python 3.12 or later. Plots need the `viz` extra (matplotlib):
60
60
  Every saturation vapour pressure formulation of the catalog against the
61
61
  IAPWS reference, from 0 to 60 °C and within 1 %; curves stop where a formulation leaves its
62
62
  stated validity domain, and the figure takes the option set of nomogram's
63
- documentation ([script](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/examples/saturation_vapour_pressure.py)):
63
+ documentation ([script](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/examples/saturation_vapour_pressure.py)):
64
64
 
65
65
  ```python
66
66
  import numpy as np
@@ -79,7 +79,7 @@ with nomo.display.display_options(nomo.display.DisplayOptions.DOCUMENTATION):
79
79
  nomo.plot.plot_deviations(table, xlim=(0, 60), ylim=(-1.0, 1.0)) # extra viz
80
80
  ```
81
81
 
82
- ![Deviation of saturation vapour pressure formulations from IAPWS](https://raw.githubusercontent.com/miki4iaml/nomogram/v0.5.0/docs/images/saturation-vapour-pressure.png)
82
+ ![Deviation of saturation vapour pressure formulations from IAPWS](https://raw.githubusercontent.com/miki4iaml/nomogram/v0.6.0/docs/images/saturation-vapour-pressure.png)
83
83
 
84
84
  ## Usage
85
85
 
@@ -102,7 +102,7 @@ pressures p_1 and p_2 of the levels), compares once all but one of them
102
102
  are fixed, which `compare` asks for: `partial` fixes inputs as `functools.partial` fixes arguments,
103
103
  here the two levels, and leaves a function of p alone, evaluated,
104
104
  compared and plotted like any formulation
105
- ([Humidity between two levels](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/vertical.md#humidity-between-two-levels)).
105
+ ([Humidity between two levels](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/vertical.md#humidity-between-two-levels)).
106
106
  It also fixes what is known in advance, such as the levels of a sounding,
107
107
  and names the curve in legends:
108
108
 
@@ -117,7 +117,7 @@ in_ln_p.evaluate(p=Q_(700, "hPa")).to("K") # 268.49
117
117
  ```
118
118
 
119
119
  Formulations are found by words, wildcards and fields, whatever their
120
- notation ([Finding formulations](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/search.md)):
120
+ notation ([Finding formulations](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/search.md)):
121
121
 
122
122
  ```python
123
123
  catalog.search(variable="rho*") # ρ in every notation
@@ -125,20 +125,28 @@ catalog.search(kind="VapourPressure", source="buck*")
125
125
  ```
126
126
 
127
127
  Each formulation keeps its units, validity domain, temperature scale and
128
- references. The vocabulary is mapped in [docs/rosetta.md](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/rosetta.md);
129
- [How nomogram earns trust](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/approach.md) explains what is checked and
130
- how, and [Displaying formulas](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/display.md) shows formulas in notebooks,
131
- Markdown and plots. [Sea water](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/sea-water.md) shows the salinity
128
+ references. The vocabulary is mapped in [docs/rosetta.md](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/rosetta.md),
129
+ and [Shared vocabularies](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/shared-vocabularies.md) explains how nomogram
130
+ builds on QUDT, CF and Wikidata and contributes to them;
131
+ [How nomogram earns trust](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/approach.md) explains what is checked and
132
+ how, and [Displaying formulas](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/display.md) shows formulas in notebooks,
133
+ Markdown and plots. [Sea water](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/sea-water.md) shows the salinity
132
134
  scales and the vapour pressure of sea water, and what its 2 % lowering
133
- changes at the sea surface. [The logo](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/logo.md) is a working
134
- nomogram.
135
+ changes at the sea surface. [Humidity aloft](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/humidity-aloft.md)
136
+ sets the formula of a radiosonde's producer against its users' along a
137
+ vertical profile, through the dew point, over water or over ice, and
138
+ against WMO's requirements.
139
+ [Security and compliance](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/security-and-compliance.md) gathers, for
140
+ those who approve its use on a laboratory network, how nomogram is
141
+ developed, checked and published, what remains to do, and a checklist.
142
+ [The logo](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/logo.md) is a working nomogram.
135
143
 
136
144
  ## Contributing
137
145
 
138
146
  References to integrate, information or corrections about catalog
139
147
  entries, new formulas and code are all welcome: see the
140
- [ways to contribute](https://github.com/miki4iaml/nomogram/blob/v0.5.0/.github/CONTRIBUTING.md#ways-to-contribute) and
141
- the [catalog guide](https://github.com/miki4iaml/nomogram/blob/v0.5.0/docs/catalog.md).
148
+ [ways to contribute](https://github.com/miki4iaml/nomogram/blob/v0.6.0/.github/CONTRIBUTING.md#ways-to-contribute) and
149
+ the [catalog guide](https://github.com/miki4iaml/nomogram/blob/v0.6.0/docs/catalog.md).
142
150
 
143
151
  ## Data sources
144
152
 
@@ -149,7 +157,7 @@ their canonical units, from the CF standard name table. The package
149
157
  bundles a subset of each source:
150
158
 
151
159
  - QUDT — Quantities, Units, Dimensions and Types, by QUDT.org
152
- (<https://qudt.org>), release 3.5.2, licensed under
160
+ (<https://qudt.org>), release 3.5.3, licensed under
153
161
  [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/);
154
162
  - the [CF standard name table](https://cfconventions.org/Data/cf-standard-names/95/build/cf-standard-name-table.html),
155
163
  version 95, [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/);
@@ -157,9 +165,9 @@ bundles a subset of each source:
157
165
  Institute, Inc., [UCUM License](https://ucum.org/license).
158
166
 
159
167
  What nomogram selects, changes and adds is listed in
160
- [NOTICE.md](https://github.com/miki4iaml/nomogram/blob/v0.5.0/src/nomogram/data/NOTICE.md).
168
+ [NOTICE.md](https://github.com/miki4iaml/nomogram/blob/v0.6.0/src/nomogram/data/NOTICE.md).
161
169
 
162
170
  ## License
163
171
 
164
- Code: [BSD-3-Clause](https://github.com/miki4iaml/nomogram/blob/v0.5.0/LICENSE). Bundled data: see
172
+ Code: [BSD-3-Clause](https://github.com/miki4iaml/nomogram/blob/v0.6.0/LICENSE). Bundled data: see
165
173
  [Data sources](#data-sources).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nomogram"
3
- version = "0.5.0"
3
+ version = "0.6.0"
4
4
  description = "Repository of scientific formulas: notations, units, validity domains"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -39,7 +39,7 @@ classifiers = [
39
39
  dependencies = [
40
40
  "numpy>=2.0",
41
41
  "pint>=0.24.4",
42
- "sympy>=1.13",
42
+ "sympy>=1.14",
43
43
  ]
44
44
 
45
45
  [[project.authors]]
@@ -56,7 +56,7 @@ Changelog = "https://github.com/miki4iaml/nomogram/blob/main/CHANGELOG.md"
56
56
  viz = ["matplotlib>=3.10.7"]
57
57
 
58
58
  [build-system]
59
- requires = ["uv_build>=0.12.18,<0.13.0"]
59
+ requires = ["uv_build>=0.12.18,<0.14.0"]
60
60
  build-backend = "uv_build"
61
61
 
62
62
  [dependency-groups]
@@ -133,8 +133,24 @@ extend-select = [
133
133
  "PTH",
134
134
  "RET",
135
135
  "T20",
136
+ "TID251",
136
137
  ]
137
138
 
139
+ [tool.ruff.lint.flake8-tidy-imports.banned-api."sympy.sympify"]
140
+ msg = "read formulas with nomogram.expression.parse_expression"
141
+
142
+ [tool.ruff.lint.flake8-tidy-imports.banned-api."sympy.core.sympify"]
143
+ msg = "read formulas with nomogram.expression.parse_expression"
144
+
145
+ [tool.ruff.lint.flake8-tidy-imports.banned-api."sympy.parse_expr"]
146
+ msg = "read formulas with nomogram.expression.parse_expression"
147
+
148
+ [tool.ruff.lint.flake8-tidy-imports.banned-api."sympy.parsing"]
149
+ msg = "read formulas with nomogram.expression.parse_expression"
150
+
151
+ [tool.ruff.lint.flake8-tidy-imports.banned-api."sympy.parsing.sympy_parser"]
152
+ msg = "read formulas with nomogram.expression.parse_expression"
153
+
138
154
  [tool.ruff.lint.per-file-ignores]
139
155
  "tests/**" = ["ARG001"]
140
156
  "scripts/**" = ["T20"]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nomogram"
3
- version = "0.5.0"
3
+ version = "0.6.0"
4
4
  description = "Repository of scientific formulas: notations, units, validity domains"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -39,7 +39,7 @@ classifiers = [
39
39
  dependencies = [
40
40
  "numpy>=2.0",
41
41
  "pint>=0.24.4",
42
- "sympy>=1.13",
42
+ "sympy>=1.14",
43
43
  ]
44
44
 
45
45
  [project.urls]
@@ -54,7 +54,7 @@ viz = [
54
54
  ]
55
55
 
56
56
  [build-system]
57
- requires = ["uv_build>=0.12.18,<0.13.0"]
57
+ requires = ["uv_build>=0.12.18,<0.14.0"]
58
58
  build-backend = "uv_build"
59
59
 
60
60
  [dependency-groups]
@@ -110,7 +110,16 @@ exclude = ["*.md"]
110
110
 
111
111
  [tool.ruff.lint]
112
112
  # On top of ruff's default selection, which Dependabot bumps surface in CI.
113
- extend-select = ["ARG", "B", "C4", "PIE", "PT", "PTH", "RET", "T20"]
113
+ extend-select = ["ARG", "B", "C4", "PIE", "PT", "PTH", "RET", "T20", "TID251"]
114
+
115
+ # A formula is read by nomogram.expression.parse_expression, against a
116
+ # whitelist: never by SymPy's parsers, which rely on eval (AGENTS.md).
117
+ [tool.ruff.lint.flake8-tidy-imports.banned-api]
118
+ "sympy.sympify".msg = "read formulas with nomogram.expression.parse_expression"
119
+ "sympy.core.sympify".msg = "read formulas with nomogram.expression.parse_expression"
120
+ "sympy.parse_expr".msg = "read formulas with nomogram.expression.parse_expression"
121
+ "sympy.parsing".msg = "read formulas with nomogram.expression.parse_expression"
122
+ "sympy.parsing.sympy_parser".msg = "read formulas with nomogram.expression.parse_expression"
114
123
 
115
124
  [tool.ruff.lint.per-file-ignores]
116
125
  # Fixtures requested for their side effects look like unused arguments.
@@ -1017,7 +1017,7 @@ class _Builder:
1017
1017
  names = {
1018
1018
  self.constants[n].identifier: n for n in self.constants[key].components
1019
1019
  }
1020
- return expr.subs({s: value(names[s.name]) for s in expr.free_symbols})
1020
+ return expr.xreplace({s: value(names[s.name]) for s in expr.free_symbols})
1021
1021
 
1022
1022
  def unrounded(self, key: str) -> Any:
1023
1023
  """The exact value of a constant: its definition, recursively, else as printed."""
@@ -103,6 +103,24 @@ def feeds(output_kind: str, input_kind: str) -> bool:
103
103
  return output_kind == input_kind
104
104
 
105
105
 
106
+ def _may_feed(output_kind: str, input_kind: str) -> bool:
107
+ """Whether a computed value may feed an input of a composition.
108
+
109
+ As :func:`feeds`; or a temperature in the same state, in kelvins or in
110
+ degrees Celsius; or the temperature of a point at which the receiving
111
+ formulation is evaluated (a dew or frost point, a wet- or ice-bulb
112
+ temperature), as a formulation of the catalog calling another may pass
113
+ it.
114
+ """
115
+ from nomogram.catalog import _EVALUATION_POINTS
116
+
117
+ return (
118
+ feeds(output_kind, input_kind)
119
+ or same_state(output_kind, input_kind)
120
+ or input_kind in _EVALUATION_POINTS.get(output_kind, ())
121
+ )
122
+
123
+
106
124
  def _arguments(formulation: Evaluable, values: Mapping[str, Any]) -> dict[str, Any]:
107
125
  arguments = {}
108
126
  fed: dict[str, list[str]] = {}
@@ -180,6 +198,7 @@ def compare(
180
198
  reference: Evaluable,
181
199
  inputs: Mapping[str, Any],
182
200
  *,
201
+ kind: str | None = None,
183
202
  outside: Outside = "nan",
184
203
  basis: Basis = "stated",
185
204
  scale: ScaleConversion = "convert",
@@ -196,6 +215,12 @@ def compare(
196
215
  One value per quantity kind, for example
197
216
  ``{"ThermodynamicTemperature": Q_(grid, "degC")}``; numpy arrays
198
217
  give the whole table in one pass.
218
+ kind : str, optional
219
+ A quantity kind every formulation, the reference included,
220
+ computes or specializes: asked for, it compares formulations of
221
+ sibling kinds, as saturation over ice against saturation over
222
+ water, both a ``"SaturationVapourPressure"``. By default, every
223
+ formulation computes the reference's kind.
199
224
  outside, basis, scale
200
225
  Passed to each evaluation (see
201
226
  :meth:`nomogram.model.Formulation.evaluate`). ``"nan"`` keeps
@@ -210,17 +235,21 @@ def compare(
210
235
  Raises
211
236
  ------
212
237
  ValueError
213
- If a formulation computes another kind than the reference, an input
238
+ If a formulation computes another kind than the reference (or,
239
+ with ``kind``, a kind that does not specialize it), an input
214
240
  cannot be matched to exactly one value, or one value would feed
215
241
  several inputs of a formulation (fix the others with :func:`partial`).
216
242
  """
217
- kind = reference.output.kind
218
243
  unit = None
219
244
  values: dict[str, Any] = {}
220
245
  candidates = [reference, *(f for f in formulations if f.key != reference.key)]
221
246
  for formulation in candidates:
222
- if formulation.output.kind != kind:
223
- msg = f"{formulation.key} computes {formulation.output.kind}, not {kind}"
247
+ computed = formulation.output.kind
248
+ if kind is None and computed != reference.output.kind:
249
+ msg = f"{formulation.key} computes {computed}, not {reference.output.kind}"
250
+ raise ValueError(msg)
251
+ if kind is not None and not feeds(computed, kind):
252
+ msg = f"{formulation.key} computes {computed}, which does not specialize {kind}"
224
253
  raise ValueError(msg)
225
254
  result = formulation.evaluate(
226
255
  outside=outside, basis=basis, scale=scale, **_arguments(formulation, inputs)
@@ -341,7 +370,10 @@ def compose(
341
370
  inner : mapping of str to Formulation
342
371
  For some inputs of ``outer``, by identifier, the formulation that
343
372
  computes them; its output kind must be the input's kind or a
344
- specialization of it (see :func:`feeds`).
373
+ specialization of it (see :func:`feeds`), a temperature in the
374
+ same state (kelvins and degrees Celsius), or the temperature of a
375
+ point at which ``outer`` is evaluated: a dew point feeds the
376
+ temperature of a saturation vapour pressure.
345
377
  bind : mapping of str to str, optional
346
378
  Inputs of inner formulations to take from inputs of ``outer``, by
347
379
  identifier, for example ``{"t": "T"}``: the binding is declared,
@@ -367,7 +399,7 @@ def compose(
367
399
  if target is None:
368
400
  msg = f"{outer.key} has no input {identifier!r}"
369
401
  raise ValueError(msg)
370
- if not feeds(formulation.output.kind, target.kind):
402
+ if not _may_feed(formulation.output.kind, target.kind):
371
403
  msg = (
372
404
  f"{formulation.key} computes {formulation.output.kind}, "
373
405
  f"but {identifier} is {target.kind}"
@@ -7,7 +7,7 @@ sources below. Never edit it by hand.
7
7
 
8
8
  Quantity kinds and unit definitions are extracted from QUDT —
9
9
  Quantities, Units, Dimensions and Types, by QUDT.org
10
- (<https://qudt.org>), release 3.5.2, licensed under CC BY 4.0
10
+ (<https://qudt.org>), release 3.5.3, licensed under CC BY 4.0
11
11
  (<https://creativecommons.org/licenses/by/4.0/>).
12
12
 
13
13
  Changes: a subset of quantity kinds and units was selected and