@@ -145,6 +145,27 @@ def objects(self):
145145 self .logger .warning ("No objects found on image." )
146146 return self ._objects
147147
148+ def _build_dtype_dict (self ):
149+ self ._dtype_dict = {}
150+ obj_types = []
151+ for coll in self ._objects .get_collections ():
152+ objects_type = coll ._object_type_unique
153+ if objects_type in obj_types :
154+ continue
155+ col_names = list (coll .native_columns )
156+ for col_name in col_names :
157+ try :
158+ # Some columns cannot be read in snana
159+ np_type = coll .get_native_attribute (col_name ).dtype .type ()
160+ except Exception as e :
161+ self .logger .warning (f"The column { col_name } could not be read from skyCatalog." )
162+ continue
163+ if np_type is None :
164+ py_type = str
165+ else :
166+ py_type = type (np_type .astype (object ))
167+ self ._dtype_dict [col_name ] = py_type
168+
148169 def get_sca_center (self ):
149170 """
150171 Return the SCA center.
@@ -243,6 +264,45 @@ def getFlux(self, index=None, skycat_obj=None, filter=None, mjd=None, exptime=No
243264
244265 return fluxes
245266
267+ def getValue (self , index , field ):
268+ """
269+ Return a skyCatalog value for the an object.
270+
271+ Parameters
272+ ----------
273+ index : int
274+ Index of the object in the self.objects catalog.
275+ field : str
276+ Name of the field for which you want the value.
277+
278+ Returns
279+ -------
280+ int or float or str or None
281+ The value associated to the field or None if the field do not exist.
282+ """
283+
284+ skycat_obj = self .objects [index ]
285+
286+ if field not in self ._dtype_dict :
287+ # We cannot raise an error because one could have a field for snana
288+ # in the config and we don't want to crash because there are no SN
289+ # in this particular image. We then default to False which might not
290+ # be the right type for the required column but we have no way of knowing
291+ # the correct type if the column do not exist.
292+ self .logger .warning (f"The field { field } was not found in skyCatalog." )
293+ return None
294+ elif field not in skycat_obj .native_columns :
295+ if self ._dtype_dict [field ] is int :
296+ # There are no "special value" for integer so we default to
297+ # hopefully something completely off
298+ return - 9999
299+ elif self ._dtype_dict [field ] is float :
300+ return np .nan
301+ elif self ._dtype_dict [field ] is str :
302+ return None
303+ else :
304+ return skycat_obj .get_native_attribute (field )
305+
246306 def getObj (self , index , gsparams = None , rng = None ):
247307 """
248308 Return the galsim object for the skyCatalog object
@@ -289,11 +349,7 @@ def getObj(self, index, gsparams=None, rng=None):
289349 if faint :
290350 seds = {cmp_name : self ._trivial_sed for cmp_name in gsobjs }
291351 else :
292- seds = (
293- self ._seds
294- if self ._seds is not None
295- else skycat_obj .get_observer_sed_components (mjd = self .mjd )
296- )
352+ seds = skycat_obj .get_observer_sed_components (mjd = self .mjd )
297353 else :
298354 seds = {cmp_name : 1.0 for cmp_name in gsobjs }
299355
@@ -425,10 +481,47 @@ def SkyCatWorldPos(config, base, value_type):
425481 return pos , safe
426482
427483
484+ def SkyCatValue (config , base , value_type ):
485+ """Return a value from the object part of the skyCatalog"""
486+
487+ skycat = galsim .config .GetInputObj ("sky_catalog" , config , base , "SkyCatValue" )
488+
489+ # Setup the indexing sequence if it hasn't been specified. The
490+ # normal thing with a catalog is to just use each object in order,
491+ # so we don't require the user to specify that by hand. We can do
492+ # it for them.
493+ galsim .config .SetDefaultIndex (config , skycat .getNObjects ())
494+
495+ req = {"field" : str , "index" : int }
496+ opt = {"obs_kind" : str }
497+ params , safe = galsim .config .GetAllParams (config , base , req = req , opt = opt )
498+ field = params ["field" ]
499+ index = params ["index" ]
500+ obs_kind = params .get ("obs_kind" , None )
501+
502+ if field == "flux" :
503+ if obs_kind is None :
504+ val = skycat .getFlux (index )
505+ else :
506+ pointing = galsim .config .GetInputObj ("obseq_data" , config , base , "OpSeqDataLoader" )
507+ filter = pointing .get ("filter" , obs_kind = obs_kind )
508+ exptime = pointing .get ("exptime" , obs_kind = obs_kind )
509+ mjd = pointing .get ("mjd" , obs_kind = obs_kind )
510+ val = skycat .getFlux (index , filter = filter , exptime = exptime , mjd = mjd )
511+ else :
512+ val = skycat .getValue (index , field )
513+
514+ return val , safe
515+
516+
428517RegisterInputType ("sky_catalog" , SkyCatalogLoader (SkyCatalogInterface , has_nobj = True ))
429518RegisterObjectType ("SkyCatObj" , SkyCatObj , input_type = "sky_catalog" )
430519RegisterValueType ("SkyCatWorldPos" , SkyCatWorldPos , [galsim .CelestialCoord ], input_type = "sky_catalog" )
431520
521+ # Here we have to provide None as a type otherwise Galsim complains but I don't know why..
522+ RegisterValueType ("SkyCatValue" , SkyCatValue , [float , int , str , None ], input_type = "sky_catalog" )
523+
524+
432525# This class was modified from https://github.com/LSSTDESC/imSim/. License info follows:
433526
434527# Copyright (c) 2016-2019, LSST Dark Energy Science Collaboration (DESC)
0 commit comments