Skip to content

Commit c0c0a40

Browse files
author
David Turner
committed
Constructed warning about removed data
Signed-off-by: David Turner <djturner@umbc.edu>
1 parent 1b800b8 commit c0c0a40

1 file changed

Lines changed: 36 additions & 47 deletions

File tree

xga/sources/base.py

Lines changed: 36 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This code is part of X-ray: Generate and Analyse (XGA), a module designed for the XMM Cluster Survey (XCS).
2-
# Last modified by David J Turner (djturner@umbc.edu) 5/21/26, 3:19 PM. Copyright (c) The Contributors.
2+
# Last modified by David J Turner (djturner@umbc.edu) 5/21/26, 3:53 PM. Copyright (c) The Contributors.
33

44
import contextlib
55
import gc
@@ -310,36 +310,6 @@ def __init__(self, ra: float, dec: float, redshift: float = None, name: str = No
310310
# actual event list/image/expmap/region files - those initial products are loaded into XGA products
311311
self._products, region_dict = self._initial_products(obs, load_regions, null_load_products)
312312

313-
# # We need to make sure that we only keep instruments (and ObsIDs) that actually have an
314-
# # event list associated with them - it is possible for initial_products to have not been
315-
# # able to load them
316-
# new_prods = {t: {o: {i: self._products[t][o][i] for i in self._products[t][o]
317-
# if 'events' in self._products[t][o][i]}
318-
# for o in self._products[t]} for t in self._products}
319-
# # Then we remove any ObsIDs that no longer have any instruments
320-
# new_prods = {t: {o: new_prods[t][o] for o in new_prods[t]
321-
# if len(new_prods[t][o]) != 0}
322-
# for t in new_prods}
323-
# # Replicate the new_prods structure for the 'obs' and 'region_dict' variables
324-
# new_obs = {t: {o: [i for i in obs[t][o] if i in new_prods[t][o]] for o in new_prods[t]} for t in new_prods}
325-
# new_regs = {t: {o: region_dict[t][o] for o in new_prods[t]} for t in new_prods}
326-
#
327-
# # Warn the user about removals
328-
# # Aggregate all removed combinations for a single warning
329-
# all_removed = ["{t}: {o}({i})".format(t=t, o=o, i=", ".join([i for i in obs[t][o] if o not in new_obs[t]
330-
# or i not in new_obs[t][o]]))
331-
# for t in obs for o in obs[t] if o not in new_obs[t]
332-
# or any(i not in new_obs[t][o] for i in obs[t][o])]
333-
#
334-
# if all_removed:
335-
# warn(f"Some observations/instruments were removed as their event lists could not "
336-
# f"be read: {"; ".join(all_removed)}", stacklevel=2)
337-
338-
# # Assign the altered dictionaries
339-
# self._products = new_prods
340-
# obs = new_obs
341-
# region_dict = new_regs
342-
343313
# Now we do ANOTHER check just like the one above, but on the product attribute, as it is possible that
344314
# all those files cannot be found
345315
cur_obs_nums = {tel: len(self._products[tel]) for tel in self._products}
@@ -352,10 +322,36 @@ def __init__(self, ra: float, dec: float, redshift: float = None, name: str = No
352322
new_obs = {tel: obs[tel] for tel, num in cur_obs_nums.items() if num != 0}
353323
new_prods = {tel: self._products[tel] for tel, num in cur_obs_nums.items() if num != 0}
354324
new_regs = {tel: region_dict[tel] for tel, num in cur_obs_nums.items() if num != 0}
355-
# Then assign the new cut down dictionaries to their original names
356-
obs = new_obs
357-
self._products = new_prods
358-
region_dict = new_regs
325+
326+
else:
327+
new_obs = obs
328+
new_prods = self._products
329+
new_regs = region_dict
330+
331+
# Identify any observations or instruments that were removed because their event lists
332+
# could not be read in successfully
333+
removed_obs = {t: {o: [i for i in obs[t][o] if o not in new_prods[t] or i not in new_prods[t][o]]
334+
for o in obs[t]} for t in obs}
335+
# Clean up the dictionary so it only contains entries that actually have removed instruments
336+
removed_obs = {t: {o: i for o, i in removed_obs[t].items() if len(i) != 0} for t in removed_obs}
337+
removed_obs = {t: o for t, o in removed_obs.items() if len(o) != 0}
338+
339+
# If there are any removed observations/instruments, we raise a warning
340+
if len(removed_obs) != 0:
341+
# We construct a message to warn the user
342+
warn_msg = "The following observations/instruments could not be read in and have been removed: "
343+
# This nested join formats the dictionary into Telescope: ObsID(inst1, inst2); ...
344+
warn_msg += "; ".join(["{t}: {o}".format(t=t, o=", ".join(["{o}({i})".format(o=o, i=", ".join(i))
345+
for o, i in removed_obs[t].items()]))
346+
for t in removed_obs])
347+
warn(warn_msg, stacklevel=2)
348+
349+
# Assign the new, potentially cut down, dictionaries to their original names - this is separated from the
350+
# checking logic above so that we can raise a warning by comparing obs and new_prods before obs
351+
# gets overwritten
352+
obs = new_obs
353+
self._products = new_prods
354+
region_dict = new_regs
359355

360356
# This is somewhat inelegant, but oh well; it ensures that there are individual instrument entries for each
361357
# ObsID in the products dictionary, for cases where the data are shipped with all instruments combined
@@ -1133,16 +1129,13 @@ def read_default_products(en_lims: tuple) -> Tuple[str, dict]:
11331129
# the copy so that any modifications don't harm the original file.
11341130
reg_file = rel_sec["region_file"].format(obs_id=obs_id)
11351131

1136-
1137-
1138-
1132+
# Load the event list - if this doesn't work then there isn't any point continuing to the
1133+
# rest of the initial product loading process for the current telescope-ObsID-instrument
11391134
evt_list = EventList(evt_file, obs_id=obs_id, instrument=inst, stdout_str="", stderr_str="",
11401135
gen_cmd="", telescope=tel)
11411136
if not evt_list.usable:
11421137
continue
11431138

1144-
1145-
11461139
# Attitude file is a special type of data product, we shouldn't ever deal with it directly so it
11471140
# doesn't have a product object. It also isn't guaranteed to be a separate thing for all
11481141
# telescopes, so we do check that the configuration file actually has an entry for it.
@@ -1184,14 +1177,10 @@ def read_default_products(en_lims: tuple) -> Tuple[str, dict]:
11841177
else:
11851178
mask_prod = None
11861179

1180+
# If we've gotten to this part of the method we know that the EventList exists and is usable, so
1181+
# to proceed to populating the obs_dict we check that the attitude file (if one is meant to
1182+
# exist for this telescope) actually exists.
11871183
if (att_prod is not None and att_prod.usable) or att_prod is None:
1188-
# An instrument subsection of an observation will ONLY be populated if the events file exists
1189-
# Otherwise nothing can be done with it.
1190-
# evt_list = EventList(evt_file, obs_id=obs_id, instrument=inst, stdout_str="", stderr_str="",
1191-
# gen_cmd="", telescope=tel)
1192-
# if not evt_list.usable:
1193-
# continue
1194-
11951184
# Start off with the events list going in - make sure there is an inst entry first
11961185
obs_dict[tel][obs_id].setdefault(inst, {})
11971186
obs_dict[tel][obs_id][inst]["events"] = evt_list

0 commit comments

Comments
 (0)