Hide keyboard shortcuts

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 

5 

6 

7__all__ = ["DowntimeModel"] 

8 

9 

10class DowntimeModel(object): 

11 """Downtime estimates, both scheduled and unscheduled. 

12 

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. 

20 

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 

35 

36 def configure(self, config=None): 

37 """Configure the model. After 'configure' the model config will be frozen. 

38 

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() 

58 

59 def config_info(self): 

60 """Report configuration parameters and version information. 

61 

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 

72 

73 def __call__(self, efdData, targetDict): 

74 """Calculate the sky coverage due to clouds. 

75 

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. 

86 

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 

114 

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']}