From 6eeec4cdacf82b72326474292d2e9fc0d807ea02 Mon Sep 17 00:00:00 2001 From: Rob Knop Date: Wed, 4 Dec 2024 13:40:43 -0800 Subject: [PATCH] Add optional hostgal info to elasticc2/ltcv and elasticc2/gethottransients --- README.md | 5 + tests/test_elasticc2_api.py | 48 +++++++ tests/test_elasticc2_spectrumcycle.py | 61 +++++++++ tom_desc/elasticc2/views.py | 183 ++++++++++++++++++-------- 4 files changed, 245 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 6c99a4d1..9ebe5388 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,7 @@ TODO: flesh out You can get lightcurves for objects at the URL `elasticc2/ltcv`. POST to this URL, with the post body a json-encoded dict, with keys: * `objectid` or `objecitds`: One of these two is required. Either the numerical ID of the object whose lightcurve you want, or a list of such numerical ids. * `mjd_now`: (Optional.) For testing purposes. Normally, you will get all known photometry for an object. Pass an MJD here, and you'll only get photometry before that mjd. +* `hostgal_info`: (Optional.) 0 or 1, default 0. If 1, return information about the first possible host galaxy for each transient. * `return_format`: (Optional.) 0, 1, or 2, default 0. (See below.) Example: @@ -318,6 +319,9 @@ In all cases, what you find in `objectid` is what you will use to indicate a giv } ``` +*For all three return formats* + +If you specified `include_hostinfo`, there will be additional keys `hostgal_mag_*` and `hostgal_magerr_*` (where * is u, g, r, i, z), as well as `hostgal_ellipticity` and `hostgal_sqradius`. The values of these are all floats (or lists of floats, for return format 2). ## Getting and pushing spectrum information @@ -329,6 +333,7 @@ Currently hot transients can be found at the URL `elasticc2/gethottransients`. * `detected_since_mjd: float` — will return all SNe detected since the indicated mjd. ("Detected" means a LSST alert was sent out, and at least one broker has returned a classification.) * `detected_in_last_days: float` — will return all SNe detected between this many days before now and now. The TOM will search what it knows about forced photometry, considering any point with S/N>5 as a detection. * `mjd_now: float` — The mjd of right now. Usually you don't want to specify this, and the server will automatically determine the current MJD. This is here so it can be used with simulations, where "right now" in the simulation may not be the real right now. You will not get back any detections or forced photometry with an MJD newer than this value. +* `hostgal_info`: (Optional.) 0 or 1, default 0. If 1, return information about the first possible host galaxy for each transient. * `return_format: int` — 0, 1, or 2. Optional, defaults to 0. Example: diff --git a/tests/test_elasticc2_api.py b/tests/test_elasticc2_api.py index 03feb418..7a58ba2e 100644 --- a/tests/test_elasticc2_api.py +++ b/tests/test_elasticc2_api.py @@ -111,8 +111,14 @@ def test_alert_api( self, elasticc2_ppdb_class, tomclient ): class TestLtcv: def test_ltcvs( self, elasticc2_database_snapshot_class, tomclient ): + # Make sure it objects to an unknown keyword + res = tomclient.post( "elasticc2/ltcv", json={ 'objectid': 1552185, 'foo': 1 } ) + assert res.status_code == 500 + assert res.text == "Exception in LtcvsView: Unknown parameters: {'foo'}" + # Try with a single objectid res = tomclient.post( "elasticc2/ltcv", json={ 'objectid': 1552185 } ) + assert res.status_code == 200 data = res.json() assert data['status'] == 'ok' @@ -128,6 +134,7 @@ def test_ltcvs( self, elasticc2_database_snapshot_class, tomclient ): # Get full lightcurves res = tomclient.post( "elasticc2/ltcv", json={ 'objectid': testobjs } ) + assert res.status_code == 200 data = res.json() assert data['status'] == 'ok' @@ -135,6 +142,7 @@ def test_ltcvs( self, elasticc2_database_snapshot_class, tomclient ): assert set( data['diaobject'][i]['objectid'] for i in [0,1,2] ) == set( testobjs ) fullltcvlens = [] for i in range(3): + assert set( data['diaobject'][i].keys() ) == { 'objectid', 'ra', 'dec', 'zp', 'photometry' } fullltcvlens.append( len( data['diaobject'][i]['photometry']['mjd'] ) ) assert fullltcvlens[i] > 0 for field in [ 'band', 'flux', 'fluxerr' ]: @@ -142,6 +150,7 @@ def test_ltcvs( self, elasticc2_database_snapshot_class, tomclient ): # Test a fake current mjd res = tomclient.post( "elasticc2/ltcv", json={ 'objectid': testobjs, 'mjd_now': 60420 } ) + assert res.status_code == 200 data = res.json() assert data['status'] == 'ok' @@ -153,14 +162,53 @@ def test_ltcvs( self, elasticc2_database_snapshot_class, tomclient ): assert partialltcvlens[i] < fullltcvlens[i] assert all ( m < 60420 for m in data['diaobject'][i]['photometry']['mjd'] ) + + # Make sure that include_hostinfo works + res = tomclient.post( "elasticc2/ltcv", json={ 'objectid': testobjs, 'include_hostinfo': 1 } ) + assert res.status_code == 200 + data = res.json() + assert data['status'] == 'ok' + assert len( data['diaobject'] ) == 3 + assert data['diaobject'][0].keys() == { 'objectid', 'ra','dec', 'zp', 'photometry', + 'hostgal_mag_u', 'hostgal_magerr_u', + 'hostgal_mag_g', 'hostgal_magerr_g', + 'hostgal_mag_r', 'hostgal_magerr_r', + 'hostgal_mag_i', 'hostgal_magerr_i', + 'hostgal_mag_z', 'hostgal_magerr_z', + 'hostgal_mag_y', 'hostgal_magerr_y', + 'hostgal_ellipticity', 'hostgal_sqradius' } + + # Test returnformat 2 (TODO : returnformat 1) # Test a fake current mjd res = tomclient.post( "elasticc2/ltcv", json={ 'objectid': testobjs, 'mjd_now': 60420, 'return_format': 2 } ) + assert res.status_code == 200 data = res.json() + assert data['status'] == 'ok' + df = pandas.DataFrame( data['diaobject'] ) + assert set( df.columns ) == { 'objectid', 'ra', 'dec', 'zp', 'mjd', 'band', 'flux', 'fluxerr' } + assert set( df.objectid ) == set( testobjs ) + assert all( len( df.mjd[i] ) == partialltcvlens[i] for i in range(2) ) + assert all( len( df.mjd[i] ) == len( df[field][i] ) + for field in [ 'band', 'flux', 'fluxerr' ] + for i in range(2) ) + res = tomclient.post( "elasticc2/ltcv", json={ 'objectid': testobjs, 'mjd_now': 60420, + 'include_hostinfo': 1, + 'return_format': 2 } ) + assert res.status_code == 200 + data = res.json() assert data['status'] == 'ok' df = pandas.DataFrame( data['diaobject'] ) + assert set( df.columns ) == { 'objectid', 'ra', 'dec', 'zp', 'mjd', 'band', 'flux', 'fluxerr', + 'hostgal_mag_u', 'hostgal_magerr_u', + 'hostgal_mag_g', 'hostgal_magerr_g', + 'hostgal_mag_r', 'hostgal_magerr_r', + 'hostgal_mag_i', 'hostgal_magerr_i', + 'hostgal_mag_z', 'hostgal_magerr_z', + 'hostgal_mag_y', 'hostgal_magerr_y', + 'hostgal_ellipticity', 'hostgal_sqradius' } assert set( df.objectid ) == set( testobjs ) assert all( len( df.mjd[i] ) == partialltcvlens[i] for i in range(2) ) assert all( len( df.mjd[i] ) == len( df[field][i] ) diff --git a/tests/test_elasticc2_spectrumcycle.py b/tests/test_elasticc2_spectrumcycle.py index f73f18d9..b4cc3b43 100644 --- a/tests/test_elasticc2_spectrumcycle.py +++ b/tests/test_elasticc2_spectrumcycle.py @@ -9,6 +9,8 @@ import dateutil.parser import pytest +import numpy +import pandas import astropy.time sys.path.insert( 0, "/tom_desc" ) @@ -52,12 +54,19 @@ def ask_for_spectra( self, elasticc2_database_snapshot_class, tomclient ): # TODO : test things other than detected_since_mjd sent to gethottransients def test_hot_sne( self, elasticc2_database_snapshot_class, tomclient ): + # Make sure it rejects bad keywords + res = tomclient.post( 'elasticc2/gethottransients', json={ 'foo': 0 } ) + assert res.status_code == 500 + assert res.text == "Error, unknown parameters passed in request body: ['foo']" + # Testing detected_in_last_days is fraught because # the mjds in elasticc2 are what they are, are # in the future (as of this comment writing). # So, go old school and just not test it. + # (Should test with mjd_now...) res = tomclient.post( 'elasticc2/gethottransients', json={ 'detected_since_mjd': 60660 } ) + assert res.status_code == 200 sne = res.json()['diaobject'] assert len(sne) == 8 @@ -68,6 +77,58 @@ def test_hot_sne( self, elasticc2_database_snapshot_class, tomclient ): assert set( sne[0].keys() ) == { 'objectid', 'ra', 'dec', 'photometry', 'zp', 'redshift', 'sncode' } assert set( sne[0]['photometry'].keys() ) == { 'mjd', 'band', 'flux', 'fluxerr' } + # Make sure the include_hostinfo parameter works + res = tomclient.post( 'elasticc2/gethottransients', json={ 'detected_since_mjd': 60660, + 'include_hostinfo': 1 } ) + assert res.status_code == 200 + sne = res.json()['diaobject'] + assert len(sne) == 8 + snids = { s['objectid'] for s in sne } + assert snids == { 15232, 1913410, 2110476, 416626, 1286131, 1684659, 1045654, 1263066 } + assert set( sne[0].keys() ) == { 'objectid', 'ra', 'dec', 'photometry', 'zp', 'redshift', 'sncode', + 'hostgal_mag_u','hostgal_magerr_u', + 'hostgal_mag_g','hostgal_magerr_g', + 'hostgal_mag_r','hostgal_magerr_r', + 'hostgal_mag_i','hostgal_magerr_i', + 'hostgal_mag_z','hostgal_magerr_z', + 'hostgal_mag_y','hostgal_magerr_y', + 'hostgal_ellipticity', 'hostgal_sqradius' + } + assert set( sne[0]['photometry'].keys() ) == { 'mjd', 'band', 'flux', 'fluxerr' } + + # Try return format 2 + res = tomclient.post( 'elasticc2/gethottransients', json={ 'detected_since_mjd': 60660, + 'return_format': 2 } ) + assert res.status_code == 200 + df = pandas.DataFrame( res.json()['diaobject'] ) + assert len(df) == 8 + assert set( df.objectid.values ) == { 15232, 1913410, 2110476, 416626, 1286131, 1684659, 1045654, 1263066 } + assert set( df.columns ) == { 'objectid', 'ra', 'dec', 'mjd', 'band', 'flux', 'fluxerr', + 'zp', 'redshift', 'sncode' } + assert df.mjd.dtype == numpy.dtype('O') + assert len( df.mjd[0] ) > 1 + + res = tomclient.post( 'elasticc2/gethottransients', json={ 'detected_since_mjd': 60660, + 'include_hostinfo': 1, + 'return_format': 2 } ) + assert res.status_code == 200 + df = pandas.DataFrame( res.json()['diaobject'] ) + assert len(df) == 8 + assert set( df.objectid.values ) == { 15232, 1913410, 2110476, 416626, 1286131, 1684659, 1045654, 1263066 } + assert set( df.columns ) == { 'objectid', 'ra', 'dec', 'mjd', 'band', 'flux', 'fluxerr', + 'zp', 'redshift', 'sncode', + 'hostgal_mag_u','hostgal_magerr_u', + 'hostgal_mag_g','hostgal_magerr_g', + 'hostgal_mag_r','hostgal_magerr_r', + 'hostgal_mag_i','hostgal_magerr_i', + 'hostgal_mag_z','hostgal_magerr_z', + 'hostgal_mag_y','hostgal_magerr_y', + 'hostgal_ellipticity', 'hostgal_sqradius' + } + assert df.mjd.dtype == numpy.dtype('O') + assert len( df.mjd[0] ) > 1 + + def test_ask_for_spectra( self, ask_for_spectra, tomclient ): objs, prios = ask_for_spectra diff --git a/tom_desc/elasticc2/views.py b/tom_desc/elasticc2/views.py index f8abde65..8b0219a9 100644 --- a/tom_desc/elasticc2/views.py +++ b/tom_desc/elasticc2/views.py @@ -658,6 +658,7 @@ def post( self, request ): # ====================================================================== +# This and GetHotSNe view have a bunch of overlapping code; think about that. class LtcvsView(PermissionRequiredMixin, django.views.View): raise_exception = True @@ -671,6 +672,10 @@ def get( self, *args, **kwargs ): def post( self, request ): try: data = json.loads( request.body ) + known_keys = { 'objectid', 'objectids', 'mjd_now', 'return_format', 'include_hostinfo' } + if not ( set( data.keys() ) <= known_keys ): + raise ValueError( f"Unknown parameters: {set(data.keys())-known_keys}" ) + if ( ( not isinstance( data, dict ) ) or ( ( 'objectid' not in data ) and ( 'objectids' not in data ) @@ -693,6 +698,8 @@ def post( self, request ): if return_format not in ( 0, 1, 2 ): raise ValueError( f"Unknown return_format {return_format}" ) + include_object_hostinfo = ( 'include_hostinfo' in data ) and ( data['include_hostinfo'] ) + dbinfo = tom_desc.settings.DATABASES['default'] with psycopg2.connect( host=dbinfo['HOST'], port=dbinfo['PORT'], @@ -702,9 +709,15 @@ def post( self, request ): ) as dbcon: with dbcon.cursor() as cursor: - q = ( 'SELECT diaobject_id,diaforcedsource_id,filtername,midpointtai,psflux,psfluxerr ' - 'FROM elasticc2_diaforcedsource f ' - 'WHERE f.diaobject_id IN %(objectids)s ' ) + q = 'SELECT f.diaobject_id,o.ra,o.decl as dec,' + if include_object_hostinfo: + for band in [ 'u', 'g', 'r', 'i', 'z', 'y' ]: + q += f"o.hostgal_mag_{band},o.hostgal_magerr_{band}," + q += "o.hostgal_ellipticity,o.hostgal_sqradius," + q += ( 'f.diaforcedsource_id,f.filtername,f.midpointtai,f.psflux,f.psfluxerr ' + 'FROM elasticc2_diaforcedsource f ' + 'INNER JOIN elasticc2_diaobject o ON f.diaobject_id=o.diaobject_id ' + 'WHERE f.diaobject_id IN %(objectids)s ' ) if mjdnow is not None: q += ' AND f.midpointtai <= %(now)s ' q += 'ORDER BY f.diaobject_id, f.midpointtai' @@ -717,11 +730,19 @@ def post( self, request ): sne = [] elif return_format == 2: sne = { 'objectid': [], + 'ra': [], + 'dec': [], 'mjd': [], 'band': [], 'flux': [], 'fluxerr': [], 'zp': [] } + if include_object_hostinfo: + for band in [ 'u', 'g', 'r', 'i', 'z', 'y' ]: + sne[ f'hostgal_mag_{band}' ] = [] + sne[ f'hostgal_magerr_{band}' ] = [] + sne[ 'hostgal_ellipticity' ] = [] + sne[ 'hostgal_sqradius' ] = [] else: raise RuntimeError( "This should never happen" ) @@ -731,27 +752,47 @@ def post( self, request ): for objid in objids: subdf = df.xs( objid, level='diaobject_id' ) - if return_format == 0: - sne.append( { 'objectid': int(objid), - 'photometry': { 'mjd': list( subdf['midpointtai'] ), - 'band': list( subdf['filtername'] ), - 'flux': list( subdf['psflux'] ), - 'fluxerr': list( subdf['psfluxerr'] ) }, - 'zp': 27.5 } ) - elif return_format == 1: - sne.append( { 'objectid': int(objid), - 'mjd': list( subdf['midpointtai'] ), - 'band': list( subdf['filtername'] ), - 'flux': list( subdf['psflux'] ), - 'fluxerr': list( subdf['psfluxerr'] ), - 'zp': 27.5 } ) + if ( return_format == 0 ) or ( return_format == 1): + toadd = { 'objectid': int(objid), + 'ra': subdf.ra.values[0], + 'dec': subdf.dec.values[0], + 'zp': 27.5 } + if include_object_hostinfo: + for band in [ 'u', 'g', 'r', 'i', 'z', 'y' ]: + toadd[ f'hostgal_mag_{band}' ] = subdf[ f'hostgal_mag_{band}' ].values[0] + toadd[ f'hostgal_magerr_{band}' ] = subdf[ f'hostgal_magerr_{band}' ].values[0] + toadd[ f'hostgal_ellipticity' ] = subdf[ f'hostgal_ellipticity' ].values[0] + toadd[ f'hostgal_sqradius' ] = subdf[ f'hostgal_sqradius' ].values[0] + + if return_format == 0: + toadd['photometry'] = { 'mjd': list( subdf['midpointtai'] ), + 'band': list( subdf['filtername'] ), + 'flux': list( subdf['psflux'] ), + 'fluxerr': list( subdf['psfluxerr'] ) } + else: + toadd['mjd'] = list( subdf['mjd'] ), + toadd['band'] = list( subdf['band'] ) + toadd['flux'] = list( subdf['flux'] ) + toadd['fluxerr'] = list( subdf['fluxerr'] ) + + sne.append( toadd ) + elif return_format == 2: sne['objectid'].append( int(objid) ) + sne['ra'].append( subdf.ra.values[0] ) + sne['dec'].append( subdf.dec.values[0] ) sne['mjd'].append( list( subdf['midpointtai'] ) ) sne['band'].append( list( subdf['filtername'] ) ) sne['flux'].append( list( subdf['psflux'] ) ) sne['fluxerr'].append( list( subdf['psfluxerr'] ) ) sne['zp'].append( 27.5 ) + if include_object_hostinfo: + for band in [ 'u', 'g', 'r', 'i', 'z', 'y' ]: + sne[ f'hostgal_mag_{band}' ].append( subdf[f'hostgal_mag_{band}'].values[0] ) + sne[ f'hostgal_magerr_{band}' ].append( subdf[f'hostgal_magerr_{band}'].values[0] ) + sne[ 'hostgal_ellipticity' ].append( subdf['hostgal_ellipticity'].values[0] ) + sne[ 'hostgal_sqradius' ].append( subdf['hostgal_sqradius'].values[0] ) + else: raise RuntimeError( "This should never happen." ) @@ -1092,13 +1133,15 @@ def process( self, request ): data = json.loads( request.body ) mjdnow = None - mjd0 = 0. + mjd0 = None + include_object_hostinfo = False if 'return_format' in data.keys(): return_format = int( data['return_format'] ) if return_format not in (0, 1, 2): return HttpResponse( f"Error, unknown return_format {return_format}", status=500, content_type='text/plain; charset=utf-8' ) + del data['return_format' ] else: return_format = 0 @@ -1109,17 +1152,22 @@ def process( self, request ): content_type='text/plain; charset=utf-8' ) # _logger.info( f"Getting hot SNe since {data['detected_since_mjd']}" ) mjd0 = float( data['detected_since_mjd'] ) + del data['detected_since_mjd'] else: lastdays = 30 if 'detected_in_last_days' in data.keys(): lastdays = float( data['detected_in_last_days'] ) - # _logger.info( f"Getting hot SNe detected in last {lastdays} days" ) - if 'mjd_now' in data.keys(): - mjdnow = float( data['mjd_now'] ) + del data['detected_in_last_days'] + + if 'mjd_now' in data.keys(): + mjdnow = float( data['mjd_now'] ) + if mjd0 is None: mjd0 = mjdnow - lastdays - else: - mjd0 = astropy.time.Time( datetime.datetime.now( datetime.timezone.utc ) - - datetime.timedelta( days=lastdays ) ).mjd + del data['mjd_now'] + + elif mjd0 is None: + mjd0 = astropy.time.Time( datetime.datetime.now( datetime.timezone.utc ) + - datetime.timedelta( days=lastdays ) ).mjd cheat_gentypes = None if 'cheat_gentypes' in data.keys(): @@ -1128,6 +1176,17 @@ def process( self, request ): return HttpResponse( "Error, cheat_gentypes must be a list", status=500, content_type='text/plain; charset=utf-8' ) cheat_gentypes = tuple( cheat_gentypes ) + del data['cheat_gentypes'] + + if 'include_hostinfo' in data.keys(): + if data['include_hostinfo']: + include_object_hostinfo = True + del data['include_hostinfo'] + + + if len(data) != 0: + return HttpResponse( f"Error, unknown parameters passed in request body: {list(data.keys())}", + status=500, content_type="text/plain; charset=utf-8" ) # _logger.info( f"Getting SNe detected since mjd {mjd0}" ) @@ -1164,12 +1223,16 @@ def process( self, request ): q = ( "/* IndexScan(f diaobject_id)\n" " IndexScan(o)\n" "*/\n" - "SELECT f.diaobject_id AS diaobject_id, o.ra AS ra, o.decl AS dec," - " f.diaforcedsource_id AS diaforcedsource_id," - " f.filtername AS band,f.midpointtai AS mjd," - " f.psflux AS flux, f.psfluxerr AS fluxerr " - "FROM elasticc2_diaforcedsource f " - "INNER JOIN elasticc2_diaobject o ON f.diaobject_id=o.diaobject_id " ) + "SELECT f.diaobject_id AS diaobject_id, o.ra AS ra, o.decl AS dec," ) + if include_object_hostinfo: + for band in [ 'u', 'g', 'r', 'i', 'z', 'y' ]: + q += f"o.hostgal_mag_{band},o.hostgal_magerr_{band}," + q += "o.hostgal_ellipticity,o.hostgal_sqradius," + q += ( " f.diaforcedsource_id AS diaforcedsource_id," + " f.filtername AS band,f.midpointtai AS mjd," + " f.psflux AS flux, f.psfluxerr AS fluxerr " + "FROM elasticc2_diaforcedsource f " + "INNER JOIN elasticc2_diaobject o ON f.diaobject_id=o.diaobject_id " ) if cheat_gentypes is not None: q += "INNER JOIN elasticc2_diaobjecttruth t ON o.diaobject_id=t.diaobject_id " q += "WHERE f.diaobject_id IN ( SELECT diaobject_id FROM tmp_objids ) " @@ -1195,6 +1258,12 @@ def process( self, request ): 'zp': [], 'redshift': [], 'sncode': [] } + if include_object_hostinfo: + for band in [ 'u', 'g', 'r', 'i', 'z', 'y' ]: + sne[ f'hostgal_mag_{band}' ] = [] + sne[ f'hostgal_magerr_{band}' ] = [] + sne[ 'hostgal_ellipticity' ] = [] + sne[ 'hostgal_sqradius' ] = [] else: raise RuntimeError( "This should never happen." ) @@ -1205,28 +1274,31 @@ def process( self, request ): for objid in objids: subdf = df.xs( objid, level='diaobject_id' ) - if return_format == 0: - sne.append( { 'objectid': int(objid), - 'ra': subdf.ra.values[0], - 'dec': subdf.dec.values[0], - 'photometry': { 'mjd': list( subdf['mjd'] ), - 'band': list( subdf['band'] ), - 'flux': list( subdf['flux'] ), - 'fluxerr': list( subdf['fluxerr'] ) }, - 'zp': 27.5, # standard SNANA zeropoint, - 'redshift': -99, - 'sncode': -99 } ) - elif return_format == 1: - sne.append( { 'objectid': int(objid), - 'ra': subdf.ra.values[0], - 'dec': subdf.dec.values[0], - 'mjd': list( subdf['mjd'] ), - 'band': list( subdf['band'] ), - 'flux': list( subdf['flux'] ), - 'fluxerr': list( subdf['fluxerr'] ), - 'zp': 27.5, # standard SNANA zeropoint, - 'redshift': -99, - 'sncode': -99 } ) + if ( return_format == 0 ) or ( return_format == 1 ): + toadd = { 'objectid': int(objid), + 'ra': subdf.ra.values[0], + 'dec': subdf.dec.values[0], + 'zp': 27.5, # standard SNANA zeropoint, + 'redshift': -99, + 'sncode': -99 } + if include_object_hostinfo: + for band in [ 'u', 'g', 'r', 'i', 'z', 'y' ]: + toadd[ f'hostgal_mag_{band}' ] = subdf[f'hostgal_mag_{band}'].values[0] + toadd[ f'hostgal_magerr_{band}' ] = subdf[f'hostgal_magerr_{band}'].values[0] + toadd[ 'hostgal_ellipticity' ] = subdf.hostgal_ellipticity.values[0] + toadd[ 'hostgal_sqradius' ] = subdf.hostgal_sqradius.values[0] + + if return_format == 0: + toadd['photometry'] = { 'mjd': list( subdf['mjd'] ), + 'band': list( subdf['band'] ), + 'flux': list( subdf['flux'] ), + 'fluxerr': list( subdf['fluxerr'] ) } + else: + toadd['mjd'] = list( subdf['mjd'] ), + toadd['band'] = list( subdf['band'] ) + toadd['flux'] = list( subdf['flux'] ) + toadd['fluxerr'] = list( subdf['fluxerr'] ) + sne.append( toadd ) elif return_format == 2: sne['objectid'].append( int(objid) ) sne['ra'].append( subdf.ra.values[0] ) @@ -1238,6 +1310,13 @@ def process( self, request ): sne['zp'].append( 27.5 ) sne['redshift'].append( -99 ) sne['sncode'].append( -99 ) + if include_object_hostinfo: + for band in [ 'u', 'g', 'r', 'i', 'z', 'y' ]: + sne[ f'hostgal_mag_{band}' ].append( subdf[f'hostgal_mag_{band}'].values[0] ) + sne[ f'hostgal_magerr_{band}' ].append( subdf[f'hostgal_magerr_{band}'].values[0] ) + sne[ 'hostgal_ellipticity' ].append( subdf['hostgal_ellipticity'].values[0] ) + sne[ 'hostgal_sqradius' ].append( subdf['hostgal_sqradius'].values[0] ) + else: raise RuntimeError( "This should never happen." )