Coverage for python/lsst/sims/downtimeModel/downtimeModel.py : 13%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from builtins import object
2from collections import OrderedDict
3from .downtimeModelConfig import DowntimeModelConfig
4from lsst.sims.downtimeModel import version
7__all__ = ["DowntimeModel"]
10class DowntimeModel(object):
11 """Downtime estimates, both scheduled and unscheduled.
13 Parameters
14 ----------
15 config: DowntimeModelConfig, opt
16 A configuration class for the downtime model.
17 This can be None, in which case the default DowntimeModelConfig is used.
18 The user should set any non-default values for DowntimeModelConfig before
19 configuration of the actual DowntimeModel.
21 self.efd_requirements and self.target_requirements are also set.
22 efd_requirements is a tuple: (list of str, float).
23 This corresponds to the data columns required from the EFD and the amount of time history required.
24 target_requirements is a list of str.
25 This corresponds to the data columns required in the target dictionary passed when calculating the
26 processed telemetry values.
27 """
28 def __init__(self, config=None):
29 self._config = None
30 self.configure(config=config)
31 self.efd_requirements = (self._config.efd_columns, self._config.efd_delta_time)
32 self.schedDown = self._config.efd_columns[0]
33 self.unschedDown = self._config.efd_columns[1]
34 self.target_requirements = self._config.target_columns
36 def configure(self, config=None):
37 """Configure the model. After 'configure' the model config will be frozen.
39 Parameters
40 ----------
41 config: DowntimeModelConfig, opt
42 A configuration class for the downtime model.
43 This can be None, in which case the default values are used.
44 """
45 if config is None:
46 self._config = DowntimeModelConfig()
47 elif isinstance(config, dict):
48 self._config = DowntimeModelConfig()
49 for key in config:
50 setattr(self._config, key, config[key])
51 elif isinstance(config, DowntimeModelConfig):
52 self._config = config
53 else:
54 raise RuntimeError(f'Expecting `None`, dictionary or `DowntimeModelConfig`, '
55 f'got {type(config)}: {config!r}.')
56 self._config.validate()
57 self._config.freeze()
59 def config_info(self):
60 """Report configuration parameters and version information.
62 Returns
63 -------
64 OrderedDict
65 """
66 config_info = OrderedDict()
67 config_info['DowntimeModel_version'] = '%s' % version.__version__
68 config_info['DowntimeModel_sha'] = '%s' % version.__fingerprint__
69 for k, v in self._config.iteritems():
70 config_info[k] = v
71 return config_info
73 def __call__(self, efdData, targetDict):
74 """Calculate the sky coverage due to clouds.
76 Parameters
77 ----------
78 efdData: dict
79 Dictionary of input telemetry, typically from the EFD.
80 This must contain columns self.efd_requirements.
81 (work in progress on handling time history).
82 targetDict: dict
83 Dictionary of target values over which to calculate the processed telemetry.
84 (e.g. mapDict = {'ra': [], 'dec': [], 'altitude': [], 'azimuth': [], 'airmass': []})
85 Here we use 'time', an astropy.time.Time, as we just need to know the time.
87 Returns
88 -------
89 dict of bool, astropy.time.Time, astropy.time.Time
90 Status of telescope (True = Down, False = Up) at time,
91 time of expected end of downtime (~noon of the first available day),
92 time of next scheduled downtime (~noon of the first available day).
93 """
94 # Check for downtime in scheduled downtimes.
95 time = targetDict[self.target_requirements[0]]
96 next_start = efdData[self.schedDown]['start'].searchsorted(time, side='right')
97 next_end = efdData[self.schedDown]['end'].searchsorted(time, side='right')
98 if next_start > next_end:
99 # Currently in a scheduled downtime.
100 current_sched = efdData[self.schedDown][next_end]
101 else:
102 # Not currently in a scheduled downtime.
103 current_sched = None
104 # This will be the next reported/expected downtime.
105 next_sched = efdData[self.schedDown][next_start]
106 # Check for downtime in unscheduled downtimes.
107 next_start = efdData[self.unschedDown]['start'].searchsorted(time, side='right')
108 next_end = efdData[self.unschedDown]['end'].searchsorted(time, side='right')
109 if next_start > next_end:
110 # Currently in an unscheduled downtime.
111 current_unsched = efdData[self.unschedDown][next_end]
112 else:
113 current_unsched = None
115 # Figure out what to report about current state.
116 if current_sched is None and current_unsched is None: # neither down
117 status = False
118 end_down = None
119 else: # we have a downtime from something ..
120 if current_unsched is None: # sched down only
121 status = True
122 end_down = current_sched['end']
123 elif current_sched is None: # unsched down only
124 status = True
125 # should decide what to report on end of downtime here ..
126 end_down = current_unsched['end']
127 else: # both down ..
128 status = True
129 end_down = max(current_sched['end'], current_unsched['end'])
130 return {'status': status, 'end': end_down, 'next': next_sched['start']}