ParaNMR-Synth 0.3.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.
- paranmr_synth-0.3.0/LICENSE +21 -0
- paranmr_synth-0.3.0/PKG-INFO +149 -0
- paranmr_synth-0.3.0/README.md +103 -0
- paranmr_synth-0.3.0/pyproject.toml +78 -0
- paranmr_synth-0.3.0/setup.cfg +4 -0
- paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/PKG-INFO +149 -0
- paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/SOURCES.txt +42 -0
- paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/dependency_links.txt +1 -0
- paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/entry_points.txt +2 -0
- paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/requires.txt +9 -0
- paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/top_level.txt +1 -0
- paranmr_synth-0.3.0/src/paranmr_synth/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/__version__.py +3 -0
- paranmr_synth-0.3.0/src/paranmr_synth/app/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/app/pipelines/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/app/pipelines/dataset_export.py +80 -0
- paranmr_synth-0.3.0/src/paranmr_synth/app/pipelines/dataset_generation.py +260 -0
- paranmr_synth-0.3.0/src/paranmr_synth/app/pipelines/dataset_validation.py +114 -0
- paranmr_synth-0.3.0/src/paranmr_synth/cfg/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/cfg/dataset.py +132 -0
- paranmr_synth-0.3.0/src/paranmr_synth/cfg/models.py +44 -0
- paranmr_synth-0.3.0/src/paranmr_synth/cli/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/cli/main.py +101 -0
- paranmr_synth-0.3.0/src/paranmr_synth/cli/set_logging.py +80 -0
- paranmr_synth-0.3.0/src/paranmr_synth/core/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/core/dataset/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/core/dataset/records.py +72 -0
- paranmr_synth-0.3.0/src/paranmr_synth/core/generators/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/core/generators/deterministic.py +12 -0
- paranmr_synth-0.3.0/src/paranmr_synth/core/generators/linewidth.py +124 -0
- paranmr_synth-0.3.0/src/paranmr_synth/core/generators/specs.py +32 -0
- paranmr_synth-0.3.0/src/paranmr_synth/core/generators/susceptibility.py +56 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/csv/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/csv/csv_util.py +41 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/csv/experiment.py +45 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/csv/ml.py +22 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/csv/susceptibility.py +36 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/json/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/json/manifest.py +37 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/xyz/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/xyz/geometry.py +18 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/yaml/__init__.py +0 -0
- paranmr_synth-0.3.0/src/paranmr_synth/io/yaml/fit.py +44 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ernest Borysenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ParaNMR-Synth
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Reproducible synthetic pNMR dataset generator for ParaNMR workflows
|
|
5
|
+
Author: Ernest Borysenko
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Ernest Borysenko
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/Mephistos-ML/ParaNMR-Synth
|
|
29
|
+
Project-URL: Repository, https://github.com/Mephistos-ML/ParaNMR-Synth
|
|
30
|
+
Project-URL: Issues, https://github.com/Mephistos-ML/ParaNMR-Synth/issues
|
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Requires-Python: >=3.10
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Requires-Dist: numpy
|
|
38
|
+
Requires-Dist: paranmr
|
|
39
|
+
Requires-Dist: pyyaml
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
43
|
+
Requires-Dist: python-semantic-release>=9.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: ruff>=0.5.0; extra == "dev"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# ParaNMR-Synth
|
|
48
|
+
|
|
49
|
+
`ParaNMR-Synth` generates deterministic, replayable synthetic pNMR datasets for supervised learning and validation of ParaNMR fitting workflows.
|
|
50
|
+
|
|
51
|
+
Each synthetic case follows the layout of a ParaNMR example. The dataset root
|
|
52
|
+
also contains one paired ML table:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
dataset.csv
|
|
56
|
+
manifest.json
|
|
57
|
+
cases/<sample_id>/
|
|
58
|
+
DATA/
|
|
59
|
+
PARA/generated_shifts.csv
|
|
60
|
+
HFC/geometry.xyz
|
|
61
|
+
DIA/diamagnetic.csv
|
|
62
|
+
CHI/susceptibility.csv
|
|
63
|
+
LABELS/labels.csv # optional
|
|
64
|
+
SIMULATIONS/
|
|
65
|
+
FITTING/config.yml
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`dataset.csv` is the canonical supervised-learning artifact. One row contains `m1..mN` as features and six Cartesian susceptibility components plus `p1,p2` as targets. The selected susceptibility unit is recorded in `manifest.json`.
|
|
69
|
+
|
|
70
|
+
`DATA/DIA/diamagnetic.csv` is always atom-resolved and normalized to
|
|
71
|
+
`atom_label,shift`, including when the source input was DFT plus a reference.
|
|
72
|
+
`DATA/CHI/susceptibility.csv` contains susceptibility truth only; linewidth
|
|
73
|
+
truth remains exclusively in the root `dataset.csv`.
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
The dataset pipeline requires ParaNMR with atom-labelled diamagnetic CSV input, fixed-assignment `linewidth: estimate: p1_p2`, and ParaNMR experiment CSV round-tripping.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python3 -m pip install paranmr
|
|
81
|
+
python3 -m pip install -e .[dev]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Dataset YAML
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
project:
|
|
88
|
+
name: ybl8_moments_v1
|
|
89
|
+
n_cases: 1000
|
|
90
|
+
seed: 42
|
|
91
|
+
hyperfine:
|
|
92
|
+
method: pdip
|
|
93
|
+
file: geometries/YbL8.xyz
|
|
94
|
+
paramagnetic_centre: [0.0, 0.0, 0.0]
|
|
95
|
+
spin: 0.5
|
|
96
|
+
orbit: 3
|
|
97
|
+
total_momentum_J: 3.5
|
|
98
|
+
nuclei:
|
|
99
|
+
include: H
|
|
100
|
+
diamagnetic:
|
|
101
|
+
method: csv
|
|
102
|
+
file: inputs/diamagnetic.csv
|
|
103
|
+
signal_labels: # optional
|
|
104
|
+
file: inputs/labels.csv
|
|
105
|
+
experiment:
|
|
106
|
+
temperature_k: 302.15
|
|
107
|
+
magnetic_field_t: 4.7
|
|
108
|
+
moments:
|
|
109
|
+
number_of_moments: 10
|
|
110
|
+
linewidth:
|
|
111
|
+
method: r6
|
|
112
|
+
susceptibility:
|
|
113
|
+
model: isoaxrho_euler
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`chi_iso` is calculated through ParaNMR's spin-only Curie-law implementation.
|
|
117
|
+
Synth samples `rho_over_ax` in `[0, 1/3]`, derives physical bounds for
|
|
118
|
+
`chi_ax`, and samples Euler angles in standard ZYZ domains. All χ targets are
|
|
119
|
+
exported in canonical ParaNMR units of ų.
|
|
120
|
+
|
|
121
|
+
For `linewidth.method: r6`, Synth derives `p1` from ParaNMR's point-dipole
|
|
122
|
+
Guéron Curie R2 calculation with the fixed generation policy
|
|
123
|
+
`tau_R = 1 ns`. It samples the distance-independent `p2` uniformly in
|
|
124
|
+
`[0, 50] Hz`, then converts it to the ppm convention required by ParaNMR's R6
|
|
125
|
+
forward model. Neither coefficient is a user-facing configuration parameter.
|
|
126
|
+
|
|
127
|
+
## CLI
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
paranmr-synth dataset generate ybl8.yml --output datasets/yb_v1
|
|
131
|
+
cd datasets/yb_v1/cases/<sample_id>/SIMULATIONS/FITTING
|
|
132
|
+
MPLBACKEND=Agg paranmr --hide fit_susc config.yml
|
|
133
|
+
paranmr-synth dataset validate ../..
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`validation_report.json` records truth, fitted values and errors. It does not silently reject a sample based on rank, condition number or score.
|
|
137
|
+
|
|
138
|
+
## Validation stages
|
|
139
|
+
|
|
140
|
+
The replay profile uses ParaNMR fixed assignment. It validates the forward data contract and separately recovers R6 `p1,p2` from labelled linewidths. Assignment-free GMM moments validation belongs to ParaNMR's own synthetic test suite and is intentionally a later stage.
|
|
141
|
+
|
|
142
|
+
## Development
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
python3 -m pytest -m 'not integration'
|
|
146
|
+
python3 -m pytest -m integration
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The integration suite launches the real `paranmr` executable and must run against the compatible ParaNMR version. Every generated CSV records `ParaNMR-Synth` version provenance in its comment header.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# ParaNMR-Synth
|
|
2
|
+
|
|
3
|
+
`ParaNMR-Synth` generates deterministic, replayable synthetic pNMR datasets for supervised learning and validation of ParaNMR fitting workflows.
|
|
4
|
+
|
|
5
|
+
Each synthetic case follows the layout of a ParaNMR example. The dataset root
|
|
6
|
+
also contains one paired ML table:
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
dataset.csv
|
|
10
|
+
manifest.json
|
|
11
|
+
cases/<sample_id>/
|
|
12
|
+
DATA/
|
|
13
|
+
PARA/generated_shifts.csv
|
|
14
|
+
HFC/geometry.xyz
|
|
15
|
+
DIA/diamagnetic.csv
|
|
16
|
+
CHI/susceptibility.csv
|
|
17
|
+
LABELS/labels.csv # optional
|
|
18
|
+
SIMULATIONS/
|
|
19
|
+
FITTING/config.yml
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`dataset.csv` is the canonical supervised-learning artifact. One row contains `m1..mN` as features and six Cartesian susceptibility components plus `p1,p2` as targets. The selected susceptibility unit is recorded in `manifest.json`.
|
|
23
|
+
|
|
24
|
+
`DATA/DIA/diamagnetic.csv` is always atom-resolved and normalized to
|
|
25
|
+
`atom_label,shift`, including when the source input was DFT plus a reference.
|
|
26
|
+
`DATA/CHI/susceptibility.csv` contains susceptibility truth only; linewidth
|
|
27
|
+
truth remains exclusively in the root `dataset.csv`.
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
The dataset pipeline requires ParaNMR with atom-labelled diamagnetic CSV input, fixed-assignment `linewidth: estimate: p1_p2`, and ParaNMR experiment CSV round-tripping.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python3 -m pip install paranmr
|
|
35
|
+
python3 -m pip install -e .[dev]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Dataset YAML
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
project:
|
|
42
|
+
name: ybl8_moments_v1
|
|
43
|
+
n_cases: 1000
|
|
44
|
+
seed: 42
|
|
45
|
+
hyperfine:
|
|
46
|
+
method: pdip
|
|
47
|
+
file: geometries/YbL8.xyz
|
|
48
|
+
paramagnetic_centre: [0.0, 0.0, 0.0]
|
|
49
|
+
spin: 0.5
|
|
50
|
+
orbit: 3
|
|
51
|
+
total_momentum_J: 3.5
|
|
52
|
+
nuclei:
|
|
53
|
+
include: H
|
|
54
|
+
diamagnetic:
|
|
55
|
+
method: csv
|
|
56
|
+
file: inputs/diamagnetic.csv
|
|
57
|
+
signal_labels: # optional
|
|
58
|
+
file: inputs/labels.csv
|
|
59
|
+
experiment:
|
|
60
|
+
temperature_k: 302.15
|
|
61
|
+
magnetic_field_t: 4.7
|
|
62
|
+
moments:
|
|
63
|
+
number_of_moments: 10
|
|
64
|
+
linewidth:
|
|
65
|
+
method: r6
|
|
66
|
+
susceptibility:
|
|
67
|
+
model: isoaxrho_euler
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`chi_iso` is calculated through ParaNMR's spin-only Curie-law implementation.
|
|
71
|
+
Synth samples `rho_over_ax` in `[0, 1/3]`, derives physical bounds for
|
|
72
|
+
`chi_ax`, and samples Euler angles in standard ZYZ domains. All χ targets are
|
|
73
|
+
exported in canonical ParaNMR units of ų.
|
|
74
|
+
|
|
75
|
+
For `linewidth.method: r6`, Synth derives `p1` from ParaNMR's point-dipole
|
|
76
|
+
Guéron Curie R2 calculation with the fixed generation policy
|
|
77
|
+
`tau_R = 1 ns`. It samples the distance-independent `p2` uniformly in
|
|
78
|
+
`[0, 50] Hz`, then converts it to the ppm convention required by ParaNMR's R6
|
|
79
|
+
forward model. Neither coefficient is a user-facing configuration parameter.
|
|
80
|
+
|
|
81
|
+
## CLI
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
paranmr-synth dataset generate ybl8.yml --output datasets/yb_v1
|
|
85
|
+
cd datasets/yb_v1/cases/<sample_id>/SIMULATIONS/FITTING
|
|
86
|
+
MPLBACKEND=Agg paranmr --hide fit_susc config.yml
|
|
87
|
+
paranmr-synth dataset validate ../..
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`validation_report.json` records truth, fitted values and errors. It does not silently reject a sample based on rank, condition number or score.
|
|
91
|
+
|
|
92
|
+
## Validation stages
|
|
93
|
+
|
|
94
|
+
The replay profile uses ParaNMR fixed assignment. It validates the forward data contract and separately recovers R6 `p1,p2` from labelled linewidths. Assignment-free GMM moments validation belongs to ParaNMR's own synthetic test suite and is intentionally a later stage.
|
|
95
|
+
|
|
96
|
+
## Development
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
python3 -m pytest -m 'not integration'
|
|
100
|
+
python3 -m pytest -m integration
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The integration suite launches the real `paranmr` executable and must run against the compatible ParaNMR version. Every generated CSV records `ParaNMR-Synth` version provenance in its comment header.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Project build, packaging, and tooling configuration.
|
|
2
|
+
|
|
3
|
+
[build-system]
|
|
4
|
+
requires = ["setuptools>=61", "wheel"]
|
|
5
|
+
build-backend = "setuptools.build_meta"
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "ParaNMR-Synth"
|
|
9
|
+
dynamic = ["version"]
|
|
10
|
+
description = "Reproducible synthetic pNMR dataset generator for ParaNMR workflows"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
license = { file = "LICENSE" }
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Ernest Borysenko" },
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
]
|
|
21
|
+
requires-python = ">=3.10"
|
|
22
|
+
dependencies = [
|
|
23
|
+
"numpy",
|
|
24
|
+
"paranmr",
|
|
25
|
+
"pyyaml",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = [
|
|
30
|
+
"build>=1.2.0",
|
|
31
|
+
"pytest>=8.0.0",
|
|
32
|
+
"python-semantic-release>=9.0.0",
|
|
33
|
+
"ruff>=0.5.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
paranmr-synth = "paranmr_synth.cli.main:main"
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://github.com/Mephistos-ML/ParaNMR-Synth"
|
|
41
|
+
Repository = "https://github.com/Mephistos-ML/ParaNMR-Synth"
|
|
42
|
+
Issues = "https://github.com/Mephistos-ML/ParaNMR-Synth/issues"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.dynamic]
|
|
48
|
+
version = {attr = "paranmr_synth.__version__.__version__"}
|
|
49
|
+
|
|
50
|
+
[tool.semantic_release]
|
|
51
|
+
version_variables = ["src/paranmr_synth/__version__.py:__version__"]
|
|
52
|
+
branch = "main"
|
|
53
|
+
commit_parser = "conventional"
|
|
54
|
+
allow_zero_version = true
|
|
55
|
+
build_command = "python -m pip install build && python -m build --sdist --wheel ."
|
|
56
|
+
changelog_file = "CHANGELOG.md"
|
|
57
|
+
commit_message = "chore(release): {version}"
|
|
58
|
+
|
|
59
|
+
[tool.semantic_release.remote]
|
|
60
|
+
type = "github"
|
|
61
|
+
|
|
62
|
+
[tool.ruff]
|
|
63
|
+
line-length = 88
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = ["E", "F", "I"]
|
|
67
|
+
|
|
68
|
+
[tool.pytest.ini_options]
|
|
69
|
+
addopts = "-ra -q"
|
|
70
|
+
pythonpath = ["src"]
|
|
71
|
+
markers = [
|
|
72
|
+
"integration: end-to-end example/CLI integration tests (may be slow)",
|
|
73
|
+
"smoke: fast smoke tests for CLI/entrypoints",
|
|
74
|
+
"unit: fast unit tests with no subprocess, no network, minimal IO",
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
log_cli = true
|
|
78
|
+
log_cli_level = "INFO"
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ParaNMR-Synth
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Reproducible synthetic pNMR dataset generator for ParaNMR workflows
|
|
5
|
+
Author: Ernest Borysenko
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Ernest Borysenko
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/Mephistos-ML/ParaNMR-Synth
|
|
29
|
+
Project-URL: Repository, https://github.com/Mephistos-ML/ParaNMR-Synth
|
|
30
|
+
Project-URL: Issues, https://github.com/Mephistos-ML/ParaNMR-Synth/issues
|
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Requires-Python: >=3.10
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Requires-Dist: numpy
|
|
38
|
+
Requires-Dist: paranmr
|
|
39
|
+
Requires-Dist: pyyaml
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
43
|
+
Requires-Dist: python-semantic-release>=9.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: ruff>=0.5.0; extra == "dev"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# ParaNMR-Synth
|
|
48
|
+
|
|
49
|
+
`ParaNMR-Synth` generates deterministic, replayable synthetic pNMR datasets for supervised learning and validation of ParaNMR fitting workflows.
|
|
50
|
+
|
|
51
|
+
Each synthetic case follows the layout of a ParaNMR example. The dataset root
|
|
52
|
+
also contains one paired ML table:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
dataset.csv
|
|
56
|
+
manifest.json
|
|
57
|
+
cases/<sample_id>/
|
|
58
|
+
DATA/
|
|
59
|
+
PARA/generated_shifts.csv
|
|
60
|
+
HFC/geometry.xyz
|
|
61
|
+
DIA/diamagnetic.csv
|
|
62
|
+
CHI/susceptibility.csv
|
|
63
|
+
LABELS/labels.csv # optional
|
|
64
|
+
SIMULATIONS/
|
|
65
|
+
FITTING/config.yml
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`dataset.csv` is the canonical supervised-learning artifact. One row contains `m1..mN` as features and six Cartesian susceptibility components plus `p1,p2` as targets. The selected susceptibility unit is recorded in `manifest.json`.
|
|
69
|
+
|
|
70
|
+
`DATA/DIA/diamagnetic.csv` is always atom-resolved and normalized to
|
|
71
|
+
`atom_label,shift`, including when the source input was DFT plus a reference.
|
|
72
|
+
`DATA/CHI/susceptibility.csv` contains susceptibility truth only; linewidth
|
|
73
|
+
truth remains exclusively in the root `dataset.csv`.
|
|
74
|
+
|
|
75
|
+
## Requirements
|
|
76
|
+
|
|
77
|
+
The dataset pipeline requires ParaNMR with atom-labelled diamagnetic CSV input, fixed-assignment `linewidth: estimate: p1_p2`, and ParaNMR experiment CSV round-tripping.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
python3 -m pip install paranmr
|
|
81
|
+
python3 -m pip install -e .[dev]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Dataset YAML
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
project:
|
|
88
|
+
name: ybl8_moments_v1
|
|
89
|
+
n_cases: 1000
|
|
90
|
+
seed: 42
|
|
91
|
+
hyperfine:
|
|
92
|
+
method: pdip
|
|
93
|
+
file: geometries/YbL8.xyz
|
|
94
|
+
paramagnetic_centre: [0.0, 0.0, 0.0]
|
|
95
|
+
spin: 0.5
|
|
96
|
+
orbit: 3
|
|
97
|
+
total_momentum_J: 3.5
|
|
98
|
+
nuclei:
|
|
99
|
+
include: H
|
|
100
|
+
diamagnetic:
|
|
101
|
+
method: csv
|
|
102
|
+
file: inputs/diamagnetic.csv
|
|
103
|
+
signal_labels: # optional
|
|
104
|
+
file: inputs/labels.csv
|
|
105
|
+
experiment:
|
|
106
|
+
temperature_k: 302.15
|
|
107
|
+
magnetic_field_t: 4.7
|
|
108
|
+
moments:
|
|
109
|
+
number_of_moments: 10
|
|
110
|
+
linewidth:
|
|
111
|
+
method: r6
|
|
112
|
+
susceptibility:
|
|
113
|
+
model: isoaxrho_euler
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`chi_iso` is calculated through ParaNMR's spin-only Curie-law implementation.
|
|
117
|
+
Synth samples `rho_over_ax` in `[0, 1/3]`, derives physical bounds for
|
|
118
|
+
`chi_ax`, and samples Euler angles in standard ZYZ domains. All χ targets are
|
|
119
|
+
exported in canonical ParaNMR units of ų.
|
|
120
|
+
|
|
121
|
+
For `linewidth.method: r6`, Synth derives `p1` from ParaNMR's point-dipole
|
|
122
|
+
Guéron Curie R2 calculation with the fixed generation policy
|
|
123
|
+
`tau_R = 1 ns`. It samples the distance-independent `p2` uniformly in
|
|
124
|
+
`[0, 50] Hz`, then converts it to the ppm convention required by ParaNMR's R6
|
|
125
|
+
forward model. Neither coefficient is a user-facing configuration parameter.
|
|
126
|
+
|
|
127
|
+
## CLI
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
paranmr-synth dataset generate ybl8.yml --output datasets/yb_v1
|
|
131
|
+
cd datasets/yb_v1/cases/<sample_id>/SIMULATIONS/FITTING
|
|
132
|
+
MPLBACKEND=Agg paranmr --hide fit_susc config.yml
|
|
133
|
+
paranmr-synth dataset validate ../..
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`validation_report.json` records truth, fitted values and errors. It does not silently reject a sample based on rank, condition number or score.
|
|
137
|
+
|
|
138
|
+
## Validation stages
|
|
139
|
+
|
|
140
|
+
The replay profile uses ParaNMR fixed assignment. It validates the forward data contract and separately recovers R6 `p1,p2` from labelled linewidths. Assignment-free GMM moments validation belongs to ParaNMR's own synthetic test suite and is intentionally a later stage.
|
|
141
|
+
|
|
142
|
+
## Development
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
python3 -m pytest -m 'not integration'
|
|
146
|
+
python3 -m pytest -m integration
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The integration suite launches the real `paranmr` executable and must run against the compatible ParaNMR version. Every generated CSV records `ParaNMR-Synth` version provenance in its comment header.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/ParaNMR_Synth.egg-info/PKG-INFO
|
|
5
|
+
src/ParaNMR_Synth.egg-info/SOURCES.txt
|
|
6
|
+
src/ParaNMR_Synth.egg-info/dependency_links.txt
|
|
7
|
+
src/ParaNMR_Synth.egg-info/entry_points.txt
|
|
8
|
+
src/ParaNMR_Synth.egg-info/requires.txt
|
|
9
|
+
src/ParaNMR_Synth.egg-info/top_level.txt
|
|
10
|
+
src/paranmr_synth/__init__.py
|
|
11
|
+
src/paranmr_synth/__version__.py
|
|
12
|
+
src/paranmr_synth/app/__init__.py
|
|
13
|
+
src/paranmr_synth/app/pipelines/__init__.py
|
|
14
|
+
src/paranmr_synth/app/pipelines/dataset_export.py
|
|
15
|
+
src/paranmr_synth/app/pipelines/dataset_generation.py
|
|
16
|
+
src/paranmr_synth/app/pipelines/dataset_validation.py
|
|
17
|
+
src/paranmr_synth/cfg/__init__.py
|
|
18
|
+
src/paranmr_synth/cfg/dataset.py
|
|
19
|
+
src/paranmr_synth/cfg/models.py
|
|
20
|
+
src/paranmr_synth/cli/__init__.py
|
|
21
|
+
src/paranmr_synth/cli/main.py
|
|
22
|
+
src/paranmr_synth/cli/set_logging.py
|
|
23
|
+
src/paranmr_synth/core/__init__.py
|
|
24
|
+
src/paranmr_synth/core/dataset/__init__.py
|
|
25
|
+
src/paranmr_synth/core/dataset/records.py
|
|
26
|
+
src/paranmr_synth/core/generators/__init__.py
|
|
27
|
+
src/paranmr_synth/core/generators/deterministic.py
|
|
28
|
+
src/paranmr_synth/core/generators/linewidth.py
|
|
29
|
+
src/paranmr_synth/core/generators/specs.py
|
|
30
|
+
src/paranmr_synth/core/generators/susceptibility.py
|
|
31
|
+
src/paranmr_synth/io/__init__.py
|
|
32
|
+
src/paranmr_synth/io/csv/__init__.py
|
|
33
|
+
src/paranmr_synth/io/csv/csv_util.py
|
|
34
|
+
src/paranmr_synth/io/csv/experiment.py
|
|
35
|
+
src/paranmr_synth/io/csv/ml.py
|
|
36
|
+
src/paranmr_synth/io/csv/susceptibility.py
|
|
37
|
+
src/paranmr_synth/io/json/__init__.py
|
|
38
|
+
src/paranmr_synth/io/json/manifest.py
|
|
39
|
+
src/paranmr_synth/io/xyz/__init__.py
|
|
40
|
+
src/paranmr_synth/io/xyz/geometry.py
|
|
41
|
+
src/paranmr_synth/io/yaml/__init__.py
|
|
42
|
+
src/paranmr_synth/io/yaml/fit.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
paranmr_synth
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Orchestrate a complete replayable synthetic dataset export."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import shutil
|
|
7
|
+
|
|
8
|
+
import pandas as pd
|
|
9
|
+
|
|
10
|
+
from paranmr_synth.app.pipelines.dataset_generation import (
|
|
11
|
+
GeneratedCase,
|
|
12
|
+
generate_case_artifacts,
|
|
13
|
+
prepare_dataset_molecule,
|
|
14
|
+
)
|
|
15
|
+
from paranmr_synth.cfg.dataset import DatasetGenerationConfig
|
|
16
|
+
from paranmr_synth.io.csv.experiment import write_experiment
|
|
17
|
+
from paranmr_synth.io.csv.ml import write_ml_dataset
|
|
18
|
+
from paranmr_synth.io.csv.susceptibility import write_susceptibility
|
|
19
|
+
from paranmr_synth.io.csv.csv_util import write_csv_safe
|
|
20
|
+
from paranmr_synth.io.json.manifest import write_manifest
|
|
21
|
+
from paranmr_synth.io.xyz.geometry import write_indexed_geometry
|
|
22
|
+
from paranmr_synth.io.yaml.fit import write_fit_config
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def generate_dataset(
|
|
26
|
+
*, config: DatasetGenerationConfig, output_dir: str | Path
|
|
27
|
+
) -> Path:
|
|
28
|
+
"""Generate all cases, their ParaNMR inputs, and the paired ML dataset."""
|
|
29
|
+
molecule, checksum = prepare_dataset_molecule(config)
|
|
30
|
+
cases = tuple(
|
|
31
|
+
generate_case_artifacts(
|
|
32
|
+
config=config,
|
|
33
|
+
molecule=molecule,
|
|
34
|
+
geometry_checksum=checksum,
|
|
35
|
+
case_index=index,
|
|
36
|
+
)
|
|
37
|
+
for index in range(config.project.n_cases)
|
|
38
|
+
)
|
|
39
|
+
root = Path(output_dir)
|
|
40
|
+
root.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
for case in cases:
|
|
42
|
+
_write_case(config=config, case=case, molecule=molecule, root=root)
|
|
43
|
+
write_ml_dataset(cases=cases, output_file=root / "dataset.csv")
|
|
44
|
+
write_manifest(
|
|
45
|
+
config=config,
|
|
46
|
+
output_file=root / "manifest.json",
|
|
47
|
+
geometry_checksum=checksum,
|
|
48
|
+
)
|
|
49
|
+
return root
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _write_case(*, config: DatasetGenerationConfig, case: GeneratedCase, molecule, root: Path) -> None:
|
|
53
|
+
"""Write one replayable case through format-specific IO writers."""
|
|
54
|
+
case_root = root / "cases" / case.record.sample_id
|
|
55
|
+
data_dir = case_root / "DATA"
|
|
56
|
+
fitting_dir = case_root / "SIMULATIONS" / "FITTING"
|
|
57
|
+
write_indexed_geometry(input_file=config.hyperfine.file, output_file=data_dir / "HFC" / "geometry.xyz")
|
|
58
|
+
if config.signal_labels_file:
|
|
59
|
+
labels_file = data_dir / "LABELS" / "labels.csv"
|
|
60
|
+
labels_file.parent.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
shutil.copy2(config.signal_labels_file, labels_file)
|
|
62
|
+
write_fit_config(config=config, output_file=fitting_dir / "config.yml")
|
|
63
|
+
write_experiment(config=config, case=case, output_file=data_dir / "PARA" / "generated_shifts.csv")
|
|
64
|
+
_write_diamagnetic_csv(molecule=molecule, output_file=data_dir / "DIA" / "diamagnetic.csv")
|
|
65
|
+
write_susceptibility(
|
|
66
|
+
target=case.record.target,
|
|
67
|
+
latent=case.susceptibility,
|
|
68
|
+
output_file=data_dir / "CHI" / "susceptibility.csv",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _write_diamagnetic_csv(*, molecule, output_file: Path) -> None:
|
|
73
|
+
"""Write ParaNMR-normalized atom-resolved dia shifts for replay."""
|
|
74
|
+
write_csv_safe(
|
|
75
|
+
pd.DataFrame(
|
|
76
|
+
[{"atom_label": nucleus.label, "shift": nucleus.shift.dia} for nucleus in molecule.nuclei]
|
|
77
|
+
),
|
|
78
|
+
output_file,
|
|
79
|
+
float_format="%.15g",
|
|
80
|
+
)
|