|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Checks that multithreaded Geant4 in o2-sim gives the same output for 1 and N transport threads. |
| 3 | +# |
| 4 | +# Usage: o2-sim-mt-equality.sh [-n events] [-j threads] [-g generator] [--field kG] [--seed seed] |
| 5 | +# [--seeding track|subevent] [--tolerance fraction] [--workdir dir] [module ...] |
| 6 | +# |
| 7 | +# Runs the same seeded workload with --isMT -j 1 and --isMT -j N and compares the kinematics and hit files |
| 8 | +# event by event and branch by branch. A sequential run with the same seed is the reference for the number of |
| 9 | +# hits of each detector, which must not be zero and must agree within the tolerance (default 0.2). Exits with |
| 10 | +# 1 at the first difference. Without modules, the passive geometry with ITS is used. |
| 11 | + |
| 12 | +nev=2 |
| 13 | +nthreads=2 |
| 14 | +gen=pythia8pp |
| 15 | +field=-5 |
| 16 | +seed=4711 |
| 17 | +seeding=track |
| 18 | +tolerance=0.2 |
| 19 | +workdir= |
| 20 | +modules=() |
| 21 | +while [ $# -gt 0 ]; do |
| 22 | + case $1 in |
| 23 | + -n) nev=$2; shift 2 ;; |
| 24 | + -j) nthreads=$2; shift 2 ;; |
| 25 | + -g) gen=$2; shift 2 ;; |
| 26 | + --field) field=$2; shift 2 ;; |
| 27 | + --seed) seed=$2; shift 2 ;; |
| 28 | + --seeding) seeding=$2; shift 2 ;; |
| 29 | + --tolerance) tolerance=$2; shift 2 ;; |
| 30 | + --workdir) workdir=$2; shift 2 ;; |
| 31 | + -h|--help) sed -n '2,10p' $0; exit 0 ;; |
| 32 | + *) modules+=("$1"); shift ;; |
| 33 | + esac |
| 34 | +done |
| 35 | +[ ${#modules[@]} -eq 0 ] && modules=(HALL MAG DIPO COMP PIPE ABSO SHIL ITS) |
| 36 | +case $seeding in |
| 37 | + track) seedconf="SimCutParams.trackSeed=true" ;; |
| 38 | + subevent) seedconf="SimCutParams.trackSeed=false" ;; |
| 39 | + *) echo "unknown seeding '$seeding', use track or subevent"; exit 1 ;; |
| 40 | +esac |
| 41 | +o2sim=o2-sim |
| 42 | +[ -x "$O2_ROOT/bin/o2-sim" ] && o2sim=$O2_ROOT/bin/o2-sim |
| 43 | +[ -z "$workdir" ] && workdir=$(mktemp -d ${TMPDIR:-/tmp}/o2sim-mt-equality-XXXXXX) |
| 44 | +mkdir -p $workdir && cd $workdir || exit 1 |
| 45 | + |
| 46 | +# content hash and number of entries per event and branch of the o2sim tree, independent of the basket layout |
| 47 | +cat > hashtree.C <<'EOF' |
| 48 | +void hashtree(const char* fname) |
| 49 | +{ |
| 50 | + TFile f(fname); |
| 51 | + auto t = (TTree*)f.Get("o2sim"); |
| 52 | + if (!t) { |
| 53 | + return; |
| 54 | + } |
| 55 | + std::vector<std::tuple<TClass*, void*, std::string>> objs; |
| 56 | + objs.reserve(t->GetListOfBranches()->GetEntries()); // the branch addresses point into objs |
| 57 | + for (auto b : *t->GetListOfBranches()) { |
| 58 | + auto br = (TBranch*)b; |
| 59 | + TClass* cl = nullptr; |
| 60 | + EDataType dt; |
| 61 | + br->GetExpectedType(cl, dt); |
| 62 | + if (!cl) { |
| 63 | + continue; |
| 64 | + } |
| 65 | + objs.emplace_back(cl, cl->New(), br->GetName()); |
| 66 | + br->SetAddress(&std::get<1>(objs.back())); |
| 67 | + } |
| 68 | + for (Long64_t i = 0; i < t->GetEntries(); ++i) { |
| 69 | + t->GetEntry(i); |
| 70 | + for (auto& [cl, obj, name] : objs) { |
| 71 | + TBufferFile buf(TBuffer::kWrite); |
| 72 | + buf.WriteObjectAny(obj, cl); |
| 73 | + TMD5 md5; |
| 74 | + md5.Update((UChar_t*)buf.Buffer(), buf.Length()); |
| 75 | + md5.Final(); |
| 76 | + printf("HASH event %lld branch %s %s\n", i, name.c_str(), md5.AsString()); |
| 77 | + if (auto proxy = cl->GetCollectionProxy()) { |
| 78 | + TVirtualCollectionProxy::TPushPop helper(proxy, obj); |
| 79 | + printf("COUNT event %lld branch %s %u\n", i, name.c_str(), proxy->Size()); |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | +} |
| 84 | +EOF |
| 85 | + |
| 86 | +run() { # <directory> <o2-sim mode options> |
| 87 | + local dir=$1 |
| 88 | + shift |
| 89 | + mkdir -p $dir && cd $dir |
| 90 | + $o2sim "$@" -n $nev -g $gen -e TGeant4 --seed $seed --field $field -m ${modules[@]} --configKeyValues "$seedconf" > sim.log 2>&1 |
| 91 | + local rc=$? |
| 92 | + if [ $rc -ne 0 ] || ! grep -q "SIMULATION RETURNED SUCCESFULLY" sim.log; then |
| 93 | + echo "o2-sim in $dir failed (exit code $rc), see $workdir/$dir" |
| 94 | + exit 1 |
| 95 | + fi |
| 96 | + for f in o2sim_Kine.root o2sim_Hits*.root; do |
| 97 | + [ -f $f ] || continue |
| 98 | + root -l -b -q "../hashtree.C(\"$f\")" 2>/dev/null > $f.out |
| 99 | + grep "^HASH" $f.out | sed "s/^HASH/$f/" > $f.hashes |
| 100 | + grep "^COUNT" $f.out | awk '{n += $NF} END {print n + 0}' > $f.count |
| 101 | + done |
| 102 | + cd .. |
| 103 | +} |
| 104 | + |
| 105 | +echo "o2-sim MT equality: ${modules[*]}, $nev events of $gen, field $field kG, $seeding seeding, 1 against $nthreads threads, in $workdir" |
| 106 | +run seq -j 1 |
| 107 | +run mt1 --isMT 1 -j 1 |
| 108 | +run mt$nthreads --isMT 1 -j $nthreads |
| 109 | +status=0 |
| 110 | +for h in mt1/*.hashes; do |
| 111 | + f=$(basename $h) |
| 112 | + file=${f%.hashes} |
| 113 | + if [ ! -s $h ]; then |
| 114 | + echo "$file: no entries" |
| 115 | + status=1 |
| 116 | + elif cmp -s $h mt$nthreads/$f; then |
| 117 | + echo "$file: identical ($(wc -l < $h) event-branch hashes)" |
| 118 | + else |
| 119 | + echo "$file: DIFFERS, first at $(diff $h mt$nthreads/$f | grep -m1 '^<' | cut -d' ' -f3-6)" |
| 120 | + status=1 |
| 121 | + fi |
| 122 | +done |
| 123 | +[ $(ls mt$nthreads/*.hashes | wc -l) -eq $(ls mt1/*.hashes | wc -l) ] || { echo "the runs wrote different output files"; status=1; } |
| 124 | +# the sequential run as reference for the number of hits, which catches a detector clone that makes no hits |
| 125 | +for c in seq/o2sim_Hits*.root.count; do |
| 126 | + [ -f "$c" ] || continue |
| 127 | + file=$(basename ${c%.count}) |
| 128 | + nseq=$(cat $c) |
| 129 | + nmt=$(cat mt1/$file.count 2>/dev/null || echo 0) |
| 130 | + if [ "$nmt" -eq 0 ]; then |
| 131 | + echo "$file: no hits in MT (sequential: $nseq)" |
| 132 | + status=1 |
| 133 | + elif ! awk -v a=$nseq -v b=$nmt -v t=$tolerance 'BEGIN {exit !(a > 0 && (a - b < 0 ? b - a : a - b) <= t * a)}'; then |
| 134 | + echo "$file: $nmt hits in MT against $nseq in sequential mode, beyond the tolerance $tolerance" |
| 135 | + status=1 |
| 136 | + else |
| 137 | + echo "$file: $nmt hits in MT, $nseq in sequential mode" |
| 138 | + fi |
| 139 | +done |
| 140 | +[ $status -eq 0 ] && echo "EQUALITY TEST PASSED" || echo "EQUALITY TEST FAILED" |
| 141 | +exit $status |
0 commit comments