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.
Files changed (50) hide show
  1. eclipse/__init__.py +95 -0
  2. eclipse/analysis.py +853 -0
  3. eclipse/atmosphere.py +859 -0
  4. eclipse/band.py +477 -0
  5. eclipse/cli.py +138 -0
  6. eclipse/config.py +1710 -0
  7. eclipse/continuum.py +413 -0
  8. eclipse/data/eis_response/EIS_EffArea_A.004 +61 -0
  9. eclipse/data/eis_response/EIS_EffArea_B.004 +60 -0
  10. eclipse/data/eis_response/EIS_EffArea_B.005 +64 -0
  11. eclipse/data/eis_response/README_dz2025 +50 -0
  12. eclipse/data/eis_response/fit_eis_ea_2023-05-04_smooth.sav +0 -0
  13. eclipse/data/eis_response/source.txt +33 -0
  14. eclipse/data/science_cases.yaml +365 -0
  15. eclipse/data/throughput/grating_reflection_efficiency.dat +25 -0
  16. eclipse/data/throughput/primary_mirror_coating_reflectance.dat +25 -0
  17. eclipse/data/throughput/source.txt +6 -0
  18. eclipse/data/throughput/throughput_aluminium_1000_angstrom.dat +503 -0
  19. eclipse/data/throughput/throughput_aluminium_oxide_1000_angstrom.dat +503 -0
  20. eclipse/data/throughput/throughput_carbon_1000_angstrom.dat +503 -0
  21. eclipse/data_processing.py +904 -0
  22. eclipse/deprecated.py +161 -0
  23. eclipse/eis_calibration.py +573 -0
  24. eclipse/extern/__init__.py +0 -0
  25. eclipse/extern/mpfit.py +2388 -0
  26. eclipse/fitting.py +1734 -0
  27. eclipse/frame.py +594 -0
  28. eclipse/full_frame.py +944 -0
  29. eclipse/main.py +1646 -0
  30. eclipse/monte_carlo.py +660 -0
  31. eclipse/pinhole_diffraction.py +409 -0
  32. eclipse/psf.py +6 -0
  33. eclipse/radiometric.py +1328 -0
  34. eclipse/raster.py +869 -0
  35. eclipse/readout.py +1002 -0
  36. eclipse/resolution_budget.py +108 -0
  37. eclipse/results_file.py +1226 -0
  38. eclipse/sampling.py +351 -0
  39. eclipse/science_cases.py +364 -0
  40. eclipse/synthesis.py +2492 -0
  41. eclipse/synthesis_cli.py +12 -0
  42. eclipse/synthesis_file.py +882 -0
  43. eclipse/utils.py +1145 -0
  44. eclipse-0.13.0.dist-info/METADATA +70 -0
  45. eclipse-0.13.0.dist-info/RECORD +50 -0
  46. eclipse-0.13.0.dist-info/WHEEL +5 -0
  47. eclipse-0.13.0.dist-info/entry_points.txt +7 -0
  48. eclipse-0.13.0.dist-info/licenses/LICENSE +3 -0
  49. eclipse-0.13.0.dist-info/top_level.txt +2 -0
  50. euvst_response/__init__.py +129 -0
eclipse/continuum.py ADDED
@@ -0,0 +1,413 @@
1
+ """
2
+ Continuum under the lines: free-free, free-bound and two-photon emission.
3
+
4
+ Computed from CHIANTI through fiasco for every element, with the same
5
+ abundances and ionisation fractions as the lines. Like a contribution
6
+ function, it multiplies an emission measure of n_e^2 dh, so fiasco's values
7
+ are multiplied by n_H / n_e and divided by 4 pi. Only two-photon emission
8
+ depends on density. In a synthesis file, each group of overlapping windows
9
+ gets one continuum entry, which the instrument run adds to every window it
10
+ reaches.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import os
16
+ from typing import Dict, List, Optional, Sequence, Tuple
17
+
18
+ import numpy as np
19
+ import astropy.units as u
20
+
21
+ # Name prefix of a continuum entry in a synthesis file, followed by the
22
+ # wavelength range of its window group in Angstrom.
23
+ CONTINUUM_PREFIX = "continuum"
24
+ # Unit of the continuum per emission measure: spectral radiance per
25
+ # n_e^2 dh, with wavelengths in cm, as for ECLIPSE's line spectra.
26
+ EMISSIVITY_UNIT = u.erg * u.cm**3 / (u.s * u.sr * u.cm)
27
+
28
+
29
+ def is_continuum(name: str) -> bool:
30
+ """Whether synthesis file entry `name` is the continuum rather than a line."""
31
+ return name.startswith(CONTINUUM_PREFIX + "_")
32
+
33
+
34
+ def continuum_windows(wavelengths: Sequence[u.Quantity]) -> Dict[str, u.Quantity]:
35
+ """
36
+ Wavelengths of the continuum entries covering a set of spectral windows.
37
+
38
+ Each window wavelength covers the bin halfway to its neighbours. The
39
+ bins of the end wavelengths extend the same distance outward. Windows
40
+ whose bins overlap are grouped. Each group gets one evenly spaced grid,
41
+ at the smallest spacing of its windows, whose bins cover all of theirs.
42
+ Groups do not overlap, so no wavelength is in two entries.
43
+
44
+ Parameters
45
+ ----------
46
+ wavelengths : sequence of u.Quantity
47
+ Wavelengths of each line, increasing, as in `wl_grid` from
48
+ `synthesise_spectra`.
49
+
50
+ Returns
51
+ -------
52
+ dict
53
+ Wavelengths in cm for each group, keyed by entry name such as
54
+ `"continuum_194.9248-195.3757"`.
55
+ """
56
+ windows = []
57
+ for grid in wavelengths:
58
+ values = np.asarray(u.Quantity(grid).to_value(u.cm), dtype=float)
59
+ if values.size < 2:
60
+ raise ValueError("A spectral window needs two or more wavelengths.")
61
+ spacing = np.diff(values)
62
+ if not np.all(spacing > 0):
63
+ raise ValueError("A spectral window's wavelengths must increase.")
64
+ # The window's bins, from half a spacing before its first wavelength
65
+ # to half a spacing after its last.
66
+ windows.append((float(values[0] - spacing[0] / 2), float(values[-1] + spacing[-1] / 2),
67
+ float(np.min(spacing))))
68
+
69
+ def bins(low, high, step):
70
+ """Number of bins of width `step` needed to reach from `low` to `high`."""
71
+ return int(np.ceil((high - low) / step * (1 - 1e-12)))
72
+
73
+ windows.sort()
74
+ groups: List[List[float]] = []
75
+ for low, high, step in windows:
76
+ # A group's bins can reach past its windows' last bin, so a window is
77
+ # grouped with it if it begins before the group's bins end.
78
+ if groups:
79
+ first, last, spacing = groups[-1]
80
+ if low < first + bins(first, last, spacing) * spacing:
81
+ groups[-1] = [first, max(last, high), min(spacing, step)]
82
+ continue
83
+ groups.append([low, high, step])
84
+ grids = {}
85
+ for low, high, step in groups:
86
+ # Bins of this spacing from the group's first bin edge to past its last.
87
+ grid = low + (np.arange(bins(low, high, step)) + 0.5) * step
88
+ name = f"{CONTINUUM_PREFIX}_{grid[0] * 1e8:.4f}-{grid[-1] * 1e8:.4f}"
89
+ # Windows far narrower than any line's could round to the same name.
90
+ if name in grids:
91
+ name = f"{name}_{sum(key.startswith(name) for key in grids) + 1}"
92
+ grids[name] = grid * u.cm
93
+ return grids
94
+
95
+
96
+ def _element_continuum(args):
97
+ """
98
+ One element's continuum emission, for a worker process.
99
+
100
+ Free-free plus free-bound emission, shape `(nT, n_wavelength)`, and
101
+ two-photon emission, shape `(nT, nN, n_wavelength)`. Both are in
102
+ erg cm3 / (s Angstrom), per n_e n_H and over all directions, as fiasco
103
+ gives them.
104
+ """
105
+ symbol, temperature_K, wavelength_aa, densities_cm3, abundance, dbase_root = args
106
+ import logging
107
+
108
+ import fiasco
109
+ from fiasco.util.exceptions import MissingDatasetException
110
+
111
+ # fiasco skips and logs each ion lacking data for a continuum; collect
112
+ # them to report once, rather than a line each.
113
+ left_out = []
114
+
115
+ class _LeftOut(logging.Handler):
116
+ def emit(self, record):
117
+ message = record.getMessage()
118
+ if " not included in " in message:
119
+ ion, rest = message.split(" not included in ", 1)
120
+ # An ion with no electrons has no bound states, and so no
121
+ # free-bound emission to leave out.
122
+ if ion.split()[-1] == str(atomic_number + 1):
123
+ return
124
+ left_out.append(f"{ion} ({rest.split(' emission')[0]})")
125
+
126
+ from .utils import element_data
127
+
128
+ atomic_number, _ = element_data(symbol)
129
+ logger = logging.getLogger("fiasco")
130
+ handler, propagate = _LeftOut(), logger.propagate
131
+ logger.addHandler(handler)
132
+ logger.propagate = False
133
+ single_ion = []
134
+ try:
135
+ kwargs = {} if dbase_root is None else {"hdf5_dbase_root": dbase_root}
136
+ element = fiasco.Element(symbol, temperature_K * u.K, abundance=abundance, **kwargs)
137
+ wavelength = wavelength_aa * u.AA
138
+ unit = u.erg * u.cm**3 / (u.s * u.AA)
139
+ free = (element.free_free(wavelength) + element.free_bound(wavelength)).to_value(unit)
140
+ density = densities_cm3 * u.cm**-3
141
+ two_photon = np.zeros((temperature_K.size, densities_cm3.size, wavelength_aa.size))
142
+ for ion in element:
143
+ # Only hydrogen- and helium-like ions give two-photon emission.
144
+ if not (ion.hydrogenic or ion.helium_like):
145
+ continue
146
+ try:
147
+ emission = _two_photon(ion, wavelength, density, unit, single_ion, kwargs,
148
+ abundance)
149
+ except MissingDatasetException:
150
+ left_out.append(f"{ion.ion_name} (two-photon)")
151
+ continue
152
+ try:
153
+ abundance_of = u.Quantity(ion.abundance).to_value(u.dimensionless_unscaled)
154
+ except MissingDatasetException:
155
+ # An element missing from the abundance set has zero abundance.
156
+ continue
157
+ share = (abundance_of
158
+ * u.Quantity(ion.ionization_fraction).to_value(u.dimensionless_unscaled))
159
+ two_photon += emission * share[:, np.newaxis, np.newaxis]
160
+ finally:
161
+ logger.removeHandler(handler)
162
+ logger.propagate = propagate
163
+ return (symbol, free, two_photon, str(element[0].hdf5_dbase_root), left_out,
164
+ single_ion)
165
+
166
+
167
+ def _beyond_the_rates(error: ValueError) -> bool:
168
+ """Whether fiasco stopped at a temperature beyond the rates CHIANTI tabulates."""
169
+ return "interpolation range" in str(error)
170
+
171
+
172
+ def _two_photon(ion, wavelength, density, unit, single_ion: list, ion_kwargs: dict,
173
+ abundance: str) -> np.ndarray:
174
+ """
175
+ One ion's two-photon emission, shape (nT, nN, n_wavelength), in `unit`.
176
+
177
+ fiasco is called one density at a time, since version 0.8 fails to
178
+ arrange its result for several. Its level populations use level-resolved
179
+ recombination and ionisation rates, which for some ions CHIANTI
180
+ tabulates only up to some temperature. Above that, fiasco's single-ion
181
+ model is used, as for ions with no such rates at all, and the ion and
182
+ temperatures are added to `single_ion`.
183
+ """
184
+ import fiasco
185
+
186
+ def at(one_density, ions):
187
+ parts = []
188
+ for part, single in ions:
189
+ kwargs = {"use_two_ion_model": False} if single else {}
190
+ parts.append(part.two_photon(wavelength, one_density, **kwargs).to_value(unit)[:, 0])
191
+ return np.concatenate(parts)
192
+
193
+ ions = [(ion, False)]
194
+ columns = []
195
+ for one_density in density:
196
+ one_density = one_density[np.newaxis]
197
+ try:
198
+ columns.append(at(one_density, ions))
199
+ continue
200
+ except ValueError as error:
201
+ if not _beyond_the_rates(error) or len(ions) > 1:
202
+ raise
203
+ # First temperature beyond the rates, found once.
204
+ first = None
205
+ for index, temperature in enumerate(ion.temperature):
206
+ one = fiasco.Ion(ion.ion_name, temperature[np.newaxis], abundance=abundance,
207
+ **ion_kwargs)
208
+ try:
209
+ one.two_photon(wavelength, one_density)
210
+ except ValueError as error:
211
+ if not _beyond_the_rates(error):
212
+ raise
213
+ first = index
214
+ break
215
+ if first is None:
216
+ raise RuntimeError(f"fiasco could not work out the two-photon emission of "
217
+ f"{ion.ion_name} at its temperatures together, but could at "
218
+ f"each on its own.")
219
+ below, above = ion.temperature[:first], ion.temperature[first:]
220
+ ions = ([(fiasco.Ion(ion.ion_name, below, abundance=abundance, **ion_kwargs), False)]
221
+ if below.size else [])
222
+ ions.append((fiasco.Ion(ion.ion_name, above, abundance=abundance, **ion_kwargs), True))
223
+ single_ion.append(f"{ion.ion_name} from log T "
224
+ f"{np.log10(above[0].to_value(u.K)):.2f}")
225
+ columns.append(at(one_density, ions))
226
+ return np.stack(columns, axis=1)
227
+
228
+
229
+ def compute_continuum_fiasco(
230
+ wavelength: u.Quantity,
231
+ logT_grid: np.ndarray,
232
+ logN_grid: np.ndarray,
233
+ abundance: str = "sun_coronal_2021_chianti",
234
+ n_workers: int = 0,
235
+ hdf5_dbase_root=None,
236
+ elements: Optional[Sequence[str]] = None,
237
+ ) -> Tuple[np.ndarray, np.ndarray]:
238
+ """
239
+ Continuum per emission measure, from CHIANTI through fiasco.
240
+
241
+ Parameters
242
+ ----------
243
+ wavelength : u.Quantity
244
+ Wavelengths to compute it at.
245
+ logT_grid : np.ndarray
246
+ Temperatures as log10(T / K), as for the lines' contribution
247
+ functions.
248
+ logN_grid : np.ndarray
249
+ Densities as log10(n_e / cm-3), as for the lines' contribution
250
+ functions, for the two-photon emission.
251
+ abundance : str, optional
252
+ CHIANTI abundance set, as for the lines. Default
253
+ `"sun_coronal_2021_chianti"`.
254
+ n_workers : int, optional
255
+ Number of processes for the elements. Default 0 uses every CPU
256
+ available to this process, up to one per element. The workers are
257
+ spawned, so a calling script needs an `if __name__ == "__main__":`
258
+ guard.
259
+ hdf5_dbase_root : str or Path, optional
260
+ CHIANTI database to read. Default fiasco's own.
261
+ elements : sequence of str, optional
262
+ Elements by symbol. Default every element in CHIANTI.
263
+
264
+ Returns
265
+ -------
266
+ free : np.ndarray
267
+ Free-free and free-bound emission, shape (nT, n_wavelength), in
268
+ erg cm3 / (s sr cm): spectral radiance per n_e^2 dh.
269
+ two_photon : np.ndarray
270
+ Two-photon emission, shape (nN, nT, n_wavelength), in the same unit,
271
+ on the `logN_grid` densities, like a line's `g_tn`.
272
+ """
273
+ import fiasco
274
+
275
+ from .atmosphere import _offer_database_build
276
+
277
+ dbase_root = None if hdf5_dbase_root is None else str(hdf5_dbase_root)
278
+ _offer_database_build(dbase_root)
279
+ temperature_K = 10.0 ** np.asarray(logT_grid, dtype=float)
280
+ densities_cm3 = 10.0 ** np.asarray(logN_grid, dtype=float)
281
+ wavelength_aa = np.atleast_1d(u.Quantity(wavelength).to_value(u.AA))
282
+ if elements is None:
283
+ elements = fiasco.list_elements(dbase_root)
284
+ worker_args = [(symbol, temperature_K, wavelength_aa, densities_cm3, abundance, dbase_root)
285
+ for symbol in elements]
286
+
287
+ if n_workers <= 0:
288
+ n_workers = (len(os.sched_getaffinity(0)) if hasattr(os, "sched_getaffinity")
289
+ else os.cpu_count() or 1)
290
+ if n_workers > 1 and len(worker_args) > 1:
291
+ import multiprocessing as mp
292
+
293
+ with mp.get_context("spawn").Pool(min(n_workers, len(worker_args))) as pool:
294
+ results = pool.map(_element_continuum, worker_args)
295
+ else:
296
+ results = [_element_continuum(args) for args in worker_args]
297
+
298
+ free = np.zeros((temperature_K.size, wavelength_aa.size))
299
+ two_photon = np.zeros((temperature_K.size, densities_cm3.size, wavelength_aa.size))
300
+ left_out = {ion for *_, ions, _ in results for ion in ions}
301
+ single_ion = [entry for *_, entries in results for entry in entries]
302
+ if single_ion:
303
+ print(f" CHIANTI's recombination and ionisation rates of each level stop short of "
304
+ f"the hottest temperatures for {len(single_ion)} ions, whose two-photon "
305
+ f"emission there is worked out with fiasco's single-ion model, as for ions "
306
+ f"that have no such rates: {', '.join(single_ion)}")
307
+ for kind in ("free-bound", "two-photon"):
308
+ ions = [entry.rsplit(" (", 1)[0] for entry in left_out if entry.endswith(f"({kind})")]
309
+ if ions:
310
+ print(f" CHIANTI has no {kind} data for {len(ions)} ions, which are left out of "
311
+ f"that part of the continuum: {_ion_list(ions)}")
312
+ for symbol, element_free, element_two_photon, used, _, _ in results:
313
+ if dbase_root is not None and used != dbase_root:
314
+ raise RuntimeError(
315
+ f"The continuum of {symbol} was worked out from the CHIANTI database at "
316
+ f"{used} instead of the requested {dbase_root}.")
317
+ if not (np.all(np.isfinite(element_free)) and np.all(np.isfinite(element_two_photon))):
318
+ raise RuntimeError(f"fiasco gave a continuum for {symbol} that is not finite "
319
+ f"everywhere.")
320
+ free += element_free
321
+ two_photon += element_two_photon
322
+
323
+ # Convert fiasco's continuum, per n_e n_H, over all directions and per
324
+ # Angstrom, to per n_e^2, per steradian and per cm.
325
+ kwargs = {} if dbase_root is None else {"hdf5_dbase_root": dbase_root}
326
+ hydrogen = fiasco.Ion("H 1", temperature_K * u.K, abundance=abundance, **kwargs)
327
+ ratio = np.asarray(hydrogen.proton_electron_ratio.to_value(u.dimensionless_unscaled))
328
+ per_cm = (1.0 / u.AA).to_value(1.0 / u.cm)
329
+ scale = ratio / (4.0 * np.pi) * per_cm
330
+ free = free * scale[:, np.newaxis]
331
+ two_photon = np.moveaxis(two_photon * scale[:, np.newaxis, np.newaxis], 1, 0)
332
+ return free, two_photon
333
+
334
+
335
+ def continuum_spectra(
336
+ emission_measure: np.ndarray,
337
+ electron_density: np.ndarray,
338
+ logN_grid: np.ndarray,
339
+ free: np.ndarray,
340
+ two_photon: np.ndarray,
341
+ ) -> np.ndarray:
342
+ """
343
+ Continuum spectral radiance in every pixel.
344
+
345
+ Parameters
346
+ ----------
347
+ emission_measure : np.ndarray
348
+ Emission measure n_e^2 dh in each temperature bin of each pixel, in
349
+ cm^-5, shape (rows, columns, nT): a DEM times its bin widths.
350
+ ECLIPSE's synthesis uses its own DEM, which, unlike `em_tv`, keeps
351
+ plasma moving faster than the velocity grid reaches.
352
+ electron_density : np.ndarray or float
353
+ Electron density in cm^-3 at each pixel and temperature, same shape
354
+ as `emission_measure`, or one density for all. ECLIPSE's own
355
+ synthesis gives the mean weighted by emission measure.
356
+ logN_grid : np.ndarray
357
+ Densities `two_photon` is tabulated on, as log10(n_e / cm-3).
358
+ free, two_photon : np.ndarray
359
+ From `compute_continuum_fiasco`, on the temperatures of the emission
360
+ measure.
361
+
362
+ Returns
363
+ -------
364
+ np.ndarray
365
+ Spectral radiance, shape (rows, columns, n_wavelength), in
366
+ erg / (s cm2 sr cm). Two-photon emission is interpolated linearly in
367
+ log10 n_e and is zero at densities off the grid, as for the lines'
368
+ contribution functions.
369
+ """
370
+ em = np.asarray(emission_measure, dtype=float)
371
+ rows, columns, n_t = em.shape
372
+ if free.shape[0] != n_t or two_photon.shape[1] != n_t:
373
+ raise ValueError(f"The emission measure has {n_t} temperatures, but the continuum "
374
+ f"has {free.shape[0]}.")
375
+ density = np.broadcast_to(np.asarray(electron_density, dtype=float), em.shape)
376
+ flat = em.reshape(-1, n_t)
377
+ spectra = flat @ free
378
+ log_n = np.log10(np.where(density > 0, density, np.nan)).reshape(-1, n_t)
379
+ grid = np.asarray(logN_grid, dtype=float)
380
+ for t in range(n_t):
381
+ weight = flat[:, t]
382
+ lit = (weight > 0) & np.isfinite(log_n[:, t])
383
+ lit &= (log_n[:, t] >= grid[0]) & (log_n[:, t] <= grid[-1])
384
+ if not lit.any():
385
+ continue
386
+ position = np.interp(log_n[lit, t], grid, np.arange(grid.size, dtype=float))
387
+ lower = np.floor(position).astype(int)
388
+ upper = np.minimum(lower + 1, grid.size - 1)
389
+ fraction = position - lower
390
+ table = two_photon[:, t, :]
391
+ spectra[lit] += weight[lit, np.newaxis] * (
392
+ (1.0 - fraction)[:, np.newaxis] * table[lower] + fraction[:, np.newaxis] * table[upper])
393
+ return spectra.reshape(rows, columns, -1)
394
+
395
+
396
+ def _ion_list(ions: Sequence[str]) -> str:
397
+ """Ions such as `["Fe 1", "Fe 2", "Fe 27"]` written as `"Fe 1-2, 27"`, element by element."""
398
+ stages: Dict[str, List[int]] = {}
399
+ for ion in ions:
400
+ symbol, stage = ion.split()
401
+ stages.setdefault(symbol, []).append(int(stage))
402
+ parts = []
403
+ from .utils import element_data
404
+
405
+ for symbol in sorted(stages, key=lambda s: element_data(s)[0]):
406
+ numbers = sorted(set(stages[symbol]))
407
+ runs, start = [], numbers[0]
408
+ for previous, number in zip(numbers, numbers[1:] + [None]):
409
+ if number is None or number != previous + 1:
410
+ runs.append(str(start) if start == previous else f"{start}-{previous}")
411
+ start = number
412
+ parts.append(f"{symbol} {', '.join(runs)}")
413
+ return "; ".join(parts)
@@ -0,0 +1,61 @@
1
+ # EIS_EFFArea_A.004
2
+ # EIS Effective Area
3
+ # Mon Apr 23 10:40:45 2007
4
+ # Front filter data file: EIS_FFA_A_Trans.003
5
+ # SEF data file: EIS_SEFTrans.002
6
+ # Mirror data file: EIS_MirrorRefl_A.003
7
+ # Grating data file: EIS_GratingRefl_A.003
8
+ # Vignetting data file: EIS_vignetting.001
9
+ # Mirror area: 88.4
10
+ # Groove efficiency: 1.00
11
+ # CCD qe: 0.64
12
+ # Spider trans: 0.80
13
+ # Mesh trans: 1.00
14
+ 245.000 0.0226728
15
+ 246.000 0.0243236
16
+ 247.000 0.0262798
17
+ 248.000 0.0281824
18
+ 249.000 0.0296339
19
+ 250.000 0.0315844
20
+ 251.000 0.0351500
21
+ 252.000 0.0390812
22
+ 253.000 0.0428331
23
+ 254.000 0.0466468
24
+ 255.000 0.0506535
25
+ 256.000 0.0546878
26
+ 257.000 0.0587970
27
+ 258.000 0.0630460
28
+ 259.000 0.0673784
29
+ 260.000 0.0718699
30
+ 261.000 0.0765660
31
+ 262.000 0.0813246
32
+ 263.000 0.0860998
33
+ 264.000 0.0909178
34
+ 265.000 0.0955089
35
+ 266.000 0.0998424
36
+ 267.000 0.103622
37
+ 268.000 0.106984
38
+ 269.000 0.109509
39
+ 270.000 0.110764
40
+ 271.000 0.110875
41
+ 272.000 0.109445
42
+ 273.000 0.106640
43
+ 274.000 0.102602
44
+ 275.000 0.0974887
45
+ 276.000 0.0914836
46
+ 277.000 0.0847751
47
+ 278.000 0.0777747
48
+ 279.000 0.0705505
49
+ 280.000 0.0635321
50
+ 281.000 0.0571789
51
+ 282.000 0.0513891
52
+ 283.000 0.0460830
53
+ 284.000 0.0413185
54
+ 285.000 0.0371190
55
+ 286.000 0.0333321
56
+ 287.000 0.0298378
57
+ 288.000 0.0266719
58
+ 289.000 0.0238613
59
+ 290.000 0.0213016
60
+ 291.000 0.0189506
61
+ 292.000 0.0167953
@@ -0,0 +1,60 @@
1
+ # EIS_EFFArea_B.004
2
+ # EIS Effective Area
3
+ # Mon Apr 23 10:40:45 2007
4
+ # Front filter data file: EIS_FFA_B_Trans.003
5
+ # SEF data file: EIS_SEFTrans.002
6
+ # Mirror data file: EIS_MirrorRefl_B.003
7
+ # Grating data file: EIS_GratingRefl_B.003
8
+ # Mirror area: 88.4
9
+ # Groove efficiency: 1.00
10
+ # CCD qe: 0.64
11
+ # Spider trans: 0.80
12
+ # Mesh trans: 1.00
13
+ 165.000 0.000174973
14
+ 166.000 0.000232704
15
+ 167.000 0.000248308
16
+ 168.000 0.000241170
17
+ 169.000 0.000265181
18
+ 170.000 0.000379874
19
+ 171.000 0.000255772
20
+ 172.000 0.000621409
21
+ 173.000 0.00109901
22
+ 174.000 0.00140740
23
+ 175.000 0.00184703
24
+ 176.000 0.00275733
25
+ 177.000 0.00436359
26
+ 178.000 0.00677930
27
+ 179.000 0.0100962
28
+ 180.000 0.0146472
29
+ 181.000 0.0209196
30
+ 182.000 0.0296101
31
+ 183.000 0.0412875
32
+ 184.000 0.0562303
33
+ 185.000 0.0740649
34
+ 186.000 0.0945498
35
+ 187.000 0.117659
36
+ 188.000 0.142528
37
+ 189.000 0.168455
38
+ 190.000 0.194897
39
+ 191.000 0.221390
40
+ 192.000 0.246519
41
+ 193.000 0.269192
42
+ 194.000 0.288602
43
+ 195.000 0.301803
44
+ 196.000 0.305428
45
+ 197.000 0.295828
46
+ 198.000 0.269425
47
+ 199.000 0.226404
48
+ 200.000 0.174608
49
+ 201.000 0.124217
50
+ 202.000 0.0838537
51
+ 203.000 0.0570717
52
+ 204.000 0.0416032
53
+ 205.000 0.0325555
54
+ 206.000 0.0267497
55
+ 207.000 0.0224701
56
+ 208.000 0.0189209
57
+ 209.000 0.0157723
58
+ 210.000 0.0131231
59
+ 211.000 0.0110494
60
+ 212.000 0.00951424
@@ -0,0 +1,64 @@
1
+ # EIS_EFFArea_B.005
2
+ # EIS Effective Area
3
+ # Mon Apr 23 10:40:45 2007
4
+ # Front filter data file: EIS_FFA_B_Trans.003
5
+ # SEF data file: EIS_SEFTrans.002
6
+ # Mirror data file: EIS_MirrorRefl_B.003
7
+ # Grating data file: EIS_GratingRefl_B.003
8
+ # Mirror area: 88.4
9
+ # Groove efficiency: 1.00
10
+ # CCD qe: 0.64
11
+ # Spider trans: 0.80
12
+ # Mesh trans: 1.00
13
+ # Thu Apr 14 08:08:21 EDT 2011
14
+ # Extrapolated [linear extrapolation in log(y)]
15
+ # one new point at 213 Angstroms (JTM)
16
+ 165.000 0.000174973
17
+ 166.000 0.000232704
18
+ 167.000 0.000248308
19
+ 168.000 0.000241170
20
+ 169.000 0.000265181
21
+ 170.000 0.000379874
22
+ 171.000 0.000255772
23
+ 172.000 0.000621409
24
+ 173.000 0.00109901
25
+ 174.000 0.00140740
26
+ 175.000 0.00184703
27
+ 176.000 0.00275733
28
+ 177.000 0.00436359
29
+ 178.000 0.00677930
30
+ 179.000 0.0100962
31
+ 180.000 0.0146472
32
+ 181.000 0.0209196
33
+ 182.000 0.0296101
34
+ 183.000 0.0412875
35
+ 184.000 0.0562303
36
+ 185.000 0.0740649
37
+ 186.000 0.0945498
38
+ 187.000 0.117659
39
+ 188.000 0.142528
40
+ 189.000 0.168455
41
+ 190.000 0.194897
42
+ 191.000 0.221390
43
+ 192.000 0.246519
44
+ 193.000 0.269192
45
+ 194.000 0.288602
46
+ 195.000 0.301803
47
+ 196.000 0.305428
48
+ 197.000 0.295828
49
+ 198.000 0.269425
50
+ 199.000 0.226404
51
+ 200.000 0.174608
52
+ 201.000 0.124217
53
+ 202.000 0.0838537
54
+ 203.000 0.0570717
55
+ 204.000 0.0416032
56
+ 205.000 0.0325555
57
+ 206.000 0.0267497
58
+ 207.000 0.0224701
59
+ 208.000 0.0189209
60
+ 209.000 0.0157723
61
+ 210.000 0.0131231
62
+ 211.000 0.0110494
63
+ 212.000 0.00951424
64
+ 213.000 0.00819236
@@ -0,0 +1,50 @@
1
+
2
+ The files are associated with the paper
3
+ describing the in-flight radiometric calibration of the
4
+ Hinode EIS instrument
5
+
6
+ see doi: 10.48550/arXiv.2308.06609
7
+
8
+
9
+
10
+ The IDL save files contain a structure RETURN_STR with the results of the
11
+ fits of the single spectra, merged.
12
+
13
+ The main array is return_str.total_counts which contains the
14
+ total counts in the lines for all the dates, in units of
15
+ DN/s/1arc sec
16
+
17
+ The array return_str.list_lambda has the expected wavelengths of the lines.
18
+
19
+ The arrays in data_active_sfit_2023.save
20
+ return_str.eis_sw_ar_spectra and return_str.eis_lw_ar_spectra
21
+ contain the active region averaged spectra.
22
+
23
+ The arrays in data_quiet_sfit_2023.save
24
+ return_str.eis_sw_qs_spectra and return_str.eis_lw_qs_spectra
25
+ contain the quiet Sun averaged spectra.
26
+
27
+ The wavelengths can be obtained with
28
+ eis_pixel_to_wavelength(indgen(2048),1,2)
29
+ and
30
+ eis_pixel_to_wavelength(indgen(2048),2,2)
31
+ for the 2 arcsecond slit.
32
+
33
+ Note that the spectra have not been wavelength calibrated.
34
+
35
+
36
+ They are the result of the processing of a large number of EIS data
37
+ for the in-flight calibration from 2007 to 2022.
38
+
39
+
40
+
41
+ The routine used to process Hinode EIS full spectral raster atlases
42
+ is process_atlas.pro
43
+
44
+ The routine interpol_eis_ea.pro is to be used together with
45
+ the save file fit_eis_ea_2023-05-04_smooth.sav to obtain the
46
+ time and wavelength-dependent effective area.
47
+
48
+
49
+ written by Giulio Del Zanna (GDZ), December 15 2023
50
+
@@ -0,0 +1,33 @@
1
+ Hinode/EIS effective-area data, used by eclipse/eis_calibration.py.
2
+
3
+ EIS_EffArea_A.004 (long-wavelength channel, 245-292 Angstrom)
4
+ EIS_EffArea_B.004 (short-wavelength channel, 165-212 Angstrom)
5
+ EIS_EffArea_B.005 (short-wavelength channel, 165-213 Angstrom)
6
+
7
+ Pre-flight ground-calibration effective areas, produced at MSSL in
8
+ April 2007. Copied verbatim from SolarSoft:
9
+ $SSW/hinode/eis/response/. IDL eis_ea.pro reads the latest of each,
10
+ A.004 and B.005, which is B.004 with a point at 213 Angstrom added;
11
+ eis_ltds.pro names A.004 and B.004. Column 1 is wavelength in Angstrom,
12
+ column 2 is effective area in cm^2 with the CCD quantum efficiency
13
+ already included.
14
+
15
+ Lang, J. et al. 2006, Applied Optics, 45, 8689
16
+ EIS Software Note 2, "Radiometric Calibration".
17
+
18
+ fit_eis_ea_2023-05-04_smooth.sav
19
+
20
+ Fitted time- and wavelength-dependent effective areas from the Del
21
+ Zanna et al. (2025) in-flight radiometric calibration, covering 2007
22
+ to 2022. interpol_eis_ea.pro reads the unsmoothed
23
+ fit_eis_ea_2023-05-04.sav unless given another; this is the smoothed
24
+ one, which the accompanying README_dz2025 (kept alongside it here,
25
+ verbatim) says to use. Distributed by Giulio Del Zanna.
26
+
27
+ doi: 10.48550/arXiv.2308.06609
28
+
29
+ The Del Zanna (2013) spline points and the Warren et al. (2014) exponential
30
+ decay coefficients are small enough to live in the source rather than in a
31
+ data file; their provenance is recorded in eis_calibration.py.
32
+
33
+ 13/08/2026, B.005 added 28/09/2026