From 139a44f0d83707c78839b73488a4424042b786ec Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Wed, 29 Apr 2026 15:01:47 -0700 Subject: [PATCH 1/9] adds mag and mag err to what source_catalog returns --- datalab/datalab_session/analysis/source_catalog.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/datalab/datalab_session/analysis/source_catalog.py b/datalab/datalab_session/analysis/source_catalog.py index fa13d5e..0de98fe 100644 --- a/datalab/datalab_session/analysis/source_catalog.py +++ b/datalab/datalab_session/analysis/source_catalog.py @@ -4,6 +4,7 @@ from datalab.datalab_session.exceptions import ClientAlertException from datalab.datalab_session.utils.file_utils import get_hdu, scale_points from datalab.datalab_session.utils.filecache import FileCache +from datalab.datalab_session.utils.flux_to_mag import flux_to_mag # Source catalog Function Definition # ARGS: input (dict) @@ -45,6 +46,7 @@ def source_catalog(input: dict, user: User): x = cat_hdu.data["x"][:MAX_SOURCE_CATALOG_SIZE] y = cat_hdu.data["y"][:MAX_SOURCE_CATALOG_SIZE] flux = cat_hdu.data["flux"][:MAX_SOURCE_CATALOG_SIZE] + fluxerr = cat_hdu.data["fluxerr"][:MAX_SOURCE_CATALOG_SIZE] # ra, dec values may or may not be present in the CAT hdu if "ra" in cat_hdu.data.names and "dec" in cat_hdu.data.names: ra = cat_hdu.data["ra"][:MAX_SOURCE_CATALOG_SIZE] @@ -62,12 +64,15 @@ def source_catalog(input: dict, user: User): # create the list of source catalog objects source_catalog_data = [] for i in range(MAX_SOURCE_CATALOG_SIZE): + mag, magerr = flux_to_mag(flux[i], fluxerr[i]) source_data = { "x_win": x_points[i], "y_win": y_points[i], "x": x[i], "y": y[i], - "flux": flux[i].astype(int) + "flux": flux[i].astype(int), + "mag": mag, + "magerr": magerr, } if ra is not None and dec is not None: source_data["ra"] = f'%.{DECIMALS_OF_PRECISION}f' % (ra[i]) From 2065186a7cffe78638410b914f8e0c6065db04a0 Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Wed, 29 Apr 2026 15:02:47 -0700 Subject: [PATCH 2/9] adds flux to mag utils --- datalab/datalab_session/utils/flux_to_mag.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 datalab/datalab_session/utils/flux_to_mag.py diff --git a/datalab/datalab_session/utils/flux_to_mag.py b/datalab/datalab_session/utils/flux_to_mag.py new file mode 100644 index 0000000..794d05e --- /dev/null +++ b/datalab/datalab_session/utils/flux_to_mag.py @@ -0,0 +1,17 @@ +import numpy as np + + +def flux_to_mag(flux, fluxerr): + """ + Convert flux and fluxerr to magnitude and magnitude error. + """ + conversion_factor = 2.5 + flux2mag = conversion_factor / np.log(10) + + if flux <= 0: + return None, None + + mag = -conversion_factor * np.log10(flux) + magerr = flux2mag * (fluxerr / flux) + + return mag, magerr From 02cd04e1e53fa22d3027e9046e7c046194df08d6 Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Wed, 29 Apr 2026 15:03:53 -0700 Subject: [PATCH 3/9] updates tests to test for flux to mag --- .../datalab_session/tests/test_analysis.py | 21 ++++++++++++++++++- datalab/datalab_session/tests/test_utils.py | 11 ++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/datalab/datalab_session/tests/test_analysis.py b/datalab/datalab_session/tests/test_analysis.py index 061904b..765e40d 100644 --- a/datalab/datalab_session/tests/test_analysis.py +++ b/datalab/datalab_session/tests/test_analysis.py @@ -8,6 +8,7 @@ from numpy.testing import assert_almost_equal from datalab.datalab_session.analysis import centroiding, line_profile, source_catalog +from datalab.datalab_session.utils.flux_to_mag import flux_to_mag class TestAnalysis(TestCase): analysis_test_path = 'datalab/datalab_session/tests/test_files/analysis/' @@ -51,7 +52,25 @@ def test_source_catalog(self, mock_file_cache): 'source': 'archive' }, None) - self.assertEqual(output, self.test_source_catalog_data) + self.assertEqual(len(output), len(self.test_source_catalog_data)) + + for result, expected in zip(output, self.test_source_catalog_data): + self.assertEqual(result['x_win'], expected['x_win']) + self.assertEqual(result['y_win'], expected['y_win']) + self.assertEqual(result['x'], expected['x']) + self.assertEqual(result['y'], expected['y']) + self.assertEqual(result['flux'], expected['flux']) + self.assertEqual(result['ra'], expected['ra']) + self.assertEqual(result['dec'], expected['dec']) + self.assertIn('mag', result) + self.assertIn('magerr', result) + + with fits.open(self.analysis_fits_1_path) as hdul: + fluxerr = hdul['CAT'].data['fluxerr'][0] + + expected_mag, expected_magerr = flux_to_mag(output[0]['flux'], fluxerr) + self.assertAlmostEqual(output[0]['mag'], expected_mag) + self.assertAlmostEqual(output[0]['magerr'], expected_magerr) def test_centroid_finds_pixels_center(self): image = np.zeros((21, 21), dtype=float) diff --git a/datalab/datalab_session/tests/test_utils.py b/datalab/datalab_session/tests/test_utils.py index daf9688..a2fa5af 100644 --- a/datalab/datalab_session/tests/test_utils.py +++ b/datalab/datalab_session/tests/test_utils.py @@ -1,5 +1,6 @@ from datalab.datalab_session.utils.file_utils import * from datalab.datalab_session.utils.s3_utils import * +from datalab.datalab_session.utils.flux_to_mag import flux_to_mag from datalab.datalab_session.tests.test_files.file_extended_test_case import FileExtendedTestCase class FileUtilsTestClass(FileExtendedTestCase): @@ -73,3 +74,13 @@ def test_scale_points(self): # flip y scaled_points = scale_points(10, 10, 20, 20, x_points, y_points, flip_y=True) self.assertEqual(scaled_points[1].tolist(), [12, 10, 8]) + + def test_flux_to_mag(self): + mag, magerr = flux_to_mag(100.0, 5.0) + + self.assertAlmostEqual(mag, -5.0) + self.assertAlmostEqual(magerr, 0.05428681023790647) + + def test_flux_to_mag_rejects_non_positive_flux(self): + self.assertEqual(flux_to_mag(0.0, 5.0), (None, None)) + self.assertEqual(flux_to_mag(-1.0, 5.0), (None, None)) From d3f3d3cf530fad5a3db8b729c59df702f2f38db9 Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Wed, 29 Apr 2026 15:04:32 -0700 Subject: [PATCH 4/9] uses flux to mag util function --- .../datalab_session/analysis/variable_star.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/datalab/datalab_session/analysis/variable_star.py b/datalab/datalab_session/analysis/variable_star.py index 7e47327..f688634 100644 --- a/datalab/datalab_session/analysis/variable_star.py +++ b/datalab/datalab_session/analysis/variable_star.py @@ -7,6 +7,7 @@ from datalab.datalab_session.utils.file_utils import get_hdu from datalab.datalab_session.utils.filecache import FileCache +from datalab.datalab_session.utils.flux_to_mag import flux_to_mag log = logging.getLogger(__name__) log.setLevel(logging.INFO) @@ -108,21 +109,6 @@ def find_target_source(cat_hdu, target_ra, target_dec): return None -def flux_to_mag(flux, fluxerr): - """ - Convert flux and fluxerr to magnitude and magnitude error. - """ - CONVERSION_FACTOR = 2.5 - FLUX2MAG = CONVERSION_FACTOR / np.log(10) - - if flux <= 0: - return None, None - - mag = -CONVERSION_FACTOR * np.log10(flux) - magerr = FLUX2MAG * (fluxerr / flux) - - return mag, magerr - def calculate_period(light_curve): """ Use the astropy lomb scargle to perform the periodogram analysis on the light curve From c3c8907c22cf357339b76bd094bc2c6c09766d6a Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Wed, 29 Apr 2026 16:28:20 -0700 Subject: [PATCH 5/9] fixes test --- datalab/datalab_session/tests/test_analysis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/datalab/datalab_session/tests/test_analysis.py b/datalab/datalab_session/tests/test_analysis.py index 765e40d..79ceaac 100644 --- a/datalab/datalab_session/tests/test_analysis.py +++ b/datalab/datalab_session/tests/test_analysis.py @@ -66,9 +66,10 @@ def test_source_catalog(self, mock_file_cache): self.assertIn('magerr', result) with fits.open(self.analysis_fits_1_path) as hdul: + flux = hdul['CAT'].data['flux'][0] fluxerr = hdul['CAT'].data['fluxerr'][0] - expected_mag, expected_magerr = flux_to_mag(output[0]['flux'], fluxerr) + expected_mag, expected_magerr = flux_to_mag(flux, fluxerr) self.assertAlmostEqual(output[0]['mag'], expected_mag) self.assertAlmostEqual(output[0]['magerr'], expected_magerr) From 71ed7a0aeed32fcaf306366b1633ecbec334b175 Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Thu, 30 Apr 2026 12:37:14 -0700 Subject: [PATCH 6/9] updates flux_to_mag to take the entire np array for efficiency. updates test --- .../analysis/source_catalog.py | 10 ++++++---- datalab/datalab_session/tests/test_utils.py | 8 ++++++++ datalab/datalab_session/utils/flux_to_mag.py | 20 +++++++++++++++---- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/datalab/datalab_session/analysis/source_catalog.py b/datalab/datalab_session/analysis/source_catalog.py index 0de98fe..906414b 100644 --- a/datalab/datalab_session/analysis/source_catalog.py +++ b/datalab/datalab_session/analysis/source_catalog.py @@ -34,7 +34,8 @@ def source_catalog(input: dict, user: User): cat_hdu = get_hdu(file_path, 'CAT') sci_hdu = get_hdu(file_path, 'SCI') - + print(cat_hdu.columns) + print(sci_hdu.data) DECIMALS_OF_PRECISION = 6 MAX_SOURCE_CATALOG_SIZE = min(len(cat_hdu.data["x"]), 1000) @@ -47,6 +48,8 @@ def source_catalog(input: dict, user: User): y = cat_hdu.data["y"][:MAX_SOURCE_CATALOG_SIZE] flux = cat_hdu.data["flux"][:MAX_SOURCE_CATALOG_SIZE] fluxerr = cat_hdu.data["fluxerr"][:MAX_SOURCE_CATALOG_SIZE] + mag, magerr = flux_to_mag(flux, fluxerr) + # ra, dec values may or may not be present in the CAT hdu if "ra" in cat_hdu.data.names and "dec" in cat_hdu.data.names: ra = cat_hdu.data["ra"][:MAX_SOURCE_CATALOG_SIZE] @@ -64,15 +67,14 @@ def source_catalog(input: dict, user: User): # create the list of source catalog objects source_catalog_data = [] for i in range(MAX_SOURCE_CATALOG_SIZE): - mag, magerr = flux_to_mag(flux[i], fluxerr[i]) source_data = { "x_win": x_points[i], "y_win": y_points[i], "x": x[i], "y": y[i], "flux": flux[i].astype(int), - "mag": mag, - "magerr": magerr, + "mag": mag[i], + "magerr": magerr[i], } if ra is not None and dec is not None: source_data["ra"] = f'%.{DECIMALS_OF_PRECISION}f' % (ra[i]) diff --git a/datalab/datalab_session/tests/test_utils.py b/datalab/datalab_session/tests/test_utils.py index a2fa5af..956303f 100644 --- a/datalab/datalab_session/tests/test_utils.py +++ b/datalab/datalab_session/tests/test_utils.py @@ -84,3 +84,11 @@ def test_flux_to_mag(self): def test_flux_to_mag_rejects_non_positive_flux(self): self.assertEqual(flux_to_mag(0.0, 5.0), (None, None)) self.assertEqual(flux_to_mag(-1.0, 5.0), (None, None)) + + def test_flux_to_mag_supports_arrays(self): + mag, magerr = flux_to_mag(np.array([100.0, 0.0]), np.array([5.0, 1.0])) + + self.assertAlmostEqual(mag[0], -5.0) + self.assertAlmostEqual(magerr[0], 0.05428681023790647) + self.assertTrue(np.isnan(mag[1])) + self.assertTrue(np.isnan(magerr[1])) diff --git a/datalab/datalab_session/utils/flux_to_mag.py b/datalab/datalab_session/utils/flux_to_mag.py index 794d05e..eafe03c 100644 --- a/datalab/datalab_session/utils/flux_to_mag.py +++ b/datalab/datalab_session/utils/flux_to_mag.py @@ -8,10 +8,22 @@ def flux_to_mag(flux, fluxerr): conversion_factor = 2.5 flux2mag = conversion_factor / np.log(10) - if flux <= 0: - return None, None + flux_array = np.asarray(flux) + fluxerr_array = np.asarray(fluxerr) - mag = -conversion_factor * np.log10(flux) - magerr = flux2mag * (fluxerr / flux) + if flux_array.ndim == 0: + if flux_array <= 0: + return None, None + + mag = -conversion_factor * np.log10(flux_array) + magerr = flux2mag * (fluxerr_array / flux_array) + return float(mag), float(magerr) + + mag = np.full(flux_array.shape, np.nan, dtype=float) + magerr = np.full(flux_array.shape, np.nan, dtype=float) + valid_flux = flux_array > 0 + + mag[valid_flux] = -conversion_factor * np.log10(flux_array[valid_flux]) + magerr[valid_flux] = flux2mag * (fluxerr_array[valid_flux] / flux_array[valid_flux]) return mag, magerr From c753b0afdee3af5c6afb96caea07c04f39bb11c6 Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Thu, 30 Apr 2026 13:34:42 -0700 Subject: [PATCH 7/9] deletes print statements --- datalab/datalab_session/analysis/source_catalog.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/datalab/datalab_session/analysis/source_catalog.py b/datalab/datalab_session/analysis/source_catalog.py index 906414b..d037916 100644 --- a/datalab/datalab_session/analysis/source_catalog.py +++ b/datalab/datalab_session/analysis/source_catalog.py @@ -34,8 +34,7 @@ def source_catalog(input: dict, user: User): cat_hdu = get_hdu(file_path, 'CAT') sci_hdu = get_hdu(file_path, 'SCI') - print(cat_hdu.columns) - print(sci_hdu.data) + DECIMALS_OF_PRECISION = 6 MAX_SOURCE_CATALOG_SIZE = min(len(cat_hdu.data["x"]), 1000) From 0a43671294d0e6df8f9e394e48f9b74531377253 Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Thu, 30 Apr 2026 14:24:55 -0700 Subject: [PATCH 8/9] breaks flux_to_mag into two methods: for single and array values --- datalab/datalab_session/tests/test_utils.py | 16 +++++- datalab/datalab_session/utils/flux_to_mag.py | 51 +++++++++++++------- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/datalab/datalab_session/tests/test_utils.py b/datalab/datalab_session/tests/test_utils.py index 956303f..c63b60c 100644 --- a/datalab/datalab_session/tests/test_utils.py +++ b/datalab/datalab_session/tests/test_utils.py @@ -1,6 +1,6 @@ from datalab.datalab_session.utils.file_utils import * from datalab.datalab_session.utils.s3_utils import * -from datalab.datalab_session.utils.flux_to_mag import flux_to_mag +from datalab.datalab_session.utils.flux_to_mag import flux_to_mag, flux_to_mag_array, flux_to_mag_scalar from datalab.datalab_session.tests.test_files.file_extended_test_case import FileExtendedTestCase class FileUtilsTestClass(FileExtendedTestCase): @@ -81,6 +81,12 @@ def test_flux_to_mag(self): self.assertAlmostEqual(mag, -5.0) self.assertAlmostEqual(magerr, 0.05428681023790647) + def test_flux_to_mag_scalar(self): + mag, magerr = flux_to_mag_scalar(100.0, 5.0) + + self.assertAlmostEqual(mag, -5.0) + self.assertAlmostEqual(magerr, 0.05428681023790647) + def test_flux_to_mag_rejects_non_positive_flux(self): self.assertEqual(flux_to_mag(0.0, 5.0), (None, None)) self.assertEqual(flux_to_mag(-1.0, 5.0), (None, None)) @@ -92,3 +98,11 @@ def test_flux_to_mag_supports_arrays(self): self.assertAlmostEqual(magerr[0], 0.05428681023790647) self.assertTrue(np.isnan(mag[1])) self.assertTrue(np.isnan(magerr[1])) + + def test_flux_to_mag_array(self): + mag, magerr = flux_to_mag_array(np.array([100.0, 0.0]), np.array([5.0, 1.0])) + + self.assertAlmostEqual(mag[0], -5.0) + self.assertAlmostEqual(magerr[0], 0.05428681023790647) + self.assertTrue(np.isnan(mag[1])) + self.assertTrue(np.isnan(magerr[1])) diff --git a/datalab/datalab_session/utils/flux_to_mag.py b/datalab/datalab_session/utils/flux_to_mag.py index eafe03c..38ca26a 100644 --- a/datalab/datalab_session/utils/flux_to_mag.py +++ b/datalab/datalab_session/utils/flux_to_mag.py @@ -1,29 +1,46 @@ import numpy as np +conversion_factor = 2.5 +flux2mag = conversion_factor / np.log(10) -def flux_to_mag(flux, fluxerr): + +def _calculate_mag(flux, fluxerr): + mag = -conversion_factor * np.log10(flux) + magerr = flux2mag * (fluxerr / flux) + + return mag, magerr + + +def flux_to_mag_scalar(flux, fluxerr): """ - Convert flux and fluxerr to magnitude and magnitude error. + Convert scalar flux and fluxerr values to magnitude and magnitude error. """ - conversion_factor = 2.5 - flux2mag = conversion_factor / np.log(10) + if flux <= 0: + return None, None - flux_array = np.asarray(flux) - fluxerr_array = np.asarray(fluxerr) + mag, magerr = _calculate_mag(flux, fluxerr) - if flux_array.ndim == 0: - if flux_array <= 0: - return None, None + return float(mag), float(magerr) - mag = -conversion_factor * np.log10(flux_array) - magerr = flux2mag * (fluxerr_array / flux_array) - return float(mag), float(magerr) - mag = np.full(flux_array.shape, np.nan, dtype=float) - magerr = np.full(flux_array.shape, np.nan, dtype=float) - valid_flux = flux_array > 0 +def flux_to_mag_array(flux, fluxerr): + """ + Convert flux and fluxerr arrays to magnitude and magnitude error arrays. + """ + mag = np.full(flux.shape, np.nan, dtype=float) + magerr = np.full(flux.shape, np.nan, dtype=float) + valid_flux = flux > 0 - mag[valid_flux] = -conversion_factor * np.log10(flux_array[valid_flux]) - magerr[valid_flux] = flux2mag * (fluxerr_array[valid_flux] / flux_array[valid_flux]) + mag[valid_flux], magerr[valid_flux] = _calculate_mag(flux[valid_flux], fluxerr[valid_flux]) return mag, magerr + + +def flux_to_mag(flux, fluxerr): + """ + Convert flux and fluxerr to magnitude and magnitude error. + """ + if np.isscalar(flux): + return flux_to_mag_scalar(flux, fluxerr) + + return flux_to_mag_array(flux, fluxerr) From 707f590011cd8cedf85a8c1ffe79a1a254324d6c Mon Sep 17 00:00:00 2001 From: Carolina Capetillo Date: Thu, 30 Apr 2026 16:44:57 -0700 Subject: [PATCH 9/9] updates mag and magerr values because we get them just on GRIZ. Added fallback --- datalab/datalab_session/analysis/source_catalog.py | 9 ++++++++- datalab/datalab_session/tests/test_analysis.py | 7 ++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/datalab/datalab_session/analysis/source_catalog.py b/datalab/datalab_session/analysis/source_catalog.py index d037916..bc86210 100644 --- a/datalab/datalab_session/analysis/source_catalog.py +++ b/datalab/datalab_session/analysis/source_catalog.py @@ -47,7 +47,13 @@ def source_catalog(input: dict, user: User): y = cat_hdu.data["y"][:MAX_SOURCE_CATALOG_SIZE] flux = cat_hdu.data["flux"][:MAX_SOURCE_CATALOG_SIZE] fluxerr = cat_hdu.data["fluxerr"][:MAX_SOURCE_CATALOG_SIZE] - mag, magerr = flux_to_mag(flux, fluxerr) + flux_fallback = False + if "mag" in cat_hdu.data.names and "magerr" in cat_hdu.data.names: + mag = cat_hdu.data["mag"][:MAX_SOURCE_CATALOG_SIZE] + magerr = cat_hdu.data["magerr"][:MAX_SOURCE_CATALOG_SIZE] + else: + mag, magerr = flux_to_mag(flux, fluxerr) + flux_fallback = True # ra, dec values may or may not be present in the CAT hdu if "ra" in cat_hdu.data.names and "dec" in cat_hdu.data.names: @@ -74,6 +80,7 @@ def source_catalog(input: dict, user: User): "flux": flux[i].astype(int), "mag": mag[i], "magerr": magerr[i], + "flux_fallback": flux_fallback } if ra is not None and dec is not None: source_data["ra"] = f'%.{DECIMALS_OF_PRECISION}f' % (ra[i]) diff --git a/datalab/datalab_session/tests/test_analysis.py b/datalab/datalab_session/tests/test_analysis.py index 79ceaac..5afd0e1 100644 --- a/datalab/datalab_session/tests/test_analysis.py +++ b/datalab/datalab_session/tests/test_analysis.py @@ -8,8 +8,6 @@ from numpy.testing import assert_almost_equal from datalab.datalab_session.analysis import centroiding, line_profile, source_catalog -from datalab.datalab_session.utils.flux_to_mag import flux_to_mag - class TestAnalysis(TestCase): analysis_test_path = 'datalab/datalab_session/tests/test_files/analysis/' analysis_fits_1_path = f'datalab/datalab_session/tests/test_files/fits_1.fits.fz' @@ -66,10 +64,9 @@ def test_source_catalog(self, mock_file_cache): self.assertIn('magerr', result) with fits.open(self.analysis_fits_1_path) as hdul: - flux = hdul['CAT'].data['flux'][0] - fluxerr = hdul['CAT'].data['fluxerr'][0] + expected_mag = hdul['CAT'].data['mag'][0] + expected_magerr = hdul['CAT'].data['magerr'][0] - expected_mag, expected_magerr = flux_to_mag(flux, fluxerr) self.assertAlmostEqual(output[0]['mag'], expected_mag) self.assertAlmostEqual(output[0]['magerr'], expected_magerr)