diff --git a/esbo-etc_defaults.xml b/esbo-etc_defaults.xml new file mode 100644 index 0000000..ffdafcd --- /dev/null +++ b/esbo-etc_defaults.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/esbo_etc/__init__.py b/esbo_etc/__init__.py new file mode 100644 index 0000000..6aaf515 --- /dev/null +++ b/esbo_etc/__init__.py @@ -0,0 +1,4 @@ +from esbo_etc.classes import * +from esbo_etc.modules import * + +# __root__ = "." diff --git a/esbo_etc/classes/__init__.py b/esbo_etc/classes/__init__.py new file mode 100644 index 0000000..b08b7a2 --- /dev/null +++ b/esbo_etc/classes/__init__.py @@ -0,0 +1 @@ +from esbo_etc.classes.config import * diff --git a/esbo_etc/classes/config.py b/esbo_etc/classes/config.py new file mode 100644 index 0000000..b91ac18 --- /dev/null +++ b/esbo_etc/classes/config.py @@ -0,0 +1,146 @@ +import xml.etree.ElementTree as eT +import numpy as np +import quantities as pq +import os +import logging +import sys + + +class Entry(object): + """ + A class used to represent a configuration entry. + """ + + val = None + attrib = None + xml_entry = None + + def __call__(self): + return self.val + + def parse(self, xml): + """ + Parse a XML tree element + + :param xml: XML element tree to parse + """ + self.attrib = xml.attrib + for attr in self.attrib.keys(): + setattr(self, attr, self.attrib[attr]) + + if hasattr(self, 'units'): + try: + self.val = pq.Quantity(list(map(float, self.val.split(','))), + self.units).simplified + if self.units == 'deg': + self.val = [x * pq.rad for x in self.val] # workaround for qt unit conversion + if len(self.val) == 1: + self.val = self.val[0] + except (ValueError, LookupError): + logging.error('unable to convert units in entry [tag, units, value]: ', + xml.tag, self.units, self.val) + + +class Configuration(object): + """ + A Class to parse the XML configuration file. + + Attributes + ---------- + conf : str + Parsed XML tree + """ + conf = None + + def __init__(self, filename="esbo-etc_defaults.xml", default_path=None): + """ + Parse a XML configuration file. + + Parameters + ---------- + filename : str + configuration file to parse + default_path : str + default path to use for relative paths + """ + if not os.path.exists(filename): + logging.error("Configuration file '" + filename + "' doesn't exist.") + sys.exit(1) + + logging.info("Reading configuration from file '" + filename + "'.") + self.conf = self.parser(eT.parse(filename).getroot()) + + if default_path: + setattr(self.conf, "__path__", default_path) + elif hasattr(self.conf.common, "ConfigPath"): + setattr(self.conf, "__path__", + os.path.expanduser(self.conf.common.ConfigPath().replace('__path__', os.getcwd()))) + else: + logging.error("Path to config files not defined") + + self.validate_options() + self.calc_metaoptions() + + def parser(self, root): + """ + Parse a XML configuration file. + + Parameters + ---------- + root : ElementTree + The XML tree to be parsed + + Returns + ------- + obj : Entry + The parsed XML tree + """ + obj = Entry() + + for ch in root: + retval = self.parser(ch) + retval.parse(ch) + + if hasattr(obj, ch.tag): + if isinstance(getattr(obj, ch.tag), list): + getattr(obj, ch.tag).append(retval) + else: + setattr(obj, ch.tag, [getattr(obj, ch.tag), retval]) + else: + setattr(obj, ch.tag, retval) + return obj + + def validate_options(self): + self.validate_is_list() + self.validate_True_False_spelling() + + def validate_is_list(self): + if not isinstance(self.conf.common_optics.optical_component, list): + self.conf.common_optics.optical_component = [self.conf.common_optics.optical_component] + if not isinstance(self.conf.instrument, list): + self.conf.instrument = [self.conf.instrument] + + def validate_True_False_spelling(self): + accepted_values = ['True', 'False'] + test_cases = [ + 'noise/EnableJitter', + 'noise/EnableShotNoise', + 'noise/EnableReadoutNoise', + ] + for item in test_cases: + if hasattr(self.conf, item.split('/')[0]): + if not self.conf.__getattribute__(item.split('/')[0]).__dict__[item.split('/')[1]]() in accepted_values: + raise ValueError("Accepted values for [%s] are 'True' or 'False'" % item) + + def calc_metaoptions(self): + self.calc_metaoption_wl_delta() + + def calc_metaoption_wl_delta(self): + wl_delta = self.conf.common.wl_min() / self.conf.common.logbinres() + setattr(self.conf.common, 'common_wl', (np.arange(self.conf.common.wl_min(), + self.conf.common.wl_max(), + wl_delta) * wl_delta.units).rescale(pq.um)) + + +if __name__ == "__main__": + conf = Configuration() diff --git a/esbo_etc/esbo-etc.py b/esbo_etc/esbo-etc.py new file mode 100644 index 0000000..f31d026 --- /dev/null +++ b/esbo_etc/esbo-etc.py @@ -0,0 +1,47 @@ +import esbo_etc +import argparse +import logging +import sys +import os + + +def run_exosim(opt=None): + pass + # star, planet = exosim.modules.astroscene.run(opt) + # + # exosim_msg(' Stellar SED: {:s}\n'.format(os.path.basename(star.ph_filename))) + # exosim_msg(' Star luminosity {:f}\n'.format(star.luminosity)) + # + # # Instanciate Zodi + # zodi = exosim.classes.zodiacal_light(opt.common.common_wl, level=1.0) + # + # exosim.exolib.sed_propagation(star.sed, zodi.transmission) + # # Run Instrument Model + # channel = exosim.modules.instrument.run(opt, star, planet, zodi) + # # Create Signal timelines + # frame_time, total_observing_time, exposure_time = exosim.modules.timeline_generator.run(opt, channel, planet) + # # Generate noise timelines + # exosim.modules.noise.run(opt, channel, frame_time, total_observing_time, exposure_time) + # # Save + # exosim.modules.output.run(opt, channel, planet) + # + # return star, planet, zodi, channel + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(prog="esbo_etc/esbo-etc.py", description='Exposure time calculator for ESBO-DS') + parser.add_argument("-c", "--config", dest='config', default="esbo-etc_defaults.xml", + metavar="config.xml", help="path to the configuration file") + parser.add_argument("-d", "--debug", action="store_true", dest="debug", help="print debug information") + parser.add_argument("-o", "--output-dir", dest="output_dir", help="path to the output directory", + default="output") + parser.add_argument("-v", "--version", action="version", version="ESBO-ETC version 1.0.0", + help="show version information") + args = parser.parse_args() + + logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG if args.debug else logging.WARNING, + stream=sys.stdout) + + conf = esbo_etc.Configuration(filename=args.config).conf + + # run_exosim(opt) diff --git a/esbo_etc/lib/__init__.py b/esbo_etc/lib/__init__.py new file mode 100644 index 0000000..42fc95b --- /dev/null +++ b/esbo_etc/lib/__init__.py @@ -0,0 +1 @@ +from esbo_etc.lib.helpers import * diff --git a/esbo_etc/lib/helpers.py b/esbo_etc/lib/helpers.py new file mode 100644 index 0000000..e69de29