Skip to content

Commit fbb44d4

Browse files
committed
Add SkyCatValue as a value type
This allows to get any value from skycatalogue to the truth catalogue (or elsewhere).
1 parent 6009f55 commit fbb44d4

1 file changed

Lines changed: 98 additions & 5 deletions

File tree

roman_imsim/skycat.py

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
428517
RegisterInputType("sky_catalog", SkyCatalogLoader(SkyCatalogInterface, has_nobj=True))
429518
RegisterObjectType("SkyCatObj", SkyCatObj, input_type="sky_catalog")
430519
RegisterValueType("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

Comments
 (0)