dkist-processing-cryonirsp 1.4.20__py3-none-any.whl → 1.14.9rc1__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 (95) hide show
  1. changelog/232.misc.rst +1 -0
  2. dkist_processing_cryonirsp/__init__.py +1 -0
  3. dkist_processing_cryonirsp/codecs/fits.py +1 -0
  4. dkist_processing_cryonirsp/config.py +5 -1
  5. dkist_processing_cryonirsp/models/beam_boundaries.py +1 -0
  6. dkist_processing_cryonirsp/models/constants.py +31 -30
  7. dkist_processing_cryonirsp/models/exposure_conditions.py +6 -5
  8. dkist_processing_cryonirsp/models/fits_access.py +40 -0
  9. dkist_processing_cryonirsp/models/parameters.py +14 -26
  10. dkist_processing_cryonirsp/models/tags.py +1 -0
  11. dkist_processing_cryonirsp/models/task_name.py +1 -0
  12. dkist_processing_cryonirsp/parsers/check_for_gains.py +1 -0
  13. dkist_processing_cryonirsp/parsers/cryonirsp_l0_fits_access.py +40 -47
  14. dkist_processing_cryonirsp/parsers/cryonirsp_l1_fits_access.py +1 -0
  15. dkist_processing_cryonirsp/parsers/exposure_conditions.py +14 -13
  16. dkist_processing_cryonirsp/parsers/map_repeats.py +1 -0
  17. dkist_processing_cryonirsp/parsers/measurements.py +29 -16
  18. dkist_processing_cryonirsp/parsers/modstates.py +5 -1
  19. dkist_processing_cryonirsp/parsers/optical_density_filters.py +1 -0
  20. dkist_processing_cryonirsp/parsers/polarimetric_check.py +18 -7
  21. dkist_processing_cryonirsp/parsers/scan_step.py +12 -4
  22. dkist_processing_cryonirsp/parsers/time.py +7 -7
  23. dkist_processing_cryonirsp/parsers/wavelength.py +6 -1
  24. dkist_processing_cryonirsp/tasks/__init__.py +2 -1
  25. dkist_processing_cryonirsp/tasks/assemble_movie.py +1 -0
  26. dkist_processing_cryonirsp/tasks/bad_pixel_map.py +6 -5
  27. dkist_processing_cryonirsp/tasks/beam_boundaries_base.py +12 -11
  28. dkist_processing_cryonirsp/tasks/ci_beam_boundaries.py +1 -0
  29. dkist_processing_cryonirsp/tasks/ci_science.py +1 -0
  30. dkist_processing_cryonirsp/tasks/cryonirsp_base.py +2 -3
  31. dkist_processing_cryonirsp/tasks/dark.py +5 -4
  32. dkist_processing_cryonirsp/tasks/gain.py +7 -6
  33. dkist_processing_cryonirsp/tasks/instrument_polarization.py +17 -16
  34. dkist_processing_cryonirsp/tasks/l1_output_data.py +1 -0
  35. dkist_processing_cryonirsp/tasks/linearity_correction.py +1 -0
  36. dkist_processing_cryonirsp/tasks/make_movie_frames.py +3 -2
  37. dkist_processing_cryonirsp/tasks/mixin/corrections.py +1 -0
  38. dkist_processing_cryonirsp/tasks/mixin/shift_measurements.py +9 -2
  39. dkist_processing_cryonirsp/tasks/parse.py +70 -52
  40. dkist_processing_cryonirsp/tasks/quality_metrics.py +15 -14
  41. dkist_processing_cryonirsp/tasks/science_base.py +8 -6
  42. dkist_processing_cryonirsp/tasks/sp_beam_boundaries.py +2 -1
  43. dkist_processing_cryonirsp/tasks/sp_geometric.py +11 -10
  44. dkist_processing_cryonirsp/tasks/sp_science.py +1 -0
  45. dkist_processing_cryonirsp/tasks/sp_solar_gain.py +15 -12
  46. dkist_processing_cryonirsp/tasks/sp_wavelength_calibration.py +300 -0
  47. dkist_processing_cryonirsp/tasks/write_l1.py +59 -38
  48. dkist_processing_cryonirsp/tests/conftest.py +75 -53
  49. dkist_processing_cryonirsp/tests/header_models.py +62 -11
  50. dkist_processing_cryonirsp/tests/local_trial_workflows/l0_cals_only.py +26 -46
  51. dkist_processing_cryonirsp/tests/local_trial_workflows/l0_to_l1.py +26 -47
  52. dkist_processing_cryonirsp/tests/local_trial_workflows/linearize_only.py +3 -3
  53. dkist_processing_cryonirsp/tests/local_trial_workflows/local_trial_helpers.py +57 -26
  54. dkist_processing_cryonirsp/tests/test_assemble_movie.py +4 -5
  55. dkist_processing_cryonirsp/tests/test_assemble_qualilty.py +5 -1
  56. dkist_processing_cryonirsp/tests/test_bad_pixel_maps.py +4 -5
  57. dkist_processing_cryonirsp/tests/test_ci_beam_boundaries.py +4 -5
  58. dkist_processing_cryonirsp/tests/test_ci_science.py +4 -5
  59. dkist_processing_cryonirsp/tests/test_corrections.py +5 -6
  60. dkist_processing_cryonirsp/tests/test_cryo_base.py +4 -6
  61. dkist_processing_cryonirsp/tests/test_cryo_constants.py +7 -3
  62. dkist_processing_cryonirsp/tests/test_dark.py +7 -8
  63. dkist_processing_cryonirsp/tests/test_fits_access.py +44 -0
  64. dkist_processing_cryonirsp/tests/test_gain.py +7 -8
  65. dkist_processing_cryonirsp/tests/test_instrument_polarization.py +19 -10
  66. dkist_processing_cryonirsp/tests/test_linearity_correction.py +5 -4
  67. dkist_processing_cryonirsp/tests/test_make_movie_frames.py +2 -3
  68. dkist_processing_cryonirsp/tests/test_parameters.py +23 -28
  69. dkist_processing_cryonirsp/tests/test_parse.py +48 -12
  70. dkist_processing_cryonirsp/tests/test_quality.py +2 -3
  71. dkist_processing_cryonirsp/tests/test_sp_beam_boundaries.py +5 -5
  72. dkist_processing_cryonirsp/tests/test_sp_geometric.py +5 -6
  73. dkist_processing_cryonirsp/tests/test_sp_make_movie_frames.py +2 -3
  74. dkist_processing_cryonirsp/tests/test_sp_science.py +4 -5
  75. dkist_processing_cryonirsp/tests/test_sp_solar.py +6 -5
  76. dkist_processing_cryonirsp/tests/{test_sp_dispersion_axis_correction.py → test_sp_wavelength_calibration.py} +11 -29
  77. dkist_processing_cryonirsp/tests/test_trial_create_quality_report.py +1 -1
  78. dkist_processing_cryonirsp/tests/test_workflows.py +1 -0
  79. dkist_processing_cryonirsp/tests/test_write_l1.py +29 -31
  80. dkist_processing_cryonirsp/workflows/__init__.py +1 -0
  81. dkist_processing_cryonirsp/workflows/ci_l0_processing.py +9 -5
  82. dkist_processing_cryonirsp/workflows/sp_l0_processing.py +12 -8
  83. dkist_processing_cryonirsp/workflows/trial_workflows.py +12 -11
  84. dkist_processing_cryonirsp-1.14.9rc1.dist-info/METADATA +552 -0
  85. dkist_processing_cryonirsp-1.14.9rc1.dist-info/RECORD +115 -0
  86. {dkist_processing_cryonirsp-1.4.20.dist-info → dkist_processing_cryonirsp-1.14.9rc1.dist-info}/WHEEL +1 -1
  87. docs/ci_science_calibration.rst +10 -0
  88. docs/conf.py +1 -0
  89. docs/index.rst +1 -0
  90. docs/sp_science_calibration.rst +7 -0
  91. docs/wavelength_calibration.rst +62 -0
  92. dkist_processing_cryonirsp/tasks/sp_dispersion_axis_correction.py +0 -492
  93. dkist_processing_cryonirsp-1.4.20.dist-info/METADATA +0 -452
  94. dkist_processing_cryonirsp-1.4.20.dist-info/RECORD +0 -111
  95. {dkist_processing_cryonirsp-1.4.20.dist-info → dkist_processing_cryonirsp-1.14.9rc1.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,9 @@
1
1
  import json
2
- import os
3
2
  from collections.abc import Iterable
4
3
  from dataclasses import asdict
5
4
  from dataclasses import dataclass
6
5
  from dataclasses import field
7
6
  from dataclasses import is_dataclass
8
- from pathlib import Path
9
7
  from random import randint
10
8
  from typing import Any
11
9
  from typing import Callable
@@ -21,8 +19,16 @@ from dkist_data_simulator.spec122 import Spec122Dataset
21
19
  from dkist_header_validator import spec122_validator
22
20
  from dkist_header_validator.translator import sanitize_to_spec214_level1
23
21
  from dkist_header_validator.translator import translate_spec122_to_spec214_l0
22
+ from dkist_processing_common.codecs.array import array_encoder
23
+ from dkist_processing_common.codecs.basemodel import basemodel_encoder
24
24
  from dkist_processing_common.codecs.fits import fits_array_encoder
25
+ from dkist_processing_common.models.input_dataset import InputDatasetFilePointer
26
+ from dkist_processing_common.models.input_dataset import InputDatasetObject
27
+ from dkist_processing_common.models.input_dataset import InputDatasetPartDocumentList
25
28
  from dkist_processing_common.tasks import WorkflowTaskBase
29
+ from dkist_processing_common.tests.mock_metadata_store import fake_gql_client
30
+ from pydantic import Field
31
+ from pydantic import model_validator
26
32
 
27
33
  from dkist_processing_cryonirsp.models.constants import CryonirspConstants
28
34
  from dkist_processing_cryonirsp.models.exposure_conditions import AllowableOpticalDensityFilterNames
@@ -143,6 +149,7 @@ class CryonirspConstantsDb:
143
149
  )
144
150
  SPECTRAL_LINE: str = "CRSP Ca II H"
145
151
  MODULATOR_SPIN_MODE: str = "Continuous"
152
+ RETARDER_NAME: str = "SiO2 OC"
146
153
  STOKES_PARAMS: tuple[str] = (
147
154
  "I",
148
155
  "Q",
@@ -160,7 +167,7 @@ class CryonirspConstantsDb:
160
167
  "EXPERID3",
161
168
  )
162
169
  # These are SP defaults...
163
- AXIS_1_TYPE: str = "AWAV"
170
+ AXIS_1_TYPE: str = "AWAV-GRA"
164
171
  AXIS_2_TYPE: str = "HPLT-TAN"
165
172
  AXIS_3_TYPE: str = "HPLN-TAN"
166
173
  ROI_1_ORIGIN_X: int = 0
@@ -170,7 +177,9 @@ class CryonirspConstantsDb:
170
177
  GRATING_POSITION_DEG: float = 62.505829779431224
171
178
  GRATING_LITTROW_ANGLE_DEG: float = -5.5
172
179
  GRATING_CONSTANT: float = 31.6
173
- SOLAR_GAIN_IP_START_TIME: str = "2021-01-01T00:00:00"
180
+ SOLAR_GAIN_START_TIME: str = "2021-01-01T00:00:00"
181
+ CENTER_WAVELENGTH: float = 1074.9
182
+ SLIT_WIDTH: int = 175
174
183
 
175
184
 
176
185
  @pytest.fixture()
@@ -249,65 +258,65 @@ class WavelengthParameter:
249
258
  return hash((self.values, self.wavelength))
250
259
 
251
260
 
252
- @dataclass
253
- class FileParameter:
254
- """For parameters that are files on disk."""
255
-
256
- param_path: str
257
- is_file: bool = True
258
- objectKey: str = "not_used_because_its_already_converted"
259
- bucket: str = "not_used_because_we_dont_transfer"
260
- # Note: we have these as already-parsed file parameter (i.e., no "__file__") mainly because it allows us to have
261
- # parameter files that are outside of the workflow basepath (where they would not be able to be tagged with
262
- # PARAMETER_FILE). This is a pattern that we see in grogu testing.
263
- # A downside of this approach is that we are slightly more fragile to changes in the underlying __file__ parsing
264
- # in `*-common`. Apologies to any future devs who run into this problem. To fix it you'll need to make
265
- # downstream fixtures aware of the actual files so they can be tagged prior to the instantiation of the
266
- # Parameter object on some Task.
261
+ class FileObject(InputDatasetObject):
262
+ """For files on disk, with attributes overridden to have defaults."""
263
+
264
+ bucket: str | None = None
265
+ object_key: str | None = None
266
+
267
+ def __hash__(self):
268
+ return hash((self.bucket, self.object_key, self.tag))
269
+
270
+
271
+ class FileParameter(InputDatasetFilePointer):
272
+ """For parameters that are files, with additional attributes to make FileObjects."""
273
+
274
+ object_key: str | None = Field(
275
+ default="dummy_default_value", exclude=True
276
+ ) # Not necessary, but useful for GROGU
277
+ file_pointer: FileObject = Field(default_factory=lambda: FileObject(), alias="__file__")
278
+
279
+ @model_validator(mode="after")
280
+ def _populate_file_object(self):
281
+ self.file_pointer.bucket = "not_used_because_we_dont_transfer"
282
+ self.file_pointer.object_key = self.object_key
283
+ self.file_pointer.tag = CryonirspTag.parameter((self.object_key))
284
+ return self
267
285
 
268
286
 
269
287
  # These constants are used to prevent name errors in _create_parameter_files
270
- # and in CryonirspTestingParameters
288
+ # and in CryonirspTestingParameters.
271
289
  LINEARIZATION_THRESHOLDS_CI = "cryonirsp_linearization_thresholds_ci.npy"
272
290
  LINEARIZATION_THRESHOLDS_SP = "cryonirsp_linearization_thresholds_sp.npy"
273
- SOLAR_ATLAS = "cryonirsp_solar_atlas.npy"
274
- TELLURIC_ATLAS = "cryonirsp_telluric_atlas.npy"
275
291
 
276
292
 
277
- def _create_parameter_files(param_path: Path) -> None:
293
+ def _create_parameter_files(task: WorkflowTaskBase) -> None:
278
294
  # linearization thresholds
279
295
  thresh = np.ones((10, 10), dtype=np.float64) * 100.0
280
- np.save(os.path.join(param_path, LINEARIZATION_THRESHOLDS_CI), thresh)
281
- np.save(os.path.join(param_path, LINEARIZATION_THRESHOLDS_SP), thresh)
282
-
283
- # solar and telluric atlases
284
- atlas_wavelengths = range(300, 16600)
285
- atlas_transmission = np.random.rand(16300)
286
- atlas = [atlas_wavelengths, atlas_transmission]
287
- np.save(os.path.join(param_path, SOLAR_ATLAS), atlas)
288
- np.save(os.path.join(param_path, TELLURIC_ATLAS), atlas)
296
+ task.write(
297
+ data=thresh, tags=CryonirspTag.parameter(LINEARIZATION_THRESHOLDS_CI), encoder=array_encoder
298
+ )
299
+ task.write(
300
+ data=thresh, tags=CryonirspTag.parameter(LINEARIZATION_THRESHOLDS_SP), encoder=array_encoder
301
+ )
289
302
 
290
303
 
291
304
  TestingParameters = TypeVar("TestingParameters", bound="CryonirspTestingParameters")
292
305
 
293
306
 
294
307
  def cryonirsp_testing_parameters_factory(
295
- param_path: Path | str = "", create_files: bool = True
308
+ task: WorkflowTaskBase, create_files: bool = True
296
309
  ) -> TestingParameters:
297
310
  """Create the InputDatasetParameterValue objects and write the parameter files."""
298
- if isinstance(param_path, str):
299
- param_path = Path(param_path)
300
- absolute_path = param_path.absolute()
301
311
 
302
312
  if create_files:
303
- _create_parameter_files(absolute_path)
313
+ _create_parameter_files(task=task)
304
314
 
305
315
  @dataclass
306
316
  class CryonirspTestingParameters:
307
317
  cryonirsp_polcal_num_spatial_bins: int = 1
308
318
  cryonirsp_polcal_num_spectral_bins: int = 1
309
319
  cryonirsp_polcal_pac_fit_mode: str = "use_M12_I_sys_per_step"
310
- cryonirsp_polcal_pac_init_set: str = "OCCal_VIS"
311
320
  cryonirsp_geo_upsample_factor: int = 100
312
321
  cryonirsp_geo_max_shift: int = 80
313
322
  cryonirsp_geo_poly_fit_order: int = 3
@@ -339,7 +348,7 @@ def cryonirsp_testing_parameters_factory(
339
348
  cryonirsp_fringe_correction_lowpass_cutoff_period: float = 40.0
340
349
  cryonirsp_linearization_thresholds_ci: FileParameter = field(
341
350
  default_factory=lambda: FileParameter(
342
- param_path=str(absolute_path / LINEARIZATION_THRESHOLDS_CI)
351
+ object_key=LINEARIZATION_THRESHOLDS_CI,
343
352
  )
344
353
  )
345
354
  cryonirsp_linearization_polyfit_coeffs_ci: list[float] = field(
@@ -347,7 +356,7 @@ def cryonirsp_testing_parameters_factory(
347
356
  )
348
357
  cryonirsp_linearization_thresholds_sp: FileParameter = field(
349
358
  default_factory=lambda: FileParameter(
350
- param_path=str(absolute_path / LINEARIZATION_THRESHOLDS_SP)
359
+ object_key=LINEARIZATION_THRESHOLDS_SP,
351
360
  )
352
361
  )
353
362
  cryonirsp_linearization_polyfit_coeffs_sp: list[float] = field(
@@ -363,14 +372,18 @@ def cryonirsp_testing_parameters_factory(
363
372
  cryonirsp_linearization_optical_density_filter_attenuation_g408: WavelengthParameter = (
364
373
  WavelengthParameter(values=(-4.26, -4.26, -4.26, -4.26))
365
374
  )
366
- cryonirsp_solar_atlas: FileParameter = field(
367
- default_factory=lambda: FileParameter(param_path=str(absolute_path / SOLAR_ATLAS))
368
- )
369
- cryonirsp_telluric_atlas: FileParameter = field(
370
- default_factory=lambda: FileParameter(param_path=str(absolute_path / TELLURIC_ATLAS))
371
- )
372
375
  cryonirsp_camera_mirror_focal_length_mm: float = 932.0
373
376
  cryonirsp_pixel_pitch_micron: float = 18.0
377
+ cryonirsp_wavecal_atlas_download_config: dict[str, str] = field(
378
+ default_factory=lambda: {
379
+ "base_url": "https://g-a36282.cd214.a567.data.globus.org/atlas/",
380
+ "telluric_reference_atlas_file_name": "telluric_reference_atlas.npy",
381
+ "telluric_reference_atlas_hash_id": "md5:8db5e12508b293bca3495d81a0747447",
382
+ "solar_reference_atlas_file_name": "solar_reference_atlas.npy",
383
+ "solar_reference_atlas_hash_id": "md5:84ab4c50689ef235fe5ed4f7ee905ca0",
384
+ }
385
+ )
386
+ cryonirsp_wavecal_fraction_of_unweighted_edge_pixels: int = 10
374
387
 
375
388
  return CryonirspTestingParameters
376
389
 
@@ -387,11 +400,15 @@ def testing_obs_ip_start_time() -> str:
387
400
 
388
401
  @pytest.fixture(scope="session")
389
402
  def input_dataset_document_simple_parameters_part():
390
- def get_input_dataset_parameters_part(parameters):
403
+ """Convert a dataclass of parameterValues into an actual input dataset parameters part."""
404
+
405
+ def make_input_dataset_parameters_part(parameters):
391
406
  parameters_list = []
392
407
 
393
408
  value_id = randint(1000, 2000)
394
409
  for pn, pv in asdict(parameters).items():
410
+ if isinstance(pv, FileParameter):
411
+ pv = pv.model_dump()
395
412
  values = [
396
413
  {
397
414
  "parameterValueId": value_id,
@@ -403,7 +420,7 @@ def input_dataset_document_simple_parameters_part():
403
420
  parameters_list.append(parameter)
404
421
  return parameters_list
405
422
 
406
- return get_input_dataset_parameters_part
423
+ return make_input_dataset_parameters_part
407
424
 
408
425
 
409
426
  @pytest.fixture(scope="session")
@@ -412,6 +429,8 @@ def assign_input_dataset_doc_to_task(
412
429
  testing_wavelength,
413
430
  testing_obs_ip_start_time,
414
431
  ):
432
+ """Load the parameters the way that tasks load the parameters in task init."""
433
+
415
434
  def update_task(
416
435
  task,
417
436
  parameters,
@@ -419,12 +438,15 @@ def assign_input_dataset_doc_to_task(
419
438
  arm_id: str = "SP",
420
439
  obs_ip_start_time=testing_obs_ip_start_time,
421
440
  ):
422
- doc_path = task.scratch.workflow_base_path / "dataset_doc.json"
423
- with open(doc_path, "w") as f:
424
- f.write(json.dumps(input_dataset_document_simple_parameters_part(parameters)))
425
- task.tag(doc_path, CryonirspTag.input_dataset_parameters())
441
+ task.write(
442
+ data=InputDatasetPartDocumentList(
443
+ doc_list=input_dataset_document_simple_parameters_part(parameters)
444
+ ),
445
+ tags=CryonirspTag.input_dataset_parameters(),
446
+ encoder=basemodel_encoder,
447
+ )
426
448
  task.parameters = parameter_class(
427
- task.input_dataset_parameters,
449
+ scratch=task.scratch,
428
450
  wavelength=testing_wavelength,
429
451
  arm_id=arm_id,
430
452
  obs_ip_start_time=obs_ip_start_time,
@@ -1,18 +1,16 @@
1
1
  """
2
2
  Model header objects
3
3
  """
4
+
4
5
  import datetime
5
6
  import random
6
7
  import uuid
7
8
  from random import choice
8
9
 
9
10
  import numpy as np
10
- import pytest
11
- from astropy.io import fits
12
11
  from astropy.wcs import WCS
13
12
  from dkist_data_simulator.dataset import key_function
14
13
  from dkist_data_simulator.spec122 import Spec122Dataset
15
- from dkist_header_validator import spec122_validator
16
14
 
17
15
  from dkist_processing_cryonirsp.models.exposure_conditions import AllowableOpticalDensityFilterNames
18
16
  from dkist_processing_cryonirsp.models.exposure_conditions import ExposureConditions
@@ -24,7 +22,8 @@ class CryonirspHeaders(Spec122Dataset):
24
22
  dataset_shape: tuple[int, ...],
25
23
  array_shape: tuple[int, ...],
26
24
  time_delta: 10,
27
- instrument: str = "cryo-nirsp",
25
+ instrument: str = "cryonirsp",
26
+ exp_time: float = 15.0,
28
27
  **kwargs,
29
28
  ):
30
29
  super().__init__(
@@ -50,6 +49,20 @@ class CryonirspHeaders(Spec122Dataset):
50
49
  self.add_constant_key("CRSP_053", 1083.0)
51
50
  self.add_constant_key("CRSP_054", 1.0)
52
51
 
52
+ self.add_constant_key("CAM__004", exp_time)
53
+
54
+ self.add_constant_key("CAM__001", "camera_id")
55
+ self.add_constant_key("CAM__002", "camera_name")
56
+ self.add_constant_key("CAM__003", 1)
57
+ self.add_constant_key("CAM__009", 1)
58
+ self.add_constant_key("CAM__010", 1)
59
+ self.add_constant_key("CAM__011", 1)
60
+ self.add_constant_key("CAM__012", 1)
61
+ self.add_constant_key("ID___014", "v1")
62
+ self.add_constant_key("TELTRACK", "Fixed Solar Rotation Tracking")
63
+ self.add_constant_key("TTBLTRCK", "fixed angle on sun")
64
+ self.add_constant_key("CAM__014", 10) # num_raw_frames_per_fpa
65
+
53
66
  @key_function("CRSP_042")
54
67
  # current modstate
55
68
  def current_modstate(self, key: str):
@@ -172,6 +185,13 @@ class CryonirspHeadersValidDarkFrames(CryonirspHeaders):
172
185
  self.add_constant_key("CRSP_041", 1)
173
186
  self.add_constant_key("CRSP_042", 1)
174
187
 
188
+ self.add_constant_key("TELSCAN", "Raster")
189
+ self.add_constant_key("PAC__002", "lamp")
190
+ self.add_constant_key("PAC__003", "on")
191
+ self.add_constant_key("PAC__004", "Sapphire Polarizer")
192
+ self.add_constant_key("PAC__006", "SiO2 OC")
193
+ self.add_constant_key("PAC__008", "FieldStop (5arcmin)")
194
+
175
195
 
176
196
  class CryonirspHeadersValidLampGainFrames(CryonirspHeaders):
177
197
  def __init__(
@@ -226,6 +246,10 @@ class CryonirspHeadersValidCISolarGainFrames(CryonirspHeaders):
226
246
  self.add_constant_key("CRSP_007", 1)
227
247
  # lamp (clear, lamp, undefined)
228
248
  self.add_constant_key("PAC__002", "clear")
249
+ self.add_constant_key("PAC__003", "off")
250
+ self.add_constant_key("PAC__004", "clear")
251
+ self.add_constant_key("PAC__006", "clear")
252
+ self.add_constant_key("PAC__008", "FieldStop (5arcmin)")
229
253
  self.add_constant_key("TELSCAN", "Raster")
230
254
  # inst prog id
231
255
  self.add_constant_key("ID___004")
@@ -259,6 +283,10 @@ class CryonirspHeadersValidSPSolarGainFrames(CryonirspHeaders):
259
283
  self.add_constant_key("CRSP_007", 1)
260
284
  # lamp (clear, lamp, undefined)
261
285
  self.add_constant_key("PAC__002", "clear")
286
+ self.add_constant_key("PAC__003", "off")
287
+ self.add_constant_key("PAC__004", "clear")
288
+ self.add_constant_key("PAC__006", "clear")
289
+ self.add_constant_key("PAC__008", "FieldStop (5arcmin)")
262
290
  self.add_constant_key("TELSCAN", "Raster")
263
291
  # inst prog id
264
292
  self.add_constant_key("ID___004")
@@ -374,6 +402,8 @@ class SimpleModulatedHeaders(CryonirspHeaders):
374
402
  ),
375
403
  start_date: str = "2023-01-01T01:23:45",
376
404
  modstate_length_sec: float = 0.5,
405
+ center_wavelength: float = 1080.0,
406
+ slit_width: float = 52.0,
377
407
  ):
378
408
  dataset_shape = (1, *array_shape)
379
409
  super().__init__(
@@ -395,9 +425,11 @@ class SimpleModulatedHeaders(CryonirspHeaders):
395
425
  self.add_constant_key("CRSP_042", modstate)
396
426
  self.add_constant_key("CAM__004", exposure_condition.exposure_time)
397
427
  self.add_constant_key("CRSP_048", exposure_condition.filter_name)
428
+ self.add_constant_key("CRSP_053", center_wavelength)
398
429
  self.add_constant_key("CRSP_074", grating_angle_deg)
399
430
  self.add_constant_key("CRSP_079", grating_littrow_angle)
400
431
  self.add_constant_key("CRSP_077", grating_constant)
432
+ self.add_constant_key("CRSP_082", slit_width)
401
433
  self.add_constant_key("CRVAL1", CRVAL1)
402
434
  self.add_constant_key("CRPIX1", CRPIX1)
403
435
  self.add_constant_key("CDELT1", CDELT1)
@@ -445,6 +477,8 @@ class ModulatedSolarGainHeaders(SimpleModulatedHeaders):
445
477
  modstate_length_sec: float = 0.5,
446
478
  num_modstates: int = 1,
447
479
  modstate: int = 1,
480
+ center_wavelength: float = 1080.0,
481
+ slit_width: float = 52.0,
448
482
  ):
449
483
  super().__init__(
450
484
  num_modstates=num_modstates,
@@ -454,6 +488,8 @@ class ModulatedSolarGainHeaders(SimpleModulatedHeaders):
454
488
  exposure_condition=exposure_condition,
455
489
  start_date=start_date,
456
490
  modstate_length_sec=modstate_length_sec,
491
+ center_wavelength=center_wavelength,
492
+ slit_width=slit_width,
457
493
  )
458
494
 
459
495
  self.add_constant_key("PAC__002", "clear")
@@ -469,6 +505,9 @@ class ModulatedSolarGainHeaders(SimpleModulatedHeaders):
469
505
  self.add_constant_key("CRSP_007", 1)
470
506
  # inst prog id
471
507
  self.add_constant_key("ID___004")
508
+ self.add_constant_key("PAC__004", "clear")
509
+ self.add_constant_key("PAC__006", "clear")
510
+ self.add_constant_key("PAC__008", "FieldStop (5arcmin)")
472
511
 
473
512
 
474
513
  class ModulatedDarkHeaders(SimpleModulatedHeaders):
@@ -502,6 +541,12 @@ class ModulatedDarkHeaders(SimpleModulatedHeaders):
502
541
  # inst prog id
503
542
  self.add_constant_key("ID___004")
504
543
  self.add_constant_key("WAVELNTH", 0.0)
544
+ self.add_constant_key("TELSCAN", "Raster")
545
+ self.add_constant_key("PAC__002", "lamp")
546
+ self.add_constant_key("PAC__003", "on")
547
+ self.add_constant_key("PAC__004", "Sapphire Polarizer")
548
+ self.add_constant_key("PAC__006", "SiO2 OC")
549
+ self.add_constant_key("PAC__008", "FieldStop (5arcmin)")
505
550
 
506
551
 
507
552
  class ModulatedPolcalHeaders(SimpleModulatedHeaders):
@@ -536,13 +581,15 @@ class ModulatedPolcalHeaders(SimpleModulatedHeaders):
536
581
  self.add_constant_key("PAC__007", "0.0")
537
582
  self.add_constant_key("CRSP_044", "Continuous")
538
583
 
539
- if extra_headers != None:
540
- for header, value in extra_headers.items():
541
- self.add_constant_key(header, value)
542
- else:
543
- self.add_constant_key("PAC__004", "Sapphire Polarizer")
544
- self.add_constant_key("PAC__006", "clear")
545
- self.add_constant_key("PAC__008", "FieldStop (5arcmin)")
584
+ default_pac_values = {
585
+ "PAC__004": "Sapphire Polarizer",
586
+ "PAC__006": "clear",
587
+ "PAC__008": "FieldStop (5arcmin)",
588
+ }
589
+ if extra_headers is None:
590
+ extra_headers = dict()
591
+ for header, value in (default_pac_values | extra_headers).items():
592
+ self.add_constant_key(header, value)
546
593
 
547
594
 
548
595
  class ModulatedObserveHeaders(SimpleModulatedHeaders):
@@ -563,6 +610,8 @@ class ModulatedObserveHeaders(SimpleModulatedHeaders):
563
610
  start_date: str = "2023-01-01T01:23:45",
564
611
  modstate_length_sec: float = 0.5,
565
612
  meas_num: int = 1,
613
+ center_wavelength: float = 1080.0,
614
+ slit_width: float = 52.0,
566
615
  ):
567
616
  super().__init__(
568
617
  num_modstates=num_modstates,
@@ -572,6 +621,8 @@ class ModulatedObserveHeaders(SimpleModulatedHeaders):
572
621
  exposure_condition=exposure_condition,
573
622
  start_date=start_date,
574
623
  modstate_length_sec=modstate_length_sec,
624
+ center_wavelength=center_wavelength,
625
+ slit_width=slit_width,
575
626
  )
576
627
 
577
628
  self.num_map_scans = num_map_scans
@@ -1,5 +1,4 @@
1
1
  import argparse
2
- import json
3
2
  import os
4
3
  import sys
5
4
  from datetime import datetime
@@ -12,9 +11,10 @@ from dkist_processing_common.tasks import WorkflowTaskBase
12
11
  from dkist_service_configuration.logging import logger
13
12
 
14
13
  from dkist_processing_cryonirsp.models.constants import CryonirspBudName
14
+ from dkist_processing_cryonirsp.models.fits_access import CryonirspMetadataKey
15
15
  from dkist_processing_cryonirsp.models.tags import CryonirspTag
16
16
  from dkist_processing_cryonirsp.tasks import CIBeamBoundariesCalibration
17
- from dkist_processing_cryonirsp.tasks import SPDispersionAxisCorrection
17
+ from dkist_processing_cryonirsp.tasks import SPWavelengthCalibration
18
18
  from dkist_processing_cryonirsp.tasks.bad_pixel_map import BadPixelMapCalibration
19
19
  from dkist_processing_cryonirsp.tasks.cryonirsp_base import CryonirspTaskBase
20
20
  from dkist_processing_cryonirsp.tasks.dark import DarkCalibration
@@ -33,13 +33,7 @@ from dkist_processing_cryonirsp.tasks.parse import ParseL0CryonirspSPLinearizedD
33
33
  from dkist_processing_cryonirsp.tasks.sp_beam_boundaries import SPBeamBoundariesCalibration
34
34
  from dkist_processing_cryonirsp.tasks.sp_geometric import SPGeometricCalibration
35
35
  from dkist_processing_cryonirsp.tasks.sp_solar_gain import SPSolarGainCalibration
36
- from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
37
- create_input_dataset_parameter_document,
38
- )
39
36
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import DBAccess
40
- from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
41
- load_parsing_task,
42
- )
43
37
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
44
38
  LoadBadPixelMap,
45
39
  )
@@ -47,9 +41,6 @@ from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers
47
41
  LoadBeamBoundaryCal,
48
42
  )
49
43
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import LoadDarkCal
50
- from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
51
- LoadDispersionAxisCorrection,
52
- )
53
44
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
54
45
  LoadGeometricCal,
55
46
  )
@@ -62,7 +53,7 @@ from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers
62
53
  )
63
54
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import LoadSolarCal
64
55
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
65
- save_parsing_task,
56
+ LoadWavelengthCorrection,
66
57
  )
67
58
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
68
59
  SaveBadPixelMap,
@@ -71,9 +62,6 @@ from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers
71
62
  SaveBeamBoundaryCal,
72
63
  )
73
64
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import SaveDarkCal
74
- from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
75
- SaveDispersionAxisCorrection,
76
- )
77
65
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
78
66
  SaveGeometricCal,
79
67
  )
@@ -85,6 +73,18 @@ from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers
85
73
  SaveLinearizedFiles,
86
74
  )
87
75
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import SaveSolarCal
76
+ from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
77
+ SaveWavelengthCorrection,
78
+ )
79
+ from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
80
+ create_input_dataset_parameter_document,
81
+ )
82
+ from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
83
+ load_parsing_task,
84
+ )
85
+ from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
86
+ save_parsing_task,
87
+ )
88
88
  from dkist_processing_cryonirsp.tests.local_trial_workflows.local_trial_helpers import (
89
89
  tag_inputs_task,
90
90
  )
@@ -134,7 +134,7 @@ def tag_linearized_inputs_task(suffix: str):
134
134
  hdu = hdul[0]
135
135
  else:
136
136
  hdu = hdul[1]
137
- arm_id = hdu.header["CNARMID"]
137
+ arm_id = hdu.header[CryonirspMetadataKey.arm_id]
138
138
  self.constants._update({CryonirspBudName.arm_id.value: arm_id})
139
139
 
140
140
  return TagLinearizedInputs
@@ -170,21 +170,6 @@ def spoof_obs_lin_parsed_constants(
170
170
  return SetCalOnlyConstants
171
171
 
172
172
 
173
- def setup_APM_config() -> None:
174
- mesh_config = {
175
- "system-monitoring-log-apm": {
176
- "mesh_address": "system-monitoring-log-apm.service.sim.consul",
177
- "mesh_port": 8200,
178
- },
179
- "automated-processing-scratch-inventory": {"mesh_address": "localhost", "mesh_port": 6379},
180
- "internal-api-gateway": {"mesh_address": "localhost", "mesh_port": 80},
181
- }
182
- apm_options = {"TRANSACTION_MAX_SPANS": 10000}
183
- os.environ["MESH_CONFIG"] = json.dumps(mesh_config)
184
- os.environ["ELASTIC_APM_ENABLED"] = "true"
185
- os.environ["ELASTIC_APM_OTHER_OPTIONS"] = json.dumps(apm_options)
186
-
187
-
188
173
  def CI_workflow(
189
174
  manual_processing_run: ManualProcessing,
190
175
  load_beam_boundaries: bool = False,
@@ -224,7 +209,7 @@ def SP_workflow(
224
209
  load_lamp: bool = False,
225
210
  load_geometric: bool = False,
226
211
  load_solar: bool = False,
227
- load_dispersion_correction: bool = False,
212
+ load_wavelength_correction: bool = False,
228
213
  load_inst_pol: bool = False,
229
214
  ) -> None:
230
215
  if load_beam_boundaries:
@@ -257,11 +242,11 @@ def SP_workflow(
257
242
  manual_processing_run.run_task(task=SPSolarGainCalibration)
258
243
  manual_processing_run.run_task(task=SaveSolarCal)
259
244
 
260
- if load_dispersion_correction:
261
- manual_processing_run.run_task(task=LoadDispersionAxisCorrection)
245
+ if load_wavelength_correction:
246
+ manual_processing_run.run_task(task=LoadWavelengthCorrection)
262
247
  else:
263
- manual_processing_run.run_task(task=SPDispersionAxisCorrection)
264
- manual_processing_run.run_task(task=SaveDispersionAxisCorrection)
248
+ manual_processing_run.run_task(task=SPWavelengthCalibration)
249
+ manual_processing_run.run_task(task=SaveWavelengthCorrection)
265
250
 
266
251
  if load_inst_pol:
267
252
  manual_processing_run.run_task(task=LoadInstPolCal)
@@ -287,15 +272,12 @@ def main(
287
272
  load_lamp: bool = False,
288
273
  load_geometric: bool = False,
289
274
  load_solar: bool = False,
290
- load_dispersion_correction: bool = False,
275
+ load_wavelength_correction: bool = False,
291
276
  load_inst_pol: bool = False,
292
- use_apm: bool = False,
293
277
  param_path: Path = None,
294
278
  dummy_wavelength: float = 1083.0,
295
279
  polarimetric: bool = True,
296
280
  ):
297
- if use_apm:
298
- setup_APM_config()
299
281
  with ManualProcessing(
300
282
  workflow_path=Path(scratch_path),
301
283
  recipe_run_id=recipe_run_id,
@@ -378,7 +360,7 @@ def main(
378
360
  load_lamp=load_lamp,
379
361
  load_geometric=load_geometric,
380
362
  load_solar=load_solar,
381
- load_dispersion_correction=load_dispersion_correction,
363
+ load_wavelength_correction=load_wavelength_correction,
382
364
  load_inst_pol=load_inst_pol,
383
365
  )
384
366
  elif arm_id == "CI":
@@ -481,8 +463,8 @@ if __name__ == "__main__":
481
463
  )
482
464
  parser.add_argument(
483
465
  "-W",
484
- "--load-dispersion-correction",
485
- help="Load dispersion correction solution from previously saved run",
466
+ "--load-wavelength-correction",
467
+ help="Load wavelength correction solution from previously saved run",
486
468
  action="store_true",
487
469
  )
488
470
  parser.add_argument(
@@ -491,7 +473,6 @@ if __name__ == "__main__":
491
473
  help="Load instrument polarization calibration from previously saved run",
492
474
  action="store_true",
493
475
  )
494
- parser.add_argument("-A", "--use-apm", help="Send APM spans to SIM", action="store_true")
495
476
  parser.add_argument(
496
477
  "-p",
497
478
  "--param-path",
@@ -524,9 +505,8 @@ if __name__ == "__main__":
524
505
  load_lamp=args.load_lamp,
525
506
  load_geometric=args.load_geometric,
526
507
  load_solar=args.load_solar,
527
- load_dispersion_correction=args.load_dispersion_correction,
508
+ load_wavelength_correction=args.load_wavelength_correction,
528
509
  load_inst_pol=args.load_inst_pol,
529
- use_apm=args.use_apm,
530
510
  param_path=Path(args.param_path),
531
511
  polarimetric=not args.intensity_only,
532
512
  )