import h5py as h5
import pickle
import os
import glob
# Name
# ----
# Manage Event
# File
# ----
# manageevnet.py
# Description
# -----------
# Routines for handling events.
# Package Contents
# ----------------
# saveevent(event, filename, save=['event'], delete=[])
# Saves an event in .dat (using cpickle) and .h5 (using h5py) files.
# loadevent(filename, load):
# Loads an event stored in .dat and .h5 files.
# updateevent(event, filename, add):
# Adds parameters given by add from filename to event.
# Examples
# --------
# >>> from manageevent import *
# >>> # Save hd209bs51_ini.dat and hd209bs51_ini.h5 files.
# >>> saveevent(event, 'd209bs51_ini', save=['data', 'head','uncd',
# 'bdmskd'])
# >>> # Load the event and its data frames
# >>> event = loadevent('hd209bs51_ini', ['data'])
# >>> # Load uncd and bdmsk into event:
# >>> updateevent(event, 'hd209bs51_ini', ['uncd', 'bdmskd'])
# Notes
# -----
# History:
#
# - 2010-07-10 patricio pcubillos@fulbrightmail.org
# joined loadevent and saveevent into this package. updateevent added.
# - 2010-11-12 patricio
# reimplemented using exec()
[docs]def saveevent(event, filename, save=[], delete=[], protocol=3):
"""Saves an event in .dat (using cpickle) and .h5 (using h5py) files.
Parameters
----------
event : eureka.lib.readECF.MetaClass
The meta data object to save.
filename : String
The string contains the name of the event file.
save : string tuple
The elements of this tuple contain the parameters to save.
We usually use the values: 'data', 'uncd', 'head', 'bdmskd',
'brmksd' or 'mask'.
delete : string tuple
Parameters to be deleted.
Notes
-----
The input filename should not have the .dat nor the .h5 extentions.
Side effect: This routine deletes all parameters except 'event' after
saving it.
History:
- 2010-07-10 patricio
Added documentation.
"""
if save != []:
with h5.File(filename + '.h5', 'w') as handle:
for param in save:
exec('handle["' + param + '"] = event.' + param)
exec('del(event.' + param + ')')
# calibration data
if event.havecalaor:
exec('handle["pre' + param + '"] = event.pre' + param)
exec('handle["post' + param + '"] = event.post' + param)
exec('del(event.pre' + param + ', event.post' +
param + ')')
# delete if requested
for param in delete:
exec('del(event.' + param + ')')
if event.havecalaor:
exec('del(event.pre' + param + ', event.post' + param + ')')
# Pickle-Save the event
with open(filename + '.dat', 'wb') as handle:
pickle.dump(event, handle, protocol)
[docs]def loadevent(filename, load=[], loadfilename=None):
"""Loads an event stored in .dat and .h5 files.
Parameters
----------
filename : str
The string contains the name of the event file.
load : str tuple; optional
The elements of this tuple contain the parameters to read.
We usually use the values: 'data', 'uncd', 'head', 'bdmskd',
'brmskd' or 'mask'. Defaults to [].
loadfilename : str; optional
The filename of the .h5 save file (excluding the file extension).
Defaults to None which uses filename.
Returns
-------
eureka.lib.readECF.MetaClass
The requested metadata object.
Notes
-----
The input filename should not have the .dat nor the .h5 extentions.
History:
- 2010-07-10 patricio
Added documentation.
"""
with open(filename + '.dat', 'rb') as handle:
event = pickle.load(handle, encoding='latin1')
if loadfilename is None:
loadfilename = filename
if load != []:
with h5.File(loadfilename + '.h5', 'r') as handle:
for param in load:
exec('event.' + param + ' = handle["' + param + '"][:]')
# calibration data:
if event.havecalaor:
exec('event.pre' + param + ' = handle["pre' + param +
'"][:]')
exec('event.post' + param + ' = handle["post' + param +
'"][:]')
return event
[docs]def updateevent(event, filename, add):
"""Adds parameters given by add from filename to event.
Parameters
----------
event : eureka.lib.readECF.MetaClass
The metadata object to update.
filename : str
The string contains the name of the event file.
add : str tuple
The elements of this tuple contain the parameters to
add. We usually use the values: 'data', 'uncd', 'head',
'bdmskd', 'brmaskd' or 'mask'.
Returns
-------
eureka.lib.readECF.MetaClass
The updated metadata object.
Notes
-----
The input filename should not have the .dat nor the .h5 extentions.
History:
- 2010-07-10 patricio
Initial version.
"""
event2 = loadevent(filename, load=add)
for param in add:
exec('event.' + param + ' = event2.' + param)
# calibration data
if event.havecalaor:
exec('event.pre' + param + ' = event2.pre' + param)
exec('event.post' + param + ' = event2.post' + param)
return event
[docs]def findevent(meta, stage, allowFail=False):
"""Loads in an earlier stage meta file.
Parameters
----------
meta : eureka.lib.readECF.MetaClass
The new meta object for the current processing.
stage : str
The previous stage (e.g. "S2" for Stage 3).
allowFail : bool; optional
Whether to allow the code to find no previous stage metadata files
(for S2, S3) or throw an error if no metadata files are found.
Default is False.
Returns
-------
old_meta : eureka.lib.readECF.MetaClass
The old metadata object.
inputdir : str
The new inputdir to use (based on the present location of the located
metadata file).
inputdir_raw : str
The new inputdir_raw to use (based on the present location of the
located metadata file).
Raises
------
AssertionError
Unable to find a metadata save file and allowFail was False.
Notes
-----
History:
- April 25, 2022 Taylor Bell
Initial version.
"""
# Search for the output metadata in the inputdir provided
# First just check the specific inputdir folder
fnames = glob.glob(meta.inputdir+stage+'_'+meta.eventlabel +
'*_Meta_Save.dat')
if len(fnames) == 0:
# There were no metadata files in that folder, so let's see if there
# are in children folders
fnames = glob.glob(meta.inputdir+'**'+os.sep+stage+'_' +
meta.eventlabel+'*_Meta_Save.dat', recursive=True)
if len(fnames) >= 1:
# get the folder with the latest modified time
fname = max(fnames, key=os.path.getmtime)
if len(fnames) == 0 and allowFail:
# There may be no rateints files in the inputdir or any of its
# children directories - raise an error and give a helpful message
print(f'WARNING: Unable to find an output metadata file from '
f'Eureka!\'s {stage} in the folder:\n"{meta.inputdir}"\n'
f'Assuming this {stage} data was produced by the JWST pipeline '
f'instead.')
return None, meta.inputdir, meta.inputdir_raw
elif len(fnames) == 0:
# There may be no metafiles in the inputdir - raise an error and give
# a helpful message
raise AssertionError(f'WARNING: Unable to find an output metadata file'
f' from Eureka!\'s {stage} in the folder:'
f'\n"{meta.inputdir}"')
elif len(fnames) > 1:
# There may be multiple runs - use the most recent but warn the user
print(f'WARNING: There are multiple metadata save files in the folder:'
f'\n"{meta.inputdir}"\n'
f'Using the metadata file: \n{fname}\n'
f'and will consider aperture ranges listed there. If this '
f'metadata file is not a part\n'
f'of the run you intended, please provide a more precise folder '
f'for the metadata file.')
fname = fname[:-4] # Strip off the .dat ending
# Load old savefile
old_meta = loadevent(fname)
old_meta.folder = os.sep.join(fname.split(os.sep)[:-1])+os.sep
old_meta.filename = fname.split(os.sep)[-1]
return old_meta, old_meta.folder, old_meta.folder[len(meta.topdir):]
[docs]def mergeevents(new_meta, old_meta):
"""Merge the current MetaClass data into the MetaClass object from a
previous stage.
Parameters
----------
new_meta : eureka.lib.readECF.MetaClass
The metadata object for the current stage.
old_meta : eureka.lib.readECF.MetaClass
The metadata object for the previous stage.
Returns
-------
new_meta : eureka.lib.readECF.MetaClass
The current metadata object containing the details from the previous
metadata object.
Notes
-----
History:
- April 25, 2022 Taylor Bell
Initial version.
"""
# Load current ECF into old MetaClass
old_meta.read(new_meta.folder, new_meta.filename)
# Load any missing parameters from current MetaClass into old MetaClass
for key in new_meta.__dict__:
if key not in old_meta.__dict__:
setattr(old_meta, key, getattr(new_meta, key))
# Make sure inputdir is correct
old_meta.inputdir = new_meta.inputdir
old_meta.inputdir_raw = new_meta.inputdir_raw
old_meta.datetime = new_meta.datetime
return old_meta