4 pbeastDefaultServer =
'https://pc-atlas-www.cern.ch' if os.getenv(
'PBEAST_SERVER_HTTPS_PROXY',
'').startswith(
'atlasgw')
else 'https://atlasop.cern.ch'
5 pbeastServer = os.getenv(
'PBEAST_SERVER', pbeastDefaultServer)
7 import libpbeastpy; pbeast = libpbeastpy.ServerProxy(pbeastServer)
8 import logging; log = logging.getLogger(
"DCSCalculator2.variable")
10 from bisect
import bisect
11 from collections.abc
import Collection, Iterable, Mapping
13 from itertools
import chain
15 from DQUtils.events
import process_iovs
16 from DQUtils.general
import timer
17 from DQUtils.sugar
import IOVSet, RANGEIOV_VAL, RunLumi, TimestampType, define_iov_type, make_iov_type
19 from DCSCalculator2
import config
20 from DCSCalculator2.consts
import RED, YELLOW, GREEN, GREY, GOOD, BAD, EMPTY
21 from DCSCalculator2.libcore
import map_channels
22 from DCSCalculator2.subdetector
import DCSC_DefectTranslate_Subdetector
23 from DCSCalculator2.variable
import DefectIOV, GoodIOV, DCSC_Variable
26 def __init__(self, folder, evaluator, *, mapping=None, **kwargs):
27 super().
__init__(folder, evaluator, **kwargs)
30 def read(self, query_range, folder_base, folder_name):
31 result = super().
read(query_range, folder_base, folder_name)
39 for channel, goodness
in self.evaluator(iov):
40 current =
GoodIOV(iov.since, iov.until, channel, goodness)
41 current._orig_iov = iov
49 return IOVSet(
sum(zip(*results), ()))
52 def __init__(self, folders, evaluator, *, mapping={}, **kwargs):
53 folder_merge =
','.
join(folders)
55 super().
__init__(folder_merge, evaluator, **kwargs)
59 def read(self, query_range, folder_base, folder_names):
61 folders = folder_names.split(
',')
63 for folder
in folders:
64 iovs = super().
read(query_range, folder_base, folder)
71 if config.opts.check_input_time:
72 self.print_time_info(iovs)
74 if log.isEnabledFor(logging.INFO):
75 input_hash =
hash(iovs)
76 self.input_hashes.
append(input_hash)
82 type_bases = [iovs.iov_type
for iovs
in inputs]
83 base_names = [base.__name__[:-4]
for base
in type_bases]
84 attributes = [base.lower()
for base
in base_names]
85 clazz =
make_iov_type(
'MERGER_OF_' +
'_AND_'.
join(base_names), tuple([
'channel'] + attributes))
87 inputs_by_channel = [iovs.by_channel
for iovs
in inputs]
88 all_channels =
sorted(
set(y
for x
in inputs_by_channel
for y
in x.keys()))
91 for channel
in all_channels:
92 c_inputs = [x[channel]
for x
in inputs_by_channel]
93 result.extend(iov
for iov
in self.
merge_inputs(clazz, channel, *c_inputs))
95 return IOVSet(result, iov_type=clazz, origin=self.
folder_names)
98 result = [clazz(since, until, channel, *states)
for since, until, states
in process_iovs(*inputs)]
99 return IOVSet(result, iov_type=clazz, origin=self.
folder_names)
103 "Stores the value of an object's attribute queried from pBeast"
105 class TDAQC_Variable(DCSC_Variable):
107 A variable which reads data from pBeast.
113 return int(timestamp/TDAQC_Variable.TIME_RATIO)
117 return TimestampType(timestamp*TDAQC_Variable.TIME_RATIO)
119 def __init__(self, query, evaluator, *, regex=False, mapping=dict(), force_mapping=
False, empty_value=
None):
126 self.partition, self.className, self.attribute, self.
path = query.split(
'.', 3)
130 return f
"<TDAQCVariable {self.query}>"
132 def read(self, query_range, query, *, regex=False):
134 Read the relevant data from pBeast for this variable, and convert them to COOL-like format
136 partition, className, attribute, path = query.split(
'.', 3)
138 log.info(f
"Querying pBeast object{'s using regex' if regex else ''} {query}")
140 since, until = query_range
141 since, until = TDAQC_Variable.timeCOOL2PBeast(since), TDAQC_Variable.timeCOOL2PBeast(until)
143 query_data = pbeast.get_data(partition, className, attribute, path, regex, since, until)
146 data.update(query_data[0].data)
148 def instantiate(since, until, channel, value):
149 if isinstance(value, list):
151 return PBeastIOV(TDAQC_Variable.timePBeast2COOL(since), TDAQC_Variable.timePBeast2COOL(until), channel, value)
154 for channel, entries
in data.items():
161 for point
in entries:
162 if point.value == value:
164 iovs.append(instantiate(since, point.ts, channel, value))
168 iovs.append(instantiate(since, last.ts, channel, value))
169 iovs = IOVSet(iovs, iov_type=PBeastIOV, origin=query)
171 if log.isEnabledFor(logging.INFO):
172 input_hash =
hash(iovs)
174 log.info(
" -> Input hash: % 09x (len=%i)", input_hash, len(iovs))
180 Calculate LB-wise "good" states
185 since, until = lbtime.first, lbtime.last
186 if self.timewise_folder:
190 RunLumi(until.Run, until.LumiBlock))
195 iovs = self.make_good_iovs(iovs)
197 iovs = self.map_input_channels(iovs)
199 if self.timewise_folder
and not config.opts.timewise:
201 with timer(
"Quantize %s (%i iovs over %i lbs)" %
202 (self.
query, len(iovs), len(lbtime))):
204 iovs = self.quantize(lbtime, iovs)
211 Determine if one input iov is good.
213 giov =
GoodIOV(iov.since, iov.until, self.
mapping.
get(iov.channel, iov.channel), self.evaluator(iov))
220 Determine if channels in one input iov are good.
223 for channel, goodness
in self.evaluator(iov):
224 current =
GoodIOV(iov.since, iov.until, channel, goodness)
225 current._orig_iov = iov
231 Determine whether each iov signifies a good or bad state.
236 return IOVSet(
sum(zip(*results), ()))
241 Determine if channels in one input iov are good.
245 iov_value = (((iov.value >> bit) & 1) == 1)
if iov.value
is not None else None
246 test_iov =
PBeastIOV(iov.since, iov.until, channel, iov_value)
247 current =
GoodIOV(iov.since, iov.until, channel, self.evaluator(test_iov))
248 current._orig_iov = iov
255 Determine if channels in one input iov are good.
259 iov_value = iov.value[index]
if iov.value
is not None else None
260 test_iov =
PBeastIOV(iov.since, iov.until, channel, iov_value)
261 current =
GoodIOV(iov.since, iov.until, channel, self.evaluator(test_iov))
262 current._orig_iov = iov
266 def load_current(filename:str, n_modules:int) -> tuple[list[float],list[tuple[float,...]]]:
267 from datetime
import datetime, timezone
268 from pkg_resources
import resource_string
269 data = resource_string(
'DCSCalculator2.subdetectors.data', filename).
decode().strip().
split(
'\n')
273 if not line
or line[0] ==
'#':
continue
275 current = tuple(
float(x)
for x
in line[1:])
276 if len(current) != n_modules:
277 log.warning(f
"Wrong number of modules ({len(current)}) in resource '{filename}' from {line[0]}. Setting thresholds to 0...")
278 current = (0.,) * n_modules
279 time = datetime.fromisoformat(line[0])
280 if time.tzinfo
is None: time = time.replace(tzinfo=timezone.utc)
281 time = time.timestamp()
282 result[time] = current
283 keys, values = zip(*
sorted(result.items()))
284 if not values: keys, values = [0.], [(0.,) * n_modules]
287 def get_current(data: tuple[list[float],list[tuple[float,...]]], timestamp:float) -> tuple[float, ...]:
288 timestamp = timestamp / 1e9
290 index =
max(bisect(keys, timestamp) - 1, 0)
293 get_sit_current = functools.partial(get_current,
load_current(
'afp_sit_current.dat', 16))
294 get_tdc_current = functools.partial(get_current,
load_current(
'afp_tdc_current.dat', 4))
297 A_FAR_GARAGE, A_NEAR_GARAGE, C_FAR_GARAGE, C_NEAR_GARAGE = 101, 105, 109, 113
298 A_FAR_SIT_HV, A_NEAR_SIT_HV, C_FAR_SIT_HV, C_NEAR_SIT_HV = 1, 5, 9, 13
299 A_FAR_SIT_LV, A_NEAR_SIT_LV, C_FAR_SIT_LV, C_NEAR_SIT_LV = 21, 25, 29, 33
300 A_FAR_TOF_HV, C_FAR_TOF_HV = 17, 19
301 A_FAR_TOF_LV, C_FAR_TOF_LV = 37, 39
305 STOPLESSLY_REMOVED = 5000
307 A_FAR_SIT_DISABLED, A_NEAR_SIT_DISABLED, C_FAR_SIT_DISABLED, C_NEAR_SIT_DISABLED = 1001, 1005, 1009, 1013
308 A_FAR_TOF_DISABLED, C_FAR_TOF_DISABLED = 1017, 1019
311 NAMING = [
'FSA0',
'FSA1',
'FSA2',
'FSA3',
312 'NSA0',
'NSA1',
'NSA2',
'NSA3',
313 'FSC0',
'FSC1',
'FSC2',
'FSC3',
314 'NSC0',
'NSC1',
'NSC2',
'NSC3',
315 'TDC-A-1',
'TDC-A-2',
316 'TDC-C-1',
'TDC-C-2']
319 GARAGE = [A_FAR_GARAGE, A_NEAR_GARAGE, C_FAR_GARAGE, C_NEAR_GARAGE]
320 SIT_HV = [A_FAR_SIT_HV, A_NEAR_SIT_HV, C_FAR_SIT_HV, C_NEAR_SIT_HV]
321 SIT_LV = [A_FAR_SIT_LV, A_NEAR_SIT_LV, C_FAR_SIT_LV, C_NEAR_SIT_LV]
322 TOF_HV = [A_FAR_TOF_HV, C_FAR_TOF_HV]
323 TOF_LV = [A_FAR_TOF_LV, C_FAR_TOF_LV]
325 SIT_DISABLED = [A_FAR_SIT_DISABLED, A_NEAR_SIT_DISABLED, C_FAR_SIT_DISABLED, C_NEAR_SIT_DISABLED]
326 TOF_DISABLED = [A_FAR_TOF_DISABLED, C_FAR_TOF_DISABLED]
329 SIT_HV_DEAD_BAND = 0.05
330 TOF_HV_DEAD_BAND = 0.90
332 SIT_LV_CURRENT_HIGH = 0.8
333 TOF_HV_CURRENT_LOW = 600
335 def mapChannels(*mapseqArgs: tuple[Collection[int], int]) -> dict[int, int]:
336 return dict(
chain(*[zip(channels,
range(defectChannel, defectChannel + len(channels)))
for channels, defectChannel
in mapseqArgs]))
339 return {channel:
range(channel, channel + count)
for count, channels
in countMap.items()
for channel
in channels}
342 return value
if value
is not None else default
344 class AFP(DCSC_DefectTranslate_Subdetector):
345 folder_base =
'/AFP/DCS'
354 lambda iov: iov.inphysics
is True,
355 mapping = {1: C_FAR_GARAGE, 2: C_NEAR_GARAGE, 3: A_FAR_GARAGE, 4: A_NEAR_GARAGE}
365 ([ 9, 10, 11, 12], A_FAR_SIT_LV ),
366 ([13, 14, 15, 16], A_NEAR_SIT_LV),
367 ([ 1, 2, 3, 4], C_FAR_SIT_LV ),
368 ([ 5, 6, 7, 8], C_NEAR_SIT_LV)
374 [
'SIT/HV',
'SIT/HV_VOLTAGE_SET'],
375 lambda iov: -
remove_None(iov.hv.voltage, 0) > iov.hv_voltage_set.voltageSet - SIT_HV_DEAD_BAND,
378 ([ 6, 7, 1, 2], A_FAR_SIT_HV ),
379 ([ 8, 3, 4, 9], A_NEAR_SIT_HV),
380 ([10, 11, 12, 5], C_FAR_SIT_HV ),
381 ([13, 14, 15, 16], C_NEAR_SIT_HV)),
383 ([ 1, 2, 3, 4], A_FAR_SIT_HV ),
384 ([ 5, 6, 7, 8], A_NEAR_SIT_HV),
385 ([ 9, 10, 11, 12], C_FAR_SIT_HV ),
386 ([13, 14, 15, 16], C_NEAR_SIT_HV))
395 mapping = {1: A_FAR_TOF_LV, 2: C_FAR_TOF_LV}
400 [
'TOF',
'TOF_PMT_VOLTAGE_SET'],
401 lambda iov: -
remove_None(iov.tof.pmt_voltage, 0) > iov.tof_pmt_voltage_set.pmt_voltageSet - TOF_HV_DEAD_BAND
and -
remove_None(iov.tof.pmt_current, 0) > TOF_HV_CURRENT_LOW,
403 'TOF': {1: A_FAR_TOF_HV, 2: C_FAR_TOF_HV},
404 'TOF_PMT_VOLTAGE_SET': {1: A_FAR_TOF_HV, 2: C_FAR_TOF_HV},
414 'ATLAS.RCStateInfo.state.RunCtrl.AFP',
415 lambda iov: iov.value ==
'RUNNING',
416 mapping = {
'RunCtrl.AFP': TTC_RESTART}
421 'ATLAS.RODBusyIS.BusyEnabled.Monitoring.afp_rodBusy-VLDB/RODBusy',
422 lambda iov: iov.value
is not False,
423 mapping = {
'Monitoring.afp_rodBusy-VLDB/RODBusy': {6: STOPLESSLY_REMOVED}}
428 'ATLAS.RceMonitoring.DisabledPerm.Monitoring.RceMonitoring_RCE[34]',
429 lambda iov: iov.value
is not True,
432 'Monitoring.RceMonitoring_RCE3':
mapChannels(([0, 2, 4, 6], A_NEAR_SIT_DISABLED), ([8, 10, 12, 14], A_FAR_SIT_DISABLED), ([9, 11], A_FAR_TOF_DISABLED)),
433 'Monitoring.RceMonitoring_RCE4':
mapChannels(([0, 2, 4, 6], C_NEAR_SIT_DISABLED), ([8, 10, 12, 14], C_FAR_SIT_DISABLED), ([9, 11], C_FAR_TOF_DISABLED)),
438 equality_breaker = 0.0001
440 dead_fraction_caution = 0 + equality_breaker
441 dead_fraction_bad = 0.25 + equality_breaker
444 1: [*GARAGE, TTC_RESTART, STOPLESSLY_REMOVED, *TOF_HV],
445 2: [*TOF_DISABLED, *TOF_LV],
446 4: [*SIT_DISABLED, *SIT_LV, *SIT_HV],
451 Merge input channel states across variables, taking the worst.
453 Ignore configuration variables and variables without channel.
457 states = [state
for state
in states
if state
and state.channel
is not None]
460 return min(state.good
for state
in states)
if len(states) > 0
else None
464 Calculate the dead fraction and the resulting traffic light code.
467 n_total = len(states)
468 n_working = states.count(GOOD)
469 n_bad = states.count(BAD)
470 n_unfilled = states.count(EMPTY)
472 assert n_total == len(self.
mapping[output_channel])
473 assert n_total - n_working - n_bad - n_unfilled == 0
475 n_config = n_total - n_unfilled
476 dead_fraction = 1. - n_working / n_total
486 if n_unfilled
and config.opts.mark_unfilled_grey:
489 return code, dead_fraction, 0., n_config, n_working
493 def translator_core(iovs):
494 return [
DefectIOV(iov.since, iov.until, defect_name,
True, comment=
comment(iov))
495 for iov
in iovs
if iov.channel == channel
and not iov._is_empty
and selector(iov)]
496 return translator_core
500 def combinator_core(iovs):
502 channel_iovs = iovs.by_channel
503 defect_iovs = [channel_iovs.get(channel)
for channel
in channels]
505 matched = [(state, group)
for state,group
in zip(states,channels)
if not state._is_empty
and selector(state)]
506 if len(matched) < 2:
continue
507 bad_channels = {iov.channel - group
for state,group
in matched
for iov
in state._orig_iovs
if not iov.good}
508 if len(bad_channels) < naffected:
continue
509 result.append(
DefectIOV(since, until, defect_name,
True, comment=
comment()))
511 return combinator_core
515 def selector_core(iov):
516 return iov.Code == color
521 if isinstance(nbad, int): nbad = [nbad]
522 def selector_core(iov):
523 return iov.NConfig - iov.NWorking
in nbad
527 super(AFP, self).
__init__(*args, **kwargs)
529 AFP.defect_translator(*cdsc)
534 (A_FAR_GARAGE,
'AFP_A_FAR_IN_GARAGE', AFP.color_selector(RED), AFP.comment_GARAGE),
535 (A_NEAR_GARAGE,
'AFP_A_NEAR_IN_GARAGE', AFP.color_selector(RED), AFP.comment_GARAGE),
536 (C_FAR_GARAGE,
'AFP_C_FAR_IN_GARAGE', AFP.color_selector(RED), AFP.comment_GARAGE),
537 (C_NEAR_GARAGE,
'AFP_C_NEAR_IN_GARAGE', AFP.color_selector(RED), AFP.comment_GARAGE),
539 (A_FAR_SIT_HV,
'AFP_A_FAR_SIT_PARTIALLY_OPERATIONAL_HV', AFP.nbad_selector([1]), AFP.comment_SIT_HV),
540 (A_NEAR_SIT_HV,
'AFP_A_NEAR_SIT_PARTIALLY_OPERATIONAL_HV', AFP.nbad_selector([1]), AFP.comment_SIT_HV),
541 (C_FAR_SIT_HV,
'AFP_C_FAR_SIT_PARTIALLY_OPERATIONAL_HV', AFP.nbad_selector([1]), AFP.comment_SIT_HV),
542 (C_NEAR_SIT_HV,
'AFP_C_NEAR_SIT_PARTIALLY_OPERATIONAL_HV', AFP.nbad_selector([1]), AFP.comment_SIT_HV),
543 (A_FAR_SIT_HV,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_HV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_HV),
544 (A_NEAR_SIT_HV,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_HV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_HV),
545 (C_FAR_SIT_HV,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_HV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_HV),
546 (C_NEAR_SIT_HV,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_HV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_HV),
548 (A_FAR_SIT_LV,
'AFP_A_FAR_SIT_PARTIALLY_OPERATIONAL_LV', AFP.nbad_selector([1]), AFP.comment_SIT_LV),
549 (A_NEAR_SIT_LV,
'AFP_A_NEAR_SIT_PARTIALLY_OPERATIONAL_LV', AFP.nbad_selector([1]), AFP.comment_SIT_LV),
550 (C_FAR_SIT_LV,
'AFP_C_FAR_SIT_PARTIALLY_OPERATIONAL_LV', AFP.nbad_selector([1]), AFP.comment_SIT_LV),
551 (C_NEAR_SIT_LV,
'AFP_C_NEAR_SIT_PARTIALLY_OPERATIONAL_LV', AFP.nbad_selector([1]), AFP.comment_SIT_LV),
552 (A_FAR_SIT_LV,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_LV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_LV),
553 (A_NEAR_SIT_LV,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_LV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_LV),
554 (C_FAR_SIT_LV,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_LV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_LV),
555 (C_NEAR_SIT_LV,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_LV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_LV),
556 (A_FAR_SIT_LV,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_LV_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_LV),
557 (A_NEAR_SIT_LV,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_LV_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_LV),
558 (C_FAR_SIT_LV,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_LV_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_LV),
559 (C_NEAR_SIT_LV,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_LV_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_LV),
561 (A_FAR_TOF_LV,
'AFP_A_FAR_TOF_NOT_OPERATIONAL_LV', AFP.color_selector(RED), AFP.comment_TOF_LV),
562 (C_FAR_TOF_LV,
'AFP_C_FAR_TOF_NOT_OPERATIONAL_LV', AFP.color_selector(RED), AFP.comment_TOF_LV),
564 (A_FAR_TOF_HV,
'AFP_A_FAR_TOF_NOT_OPERATIONAL_HV', AFP.color_selector(RED), AFP.comment_TOF_HV),
565 (C_FAR_TOF_HV,
'AFP_C_FAR_TOF_NOT_OPERATIONAL_HV', AFP.color_selector(RED), AFP.comment_TOF_HV),
570 (TTC_RESTART,
'AFP_TTC_RESTART', AFP.color_selector(RED), AFP.comment_TTC_RESTART),
571 (STOPLESSLY_REMOVED,
'AFP_STOPLESSLY_REMOVED', AFP.color_selector(RED), AFP.comment_STOPLESSLY_REMOVED),
573 (A_FAR_SIT_DISABLED,
'AFP_A_FAR_SIT_PARTIALLY_OPERATIONAL_TDAQ', AFP.nbad_selector([1]), AFP.comment_SIT_DISABLED),
574 (A_NEAR_SIT_DISABLED,
'AFP_A_NEAR_SIT_PARTIALLY_OPERATIONAL_TDAQ', AFP.nbad_selector([1]), AFP.comment_SIT_DISABLED),
575 (C_FAR_SIT_DISABLED,
'AFP_C_FAR_SIT_PARTIALLY_OPERATIONAL_TDAQ', AFP.nbad_selector([1]), AFP.comment_SIT_DISABLED),
576 (C_NEAR_SIT_DISABLED,
'AFP_C_NEAR_SIT_PARTIALLY_OPERATIONAL_TDAQ', AFP.nbad_selector([1]), AFP.comment_SIT_DISABLED),
577 (A_FAR_SIT_DISABLED,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_TDAQ', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_DISABLED),
578 (A_NEAR_SIT_DISABLED,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_TDAQ', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_DISABLED),
579 (C_FAR_SIT_DISABLED,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_TDAQ', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_DISABLED),
580 (C_NEAR_SIT_DISABLED,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_TDAQ', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_DISABLED),
581 (A_FAR_SIT_DISABLED,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_TDAQ_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_DISABLED),
582 (A_NEAR_SIT_DISABLED,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_TDAQ_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_DISABLED),
583 (C_FAR_SIT_DISABLED,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_TDAQ_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_DISABLED),
584 (C_NEAR_SIT_DISABLED,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_TDAQ_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_DISABLED),
586 (A_FAR_TOF_DISABLED,
'AFP_A_FAR_TOF_NOT_OPERATIONAL_TDAQ', AFP.color_selector(RED), AFP.comment_TOF_DISABLED),
587 (C_FAR_TOF_DISABLED,
'AFP_C_FAR_TOF_NOT_OPERATIONAL_TDAQ', AFP.color_selector(RED), AFP.comment_TOF_DISABLED),
590 AFP.defect_combinator(*cdsac)
592 ([A_FAR_SIT_LV, A_FAR_SIT_DISABLED],
'AFP_A_FAR_SIT_NOT_OPERATIONAL', AFP.nbad_selector([1]), 2, AFP.comment_SIT_COMBINATION),
593 ([A_NEAR_SIT_LV, A_NEAR_SIT_DISABLED],
'AFP_A_NEAR_SIT_NOT_OPERATIONAL', AFP.nbad_selector([1]), 2, AFP.comment_SIT_COMBINATION),
594 ([C_FAR_SIT_LV, C_FAR_SIT_DISABLED],
'AFP_C_FAR_SIT_NOT_OPERATIONAL', AFP.nbad_selector([1]), 2, AFP.comment_SIT_COMBINATION),
595 ([C_NEAR_SIT_LV, C_NEAR_SIT_DISABLED],
'AFP_C_NEAR_SIT_NOT_OPERATIONAL', AFP.nbad_selector([1]), 2, AFP.comment_SIT_COMBINATION),
596 ([A_FAR_SIT_LV, A_FAR_SIT_DISABLED],
'AFP_A_FAR_SIT_NOT_OPERATIONAL_3PLANES', AFP.nbad_selector([1, 2]), 3, AFP.comment_SIT_COMBINATION),
597 ([A_NEAR_SIT_LV, A_NEAR_SIT_DISABLED],
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_3PLANES', AFP.nbad_selector([1, 2]), 3, AFP.comment_SIT_COMBINATION),
598 ([C_FAR_SIT_LV, C_FAR_SIT_DISABLED],
'AFP_C_FAR_SIT_NOT_OPERATIONAL_3PLANES', AFP.nbad_selector([1, 2]), 3, AFP.comment_SIT_COMBINATION),
599 ([C_NEAR_SIT_LV, C_NEAR_SIT_DISABLED],
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_3PLANES', AFP.nbad_selector([1, 2]), 3, AFP.comment_SIT_COMBINATION),
609 return 'Station not in physics'
613 return AFP.comment_planes(iov,
'out of nominal current', SIT_LV[0])
617 return AFP.comment_planes(iov,
'out of nominal voltage', SIT_HV[0])
621 return AFP.comment_tof_tdc(iov,
'with too low current', TOF_LV[0])
625 return 'ToF PMT out of nominal voltage'
633 return 'AFP not in the RUNNING state'
637 return 'AFP stoplessly removed from the run'
641 return AFP.comment_planes(iov,
'removed from readout', SIT_DISABLED[0])
645 return AFP.comment_tof_tdc(iov,
'removed from readout', TOF_DISABLED[0])
653 return "Combination of 'partially operational' defects"
661 return AFP.comment_device(iov,
'SiT plane', message, defect_offset, module_tagger)
665 if defect_offset
is not None: defect_offset -= 16
666 return AFP.comment_device(iov,
'ToF TDC', message, defect_offset, module_tagger)
669 def comment_device(iov, device, message, defect_offset=None, module_tagger=None):
670 count = iov.NConfig - iov.NWorking
673 comment = f
"{count} {device} {message}"
674 if defect_offset
is None:
676 iovs =
sorted([orig
for orig
in iov._orig_iovs
if orig.good
is False], key=
lambda x: x.channel)
677 list = [NAMING[orig.channel - defect_offset]
for orig
in iovs]
678 if module_tagger
is not None:
679 list = [f
"{module} {module_tagger(orig)}" for module,orig
in zip(list,iovs)]
680 return comment + f
" ({', '.join(list)})"