eclipse 0.13.0__py3-none-any.whl
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.
- eclipse/__init__.py +95 -0
- eclipse/analysis.py +853 -0
- eclipse/atmosphere.py +859 -0
- eclipse/band.py +477 -0
- eclipse/cli.py +138 -0
- eclipse/config.py +1710 -0
- eclipse/continuum.py +413 -0
- eclipse/data/eis_response/EIS_EffArea_A.004 +61 -0
- eclipse/data/eis_response/EIS_EffArea_B.004 +60 -0
- eclipse/data/eis_response/EIS_EffArea_B.005 +64 -0
- eclipse/data/eis_response/README_dz2025 +50 -0
- eclipse/data/eis_response/fit_eis_ea_2023-05-04_smooth.sav +0 -0
- eclipse/data/eis_response/source.txt +33 -0
- eclipse/data/science_cases.yaml +365 -0
- eclipse/data/throughput/grating_reflection_efficiency.dat +25 -0
- eclipse/data/throughput/primary_mirror_coating_reflectance.dat +25 -0
- eclipse/data/throughput/source.txt +6 -0
- eclipse/data/throughput/throughput_aluminium_1000_angstrom.dat +503 -0
- eclipse/data/throughput/throughput_aluminium_oxide_1000_angstrom.dat +503 -0
- eclipse/data/throughput/throughput_carbon_1000_angstrom.dat +503 -0
- eclipse/data_processing.py +904 -0
- eclipse/deprecated.py +161 -0
- eclipse/eis_calibration.py +573 -0
- eclipse/extern/__init__.py +0 -0
- eclipse/extern/mpfit.py +2388 -0
- eclipse/fitting.py +1734 -0
- eclipse/frame.py +594 -0
- eclipse/full_frame.py +944 -0
- eclipse/main.py +1646 -0
- eclipse/monte_carlo.py +660 -0
- eclipse/pinhole_diffraction.py +409 -0
- eclipse/psf.py +6 -0
- eclipse/radiometric.py +1328 -0
- eclipse/raster.py +869 -0
- eclipse/readout.py +1002 -0
- eclipse/resolution_budget.py +108 -0
- eclipse/results_file.py +1226 -0
- eclipse/sampling.py +351 -0
- eclipse/science_cases.py +364 -0
- eclipse/synthesis.py +2492 -0
- eclipse/synthesis_cli.py +12 -0
- eclipse/synthesis_file.py +882 -0
- eclipse/utils.py +1145 -0
- eclipse-0.13.0.dist-info/METADATA +70 -0
- eclipse-0.13.0.dist-info/RECORD +50 -0
- eclipse-0.13.0.dist-info/WHEEL +5 -0
- eclipse-0.13.0.dist-info/entry_points.txt +7 -0
- eclipse-0.13.0.dist-info/licenses/LICENSE +3 -0
- eclipse-0.13.0.dist-info/top_level.txt +2 -0
- euvst_response/__init__.py +129 -0
eclipse/deprecated.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deprecated functions, which warn when called and will be removed in a future release.
|
|
3
|
+
|
|
4
|
+
Each can still be imported from where it was before, such as
|
|
5
|
+
`eclipse.frame.apply_spectral_psf`, so existing scripts still run.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict
|
|
12
|
+
|
|
13
|
+
import astropy.units as u
|
|
14
|
+
import numpy as np
|
|
15
|
+
from scipy.ndimage import zoom
|
|
16
|
+
from scipy.signal import convolve2d
|
|
17
|
+
|
|
18
|
+
from .radiometric import _spectral_kernel
|
|
19
|
+
from .utils import _warn_outside
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _warn(name: str, reason: str) -> None:
|
|
23
|
+
"""Warn that `name` is deprecated, attributed to the first caller outside ECLIPSE."""
|
|
24
|
+
_warn_outside(f"{name} is deprecated and will be removed in a future release: {reason}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def apply_spectral_psf(rows: u.Quantity, telescope, det, slit_width: u.Quantity,
|
|
30
|
+
spectral_psf: str = "quadrature", margin: int = 0) -> u.Quantity:
|
|
31
|
+
"""
|
|
32
|
+
Blur a frame's rows with the instrument's spectral response.
|
|
33
|
+
|
|
34
|
+
Along the dispersion a pixel is a row. The response is that of
|
|
35
|
+
:func:`~eclipse.radiometric.apply_focusing_optics_psf` for a
|
|
36
|
+
synthesis through the same slit, on the same rows: for `spectral_psf`
|
|
37
|
+
`"quadrature"` a Gaussian of
|
|
38
|
+
:func:`~eclipse.radiometric.spectral_psf_fwhm`, and for
|
|
39
|
+
`"convolution"` :func:`~eclipse.radiometric.spectral_line_spread`.
|
|
40
|
+
The slit's image is part of the line profile, so a wider slit gives a
|
|
41
|
+
wider response: a FWHM of 2.54 rows for the 0.2 arcsec slit and 3.35
|
|
42
|
+
for the 0.4 arcsec slit.
|
|
43
|
+
|
|
44
|
+
Nothing is assumed beyond the rows given: light blurred past either end
|
|
45
|
+
is lost, as off the edge of a detector, and none comes in. The edge rows
|
|
46
|
+
of a CCD do receive light from just off the chip, and at the butted edge
|
|
47
|
+
the spectrum continues across the gap. To include this, lay the spectrum
|
|
48
|
+
with a `margin` of at least
|
|
49
|
+
:func:`~eclipse.radiometric.spectral_psf_reach` rows past each
|
|
50
|
+
end (:func:`~eclipse.frame.photons_from_lines` and
|
|
51
|
+
:func:`~eclipse.frame.photons_from_spectrum` take one), and pass
|
|
52
|
+
the same margin here. The result is then the chip's own rows. The
|
|
53
|
+
kernel is normalised, so flux that stays within the rows is conserved.
|
|
54
|
+
|
|
55
|
+
Deprecated since 0.12.0: blurring the rows after the light is on them
|
|
56
|
+
moves a line narrower than a row toward the middle of its row, by up to
|
|
57
|
+
a few km/s.
|
|
58
|
+
Give `spectral_psf` and `det` to
|
|
59
|
+
:func:`~eclipse.frame.photons_from_lines` or
|
|
60
|
+
:func:`~eclipse.frame.photons_from_spectrum` instead, which blur
|
|
61
|
+
the light as it is laid onto the rows.
|
|
62
|
+
"""
|
|
63
|
+
_warn("apply_spectral_psf",
|
|
64
|
+
"blurring the rows once the light is on them moves a line narrower than a row "
|
|
65
|
+
"toward the middle of its row. Give spectral_psf and det to photons_from_lines or "
|
|
66
|
+
"photons_from_spectrum instead.")
|
|
67
|
+
margin = int(margin)
|
|
68
|
+
kernel = _spectral_kernel(telescope, det, slit_width, spectral_psf)
|
|
69
|
+
kernel = kernel / kernel.sum()
|
|
70
|
+
half = kernel.size // 2
|
|
71
|
+
if margin and margin < half:
|
|
72
|
+
raise ValueError(
|
|
73
|
+
f"A margin of {margin} rows is less than the {half} the spectral "
|
|
74
|
+
f"response reaches, so the edge rows would miss light."
|
|
75
|
+
)
|
|
76
|
+
unit = rows.unit if hasattr(rows, "unit") else 1
|
|
77
|
+
values = np.asarray(rows.value if hasattr(rows, "value") else rows, dtype=float)
|
|
78
|
+
if values.size <= 2 * margin:
|
|
79
|
+
raise ValueError(
|
|
80
|
+
f"{values.size} rows leave nothing inside a margin of {margin} at each end."
|
|
81
|
+
)
|
|
82
|
+
blurred = np.convolve(np.pad(values, half), kernel, mode="valid")
|
|
83
|
+
return blurred[margin:values.size - margin] * unit
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def get_dem_data_from_results(results: Dict[str, Any]) -> Dict[str, Any]:
|
|
87
|
+
"""
|
|
88
|
+
DEM data held in the results, which no version of ECLIPSE has written there.
|
|
89
|
+
|
|
90
|
+
Deprecated since 0.12.0. The DEM and emission measure are in the
|
|
91
|
+
synthesis file. Read them with
|
|
92
|
+
`read_synthesis_products(path, keys=["dem_map", "em_tv"])`.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
results : dict
|
|
97
|
+
Results from `load_instrument_response_results`.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
dict
|
|
102
|
+
`results["dem_data"]`.
|
|
103
|
+
|
|
104
|
+
Raises
|
|
105
|
+
------
|
|
106
|
+
KeyError
|
|
107
|
+
If the results hold no DEM; results from `eclipse` never do.
|
|
108
|
+
"""
|
|
109
|
+
_warn("get_dem_data_from_results",
|
|
110
|
+
"no released version wrote DEM data into the results. The DEM is in the synthesis "
|
|
111
|
+
"file; read it with "
|
|
112
|
+
"eclipse.read_synthesis_products(path, keys=['dem_map', 'em_tv']).")
|
|
113
|
+
if "dem_data" not in results:
|
|
114
|
+
raise KeyError(
|
|
115
|
+
"DEM data is not in the results, as no released version wrote it there. It is "
|
|
116
|
+
"in the synthesis file: read it with "
|
|
117
|
+
"eclipse.read_synthesis_products(path, keys=['dem_map', 'em_tv'])."
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
return results["dem_data"]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _load_psf_ascii(fname: Path, skip: int) -> np.ndarray:
|
|
124
|
+
"""Load PSF data from ASCII file."""
|
|
125
|
+
_warn("_load_psf_ascii", "ECLIPSE does not use it. "
|
|
126
|
+
"numpy.loadtxt(fname, skiprows=skip, encoding='utf-16 LE') does the same.")
|
|
127
|
+
return np.loadtxt(fname, skiprows=skip, encoding="utf-16 LE")
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _resample_psf(psf: np.ndarray, res_in: u.Quantity, res_out: u.Quantity) -> np.ndarray:
|
|
131
|
+
"""Resample PSF to different pixel scale."""
|
|
132
|
+
_warn("_resample_psf", "ECLIPSE does not use it. scipy.ndimage.zoom does the same.")
|
|
133
|
+
factor = (res_in / res_out).decompose().value
|
|
134
|
+
return zoom(psf, factor, order=1)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _combine_psfs(psf_focus: np.ndarray, psf_mesh: np.ndarray, crop: float = 0.99, size: int | None = None) -> np.ndarray:
|
|
138
|
+
"""Convolve the focus and mesh PSFs and crop to an energy fraction or size."""
|
|
139
|
+
_warn("_combine_psfs", "ECLIPSE does not use it. scipy.signal.convolve2d does the "
|
|
140
|
+
"convolution.")
|
|
141
|
+
psf = convolve2d(psf_focus, psf_mesh, mode="same")
|
|
142
|
+
if size is not None:
|
|
143
|
+
if size % 2 == 0:
|
|
144
|
+
size += 1
|
|
145
|
+
r0, c0 = np.array(psf.shape) // 2
|
|
146
|
+
half = size // 2
|
|
147
|
+
psf = psf[r0 - half : r0 + half + 1, c0 - half : c0 + half + 1]
|
|
148
|
+
else:
|
|
149
|
+
flat = psf.ravel()
|
|
150
|
+
idx = flat.argsort()[::-1]
|
|
151
|
+
csum = flat[idx].cumsum()
|
|
152
|
+
thr = flat[idx[np.searchsorted(csum, flat.sum() * crop)]]
|
|
153
|
+
flat[flat < thr] = 0
|
|
154
|
+
rows, cols = np.where(flat.reshape(psf.shape))
|
|
155
|
+
r0, r1 = rows.min(), rows.max()
|
|
156
|
+
c0, c1 = cols.min(), cols.max()
|
|
157
|
+
side = max(r1 - r0, c1 - c0) + 1
|
|
158
|
+
r0 = (r0 + r1) // 2 - side // 2
|
|
159
|
+
c0 = (c0 + c1) // 2 - side // 2
|
|
160
|
+
psf = psf[r0 : r0 + side, c0 : c0 + side]
|
|
161
|
+
return psf / psf.sum()
|