2020-04-06 17:17:31 +02:00
|
|
|
import xml.etree.ElementTree as eT
|
|
|
|
import numpy as np
|
2020-04-08 09:45:59 +02:00
|
|
|
import astropy.units as u
|
2020-04-06 17:17:31 +02:00
|
|
|
import os
|
|
|
|
import logging
|
2020-04-16 09:35:24 +02:00
|
|
|
from ..lib.helpers import error
|
|
|
|
from typing import Union
|
2020-04-21 10:18:33 +02:00
|
|
|
import re
|
2020-04-06 17:17:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Entry(object):
|
|
|
|
"""
|
|
|
|
A class used to represent a configuration entry.
|
2020-04-16 09:35:24 +02:00
|
|
|
Taken from ExoSim (https://github.com/ExoSim/ExoSimPublic)
|
2020-04-06 17:17:31 +02:00
|
|
|
"""
|
2020-04-16 09:35:24 +02:00
|
|
|
val: Union[str, bool, u.Quantity]
|
2020-04-06 17:17:31 +02:00
|
|
|
|
2020-04-17 13:04:59 +02:00
|
|
|
def __init__(self, **kwargs):
|
|
|
|
for key, value in kwargs.items():
|
|
|
|
self.__setattr__(key, value)
|
|
|
|
|
2020-04-06 17:17:31 +02:00
|
|
|
def __call__(self):
|
2020-04-08 09:45:59 +02:00
|
|
|
return self.val if hasattr(self, "val") else None
|
2020-04-06 17:17:31 +02:00
|
|
|
|
2020-04-16 09:35:24 +02:00
|
|
|
def parse(self, xml: eT.Element):
|
2020-04-06 17:17:31 +02:00
|
|
|
"""
|
2020-04-08 09:45:59 +02:00
|
|
|
Parse attributes of a XML element
|
2020-04-06 17:17:31 +02:00
|
|
|
|
2020-04-16 09:35:24 +02:00
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
xml : xml.etree.ElementTree.Element
|
|
|
|
XML element to parse the attributes from
|
2020-04-06 17:17:31 +02:00
|
|
|
"""
|
2020-04-08 09:45:59 +02:00
|
|
|
# Copy the XML attributes to object attributes
|
|
|
|
for attrib in xml.attrib.keys():
|
|
|
|
setattr(self, attrib, xml.attrib[attrib])
|
2020-04-21 10:18:33 +02:00
|
|
|
# parse units
|
|
|
|
attribs = list(xml.attrib.keys())
|
|
|
|
units = list(filter(re.compile(".*_unit$").match, attribs))
|
|
|
|
for unit in units:
|
|
|
|
var = unit.replace("_unit", "")
|
|
|
|
if hasattr(self, var):
|
|
|
|
try:
|
|
|
|
val = u.Quantity(list(map(float, getattr(self, var).split(','))), getattr(self, unit))
|
|
|
|
if len(val) == 1:
|
|
|
|
val = val[0]
|
|
|
|
setattr(self, var, val)
|
|
|
|
except (ValueError, LookupError):
|
|
|
|
error("unable to convert units in entry '" + xml.tag + "': " + getattr(self, var) + " " +
|
|
|
|
getattr(self, unit), exit_=False)
|
|
|
|
# Convert boolean values
|
|
|
|
if hasattr(self, "val") and type(self.val) == str and self.val.lower() in ["false", "true"]:
|
2020-04-08 09:45:59 +02:00
|
|
|
self.val = (self.val.lower() == "true")
|
2020-04-06 17:17:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
class Configuration(object):
|
|
|
|
"""
|
|
|
|
A Class to parse the XML configuration file.
|
2020-04-08 09:45:59 +02:00
|
|
|
Adapted from ExoSim (https://github.com/ExoSim/ExoSimPublic)
|
2020-04-06 17:17:31 +02:00
|
|
|
|
|
|
|
Attributes
|
|
|
|
----------
|
2020-04-08 09:45:59 +02:00
|
|
|
conf : Entry
|
|
|
|
Parsed configuration file as Entry-tree
|
2020-04-06 17:17:31 +02:00
|
|
|
"""
|
|
|
|
conf = None
|
|
|
|
|
2020-04-16 09:57:01 +02:00
|
|
|
def __init__(self, file="esbo-etc_defaults.xml"):
|
2020-04-06 17:17:31 +02:00
|
|
|
"""
|
|
|
|
Parse a XML configuration file.
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
2020-04-16 09:57:01 +02:00
|
|
|
file : str
|
2020-04-06 17:17:31 +02:00
|
|
|
configuration file to parse
|
|
|
|
"""
|
2020-04-08 09:45:59 +02:00
|
|
|
|
|
|
|
# Check if configuration file exists
|
2020-04-16 09:57:01 +02:00
|
|
|
if not os.path.exists(file):
|
|
|
|
error("Configuration file '" + file + "' doesn't exist.")
|
2020-04-06 17:17:31 +02:00
|
|
|
|
2020-04-08 09:45:59 +02:00
|
|
|
# Read configuration file
|
2020-04-16 09:57:01 +02:00
|
|
|
logging.info("Reading configuration from file '" + file + "'.")
|
|
|
|
self.conf = self.parser(eT.parse(file).getroot())
|
2020-04-06 17:17:31 +02:00
|
|
|
|
|
|
|
self.calc_metaoptions()
|
|
|
|
|
2020-04-16 13:04:21 +02:00
|
|
|
def parser(self, parent: eT.Element):
|
2020-04-06 17:17:31 +02:00
|
|
|
"""
|
2020-04-08 09:45:59 +02:00
|
|
|
Parse a XML element tree to an Entry-tree
|
2020-04-06 17:17:31 +02:00
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
2020-04-16 13:04:21 +02:00
|
|
|
parent : xml.etree.ElementTree.Element
|
2020-04-08 09:45:59 +02:00
|
|
|
The parent XML tree to be parsed
|
2020-04-06 17:17:31 +02:00
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
obj : Entry
|
|
|
|
The parsed XML tree
|
|
|
|
"""
|
2020-04-08 09:45:59 +02:00
|
|
|
|
|
|
|
# Initialize empty Entry object
|
2020-04-06 17:17:31 +02:00
|
|
|
obj = Entry()
|
|
|
|
|
2020-04-08 09:45:59 +02:00
|
|
|
for child in parent:
|
|
|
|
# recursively parse children of child element
|
|
|
|
parsed_child = self.parser(child)
|
|
|
|
# parse attributes of child element
|
|
|
|
parsed_child.parse(child)
|
2020-04-06 17:17:31 +02:00
|
|
|
|
2020-04-08 09:45:59 +02:00
|
|
|
# Add or append the parsed child to the prepared Entry object
|
|
|
|
if hasattr(obj, child.tag):
|
|
|
|
if isinstance(getattr(obj, child.tag), list):
|
|
|
|
getattr(obj, child.tag).append(parsed_child)
|
2020-04-06 17:17:31 +02:00
|
|
|
else:
|
2020-04-08 09:45:59 +02:00
|
|
|
setattr(obj, child.tag, [getattr(obj, child.tag), parsed_child])
|
2020-04-06 17:17:31 +02:00
|
|
|
else:
|
2020-04-08 09:45:59 +02:00
|
|
|
setattr(obj, child.tag, parsed_child)
|
2020-04-06 17:17:31 +02:00
|
|
|
return obj
|
|
|
|
|
|
|
|
def calc_metaoptions(self):
|
2020-04-08 09:45:59 +02:00
|
|
|
"""
|
|
|
|
Calculate additional attributes e.g. the wavelength grid
|
|
|
|
"""
|
2020-04-06 17:17:31 +02:00
|
|
|
self.calc_metaoption_wl_delta()
|
|
|
|
|
|
|
|
def calc_metaoption_wl_delta(self):
|
2020-04-08 09:45:59 +02:00
|
|
|
"""
|
|
|
|
Calculate the wavelength grid used for the calculations.
|
|
|
|
"""
|
|
|
|
if hasattr(self.conf.common, "wl_delta"):
|
|
|
|
wl_delta = self.conf.common.wl_delta()
|
|
|
|
else:
|
|
|
|
wl_delta = self.conf.common.wl_min() / self.conf.common.res()
|
2020-04-17 13:05:22 +02:00
|
|
|
setattr(self.conf.common, 'wl_bins',
|
2020-04-22 10:36:38 +02:00
|
|
|
Entry(val=np.append(np.arange(self.conf.common.wl_min().to(u.nm).value,
|
|
|
|
self.conf.common.wl_max().to(u.nm).value, wl_delta.to(u.nm).value),
|
|
|
|
self.conf.common.wl_max().to(u.nm).value) << u.nm))
|