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.
Files changed (44) hide show
  1. paranmr_synth-0.3.0/LICENSE +21 -0
  2. paranmr_synth-0.3.0/PKG-INFO +149 -0
  3. paranmr_synth-0.3.0/README.md +103 -0
  4. paranmr_synth-0.3.0/pyproject.toml +78 -0
  5. paranmr_synth-0.3.0/setup.cfg +4 -0
  6. paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/PKG-INFO +149 -0
  7. paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/SOURCES.txt +42 -0
  8. paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/dependency_links.txt +1 -0
  9. paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/entry_points.txt +2 -0
  10. paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/requires.txt +9 -0
  11. paranmr_synth-0.3.0/src/ParaNMR_Synth.egg-info/top_level.txt +1 -0
  12. paranmr_synth-0.3.0/src/paranmr_synth/__init__.py +0 -0
  13. paranmr_synth-0.3.0/src/paranmr_synth/__version__.py +3 -0
  14. paranmr_synth-0.3.0/src/paranmr_synth/app/__init__.py +0 -0
  15. paranmr_synth-0.3.0/src/paranmr_synth/app/pipelines/__init__.py +0 -0
  16. paranmr_synth-0.3.0/src/paranmr_synth/app/pipelines/dataset_export.py +80 -0
  17. paranmr_synth-0.3.0/src/paranmr_synth/app/pipelines/dataset_generation.py +260 -0
  18. paranmr_synth-0.3.0/src/paranmr_synth/app/pipelines/dataset_validation.py +114 -0
  19. paranmr_synth-0.3.0/src/paranmr_synth/cfg/__init__.py +0 -0
  20. paranmr_synth-0.3.0/src/paranmr_synth/cfg/dataset.py +132 -0
  21. paranmr_synth-0.3.0/src/paranmr_synth/cfg/models.py +44 -0
  22. paranmr_synth-0.3.0/src/paranmr_synth/cli/__init__.py +0 -0
  23. paranmr_synth-0.3.0/src/paranmr_synth/cli/main.py +101 -0
  24. paranmr_synth-0.3.0/src/paranmr_synth/cli/set_logging.py +80 -0
  25. paranmr_synth-0.3.0/src/paranmr_synth/core/__init__.py +0 -0
  26. paranmr_synth-0.3.0/src/paranmr_synth/core/dataset/__init__.py +0 -0
  27. paranmr_synth-0.3.0/src/paranmr_synth/core/dataset/records.py +72 -0
  28. paranmr_synth-0.3.0/src/paranmr_synth/core/generators/__init__.py +0 -0
  29. paranmr_synth-0.3.0/src/paranmr_synth/core/generators/deterministic.py +12 -0
  30. paranmr_synth-0.3.0/src/paranmr_synth/core/generators/linewidth.py +124 -0
  31. paranmr_synth-0.3.0/src/paranmr_synth/core/generators/specs.py +32 -0
  32. paranmr_synth-0.3.0/src/paranmr_synth/core/generators/susceptibility.py +56 -0
  33. paranmr_synth-0.3.0/src/paranmr_synth/io/__init__.py +0 -0
  34. paranmr_synth-0.3.0/src/paranmr_synth/io/csv/__init__.py +0 -0
  35. paranmr_synth-0.3.0/src/paranmr_synth/io/csv/csv_util.py +41 -0
  36. paranmr_synth-0.3.0/src/paranmr_synth/io/csv/experiment.py +45 -0
  37. paranmr_synth-0.3.0/src/paranmr_synth/io/csv/ml.py +22 -0
  38. paranmr_synth-0.3.0/src/paranmr_synth/io/csv/susceptibility.py +36 -0
  39. paranmr_synth-0.3.0/src/paranmr_synth/io/json/__init__.py +0 -0
  40. paranmr_synth-0.3.0/src/paranmr_synth/io/json/manifest.py +37 -0
  41. paranmr_synth-0.3.0/src/paranmr_synth/io/xyz/__init__.py +0 -0
  42. paranmr_synth-0.3.0/src/paranmr_synth/io/xyz/geometry.py +18 -0
  43. paranmr_synth-0.3.0/src/paranmr_synth/io/yaml/__init__.py +0 -0
  44. 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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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,2 @@
1
+ [console_scripts]
2
+ paranmr-synth = paranmr_synth.cli.main:main
@@ -0,0 +1,9 @@
1
+ numpy
2
+ paranmr
3
+ pyyaml
4
+
5
+ [dev]
6
+ build>=1.2.0
7
+ pytest>=8.0.0
8
+ python-semantic-release>=9.0.0
9
+ ruff>=0.5.0
@@ -0,0 +1 @@
1
+ paranmr_synth
File without changes
@@ -0,0 +1,3 @@
1
+ # DO NOT EDIT THIS NUMBER!
2
+ # IT IS AUTOMATICALLY CHANGED BY python-semantic-release
3
+ __version__ = "0.3.0"
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
+ )