Source code for ecpi.simu.lib.context

'''
Created on 28 sept. 2020

'''

import logging
import numpy as np
from ecpi.simu.lib.instru_x import SimuECLAIRsMaskProjection
from ecpi.common.instru.model_effect import ECLAIRsDetectorEffectDefault
from ecpi.common.mission.attitude import AttitudeECLAIRs
from ecpi.common.sky.extented_body import EarthInFov

logger = logging.getLogger(__name__)

[docs]class Observable: '''Designe pattern observer ''' def __init__(self): '''Init Observable ''' self.observers = []
[docs] def add_observer(self, observer): ''' :param observer: ''' print('add ',observer.name) if observer not in self.observers: self.observers.append(observer) else: logger.debug('Failed to add: {}'.format(observer))
def _del_all_observer(self): '''_del_all_observer ''' self.observers = []
[docs] def del_observer(self, observer): ''' :param observer: ''' try: self.observers.remove(observer) except ValueError: logger.error('Failed to remove: {}'.format(observer))
[docs] def notify_observer(self): '''notify_observer ''' # [o.update(self) for o in self.observers] [o.update() for o in self.observers]
[docs]class ContextSimulator(Observable): """Defines a general simulation context for ECLAIRs observations """ def __init__(self): """**Constructor** """ super().__init__() # high level context simulator and tools for simulator self._sim_geom = SimuECLAIRsMaskProjection() self._mdl_effect = ECLAIRsDetectorEffectDefault() self._ecl_att = AttitudeECLAIRs() self._earth_fov = EarthInFov() # Parameters of simulation self._idx_chan = 0 """energy limits in keV""" self._e_min = 0 self._e_max = 0 """satellite unit quaternion""" self._quat_att = None """position [X, Y, Z] of SVOM in km in J2000""" self._pos = [0, 0, 0] self._id_pos = -1 """velocity [VX, VY, VZ] of SVOM in km/s in J2000""" self._vel = [0, 0, 0] """observation start time in s""" self._t_start = 0 """time duration in s""" self._duration = 0 # Getter @property def duration(self): '''duration ''' return self._duration @property def t_start(self): '''t_start ''' return self._t_start @property def eclairs_attitude(self): '''eclairs_attitude ''' return self._ecl_att @property def idx_chan(self): '''idx_chan ''' return self._idx_chan @property def pos_sat(self): '''pos_sat ''' return self._pos @property def energy_range(self): '''energy_range ''' return self._e_min, self._e_max @property def earth_pos_fov_unit(self): '''earth_pos_fov_unit ''' return self._earth_fov.get_fov_xyz() @property def earth_limb(self): '''earth_limb ''' return self._earth_fov.limb_angle() #TODO: peut etre passer en _earth_fov en publique, à voir ...
[docs] def open_fov_map(self): return self._earth_fov.open_fov_map()
[docs] def earth_frac(self): m = self._earth_fov.open_fov_map() return self._earth_fov.compute_earth_frac(m)
[docs] def is_in_fov(self): return self._earth_fov.is_in_fov()
# Setter def _set_energy_band(self, e_min, e_max): """Set the energy lower and upper limit for sources models classes .. warning:: must be renamed as _set_energy_band :param e_min: energy lower limit in keV :type e_min: float :param e_max: energy upper limit in keV :type e_max: float """ self._e_min = e_min self._e_max = e_max
[docs] def set_duration(self, duration): ''' :param duration: simulation time in s :type duration: float ''' self._duration = duration
[docs] def set_t_start(self, t_start): ''' :param t_start: start time of the simulated observation in s from mjdref :type t_start: float ''' self._t_start = t_start
[docs] def set_sim_geom(self, sim_pts): ''' :param sim_pts: ''' self._sim_geom = sim_pts
[docs] def set_mdl_effect(self, mdl_effect): ''' :param mdl_effect: ''' self._mdl_effect = mdl_effect
[docs] def set_quaternion_svom(self, quater): """ ..note :: proposal: add switch to allow the user to choose between specifying a quaternion or an attitude. Or split functions. """ self._ecl_att.set_attitude_svom_quater(quater) self._earth_fov.set_quater_svom(quater)
[docs] def set_idx_chan(self, idx_chan): """Set energy channel index :param idx_chan: energy channel index :type idx_chan: int """ self._idx_chan = idx_chan self._e_min = self._mdl_effect.chan_boundary[idx_chan] self._e_max = self._mdl_effect.chan_boundary[idx_chan + 1]
[docs] def set_pos_sat(self, pos): ''' :param pos: satellite position in km in GCRS frame :type pos: array 3 float ''' print("set position") if not isinstance(pos, np.ndarray): self._pos = np.array(pos) else: self._pos = pos self._earth_fov.set_pos_sat_time(self._pos) self._id_pos += 1 self.notify_observer()
[docs]class GlobalContextSimulator(ContextSimulator): """Create global simulation context. """ instance = None def __new__(cls, *args, **kargs): """ used singleton design pattern, ie only one instance of class ManageProcessusEcpi """ if cls.instance is None: return object.__new__(cls, *args, **kargs) else: return cls.instance def __init__(self): # REMENBER : self is the return of __new__ if GlobalContextSimulator.instance is None: super().__init__() GlobalContextSimulator.instance = self
[docs] def reset(self): self._del_all_observer() # JMC some tests reduce chanel or modify ECLAIRsDetectorEffect self._mdl_effect = ECLAIRsDetectorEffectDefault()