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 itertools
import chain
12 from types
import GenericAlias
14 from DQUtils.events
import process_iovs
15 from DQUtils.general
import timer
16 from DQUtils.sugar
import IOVSet, RANGEIOV_VAL, RunLumi, TimestampType, define_iov_type, make_iov_type
18 from DCSCalculator2
import config
19 from DCSCalculator2.consts
import RED, YELLOW, GREEN, GREY, GOOD, BAD, EMPTY
20 from DCSCalculator2.libcore
import map_channels
21 from DCSCalculator2.subdetector
import DCSC_DefectTranslate_Subdetector
22 from DCSCalculator2.variable
import DefectIOV, GoodIOV, DCSC_Variable
25 def __init__(self, folder, evaluator, *, mapping=None, **kwargs):
26 super().
__init__(folder, evaluator, **kwargs)
29 def read(self, query_range, folder_base, folder_name):
30 result = super().
read(query_range, folder_base, folder_name)
38 for channel, goodness
in self.evaluator(iov):
39 current =
GoodIOV(iov.since, iov.until, channel, goodness)
40 current._orig_iov = iov
48 return IOVSet(
sum(zip(*results), ()))
51 def __init__(self, folders, evaluator, *, mapping={}, **kwargs):
52 folder_merge =
','.
join(folders)
54 super().
__init__(folder_merge, evaluator, **kwargs)
59 for var
in self.variables:
60 if var.folder_name == name:
62 raise RuntimeError(
"Folder '%s' not found" % name)
64 def read(self, query_range, folder_base, folder_names):
66 folders = folder_names.split(
',')
68 for folder
in folders:
69 iovs = super().
read(query_range, folder_base, folder)
76 if config.opts.check_input_time:
77 self.print_time_info(iovs)
79 if log.isEnabledFor(logging.INFO):
80 input_hash =
hash(iovs)
81 self.input_hashes.
append(input_hash)
87 type_bases = [iovs.iov_type
for iovs
in inputs]
88 base_names = [base.__name__[:-4]
for base
in type_bases]
89 attributes = [base.lower()
for base
in base_names]
90 clazz =
make_iov_type(
'MERGER_OF_' +
'_AND_'.
join(base_names), tuple([
'channel'] + attributes))
92 inputs_by_channel = [iovs.by_channel
for iovs
in inputs]
93 all_channels =
sorted(
set(y
for x
in inputs_by_channel
for y
in x.keys()))
96 for channel
in all_channels:
97 c_inputs = [x[channel]
for x
in inputs_by_channel]
98 result.extend(iov
for iov
in self.
merge_inputs(clazz, channel, *c_inputs))
100 return IOVSet(result, iov_type=clazz, origin=self.
folder_names)
103 result = [clazz(since, until, channel, *states)
for since, until, states
in process_iovs(*inputs)]
104 return IOVSet(result, iov_type=clazz, origin=self.
folder_names)
108 "Stores the value of an object's attribute queried from pBeast"
110 class TDAQC_Variable(DCSC_Variable):
112 A variable which reads data from pBeast.
118 return int(timestamp/TDAQC_Variable.TIME_RATIO)
122 return TimestampType(timestamp*TDAQC_Variable.TIME_RATIO)
124 def __init__(self, query, evaluator, *, regex=False, mapping=dict(), force_mapping=
False, empty_value=
None):
131 self.partition, self.className, self.attribute, self.
path = query.split(
'.', 3)
135 return f
"<TDAQCVariable {self.query}>"
137 def read(self, query_range, query, *, regex=False):
139 Read the relevant data from pBeast for this variable, and convert them to COOL-like format
141 partition, className, attribute, path = query.split(
'.', 3)
143 log.info(f
"Querying pBeast object{'s using regex' if regex else ''} {query}")
145 since, until = query_range
146 since, until = TDAQC_Variable.timeCOOL2PBeast(since), TDAQC_Variable.timeCOOL2PBeast(until)
148 query_data = pbeast.get_data(partition, className, attribute, path, regex, since, until)
151 data.update(query_data[0].data)
153 def instantiate(since, until, channel, value):
154 if isinstance(value, list):
156 return PBeastIOV(TDAQC_Variable.timePBeast2COOL(since), TDAQC_Variable.timePBeast2COOL(until), channel, value)
159 for channel, entries
in data.items():
166 for point
in entries:
167 if point.value == value:
169 iovs.append(instantiate(since, point.ts, channel, value))
173 iovs.append(instantiate(since, last.ts, channel, value))
174 iovs = IOVSet(iovs, iov_type=PBeastIOV, origin=query)
176 if log.isEnabledFor(logging.INFO):
177 input_hash =
hash(iovs)
179 log.info(
" -> Input hash: % 09x (len=%i)", input_hash, len(iovs))
185 Calculate LB-wise "good" states
190 since, until = lbtime.first, lbtime.last
191 if self.timewise_folder:
195 RunLumi(until.Run, until.LumiBlock))
200 iovs = self.make_good_iovs(iovs)
202 iovs = self.map_input_channels(iovs)
204 if self.timewise_folder
and not config.opts.timewise:
206 with timer(
"Quantize %s (%i iovs over %i lbs)" %
207 (self.
query, len(iovs), len(lbtime))):
209 iovs = self.quantize(lbtime, iovs)
216 Determine if one input iov is good.
218 giov =
GoodIOV(iov.since, iov.until, self.
mapping.
get(iov.channel, iov.channel), self.evaluator(iov))
225 Determine if channels in one input iov are good.
228 for channel, goodness
in self.evaluator(iov):
229 current =
GoodIOV(iov.since, iov.until, channel, goodness)
230 current._orig_iov = iov
236 Determine whether each iov signifies a good or bad state.
241 return IOVSet(
sum(zip(*results), ()))
246 Determine if channels in one input iov are good.
250 iov_value = (((iov.value >> bit) & 1) == 1)
if iov.value
is not None else None
251 test_iov =
PBeastIOV(iov.since, iov.until, channel, iov_value)
252 current =
GoodIOV(iov.since, iov.until, channel, self.evaluator(test_iov))
253 current._orig_iov = iov
260 Determine if channels in one input iov are good.
264 iov_value = iov.value[index]
if iov.value
is not None else None
265 test_iov =
PBeastIOV(iov.since, iov.until, channel, iov_value)
266 current =
GoodIOV(iov.since, iov.until, channel, self.evaluator(test_iov))
267 current._orig_iov = iov
271 SiT_LV_Current_Type = GenericAlias(tuple, (float,)*16)
273 from datetime
import datetime, timezone
274 from pkg_resources
import resource_string
275 sit_current = resource_string(
'DCSCalculator2.subdetectors.data',
'afp_sit_current.dat').
decode().strip().
split(
'\n')
277 for line
in sit_current:
279 if not line
or line[0] ==
'#':
continue
281 current = tuple(
float(x)
for x
in line[1:])
282 if len(current) != 16:
283 log.warn(f
"Wrong number of AFP SiT planes ({len(current)}) in the LV resource from {line[0]}. Setting thresholds to 0...")
285 assert(len(current) == 16)
286 time = datetime.fromisoformat(line[0])
287 if time.tzinfo
is None: time = time.replace(tzinfo=timezone.utc)
288 time = time.timestamp()
289 result[time] = current
290 keys, values = zip(*
sorted(result.items()))
293 SIT_LV_CURRENT_LOW_DATA:tuple[list[float],list[SiT_LV_Current_Type]] =
load_sit_current()
295 timestamp = timestamp / 1e9
296 keys, values = SIT_LV_CURRENT_LOW_DATA
297 index =
max(bisect(keys, timestamp) - 1, 0)
298 return values[index]
if values
else [0] * 16
301 A_FAR_GARAGE, A_NEAR_GARAGE, C_FAR_GARAGE, C_NEAR_GARAGE = 101, 105, 109, 113
302 A_FAR_SIT_HV, A_NEAR_SIT_HV, C_FAR_SIT_HV, C_NEAR_SIT_HV = 1, 5, 9, 13
303 A_FAR_SIT_LV, A_NEAR_SIT_LV, C_FAR_SIT_LV, C_NEAR_SIT_LV = 21, 25, 29, 33
304 A_FAR_TOF_HV, C_FAR_TOF_HV = 17, 19
305 A_FAR_TOF_LV, C_FAR_TOF_LV = 37, 39
309 STOPLESSLY_REMOVED = 5000
311 A_FAR_SIT_DISABLED, A_NEAR_SIT_DISABLED, C_FAR_SIT_DISABLED, C_NEAR_SIT_DISABLED = 1001, 1005, 1009, 1013
312 A_FAR_TOF_DISABLED, C_FAR_TOF_DISABLED = 1017, 1019
315 NAMING = [
'FSA0',
'FSA1',
'FSA2',
'FSA3',
316 'NSA0',
'NSA1',
'NSA2',
'NSA3',
317 'FSC0',
'FSC1',
'FSC2',
'FSC3',
318 'NSC0',
'NSC1',
'NSC2',
'NSC3',
319 'TDC-A-1',
'TDC-A-2',
320 'TDC-C-1',
'TDC-C-2']
323 GARAGE = [A_FAR_GARAGE, A_NEAR_GARAGE, C_FAR_GARAGE, C_NEAR_GARAGE]
324 SIT_HV = [A_FAR_SIT_HV, A_NEAR_SIT_HV, C_FAR_SIT_HV, C_NEAR_SIT_HV]
325 SIT_LV = [A_FAR_SIT_LV, A_NEAR_SIT_LV, C_FAR_SIT_LV, C_NEAR_SIT_LV]
326 TOF_HV = [A_FAR_TOF_HV, C_FAR_TOF_HV]
327 TOF_LV = [A_FAR_TOF_LV, C_FAR_TOF_LV]
329 SIT_DISABLED = [A_FAR_SIT_DISABLED, A_NEAR_SIT_DISABLED, C_FAR_SIT_DISABLED, C_NEAR_SIT_DISABLED]
330 TOF_DISABLED = [A_FAR_TOF_DISABLED, C_FAR_TOF_DISABLED]
333 SIT_HV_DEAD_BAND = 0.05
334 TOF_HV_DEAD_BAND = 0.90
341 SIT_LV_CURRENT_LOW = get_sit_current
342 SIT_LV_CURRENT_HIGH = 0.8
343 TOF_HV_CURRENT_LOW = 600
344 TOF_LV_CURRENT_LOW = 1.4
347 return dict(
chain(*[zip(channels,
range(defectChannel, defectChannel + len(channels)))
for channels, defectChannel
in mapseqArgs]))
350 return {channel:
range(channel, channel + count)
for count, channels
in countMap.items()
for channel
in channels}
353 return value
if value
is not None else default
355 class AFP(DCSC_DefectTranslate_Subdetector):
356 folder_base =
'/AFP/DCS'
365 lambda iov: iov.inphysics
is True,
366 mapping = {1: C_FAR_GARAGE, 2: C_NEAR_GARAGE, 3: A_FAR_GARAGE, 4: A_NEAR_GARAGE}
376 ([ 9, 10, 11, 12], A_FAR_SIT_LV ),
377 ([13, 14, 15, 16], A_NEAR_SIT_LV),
378 ([ 1, 2, 3, 4], C_FAR_SIT_LV ),
379 ([ 5, 6, 7, 8], C_NEAR_SIT_LV)
385 [
'SIT/HV',
'SIT/HV_VOLTAGE_SET'],
386 lambda iov: -
remove_None(iov.hv.voltage, 0) > iov.hv_voltage_set.voltageSet - SIT_HV_DEAD_BAND,
389 ([ 6, 7, 1, 2], A_FAR_SIT_HV ),
390 ([ 8, 3, 4, 9], A_NEAR_SIT_HV),
391 ([10, 11, 12, 5], C_FAR_SIT_HV ),
392 ([13, 14, 15, 16], C_NEAR_SIT_HV)),
394 ([ 1, 2, 3, 4], A_FAR_SIT_HV ),
395 ([ 5, 6, 7, 8], A_NEAR_SIT_HV),
396 ([ 9, 10, 11, 12], C_FAR_SIT_HV ),
397 ([13, 14, 15, 16], C_NEAR_SIT_HV))
404 lambda iov: [(iov.channel, TOF_LV_CURRENT_LOW <=
remove_None(iov.hptdc1_current, 0)),
405 (iov.channel + 1, TOF_LV_CURRENT_LOW <=
remove_None(iov.hptdc2_current, 0))],
406 mapping = {1: A_FAR_TOF_LV, 2: C_FAR_TOF_LV}
411 [
'TOF',
'TOF_PMT_VOLTAGE_SET'],
412 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,
414 'TOF': {1: A_FAR_TOF_HV, 2: C_FAR_TOF_HV},
415 'TOF_PMT_VOLTAGE_SET': {1: A_FAR_TOF_HV, 2: C_FAR_TOF_HV},
425 'ATLAS.RCStateInfo.state.RunCtrl.AFP',
426 lambda iov: iov.value ==
'RUNNING',
427 mapping = {
'RunCtrl.AFP': TTC_RESTART}
432 'ATLAS.RODBusyIS.BusyEnabled.Monitoring.afp_rodBusy-VLDB/RODBusy',
433 lambda iov: iov.value
is not False,
434 mapping = {
'Monitoring.afp_rodBusy-VLDB/RODBusy': {6: STOPLESSLY_REMOVED}}
439 'ATLAS.RceMonitoring.DisabledPerm.Monitoring.RceMonitoring_RCE[34]',
440 lambda iov: iov.value
is not True,
443 '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)),
444 '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)),
449 equality_breaker = 0.0001
451 dead_fraction_caution = 0 + equality_breaker
452 dead_fraction_bad = 0.25 + equality_breaker
455 1: [*GARAGE, TTC_RESTART, STOPLESSLY_REMOVED, *TOF_HV],
456 2: [*TOF_DISABLED, *TOF_LV],
457 4: [*SIT_DISABLED, *SIT_LV, *SIT_HV],
462 Merge input channel states across variables, taking the worst.
464 Ignore configuration variables and variables without channel.
468 states = [state
for state
in states
if state
and state.channel
is not None]
471 return min(state.good
for state
in states)
if len(states) > 0
else None
475 Calculate the dead fraction and the resulting traffic light code.
478 n_total = len(states)
479 n_working = states.count(GOOD)
480 n_bad = states.count(BAD)
481 n_unfilled = states.count(EMPTY)
483 assert n_total == len(self.
mapping[output_channel])
484 assert n_total - n_working - n_bad - n_unfilled == 0
486 n_config = n_total - n_unfilled
487 dead_fraction = 1. - n_working / n_total
497 if n_unfilled
and config.opts.mark_unfilled_grey:
500 return code, dead_fraction, 0., n_config, n_working
504 def translator_core(iovs):
505 return [
DefectIOV(iov.since, iov.until, defect_name,
True, comment=
comment(iov))
506 for iov
in iovs
if iov.channel == channel
and not iov._is_empty
and selector(iov)]
507 return translator_core
511 def combinator_core(iovs):
513 channel_iovs = iovs.by_channel
514 defect_iovs = [channel_iovs.get(channel)
for channel
in channels]
516 matched = [(state, group)
for state,group
in zip(states,channels)
if not state._is_empty
and selector(state)]
517 if len(matched) < 2:
continue
518 bad_channels = {iov.channel - group
for state,group
in matched
for iov
in state._orig_iovs
if not iov.good}
519 if len(bad_channels) < naffected:
continue
520 result.append(
DefectIOV(since, until, defect_name,
True, comment=
comment()))
522 return combinator_core
526 def selector_core(iov):
527 return iov.Code == color
532 if isinstance(nbad, int): nbad = [nbad]
533 def selector_core(iov):
534 return iov.NConfig - iov.NWorking
in nbad
538 super(AFP, self).
__init__(*args, **kwargs)
540 AFP.defect_translator(*cdsc)
545 (A_FAR_GARAGE,
'AFP_A_FAR_IN_GARAGE', AFP.color_selector(RED), AFP.comment_GARAGE),
546 (A_NEAR_GARAGE,
'AFP_A_NEAR_IN_GARAGE', AFP.color_selector(RED), AFP.comment_GARAGE),
547 (C_FAR_GARAGE,
'AFP_C_FAR_IN_GARAGE', AFP.color_selector(RED), AFP.comment_GARAGE),
548 (C_NEAR_GARAGE,
'AFP_C_NEAR_IN_GARAGE', AFP.color_selector(RED), AFP.comment_GARAGE),
550 (A_FAR_SIT_HV,
'AFP_A_FAR_SIT_PARTIALLY_OPERATIONAL_HV', AFP.nbad_selector([1]), AFP.comment_SIT_HV),
551 (A_NEAR_SIT_HV,
'AFP_A_NEAR_SIT_PARTIALLY_OPERATIONAL_HV', AFP.nbad_selector([1]), AFP.comment_SIT_HV),
552 (C_FAR_SIT_HV,
'AFP_C_FAR_SIT_PARTIALLY_OPERATIONAL_HV', AFP.nbad_selector([1]), AFP.comment_SIT_HV),
553 (C_NEAR_SIT_HV,
'AFP_C_NEAR_SIT_PARTIALLY_OPERATIONAL_HV', AFP.nbad_selector([1]), AFP.comment_SIT_HV),
554 (A_FAR_SIT_HV,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_HV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_HV),
555 (A_NEAR_SIT_HV,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_HV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_HV),
556 (C_FAR_SIT_HV,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_HV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_HV),
557 (C_NEAR_SIT_HV,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_HV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_HV),
559 (A_FAR_SIT_LV,
'AFP_A_FAR_SIT_PARTIALLY_OPERATIONAL_LV', AFP.nbad_selector([1]), AFP.comment_SIT_LV),
560 (A_NEAR_SIT_LV,
'AFP_A_NEAR_SIT_PARTIALLY_OPERATIONAL_LV', AFP.nbad_selector([1]), AFP.comment_SIT_LV),
561 (C_FAR_SIT_LV,
'AFP_C_FAR_SIT_PARTIALLY_OPERATIONAL_LV', AFP.nbad_selector([1]), AFP.comment_SIT_LV),
562 (C_NEAR_SIT_LV,
'AFP_C_NEAR_SIT_PARTIALLY_OPERATIONAL_LV', AFP.nbad_selector([1]), AFP.comment_SIT_LV),
563 (A_FAR_SIT_LV,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_LV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_LV),
564 (A_NEAR_SIT_LV,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_LV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_LV),
565 (C_FAR_SIT_LV,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_LV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_LV),
566 (C_NEAR_SIT_LV,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_LV', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_LV),
567 (A_FAR_SIT_LV,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_LV_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_LV),
568 (A_NEAR_SIT_LV,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_LV_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_LV),
569 (C_FAR_SIT_LV,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_LV_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_LV),
570 (C_NEAR_SIT_LV,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_LV_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_LV),
572 (A_FAR_TOF_LV,
'AFP_A_FAR_TOF_NOT_OPERATIONAL_LV', AFP.color_selector(RED), AFP.comment_TOF_LV),
573 (C_FAR_TOF_LV,
'AFP_C_FAR_TOF_NOT_OPERATIONAL_LV', AFP.color_selector(RED), AFP.comment_TOF_LV),
575 (A_FAR_TOF_HV,
'AFP_A_FAR_TOF_NOT_OPERATIONAL_HV', AFP.color_selector(RED), AFP.comment_TOF_HV),
576 (C_FAR_TOF_HV,
'AFP_C_FAR_TOF_NOT_OPERATIONAL_HV', AFP.color_selector(RED), AFP.comment_TOF_HV),
581 (TTC_RESTART,
'AFP_TTC_RESTART', AFP.color_selector(RED), AFP.comment_TTC_RESTART),
582 (STOPLESSLY_REMOVED,
'AFP_STOPLESSLY_REMOVED', AFP.color_selector(RED), AFP.comment_STOPLESSLY_REMOVED),
584 (A_FAR_SIT_DISABLED,
'AFP_A_FAR_SIT_PARTIALLY_OPERATIONAL_TDAQ', AFP.nbad_selector([1]), AFP.comment_SIT_DISABLED),
585 (A_NEAR_SIT_DISABLED,
'AFP_A_NEAR_SIT_PARTIALLY_OPERATIONAL_TDAQ', AFP.nbad_selector([1]), AFP.comment_SIT_DISABLED),
586 (C_FAR_SIT_DISABLED,
'AFP_C_FAR_SIT_PARTIALLY_OPERATIONAL_TDAQ', AFP.nbad_selector([1]), AFP.comment_SIT_DISABLED),
587 (C_NEAR_SIT_DISABLED,
'AFP_C_NEAR_SIT_PARTIALLY_OPERATIONAL_TDAQ', AFP.nbad_selector([1]), AFP.comment_SIT_DISABLED),
588 (A_FAR_SIT_DISABLED,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_TDAQ', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_DISABLED),
589 (A_NEAR_SIT_DISABLED,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_TDAQ', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_DISABLED),
590 (C_FAR_SIT_DISABLED,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_TDAQ', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_DISABLED),
591 (C_NEAR_SIT_DISABLED,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_TDAQ', AFP.nbad_selector([2, 3, 4]), AFP.comment_SIT_DISABLED),
592 (A_FAR_SIT_DISABLED,
'AFP_A_FAR_SIT_NOT_OPERATIONAL_TDAQ_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_DISABLED),
593 (A_NEAR_SIT_DISABLED,
'AFP_A_NEAR_SIT_NOT_OPERATIONAL_TDAQ_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_DISABLED),
594 (C_FAR_SIT_DISABLED,
'AFP_C_FAR_SIT_NOT_OPERATIONAL_TDAQ_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_DISABLED),
595 (C_NEAR_SIT_DISABLED,
'AFP_C_NEAR_SIT_NOT_OPERATIONAL_TDAQ_3PLANES', AFP.nbad_selector([3, 4]), AFP.comment_SIT_DISABLED),
597 (A_FAR_TOF_DISABLED,
'AFP_A_FAR_TOF_NOT_OPERATIONAL_TDAQ', AFP.color_selector(RED), AFP.comment_TOF_DISABLED),
598 (C_FAR_TOF_DISABLED,
'AFP_C_FAR_TOF_NOT_OPERATIONAL_TDAQ', AFP.color_selector(RED), AFP.comment_TOF_DISABLED),
601 AFP.defect_combinator(*cdsac)
603 ([A_FAR_SIT_LV, A_FAR_SIT_DISABLED],
'AFP_A_FAR_SIT_NOT_OPERATIONAL', AFP.nbad_selector([1]), 2, AFP.comment_SIT_COMBINATION),
604 ([A_NEAR_SIT_LV, A_NEAR_SIT_DISABLED],
'AFP_A_NEAR_SIT_NOT_OPERATIONAL', AFP.nbad_selector([1]), 2, AFP.comment_SIT_COMBINATION),
605 ([C_FAR_SIT_LV, C_FAR_SIT_DISABLED],
'AFP_C_FAR_SIT_NOT_OPERATIONAL', AFP.nbad_selector([1]), 2, AFP.comment_SIT_COMBINATION),
606 ([C_NEAR_SIT_LV, C_NEAR_SIT_DISABLED],
'AFP_C_NEAR_SIT_NOT_OPERATIONAL', AFP.nbad_selector([1]), 2, AFP.comment_SIT_COMBINATION),
607 ([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),
608 ([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),
609 ([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),
610 ([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),
620 return 'Station not in physics'
624 return AFP.comment_planes(iov,
'out of nominal current', SIT_LV[0])
628 return AFP.comment_planes(iov,
'out of nominal voltage', SIT_HV[0])
632 return AFP.comment_tof_tdc(iov,
'with too low current', TOF_LV[0])
636 return 'ToF PMT out of nominal voltage'
644 return 'AFP not in the RUNNING state'
648 return 'AFP stoplessly removed from the run'
652 return AFP.comment_planes(iov,
'removed from readout', SIT_DISABLED[0])
656 return AFP.comment_tof_tdc(iov,
'removed from readout', TOF_DISABLED[0])
664 return "Combination of 'partially operational' defects"
672 return AFP.comment_device(iov,
'SiT plane', message, defect_offset, module_tagger)
676 return AFP.comment_device(iov,
'ToF TDC', message, defect_offset - 16, module_tagger)
679 def comment_device(iov, device, message, defect_offset=None, module_tagger=None):
680 count = iov.NConfig - iov.NWorking
683 comment = f
"{count} {device} {message}"
684 if defect_offset
is None:
686 iovs =
sorted([orig
for orig
in iov._orig_iovs
if orig.good
is False], key=
lambda x: x.channel)
687 list = [NAMING[orig.channel - defect_offset]
for orig
in iovs]
688 if module_tagger
is not None:
689 list = [f
"{module} {module_tagger(orig)}" for module,orig
in zip(list,iovs)]
690 return comment + f
" ({', '.join(list)})"