From b192ea5a24ef28f10518ff47baf5a1748253e4a2 Mon Sep 17 00:00:00 2001 From: Joey Chatelain Date: Thu, 2 Jul 2026 14:55:35 -0700 Subject: [PATCH 1/2] add wavelength_unit --- tom_dataproducts/models.py | 6 +++++- tom_dataproducts/serializers.py | 1 + tom_dataproducts/sharing.py | 1 + tom_dataproducts/tests/test_api.py | 6 ++++-- tom_dataproducts/tests/tests.py | 9 ++++++--- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/tom_dataproducts/models.py b/tom_dataproducts/models.py index 0abdc617a..a491eea55 100644 --- a/tom_dataproducts/models.py +++ b/tom_dataproducts/models.py @@ -465,6 +465,7 @@ class SpectroscopyReducedDatum(ReducedDatumCommon): flux = FloatArrayField(blank=True, default=list) error = FloatArrayField(blank=True, default=list) flux_unit = models.TextField(blank=True, default="") + wavelength_unit = models.TextField(blank=True, default="") class Meta: constraints = [ @@ -554,14 +555,16 @@ def _build_photometry_reduced_datum(data: dict) -> PhotometryReducedDatum: def _build_spectroscopy_reduced_datum(data: dict) -> SpectroscopyReducedDatum: FLUX_FIELDS = {"flux", "f"} - WAVELENGTH_FIELDS = {"wavelength", "wave", "wl"} + WAVELENGTH_FIELDS = {"wavelength", "wave", "wl", "lambda"} ERROR_FIELDS = {"error", "err", "flux_error", "f_error"} FLUX_UNIT_FIELDS = {"flux_unit", "f_unit", "flux_units", "f_units"} + WAVELENGTH_UNIT_FIELDS = {"wavelength_unit", "w_unit", "wavelength_units", "w_units", "lambda_unit", "lambda_units"} flux = _pop_find_field(FLUX_FIELDS, data) or [] wavelength = _pop_find_field(WAVELENGTH_FIELDS, data) or [] error = _pop_find_field(ERROR_FIELDS, data) or [] flux_unit = _pop_find_field(FLUX_UNIT_FIELDS, data) or "" + wavelength_unit = _pop_find_field(WAVELENGTH_UNIT_FIELDS, data) or "" extra_fields = _extract_extra_fields(data, SpectroscopyReducedDatum) @@ -570,6 +573,7 @@ def _build_spectroscopy_reduced_datum(data: dict) -> SpectroscopyReducedDatum: flux=flux, error=error, flux_unit=flux_unit, + wavelength_unit=wavelength_unit, value=extra_fields, **data, ) diff --git a/tom_dataproducts/serializers.py b/tom_dataproducts/serializers.py index 87e32fbf9..d41de48a7 100644 --- a/tom_dataproducts/serializers.py +++ b/tom_dataproducts/serializers.py @@ -71,6 +71,7 @@ def _get_typed_value(self, instance): 'wavelength': instance.wavelength, 'error': instance.error, 'flux_unit': instance.flux_unit, + 'wavelength_unit': instance.wavelength_unit, 'telescope': instance.telescope, 'instrument': instance.instrument, } diff --git a/tom_dataproducts/sharing.py b/tom_dataproducts/sharing.py index 2b6b947d4..b343af7ef 100644 --- a/tom_dataproducts/sharing.py +++ b/tom_dataproducts/sharing.py @@ -205,6 +205,7 @@ def process_spectro_data_for_download(datum): 'instrument': datum.instrument, 'setup': datum.setup, 'flux_unit': datum.flux_unit, + 'wavelength_unit': datum.wavelength_unit, 'source_name': datum.source_name, } for i, (wavelength, flux) in enumerate(zip(datum.wavelength, datum.flux)): diff --git a/tom_dataproducts/tests/test_api.py b/tom_dataproducts/tests/test_api.py index 52a22e29e..d7899a494 100644 --- a/tom_dataproducts/tests/test_api.py +++ b/tom_dataproducts/tests/test_api.py @@ -226,7 +226,8 @@ def test_upload_spectroscopy_datum(self): payload = { "data_product": "", "data_type": "spectroscopy", - "value": {"flux": [123.4, 4.321], "wavelength": [150, 151], "error": [0.005], "flux_unit": "s"}, + "value": {"flux": [123.4, 4.321], "wavelength": [150, 151], "error": [0.005], "flux_unit": "s", + "wavelength_unit": "Angstrom"}, "target": self.st.id, "timestamp": "2012-02-12T01:40:47Z", } @@ -303,7 +304,7 @@ def test_spectroscopy_representation(self): """SpectroscopyReducedDatum is serialized to the legacy wire format.""" SpectroscopyReducedDatum.objects.create( target=self.st, flux=[1.0, 2.0], wavelength=[6000.0, 6001.0], - error=[0.1, 0.1], flux_unit='erg/cm2/s/A' + error=[0.1, 0.1], flux_unit='erg/cm2/s/A', wavelength_unit="um", ) result = self.client.get(reverse('api:reduceddatums-list')).data['results'][0] @@ -313,6 +314,7 @@ def test_spectroscopy_representation(self): self.assertEqual(result['value']['wavelength'], [6000.0, 6001.0]) self.assertEqual(result['value']['error'], [0.1, 0.1]) self.assertEqual(result['value']['flux_unit'], 'erg/cm2/s/A') + self.assertEqual(result['value']['wavelength_unit'], 'um') def test_astrometry_representation(self): """AstrometryReducedDatum is serialized to the legacy wire format.""" diff --git a/tom_dataproducts/tests/tests.py b/tom_dataproducts/tests/tests.py index 75f581a24..4b744234a 100644 --- a/tom_dataproducts/tests/tests.py +++ b/tom_dataproducts/tests/tests.py @@ -564,7 +564,8 @@ def test_create_spectra_with_flux_data(self): exposure_time=1000.0, flux=flux, wavelength=wavelength, - flux_unit="Å", + flux_unit="mJy", + wavelength_unit="µm", ) rd.refresh_from_db() # ensure we round trip to the database self.assertEqual(flux, rd.flux) @@ -578,7 +579,8 @@ def test_create_spectra_with_error_data(self): flux=[1.0, 2.0, 3.0, 4.0], wavelength=[1, 2, 3, 4], error=error, - flux_unit="Å", + flux_unit="erg / s / cm2 / Å", + wavelength_unit="Å", ) rd.refresh_from_db() self.assertEqual(error, rd.error) @@ -591,7 +593,8 @@ def test_create_spectra_bad_flux(self): exposure_time=1000.0, flux=[1.0, 2.0, 3.0, "asd"], wavelength=[1, 2, 3, 4], - flux_unit="cm^2", + flux_unit="erg / s / cm2 / Å", + wavelength_unit="µm", ) From 1ed3642d068a91b49bb90bc7f8f90937b27d16bb Mon Sep 17 00:00:00 2001 From: Joey Chatelain Date: Thu, 2 Jul 2026 14:57:35 -0700 Subject: [PATCH 2/2] add migration --- ...spectroscopyreduceddatum_wavelength_unit.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tom_dataproducts/migrations/0017_spectroscopyreduceddatum_wavelength_unit.py diff --git a/tom_dataproducts/migrations/0017_spectroscopyreduceddatum_wavelength_unit.py b/tom_dataproducts/migrations/0017_spectroscopyreduceddatum_wavelength_unit.py new file mode 100644 index 000000000..25a881690 --- /dev/null +++ b/tom_dataproducts/migrations/0017_spectroscopyreduceddatum_wavelength_unit.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.14 on 2026-07-02 21:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tom_dataproducts', '0016_reduceddatum_instrument_reduceddatum_telescope_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='spectroscopyreduceddatum', + name='wavelength_unit', + field=models.TextField(blank=True, default=''), + ), + ]