SPADI-A Wiki/SPADI-A DAQ マニュアル/ソフトウェア/DAQのセットアップ


DAQ のセットアップ

DAQ 関連のソフトウェアをインストールが終わったら、各々の実験に合わせて、スクリプトを用意する。基本的には、これまでの実験で使われたスクリプトをまとめた GitHub の以下のリポジトリをベースにするのがよいであろう。

ここに、AMANEQ といった FEE 用のレジスタ設定スクリプトのサンプルや、NestDAQ の設定スクリプトのサンプルがある。

設定の手順について

まず、リポジトリを GitHub から clone する。

$ cd $HOME/
$ git clone https://github.com/spadi-alliance/exp-config

その後、exp-config 内に入り、自身のセットアップに近いディレクトリをコピーして、自身の実験用のディレクトリを作成する。

$ cd $HOME/exp-config
$ ls
README.md	jparc_e50_blm	jparc_t103	raris_bpm	rcnp_d202407a	rcnp_e585
$ cp -a rcnp_d202407a my_exp
$ cd my_exp
$ ls
fee_scripts run

ちなみに、各ディレクトリ内の run スクリプトには頻繁にアクセスするため、ホームディレクトリにリンクを作っておくと便利であろう。ls コマンドなどで $HOME/run ディレクトリが存在しないことを確認したら、以下のリンクコマンド (ln -s) を実行。

$ ln -s $HOME/exp-config/my_exp/run $HOME/run

そのあと、実験ごとのセットアップ (FEE の台数や IPアドレスなど) に応じて、スクリプトの編集を行う。以下、それぞれのスクリプトの説明と編集方法を記述する。

fee_scirpts 内のスクリプトの編集

fee_scripts ディレクトリには、AMANEQ のレジスタ設定を行う以下のスクリプトが用意してある。

config_modules.sh
init_hrtdc.sh
reset_modules.sh
set_hbfstate_on.sh
set_hbfthrottling.sh
set_selfrecovery.sh
set_tdcmask.sh
set_totfilter.sh

この中で、実験時に実行するスクリプトは config_modules.sh である。config_module.sh の中身を確認すればわかるが、このスクリプトを実行することで、その他のスクリプトが順次実行される。特に問題がなければ、AMANEQ 電源投入時に config_modules.sh を実行すればよい。なんらかの問題が生じた場合 reset_modules.sh を実行して、モジュールのリセットを行う。これらのスクリプトはパスがベタ書きになっているので、それをすべて書き換えるか、うまく変数を使って書き直すのが良いであろう。さらに、その他のスクリプトの中身をセットアップに合わせてすべて書き換える。各スクリプトの意味と編集方法は、以下の通り。

fee_scripts/config_modules.sh

実験時に実行するスクリプトは config_modules.sh である。このスクリプトの中身は以下のようになっており、

#!/bin/bash

$HOME/exp-config/rcnp_d202407a/fee_scripts/init_hrtdc.sh
$HOME/exp-config/rcnp_d202407a/fee_scripts/set_tdcmask.sh
$HOME/exp-config/rcnp_d202407a/fee_scripts/set_totfilter.sh
$HOME/exp-config/rcnp_d202407a/fee_scripts/set_selfrecovery.sh
$HOME/exp-config/rcnp_d202407a/fee_scripts/set_hbfthrottling.sh
$HOME/exp-config/rcnp_d202407a/fee_scripts/set_hbfstate_on.sh

これを実行することで、その他のスクリプトが順次実行される。特に問題がなければ、システム起動時に config_modules.sh を実行すればよい。現状のディレクトリ構造に合わせて、編集する。パスがベタ書きになっているので、それをすべて書き換えるか、うまく変数を使って書き直すのが良いであろう。

fee_scripts/reset_modules.sh

データ収集を行なっている際になんらかの問題が生じた場合 reset_modules.sh を実行して、モジュールのリセットを行う。現状のディレクトリ構造に合わせて、編集する。パスがベタ書きになっているので、それをすべて書き換えるか、うまく変数を使って書き直すのが良いであろう。

#!/bin/bash
#low resolution
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/gen_user_reset 192.168.2.160
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/gen_user_reset 192.168.2.161 
...
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/gen_user_reset 192.168.2.169

#high resolution
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/gen_mzn_userreset 192.168.2.169 both

fee_scripts/init_hrtdc.sh

HR-TDC FPGAファームウェアのリセットと、HR-TDC メザニンのリセットを行う。HR-TDC を利用する場合、AMANEQの電源を投入後、一度だけこのスクリプトを実行する必要がある。そうしないと AMANEQ はデータを出力しない。一度実行した後はもう実行する必要はないが、何度実行しても問題はない模様。中身は以下のようになっている。

#!/bin/bash

$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/write_mzn_register 192.168.2.169 both 0x2010 0x0 1
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/initialize 192.168.2.169 both 
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/write_mzn_register 192.168.2.169 both 0x2010 0x2 1

バイナリのパスと 192.168.2.169という部分を自身の環境に合わせて編集する。ここで、 192.168.2.169 は HR-TDC の IP アドレスである。HR-TDCが2台以上ある場合は、上記の 3 行をモジュールの台数に合わせて増やせば良い。

fee_scripts/set_tdcmask.sh

TDC の特定の入力チャンネルをマスクするためのスクリプト。ここでいうマスクとは、入力チャンネルを覆い隠すためのものであり、マスクしたチャンネルは入力を受け付けなくなり、そのチャンネルのTDC hit データは出力されなくなる。設定方法は、マスクしたいチャンネルに bit の 1 (true) を立て、マスクしないチャンネルは 0 (false) を立てる。(別の言い方をすると、入力のチャンネルを enable するには 0, disable するには 1 を指定することになる。)AMANEQの全チャンネルを読みたい場合はすべてのチャンネルに対して 0 を指定すればよい。具体的なスクリプトの中身は以下の通り。

#low resolution
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrLRTDC/bin/set_tdcmask 192.168.2.160      0x00000000 0x00000000 0x00000000 0x000000000 0x0
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrLRTDC/bin/set_tdcmask 192.168.2.161      0x00000000 0x00000000 0x00000000 0x000000000 0x0
...
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrLRTDC/bin/set_tdcmask 192.168.2.168      0x00000000 0x00000000 0x00000000 0x000000000 0x0

$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/set_tdcmask 192.168.2.169 both  0xffff0000 0xffff0000

ここで、bit の立て方などは一部のスクリプトのコメントに書いてある。以下抜粋。

# Usage:
#   LRTDC: set_tdcmask [IP address] [Mask value Main-U (Hex)] [Mask value Main-D (Hex)] [Mask value MZN-U (Hex)] [Mask value MZN-D (Hex)] [kMaskEx]
#   HRTDC: set_tdcmask [IP address] [Mezzanine existence] [Mask value uppper mezzanine (Hex)] [Mask value lower mezzanine (Hex)]
#     Description of mezzanine existence
#     - up   (mezzanine is attached on upper slot)
#     - low  (mezzanine is attached on lower slot)
#     - both (mezzanine is attached on both slot2)
#
# Bit:
#   Bit 1: masked (channel disabled), Bit 0: unmasked (channel enabled)
#
# Example:
#   Taking all channels (No mask)
#     LRTDC: set_tdcmask xx.xx.xx.xx      0x00000000 0x00000000 0x00000000 0x000000000 0x0
#     HRTDC: set_tdcmask xx.xx.xx.xx both 0x00000000 0x00000000
#   All channels are masked (No TDC data taken)
#     LRTDC: set_tdcmask xx.xx.xx.xx      0xffffffff 0xffffffff 0xffffffff 0xfffffffff 0xffffffff (Is this correct?)
#     HRTDC: set_tdcmask xx.xx.xx.xx both 0xffffffff 0xffffffff
#   Only first channel (ch0) is masked
#     LRTDC: set_tdcmask xx.xx.xx.xx      0x00000001 0x00000000 0x00000000 0x000000000 0x0
#     HRTDC: set_tdcmask xx.xx.xx.xx both 0x00000001 0x00000000
#   ch0 - ch3 are masked
#     LRTDC: set_tdcmask xx.xx.xx.xx      0x0000000f 0x00000000 0x00000000 0x000000000 0x0
#     HRTDC: set_tdcmask xx.xx.xx.xx both 0x0000000f 0x00000000
#   Only ch0 - ch3 are taken
#     LRTDC: set_tdcmask xx.xx.xx.xx      0xfffffff0 0xffffffff 0xffffffff 0xfffffffff 0xffffffff (Is this correct?)
#     HRTDC: set_tdcmask xx.xx.xx.xx both 0xfffffff0 0xffffffff
#   Only ch31 is masked
#     LRTDC: set_tdcmask xx.xx.xx.xx      0x80000000 0x00000000 0x00000000 0x000000000 0x0
#     HRTDC: set_tdcmask xx.xx.xx.xx both 0x80000000 0x00000000
#   Only ch32 is masked
#     LRTDC: set_tdcmask xx.xx.xx.xx      0x00000000 0x00000001 0x00000000 0x000000000 0x0
#     HRTDC: set_tdcmask xx.xx.xx.xx both 0x00000000 0x00000001
#   Only ch63 is masked
#     LRTDC: set_tdcmask xx.xx.xx.xx      0x00000000 0x80000000 0x00000000 0x000000000 0x0
#     HRTDC: set_tdcmask xx.xx.xx.xx both 0x00000000 0x80000000

ちなみに、AMANEQ の信号入力部分は差動信号を受け付けるが、ケーブルをつなげないと発振する場合がある。そのため、ケーブルを指していないチャンネルは基本的にマスクする。ちなみに、RBCP のスケーラはこのマスクの設定にかかわらずカウントを行う。

fee_scripts/set_totfilter.sh

AMANEQ が出力する TDC TOT (time over threshold) データにおいて、設定した時間以上 (と以下) の TOT を持つもののみを出力したい場合、この TOT filter を設定する。設定で与える時間の単位は TOT の LSB (Least significant bit, 最小の時間単位) である。そのため、例えば LR-TDC の場合、LSB はおおよそ 1 ns であるため、例えば 0xff (=255) と設定すると、TOT がおおよそ 255 ns 以上の TDC データのみ出力され、255 ns 未満の TDC データは破棄される。HR-TDC の場合、LSB はおおよそ 1 ps であるため、例えば 0x200 (= 512) と設定すると、TOT がおおよそ 512 ps 以上のTDCデータのみ出力され、512 ps 未満の TDC データは破棄される。具体的なスクリプトは以下のようなもの。ここで、MIN_TH と MAX_TH で最小 TOT と最大 TOT を設定する。CTRL は何を設定しているかAMANEQ Users Guide 参照。

#!/bin/bash

CTRL=0
MIN_TH=0
MAX_TH=0xffff

#LR*9
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.160 0x10500000 ${CTRL} 1
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.160 0x10600000 ${MIN_TH} 2
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.160 0x10700000 ${MAX_TH} 2
...
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.168 0x10500000 ${CTRL} 1
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.168 0x10600000 ${MIN_TH} 2
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.168 0x10700000 ${MAX_TH} 2

#HR
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/write_mzn_register 192.168.2.169 up 0x2060 ${CTRL} 1
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/write_mzn_register 192.168.2.169 up 0x2070 ${MIN_TH} 2
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/write_mzn_register 192.168.2.169 up 0x2080 ${MAX_TH} 2

fee_scripts/set_selfrecovery.sh

AMANEQ に対してバックプレッシャーがかかり、Heart Beat Frame Number Mismatch が生じた場合でも、self recovery が効くように設定する。ちなみに self recovery が効くタイミングは TCP 接続が切れたタイミングである。スクリプトの中身は以下のようなもの。LR-TDC と HR-TDC 用に分けて IP アドレスとレジスタの値を設定する。

#!/bin/bash
#low resolution
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.160 0x10D00000 0x1 1
...
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.168 0x10D00000 0x1 1

#high resolution
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/write_mzn_register 192.168.2.169 both 0x20E0 0x1 1

fee_scripts/set_hbfthrottling.sh

Heart Beat Frame throttling を設定する。ここで、Heart Beat Frame throttling とは、Heart Beat Frame の間引きを行うことであり、AMANEQ が出力するデータ量を減らしたいときに用いる。2 の累乗 (2, 4, 8, 16) の単位で Heart Beat Frame を間引くことができる。連続読み出しDAQ において、通常は FEE の段階でデータを破棄することはしないので、throttling は有効にしない。ただ、ビーム強度が強いが下げられない、もしくは校正用ランなどにおいて、検出器のカウントレートが高く、データがとり切れない場合などにこの throttling を有効にする。例えば 4 に設定すると、4 つの Heart Beat Frame のうち 1 つの Heart Beat Frame を出力し、3 つの Heart Beat Frame を破棄する。この場合 AMANEQ が出力するデータ量は (Heart Beat Frame Delimiter のデータ量の寄与を無視すれば) ほぼ4分の1になる。実際のスクリプトは以下のようになる。コメントの部分にあるように、CTRL は 0, 1, 2, 4, 8 を指定し、それぞれ throttling なし、1/2, 1/4, 1/8, 1/16 間引きに対応する。ここで、設定する値は MIKUMARI Link で接続しているボードですべて同じにする。異なる値にした場合、正常に動作しない(はず)。

#!/bin/bash

CTRL=0
# 0: no throttling
# 1: 1/2
# 2: 1/4
# 4: 1/8
# 8: 1/16

#low resolution
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.160 0x10B00000 ${CTRL} 1
...
$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/write_register 192.168.2.168 0x10B00000 ${CTRL} 1

#high resolution
$HOME/exp-config/rcnp_d202407a/amaneq-soft/install/StrHRTDC/bin/write_mzn_register 192.168.2.169 both 0x20C0 ${CTRL} 1

fee_scripts/set_hbfstate_on.sh

Heart Beat State を ON にするスクリプト。このスクリプトを実行することで AMANEQ は Ready の状態になり TCP で接続すると、データを返すようになる。スクリプトの中身は以下のようなもの。AMANEQ MIKUMARI Primary の FPGA firmware が載ったボードに対して設定を行う。以下のスクリプトでは MIKUMARI Primary の IP アドレスが 192.168.2.160 の場合の記述になっている。

#!/bin/bash

$HOME/exp-config/rcnp_d202407a/hul-common-lib/install/bin/set_hbfstate 192.168.2.160 on

run ディレクトリ内のスクリプトの編集

my_exp/run ディレクトリ内のスクリプトは NestDAQ の設定をするための各種スクリプトが格納してある。これは FEE のボード数、IP アドレスなどのハードウェアに近いところの情報、さらに、データを取る際の DAQ の設定を指定するためのスクリプト群である。DAQ を動かすために最低限必要となるスクリプトは

init.sh
mq-param.sh
topology.sh
run.sh
start_device.sh

である。ここで、mq-param.sh, topology.sh, run.sh は DAQ の設定に応じてファイル名を派生させる用いる場合が多い。例えば、DAQ の設定に応じて、topology.sh を topology-stf.sh にとしたりする。さらに、DAQ のコントロールを便利にサポートするため、以下の幾つかのスクリプトが用意してある。

kill_fairmq_devices.sh
del_daqservices.sh
triggerlogic.sh
tf.sh
stf.sh
flt.sh
secflt.sh
tfs.sh

この中で実験で 以下、各スクリプトについて説明する。

init.sh

DAQ に必要なソフトウェアを起動するためのスクリプト。基本的に計算機を起動したあと、一度だけ実行すれば良い。やっていることは、redis データベースサーバーの起動と、daq web コントローラのhttp server の起動である。redis の viewer である redisinsight を立ち上げる場合もある。redis を立ち上げるコンピュータと FairMQ デバイスのプロセスが走るコンピュータが別れていたりする場合は記述がややこしくなるが、一つのコンピュータで完結する場合はシンプルになる。以下、シンプルな init.sh (exp-config/raris_bpm/run_bpmdaq/init.sh) の例 (コメント行は省略した)。

#!/bin/bash
pkill daq-webctl
sleep 0.2

redis-server $HOME/nestdaq/etc/redis.conf --loadmodule $HOME/nestdaq/lib/redistimeseries.so
$HOME/nestdaq/bin/daq-webctl >& /dev/null &

ここで、pkill という行で、もしすでに daq-webctl というプロセスが走っていたら、プロセスを殺し、sleep する。daq-webctl がハングしたときに、このスクリプトをもう一度走らせて復旧することを想定している。redis-server で始まる行が redis のデータベースサーバーを立ち上げている。引数の conf ファイルのファイルパスは各自の redis のインストール先のディレクトリ構造に合わせて編集する。redistimeseries.so の部分も同様に自身のディレクトリ構造に合わせて編集する。最後の行の $HOME/nestdaq/bin/daq-webctl >& /dev/null & で DAQ の Web controller を立ち上げている。 ">& /dev/null &" の部分はdaq-webctl の出力を /dev/null に捨てて、かつバックグランドで実行することを表している。引数なしのデフォルトで daq-webctl を立ち上げる場合、アクセスする redis サーバーは自分自身のコンピュータ上 (localhost, IP: 127.0.0.1) で走る redis (ポート番号はデフォルトの 6379) である。DAQ web コントローラのデフォルトのポート番号は 8080 になる。これらをデフォルトから変えたい場合は、以下のように指定する。

daq-webctl --redis-uri tcp://192.168.2.82:6379 --http-uri http://0.0.0.0:5962 >& /dev/null &

redis として、IP アドレスが 192.168.2.82 のポート番号 6379 に立ち上がっている redis にアクセスし、DAQ Web コントローラのポート番号は 5962 を指定している。

mq-param.sh

このスクリプトでは、各 FairMQ デバイスのプロセスのパラメータを設定している。NestDAQ では FairMQ デバイスのインスタンスが複数走るため、各インスタンスに応じてパラメータを設定する。以下、AMANEQ 4 台を用いた RARiS NKS2 BPM 実験のときの mq- param.sh の設定を示す。

#!/bin/bash

server=redis://127.0.0.1:6379/2

function param () {
  # "instance":"field" "value"
  #echo redis-cli -u $server set parameters:$1:$2 ${@:3}
  #redis-cli -u $server set parameters:$1:$2 ${@:3}
  echo redis-cli -u $server hset parameters:$1 ${@:2}
  redis-cli -u $server hset parameters:$1 ${@:2}
}

redis-cli -u $server  flushdb 

#===============================================================================================
#      isntance-id                field       value             field       value  
#===============================================================================================
#
# TdcType HR-TDC: 5, LR-TDC: 6 (on Jun. 7, 2024)
param  AmQStrTdcSampler-0         msiTcpIp   192.168.10.35   TdcType     6
param  AmQStrTdcSampler-1         msiTcpIp   192.168.10.36   TdcType     5
param  AmQStrTdcSampler-2         msiTcpIp   192.168.10.37   TdcType     5
param  AmQStrTdcSampler-3         msiTcpIp   192.168.10.16   TdcType     6
#
param  STFBuilder-0  max-hbf 4
param  STFBuilder-1  max-hbf 4
param  STFBuilder-2  max-hbf 4
param  STFBuilder-3  max-hbf 4
#
param Scaler-0    prefix exedir/00 ext .dat
param Scaler-1    prefix exedir/01 ext .dat
param Scaler-2    prefix exedir/02 ext .dat
param Scaler-3    prefix exedir/03 ext .dat
#
param TimeFrameBuilder-0  decimation-factor 1000
param TimeFrameBuilder-1  decimation-factor 1000
param TimeFrameBuilder-2  decimation-factor 1000
param TimeFrameBuilder-3  decimation-factor 1000
#
param FileSink-0  multipart true prefix  data/rawdata/00 ext .dat
param FileSink-1  multipart true prefix  data/rawdata/01 ext .dat
param FileSink-2  multipart true prefix  data/rawdata/02 ext .dat
param FileSink-3  multipart true prefix  data/rawdata/03 ext .dat
#
param ScrSink-0   multipart true  prefix scdata/00 ext .dat
param ScrSink-1   multipart true  prefix scdata/01 ext .dat
param ScrSink-2   multipart true  prefix scdata/02 ext .dat
param ScrSink-3   multipart true  prefix scdata/03 ext .dat
#
# Sink for Decimator         
param DecSink-0  multipart true prefix dcmdata/00 ext .dat
param DecSink-1  multipart true prefix dcmdata/01 ext .dat
param DecSink-2  multipart true prefix dcmdata/02 ext .dat
param DecSink-3  multipart true prefix dcmdata/03 ext .dat

param TimeFrameSlicerByLogicTiming time-offset-begin -25 time-offset-end 25 

ここで、 function param () {...} の部分は bash の関数を定義しており、redis にパラメータの設定するための param という関数を作っている。ユーザーはこの関数の部分は基本的に編集しない。redis-cli -u $server flushdb という行でデータベースの中身をリセットしている。param AmQStrTdcSampler-0 msiTcpIp 192.168.10.35 TdcType 6 に続く4行で Sampler プロセスの挙動を指定している。ここでは AMANEQ 4台があり、それぞれ IP アドレスを持っているため、その IP アドレスをここに記述する。また、それぞれ Tdc Type (LR-TDC or HR-TDC) が異なるので、それを指定している。Tdc Type については、NestDAQ に関する記述を参照のこと。このように、それぞれのプロセスに応じてパラメータを設定する。各プロセスがどのような引数を持つかは、端末上で

$HOME/local/bin/AmQStrTdcSampler --help

として確認するか、FairMQ デバイスのソースコードを読むことでわかる。

mq-param.sh の派生形として、mq-param-dev-null.sh というものもあるが、このスクリプトでは FileSink (DecSink, ScrSink 含む) のデータ保存先を /dev/null にして、データを保存しないモードで DAQ を走らせたい場合に利用する。

topology.sh

FairMQ デバイス間の接続のトポロジーを指定するためのスクリプト。このファイルはトポロジーによってファイル名を派生させることが多い。以下では、シンプルな exp-config/raris_bpm/run_bpmdaq/topology-stf-tf.sh の例 (データベースのリセットを追記した) を示す。

#!/bin/bash

#host=127.0.0.1
#port=6379
#db=0
server=redis://127.0.0.1:6379/0

#function config_endpoint () {
function endpoint () {
  # Usage: 
  #   config_endpoint "service" "channel" "parameters"
  
  echo redis-cli -u $server hset daq_service:topology:endpoint:$1:$2 ${@:3}  
  redis-cli -u $server hset daq_service:topology:endpoint:$1:$2 ${@:3}  
}

#function config_link () {
function link () {
  # config_link "service1" "channel" "service2" "channel" "parameters"
  
  echo redis-cli -u $server set daq_service:topology:link:$1:$2,$3:$4 non
  redis-cli -u $server set daq_service:topology:link:$1:$2,$3:$4 none
}

echo "Clear DAQ service keys"
redis-cli -n 0 keys 'daq_service:*' | xargs redis-cli del

echo "---------------------------------------------------------------------"
echo " config endpoint (socket)"
echo "---------------------------------------------------------------------"
#------------------------------------------------------------------------------------
#            service                channel         options
#------------------------------------------------------------------------------------

# Sampler 
endpoint     AmQStrTdcSampler        out           type push  method bind 

# subtime frame builder
endpoint     STFBuilder              in            type pull method connect 
endpoint     STFBuilder              out           type push method connect    autoSubChannel true
#endpoint     STFBuilder              dqm           type push method bind

#Scaler      
#endpoint     Scaler                  in            type pull method bind
#endpoint     Scaler                  out           type push method connect

# tf                                                                                                                         
endpoint     TimeFrameBuilder        in            type pull  method bind
endpoint     TimeFrameBuilder        out           type push  method connect  #  autoSubChannel true
#endpoint     TimeFrameBuilder        decimator     type push  method connect

# Sink
endpoint     FileSink                in            type pull  method bind
#endpoint     DecSink                 in            type pull  method bind

echo "---------------------------------------------------------------------"
echo " config link"
echo "---------------------------------------------------------------------"
#------------------------------------------------------------------------------------
#       service1                channel1              service2        channel2      
#------------------------------------------------------------------------------------

link    AmQStrTdcSampler        out                  STFBuilder        in
link    STFBuilder              out                  TimeFrameBuilder  in
#link    STFBuilder              dqm                  Scaler           in
#link    Scaler                  out                  ScrSink          in
link    TimeFrameBuilder        out                  FileSink          in
#link    TimeFrameBuilder        decimator            DecSink           in

この例では、AMANEQ 4 台からのデータを AmQStrTdcSampler で読み出し、STFBuilder を噛ませて TimeFrameBuild し、FileSinkプロセスでデータの保存をしている。このスクリプトの

server=redis://127.0.0.1:6379/0

の行は利用する redis データベースを指定しており 127.0.0.1:6379 の部分は自身の環境に合わせる必要がある。/0 の部分は redis のデータ番号を表しており、ここはデフォルトの 0 から変えることはあまりない。function endpoint () {...} と function link () {...} の部分は基本的にユーザーは編集しない。

endpoint     AmQStrTdcSampler        out           type push  method bind

という endpoint で始まる行で、各 FairMQ デバイスの endpoint (イメージはポートに近いか?ケーブルの入出力端子みたいなもの) の設定をしている。さらに、

 link    AmQStrTdcSampler        out                  STFBuilder        in

という link で始まる行で endpoint 間の接続を指定している。このスクリプトでは、いろいろな言葉が出てきて混乱しやすいが、channel: in/out/dqm/decimator は NestDAQ で定義されている言葉である。また type: push/pull や method: bind/connect は ZeroMQ で使われる言葉である。push/pull, bind/connect を詳しく理解するには ZeroMQ のマニュアルを読むのがよいが、簡単にいえば、データの入力と出力の"方向"を指定するのが type: push (出力) / pull (入力) であり、channel は入出力の endpoint としてどのチャンネル (ポートの種類をイメージするとわかりやすいか?) を利用するかを表している。endpoint の行において、type と channel の指定は無矛盾になっている必要があり、channel に in を指定した場合、type は必ず pull にする。また、channel に out/dqm/decimator を指定した場合、type は必ず push にする。method はデータの流れの方向を指定するものではなく、接続自体の方向を指定する。method を bind とすると、endpoint (言い換えるとポート) を開けて待っている状態であり、method を connect とすると、すでにどこかに endpoint として bind で待っているところに接続しにいくことになる。そのため、topology.sh を記述する際に、endpoint として method: bind の行を書いておいて、実際はそこになにも接続 (connect) しないことは許されるが、接続先の bind が存在しないにも関わらず endpoint として method: connect だけを書くことは許されない。ちなみに、method: bind / connect とデータの流れの方向 type: push (出力) / pull (入力) に対応関係はなく、endpoint の行で type: push (出力) としたときに method は bind でも connect でも良いし、type: pull (入力) としたときに method は bind でも connect でも良い。また、endpoint を指定する際のオプションとして、autoSubChannel というものがある。これは、channnel: out に指定するものであり、ラウンドロビンでデータを push したいときに設定する (?)。

例を挙げてもう少し解説しよう。以下のようなトポロジーがあったとする。

endpoint     AmQStrTdcSampler        out           type push method bind 
endpoint     STFBuilder              in            type pull method connect 
link         AmQStrTdcSampler        out           STFBuilder       in

AmQStrTdcSampler の out チャンネルのデータを STFBuilder の in チャンネルに送るトポロジーを表している。ここで、1行目の endpoint は channel が out なので type は push にする必要がある。2行目の endpoint は channel が in なので type は pull にする必要がある。method は 1 行目が bind、2 行目が connect になっているが、これを逆にして 1 行目を connect, 2 行目を bind としても問題ない。一方で、1 行目と2行目の method を共に bind にしたり共に connect にすることは許されない。また、2 行目と 3 行目をコメントアウトして 1 行目の bind だけを残すことはできるが、1 行目と 3 行目をコメントアウトして、2 行目の connect だけを残すことは許されない。

run.sh

run.sh スクリプトは FairMQ デバイスを立ち上げるためのスクリプトである。具体的な例は、exp-config/raris_bpm/run_bpmdaq/run-stf-tf.sh (を編集したもの) を示す。

#!/bin/bash

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/local/lib:$HOME/local/lib64

# 1. Sampler
tmux new-session -d -t sampler
for runID in {0..3}
do
    echo "start device Sampler ${runID}"
    #./start_device.sh.in AmQStrTdcSampler
    tmux new-window -d -n S${runID} -t sampler -- ./start_device.sh AmQStrTdcSampler #--host-ip 192.168.2.51
    sleep 0.1
done

tmux kill-window -t sampler:0
xterm -geometry 80x15+0+0 -T Sampler -e tmux a -t sampler &

# 2. STFB
tmux new-session -d -t stfb
for runID in {0..3}
do
    echo "start device SubTime Frame Builder ${runID}"
        tmux new-window -d -n STF${runID} -t stfb -- ./start_device.sh STFBuilder #--host-ip 192.168.2.51
    sleep 0.1
done

tmux kill-window -t stfb:0
xterm -geometry 80x15+500+0 -T SubTimeFrameBuilder -e tmux a -t stfb &
        
# 3. TFB
tmux new-session -d -t tfb
for runID in {0..0}
do
    echo "start device TimeFrameBuilder ${runID}"
    tmux new-window -d -n TFB${runID} -t tfb -- ./start_device.sh TimeFrameBuilder #--host-ip 192.168.2.51
    sleep 0.2
done
tmux kill-window -t tfb:0
xterm -geometry 80x15+0+270 -T TimeFrameBuilder -e tmux a -t tfb &

# 5. FileSink
tmux new-session -d -t sink

for runID in {0..0}
do
    echo "start device FileSink ${runID}"
        tmux new-window -d -n Sink${runID} -t sink -- ./start_device.sh FileSink #--host-ip 192.168.2.51
    sleep 0.2
done
tmux kill-window -t sink:0
xterm -geometry 80x15+500+270 -T Sink -e tmux a -t sink &

このスクリプトは各FairMQ デバイスを何プロセス立ち上げるかを記述し、その数だけ立ち上げるためものである。この例では、AmQStrTdcSampler を 4 プロセス、STFBuilder を 4 プロセス、TimeFrameBuilder を 1 プロセス、FileSinkプロセスを 1 プロセス立ち上げている。

for runID in {0..3}

という行で 4 プロセス立ち上げることを指定している。やっていることとしては、各 FairMQ デバイスの種類毎に xterm を立ち上げ、その中で tmux でウィンドウを分割して各ウィンドウに 1 プロセスを走らせる。具体的には、AmQStrTdcSampler のために xterm を 1 立ち上げ、そこに tmux で4つウィンドウを分け、それぞれのウィンドウで AmQStrTdcSampler のプロセスを走らせている。なんらかの理由によりプロセスがハングした場合は、xterm のウィンドウを消せば tmux も殺されるが、走っている FairMQ のプロセスによっては tmux が残る場合があり、その時は、kill_fairmq_devices.sh スクリプトを走らせると殺せる。

編集項目は、実験のFEEボードの数に合わせて、AmQStrTdcSampler、STFBuilder の立ち上げ数を決める。さらに、TimeFrameBuilder の負荷を見ながら立ち上げ数の調整を行う。他の後段のプロセス (Filter, TimeFrameSlicer, FileSink etc.) の立ち上げ数についても負荷を見ながら立ち上げ数の調整を行う。この調整は CPU 使用率、メモリ使用率、データの流れをモニターしながら調整するが、経験がものを言う場合もあるので、初心者には難しいかもしれない。エキスパートに相談するのがおすすめである。

start_device.sh

run.sh の中で実行しているスクリプト。

#!/bin/bash
#MY_TERM=xterm

DAQSERVICE_URI=' --registry-uri tcp://127.0.0.1:6379/0'
METRICS_URI=' --metrics-uri tcp://127.0.0.1:6379/1'
CONFIG_URI=' --parameter-config-uri tcp://127.0.0.1:6379/2'

#---------------------------------------------------------
if [[ $1 =~ fairmq- ]]; then
  BINDIR=""
else
  BINDIR=$HOME/nestdaq/bin
fi

PLUGIN_LIBDIR=$HOME/nestdaq/lib64

PLUGIN_SEARCH_PATH=" -S '<$PLUGIN_LIBDIR'"
DAQSERVICE_PLUGIN=" -P daq_service"
METRICS_PLUGIN=" -P metrics"
CONFIG_PLUGIN=" -P parameter_config"

echo "BINDIR             = $BINDIR"
echo "PLUGIN_LIBDIR      = $PLUGIN_LIBDIR"
echo "PLUGIN_SEARCH_PATH = $PLUGIN_SEARCH_PATH"
echo "DAQSERVICE_PLUGIN  = $DAQSERVICE_PLUGIN"
echo "METRICS_PLUGIN     = $METRICS_PLUGIN"
echo "CONFIG_PLUGIN      = $CONFIG_PLUGIN"
echo "DAQSERVICE_URI     = $DAQSERVICE_URI"
echo "METRICS_URI        = $METRICS_URI"
echo "CONFIG_URI         = $CONFIG_URI"

#==============================================================================
function run_device () {
  local var;
  var+=$PLUGIN_SEARCH_PATH
  var+=$DAQSERVICE_PLUGIN
  var+=$METRICS_PLUGIN
  var+=$CONFIG_PLUGIN
  var+=$DAQSERVICE_URI
  var+=$METRICS_URI
  var+=$CONFIG_URI
  #var+=" --severity debug4"
  var+=" --severity info"

  if [ -n "$MY_TERM" ]; then
    #echo \
    $MY_TERM -title $1 -e "$BINDIR/$@ $var"
  else
    #echo \
    eval "$BINDIR/$@ $var"
  fi
}

run_device $@

このスクリプトにおいて、

DAQSERVICE_URI=' --registry-uri tcp://127.0.0.1:6379/0'
METRICS_URI=' --metrics-uri tcp://127.0.0.1:6379/1'
CONFIG_URI=' --parameter-config-uri tcp://127.0.0.1:6379/2'

で利用する redis データベースの IP アドレス、ポート番号、データベース番号をしてしている。IPアドレス: 127.0.0.1 は自分自身の IP アドレスを表す。ポート番号 6379 とデータベース番号 /0, /1, /2 は特別な理由がない限りデフォルトのままでユーザーは編集しない。以下の bin ディレクトリとライブラリディレクトリのパスは自身の環境に合わせて指定する。

BINDIR=$HOME/nestdaq/bin
PLUGIN_LIBDIR=$HOME/nestdaq/lib64

本マニュアルでは、

BINDIR=$HOME/local/bin
PLUGIN_LIBDIR=$HOME/local/lib64

がデフォルトである。さらに、

var+=" --severity info"

の部分で、FairMQデバイスが出力するメッセージの severity (エラーメッセージをどこまで詳しく表示するか) をしており、これを変更しても良い。

kill_fairmq_devices.sh

#!/bin/bash

pkill start_device.sh

run.sh で立ち上げた FairMQ デバイスをすべて殺すスクリプト。run.sh の中では start_device.sh スクリプトを使って各 FairMQ デバイスを立ち上げるので、pkill start_device.sh とすれば、すべての FiarMQ デバイスを殺せる。DAQが正常に走り始めなかったりした場合、これを走らせる。

del_daqservices.sh

#!/bin/bash
redis-cli -n 0 keys 'daq_service:*' | xargs redis-cli del
#redis-cli -u redis://127.0.0.1:6379 flushall                           
#redis-cli -u redis://127.0.0.1:6379/0 flushdb                          
#redis-cli -u redis://127.0.0.1:6379/1 flushdb                          
redis-cli -u redis://127.0.0.1:6379/2 flushdb 

redis データベースの中身を一部リセットするスクリプト。基本的にこのスクリプトを走らせると、DAQにコントロールに関係するラン番号以外の情報は綺麗に消えてくれる。

triggerlogic.sh

FairMQ デバイスの LogicFilter のパラメータを設定するためのスクリプトである。スクリプトの構造は mq-param.sh とほぼ同じであるが、mq-param.sh の中に書くとうまくエスケープ文字が処理されない場合があったため、このスクリプトが mq-param.sh とは別 に用意された。エスケープ文字の問題が解決できれば、mq-param.sh の中に書いても問題ない。中身は以下のような感じ。

#!/bin/bash

server=redis://127.0.0.1:6379/2

function param () {
  # "instance":"field" "value"
  #echo redis-cli -u $server set parameters:$1:$2 ${@:3}
  #redis-cli -u $server set parameters:$1:$2 ${@:3}
  echo redis-cli -u $server hset parameters:$1 ${@:2}
  redis-cli -u $server hset parameters:$1 ${@:2}
}

function param1 () {
  #echo redis-cli -u $server hset parameters:$1 ${@:2}
        echo zero:$0
        echo one:$1
        echo two:$2
        echo three:$3
  echo redis-cli -u $server hset parameters:$1 $3
  redis-cli -u $server hset parameters:$1 $2 $3
}

redis-cli -u $server hset parameters:LogicFilter trigger-signals \
          "(0xc0a80a25 0 0) (0xc0a80a25 1 0)"
#         "(0xc0a80a24 0 0) (0xc0a80a24 16 0) \
#     (0xc0a80a25 0 0) (0xc0a80a25  1 0) (0xc0a80a25 2 0) (0xc0a80a25 3 0) \
#     (0xc0a80a25 4 0) (0xc0a80a25  5 0) (0xc0a80a25 6 0) (0xc0a80a25 7 0) \
#     (0xc0a80a25 8 0) (0xc0a80a25  9 0)"
#         "(0xc0a80a23 7 0) (0xc0a80a23 24 0)"

# (0xc0a80a23 31 0) (0xc0a80a23 15 0) \ 
# (0xc0a80a23 63 0) (0xc0a80a23 47 0) \
# (0xc0a80a24  0 0) (0xc0a80a24 16 0) \
# (0xc0a80a25  0 0) (0xc0a80a25  1 0) (0xc0a80a25  2 0) (0xc0a80a25  3 0) \
# (0xc0a80a25  4 0) (0xc0a80a25  5 0) (0xc0a80a25  6 0) (0xc0a80a25  7 0) \
# (0xc0a80a25  8 0) (0xc0a80a25  9 0) (0xc0a80a25 10 0) (0xc0a80a25 11 0) \
# (0xc0a80a25 12 0) (0xc0a80a25 13 0) (0xc0a80a25 24 0) (0xc0a80a25 15 0) \
# (0xc0a80a25 16 0) (0xc0a80a25 17 0) (0xc0a80a25 18 0) (0xc0a80a25 19 0) \
# (0xc0a80a25 20 0) (0xc0a80a25 21 0) (0xc0a80a25 22 0) (0xc0a80a25 23 0) "

redis-cli -u $server hset parameters:LogicFilter trigger-formula \
 "RPN 1 ! 0 &"
# "( 0 & 1 )"
#"( 0 & 1 & ( 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 ) )"
#"RPN 0 ! 1 & 2 ! 3 & | 4 ! 5 & | 6 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |"

redis-cli -u $server hset parameters:LogicFilter trigger-width "10"

echo '----'

redis-cli -u $server hgetall parameters:LogicFilter

このスクリプトの中で編集項目は

server=redis://127.0.0.1:6379/2

の部分で、IPアドレスとポート番号が正しいかを確認する。 function param () {...}, function param1 () {...} の部分は編集しない。また、

redis-cli -u $server hset parameters:LogicFilter trigger-signals ...
redis-cli -u $server hset parameters:LogicFilter trigger-formula ...
...
 redis-cli -u $server hset parameters:LogicFilter trigger-width "10"

の部分はトリガー条件を指定しており、実験のトリガー条件に合わせて編集を行う。

stf.sh

AmQStrTdcSampler - STFBuilder - FileSink のコンフィグレーションでDAQを走らせたい場合に利用するスクリプト。中身を見ると、

#!/bin/sh

#./mq-param-dev-null.sh
./mq-param.sh
./topology-stf.sh
exec ./run-stf.sh

というように単に mq-param.sh, topology-stf.sh, run-stf.sh を実行しているに過ぎない。個別に実行するのが面倒なときにこのスクリプトを用いる。データを保存しないモードで DAQ を走らせたい場合は、以下のように編集すれば良いはず。

./mq-param-dev-null.sh
#./mq-param.sh

tf.sh

AmQStrTdcSampler - STFBuilder - TimeFrameBuilder - FileSink のコンフィグレーションでDAQを走らせたい場合に利用するスクリプト。中身は以下の通り。

#!/bin/sh

#./mq-param-dev-null.sh
./mq-param.sh
./topology-stf-tf.sh
exec ./run-stf-tf.sh

tfs.sh

AmQStrTdcSampler - STFBuilder - TimeFrameBuilder - LogicFilter - TimeFrameSlicer - FileSink のコンフィグレーションでDAQを走らせたい場合に利用するスクリプト。中身は以下の通り。

#!/bin/sh

#./mq-param-dev-null.sh
./mq-param.sh
./topology-stf-tf-flt-tfs.sh
./triggerlogic.sh
exec ./run-stf-tf-flt-tfs.sh

secflt.sh

AmQStrTdcSampler - STFBuilder - TimeFrameBuilder - LogicFilter - TimeFrameSlicer - SecondFilter - FileSink のコンフィグレーションでDAQを走らせたい場合に利用するスクリプト。中身は以下の通り。

#!/bin/sh

#./mq-param-dev-null.sh
./mq-param.sh
./triggerlogic.sh
./topology-stf-tf-flt-tfs-secflt.sh
exec ./run-stf-tf-flt-tfs-secflt.sh

付録: AMANEQ のリセットについて

ここで、reset_modules.sh の利用機会について言及しておく。AMANEQから読み出したデータに問題があるといった場合、reset_modules.sh スクリプトを実行し、AMANEQ のソフトウェアリセットを行う。ただ、最新のファームウェアの動作はかなり安定しつつあり、リセットが必要な機会は減ってきている。( 前のHR-TDC のファームウェアバージョンでは、データの読み出しで負荷がかかった場合、Local Heart Beat Frame Mismatch が起きて、リセットが必要になる時があった。)何らかの理由でソフトウェアのリセット効かない場合は、AMANEQのハードウェアリセットスイッチを押す。ちなみに、本多氏曰く、AMANEQ のパワーサイクル (電源 OFF/ON) が有効な場合はあまり考えられず、問題を悪化させるだけであろうとのこと。