From 177bdb2252b8bc6189c3e272a949f4a6ed1d08e1 Mon Sep 17 00:00:00 2001 From: Duncan Meacher <duncan.meacher@ligo.org> Date: Thu, 21 Sep 2017 16:37:57 -0700 Subject: [PATCH] Added ETG offline pipeline gen tool --- gstlal-ugly/bin/Makefile.am | 3 +- gstlal-ugly/bin/gstlal_etg | 62 +++--- gstlal-ugly/bin/gstlal_etg_pipe | 178 ++++++++++++++++++ gstlal-ugly/python/multichannel_datasource.py | 56 +++++- .../share/etg/Makefile.gstlal_etg_offline | 91 +++++++++ gstlal-ugly/share/etg/channel_list.txt | 100 ++++++++++ 6 files changed, 453 insertions(+), 37 deletions(-) create mode 100755 gstlal-ugly/bin/gstlal_etg_pipe create mode 100644 gstlal-ugly/share/etg/Makefile.gstlal_etg_offline create mode 100644 gstlal-ugly/share/etg/channel_list.txt diff --git a/gstlal-ugly/bin/Makefile.am b/gstlal-ugly/bin/Makefile.am index 8bd2554f1f..5c159cb5cf 100644 --- a/gstlal-ugly/bin/Makefile.am +++ b/gstlal-ugly/bin/Makefile.am @@ -33,4 +33,5 @@ dist_bin_SCRIPTS = \ gstlal_ll_dq \ gstlal_ll_inspiral_state \ gstlal_condor_top \ - gstlal_etg + gstlal_etg \ + gstlal_etg_pipe diff --git a/gstlal-ugly/bin/gstlal_etg b/gstlal-ugly/bin/gstlal_etg index 7ce440de29..ffef4cf20e 100755 --- a/gstlal-ugly/bin/gstlal_etg +++ b/gstlal-ugly/bin/gstlal_etg @@ -144,34 +144,6 @@ def phi_ql(phi_min, phi_max, q_min, q_max, mismatch = 0.2): for l in range(int(nphi)): yield (phi_min*(phi_max/phi_min)**((0.5+l)/nphi), q) -def parse_command_line(): - - parser = OptionParser(description = __doc__) - - # - # First append the datasource common options - # - - multichannel_datasource.append_options(parser) - parser.add_option("--out-path", metavar = "path", default = ".", help = "Write to this path. Default = .") - parser.add_option("--description", metavar = "string", default = "GSTLAL_IDQ_TRIGGERS", help = "Set the filename description in which to save the output.") - parser.add_option("--cadence", type = "int", default = 32, help = "Rate at which to write trigger files to disk. Default = 32 seconds.") - parser.add_option("--disable-web-service", action = "store_true", help = "If set, disables web service that allows monitoring of PSDS of aux channels.") - parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.") - parser.add_option("--triggers-from-dataframe", action = "store_true", default = False, help = "If set, will output iDQ-compatible triggers to disk straight from dataframe once every cadence") - parser.add_option("-m", "--mismatch", type = "float", default = 0.2, help = "Mismatch between templates, mismatch = 1 - minimal match. Default = 0.2.") - parser.add_option("-q", "--qhigh", type = "float", default = 20, help = "Q high value for half sine-gaussian waveforms. Default = 20.") - parser.add_option("-l", "--latency", action = "store_true", help = "Print latency to output ascii file. Temporary.") - parser.add_option("--save-hdf", action = "store_true", default = False, help = "If set, will save hdf5 files to disk straight from dataframe once every cadence") - - # - # parse the arguments and sanity check - # - - options, filenames = parser.parse_args() - - return options, filenames - #################### # # classes @@ -565,6 +537,40 @@ class LinkedAppSync(pipeparts.AppSync): self.appsinks[elem] = None self.appsink_new_buffer(elem, self.sink_dict) +############################### +# +# command line parser +# +############################### + +def parse_command_line(): + + parser = OptionParser(description = __doc__) + + # + # First append the datasource common options + # + + multichannel_datasource.append_options(parser) + parser.add_option("--out-path", metavar = "path", default = ".", help = "Write to this path. Default = .") + parser.add_option("--description", metavar = "string", default = "GSTLAL_IDQ_TRIGGERS", help = "Set the filename description in which to save the output.") + parser.add_option("--cadence", type = "int", default = 32, help = "Rate at which to write trigger files to disk. Default = 32 seconds.") + parser.add_option("--disable-web-service", action = "store_true", help = "If set, disables web service that allows monitoring of PSDS of aux channels.") + parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.") + parser.add_option("--triggers-from-dataframe", action = "store_true", default = False, help = "If set, will output iDQ-compatible triggers to disk straight from dataframe once every cadence") + parser.add_option("-m", "--mismatch", type = "float", default = 0.2, help = "Mismatch between templates, mismatch = 1 - minimal match. Default = 0.2.") + parser.add_option("-q", "--qhigh", type = "float", default = 20, help = "Q high value for half sine-gaussian waveforms. Default = 20.") + parser.add_option("-l", "--latency", action = "store_true", help = "Print latency to output ascii file. Temporary.") + parser.add_option("--save-hdf", action = "store_true", default = False, help = "If set, will save hdf5 files to disk straight from dataframe once every cadence") + + # + # parse the arguments and sanity check + # + + options, filenames = parser.parse_args() + + return options, filenames + #################### # diff --git a/gstlal-ugly/bin/gstlal_etg_pipe b/gstlal-ugly/bin/gstlal_etg_pipe new file mode 100755 index 0000000000..6ac12c3019 --- /dev/null +++ b/gstlal-ugly/bin/gstlal_etg_pipe @@ -0,0 +1,178 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011-2017 Chad Hanna, Duncan Meacher +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +""" +This program makes a dag to run gstlal_inspiral offline +""" + +__author__ = 'Duncan Meacher <duncan.meacher@ligo.org>' + +############################################################################## +# import standard modules and append the lalapps prefix to the python path +import sys, os, stat +import itertools +import numpy +import math +from optparse import OptionParser + +############################################################################## +# import the modules we need to build the pipeline +import lal +import lal.series +from lal.utils import CacheEntry +from glue import pipeline +from glue.lal import Cache +from glue import segments +from glue.ligolw import ligolw +from glue.ligolw import lsctables +import glue.ligolw.utils as ligolw_utils +import glue.ligolw.utils.segments as ligolw_segments +from gstlal import inspiral, inspiral_pipe +from gstlal import dagparts as gstlaldagparts +from gstlal import datasource +from gstlal import multichannel_datasource + +class LIGOLWContentHandler(ligolw.LIGOLWContentHandler): + pass +lsctables.use_in(LIGOLWContentHandler) + +# +# get a dictionary of all the channels per gstlal_etg job +# + +def etg_node_gen(gstlalETGJob, dag, parent_nodes, options, channels, data_source_info): + etg_nodes = {} + cumsum_rates = 0 + outstr = "" + out_index = 0 + + for ii, channel in enumerate(channels,1): + samp_rate = data_source_info.channel_dict[channel]['fsamp'] + max_samp_rate = min(2048, int(samp_rate)) + min_samp_rate = min(32, max_samp_rate) + n_rates = int(numpy.log2(max_samp_rate/min_samp_rate) + 1) + cumsum_rates += n_rates + outstr = outstr + channel + ":" + str(int(samp_rate)) + + if cumsum_rates < options.streams: + outstr = outstr + " --channel-name=" + + if cumsum_rates >= options.streams or ii == len(data_source_info.channel_dict.keys()): + out_index += 1 + outpath = options.out_path + "/gstlal_etg/gstlal_etg_%04d" % out_index + etg_nodes[channel] = \ + inspiral_pipe.generic_node(gstlalETGJob, dag, parent_nodes = parent_nodes, + opts = {"gps-start-time":options.gps_start_time, + "gps-end-time":options.gps_end_time, + "data-source":"frames", + "channel-name":outstr, + "mismatch":options.mismatch, + "qhigh":options.qhigh, + "cadence":options.cadence, + #"triggers-from-dataframe":"", + "disable-web-service":"" + }, + input_files = {"frame-cache":options.frame_cache}, + output_files = {"out-path":outpath} + ) + cumsum_rates = 0 + outstr = "" + + return etg_nodes + +# +# Main +# + +def parse_command_line(): + parser = OptionParser(description = __doc__) + + # generic data source options + #datasource.append_options(parser) + multichannel_datasource.append_options(parser) + + # trigger generation options + parser.add_option("-v", "--verbose", action = "store_true", help = "Be verbose.") + parser.add_option("--triggers-from-dataframe", action = "store_true", default = False, + help = "If set, will output iDQ-compatible triggers to disk straight from dataframe once every cadence") + parser.add_option("--disable-web-service", action = "store_true", help = "If set, disables web service that allows monitoring of PSDS of aux channels.") + parser.add_option("--description", metavar = "string", default = "GSTLAL_IDQ_TRIGGERS", help = "Set the filename description in which to save the output.") + parser.add_option("--cadence", type = "int", default = 32, help = "Rate at which to write trigger files to disk. Default = 32 seconds.") + parser.add_option("-m", "--mismatch", type = "float", default = 0.2, help = "Mismatch between templates, mismatch = 1 - minimal match. Default = 0.2.") + parser.add_option("-q", "--qhigh", type = "float", default = 20, help = "Q high value for half sine-gaussian waveforms. Default = 20.") + parser.add_option("-s", "--streams", type = "float", default = 100, help = "Number of streams to process per node. Default = 100.") + parser.add_option("-l", "--latency", action = "store_true", help = "Print latency to output ascii file. Temporary.") + parser.add_option("--save-hdf", action = "store_true", default = False, help = "If set, will save hdf5 files to disk straight from dataframe once every cadence") + parser.add_option("--out-path", metavar = "path", default = ".", help = "Write to this path. Default = .") + + # Condor commands + parser.add_option("--request-cpu", default = "2", metavar = "integer", help = "set the inspiral CPU count, default = 2") + parser.add_option("--request-memory", default = "7GB", metavar = "integer", help = "set the inspiral memory, default = 7GB") + parser.add_option("--condor-command", action = "append", default = [], metavar = "command=value", help = "set condor commands of the form command=value; can be given multiple times") + + options, filenames = parser.parse_args() + + return options, filenames + + +# +# Useful variables +# + +options, filenames = parse_command_line() + +output_dir = "plots" + +# +# +# + +data_source_info = multichannel_datasource.DataSourceInfo(options) +instrument = data_source_info.instrument +channels = data_source_info.channel_dict.keys() + +# +# Setup the dag +# + +try: + os.mkdir("logs") +except: + pass +dag = inspiral_pipe.DAG("etg_pipe") + +# +# setup the job classes +# + +gstlalETGJob = inspiral_pipe.generic_job("gstlal_etg", condor_commands = inspiral_pipe.condor_command_dict_from_opts(options.condor_command, {"request_memory":options.request_memory, "request_cpus":options.request_cpu, "want_graceful_removal":"True", "kill_sig":"15"})) + +# +# Inspiral jobs by segment +# + +etg_nodes = etg_node_gen(gstlalETGJob, dag, [], options, channels, data_source_info) + +# +# all done +# + +dag.write_sub_files() +dag.write_dag() +dag.write_script() +dag.write_cache() diff --git a/gstlal-ugly/python/multichannel_datasource.py b/gstlal-ugly/python/multichannel_datasource.py index 7306d95c47..c52d07f548 100644 --- a/gstlal-ugly/python/multichannel_datasource.py +++ b/gstlal-ugly/python/multichannel_datasource.py @@ -66,6 +66,31 @@ framexmit_ports = { # misc useful functions # +def channel_dict_from_channel_list(channel_list): + """! + Given a list of channels, produce a dictionary keyed by channel names: + + The list here typically comes from an option parser with options that + specify the "append" action. + + Examples: + + >>> multichannel_datasource.channel_dict_from_channel_list(["H1:AUX-CHANNEL-NAME_1:2048", "H1:AUX-CHANNEL-NAME-2:512"]) + {'H1:AUX-CHANNEL-NAME_1': {'qhigh': None, 'ifo': 'H1', 'flow': None, 'fsamp': 2048.0, 'fhigh': None, 'frametype': None}, 'H1:AUX-CHANNEL-NAME-2': {'qhigh': None, 'ifo': 'H1', 'flow': None, 'fsamp': 512.0, 'fhigh': None, 'frametype': None}} + """ + + channel_dict = {} + for channel in channel_list: + ifo, channel_info, fsamp = channel.split(':') + channel_name = ifo + ":" + channel_info + channel_dict[channel_name] = {'fsamp': float(fsamp), + 'ifo': ifo, + 'flow': None, + 'fhigh': None, + 'qhigh' : None, + 'frametype' : None} + return channel_dict + def channel_dict_from_channel_file(channel_file): """! Given a file of channel names with sampling rates, produce a dictionary keyed by ifo: @@ -193,8 +218,10 @@ class DataSourceInfo(object): raise ValueError("can only give --frame-segments-file if --data-source=frames") if options.frame_segments_name is not None and options.frame_segments_file is None: raise ValueError("can only specify --frame-segments-name if --frame-segments-file is given") - if not options.channel_list: - raise ValueError("must specify a channel list in the form --channel-list=/path/to/file") + if not (options.channel_list or options.channel_name): + raise ValueError("must specify a channel list in the form --channel-list=/path/to/file or --channel-name=H1:AUX-CHANNEL-NAME:RATE --channel-name=H1:SOMETHING-ELSE:RATE") + if (options.channel_list and options.channel_name): + raise ValueError("must specify a channel list in the form --channel-list=/path/to/file or --channel-name=H1:AUX-CHANNEL-NAME:RATE --channel-name=H1:SOMETHING-ELSE:RATE") ## Generate a dictionary of requested channels from channel INI file @@ -212,12 +239,16 @@ class DataSourceInfo(object): assert fidelity in self.known_fidelity, '--fidelity-exclude=%s is not understood. Must be one of %s'%(fidelity, ", ".join(self.known_fidelity)) # dictionary of the requested channels, e.g., {"H1": {"LDAS-STRAIN": 16384}, "L1": {"LDAS-STRAIN": 16384}} - name, self.extension = options.channel_list.rsplit('.', 1) - if self.extension == 'ini': - self.channel_dict = channel_dict_from_channel_ini(options) - else: - self.channel_dict = channel_dict_from_channel_file(options.channel_list) - + if options.channel_list: + name, self.extension = options.channel_list.rsplit('.', 1) + if self.extension == 'ini': + self.channel_dict = channel_dict_from_channel_ini(options) + else: + self.channel_dict = channel_dict_from_channel_file(options.channel_list) + elif options.channel_name: + self.extension = 'none' + self.channel_dict = channel_dict_from_channel_list(options.channel_name) + # set instrument; it is assumed all channels from a given channel list are from the same instrument self.instrument = self.channel_dict[next(iter(self.channel_dict))]['ifo'] @@ -306,6 +337,10 @@ def append_options(parser): File needs to be in format channel-name[spaces]sampling_rate with a new channel in each line. Command given as --channel-list=location/to/file. +- --channel-name [string] + Set the name of the channels to process. + Can be given multiple times as --channel-name=IFO:AUX-CHANNEL-NAME:RATE + - --framexmit-addr [string] Set the address of the framexmit service. Can be given multiple times as --framexmit-addr=IFO=xxx.xxx.xxx.xxx:port @@ -345,6 +380,10 @@ def append_options(parser): #### Typical usage case examples + -# Reading data from frames + + --data-source=frames --gps-start-time=999999000 --gps-end-time=999999999 --channel-name=H1:AUX-CHANNEL-NAME:RATE + -# Reading online data via framexmit --data-source=framexmit --channel-list=H1=location/to/file @@ -358,6 +397,7 @@ def append_options(parser): group.add_option("--gps-end-time", metavar = "seconds", help = "Set the end time of the segment to analyze in GPS seconds. Required unless --data-source=lvshm") group.add_option("--frame-cache", metavar = "filename", help = "Set the name of the LAL cache listing the LIGO-Virgo .gwf frame files (optional). This is required iff --data-source=frames") group.add_option("--channel-list", type="string", metavar = "name", help = "Set the list of the channels to process. Command given as --channel-list=location/to/file") + group.add_option("--channel-name", metavar = "name", action = "append", help = "Set the name of the channels to process. Can be given multiple times as --channel-name=IFO:AUX-CHANNEL-NAME:RATE") group.add_option("--framexmit-addr", metavar = "name", action = "append", help = "Set the address of the framexmit service. Can be given multiple times as --framexmit-addr=IFO=xxx.xxx.xxx.xxx:port") group.add_option("--framexmit-iface", metavar = "name", help = "Set the multicast interface address of the framexmit service.") group.add_option("--shared-memory-partition", metavar = "name", action = "append", help = "Set the name of the shared memory partition for a given instrument. Can be given multiple times as --shared-memory-partition=IFO=PARTITION-NAME") diff --git a/gstlal-ugly/share/etg/Makefile.gstlal_etg_offline b/gstlal-ugly/share/etg/Makefile.gstlal_etg_offline new file mode 100644 index 0000000000..98cc710af0 --- /dev/null +++ b/gstlal-ugly/share/etg/Makefile.gstlal_etg_offline @@ -0,0 +1,91 @@ +SHELL := /bin/bash +# condor commands +# Set the accounting tag from https://ldas-gridmon.ligo.caltech.edu/ldg_accounting/user +ACCOUNTING_TAG=ligo.dev.o3.detchar.onlinedq.idq +GROUP_USER=duncan.meacher +CONDOR_COMMANDS:=--condor-command=accounting_group=$(ACCOUNTING_TAG) --condor-command=accounting_group_user=$(GROUP_USER) + +######################### +# Triggering parameters # +######################### + +# The GPS start time for analysis +START = 1176638000 +# The GPS end time for analysis +STOP = 1176639000 + +OUTPATH = $(PWD) +# Number of streams (N_channels x N_rates_per_channel) that each processor will analise +N_STREAMS = 100 +MISMATCH = 0.2 +QHIGH = 40 + +# Detector +CLUSTER:=$(shell hostname -d) + +FRAME_TYPE=R + +################# +# Web directory # +################# + +# A user tag for the run +TAG = O2_C00 +# Run number +RUN = run_1 +# A web directory for output (note difference between cit+uwm and Atlas) +# cit & uwm +WEBDIR = ~/public_html/observing/$(TAG)/$(START)-$(STOP)-$(RUN) +# Atlas +#WEBDIR = ~/WWW/LSC/testing/$(TAG)/$(START)-$(STOP)-test_dag-$(RUN) + +############ +# Workflow # +############ + +all : dag + sed -i '/gstlal_etg / s/$$/ |& grep -v '\''XLAL\|GSL\|Generic'\''/' etg_pipe.sh + @echo "Submit with: condor_submit_dag etg_pipe.dag" + +# Run etg pipe to produce dag +dag : frame.cache plots channel_list.txt + gstlal_etg_pipe \ + --data-source frames \ + --gps-start-time $(START) \ + --gps-end-time $(STOP) \ + --frame-cache frame.cache \ + --channel-list channel_list.txt \ + --out-path $(OUTPATH) \ + --streams $(N_STREAMS)\ + --mismatch $(MISMATCH) \ + --qhigh $(QHIGH) \ + $(CONDOR_COMMANDS) \ + --request-cpu 2 \ + --request-memory 5GB \ + --disable-web-service + +# --web-dir $(WEBDIR) \ + +full_channel_list.txt : frame.cache + FrChannels $$(head -n 1 $^ | awk '{ print $$5}' | sed -e "s@file://localhost@@g") > $@ + +frame.cache : + # FIXME force the observatory column to actually be instrument + if [[ ${CLUSTER} == *"ligo-wa.caltech.edu" ]] ; then \ + gw_data_find -o H -t H1_$(FRAME_TYPE) -l -s $(START) -e $(STOP) --url-type file -O $@ ; \ + elif [[ ${CLUSTER} == *"ligo-la.caltech.edu" ]] ; then \ + gw_data_find -o L -t L1_$(FRAME_TYPE) -l -s $(START) -e $(STOP) --url-type file -O $@ ; \ + fi + +# Make webpage directory and copy files across +#$(WEBDIR) : $(MAKEFILE_LIST) +# mkdir -p $(WEBDIR)/OPEN-BOX +# cp $(MAKEFILE_LIST) $@ + +# Makes local plots directory +plots : + mkdir plots + +clean : + -rm -rvf *.sub *.dag* *.cache *.sh logs *.sqlite plots *.html Images *.css *.js + diff --git a/gstlal-ugly/share/etg/channel_list.txt b/gstlal-ugly/share/etg/channel_list.txt new file mode 100644 index 0000000000..31ad0beb70 --- /dev/null +++ b/gstlal-ugly/share/etg/channel_list.txt @@ -0,0 +1,100 @@ +H1:CAL-CS_CARM_DELTAF_DQ 16384 +H1:CAL-CS_LINE_SUM_DQ 16384 +H1:CAL-DARM_CTRL_WHITEN_OUT_DBL_DQ 16384 +H1:CAL-DARM_ERR_WHITEN_OUT_DBL_DQ 16384 +H1:CAL-DELTAL_EXTERNAL_DQ 16384 +H1:CAL-DELTAL_RESIDUAL_DBL_DQ 16384 +H1:CAL-PCALX_FPGA_DTONE_IN1_DQ 16384 +H1:CAL-PCALX_IRIGB_OUT_DQ 16384 +H1:CAL-PCALX_RX_PD_OUT_DQ 16384 +H1:CAL-PCALX_TX_PD_OUT_DQ 16384 +H1:CAL-PCALY_EXC_SUM_DQ 16384 +H1:CAL-PCALY_FPGA_DTONE_IN1_DQ 16384 +H1:CAL-PCALY_IRIGB_OUT_DQ 16384 +H1:CAL-PCALY_RX_PD_OUT_DQ 16384 +H1:CAL-PCALY_TX_PD_OUT_DQ 16384 +H1:IMC-F_OUT_DQ 16384 +H1:IMC-I_OUT_DQ 16384 +H1:LSC-ASAIR_A_RF45_I_ERR_DQ 16384 +H1:LSC-ASAIR_A_RF45_Q_ERR_DQ 16384 +H1:LSC-DARM_IN1_DQ 16384 +H1:LSC-DARM_OUT_DQ 16384 +H1:LSC-MCL_IN1_DQ 16384 +H1:LSC-MCL_OUT_DQ 16384 +H1:LSC-MICH_IN1_DQ 16384 +H1:LSC-MICH_OUT_DQ 16384 +H1:LSC-MOD_RF45_AM_AC_OUT_DQ 16384 +H1:LSC-PRCL_IN1_DQ 16384 +H1:LSC-PRCL_OUT_DQ 16384 +H1:LSC-REFLAIR_A_RF45_I_ERR_DQ 16384 +H1:LSC-REFLAIR_A_RF45_Q_ERR_DQ 16384 +H1:LSC-REFLAIR_A_RF9_I_ERR_DQ 16384 +H1:LSC-REFLAIR_A_RF9_Q_ERR_DQ 16384 +H1:LSC-REFL_SERVO_CTRL_OUT_DQ 16384 +H1:LSC-REFL_SERVO_ERR_OUT_DQ 16384 +H1:LSC-SRCL_IN1_DQ 16384 +H1:LSC-SRCL_OUT_DQ 16384 +H1:OMC-DCPD_NORM_OUT_DQ 16384 +H1:OMC-DCPD_NULL_OUT_DQ 16384 +H1:OMC-DCPD_SUM_OUT_DQ 16384 +H1:OMC-LSC_DITHER_OUT_DQ 16384 +H1:OMC-LSC_I_OUT_DQ 16384 +H1:OMC-PZT1_MON_AC_OUT_DQ 16384 +H1:OMC-PZT2_MON_AC_OUT_DQ 16384 +H1:PEM-CS_ACC_BEAMTUBE_MCTUBE_Y_DQ 16384 +H1:PEM-CS_ACC_BSC1_ITMY_Y_DQ 16384 +H1:PEM-CS_ACC_BSC3_ITMX_X_DQ 16384 +H1:PEM-CS_ACC_HAM6_OMC_Z_DQ 16384 +H1:PEM-CS_ACC_PSL_PERISCOPE_X_DQ 16384 +H1:PEM-CS_ADC_4_30_16K_OUT_DQ 16384 +H1:PEM-CS_ADC_4_31_16K_OUT_DQ 16384 +H1:PEM-CS_MIC_EBAY_RACKS_DQ 16384 +H1:PEM-CS_MIC_LVEA_BS_DQ 16384 +H1:PEM-CS_MIC_LVEA_HAM7_DQ 16384 +H1:PEM-CS_MIC_LVEA_INPUTOPTICS_DQ 16384 +H1:PEM-CS_MIC_LVEA_OUTPUTOPTICS_DQ 16384 +H1:PEM-CS_MIC_LVEA_VERTEX_DQ 16384 +H1:PEM-CS_MIC_LVEA_XMANSPOOL_DQ 16384 +H1:PEM-CS_MIC_LVEA_YMANSPOOL_DQ 16384 +H1:PEM-CS_MIC_PSL_CENTER_DQ 16384 +H1:PEM-CS_RADIO_EBAY_NARROWBAND_1_DQ 16384 +H1:PEM-CS_RADIO_EBAY_NARROWBAND_2_DQ 16384 +H1:PEM-CS_RADIO_LVEA_NARROWBAND_1_DQ 16384 +H1:PEM-CS_RADIO_LVEA_NARROWBAND_2_DQ 16384 +H1:PEM-CS_RADIO_ROOF1_BROADBAND_DQ 16384 +H1:PEM-CS_RADIO_ROOF2_BROADBAND_DQ 16384 +H1:PEM-CS_RADIO_ROOF3_BROADBAND_DQ 16384 +H1:PEM-CS_RADIO_ROOF4_BROADBAND_DQ 16384 +H1:PEM-EX_ACC_BSC9_ETMX_Y_DQ 16384 +H1:PEM-EX_MIC_EBAY_RACKS_DQ 16384 +H1:PEM-EX_MIC_VEA_MINUSX_DQ 16384 +H1:PEM-EX_MIC_VEA_PLUSX_DQ 16384 +H1:PEM-EY_ACC_BSC10_ETMY_X_DQ 16384 +H1:PEM-EY_MIC_EBAY_RACKS_DQ 16384 +H1:PEM-EY_MIC_VEA_MINUSY_DQ 16384 +H1:PEM-EY_MIC_VEA_PLUSY_DQ 16384 +H1:PSL-FSS_FAST_MON_OUT_DQ 16384 +H1:PSL-FSS_MIXER_OUT_DQ 16384 +H1:PSL-FSS_PC_MON_OUT_DQ 16384 +H1:PSL-FSS_TPD_DC_OUT_DQ 16384 +H1:PSL-ILS_HV_MON_OUT_DQ 16384 +H1:PSL-ILS_MIXER_OUT_DQ 16384 +H1:PSL-ISS_AOM_DRIVER_MON_OUT_DQ 16384 +H1:PSL-ISS_PDA_REL_OUT_DQ 16384 +H1:PSL-ISS_PDB_REL_OUT_DQ 16384 +H1:PSL-OSC_PD_AMP_DC_OUT_DQ 16384 +H1:PSL-OSC_PD_BP_DC_OUT_DQ 16384 +H1:PSL-OSC_PD_INT_DC_OUT_DQ 16384 +H1:PSL-OSC_PD_ISO_DC_OUT_DQ 16384 +H1:PSL-PMC_HV_MON_OUT_DQ 16384 +H1:PSL-PMC_MIXER_OUT_DQ 16384 +H1:PSL-PWR_HPL_DC_OUT_DQ 16384 +H1:PEM-CS_MAG_EBAY_LSCRACK_X_DQ 8192 +H1:PEM-CS_MAG_EBAY_LSCRACK_Y_DQ 8192 +H1:PEM-CS_MAG_EBAY_LSCRACK_Z_DQ 8192 +H1:PEM-CS_MAG_EBAY_SUSRACK_X_DQ 8192 +H1:PEM-CS_MAG_EBAY_SUSRACK_Y_DQ 8192 +H1:PEM-CS_MAG_EBAY_SUSRACK_Z_DQ 8192 +H1:PEM-CS_MAG_LVEA_INPUTOPTICS_X_DQ 8192 +H1:PEM-CS_MAG_LVEA_INPUTOPTICS_Y_DQ 8192 +H1:PEM-CS_MAG_LVEA_INPUTOPTICS_Z_DQ 8192 -- GitLab