diff --git a/datalab/datalab_session/analysis/source_catalog.py b/datalab/datalab_session/analysis/source_catalog.py index fa13d5e..bc86210 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,15 @@ 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] + 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: ra = cat_hdu.data["ra"][:MAX_SOURCE_CATALOG_SIZE] @@ -67,7 +77,10 @@ def source_catalog(input: dict, user: User): "y_win": y_points[i], "x": x[i], "y": y[i], - "flux": flux[i].astype(int) + "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/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 diff --git a/datalab/datalab_session/tests/test_analysis.py b/datalab/datalab_session/tests/test_analysis.py index 061904b..5afd0e1 100644 --- a/datalab/datalab_session/tests/test_analysis.py +++ b/datalab/datalab_session/tests/test_analysis.py @@ -8,7 +8,6 @@ from numpy.testing import assert_almost_equal from datalab.datalab_session.analysis import centroiding, line_profile, source_catalog - 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' @@ -51,7 +50,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: + expected_mag = hdul['CAT'].data['mag'][0] + expected_magerr = hdul['CAT'].data['magerr'][0] + + 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..c63b60c 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, flux_to_mag_array, flux_to_mag_scalar from datalab.datalab_session.tests.test_files.file_extended_test_case import FileExtendedTestCase class FileUtilsTestClass(FileExtendedTestCase): @@ -73,3 +74,35 @@ 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_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)) + + 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])) + + 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 new file mode 100644 index 0000000..38ca26a --- /dev/null +++ b/datalab/datalab_session/utils/flux_to_mag.py @@ -0,0 +1,46 @@ +import numpy as np + +conversion_factor = 2.5 +flux2mag = conversion_factor / np.log(10) + + +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 scalar flux and fluxerr values to magnitude and magnitude error. + """ + if flux <= 0: + return None, None + + mag, magerr = _calculate_mag(flux, fluxerr) + + return float(mag), float(magerr) + + +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], 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)