solarc-eclipse 0.5.0__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {solarc_eclipse-0.5.0/solarc_eclipse.egg-info → solarc_eclipse-0.6.0}/PKG-INFO +58 -18
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/README.md +57 -17
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/__init__.py +1 -1
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/analysis.py +3 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/data_processing.py +12 -7
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/main.py +45 -1
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/radiometric.py +7 -3
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/synthesis.py +578 -133
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0/solarc_eclipse.egg-info}/PKG-INFO +58 -18
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/LICENSE +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/MANIFEST.in +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/cli.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/config.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/data/throughput/grating_reflection_efficiency.dat +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/data/throughput/primary_mirror_coating_reflectance.dat +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/data/throughput/source.txt +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/data/throughput/throughput_aluminium_1000_angstrom.dat +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/data/throughput/throughput_aluminium_oxide_1000_angstrom.dat +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/data/throughput/throughput_carbon_1000_angstrom.dat +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/fitting.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/monte_carlo.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/pinhole_diffraction.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/psf.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/synthesis_cli.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/euvst_response/utils.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/pyproject.toml +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/setup.cfg +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/setup.py +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/solarc_eclipse.egg-info/SOURCES.txt +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/solarc_eclipse.egg-info/dependency_links.txt +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/solarc_eclipse.egg-info/entry_points.txt +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/solarc_eclipse.egg-info/not-zip-safe +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/solarc_eclipse.egg-info/requires.txt +0 -0
- {solarc_eclipse-0.5.0 → solarc_eclipse-0.6.0}/solarc_eclipse.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: solarc-eclipse
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: ECLIPSE: Emission Calculation and Line Intensity Prediction for SOLAR-C EUVST
|
|
5
5
|
Home-page: https://github.com/jamesmckevitt/eclipse
|
|
6
6
|
Author: James McKevitt
|
|
@@ -49,6 +49,8 @@ Contact: James McKevitt (jm2@mssl.ucl.ac.uk). License: Contact for permission to
|
|
|
49
49
|
|
|
50
50
|
The instrument response generated by this code will be updated during instrument development, testing, and commissioning.
|
|
51
51
|
|
|
52
|
+
[](https://doi.org/10.5281/zenodo.17543844)
|
|
53
|
+
|
|
52
54
|
## Installation
|
|
53
55
|
|
|
54
56
|
### From PyPI (recommended)
|
|
@@ -158,15 +160,15 @@ synthesise-spectra \
|
|
|
158
160
|
--vy-file vy/result_prim_3.0270000 \
|
|
159
161
|
--vz-file vz/result_prim_2.0270000 \
|
|
160
162
|
--cube-shape 512 768 256 \
|
|
161
|
-
--voxel-dx 0.192 \
|
|
162
|
-
--voxel-dy 0.192 \
|
|
163
|
-
--voxel-dz 0.064 \
|
|
164
|
-
--vel-res 5.0 \
|
|
165
|
-
--vel-lim 300.0 \
|
|
163
|
+
--voxel-dx "0.192 Mm" \
|
|
164
|
+
--voxel-dy "0.192 Mm" \
|
|
165
|
+
--voxel-dz "0.064 Mm" \
|
|
166
|
+
--vel-res "5.0 km/s" \
|
|
167
|
+
--vel-lim "300.0 km/s" \
|
|
166
168
|
--integration-axis z \
|
|
167
|
-
--crop-x -50 50 \
|
|
168
|
-
--crop-y -50 50 \
|
|
169
|
-
--crop-z 0 20 \
|
|
169
|
+
--crop-x "-50 Mm" "50 Mm" \
|
|
170
|
+
--crop-y "-50 Mm" "50 Mm" \
|
|
171
|
+
--crop-z "0 Mm" "20 Mm" \
|
|
170
172
|
--downsample 1 \
|
|
171
173
|
--precision float64 \
|
|
172
174
|
--mean-mol-wt 1.29 \
|
|
@@ -193,11 +195,11 @@ synthesise-spectra --help
|
|
|
193
195
|
|
|
194
196
|
**Grid Parameters:**
|
|
195
197
|
- `--cube-shape`: Cube dimensions as three integers (default: `512 768 256`)
|
|
196
|
-
- `--voxel-dx`, `--voxel-dy`, `--voxel-dz`: Voxel sizes
|
|
198
|
+
- `--voxel-dx`, `--voxel-dy`, `--voxel-dz`: Voxel sizes with units (default: `"0.192 Mm"`, `"0.192 Mm"`, `"0.064 Mm"`)
|
|
197
199
|
|
|
198
200
|
**Velocity Grid:**
|
|
199
|
-
- `--vel-res`: Velocity resolution
|
|
200
|
-
- `--vel-lim`: Velocity limit
|
|
201
|
+
- `--vel-res`: Velocity resolution with units (default: `"5.0 km/s"`)
|
|
202
|
+
- `--vel-lim`: Velocity limit +-km/s with units (default: `"300.0 km/s"`)
|
|
201
203
|
|
|
202
204
|
**Integration and Viewing:**
|
|
203
205
|
- `--integration-axis`: Integration axis: `x`, `y`, or `z` (default: `z`)
|
|
@@ -205,10 +207,10 @@ synthesise-spectra --help
|
|
|
205
207
|
- `x`: Side view from the left (integrates left-to-right)
|
|
206
208
|
- `y`: Side view from the front (integrates front-to-back)
|
|
207
209
|
|
|
208
|
-
**Spatial Cropping (Heliocentric coordinates
|
|
209
|
-
- `--crop-x`: X-range to crop, e.g., `--crop-x -50 50` (optional)
|
|
210
|
-
- `--crop-y`: Y-range to crop, e.g., `--crop-y -50 50` (optional)
|
|
211
|
-
- `--crop-z`: Z-range to crop, e.g., `--crop-z 0 20` (optional)
|
|
210
|
+
**Spatial Cropping (Heliocentric coordinates with units):**
|
|
211
|
+
- `--crop-x`: X-range to crop with units, e.g., `--crop-x "-50 Mm" "50 Mm"` (optional)
|
|
212
|
+
- `--crop-y`: Y-range to crop with units, e.g., `--crop-y "-50 Mm" "50 Mm"` (optional)
|
|
213
|
+
- `--crop-z`: Z-range to crop with units, e.g., `--crop-z "0 Mm" "20 Mm"` (optional)
|
|
212
214
|
- Omit any crop option to use the full range in that dimension
|
|
213
215
|
|
|
214
216
|
**Processing Options:**
|
|
@@ -219,6 +221,40 @@ synthesise-spectra --help
|
|
|
219
221
|
**Line Selection:**
|
|
220
222
|
- `--limit-lines`: Limit to specific lines, e.g., `--limit-lines Fe12_195.1190 Fe12_195.1790`
|
|
221
223
|
|
|
224
|
+
#### Dynamic Mode (Time-varying Atmospheres)
|
|
225
|
+
|
|
226
|
+
For simulating raster scans over evolving atmospheres, use dynamic mode which combines MHD timesteps based on instrument scanning:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
synthesise-spectra \
|
|
230
|
+
--data-dir ./data/atmosphere \
|
|
231
|
+
--goft-file ./data/gofnt.sav \
|
|
232
|
+
--output-dir ./run/input \
|
|
233
|
+
--slit-rest-time "40 s" \
|
|
234
|
+
--slit-width "0.2 arcsec" \
|
|
235
|
+
--temp-dir temp \
|
|
236
|
+
--temp-filename eosT \
|
|
237
|
+
--rho-dir rho \
|
|
238
|
+
--rho-filename result_prim_0 \
|
|
239
|
+
--vz-dir vz \
|
|
240
|
+
--vz-filename result_prim_2 \
|
|
241
|
+
--time-dir time \
|
|
242
|
+
--time-filename tau_slice_0.100 \
|
|
243
|
+
--cube-shape 512 768 256 \
|
|
244
|
+
--voxel-dx "0.192 Mm" \
|
|
245
|
+
--voxel-dy "0.192 Mm" \
|
|
246
|
+
--voxel-dz "0.064 Mm" \
|
|
247
|
+
--vel-res "5.0 km/s" \
|
|
248
|
+
--vel-lim "300.0 km/s" \
|
|
249
|
+
--integration-axis z
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Dynamic Mode Options:**
|
|
253
|
+
- `--slit-rest-time`: Slit rest time per position - enables dynamic mode
|
|
254
|
+
- `--slit-width`: Slit width
|
|
255
|
+
- `--temp-dir`, `--rho-dir`, `--vx-dir`, `--vy-dir`, `--vz-dir`, `--time-dir`: Directories containing timestep files
|
|
256
|
+
- `--temp-filename`, `--rho-filename`, `--vx-filename`, `--vy-filename`, `--vz-filename`, `--time-filename`: Filename prefix before timestep suffix
|
|
257
|
+
|
|
222
258
|
#### Output
|
|
223
259
|
|
|
224
260
|
The synthesis produces a pickle file containing:
|
|
@@ -230,7 +266,7 @@ The synthesis produces a pickle file containing:
|
|
|
230
266
|
|
|
231
267
|
- Use `--downsample 2` or `--downsample 4` for initial testing
|
|
232
268
|
- Use `--precision float32` to reduce memory usage (may affect accuracy)
|
|
233
|
-
- Use `--limit-lines` to
|
|
269
|
+
- Use `--limit-lines` to synthesise only specific lines for development
|
|
234
270
|
- Use spatial cropping to focus on regions of interest and reduce computation time
|
|
235
271
|
- Monitor memory usage - full resolution synthesis can require 50+ GB RAM
|
|
236
272
|
- Side views (`--integration-axis x` or `y`) may require different velocity files
|
|
@@ -328,7 +364,11 @@ ccd_temperature: -60 Celsius # Default (expected operating temperature)
|
|
|
328
364
|
vis_sl: 0 photon / (s * pixel) # Default, (ideal case, no stray light)
|
|
329
365
|
```
|
|
330
366
|
|
|
331
|
-
For
|
|
367
|
+
For guidance on recommended values, see McKevitt et al. (2025) (in prep.).
|
|
368
|
+
|
|
369
|
+
If you synthesised data in dynamic mode, your configuration must specify:
|
|
370
|
+
- Exactly one slit width matching the synthesis slit width
|
|
371
|
+
- Exactly one exposure time matching the synthesis exposure time
|
|
332
372
|
|
|
333
373
|
#### Running Simulations
|
|
334
374
|
|
|
@@ -6,6 +6,8 @@ Contact: James McKevitt (jm2@mssl.ucl.ac.uk). License: Contact for permission to
|
|
|
6
6
|
|
|
7
7
|
The instrument response generated by this code will be updated during instrument development, testing, and commissioning.
|
|
8
8
|
|
|
9
|
+
[](https://doi.org/10.5281/zenodo.17543844)
|
|
10
|
+
|
|
9
11
|
## Installation
|
|
10
12
|
|
|
11
13
|
### From PyPI (recommended)
|
|
@@ -115,15 +117,15 @@ synthesise-spectra \
|
|
|
115
117
|
--vy-file vy/result_prim_3.0270000 \
|
|
116
118
|
--vz-file vz/result_prim_2.0270000 \
|
|
117
119
|
--cube-shape 512 768 256 \
|
|
118
|
-
--voxel-dx 0.192 \
|
|
119
|
-
--voxel-dy 0.192 \
|
|
120
|
-
--voxel-dz 0.064 \
|
|
121
|
-
--vel-res 5.0 \
|
|
122
|
-
--vel-lim 300.0 \
|
|
120
|
+
--voxel-dx "0.192 Mm" \
|
|
121
|
+
--voxel-dy "0.192 Mm" \
|
|
122
|
+
--voxel-dz "0.064 Mm" \
|
|
123
|
+
--vel-res "5.0 km/s" \
|
|
124
|
+
--vel-lim "300.0 km/s" \
|
|
123
125
|
--integration-axis z \
|
|
124
|
-
--crop-x -50 50 \
|
|
125
|
-
--crop-y -50 50 \
|
|
126
|
-
--crop-z 0 20 \
|
|
126
|
+
--crop-x "-50 Mm" "50 Mm" \
|
|
127
|
+
--crop-y "-50 Mm" "50 Mm" \
|
|
128
|
+
--crop-z "0 Mm" "20 Mm" \
|
|
127
129
|
--downsample 1 \
|
|
128
130
|
--precision float64 \
|
|
129
131
|
--mean-mol-wt 1.29 \
|
|
@@ -150,11 +152,11 @@ synthesise-spectra --help
|
|
|
150
152
|
|
|
151
153
|
**Grid Parameters:**
|
|
152
154
|
- `--cube-shape`: Cube dimensions as three integers (default: `512 768 256`)
|
|
153
|
-
- `--voxel-dx`, `--voxel-dy`, `--voxel-dz`: Voxel sizes
|
|
155
|
+
- `--voxel-dx`, `--voxel-dy`, `--voxel-dz`: Voxel sizes with units (default: `"0.192 Mm"`, `"0.192 Mm"`, `"0.064 Mm"`)
|
|
154
156
|
|
|
155
157
|
**Velocity Grid:**
|
|
156
|
-
- `--vel-res`: Velocity resolution
|
|
157
|
-
- `--vel-lim`: Velocity limit
|
|
158
|
+
- `--vel-res`: Velocity resolution with units (default: `"5.0 km/s"`)
|
|
159
|
+
- `--vel-lim`: Velocity limit +-km/s with units (default: `"300.0 km/s"`)
|
|
158
160
|
|
|
159
161
|
**Integration and Viewing:**
|
|
160
162
|
- `--integration-axis`: Integration axis: `x`, `y`, or `z` (default: `z`)
|
|
@@ -162,10 +164,10 @@ synthesise-spectra --help
|
|
|
162
164
|
- `x`: Side view from the left (integrates left-to-right)
|
|
163
165
|
- `y`: Side view from the front (integrates front-to-back)
|
|
164
166
|
|
|
165
|
-
**Spatial Cropping (Heliocentric coordinates
|
|
166
|
-
- `--crop-x`: X-range to crop, e.g., `--crop-x -50 50` (optional)
|
|
167
|
-
- `--crop-y`: Y-range to crop, e.g., `--crop-y -50 50` (optional)
|
|
168
|
-
- `--crop-z`: Z-range to crop, e.g., `--crop-z 0 20` (optional)
|
|
167
|
+
**Spatial Cropping (Heliocentric coordinates with units):**
|
|
168
|
+
- `--crop-x`: X-range to crop with units, e.g., `--crop-x "-50 Mm" "50 Mm"` (optional)
|
|
169
|
+
- `--crop-y`: Y-range to crop with units, e.g., `--crop-y "-50 Mm" "50 Mm"` (optional)
|
|
170
|
+
- `--crop-z`: Z-range to crop with units, e.g., `--crop-z "0 Mm" "20 Mm"` (optional)
|
|
169
171
|
- Omit any crop option to use the full range in that dimension
|
|
170
172
|
|
|
171
173
|
**Processing Options:**
|
|
@@ -176,6 +178,40 @@ synthesise-spectra --help
|
|
|
176
178
|
**Line Selection:**
|
|
177
179
|
- `--limit-lines`: Limit to specific lines, e.g., `--limit-lines Fe12_195.1190 Fe12_195.1790`
|
|
178
180
|
|
|
181
|
+
#### Dynamic Mode (Time-varying Atmospheres)
|
|
182
|
+
|
|
183
|
+
For simulating raster scans over evolving atmospheres, use dynamic mode which combines MHD timesteps based on instrument scanning:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
synthesise-spectra \
|
|
187
|
+
--data-dir ./data/atmosphere \
|
|
188
|
+
--goft-file ./data/gofnt.sav \
|
|
189
|
+
--output-dir ./run/input \
|
|
190
|
+
--slit-rest-time "40 s" \
|
|
191
|
+
--slit-width "0.2 arcsec" \
|
|
192
|
+
--temp-dir temp \
|
|
193
|
+
--temp-filename eosT \
|
|
194
|
+
--rho-dir rho \
|
|
195
|
+
--rho-filename result_prim_0 \
|
|
196
|
+
--vz-dir vz \
|
|
197
|
+
--vz-filename result_prim_2 \
|
|
198
|
+
--time-dir time \
|
|
199
|
+
--time-filename tau_slice_0.100 \
|
|
200
|
+
--cube-shape 512 768 256 \
|
|
201
|
+
--voxel-dx "0.192 Mm" \
|
|
202
|
+
--voxel-dy "0.192 Mm" \
|
|
203
|
+
--voxel-dz "0.064 Mm" \
|
|
204
|
+
--vel-res "5.0 km/s" \
|
|
205
|
+
--vel-lim "300.0 km/s" \
|
|
206
|
+
--integration-axis z
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Dynamic Mode Options:**
|
|
210
|
+
- `--slit-rest-time`: Slit rest time per position - enables dynamic mode
|
|
211
|
+
- `--slit-width`: Slit width
|
|
212
|
+
- `--temp-dir`, `--rho-dir`, `--vx-dir`, `--vy-dir`, `--vz-dir`, `--time-dir`: Directories containing timestep files
|
|
213
|
+
- `--temp-filename`, `--rho-filename`, `--vx-filename`, `--vy-filename`, `--vz-filename`, `--time-filename`: Filename prefix before timestep suffix
|
|
214
|
+
|
|
179
215
|
#### Output
|
|
180
216
|
|
|
181
217
|
The synthesis produces a pickle file containing:
|
|
@@ -187,7 +223,7 @@ The synthesis produces a pickle file containing:
|
|
|
187
223
|
|
|
188
224
|
- Use `--downsample 2` or `--downsample 4` for initial testing
|
|
189
225
|
- Use `--precision float32` to reduce memory usage (may affect accuracy)
|
|
190
|
-
- Use `--limit-lines` to
|
|
226
|
+
- Use `--limit-lines` to synthesise only specific lines for development
|
|
191
227
|
- Use spatial cropping to focus on regions of interest and reduce computation time
|
|
192
228
|
- Monitor memory usage - full resolution synthesis can require 50+ GB RAM
|
|
193
229
|
- Side views (`--integration-axis x` or `y`) may require different velocity files
|
|
@@ -285,7 +321,11 @@ ccd_temperature: -60 Celsius # Default (expected operating temperature)
|
|
|
285
321
|
vis_sl: 0 photon / (s * pixel) # Default, (ideal case, no stray light)
|
|
286
322
|
```
|
|
287
323
|
|
|
288
|
-
For
|
|
324
|
+
For guidance on recommended values, see McKevitt et al. (2025) (in prep.).
|
|
325
|
+
|
|
326
|
+
If you synthesised data in dynamic mode, your configuration must specify:
|
|
327
|
+
- Exactly one slit width matching the synthesis slit width
|
|
328
|
+
- Exactly one exposure time matching the synthesis exposure time
|
|
289
329
|
|
|
290
330
|
#### Running Simulations
|
|
291
331
|
|
|
@@ -4,7 +4,7 @@ ECLIPSE: Emission Calculation and Line Intensity Prediction for SOLAR-C EUVST
|
|
|
4
4
|
This package provides tools for modeling the performance of the EUV spectrograph EUVST, on SOLAR-C.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
__version__ = "0.
|
|
7
|
+
__version__ = "0.6.0"
|
|
8
8
|
__author__ = "James McKevitt"
|
|
9
9
|
__email__ = "jm2@mssl.ucl.ac.uk"
|
|
10
10
|
|
|
@@ -561,6 +561,9 @@ def create_sunpy_maps_from_combo(
|
|
|
561
561
|
|
|
562
562
|
maps['velocity_std'] = sunpy.map.Map(analysis["v_std"].value.T, wcs_2d)
|
|
563
563
|
maps['velocity_std'].meta['bunit'] = str(analysis["v_std"].unit)
|
|
564
|
+
|
|
565
|
+
maps['velocity_true'] = sunpy.map.Map(analysis["v_true"].value.T, wcs_2d)
|
|
566
|
+
maps['velocity_true'].meta['bunit'] = str(analysis["v_true"].unit)
|
|
564
567
|
|
|
565
568
|
# Velocity error (truth - mean)
|
|
566
569
|
maps['velocity_err'] = sunpy.map.Map(analysis["v_err"].value.T, wcs_2d)
|
|
@@ -16,7 +16,7 @@ from tqdm import tqdm
|
|
|
16
16
|
from .utils import tqdm_joblib, distance_to_angle
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def load_atmosphere(pkl_file: str, metadata_line: str = None) ->
|
|
19
|
+
def load_atmosphere(pkl_file: str, metadata_line: str = None) -> tuple:
|
|
20
20
|
"""
|
|
21
21
|
Load synthetic atmosphere cube from pickle file.
|
|
22
22
|
|
|
@@ -34,9 +34,10 @@ def load_atmosphere(pkl_file: str, metadata_line: str = None) -> NDCube:
|
|
|
34
34
|
|
|
35
35
|
Returns
|
|
36
36
|
-------
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
tuple
|
|
38
|
+
(summed_cube, dynamic_mode_info) where:
|
|
39
|
+
- summed_cube: NDCube with summed line intensities
|
|
40
|
+
- dynamic_mode_info: dict with dynamic mode metadata (or None if static)
|
|
40
41
|
"""
|
|
41
42
|
with open(pkl_file, "rb") as f:
|
|
42
43
|
tmp = dill.load(f)
|
|
@@ -49,6 +50,9 @@ def load_atmosphere(pkl_file: str, metadata_line: str = None) -> NDCube:
|
|
|
49
50
|
if not line_cubes:
|
|
50
51
|
raise ValueError("No line cubes found in synthesis results")
|
|
51
52
|
|
|
53
|
+
# Get dynamic mode info if present
|
|
54
|
+
dynamic_mode_info = tmp.get("dynamic_mode", {"enabled": False})
|
|
55
|
+
|
|
52
56
|
# Get the line names
|
|
53
57
|
line_names = list(line_cubes.keys())
|
|
54
58
|
|
|
@@ -96,7 +100,8 @@ def load_atmosphere(pkl_file: str, metadata_line: str = None) -> NDCube:
|
|
|
96
100
|
"combined_lines": line_names,
|
|
97
101
|
"n_lines": len(line_names),
|
|
98
102
|
"metadata_source": metadata_line,
|
|
99
|
-
"summed_intensity": True
|
|
103
|
+
"summed_intensity": True,
|
|
104
|
+
"dynamic_mode": dynamic_mode_info,
|
|
100
105
|
})
|
|
101
106
|
|
|
102
107
|
# Create the summed cube using the reference cube's WCS
|
|
@@ -107,7 +112,7 @@ def load_atmosphere(pkl_file: str, metadata_line: str = None) -> NDCube:
|
|
|
107
112
|
meta=combined_meta
|
|
108
113
|
)
|
|
109
114
|
|
|
110
|
-
return summed_cube
|
|
115
|
+
return summed_cube, dynamic_mode_info
|
|
111
116
|
|
|
112
117
|
|
|
113
118
|
def resample_ndcube_spectral_axis(ndcube, spectral_axis, output_resolution, ncpu=-1):
|
|
@@ -248,7 +253,7 @@ def rebin_atmosphere(cube_sim, det, sim, use_dask=False):
|
|
|
248
253
|
sim : Simulation
|
|
249
254
|
Simulation configuration
|
|
250
255
|
use_dask : bool, optional
|
|
251
|
-
Whether to use Dask for automatic parallelization (default:
|
|
256
|
+
Whether to use Dask for automatic parallelization (default: False)
|
|
252
257
|
|
|
253
258
|
Returns
|
|
254
259
|
-------
|
|
@@ -226,7 +226,51 @@ def main() -> None:
|
|
|
226
226
|
# Load synthetic atmosphere cube
|
|
227
227
|
print("Loading atmosphere...")
|
|
228
228
|
print(f"Using '{reference_line}' as reference line for wavelength grid and metadata...")
|
|
229
|
-
cube_sim = load_atmosphere(synthesis_file, reference_line)
|
|
229
|
+
cube_sim, dynamic_mode_info = load_atmosphere(synthesis_file, reference_line)
|
|
230
|
+
|
|
231
|
+
# Check for dynamic mode and validate parameters
|
|
232
|
+
is_dynamic_mode = dynamic_mode_info.get("enabled", False)
|
|
233
|
+
if is_dynamic_mode:
|
|
234
|
+
print("Synthesis was done in DYNAMIC MODE (time-varying atmosphere)")
|
|
235
|
+
print(f" Slit width: {dynamic_mode_info['slit_width']}")
|
|
236
|
+
print(f" Slit rest time: {dynamic_mode_info['slit_rest_time']}")
|
|
237
|
+
print(f" Timesteps used: {len(dynamic_mode_info['available_timesteps'])}")
|
|
238
|
+
|
|
239
|
+
# Check that exactly one slit width is provided for dynamic mode
|
|
240
|
+
synth_slit_width = dynamic_mode_info["slit_width"]
|
|
241
|
+
if len(slit_widths) != 1:
|
|
242
|
+
raise ValueError(
|
|
243
|
+
f"Dynamic mode synthesis requires exactly one slit width. "
|
|
244
|
+
f"Config specifies {len(slit_widths)} slit widths: {slit_widths}. "
|
|
245
|
+
f"Please provide only the synthesis slit width: {synth_slit_width}"
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Validate that the single slit width matches synthesis
|
|
249
|
+
if not np.isclose(slit_widths[0].to_value(u.arcsec), synth_slit_width.to_value(u.arcsec), rtol=1e-6):
|
|
250
|
+
raise ValueError(
|
|
251
|
+
f"Slit width mismatch: synthesis was done with {synth_slit_width}, "
|
|
252
|
+
f"but config specifies {slit_widths[0]}. "
|
|
253
|
+
f"For dynamic mode synthesis, the slit width must match exactly: {synth_slit_width}"
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Check that exactly one exposure time is provided for dynamic mode
|
|
257
|
+
synth_rest_time = dynamic_mode_info["slit_rest_time"]
|
|
258
|
+
if len(exposures) != 1:
|
|
259
|
+
raise ValueError(
|
|
260
|
+
f"Dynamic mode synthesis requires exactly one exposure time. "
|
|
261
|
+
f"Config specifies {len(exposures)} exposure times: {exposures}. "
|
|
262
|
+
f"Please provide only the synthesis slit rest time: {synth_rest_time}"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
# Validate that the single exposure time matches synthesis
|
|
266
|
+
if not np.isclose(exposures[0].to_value(u.s), synth_rest_time.to_value(u.s), rtol=1e-6):
|
|
267
|
+
raise ValueError(
|
|
268
|
+
f"Exposure time mismatch: synthesis was done with {synth_rest_time}, "
|
|
269
|
+
f"but config specifies {exposures[0]}. "
|
|
270
|
+
f"For dynamic mode synthesis, the exposure time must match exactly: {synth_rest_time}"
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
print(" Dynamic mode parameters validated successfully!")
|
|
230
274
|
|
|
231
275
|
# Set up base detector configuration (doesn't change with parameters)
|
|
232
276
|
if instrument == "SWC":
|
|
@@ -243,8 +243,12 @@ def to_electrons(photon_counts: NDCube, t_exp: u.Quantity, det) -> NDCube:
|
|
|
243
243
|
|
|
244
244
|
e = electron_counts * (u.electron / u.pixel)
|
|
245
245
|
|
|
246
|
-
# Add dark current
|
|
247
|
-
|
|
246
|
+
# Add dark current with Poisson noise
|
|
247
|
+
dark_current_mean = (det.dark_current * t_exp).to(u.electron / u.pixel).value
|
|
248
|
+
dark_current_poisson = np.random.poisson(dark_current_mean) * (u.electron / u.pixel)
|
|
249
|
+
e += dark_current_poisson
|
|
250
|
+
|
|
251
|
+
# Add read noise
|
|
248
252
|
e += np.random.normal(0, det.read_noise_rms.value,
|
|
249
253
|
photon_counts.data.shape) * (u.electron / u.pixel) # read noise
|
|
250
254
|
|
|
@@ -279,7 +283,7 @@ def to_dn(electrons: NDCube, det) -> NDCube:
|
|
|
279
283
|
dn_q = (electrons.data * electrons.unit) / det.gain_e_per_dn # Quantity
|
|
280
284
|
dn_q = dn_q.to(det.max_dn.unit)
|
|
281
285
|
|
|
282
|
-
dn_val = dn_q.value
|
|
286
|
+
dn_val = np.round(dn_q.value) # round to nearest whole number
|
|
283
287
|
dn_val[dn_val > det.max_dn.value] = det.max_dn.value # clip
|
|
284
288
|
|
|
285
289
|
return NDCube(
|