Skip to content

Commit

Permalink
simple truth efficiency calculator (#396)
Browse files Browse the repository at this point in the history
* update URL

* truth efficiency matrix calculator

* cleanup, add warning printout

* rename, cleanup, add json

* merge scripts

* use an array

* parallelize

* cleanup

* actually loop

* now it works

* use gemc files with truth-matching enabled

* cleanup, run truth efficiency

* bugfix

* cleanup and bugfix

* bugfix, now it works

* avoid unnecessary lookups

* more convenient JSON structure

* cleanup for thread safety

* make adding threadsafe
  • Loading branch information
baltzell authored Jan 2, 2025
1 parent 3896b8f commit 9fb1b2e
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 56 deletions.
10 changes: 10 additions & 0 deletions bin/trutheff
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

. `dirname $0`/../libexec/env.sh

export MALLOC_ARENA_MAX=1

java -Xmx1536m -Xms1024m -XX:+UseSerialGC \
-cp "$CLAS12DIR/lib/clas/*:$CLAS12DIR/lib/services/*:$CLAS12DIR/lib/utils/*" \
org.jlab.analysis.efficiency.Truth \
$*
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package org.jlab.analysis.efficiency;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeMap;
import org.jlab.jnp.hipo4.data.Bank;
import org.jlab.jnp.hipo4.data.Event;
import org.jlab.jnp.hipo4.data.Schema;
import org.jlab.jnp.hipo4.data.SchemaFactory;
import org.jlab.jnp.hipo4.io.HipoReader;
import org.jlab.jnp.utils.json.JsonArray;
import org.jlab.jnp.utils.json.JsonObject;
import org.jlab.utils.options.OptionParser;

/**
* Efficiency matrix calculator based solely on the MC::GenMatch truth-matching
* bank (which is purely hit-based), and a pid assignment match in MC::Particle
* and REC::Particle.
*
* @author baltzell
*/
public class Truth {

static final int UDF = 0;
static final List<Integer> NEGATIVES = Arrays.asList(11, -211, -321, -2212);
static final List<Integer> POSITIVES = Arrays.asList(-11, 211, 321, 2212, 45);
static final List<Integer> NEUTRALS = Arrays.asList(22, 2112);

List<Integer> validPids;
Schema mcGenMatch;
Schema mcParticle;
Schema recParticle;
long[][] recTallies;
long[] mcTallies;

public static void main(String[] args) {
OptionParser o = new OptionParser("trutheff");
o.setRequiresInputList(true);
o.parse(args);
Truth t = new Truth(o.getInputList().get(0));
t.add(o.getInputList());
System.out.println(t.toTable());
System.out.println(t.toJson());
}

public Truth(SchemaFactory s) {
init(s);
}

public Truth(HipoReader r) {
init(r.getSchemaFactory());
}

public Truth(String filename) {
HipoReader r = new HipoReader();
r.open(filename);
init(r.getSchemaFactory());
}

private void init(SchemaFactory schema) {
validPids = new ArrayList(NEGATIVES);
validPids.addAll(POSITIVES);
validPids.addAll(NEUTRALS);
validPids.add(UDF);
mcTallies = new long[validPids.size()];
recTallies = new long[validPids.size()][validPids.size()];
mcGenMatch = schema.getSchema("MC::GenMatch");
mcParticle = schema.getSchema("MC::Particle");
recParticle = schema.getSchema("REC::Particle");
}

/**
* Get one element of the efficiency matrix.
* @param truth true PID
* @param rec reconstructed PID
* @return probability
*/
public float get(int truth, int rec) {
long sum = mcTallies[validPids.indexOf(truth)];
return sum>0 ? ((float)recTallies[validPids.indexOf(truth)][validPids.indexOf(rec)])/sum : 0;
}

/**
* Add an event in the form of truth and reconstructed particle species.
* @param truth truth PID
* @param rec reconstructed PID
*/
public synchronized void add(int truth, int rec) {
final int t = validPids.indexOf(truth);
if (t < 0) return;
final int r = validPids.indexOf(rec);
mcTallies[t]++;
if (r < 0) recTallies[t][UDF]++;
else recTallies[t][r]++;
}

/**
* Add a HIPO event.
* @param e
*/
public void add(Event e) {
Bank bm = new Bank(mcParticle);
Bank br = new Bank(recParticle);
e.read(bm);
e.read(br);
TreeMap<Short,Short> good = getMapping(e);
for (short row=0; row<bm.getRows(); ++row) {
if (!good.containsKey(row)) add(bm.getInt("pid",row), UDF);
else add(bm.getInt("pid",row), br.getInt("pid",good.get(row)));
}
}

/**
* Add input HIPO files by path.
* @param filenames
*/
public void add(List<String> filenames) {
Event e = new Event();
for (String f : filenames) {
HipoReader r = new HipoReader();
r.open(f);
while (r.hasNext()) {
r.nextEvent(e);
add(e);
}
}
}

/**
* Truth-matching banks contain pointers to MC::Particle and REC::Particle,
* and here we cache that mapping to avoid nested loops.
*/
private TreeMap getMapping(Event e) {
Bank b = new Bank(mcGenMatch);
e.read(b);
TreeMap<Short,Short> m = new TreeMap<>();
for (int row=0; row<b.getRows(); ++row)
m.put(b.getShort("mcindex", row), b.getShort("pindex",row));
return m;
}

/**
* Get efficiencies as a human-readable table.
* @return
*/
public String toTable() {
StringBuilder s = new StringBuilder();
s.append(" ");
for (int i=0; i<validPids.size(); ++i) {
s.append(String.format("%7d",validPids.get(i)));
if (validPids.size()==i+1) s.append("\n");
}
for (int i=0; i<validPids.size(); ++i) {
s.append(String.format("%6d",validPids.get(i)));
for (int j=0; j<validPids.size(); ++j) {
s.append(String.format("%7.4f",get(validPids.get(i),validPids.get(j))));
if (validPids.size()==j+1) s.append("\n");
}
}
return s.toString();
}

/**
* Get efficiencies as a JSON object.
* @return
*/
public JsonObject toJson() {
JsonObject effs = new JsonObject();
JsonArray pids = new JsonArray();
for (int i=0; i<validPids.size(); ++i) {
pids.add(validPids.get(i));
JsonArray a = new JsonArray();
for (int j=0; j<validPids.size(); ++j)
a.add(get(validPids.get(i),validPids.get(j)));
effs.add(Integer.toString(validPids.get(i)),a);
}
JsonObject ret = new JsonObject();
ret.add("pids", pids);
ret.add("effs", effs);
return ret;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.jlab.utils.options;

import java.util.ArrayList;
Expand All @@ -16,17 +11,15 @@
*/
public class OptionParser {

private Map<String,OptionValue> optionsDescriptors = new TreeMap<String,OptionValue>();
private Map<String,OptionValue> requiredOptions = new TreeMap<String,OptionValue>();
private Map<String,OptionValue> parsedOptions = new TreeMap<String,OptionValue>();
private List<String> parsedInputList = new ArrayList<String>();
private Map<String,OptionValue> optionsDescriptors = new TreeMap<>();
private Map<String,OptionValue> requiredOptions = new TreeMap<>();
private Map<String,OptionValue> parsedOptions = new TreeMap<>();
private List<String> parsedInputList = new ArrayList<>();
private String program = "undefined";
private boolean requiresInputList = true;
private String programDescription = "";

public OptionParser(){

}
public OptionParser(){}

public OptionParser(String pname){
this.program = pname;
Expand Down Expand Up @@ -130,7 +123,6 @@ public void parse(String[] args){
System.exit(0);
}

//this.show(arguments);
for(Map.Entry<String,OptionValue> entry : this.requiredOptions.entrySet()){
boolean status = entry.getValue().parse(arguments);
if(status==false) {
Expand All @@ -153,7 +145,11 @@ public void parse(String[] args){
this.parsedInputList.add(item);
}
}
//this.show(arguments);

// FIXME: seems like we should really be throwing a RuntimeException ...
if (this.requiresInputList && this.parsedInputList.isEmpty()) {
System.err.println(" \n*** ERROR *** Empty Input List.");
}
}

public List<String> getInputList(){
Expand All @@ -167,9 +163,7 @@ public static void main(String[] args){
parser.addOption("-r", "10");
parser.addOption("-t", "25.0");
parser.addOption("-d", "35");

parser.parse(options);

parser.show();
}
}
2 changes: 1 addition & 1 deletion install-clara
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function cleanup() {

function build_clara {
export CLARA_HOME=$1
git clone https://github.com/baltzell/clara-java
git clone https://code.jlab.org/hallb/clas12/clara-java
cd clara-java
git checkout java21
./gradlew && ./gradlew deploy
Expand Down
24 changes: 13 additions & 11 deletions validation/advanced-tests/run-eb-tests.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

webDir=http://clasweb.jlab.org/clas12offline/distribution/coatjava/validation_files/eb
webVersion=5.10-fid-r11
webVersion=5.10-fid-tm-r11
webDir=$webDir/$webVersion

# coatjava must already be built at ../../coatjava/
Expand Down Expand Up @@ -40,11 +40,11 @@ do
done

# last argument is input file stub:
webFileStub="${@: -1}"
stub="${@: -1}"

# sanity check on filestub name,
# just to error with reasonable message before proceeding:
case $webFileStub in
case $stub in
# electron in forward, hadron in forward:
electronproton)
;;
Expand Down Expand Up @@ -79,7 +79,7 @@ case $webFileStub in
electrondeuteronC)
;;
*)
echo Invalid input evio file: $webFileStub
echo Invalid input evio file: $stub
exit 1
esac

Expand Down Expand Up @@ -122,28 +122,28 @@ then
fi

# download test files, if necessary:
wget -N --no-check-certificate $webDir/${webFileStub}.hipo
wget -N --no-check-certificate $webDir/${stub}.hipo
if [ $? != 0 ] ; then echo "wget validation files failure" ; exit 1 ; fi

# update the schema dictionary: (no longer necessary now that recon-util does it)
#rm -f up_${webFileStub}.hipo
#../../coatjava/bin/hipo-utils -update -d ../../coatjava/etc/bankdefs/hipo4/ -o up_${webFileStub}.hipo ${webFileStub}.hipo
#rm -f up_${stub}.hipo
#../../coatjava/bin/hipo-utils -update -d ../../coatjava/etc/bankdefs/hipo4/ -o up_${stub}.hipo ${stub}.hipo

# run reconstruction:
rm -f out_${webFileStub}.hipo
rm -f out_${stub}.hipo
if [ $useClara -eq 0 ]
then
GEOMDBVAR=$geoDbVariation
export GEOMDBVAR
../../coatjava/bin/recon-util -i ${webFileStub}.hipo -o out_${webFileStub}.hipo -c 2
../../coatjava/bin/recon-util -i ${stub}.hipo -o out_${stub}.hipo -c 2
else
echo "set inputDir $PWD/" > cook.clara
echo "set outputDir $PWD/" >> cook.clara
echo "set threads 7" >> cook.clara
echo "set javaMemory 2" >> cook.clara
echo "set session s_cook" >> cook.clara
echo "set description d_cook" >> cook.clara
ls ${webFileStub}.hipo > files.list
ls ${stub}.hipo > files.list
echo "set fileList $PWD/files.list" >> cook.clara
echo "run local" >> cook.clara
echo "exit" >> cook.clara
Expand All @@ -152,8 +152,10 @@ then
fi

# run Event Builder tests:
java -DCLAS12DIR="$COAT" -Xmx1536m -Xms1024m -cp $classPath2 -DINPUTFILE=out_${webFileStub}.hipo org.junit.runner.JUnitCore eb.EBTwoTrackTest
java -DCLAS12DIR="$COAT" -Xmx1536m -Xms1024m -cp $classPath2 -DINPUTFILE=out_${stub}.hipo org.junit.runner.JUnitCore eb.EBTwoTrackTest
if [ $? != 0 ] ; then echo "EBTwoTrackTest unit test failure" ; exit 1 ; else echo "EBTwoTrackTest passed unit tests" ; fi

$COAT/bin/trutheff ./out_${stub}.hipo

exit 0

9 changes: 0 additions & 9 deletions validation/advanced-tests/src/eb/scripts/gemc-all.sh

This file was deleted.

Loading

0 comments on commit 9fb1b2e

Please sign in to comment.