diskmelts 2.2.0__tar.gz → 2.2.1__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 (97) hide show
  1. diskmelts-2.2.1/MANIFEST.in +2 -0
  2. {diskmelts-2.2.0/src/diskmelts.egg-info → diskmelts-2.2.1}/PKG-INFO +89 -34
  3. {diskmelts-2.2.0 → diskmelts-2.2.1}/README.md +85 -30
  4. {diskmelts-2.2.0 → diskmelts-2.2.1}/pyproject.toml +7 -4
  5. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/__init__.py +2 -0
  6. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/_core.py +24 -7
  7. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/fitting.py +188 -120
  8. diskmelts-2.2.1/src/diskmelts/models/Trained_model/sigma0/C2H2_wavelength_bank_v2/C2H2_model_bank.json +26 -0
  9. diskmelts-2.2.1/src/diskmelts/models/Trained_model/sigma0/C2H2_wavelength_bank_v2/net_C2H2_w6to9.pt +0 -0
  10. diskmelts-2.2.1/src/diskmelts/models/Trained_model/sigma0/OH_single_v2/net_OH_forward.pt +0 -0
  11. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/plotting.py +1 -1
  12. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/trainmodel.py +21 -9
  13. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/v2_fitting.py +152 -24
  14. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/v2_grid_fitting.py +117 -56
  15. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/validation.py +22 -6
  16. {diskmelts-2.2.0 → diskmelts-2.2.1/src/diskmelts.egg-info}/PKG-INFO +89 -34
  17. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts.egg-info/SOURCES.txt +6 -16
  18. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts.egg-info/requires.txt +2 -2
  19. diskmelts-2.2.0/tests/test_consub_package.py +0 -99
  20. diskmelts-2.2.0/tests/test_detection.py +0 -133
  21. diskmelts-2.2.0/tests/test_dev_v2_fitting_distance.py +0 -41
  22. diskmelts-2.2.0/tests/test_dev_v2_fitting_grids.py +0 -176
  23. diskmelts-2.2.0/tests/test_dev_v2_read_plot.py +0 -95
  24. diskmelts-2.2.0/tests/test_imports.py +0 -61
  25. diskmelts-2.2.0/tests/test_io.py +0 -80
  26. diskmelts-2.2.0/tests/test_mlp.py +0 -43
  27. diskmelts-2.2.0/tests/test_model_bank.py +0 -230
  28. diskmelts-2.2.0/tests/test_shared_area_fitting.py +0 -190
  29. diskmelts-2.2.0/tests/test_smoke.py +0 -48
  30. diskmelts-2.2.0/tests/test_v2_package_assets.py +0 -129
  31. diskmelts-2.2.0/tests/test_water_training.py +0 -126
  32. diskmelts-2.2.0/tests/test_workflows.py +0 -263
  33. {diskmelts-2.2.0 → diskmelts-2.2.1}/LICENSE +0 -0
  34. {diskmelts-2.2.0 → diskmelts-2.2.1}/setup.cfg +0 -0
  35. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/__init__.py +0 -0
  36. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/_api.py +0 -0
  37. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/cont_ranges.csv +0 -0
  38. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/cont_ranges_PPan.csv +0 -0
  39. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/regions/carbon_extended.csv +0 -0
  40. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/regions/carbon_extended.json +0 -0
  41. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/regions/carbon_rich.csv +0 -0
  42. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/regions/carbon_rich.json +0 -0
  43. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/regions/ttauri.csv +0 -0
  44. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/regions/ttauri.json +0 -0
  45. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/regions/water.csv +0 -0
  46. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/consub/regions/water.json +0 -0
  47. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/13C12CH2_single_v2/net_13C12CH2_forward.pt +0 -0
  48. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/13CO2_single_v2/net_13CO2_forward.pt +0 -0
  49. /diskmelts-2.2.0/src/diskmelts/models/Trained_model/sigma0/C2H2_single_v2/net_C2H2_forward.pt → /diskmelts-2.2.1/src/diskmelts/models/Trained_model/sigma0/C2H2_wavelength_bank_v2/net_C2H2_w11p5to17.pt +0 -0
  50. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/C2H4_single_v2/net_C2H4_forward.pt +0 -0
  51. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/C2H6_single_v2/net_C2H6_forward.pt +0 -0
  52. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/C2HD_single_v2/net_C2HD_forward.pt +0 -0
  53. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/C3H4_single_v2/net_C3H4_forward.pt +0 -0
  54. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/C4H2_single_v2/net_C4H2_forward.pt +0 -0
  55. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/C6H6_single_v2/net_C6H6_forward.pt +0 -0
  56. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/CH3_single_v2/net_CH3_forward.pt +0 -0
  57. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/CH4_single_v2/net_CH4_forward.pt +0 -0
  58. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/CO17O_single_v2/net_CO17O_forward.pt +0 -0
  59. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/CO18O_single_v2/net_CO18O_forward.pt +0 -0
  60. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/CO2_single_v2/net_CO2_forward.pt +0 -0
  61. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/H2O_wavelength_bank_v2_fixed/H2O_model_bank.json +0 -0
  62. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/H2O_wavelength_bank_v2_fixed/net_H2O_w13p5to19p2_n13to19_t100to1400.pt +0 -0
  63. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/H2O_wavelength_bank_v2_fixed/net_H2O_w19to25_n13to19_t100to1400.pt +0 -0
  64. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/H2O_wavelength_bank_v2_fixed/net_H2O_w4p9to7p4_n13to19_t100to1400.pt +0 -0
  65. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/H2O_wavelength_bank_v2_fixed/net_H2O_w7p2to11p2_n13to19_t100to1400.pt +0 -0
  66. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/H2O_wavelength_bank_v2_fixed/net_H2O_w9p9to15p1_n13to19_t100to1400.pt +0 -0
  67. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/HC3N_single_v2/net_HC3N_forward.pt +0 -0
  68. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma0/HCN_single_v2/net_HCN_forward.pt +0 -0
  69. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/13C12CH2_single_v2/net_13C12CH2_forward.pt +0 -0
  70. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/13CO2_single_v2/net_13CO2_forward.pt +0 -0
  71. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C2H2_wavelength_bank_v2/C2H2_model_bank.json +0 -0
  72. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C2H2_wavelength_bank_v2/net_C2H2_w11p5to17.pt +0 -0
  73. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C2H2_wavelength_bank_v2/net_C2H2_w6to9.pt +0 -0
  74. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C2H4_single_v2/net_C2H4_forward.pt +0 -0
  75. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C2H6_single_v2/net_C2H6_forward.pt +0 -0
  76. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C2HD_single_v2/net_C2HD_forward.pt +0 -0
  77. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C3H4_single_v2/net_C3H4_forward.pt +0 -0
  78. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C4H2_single_v2/net_C4H2_forward.pt +0 -0
  79. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/C6H6_single_v2/net_C6H6_forward.pt +0 -0
  80. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/CH3_single_v2/net_CH3_forward.pt +0 -0
  81. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/CH4_single_v2/net_CH4_forward.pt +0 -0
  82. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/CO17O_single_v2/net_CO17O_forward.pt +0 -0
  83. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/CO18O_single_v2/net_CO18O_forward.pt +0 -0
  84. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/CO2_single_v2/net_CO2_forward.pt +0 -0
  85. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/H2O_wavelength_bank_v2_fixed/H2O_model_bank.json +0 -0
  86. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/H2O_wavelength_bank_v2_fixed/net_H2O_w13p5to19p2_n13to19_t100to1400.pt +0 -0
  87. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/H2O_wavelength_bank_v2_fixed/net_H2O_w19to25_n13to19_t100to1400.pt +0 -0
  88. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/H2O_wavelength_bank_v2_fixed/net_H2O_w4p9to7p4_n13to19_t100to1400.pt +0 -0
  89. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/H2O_wavelength_bank_v2_fixed/net_H2O_w7p2to11p2_n13to19_t100to1400.pt +0 -0
  90. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/H2O_wavelength_bank_v2_fixed/net_H2O_w9p9to15p1_n13to19_t100to1400.pt +0 -0
  91. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/HC3N_single_v2/net_HC3N_forward.pt +0 -0
  92. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/HCN_single_v2/net_HCN_forward.pt +0 -0
  93. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/models/Trained_model/sigma2/OH_single_v2/net_OH_forward.pt +0 -0
  94. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/v2_paper_comparison.py +0 -0
  95. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts/v2_read_plot.py +0 -0
  96. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts.egg-info/dependency_links.txt +0 -0
  97. {diskmelts-2.2.0 → diskmelts-2.2.1}/src/diskmelts.egg-info/top_level.txt +0 -0
@@ -0,0 +1,2 @@
1
+ # Tests need the repository checkout (fixtures, Realobs_data); keep them out of the sdist.
2
+ prune tests
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diskmelts
3
- Version: 2.2.0
3
+ Version: 2.2.1
4
4
  Summary: Machine-learning Enabled Line fitting Tool for Spectra of protoplanetary disks
5
5
  Author: Chengyan Xie, Dingshan Deng
6
6
  License-Expression: MIT
@@ -12,15 +12,15 @@ Keywords: astronomy,protoplanetary disks,JWST,spectral fitting,machine learning
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Operating System :: OS Independent
14
14
  Classifier: Topic :: Scientific/Engineering :: Astronomy
15
- Requires-Python: >=3.9
15
+ Requires-Python: >=3.11
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: torch
18
+ Requires-Dist: torch>=1.13
19
19
  Requires-Dist: numpy<2,>=1.26; sys_platform == "darwin" and platform_machine == "x86_64"
20
20
  Requires-Dist: numpy; sys_platform != "darwin" or platform_machine != "x86_64"
21
21
  Requires-Dist: pandas
22
22
  Requires-Dist: scipy
23
- Requires-Dist: scikit-learn
23
+ Requires-Dist: scikit-learn<1.9,>=1.8
24
24
  Requires-Dist: matplotlib
25
25
  Provides-Extra: io
26
26
  Requires-Dist: astropy; extra == "io"
@@ -49,10 +49,11 @@ density (`logN`), and emitting area scaling (`A`) from observed spectra.
49
49
 
50
50
  ## Installation
51
51
 
52
- DiskMELTS is available on [PyPI](https://pypi.org/project/diskmelts/).
53
- Version 2.2.0 bundles 44 production checkpoints, including sigma=2 models for
54
- 18 species and CH3 in both sigma versions.
55
- With Python 3.9 or newer, install it from any directory. These commands use
52
+ DiskMELTS is available on [PyPI](https://pypi.org/project/diskmelts/) and
53
+ requires Python 3.11 or newer. It bundles 46 production checkpoints, 23 each
54
+ for the sigma=0 and sigma=2 grids, covering the same 18 species (see
55
+ [Available molecules](#available-molecules)).
56
+ Install it from any directory. These commands use
56
57
  `python` in an activated environment; the
57
58
  [installation guide](https://diskmelts.readthedocs.io/en/latest/installation.html)
58
59
  shows how to create one on macOS, Linux, Windows, or Conda:
@@ -87,6 +88,36 @@ conda activate diskmelts
87
88
  Use `environment-notebooks.yaml` or `environment-dev.yaml` for the corresponding
88
89
  notebook or contributor dependencies.
89
90
 
91
+ ## Minimal workflow
92
+
93
+ Subtract the continuum, fit one molecule, and print the result:
94
+
95
+ ```python
96
+ from diskmelts import consub, fit_stage, load_fitting_models
97
+
98
+ # 1. Raw spectrum: CSV with wave (µm), flux (Jy), and optional err columns.
99
+ raw_wave, raw_flux, raw_err = consub.read_spectrum("my_raw_spectrum.csv")
100
+ wave, flux, err, cont, cont_unshifted = consub.calculate(
101
+ raw_wave, raw_flux, raw_err, preset="ttauri",
102
+ )
103
+
104
+ # 2. Fit C2H2 near 13.7 µm with the bundled surrogate model.
105
+ models = load_fitting_models("C2H2")
106
+ fit = fit_stage(
107
+ wave, flux, molecule="C2H2", pretrained=models,
108
+ wavelength_range=(13.0, 15.0), fit_ranges=(13.5, 14.1),
109
+ distance_pc=140.0, n_samples=1024, n_refine=4, n_top=4,
110
+ )
111
+
112
+ # 3. Best-fit T (K), logN (cm^-2), A (au^2), and the spread of top solutions.
113
+ print(fit["params"]["C2H2"])
114
+ print(fit["uncertainty"]["C2H2"])
115
+ ```
116
+
117
+ The sections below explain each step, and the
118
+ [first-spectrum guide](https://diskmelts.readthedocs.io/en/latest/quickstart.html)
119
+ covers multi-stage fits, saved outputs, and plots.
120
+
90
121
  ## Runtime dependencies
91
122
 
92
123
  | Package | Purpose |
@@ -130,12 +161,6 @@ With `preset=None, linefreefile=None` (or `""`), fitting uses all nonexcluded
130
161
  pixels and skips the line-free correction, so `cont` equals `contOrig`.
131
162
  Reference tables are bundled; normal continuum subtraction needs no model grids.
132
163
 
133
- The private `0-Consub/` experiment directory is excluded from Git and is not
134
- required by the installed package. Its runtime code and reference tables are
135
- maintained under `src/diskmelts/consub/`.
136
- The distributed tests in `tests/` exercise the installed continuum API and
137
- bundled references without that private directory.
138
-
139
164
  Returned `err` represents measurement/noise error, not correlated continuum
140
165
  uncertainty. Broad excluded intervals require inspection. See the
141
166
  [continuum guide](https://diskmelts.readthedocs.io/en/latest/continuum.html) for presets, regional box sizes,
@@ -182,31 +207,35 @@ You can also read spectra with your own code. DiskMELTS only requires
182
207
  one-dimensional `obs_wav` and `obs_flux` arrays. Replace the sample CSV with
183
208
  your own file to fit your source; update `distance_pc` and fit intervals.
184
209
 
185
- For a complete staged fit-and-subtract workflow from a checkout, edit and run:
210
+ For a complete staged fit-and-subtract workflow from a clone of the
211
+ repository, run:
186
212
 
187
213
  ```bash
188
214
  python examples/dev_v2_realobs.py
215
+ python examples/dev_v2_realobs.py --input /path/to/my_spectrum.csv --name my_source --distance-pc 140 --sigma 2
189
216
  ```
190
217
 
218
+ Adjust that script's stage windows for your spectrum.
219
+ `python examples/synthetic_array_fit.py` generates an HCN spectrum and fits it
220
+ from in-memory arrays, without an observation file.
221
+
191
222
  The v2 fitting API is `load_fitting_models`, `fit_stage`, `fit_observation`, and
192
- `plot_saved_observation`. The production checkpoints are packaged under
193
- `src/diskmelts/models/` and included in the wheel. Model fitting requires no
194
- `Model_grids/` or `Pretrain_grid/` directory. `diskmelts.MODEL_SPECS` records
195
- PCA counts, network layers, and `grid_sigma=0` for the original checkpoints.
196
- In version 2.2.0, sigma=2 checkpoints are available for H2O,
197
- C2H2, HCN, CO2, 13C12CH2, 13CO2, C4H2, HC3N, C2H6, C2H4, CH4,
198
- C2HD, CO17O, CO18O, C3H4, CH3, C6H6, and OH. Select them with
199
- `load_fitting_models(['H2O', 'C2H2'], sigma=2)` or
200
- `fit_observation(..., sigma=2)`. The C2H2 bank covers 6–9 and 11.5–17 µm;
201
- choose fit windows within those bands. OH covers 15–26 µm. Both C6H6
202
- checkpoints cover 13–17 µm and 100–675 K; the sigma=2 checkpoint is selected
203
- with `load_fitting_models('C6H6', sigma=2)`.
204
- The checkpoint settings are checked when
205
- loading. The checkpoint flux convention is 1 au² at 140 pc; `distance_pc`
206
- sets the source distance and makes the returned emitting area physical.
207
- The [fitting notebook](https://github.com/wddlx/DiskMELTS/blob/main/notebooks/Example_Fitting.ipynb) requires 13C12CH2 to
208
- be no hotter than C2H2 and gives them the same emitting area. It ties 13CO2
209
- to CO2 in both temperature and area. Set
223
+ `plot_saved_observation`. The production checkpoints are included in the
224
+ wheel, so model fitting needs no local model grids. The checkpoint flux
225
+ convention is 1 au² at 140 pc; `distance_pc` sets the source distance and
226
+ makes the returned emitting area physical. `fit_observation` accepts either a
227
+ CSV path or in-memory `obs_wav`, `obs_flux`, and optional `obs_err` arrays
228
+ (new in 2.2.1).
229
+
230
+ For a synthetic spectrum, `wave, flux = diskmelts.synthesize_spectrum('HCN',
231
+ T=300, logN=18, A=1)` returns the native wavelength axis and model flux (new
232
+ in 2.2.1). See the
233
+ [generation guide](https://diskmelts.readthedocs.io/en/latest/generate_spectra.html).
234
+
235
+ The [fitting notebook](https://github.com/wddlx/DiskMELTS/blob/main/notebooks/Example_Fitting.ipynb)
236
+ requires 13C12CH2 to be no hotter than C2H2 and gives them the same emitting
237
+ area; it ties 13CO2 to CO2 in both temperature and area. Point its input at
238
+ your own continuum-subtracted CSV, or pass arrays. Set
210
239
  `isotopologue_groups`, `Tshare` (`free`, `equal`, or `less`), and `Ashare` in a
211
240
  joint stage to choose those constraints. See the
212
241
  [fitting guide](https://diskmelts.readthedocs.io/en/latest/quickstart.html) for examples.
@@ -218,6 +247,32 @@ separate method does require the full local grids. See the
218
247
  plotting.
219
248
  For complete sigma=2 grids, pass `grid_root='Model_grids/sigma2'`.
220
249
 
250
+ ## Available molecules
251
+
252
+ Each molecule is available for two slab-model grids: sigma=0 (default) assumes
253
+ no turbulent broadening, so lines are only thermally broadened, and sigma=2
254
+ assumes 2 km/s turbulent broadening. Select sigma=2 with `load_fitting_models(..., sigma=2)` or
255
+ `fit_observation(..., sigma=2)`. Fit windows must lie inside a model's band.
256
+
257
+ | Molecule | Band (µm) | T (K) | logN (cm⁻²) |
258
+ |---|---|---|---|
259
+ | H2O | 4.9–25.0 (five overlapping tiles) | 100–1400 | 13–19 |
260
+ | C2H2 | 6–9 and 11.5–17 | 100–1400 | 13–19.5 |
261
+ | HCN, CO2, 13C12CH2, 13CO2 | 11.5–17 | 100–1400 | 13–19.5 |
262
+ | HC3N, CO17O, CO18O | 13–18 | 100–1400 | 13–19.5 |
263
+ | C4H2 | 14–18 | 100–1400 | 13–19.5 |
264
+ | C3H4, CH3 | 15–18 | 100–1400 | 13–19.5 |
265
+ | C6H6 | 13–17 | 100–675 | 13–19.5 |
266
+ | C2H6 | 9–15 | 100–1400 | 13–19.5 |
267
+ | C2H4 | 8–14 | 100–1400 | 13–19.5 |
268
+ | CH4 | 5–9 | 100–1400 | 13–19.5 |
269
+ | C2HD | 11.5–20.5 | 100–1400 | 13–19.5 |
270
+ | OH | 15–26 | 100–1400 | 13–19.5 |
271
+
272
+ `diskmelts.MODEL_SPECS` records the exact domains, PCA sizes, and network
273
+ layers. Version 2.2.0 lacks the sigma=0 OH and 6–9 µm C2H2 checkpoints;
274
+ upgrade with `python -m pip install -U diskmelts`.
275
+
221
276
  ## Training and validation data
222
277
 
223
278
  Generated data under `Model_grids/` and `Pretrain_grid/` are intentionally
@@ -250,7 +305,7 @@ uses the same names with local `Model_grids/sigma0/C6H6/` and `Model_grids/sigma
250
305
  files. See the [training guide](https://diskmelts.readthedocs.io/en/latest/training.html)
251
306
  for peak audits and retraining commands.
252
307
 
253
- Version 2.2.0 also includes a CH3 checkpoint for 15–18 µm,
308
+ The package also includes a CH3 checkpoint for 15–18 µm,
254
309
  `T=100–1400 K`, and `logN=13–19.5`. Its strongest grid feature in this window
255
310
  is near 16.4–16.6 µm. Use `load_fitting_models('CH3')` after installing this
256
311
  package; direct-grid fitting uses local `Model_grids/sigma0/CH3/` files.
@@ -10,10 +10,11 @@ density (`logN`), and emitting area scaling (`A`) from observed spectra.
10
10
 
11
11
  ## Installation
12
12
 
13
- DiskMELTS is available on [PyPI](https://pypi.org/project/diskmelts/).
14
- Version 2.2.0 bundles 44 production checkpoints, including sigma=2 models for
15
- 18 species and CH3 in both sigma versions.
16
- With Python 3.9 or newer, install it from any directory. These commands use
13
+ DiskMELTS is available on [PyPI](https://pypi.org/project/diskmelts/) and
14
+ requires Python 3.11 or newer. It bundles 46 production checkpoints, 23 each
15
+ for the sigma=0 and sigma=2 grids, covering the same 18 species (see
16
+ [Available molecules](#available-molecules)).
17
+ Install it from any directory. These commands use
17
18
  `python` in an activated environment; the
18
19
  [installation guide](https://diskmelts.readthedocs.io/en/latest/installation.html)
19
20
  shows how to create one on macOS, Linux, Windows, or Conda:
@@ -48,6 +49,36 @@ conda activate diskmelts
48
49
  Use `environment-notebooks.yaml` or `environment-dev.yaml` for the corresponding
49
50
  notebook or contributor dependencies.
50
51
 
52
+ ## Minimal workflow
53
+
54
+ Subtract the continuum, fit one molecule, and print the result:
55
+
56
+ ```python
57
+ from diskmelts import consub, fit_stage, load_fitting_models
58
+
59
+ # 1. Raw spectrum: CSV with wave (µm), flux (Jy), and optional err columns.
60
+ raw_wave, raw_flux, raw_err = consub.read_spectrum("my_raw_spectrum.csv")
61
+ wave, flux, err, cont, cont_unshifted = consub.calculate(
62
+ raw_wave, raw_flux, raw_err, preset="ttauri",
63
+ )
64
+
65
+ # 2. Fit C2H2 near 13.7 µm with the bundled surrogate model.
66
+ models = load_fitting_models("C2H2")
67
+ fit = fit_stage(
68
+ wave, flux, molecule="C2H2", pretrained=models,
69
+ wavelength_range=(13.0, 15.0), fit_ranges=(13.5, 14.1),
70
+ distance_pc=140.0, n_samples=1024, n_refine=4, n_top=4,
71
+ )
72
+
73
+ # 3. Best-fit T (K), logN (cm^-2), A (au^2), and the spread of top solutions.
74
+ print(fit["params"]["C2H2"])
75
+ print(fit["uncertainty"]["C2H2"])
76
+ ```
77
+
78
+ The sections below explain each step, and the
79
+ [first-spectrum guide](https://diskmelts.readthedocs.io/en/latest/quickstart.html)
80
+ covers multi-stage fits, saved outputs, and plots.
81
+
51
82
  ## Runtime dependencies
52
83
 
53
84
  | Package | Purpose |
@@ -91,12 +122,6 @@ With `preset=None, linefreefile=None` (or `""`), fitting uses all nonexcluded
91
122
  pixels and skips the line-free correction, so `cont` equals `contOrig`.
92
123
  Reference tables are bundled; normal continuum subtraction needs no model grids.
93
124
 
94
- The private `0-Consub/` experiment directory is excluded from Git and is not
95
- required by the installed package. Its runtime code and reference tables are
96
- maintained under `src/diskmelts/consub/`.
97
- The distributed tests in `tests/` exercise the installed continuum API and
98
- bundled references without that private directory.
99
-
100
125
  Returned `err` represents measurement/noise error, not correlated continuum
101
126
  uncertainty. Broad excluded intervals require inspection. See the
102
127
  [continuum guide](https://diskmelts.readthedocs.io/en/latest/continuum.html) for presets, regional box sizes,
@@ -143,31 +168,35 @@ You can also read spectra with your own code. DiskMELTS only requires
143
168
  one-dimensional `obs_wav` and `obs_flux` arrays. Replace the sample CSV with
144
169
  your own file to fit your source; update `distance_pc` and fit intervals.
145
170
 
146
- For a complete staged fit-and-subtract workflow from a checkout, edit and run:
171
+ For a complete staged fit-and-subtract workflow from a clone of the
172
+ repository, run:
147
173
 
148
174
  ```bash
149
175
  python examples/dev_v2_realobs.py
176
+ python examples/dev_v2_realobs.py --input /path/to/my_spectrum.csv --name my_source --distance-pc 140 --sigma 2
150
177
  ```
151
178
 
179
+ Adjust that script's stage windows for your spectrum.
180
+ `python examples/synthetic_array_fit.py` generates an HCN spectrum and fits it
181
+ from in-memory arrays, without an observation file.
182
+
152
183
  The v2 fitting API is `load_fitting_models`, `fit_stage`, `fit_observation`, and
153
- `plot_saved_observation`. The production checkpoints are packaged under
154
- `src/diskmelts/models/` and included in the wheel. Model fitting requires no
155
- `Model_grids/` or `Pretrain_grid/` directory. `diskmelts.MODEL_SPECS` records
156
- PCA counts, network layers, and `grid_sigma=0` for the original checkpoints.
157
- In version 2.2.0, sigma=2 checkpoints are available for H2O,
158
- C2H2, HCN, CO2, 13C12CH2, 13CO2, C4H2, HC3N, C2H6, C2H4, CH4,
159
- C2HD, CO17O, CO18O, C3H4, CH3, C6H6, and OH. Select them with
160
- `load_fitting_models(['H2O', 'C2H2'], sigma=2)` or
161
- `fit_observation(..., sigma=2)`. The C2H2 bank covers 6–9 and 11.5–17 µm;
162
- choose fit windows within those bands. OH covers 15–26 µm. Both C6H6
163
- checkpoints cover 13–17 µm and 100–675 K; the sigma=2 checkpoint is selected
164
- with `load_fitting_models('C6H6', sigma=2)`.
165
- The checkpoint settings are checked when
166
- loading. The checkpoint flux convention is 1 au² at 140 pc; `distance_pc`
167
- sets the source distance and makes the returned emitting area physical.
168
- The [fitting notebook](https://github.com/wddlx/DiskMELTS/blob/main/notebooks/Example_Fitting.ipynb) requires 13C12CH2 to
169
- be no hotter than C2H2 and gives them the same emitting area. It ties 13CO2
170
- to CO2 in both temperature and area. Set
184
+ `plot_saved_observation`. The production checkpoints are included in the
185
+ wheel, so model fitting needs no local model grids. The checkpoint flux
186
+ convention is 1 au² at 140 pc; `distance_pc` sets the source distance and
187
+ makes the returned emitting area physical. `fit_observation` accepts either a
188
+ CSV path or in-memory `obs_wav`, `obs_flux`, and optional `obs_err` arrays
189
+ (new in 2.2.1).
190
+
191
+ For a synthetic spectrum, `wave, flux = diskmelts.synthesize_spectrum('HCN',
192
+ T=300, logN=18, A=1)` returns the native wavelength axis and model flux (new
193
+ in 2.2.1). See the
194
+ [generation guide](https://diskmelts.readthedocs.io/en/latest/generate_spectra.html).
195
+
196
+ The [fitting notebook](https://github.com/wddlx/DiskMELTS/blob/main/notebooks/Example_Fitting.ipynb)
197
+ requires 13C12CH2 to be no hotter than C2H2 and gives them the same emitting
198
+ area; it ties 13CO2 to CO2 in both temperature and area. Point its input at
199
+ your own continuum-subtracted CSV, or pass arrays. Set
171
200
  `isotopologue_groups`, `Tshare` (`free`, `equal`, or `less`), and `Ashare` in a
172
201
  joint stage to choose those constraints. See the
173
202
  [fitting guide](https://diskmelts.readthedocs.io/en/latest/quickstart.html) for examples.
@@ -179,6 +208,32 @@ separate method does require the full local grids. See the
179
208
  plotting.
180
209
  For complete sigma=2 grids, pass `grid_root='Model_grids/sigma2'`.
181
210
 
211
+ ## Available molecules
212
+
213
+ Each molecule is available for two slab-model grids: sigma=0 (default) assumes
214
+ no turbulent broadening, so lines are only thermally broadened, and sigma=2
215
+ assumes 2 km/s turbulent broadening. Select sigma=2 with `load_fitting_models(..., sigma=2)` or
216
+ `fit_observation(..., sigma=2)`. Fit windows must lie inside a model's band.
217
+
218
+ | Molecule | Band (µm) | T (K) | logN (cm⁻²) |
219
+ |---|---|---|---|
220
+ | H2O | 4.9–25.0 (five overlapping tiles) | 100–1400 | 13–19 |
221
+ | C2H2 | 6–9 and 11.5–17 | 100–1400 | 13–19.5 |
222
+ | HCN, CO2, 13C12CH2, 13CO2 | 11.5–17 | 100–1400 | 13–19.5 |
223
+ | HC3N, CO17O, CO18O | 13–18 | 100–1400 | 13–19.5 |
224
+ | C4H2 | 14–18 | 100–1400 | 13–19.5 |
225
+ | C3H4, CH3 | 15–18 | 100–1400 | 13–19.5 |
226
+ | C6H6 | 13–17 | 100–675 | 13–19.5 |
227
+ | C2H6 | 9–15 | 100–1400 | 13–19.5 |
228
+ | C2H4 | 8–14 | 100–1400 | 13–19.5 |
229
+ | CH4 | 5–9 | 100–1400 | 13–19.5 |
230
+ | C2HD | 11.5–20.5 | 100–1400 | 13–19.5 |
231
+ | OH | 15–26 | 100–1400 | 13–19.5 |
232
+
233
+ `diskmelts.MODEL_SPECS` records the exact domains, PCA sizes, and network
234
+ layers. Version 2.2.0 lacks the sigma=0 OH and 6–9 µm C2H2 checkpoints;
235
+ upgrade with `python -m pip install -U diskmelts`.
236
+
182
237
  ## Training and validation data
183
238
 
184
239
  Generated data under `Model_grids/` and `Pretrain_grid/` are intentionally
@@ -211,7 +266,7 @@ uses the same names with local `Model_grids/sigma0/C6H6/` and `Model_grids/sigma
211
266
  files. See the [training guide](https://diskmelts.readthedocs.io/en/latest/training.html)
212
267
  for peak audits and retraining commands.
213
268
 
214
- Version 2.2.0 also includes a CH3 checkpoint for 15–18 µm,
269
+ The package also includes a CH3 checkpoint for 15–18 µm,
215
270
  `T=100–1400 K`, and `logN=13–19.5`. Its strongest grid feature in this window
216
271
  is near 16.4–16.6 µm. Use `load_fitting_models('CH3')` after installing this
217
272
  package; direct-grid fitting uses local `Model_grids/sigma0/CH3/` files.
@@ -4,10 +4,10 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "diskmelts"
7
- version = "2.2.0"
7
+ version = "2.2.1"
8
8
  description = "Machine-learning Enabled Line fitting Tool for Spectra of protoplanetary disks"
9
9
  readme = "README.md"
10
- requires-python = ">=3.9"
10
+ requires-python = ">=3.11"
11
11
  license = "MIT"
12
12
  license-files = ["LICENSE"]
13
13
  authors = [
@@ -21,13 +21,16 @@ classifiers = [
21
21
  "Topic :: Scientific/Engineering :: Astronomy",
22
22
  ]
23
23
  dependencies = [
24
- "torch",
24
+ # Checkpoints load with torch.load(weights_only=False), added in 1.13.
25
+ "torch>=1.13",
25
26
  # Intel macOS wheels stop at PyTorch 2.2, whose NumPy bridge needs NumPy 1.x.
26
27
  "numpy>=1.26,<2; sys_platform == 'darwin' and platform_machine == 'x86_64'",
27
28
  "numpy; sys_platform != 'darwin' or platform_machine != 'x86_64'",
28
29
  "pandas",
29
30
  "scipy",
30
- "scikit-learn",
31
+ # Bundled checkpoints pickle scikit-learn 1.8 PCA/scaler objects; keep the
32
+ # same minor version so they unpickle without a cross-version warning.
33
+ "scikit-learn>=1.8,<1.9",
31
34
  "matplotlib",
32
35
  ]
33
36
 
@@ -41,6 +41,7 @@ from diskmelts.v2_fitting import (
41
41
  MODEL_SPECS,
42
42
  SIGMA2_MODEL_SPECS,
43
43
  load_fitting_models,
44
+ synthesize_spectrum,
44
45
  fit_stage,
45
46
  fit_observation,
46
47
  )
@@ -61,6 +62,7 @@ __all__ = [
61
62
  "MODEL_SPECS",
62
63
  "SIGMA2_MODEL_SPECS",
63
64
  "load_fitting_models",
65
+ "synthesize_spectrum",
64
66
  "fit_stage",
65
67
  "fit_observation",
66
68
  "fit_grid_stage",
@@ -41,6 +41,8 @@ def _regions(regions):
41
41
  a = np.asarray(regions, dtype=float)
42
42
  if a.size == 0:
43
43
  return np.empty((0, 2))
44
+ if a.shape == (2,):
45
+ a = a[np.newaxis]
44
46
  if a.ndim != 2 or a.shape[1] != 2 or not np.all(np.isfinite(a)) or np.any(a[:, 1] <= a[:, 0]):
45
47
  raise ValueError("Regions must be finite (xmin, xmax) pairs with xmin < xmax")
46
48
  return a
@@ -128,11 +130,21 @@ def _mad(a):
128
130
  return 1.4826 * np.median(np.abs(a - np.median(a)))
129
131
 
130
132
 
131
- def _interp(x, xp, yp):
133
+ def _interp(x, xp, yp, linear_ends=False):
132
134
  if len(xp) == 1:
133
135
  return np.full(len(x), yp[0])
134
136
  # Constant end corrections avoid unstable polynomial extrapolation.
135
- return PchipInterpolator(xp, yp)(np.clip(x, xp[0], xp[-1]))
137
+ out = PchipInterpolator(xp, yp)(np.clip(x, xp[0], xp[-1]))
138
+ if linear_ends:
139
+ # A sloped continuum beyond the last knot needs a slope, not a constant;
140
+ # fit it over about 1 um of knots so one noisy knot cannot set it.
141
+ xp, yp = np.asarray(xp), np.asarray(yp)
142
+ for outside, end, near in ((x < xp[0], 0, xp <= xp[0] + 1.0),
143
+ (x > xp[-1], -1, xp >= xp[-1] - 1.0)):
144
+ if outside.any() and near.sum() >= 2:
145
+ slope = np.polyfit(xp[near], yp[near], 1)[0]
146
+ out[outside] = yp[end] + slope * (x[outside] - xp[end])
147
+ return out
136
148
 
137
149
 
138
150
  def _widths(x, good, boxsizes):
@@ -143,7 +155,7 @@ def _widths(x, good, boxsizes):
143
155
  n = np.convolve(good.astype(float), np.ones(min(101, len(x))), "same")
144
156
  fraction = np.maximum(n / min(101, len(x)), 0.05)
145
157
  return np.clip(31 * dx / fraction, 0.25, 1.0)
146
- if np.isscalar(boxsizes):
158
+ if np.ndim(boxsizes) == 0:
147
159
  if not np.isfinite(boxsizes) or boxsizes < 5:
148
160
  raise ValueError("boxsizes must be at least 5 pixels")
149
161
  return dx * float(boxsizes)
@@ -188,7 +200,7 @@ def _local_baseline(x, y, noise, good, widths):
188
200
  if len(positions) < 3:
189
201
  raise ValueError("Too few continuum windows; widen boxsizes or revise masks")
190
202
  knots = pd.DataFrame({"x": positions, "y": values}).groupby("x", sort=True).median()
191
- return _interp(x, knots.index.to_numpy(), knots.y.to_numpy())
203
+ return _interp(x, knots.index.to_numpy(), knots.y.to_numpy(), linear_ends=True)
192
204
 
193
205
 
194
206
  def _arpls(x, y, noise, good, widths):
@@ -203,10 +215,12 @@ def _arpls(x, y, noise, good, widths):
203
215
  weights = base.copy()
204
216
  converged = False
205
217
  for _ in range(40):
206
- z = spsolve(diags(weights) + penalty, weights*y)
218
+ z = spsolve((diags(weights) + penalty).tocsc(), weights*y)
207
219
  residual = y-z
208
220
  negative = residual[good & (residual < 0)]
209
221
  if len(negative) < 3:
222
+ # Nothing left below the baseline to down-weight: a fixed point.
223
+ converged = True
210
224
  break
211
225
  scale = max(np.std(negative), np.median(noise[good])*0.1)
212
226
  new = base * expit(-2*(residual - (2*scale-np.mean(negative)))/scale)
@@ -354,8 +368,11 @@ def subtract_continuum(wav, flux, *, error=None, exclude=None, boxsizes=None,
354
368
  unsupported |= (x < x[reference][0]) | (x > x[reference][-1])
355
369
  cont_error[unsupported] = np.nan
356
370
  if unsupported.any():
357
- warnings.warn("Continuum crosses regions with weak support; inspect the plot or "
358
- "subtract_continuum() diagnostics before using those regions", stacklevel=2)
371
+ edges = np.flatnonzero(np.diff(np.r_[0, unsupported.astype(int), 0]))
372
+ spans = ", ".join(f"{x[a]:.2f}-{x[b-1]:.2f}" for a, b in zip(edges[::2], edges[1::2]))
373
+ warnings.warn(f"Continuum is interpolated or extrapolated without nearby reference "
374
+ f"pixels at {spans} um (weak_support column); inspect the plot before "
375
+ "using those regions", stacklevel=2)
359
376
  result = pd.DataFrame({"wave": x, "flux": original-continuum,
360
377
  "err": measurement, "cont": continuum,
361
378
  "cont_unshifted": baseline, "raw_flux": original,