Skip to content

Commit bf87e65

Browse files
committed
refactor: detector QA cut code should not be standalone
The code in `qa-detectors` just applies detector QA cut lines and duplicates timelines filtered by the QA cuts. This code was developed independently, and makes assumptions of the contents of HIPO timeline files, such as graph names. This is not ideal, and `applyBounds.groovy` is especially difficult to maintain. Instead, apply QA cuts _directly to_ each timeline object, which is much more flexible. Later on, we could apply these new QA methods to physics timelines too.
1 parent 2a746a5 commit bf87e65

3 files changed

Lines changed: 89 additions & 29 deletions

File tree

bin/qtl-analysis

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,6 @@ fi
255255
[ -z "$outputDir" ] && outputDir=$(realpath $(pwd -P)/outfiles/$dataset) || outputDir=$(realpath $outputDir)
256256

257257
# set subdirectories
258-
finalDirPreQA=$outputDir/timeline_web_preQA
259258
finalDir=$outputDir/timeline_web
260259
logDir=$outputDir/log
261260

@@ -267,7 +266,6 @@ $sep
267266
INPUT_DIR = $inputDir
268267
DATASET_NAME = $dataset
269268
OUTPUT_DIR = $outputDir
270-
FINAL_DIR_PREQA = $finalDirPreQA
271269
FINAL_DIR = $finalDir
272270
LOG_DIR = $logDir
273271
NUM_THREADS = $numThreads
@@ -303,9 +301,6 @@ detDirs=(
303301

304302
# cleanup output directories
305303
if $enableAna; then
306-
if [ -d $finalDirPreQA ]; then
307-
rm -rv $finalDirPreQA
308-
fi
309304
if [ -d $logDir ]; then
310305
for fail in $(find $logDir -name "*.fail"); do
311306
rm $fail
@@ -314,7 +309,7 @@ if $enableAna; then
314309
fi
315310

316311
# make output directories
317-
mkdir -p $logDir $finalDirPreQA $finalDir
312+
mkdir -p $logDir $finalDir
318313

319314

320315
##################################################################################
@@ -353,7 +348,7 @@ if $enableAna; then
353348
}
354349

355350
# change working directory to output directory
356-
pushd $finalDirPreQA
351+
pushd $finalDir
357352

358353
# make detector subdirectories
359354
for detDir in ${detDirs[@]}; do
@@ -426,23 +421,6 @@ if $enableAna; then
426421
popd
427422
fi
428423

429-
######################################
430-
# run QA
431-
######################################
432-
433-
if $enableAna; then
434-
# first, copy the timelines to the final timeline directory
435-
echo ">>> copy timelines to final directory..."
436-
cp -rL $finalDirPreQA/* $finalDir/
437-
# then add the QA lines
438-
echo ">>> add QA lines..."
439-
logFile=$logDir/qa
440-
$TIMELINESRC/libexec/run-groovy-timeline.sh $TIMELINESRC/qa-detectors/util/applyBounds.groovy $finalDirPreQA $finalDir > $logFile.out 2> $logFile.err || touch $logFile.fail
441-
outputFiles=$(find $finalDir -name "*_QA.hipo")
442-
[ -n "$outputFiles" ] && $TIMELINESRC/libexec/hipo-check.sh $outputFiles
443-
fi
444-
445-
446424

447425
######################################
448426
# error checking

src/main/java/org/jlab/clas/timeline/analysis/ec/ec_Sampl.groovy

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import java.util.concurrent.ConcurrentHashMap
33
import org.jlab.groot.data.TDirectory
44
import org.jlab.groot.data.GraphErrors
55
import org.jlab.clas.timeline.fitter.ECFitter
6+
import org.jlab.clas.timeline.util.QA
67

78
class ec_Sampl {
89

@@ -35,7 +36,7 @@ def write() {
3536

3637
TDirectory out = new TDirectory()
3738
out.mkdir('/timelines')
38-
(0..<6).each{ sec->
39+
def grtlList = (0..<6).collect{ sec->
3940
def grtl = new GraphErrors('sec'+(sec+1))
4041
grtl.setTitle("ECAL Sampling Fraction per sector")
4142
grtl.setTitleY("ECAL Sampling Fraction per sector")
@@ -50,10 +51,10 @@ def write() {
5051
out.addDataSet(it.flist[sec])
5152
grtl.addPoint(it.run, it.Sampling[sec], 0, 0)
5253
}
53-
out.cd('/timelines')
54-
out.addDataSet(grtl)
54+
grtl
5555
}
56-
57-
out.writeFile('ec_Sampling.hipo')
56+
out.cd('/timelines')
57+
QA.cutGraphs(grtlList, lb: 0.23, ub: 0.26, out: out)
58+
out.writeFile('ec_Sampling_QA.hipo')
5859
}
5960
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package org.jlab.clas.timeline.util
2+
import org.jlab.groot.data.GraphErrors
3+
import org.jlab.groot.data.TDirectory
4+
5+
class QA {
6+
7+
/// @returns a single horizontal cut line
8+
/// @param value the y-axis value of this line
9+
/// @param the color of this line
10+
static GraphErrors makeCutLine(double value, String color=null) {
11+
if(value==null) return null;
12+
line_name = [
13+
'plotLine',
14+
'horizontal',
15+
value,
16+
color ?: 'black',
17+
].join(':');
18+
new GraphErrors(line_name);
19+
}
20+
21+
/// result of `cutGraphs`
22+
class CutGraphResult {
23+
/// graphs which include only the "bad" points (points outside QA cuts)
24+
public GraphErrors[] bad_graphs;
25+
/// cut lines
26+
public GraphErrors[] cut_lines;
27+
}
28+
29+
/// @param input_graphs a list of graphs to cut
30+
/// @param args.lb lower QA bound (default: no bound)
31+
/// @param args.ub upper QA bound (default: no bound)
32+
/// @param args.lb_color color of lower bound line
33+
/// @param args.ub_color color of upper bound line
34+
/// @param args.out TDirectory for adding graphs and lines, if defined
35+
/// @returns `CutGraphResult`
36+
static CutGraphResult cutGraphs(Map args, GraphErrors[] input_graphs) {
37+
def result = new CutGraphResult();
38+
// make lines
39+
result.cut_lines = [
40+
[args.lb, args.lb_color],
41+
[args.ub, args.ub_color],
42+
]
43+
.collect{makeCutLine(*it)}
44+
.findAll{it != null};
45+
// define QA cut
46+
def reqs = []
47+
if(args.lb != null)
48+
reqs << {val -> val >= args.lb };
49+
if(args.ub != null)
50+
reqs << {val -> val <= args.ub };
51+
def checkPoint = { val ->
52+
allow = true;
53+
reqs.each{ req -> allow &= req(val) };
54+
pass;
55+
};
56+
// apply cuts
57+
result.bad_graphs = input_graphs.collect{ input_graph ->
58+
def bad_graph = new GraphErrors();
59+
bad_graph.setName(input_graph.getName() + "__bad");
60+
bad_graph.setTitle(input_graph.getTitle());
61+
bad_graph.setTitleX(input_graph.getTitleX());
62+
bad_graph.setTitleY(input_graph.getTitleY());
63+
// loop over points, checking the cuts
64+
input_graph.getDataSize(0).times{ i ->
65+
def val_x = input_graph.getDataX(i);
66+
def val_y = input_graph.getDataY(i);
67+
if(!checkPoint(val_y))
68+
bad_graph.addPoint(val_x, val_y);
69+
}
70+
bad_graph;
71+
}
72+
// write output
73+
if(args.out != null) {
74+
result.cut_lines.each{args.out.addDataSet(it)};
75+
input_graphs.each{args.out.addDataSet(it)};
76+
result.bad_graphs.each{args.out.addDataSet(it)};
77+
}
78+
result;
79+
}
80+
81+
}

0 commit comments

Comments
 (0)