diff --git a/bin/hipo-json b/bin/hipo-json new file mode 100755 index 000000000..b3dcb9b74 --- /dev/null +++ b/bin/hipo-json @@ -0,0 +1,8 @@ +#!/bin/sh + +. `dirname $0`/env.sh + +java -Xms1024m \ + -cp "$CLAS12DIR/lib/clas/*:$CLAS12DIR/lib/plugins/*" \ + org.jlab.utils.JsonUtils \ + $* diff --git a/bin/run-groovy b/bin/run-groovy index f6d937d8c..08aafb960 100755 --- a/bin/run-groovy +++ b/bin/run-groovy @@ -50,4 +50,4 @@ echo "*****************************************" echo " " echo " " export JAVA_OPTS="-Dsun.java2d.pmoffscreen=false -Djava.util.logging.config.file=$CLAS12DIR/etc/logging/debug.properties -Xms1024m -Xmx2048m -XX:+UseSerialGC" -groovy -cp "$JYPATH" $* +groovy -cp "$JYPATH" "$@" diff --git a/bin/run-jshell b/bin/run-jshell new file mode 100755 index 000000000..562383da8 --- /dev/null +++ b/bin/run-jshell @@ -0,0 +1,50 @@ +#!/bin/sh + +. `dirname $0`/env.sh + +export CLAS12DIR=`dirname $0`/.. + +#-------------------------------------------------------------- +# Adding supporting COAT jar files +for i in `ls -a $CLAS12DIR/lib/clas/*.jar` +do +#echo "$i" +if [ -z "${JYPATH}" ] ; then +JYPATH="$i" +else +JYPATH=${JYPATH}:"$i" +fi +done +#-------------------------------------------------------------- +# Adding supporting plugins directory +for i in `ls -a $CLAS12DIR/lib/services/*.jar` +do +if [ -z "${JYPATH}" ] ; then +JYPATH="$i" +else +JYPATH=${JYPATH}:"$i" +fi +done +#-------------------------------------------------------------- +# Adding supporting plugins directory +#-------------------------------------------------------------- +# Done loading plugins +#-------------------------------------------------------------- +# Adding supporting plugins directory +for i in `ls -a $CLAS12DIR/lib/utils/*.jar` +do +if [ -z "${JYPATH}" ] ; then +JYPATH="$i" +else +JYPATH=${JYPATH}:"$i" +fi +done +#------------------------------------------------------------- +echo " " +echo " " +echo "*****************************************" +echo "* Running COAT-JAVA JShell Scripts *" +echo "*****************************************" +echo " " +echo " " +jshell --class-path "$JYPATH" "$@" diff --git a/build-coatjava.sh b/build-coatjava.sh index 7356d6c28..9ba7ca377 100755 --- a/build-coatjava.sh +++ b/build-coatjava.sh @@ -92,8 +92,8 @@ cp -r etc coatjava/ which python3 >& /dev/null && python=python3 || python=python $python etc/bankdefs/util/bankSplit.py coatjava/etc/bankdefs/hipo4 || exit 1 mkdir -p coatjava/lib/clas -cp external-dependencies/JEventViewer-1.1.jar coatjava/lib/clas/ -cp external-dependencies/vecmath-1.3.1-2.jar coatjava/lib/clas/ +#cp external-dependencies/JEventViewer-1.1.jar coatjava/lib/clas/ +#cp external-dependencies/vecmath-1.3.1-2.jar coatjava/lib/clas/ mkdir -p coatjava/lib/utils cp external-dependencies/jclara-4.3-SNAPSHOT.jar coatjava/lib/utils #cp external-dependencies/jaw-1.0.jar coatjava/lib/utils diff --git a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/Dictionary.java b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/Dictionary.java index ad433e4f1..e77fdb69d 100644 --- a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/Dictionary.java +++ b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/Dictionary.java @@ -39,11 +39,18 @@ public void printDictionary() { } public void readDictionary(String fileName, TestMode mode, int wireBinning, int stripBinning, int sectorDependence) { + this.readDictionary(fileName, mode, wireBinning, stripBinning, sectorDependence, -1); + } + + public void readDictionary(String fileName, TestMode mode, int wireBinning, int stripBinning, int sectorDependence, int maxRoads) { System.out.println("\nReading dictionary from file " + fileName); + System.out.println("\nMaximum number of roads set to: " + maxRoads); int nFull = 0; int nDupli = 0; + if(maxRoads<0) maxRoads = Integer.MAX_VALUE; + File fileDict = new File(fileName); try { @@ -52,7 +59,7 @@ public void readDictionary(String fileName, TestMode mode, int wireBinning, int ProgressPrintout progress = new ProgressPrintout(); String line = null; - while ((line = txtreader.readLine()) != null) { + while ((line = txtreader.readLine()) != null && maxRoads>nFull) { Road road = new Road(line); road.setBinning(wireBinning, stripBinning, sectorDependence); diff --git a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/DictionaryValidator.java b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/DictionaryValidator.java index 70463b126..98a5c8a82 100644 --- a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/DictionaryValidator.java +++ b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/DictionaryValidator.java @@ -183,9 +183,9 @@ public EmbeddedCanvasTabbed getCanvas() { return canvas; } - public void init(String filename, TestMode mode, int wireBin, int stripBin, int sectorDependence) { + public void init(String filename, TestMode mode, int wireBin, int stripBin, int sectorDependence, int maxRoads) { this.dictionary = new Dictionary(); - this.dictionary.readDictionary(filename, mode, wireBin, stripBin, sectorDependence); + this.dictionary.readDictionary(filename, mode, wireBin, stripBin, sectorDependence, maxRoads); this.createHistos(mode, wireBin, stripBin, sectorDependence); this.plotRoads(); } @@ -313,7 +313,7 @@ public static void main(String[] args) { parser.addOption("-pid" , "0", "select particle PID for new dictionary, 0: no selection,"); parser.addOption("-charge" , "0", "select particle charge for new dictionary, 0: no selection"); parser.addOption("-wire" , "1", "dc wire bin size in road finding"); - parser.addOption("-strip" , "2", "pcal strip bin size in road finding"); + parser.addOption("-strip" , "1", "pcal strip bin size in road finding"); parser.addOption("-sector" , "0", "sector dependent roads, 0=false, 1=true)"); parser.addOption("-smear" , "1", "smearing in wire/paddle/strip matching"); parser.addOption("-mode" , "0", "select test mode, " + TestMode.getOptionsString()); @@ -321,6 +321,7 @@ public static void main(String[] args) { parser.addOption("-vzmin" , "-10", "minimum vz (cm)"); parser.addOption("-vzmax" , "10", "maximum vz (cm)"); parser.addOption("-n" ,"-1", "maximum number of events to process for validation"); + parser.addOption("-r" ,"-1", "maximum number of roads to use for validation"); parser.parse(args); String dictionaryFileName = null; @@ -362,6 +363,7 @@ public static void main(String[] args) { System.exit(1); } int maxEvents = parser.getOption("-n").intValue(); + int maxRoads = parser.getOption("-r").intValue(); double thrs = parser.getOption("-threshold").doubleValue(); double vzmin = parser.getOption("-vzmin").doubleValue(); @@ -381,9 +383,10 @@ public static void main(String[] args) { System.out.println("Smearing for wire/paddle/strip matching set to: " + smear); System.out.println("Test mode set to: " + mode); System.out.println("Maximum number of events to process set to: " + maxEvents); + System.out.println("Maximum number of roads to use set to: " + maxRoads); DictionaryValidator validator = new DictionaryValidator(); - validator.init(dictionaryFileName, mode, wireBin, stripBin, sector); + validator.init(dictionaryFileName, mode, wireBin, stripBin, sector, maxRoads); // tm.printDictionary(); validator.processFile(testFileName,wireBin,stripBin,sector,smear,mode,maxEvents,pid,charge,thrs, vzmin, vzmax); validator.plotHistos(); diff --git a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/Road.java b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/Road.java index 0a79032fd..9cf00ccf2 100644 --- a/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/Road.java +++ b/common-tools/clas-analysis/src/main/java/org/jlab/analysis/roads/Road.java @@ -161,7 +161,7 @@ public static ArrayList getRoads(DataEvent event, int chargeSelect, int pi } } road.setSector((byte) trackSector); - if(road.getLayerHits(3)<3 || road.getSuperLayers()!=6) continue; + // if(road.getSuperLayerHits(3)<3 || road.getSuperLayers()!=6) continue; // now check other detectors // check FTOF if(recScintillator!=null) { @@ -578,11 +578,11 @@ public byte getSector() { return (byte) sec; } - public int getLayerHits(int layer) { + public int getSuperLayerHits(int superlayer) { int n=0; - if(layer>0 && layer<=6) { - for(int isl=0; isl<6; isl++) { - if(this.dcWires[layer-1+isl*6]>0) n++; + if(superlayer>0 && superlayer<=6) { + for(int il=0; il<6; il++) { + if(this.dcWires[(superlayer-1)*6+il]>0) n++; } } return n; @@ -606,7 +606,7 @@ public Particle getParticle() { public double getPhi() { double phi = Math.toDegrees(particle.phi()); - if(sector==0) + if(this.getSector()==0) return (phi+360+30)%60-30; else return phi; @@ -618,18 +618,20 @@ public ArrayList getKey() { public ArrayList getKey(TestMode mode) { ArrayList road = new ArrayList<>(); + for(int i=0; i<13; i++) { + road.add((byte) 0); + } + for(int isl=0; isl<6; isl++) { for(int il=0; il<6; il++) { int layer = isl*6+il+1; if(this.dcWires[layer-1] != 0) { - road.add(this.getWire(layer)); + road.set(isl, this.getWire(layer)); break; } } } - for(int i=6; i<13; i++) { - road.add((byte) 0); - } + if(mode.contains(TestMode.DCPCALU)) { road.set(8, this.getStrip(1)); if(mode.contains(TestMode.DCFTOFPCALU)) { @@ -684,12 +686,13 @@ public List> getKeys(TestMode mode, int width) { }}}}}}}}}}} return keys; } + public final boolean isValid() { return this.isValid(TestMode.DC); } public boolean isValid(TestMode mode) { - boolean value = this.getLayerHits(3)>=3 && this.getSuperLayers()==6; + boolean value = this.getSuperLayerHits(3)>=3 && this.getSuperLayers()==6; if(mode.contains(TestMode.DCPCALU)) { value = value && this.ecalStrips[0]>0; if(mode.contains(TestMode.DCFTOFPCALU)) { diff --git a/common-tools/clas-io/src/main/java/org/jlab/utils/JsonUtils.java b/common-tools/clas-io/src/main/java/org/jlab/utils/JsonUtils.java index 5a961b168..b2a6903ae 100644 --- a/common-tools/clas-io/src/main/java/org/jlab/utils/JsonUtils.java +++ b/common-tools/clas-io/src/main/java/org/jlab/utils/JsonUtils.java @@ -6,10 +6,14 @@ import java.io.OutputStreamWriter; import org.jlab.io.base.DataBank; import org.jlab.io.base.DataEvent; +import org.jlab.jnp.hipo4.data.Bank; +import org.jlab.jnp.hipo4.data.Event; +import org.jlab.jnp.hipo4.io.HipoReader; import org.jlab.jnp.utils.json.JsonArray; import org.jlab.jnp.utils.json.JsonObject; import org.jlab.jnp.utils.json.JsonValue; import org.jlab.jnp.utils.json.PrettyPrint; +import org.jlab.utils.options.OptionParser; import org.json.JSONObject; /** @@ -49,6 +53,15 @@ public static void show(DataBank bank, String varName) { show(read(bank,varName)); } + /** + * Just print it to the screen, nicely. + * @param bank + * @param varName + */ + public static void show(Bank bank, String varName) { + show(read(bank,varName)); + } + /** * Convenience method to get a JsonObject from a bank. * @param bank bank to read @@ -58,6 +71,14 @@ public static void show(DataBank bank, String varName) { public static JsonObject read(DataBank bank, String varName) { return JsonObject.readFrom(new String(bank.getByte(varName))); } + + public static JsonObject read(Bank bank, String varName) { + byte[] x = new byte[bank.getRows()]; + for (int i=0; i 3 && parser.getOption("-i").intValue()!=0) { + System.err.println("\nERROR: Too many parsing errors.\nAre you sure your variable "+bankName+"."+varName+" is a byte array representing a JSON string?"); + System.exit(1); + } + } + } + } + reader.close(); + } + } } diff --git a/reconstruction/cvt/src/main/java/org/jlab/rec/cvt/track/StraightTrack.java b/reconstruction/cvt/src/main/java/org/jlab/rec/cvt/track/StraightTrack.java index 4ef3246cb..98ec32a60 100644 --- a/reconstruction/cvt/src/main/java/org/jlab/rec/cvt/track/StraightTrack.java +++ b/reconstruction/cvt/src/main/java/org/jlab/rec/cvt/track/StraightTrack.java @@ -191,6 +191,7 @@ public void findTrajectory() { stVec.setTrkThetaAtSurface(ThetaTrackIntersPlane); stVec.setTrkToModuleAngle(trkToMPlnAngl); stVec.setCalcCentroidStrip(CalcCentroidStrip); + stVec.setSurfaceDetector(DetectorType.BST.getDetectorId()); if(stateVecs.size()>0 && stateVecs.get(stateVecs.size()-1).x()==stVec.x() && stateVecs.get(stateVecs.size()-1).y()==stVec.y() @@ -230,7 +231,8 @@ public void findTrajectory() { stVec.setTrkThetaAtSurface(ThetaTrackIntersSurf); stVec.setTrkToModuleAngle(trkToMPlnAngl); stVec.setCalcCentroidStrip(CalcCentroidStrip); - if(stateVecs.size()>0 + stVec.setSurfaceDetector(DetectorType.BMT.getDetectorId()); + if(stateVecs.size()>0 && stateVecs.get(stateVecs.size()-1).x()==stVec.x() && stateVecs.get(stateVecs.size()-1).y()==stVec.y() && stateVecs.get(stateVecs.size()-1).z()==stVec.z()) { diff --git a/reconstruction/cvt/src/main/java/org/jlab/rec/cvt/trajectory/TrajectoryFinder.java b/reconstruction/cvt/src/main/java/org/jlab/rec/cvt/trajectory/TrajectoryFinder.java index fe0e4e8a2..0e4fa6d69 100644 --- a/reconstruction/cvt/src/main/java/org/jlab/rec/cvt/trajectory/TrajectoryFinder.java +++ b/reconstruction/cvt/src/main/java/org/jlab/rec/cvt/trajectory/TrajectoryFinder.java @@ -120,6 +120,7 @@ public Trajectory findTrajectory(int id, Ray ray, ArrayList candCrossList continue; } + stVec.setSurfaceDetector(DetectorType.BST.getDetectorId()); Cluster clsOnTrk = null; if (l % 2 == 0) { clsOnTrk = c.getCluster1(); @@ -195,6 +196,7 @@ public Trajectory findTrajectory(int id, Ray ray, ArrayList candCrossList continue; } + stVec.setSurfaceDetector(DetectorType.BMT.getDetectorId()); if (c.getType()==BMTType.C) { //C-detector measuring Z //if(traj.isFinal) { // reset the cross only for final trajectory @@ -226,9 +228,9 @@ public Trajectory findTrajectory(int id, Ray ray, ArrayList candCrossList } //Collections.sort(stateVecs); - stateVecs.sort(Comparator.comparing(StateVec::y)); - for (int l = 0; l < stateVecs.size(); l++) { + for (int l = 0; l < stateVecs.size(); l++) { + stateVecs.get(l).setSurfaceDetector(DetectorType.CVT.getDetectorId()); stateVecs.get(l).setPlaneIdx(l); } traj.setTrajectory(stateVecs); diff --git a/reconstruction/ec/src/main/java/org/jlab/display/ec/ECRECMonitor.java b/reconstruction/ec/src/main/java/org/jlab/display/ec/ECRECMonitor.java new file mode 100644 index 000000000..7d8d8fe68 --- /dev/null +++ b/reconstruction/ec/src/main/java/org/jlab/display/ec/ECRECMonitor.java @@ -0,0 +1,73 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package org.jlab.display.ec; + +import org.jlab.clas.physics.LorentzVector; +import org.jlab.clas.reco.ReconstructionEngine; +import org.jlab.groot.data.H1F; +import org.jlab.groot.ui.TGCanvas; +import org.jlab.io.base.DataBank; +import org.jlab.io.base.DataEvent; + +/** + * + * @author gavalian + */ +public class ECRECMonitor extends ReconstructionEngine { + TGCanvas canvas = null; + H1F pion = null; + + public ECRECMonitor(){ + super("ECMon","gavalian","1.0"); + } + + @Override + public boolean processDataEvent(DataEvent event) { + if(event.hasBank("REC::Particle")==true){ + DataBank bank = event.getBank("REC::Particle"); + int index1 = this.index(bank, 22, 0); + int index2 = this.index(bank, 22, 1); + if(index1>0&&index2>0){ + LorentzVector vL_g1 = this.getVector(bank, index1, 0.0); + LorentzVector vL_g2 = this.getVector(bank, index2, 0.0); + if(vL_g1.p()>1.0&&vL_g2.p()>1.0){ + vL_g1.add(vL_g2); + pion.fill(vL_g1.mass()); + } + } + } + return true; + } + + private LorentzVector getVector(DataBank b, int index, double mass){ + LorentzVector v = new LorentzVector(); + v.setPxPyPzM(b.getFloat("px", index), + b.getFloat("py", index), + b.getFloat("pz", index), + mass); + return v; + } + + private int index(DataBank b, int pid, int skip){ + int nrows = b.rows(); + int skipped = 0; + for(int r = 0; r < nrows; r++){ + int id = b.getInt("pid", r); + if(id==pid){ + if(skipped==skip) return r; + skipped++; + } + } + return -1; + } + @Override + public boolean init() { + canvas = new TGCanvas("c","EC Engine Monitoring",500,500); + canvas.getCanvas().initTimer(5000); + pion = new H1F("pion",120,0.005,0.6); + return true; + } + +} diff --git a/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/ClustersInRecParticle.png b/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/ClustersInRecParticle.png new file mode 100644 index 000000000..e0b956c78 Binary files /dev/null and b/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/ClustersInRecParticle.png differ diff --git a/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/ExampleStatWord.png b/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/ExampleStatWord.png new file mode 100644 index 000000000..3ae46d3b3 Binary files /dev/null and b/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/ExampleStatWord.png differ diff --git a/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/HitsInCluster.png b/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/HitsInCluster.png new file mode 100644 index 000000000..9e9062fff Binary files /dev/null and b/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/HitsInCluster.png differ diff --git a/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/Layer_Bits.png b/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/Layer_Bits.png new file mode 100644 index 000000000..77685bf60 Binary files /dev/null and b/reconstruction/mc/src/main/java/org/jlab/service/mc/Figs/Layer_Bits.png differ diff --git a/reconstruction/mc/src/main/java/org/jlab/service/mc/Readme_TruthMatch.md b/reconstruction/mc/src/main/java/org/jlab/service/mc/Readme_TruthMatch.md new file mode 100644 index 000000000..4678fa01e --- /dev/null +++ b/reconstruction/mc/src/main/java/org/jlab/service/mc/Readme_TruthMatch.md @@ -0,0 +1,257 @@ +#

Truth Matching

+ + + +# Read this first +In order the Truth Matching to work, it is important to invoke certain options when one runs GEMC: +* -SAVE_ALL_MOTHERS=1 +* -SKIPREJECTEDHITS=1 +* -INTEGRATEDRAW="*" +* -NGENP=50 // This is not necessarily needed, if you are sure in LUND file the number of generated particles is always smaller than 10, you can skip this option + +If you are not interested how the matching works, but just want to use it as a black-box, then please run GEMC with above mentioned options, +Below is an example command that will allow the TrutMatching service to work properly. + + gemc det.gcard -SAVE_ALL_MOTHERS=1 -SKIPREJECTEDHITS=1 -NGENP=50 -INTEGRATEDRAW="*" -N=10000 -USE_GUI=0 -INPUT_GEN_FILE="lund, inp_Lund.dat" -RUNNO=11 -OUTPUT="hipo, GEMC_Out.hipo" + + + +# Read this second +Here is a simple snippet of the code that shows for the given recon particle how to find the index of the matched MC particle in the MC::Particle bank. + + int nPart = bRecPart.getRows(); // bRecPart is defined in the code as: hipo::bank bRecPart(factory.getSchema("REC::Particle")); + for (int iPart = 0; iPart < nPart; iPart++) { + + float quality = bRecMatch.getFloat("quality", iPart); // bRecMatch is defined in the code as: hipo::bank bRecMatch(factory.getSchema("MC::RecMatch")); + int mcind = bRecMatch.getInt("mcindex", iPart); + + int charge = bRecPart.getInt("charge", iPart); + int pid = bRecPart.getInt("pid", iPart); + + /* + * Check for a charged track + */ + if (charge != 0 && pid != 0 ) { + // mcind is the index of MC particle in the MC::Particle bank so you can use it to retrieve any variable from the MC::Particle bank + float px_MC_Matched = bMCPart.getFloat("px", mcind); // bMCPart is defined in the code as hipo::bank bMCPart(factory.getSchema("MC::Particle")); + ... + ... + + // If you want very good quality matching you can do + + if( quality > 0.98 ){ + // Do whateever you want + } + } + +The example above should be good for the user to adapt it for their needs without going into details how the matching works, however if you are interested in more details +about the matching algorithm and bank structures, you can read the rest of this document. +## + + +# Introduction +In Monte Carlo (MC) simulations very frequently there is a need to know links between the generated +particle and the reconstructed particle. Users usually compare kinematics (momentum and the angle) of +the generated and reconstructed particles in order to determine if the reconstructed particle is the one +corresponding to the given MC particle. In particular, user requires the difference/ratio of angles/momenta +between reconstructed and MC particles to be within certain limits. Depending on the need of the study, +this might be sufficient, however there are also cases when this approach is not enough. In particular when +the number of generated and reconstructed particles are more than 1-2, one can get significant amount +of non-unique matches. Another downside of this type of matching is that user will always loose some +real corresponding particles, as because of multiple scattering and radiation, these distributions (difference +between MC and reconstructed kinematic variables) have tails extending beyond user specified cuts. +The service **'TruthMatch'** in COATJAVA makes links +between MC and reconstructed particles in a more rigorous way by checking MC and reconstructed hits of +particles from almost all detectors and determining which MC and Recon particle the hit correspond to. + +# The matching algorithm + +## What kind of information the matching provides +The service provides two types (one can call directions too) of matching: \ +In the first type, for each MC::Particle, it points to the entry in the REC::Particle bank, which it thinks is the +**best match** for the given MC particle in the MC::Particle bank.\ +The 2nd type does the opposite, for each reconstructed particle in the REC::Particle bank it points to the +entry in the MC::Particle bank that is the **best matched** to the given reconstructed particle.\ +The service provides also additional **status words** which encode information about what type of detectors (layers of detectors) participated +in the matching of the given particle. \ +Then finally it provides a variable **quality**, which characterizes the reliability of the matching, i.e. +higher the quality higher is the contribution of matched MC particle (or Rec Particle in the other type of matching) to the +given Rec Particle. + +## How the matching is done. + +I would like to start with a very simple example that will help to understand better the +underlying principle of the truth matching. Suppose we have generated an +event with several particles inside the CLAS12 acceptance, then this +event is passed through the GEMC, and then reconstructed with +COATJAVA. Now let say we pick up a random MC hit in the +ECal (the general concept is valid for almost all detectors), and +want to know the initial MC particle that generated the hit, and also want to know +the reconstructed particle that the given hit belongs to. \ +All MC hits are stored in the "MC::True" bank. The variable **otid** +shows the index of the original particle that generated the given hit. +So the first part was quite simple we just need to pick the **otid**-th +particle in the "MC::Particle" bank. Now for the 2nd step, which is to +find the recon particle that the given hit belongs to, we will use +another variable **hitn**, which shows the index of the given hit in the +ADC/TDC bank of the corresponding detector. The path from the ADC bank +to the "REC::Particle" is done through 3 to 4 intermediate banks (the +number of intermediate banks depends on the given detector), however it +is straightforward. First step is to look into "ECAL::hits" bank and +from it pick the hit that has the variable **id** (for some other +detector banks this variable name can differ e.g. **hitID**, **ID**). In +the "ECAL::hits" bank the variable **clusterId** (which also can have +different names in different detectors) will point to the index of the +cluster in the "ECAL::clusters" bank that the given hit belongs to. Then +we should look the "REC::Calorimeter" bank, and chose the row that has +the variable **index** equal to the **clusterId**. Finally the variable +**pindex** in the "REC::Calorimeter" bank will point to the index of the +reconstructed particle in the "REC::Particle" bank. So in this example +picking a random hit we can relate the MC particle to the recon +particle. In reality however the MC particle can leave in the CLAS12 +detector hundreds of hits, and not all MC hits of the given MC particle necessarily +will point to the same recon particle, and wise versa not all ADC/TDC +hits of the given recon particle will necessarily be generated from the same MC +particle. + +From the example above, it is obvious that a single cluster (if it +applies for a given detector) can contain hits originated from more than +one MC particles. + +![Fig:Hits](Figs/HitsInCluster.png) +*An example cluster containing hits from two different MC particles. +Numbers represent the hitID of the hit in the cluster. Hits in cyan +color were originated from one MC particle, and hits in red are +originated from another MC +particle.* + +The figure above shows an example of the cluster with 8 +hits, 2 of them are from one MC particle, let's call it mcp1, and the +other 6 are from another MC particle let's call it mcp2. The truth +matching will associate the given cluster to the MCParticle that has the +most number of hits in it. In particular for the given example the +cluster will be matched to the mcp2. This example of the cluster was an +abstract example which doesn't relate to any specific CLAS12 detector, +however the algorithm is applicable to all CLAS12 detectors, the cluster +will be matched to the MC Particle that has the highest number of hits +in it. With this rule all clusters from all detectors that participate in the truth matching, are collected and the MC Particle is +identified for each of them. + +Now as we already defined the algorithm how to match MC Particle to the +Recon cluster, we can think how to match MC Particle to the Recon +Particle. As the cluster is an object consisting of hits, we can think +of a Recon Particle as an object consisting of clusters which are +related to the Recon particle through the response banks +(e.g. REC::Calorimeter, REC::Scintillator etc). As in the case of the +cluster, it is not necessarily true that all hits of the cluster will be +originated from the same MC Particle, here again, all recon clusters +matched to a given MC Particle will not necessarily be part of the same +recon particle, and wise versa, not all clusters of the given recon +particle will necessarily be originated from the same MC Particle. + +![](Figs/ClustersInRecParticle.png)*An example illustrating a case when two clusters matched to two MC +particles end up in opposite Rec Particles. Cluster marked by red +(orange) rectangle inside the green area, is matched to the MC Particle +1(2), however Event Builder associated it with the Rec Particle +2(1).* + +An abstract example is shown in the figure above, when not all recon clusters matched +to the given MC Particle belong to the same recon particle. The +Truth Matching service in such cases chose the recon particle that has +the highest number of matched clusters to the given MC particle. + +# Bank structures + +The TruthMatch service produces two banks **MC::GenMatch** and **MC::RecMatch**. + +## **MC::GenMatch** +Lets start from the **MC::GenMatch** bank. +The number of entries (columns) in the **MC::GenMatch** is equal to the number of entries in the **MC::Particle** bank. +Below is the snippet from the json file describing the **MC::GenMatch** structure. + + "name": "MC::GenMatch", + "group": 40, + "item" : 6, + "info": "MC::Particle -> REC::Particle matching", + "entries": [ + {"name":"mcindex", "type":"S", "info":"MC::Particle index"}, + {"name":"pindex", "type":"S", "info":"REC::Particle index"}, + {"name":"mclayer1", "type":"L", "info":"layers from the 1st set of detectors hit by MC particle"}, + {"name":"mclayer2", "type":"L", "info":"layers from the 2nd set of detectors hit by MC particle"}, + {"name":"player1", "type":"L", "info":"layers from the 1st set of detectors hit by Recon particle"}, + {"name":"player2", "type":"L", "info":"layers from the 2nd set of detectors hit by Recon particle"}, + {"name":"quality", "type":"F", "info":"matching quality parameter"} + +* The **mcindex** is the index of the MC Particle in the **MC::Particle** bank that we want to match to the Rec particle. +* The **pindex** is the index of the matched REC particle in the **REC::Particle** bank. +* **mclayer1** and **mclayer2** are 64 bit LONGs, where each bit of those words indicates whether the the given MC particle +deposited hit in a specific detector/layer of CLAS12. See section [Status word description](#StatWordDescription) +for details on detector<=>bit correspondence. +* **player1** and **player2** are again 64 bit LONG words, however their bits represent detector/layers of the matched Rec Particle, + but only those layers which are matched to the given MC particle. In the **MC::GenMatch** bank, set bits of **player1(2)** are always + subset of set bits of **mclayer1(2)**. + +## **MC::RecMatch** +The structure of **MC::RecMatch** bank is very similar to **MC::GenMatch** and meanings of variables are +analogous to those from the **MC::GenMatch** bank.. +The number of entries (columns) in the **MC::RecMatch** is equal to the number of entries in the **REC::Particle** bank. +Below is the snippet from the json file describing the **MC::RecMatch** structure. + + "name": "MC::RecMatch", + "group": 40, + "item" : 7, + "info": "Rec::Particle -> MC::Particle matching", + "entries": [ + {"name":"pindex", "type":"S", "info":"REC::Particle index"}, + {"name":"mcindex", "type":"S", "info":"MC::Particle index"}, + {"name":"player1", "type":"L", "info":"layers from the 1st set of detectors hit by Recon particle"}, + {"name":"player2", "type":"L", "info":"layers from the 1st set of detectors hit by Recon particle"}, + {"name":"mclayer1", "type":"L", "info":"layers from the 1st set of detectors hit by MC particle"}, + {"name":"mclayer2", "type":"L", "info":"layers from the 2nd set of detectors hit by MC particle"}, + {"name":"quality", "type":"F", "info":"matching quality parameter"} + +* The **pindex** is the index of the particle in the **REC::Particle** bank that we want to match to MC particle +* The **mcindex** is the index of the MC Particle in the **MC::Particle** bank, that is matched to the pindext-th particle in the REC::Particle bank. +* **player1** and **player2** as in the case of **MC::GenMatch** bank, are two 64 bit LONG words where each bit indicates + presence of the hit of the given REC particle in specific detector bits. +* **mclayer1** and **mclayer2** show which detector/layers the matched MC particle has deposited hits, and here + again those detector/layers are not all detectors/layers the matched MC particle has deposited hits, but only those which + are matched to the given Rec particle, in other words, set bits of **mclayer1(2)** is always subset of set bits of **player1(2)** +* The **quality** takes values from 0 to 1, and is defined based on status words. It is just ab auxiliary variable that allows users to match +particles without the need to decode status words. See section [Description of quality](QualityDescription) for more details + +# Status word description +In [Bank Structures](#BANK_STRUCTURES) it is mentioned that in addition to the index of the matched particle, +bank provides also status words, which encode list of detector layers the given MC (or Rec) particle deposited hits into. +![](Figs/Layer_Bits.png)*Representation of status words. Fields in Orange are not implemented yet.* + +The figure above describes the mapping between word/bitnumber and detector/layer. Detector acronyms should be +well known for anyone familiar with CLAS12 detector, except "FTH" which represents Forward tagger Hodoscope, and because +of space constrains is named "FTH". + +In the figure below shown the decoding of an example status word. +![](Figs/ExampleStatWord.png)*An example of a status word, showing that the given particle deposited hits in all DC layers except 15, 19, 20 and 29. +Then it deposited hits in first four layers of BST, and in BMT it hit layers 1, 2 and 6* + +# Description of quality +As it was already mentioned in the "Bank structures" section, both Matching banks **MC::GenMatch** and **MC::RecMatch** have a variable named **quality**. +It is an auxiliary variable which in many cases might be useful for users to cut on this variable rather than doing complex checks on the status words. +Below are described what values the **quality** takes for charged tracks, neutron/antineutron, and photons. \ +### Charged particles +The quality for charged particles is 0, 0.95 or 0.98. +* **0.95** In this case the + * if the charged recon track is in the FD: then it should have at least 5 superlayers, where in each of 5 superlayers at least 4 hits + * if the charged recon track is in CVT: then recon particle should have at least one **Z** cluster and two SVT crosses, **OR** at least two **Z** clusters and one **C** cluster and one SVT cross. +* **0.98** This cases are subset of **0.95** in a sense that the same requirements are also imposed to the matched MC particles as well, or matched REC::Particle (in case of **MC::GenMatch**) + +### Neutron or antineutron +The quality takes values 0.91 or 0.92 +* **0.91** In this case the neutral particle deposits a hit in any layer of EC (includes PCal, EC_in and EC_Out), CND or CTOF +* **0.92** Those are subset of **0.91** cases, when the matched particle deposits hit in any of EC, CND or CTOF layers. +### Photons +The quality for photons are 0.93 or 0.94 +* **0.93** In this case the photon should have deposited hit in PCal **OR** any of CND layers or in CTOF +* **0.94** Thise are subset of 0.93, when the matched particle has deposited hit in PCal **OR** any of CND layers or in CTOF +## +Later based on the feedback of users, some additional values can be implemented for the quality, and/or it's definition can be changed. + \ No newline at end of file