diff --git a/etc/bankdefs/hipo4/alert.json b/etc/bankdefs/hipo4/alert.json index 7c125eb9cc..5701d1ac61 100644 --- a/etc/bankdefs/hipo4/alert.json +++ b/etc/bankdefs/hipo4/alert.json @@ -1,182 +1,322 @@ [ - { - "name": "AHDC::Hits", - "group": 23000, - "item": 23, - "info": "Raw Hits", - "entries": [ - { - "name": "ID", - "type": "S", - "info": "hit id" - }, { - "name": "layer", - "type": "B", - "info": "layer number" - }, { - "name": "superlayer", - "type": "B", - "info": "superlayer number" - }, { - "name": "wire", - "type": "I", - "info": "wire number" - }, { - "name": "Doca", - "type": "D", - "info": "distance od closest approch (mm)" - } - ] - }, { - "name": "AHDC::PreClusters", - "group": 23000, - "item": 24, - "info": "Pre Clusters info", - "entries": [ - { - "name": "X", - "type": "F", - "info": "X info (mm)" - }, { - "name": "Y", - "type": "F", - "info": "Y info (mm)" - } - ] -}, { - "name": "AHDC::Clusters", - "group": 23000, - "item": 25, - "info": "Clusters info", - "entries": [ - { - "name": "X", - "type": "F", - "info": "X info (mm)" - }, { - "name": "Y", - "type": "F", - "info": "Y info (mm)" - }, { - "name": "Z", - "type": "F", - "info": "Z info (mm)" - } - ] -}, { - "name": "AHDC::Track", - "group": 23000, - "item": 21, - "info": "Reco Tracks", - "entries": [ - { - "name": "x", - "type": "F", - "info": "x position in mm" - }, { - "name": "y", - "type": "F", - "info": "y position in mm" - }, { - "name": "z", - "type": "F", - "info": "z position in mm" - }, { - "name": "px", - "type": "F", - "info": "px in MeV" - }, { - "name": "py", - "type": "F", - "info": "py in MeV" - }, { - "name": "pz", - "type": "F", - "info": "pz in MeV" - } - ] -}, { - "name": "AHDC::KFTrack", - "group": 23000, - "item": 26, - "info": "Reco Kalman Filter Tracks", - "entries": [ - { - "name": "x", - "type": "F", - "info": "x position in mm" - }, { - "name": "y", - "type": "F", - "info": "y position in mm" - }, { - "name": "z", - "type": "F", - "info": "z position in mm" - }, { - "name": "px", - "type": "F", - "info": "px in MeV" - }, { - "name": "py", - "type": "F", - "info": "py in MeV" - }, { - "name": "pz", - "type": "F", - "info": "pz in MeV" - } - ] -}, { - "name": "AHDC::MC", - "group": 23000, - "item": 22, - "info": "MC Tracks", - "entries": [ - { - "name": "x", - "type": "F", - "info": "x position in mm" - }, { - "name": "y", - "type": "F", - "info": "y position in mm" - }, { - "name": "z", - "type": "F", - "info": "z position in mm" - }, { - "name": "px", - "type": "F", - "info": "px in MeV" - }, { - "name": "py", - "type": "F", - "info": "py in MeV" - }, { - "name": "pz", - "type": "F", - "info": "pz in MeV" - } - ] -}, - { - "name": "AHDC_AI::Prediction", - "group": 23000, - "item": 30, - "info": "Prediction given by AI", - "entries": [ - {"name": "X1", "type": "F", "info": "X1 position of the 1th superprecluster (mm)"}, - {"name": "Y1", "type": "F", "info": "Y1 position of the 1th superprecluster (mm)"}, - {"name": "X2", "type": "F", "info": "X2 position of the 2nd superprecluster (mm)"}, - {"name": "Y2", "type": "F", "info": "Y2 position of the 2nd superprecluster (mm)"}, - {"name": "X3", "type": "F", "info": "X3 position of the 3rd superprecluster (mm)"}, - {"name": "Y3", "type": "F", "info": "Y3 position of the 3rd superprecluster (mm)"}, - {"name": "X4", "type": "F", "info": "X4 position of the 4th superprecluster (mm)"}, - {"name": "Y4", "type": "F", "info": "Y4 position of the 4th superprecluster (mm)"}, - {"name": "X5", "type": "F", "info": "X5 position of the 5th superprecluster (mm)"}, - {"name": "Y5", "type": "F", "info": "Y5 position of the 5th superprecluster (mm)"}, - {"name": "Pred", "type": "F", "info": "Prediction of the model: 0 mean bad track; 1 mean good track"} - ] - } + { + "name": "ALERT::Projections", + "group": 23000, + "item": 31, + "info": "Track Projections to ATOF", + "entries": [ + { + "name": "x_at_bar", + "type": "F", + "info": "x position at atof bar (middle surface) in mm" + }, { + "name": "y_at_bar", + "type": "F", + "info": "y position at atof bar (middle surface) in mm" + }, { + "name": "z_at_bar", + "type": "F", + "info": "z position at atof bar (middle surface) in mm" + },{ + "name": "L_at_bar", + "type": "F", + "info": "path length at atof bar (inner surface) in mm" + },{ + "name": "L_in_bar", + "type": "F", + "info": "path length inside atof bar in mm" + },{ + "name": "x_at_wedge", + "type": "F", + "info": "x position at atof wedge (middle surface) in mm" + }, { + "name": "y_at_wedge", + "type": "F", + "info": "y position at atof wedge (middle surface) in mm" + }, { + "name": "z_at_wedge", + "type": "F", + "info": "z position at atof wedge (middle surface) in mm" + },{ + "name": "L_at_wedge", + "type": "F", + "info": "path length at atof wedge (inner surface) in mm" + },{ + "name": "L_in_wedge", + "type": "F", + "info": "path length inside atof wedge in mm" + } + ] + },{ + "name": "ATOF::hits", + "group": 22500, + "item": 21, + "info": "Reconstructed ATOF hits", + "entries": [ + { + "name": "id", + "type": "S", + "info": "hit id" + }, { + "name": "sector", + "type": "I", + "info": "atof sector" + }, { + "name": "layer", + "type": "I", + "info": "atof layer" + },{ + "name": "component", + "type": "I", + "info": "atof component" + },{ + "name": "time", + "type": "F", + "info": "time in ns" + },{ + "name": "x", + "type": "F", + "info": "x position in mm" + }, { + "name": "y", + "type": "F", + "info": "y position in mm" + }, { + "name": "z", + "type": "F", + "info": "z position in mm" + },{ + "name": "energy", + "type": "F", + "info": "deposited energy in MeV" + } + ] + },{ + "name": "ATOF::clusters", + "group": 22500, + "item": 22, + "info": "Clusters in ATOF", + "entries": [ + { + "name": "id", + "type": "S", + "info": "hit id" + }, { + "name": "N_bar", + "type": "I", + "info": "number of hits from the bars" + }, { + "name": "N_wedge", + "type": "I", + "info": "number of hits from the wedges" + },{ + "name": "time", + "type": "F", + "info": "time in ns" + },{ + "name": "x", + "type": "F", + "info": "x position in mm" + }, { + "name": "y", + "type": "F", + "info": "y position in mm" + }, { + "name": "z", + "type": "F", + "info": "z position in mm" + },{ + "name": "energy", + "type": "F", + "info": "energy in MeV" + },{ + "name": "pathlength", + "type": "F", + "info": "path length to the cluster in mm" + },{ + "name": "inpathlength", + "type": "F", + "info": "path length inside the detector in mm" + } + ] + },{ + "name": "AHDC::Hits", + "group": 23000, + "item": 23, + "info": "Raw Hits", + "entries": [ + { + "name": "ID", + "type": "S", + "info": "hit id" + }, { + "name": "layer", + "type": "B", + "info": "layer number" + }, { + "name": "superlayer", + "type": "B", + "info": "superlayer number" + }, { + "name": "wire", + "type": "I", + "info": "wire number" + }, { + "name": "Doca", + "type": "D", + "info": "distance od closest approch (mm)" + } + ] + }, { + "name": "AHDC::PreClusters", + "group": 23000, + "item": 24, + "info": "Pre Clusters info", + "entries": [ + { + "name": "X", + "type": "F", + "info": "X info (mm)" + }, { + "name": "Y", + "type": "F", + "info": "Y info (mm)" + } + ] + }, { + "name": "AHDC::Clusters", + "group": 23000, + "item": 25, + "info": "Clusters info", + "entries": [ + { + "name": "X", + "type": "F", + "info": "X info (mm)" + }, { + "name": "Y", + "type": "F", + "info": "Y info (mm)" + }, { + "name": "Z", + "type": "F", + "info": "Z info (mm)" + } + ] + }, { + "name": "AHDC::Track", + "group": 23000, + "item": 21, + "info": "Reco Tracks", + "entries": [ + { + "name": "x", + "type": "F", + "info": "x position in mm" + }, { + "name": "y", + "type": "F", + "info": "y position in mm" + }, { + "name": "z", + "type": "F", + "info": "z position in mm" + }, { + "name": "px", + "type": "F", + "info": "px in MeV" + }, { + "name": "py", + "type": "F", + "info": "py in MeV" + }, { + "name": "pz", + "type": "F", + "info": "pz in MeV" + } + ] + }, { + "name": "AHDC::KFTrack", + "group": 23000, + "item": 26, + "info": "Reco Kalman Filter Tracks", + "entries": [ + { + "name": "x", + "type": "F", + "info": "x position in mm" + }, { + "name": "y", + "type": "F", + "info": "y position in mm" + }, { + "name": "z", + "type": "F", + "info": "z position in mm" + }, { + "name": "px", + "type": "F", + "info": "px in MeV" + }, { + "name": "py", + "type": "F", + "info": "py in MeV" + }, { + "name": "pz", + "type": "F", + "info": "pz in MeV" + } + ] + }, { + "name": "AHDC::MC", + "group": 23000, + "item": 22, + "info": "MC Tracks", + "entries": [ + { + "name": "x", + "type": "F", + "info": "x position in mm" + }, { + "name": "y", + "type": "F", + "info": "y position in mm" + }, { + "name": "z", + "type": "F", + "info": "z position in mm" + }, { + "name": "px", + "type": "F", + "info": "px in MeV" + }, { + "name": "py", + "type": "F", + "info": "py in MeV" + }, { + "name": "pz", + "type": "F", + "info": "pz in MeV" + } + ] + }, + { + "name": "AHDC_AI::Prediction", + "group": 23000, + "item": 30, + "info": "Prediction given by AI", + "entries": [ + {"name": "X1", "type": "F", "info": "X1 position of the 1th superprecluster (mm)"}, + {"name": "Y1", "type": "F", "info": "Y1 position of the 1th superprecluster (mm)"}, + {"name": "X2", "type": "F", "info": "X2 position of the 2nd superprecluster (mm)"}, + {"name": "Y2", "type": "F", "info": "Y2 position of the 2nd superprecluster (mm)"}, + {"name": "X3", "type": "F", "info": "X3 position of the 3rd superprecluster (mm)"}, + {"name": "Y3", "type": "F", "info": "Y3 position of the 3rd superprecluster (mm)"}, + {"name": "X4", "type": "F", "info": "X4 position of the 4th superprecluster (mm)"}, + {"name": "Y4", "type": "F", "info": "Y4 position of the 4th superprecluster (mm)"}, + {"name": "X5", "type": "F", "info": "X5 position of the 5th superprecluster (mm)"}, + {"name": "Y5", "type": "F", "info": "Y5 position of the 5th superprecluster (mm)"}, + {"name": "Pred", "type": "F", "info": "Prediction of the model: 0 mean bad track; 1 mean good track"} + ] + } ] diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/banks/RecoBankWriter.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/banks/RecoBankWriter.java new file mode 100644 index 0000000000..b619956f7e --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/banks/RecoBankWriter.java @@ -0,0 +1,187 @@ +package org.jlab.rec.atof.banks; + +import java.util.ArrayList; +import org.jlab.io.base.DataBank; +import org.jlab.io.base.DataEvent; +import org.jlab.rec.atof.cluster.ATOFCluster; +import org.jlab.rec.atof.hit.ATOFHit; +import org.jlab.rec.atof.hit.BarHit; +import org.jlab.rec.atof.trackMatch.TrackProjection; + +/** + * The {@code RecoBankWriter} writes the banks needed for the atof + * reconstruction: track projections, hits and clusters info. + * + * @author pilleux + */ +public class RecoBankWriter { + + /** + * Writes the bank of atof hits. + * + * @param event the {@link DataEvent} in which to add the bank + * @param wedgeHits the {@link ArrayList} of {@link ATOFHit} containing the + * wedge hits to be added to the bank + * @param barHits the {@link ArrayList} of {@link BarHit} containing the bar + * hits to be added to the bank + * + * @return {@link DataBank} the bank with all the hits read in the event. + * + */ + public static DataBank fillATOFHitBank(DataEvent event, ArrayList wedgeHits, ArrayList barHits) { + + ArrayList hitList = new ArrayList<>(); + hitList.addAll(wedgeHits); + hitList.addAll(barHits); + + DataBank bank = event.createBank("ATOF::hits", hitList.size()); + + if (bank == null) { + System.err.println("COULD NOT CREATE A ATOF::hits BANK!!!!!!"); + return null; + } + + for (int i = 0; i < hitList.size(); i++) { + bank.setShort("id", i, (short) (i + 1)); + bank.setInt("sector", i, (int) hitList.get(i).getSector()); + bank.setInt("layer", i, (int) hitList.get(i).getLayer()); + bank.setInt("component", i, (int) hitList.get(i).getComponent()); + bank.setFloat("time", i, (float) hitList.get(i).getTime()); + bank.setFloat("x", i, (float) (hitList.get(i).getX())); + bank.setFloat("y", i, (float) (hitList.get(i).getY())); + bank.setFloat("z", i, (float) (hitList.get(i).getZ())); + bank.setFloat("energy", i, (float) hitList.get(i).getEnergy()); + } + return bank; + } + + /** + * Writes the bank of atof clusters. + * + * @param event the {@link DataEvent} in which to add the bank + * @param clusterList the {@link ArrayList} of {@link ATOFCluster} + * containing the clusters info to be added to the bank + * + * @return {@link DataBank} the bank with all the clusters built in the + * event. + * + */ + public static DataBank fillATOFClusterBank(DataEvent event, ArrayList clusterList) { + + DataBank bank = event.createBank("ATOF::clusters", clusterList.size()); + + if (bank == null) { + System.err.println("COULD NOT CREATE A ATOF::clusters BANK!!!!!!"); + return null; + } + + for (int i = 0; i < clusterList.size(); i++) { + bank.setShort("id", i, (short) (i + 1)); + bank.setInt("N_bar", i, (int) clusterList.get(i).getBarHits().size()); + bank.setInt("N_wedge", i, (int) clusterList.get(i).getWedgeHits().size()); + bank.setFloat("time", i, (float) clusterList.get(i).getTime()); + bank.setFloat("x", i, (float) (clusterList.get(i).getX())); + bank.setFloat("y", i, (float) (clusterList.get(i).getY())); + bank.setFloat("z", i, (float) (clusterList.get(i).getZ())); + bank.setFloat("energy", i, (float) clusterList.get(i).getEnergy()); + } + return bank; + } + + /** + * Writes the bank of track projections. + * + * @param event the {@link DataEvent} in which to add the bank + * @param projections the {@link ArrayList} of {@link TrackProjection} + * containing the track projection info to be added to the bank + * + * @return {@link DataBank} the bank with all the projected tracks in the + * event. + * + */ + public static DataBank fillProjectionsBank(DataEvent event, ArrayList projections) { + + DataBank bank = event.createBank("ALERT::Projections", projections.size()); + + if (bank == null) { + System.err.println("COULD NOT CREATE A ALERT::Projections BANK!!!!!!"); + return null; + } + + for (int i = 0; i < projections.size(); i++) { + TrackProjection projection = projections.get(i); + bank.setFloat("x_at_bar", i, (float) projection.getBarIntersect().x()); + bank.setFloat("y_at_bar", i, (float) projection.getBarIntersect().y()); + bank.setFloat("z_at_bar", i, (float) projection.getBarIntersect().z()); + bank.setFloat("L_at_bar", i, (float) projection.getBarPathLength()); + bank.setFloat("L_in_bar", i, (float) projection.getBarInPathLength()); + bank.setFloat("x_at_wedge", i, (float) projection.getWedgeIntersect().x()); + bank.setFloat("y_at_wedge", i, (float) projection.getWedgeIntersect().y()); + bank.setFloat("z_at_wedge", i, (float) projection.getWedgeIntersect().z()); + bank.setFloat("L_at_wedge", i, (float) projection.getWedgePathLength()); + bank.setFloat("L_in_wedge", i, (float) projection.getWedgeInPathLength()); + } + return bank; + } + + /** + * Appends the atof banks to an event. + * + * @param event the {@link DataEvent} in which to append the banks + * @param clusterList the {@link ArrayList} of {@link ATOFCluster} + * containing the clusters info to be added to the bank + * @param wedgeHits the {@link ArrayList} of {@link ATOFHit} containing the + * wedge hits info to be added + * @param barHits the {@link ArrayList} of {@link BarHit} containing the bar + * hits info to be added + * + * @return 0 if it worked, 1 if it failed + * + */ + public int appendATOFBanks(DataEvent event, ArrayList wedgeHits, ArrayList barHits, ArrayList clusterList) { + + DataBank hitbank = this.fillATOFHitBank(event, wedgeHits, barHits); + if (hitbank != null) { + event.appendBank(hitbank); + } else { + return 1; + } + + DataBank clusterbank = fillATOFClusterBank(event, clusterList); + if (clusterbank != null) { + event.appendBank(clusterbank); + } else { + return 1; + } + + return 0; + } + + /** + * Appends the alert match banks to an event. + * + * @param event the {@link DataEvent} in which to append the banks + * @param projections the {@link ArrayList} of {@link TrackProjection} containing the + * track projections info to be added + * + * @return 0 if it worked, 1 if it failed + * + */ + public int appendMatchBanks(DataEvent event, ArrayList projections) { + + DataBank projbank = this.fillProjectionsBank(event, projections); + if (projbank != null) { + event.appendBank(projbank); + } else { + return 1; + } + return 0; + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + } + +} diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/cluster/ATOFCluster.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/cluster/ATOFCluster.java new file mode 100644 index 0000000000..8f050bf7eb --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/cluster/ATOFCluster.java @@ -0,0 +1,308 @@ +package org.jlab.rec.atof.cluster; + +import java.util.ArrayList; +import org.jlab.geom.prim.Point3D; +import org.jlab.io.base.DataBank; +import org.jlab.io.base.DataEvent; +import org.jlab.rec.atof.constants.Parameters; +import org.jlab.rec.atof.hit.ATOFHit; +import org.jlab.rec.atof.hit.BarHit; + +/** + * The {@code ATOFCluster} represents clusters in the atof + * + *

+ * Create clusters and compute their basic properties from the hits composing + * them. + *

+ * + * @author pilleux + */ +public class ATOFCluster { + + /** + * list of hits in the bars. + */ + ArrayList barHits; + /** + * list of hits in the wedges. + */ + ArrayList wedgeHits; + /** + * cluster properties:position [cm], time [ns], energy[MeV], path length + * [cm] and length through the atof [cm], type of the maximum hit (to set + * resolutions). + */ + double x, y, z, time, energy; + double pathLength, inPathLength; + String typeMaxHit; + + public ArrayList getBarHits() { + return barHits; + } + + public void setBarHits(ArrayList bar_hits) { + this.barHits = bar_hits; + } + + public ArrayList getWedgeHits() { + return wedgeHits; + } + + public void setWedgeHits(ArrayList wedge_hits) { + this.wedgeHits = wedge_hits; + } + + public double getX() { + return x; + } + + public void setX(double x) { + this.x = x; + } + + public double getY() { + return y; + } + + public void setY(double y) { + this.y = y; + } + + public double getZ() { + return z; + } + + public void setZ(double z) { + this.z = z; + } + + public double getTime() { + return time; + } + + public void setTime(double time) { + this.time = time; + } + + public double getEnergy() { + return energy; + } + + public void setEnergy(double energy) { + this.energy = energy; + } + + public double getPathLength() { + return pathLength; + } + + public void setPathLength(double pathLength) { + this.pathLength = pathLength; + } + + public double getInPathLength() { + return inPathLength; + } + + public void setInPathLength(double inPathLength) { + this.inPathLength = inPathLength; + } + + public String getTypeMaxHit() { + return typeMaxHit; + } + + public void setTypeMaxHit(String typeMaxHit) { + this.typeMaxHit = typeMaxHit; + } + + /** + * Compute the cluster properties. + * + * Cluster coordinates and time are defined as the coordinates and time of + * the max energy hit. + * + * TO DO: Test other choices for the definitions. + * + */ + public final void computeClusterProperties() { + this.energy = 0; + double max_energy = -1; + ATOFHit max_energy_hit = new ATOFHit(); + + for (int i_wedge = 0; i_wedge < this.wedgeHits.size(); i_wedge++) { + ATOFHit this_wedge_hit = this.wedgeHits.get(i_wedge); + double this_energy = this_wedge_hit.getEnergy(); + this.energy += this_energy; + if (this_energy > max_energy) { + max_energy_hit = this_wedge_hit; + max_energy = this_energy; + } + } + + for (int i_bar = 0; i_bar < this.barHits.size(); i_bar++) { + BarHit this_bar_hit = this.barHits.get(i_bar); + double this_energy = this_bar_hit.getEnergy(); + this.energy += this_energy; + if (this_energy > max_energy) { + max_energy_hit = this_bar_hit; + max_energy = this_energy; + } + } + + this.time = max_energy_hit.getTime(); + this.x = max_energy_hit.getX(); + this.y = max_energy_hit.getY(); + this.z = max_energy_hit.getZ(); + this.typeMaxHit = max_energy_hit.getType(); + } + + /** + * Matches the current track with ahdc tracks projections that have been written to the banks. + * Calculates the match by comparing the hit's azimuthal angle and longitudinal position + * (z) with the track projection. If a match is found within defined + * tolerances for phi and z, the path length of the matched hit is updated. + * + * @param event a @link{DataEvent} in which the track projections bank has been written. + * + */ + public int matchTrack(DataEvent event) { + String track_bank_name = "ALERT::Projections"; + if (event == null) { // check if there is an event + //System.out.print(" no event \n"); + return 1; + } else if (event.hasBank(track_bank_name) == false) { + // check if there are ahdc tracks in the event + //System.out.print("no tracks \n"); + return 1; + } else { + DataBank track_bank = event.getBank(track_bank_name); + int nt = track_bank.rows(); // number of tracks + double sigma_phi = 0; + double sigma_z = 0; + + //Looping through all tracks + for (int i = 0; i < nt; i++) { + Float xt = null, yt = null, zt = null, path = null, inpath = null; + if (null == this.getTypeMaxHit()) { + System.out.print("Impossible to match track and hit; hit type is null \n"); + } else { + switch (this.getTypeMaxHit()) { + case "wedge" -> { + sigma_phi = Parameters.SIGMA_PHI_TRACK_MATCHING_WEDGE; + sigma_z = Parameters.SIGMA_Z_TRACK_MATCHING_WEDGE; + xt = track_bank.getFloat("x_at_wedge", i); + yt = track_bank.getFloat("y_at_wedge", i); + zt = track_bank.getFloat("z_at_wedge", i); + path = track_bank.getFloat("L_at_wedge", i); + //A wedge hit traveled through the whole bar and then through a portion of the wedge + inpath = track_bank.getFloat("L_in_wedge", i) + track_bank.getFloat("L_at_wedge", i) - track_bank.getFloat("L_at_bar", i); + } + case "bar" -> { + sigma_phi = Parameters.SIGMA_PHI_TRACK_MATCHING_BAR; + sigma_z = Parameters.SIGMA_Z_TRACK_MATCHING_BAR; + xt = track_bank.getFloat("x_at_bar", i); + yt = track_bank.getFloat("y_at_bar", i); + zt = track_bank.getFloat("z_at_bar", i); + path = track_bank.getFloat("L_at_bar", i); + inpath = track_bank.getFloat("L_in_bar", i); + } + case "bar up", "bar down" -> { + System.out.print("Impossible to match track and hit; hit type is a single up or down bar hit. \n"); + } + default -> + System.out.print("Impossible to match track and hit; hit type is undefined \n"); + } + } + Point3D projection_point = new Point3D(xt, yt, zt); + double delta_phi = Math.abs(this.getPhi() - projection_point.toVector3D().phi()); + if(delta_phi > Math.PI) delta_phi = Math.PI - delta_phi; + if (delta_phi < sigma_phi) { + if (Math.abs(this.getZ() - projection_point.z()) < sigma_z) { + this.setPathLength(path); + this.setInPathLength(inpath); + } + } + } + } + return 0; + } + + public double getEdepWedge() { + double energy = 0; + for (int i = 0; i < this.wedgeHits.size(); i++) { + ATOFHit this_hit = this.wedgeHits.get(i); + energy += this_hit.getEnergy(); + } + return energy; + } + + public double getEdepBar() { + double energy = 0; + for (int i = 0; i < this.barHits.size(); i++) { + ATOFHit this_hit = this.barHits.get(i); + energy += this_hit.getEnergy(); + } + return energy; + } + + /** + * Compute the cluster phi angle in radians. + * + * @return a double that is angle in radians + * + */ + public double getPhi() { + return Math.atan2(this.y, this.x); + } + + /** + * Compute the cluster beta from the path length and time. + * + * @return a double that is beta + * + * - TO DO: Change to non-hardcoded value for c + * + */ + public double getBeta() { + //Need to change to non hardcoded value + return (this.pathLength / this.time) / (2.9979 * Math.pow(10, 2)); + } + + /** + * Constructor that initializes the list of bar hits and list of wedge hits + * and computes the cluster properties. + * + * @param bar_hits a {@link ArrayList} of {@link BarHit}. + * @param wedge_hits a {@link ArrayList} of {@link ATOFHit}. + * + */ + public ATOFCluster(ArrayList bar_hits, ArrayList wedge_hits) { + this.barHits = bar_hits; + this.wedgeHits = wedge_hits; + this.computeClusterProperties(); + } + + /** + * Constructor that initializes the list of bar hits and list of wedge hits + * and computes the cluster properties. + * + * @param bar_hits a {@link ArrayList} of {@link BarHit}. + * @param wedge_hits a {@link ArrayList} of {@link ATOFHit}. + * + */ + public ATOFCluster(ArrayList bar_hits, ArrayList wedge_hits, DataEvent event) { + this.barHits = bar_hits; + this.wedgeHits = wedge_hits; + this.computeClusterProperties(); + this.matchTrack(event); + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + } + +} diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/cluster/ClusterFinder.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/cluster/ClusterFinder.java new file mode 100644 index 0000000000..19cabb1f3d --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/cluster/ClusterFinder.java @@ -0,0 +1,208 @@ +package org.jlab.rec.atof.cluster; + +import java.util.ArrayList; +import org.jlab.io.base.DataEvent; +import org.jlab.rec.atof.constants.Parameters; +import org.jlab.rec.atof.hit.ATOFHit; +import org.jlab.rec.atof.hit.BarHit; +import org.jlab.rec.atof.hit.HitFinder; + +/** + * The {@code ClusterFinder} class builds clusters in the atof + * + *

+ * Uses found hits information. + * Creates a {@link ATOFCluster} matching them. + *

+ * + * @author pilleux + */ +public class ClusterFinder { + + /** + * list of clusters. + */ + private ArrayList clusters; + + /** + * Sets the list of clusters. + * + * @param clusters a {@link ArrayList} of {@link ATOFCluster}. + * + */ + public void setClusters(ArrayList clusters) { + this.clusters = clusters; + } + + /** + * Gets the list of clusters. + * + * @return a {@link ArrayList} of {@link ATOFCluster}. + * + */ + public ArrayList getClusters() { + return clusters; + } + + /** + * Builds clusters in the {@link DateEvent} using hits found and + * stored in a {@link HitFinder}. + * + * @param event the {@link DataEvent} containing the clusters to be built + * + * @param hitfinder the {@link HitFinder} containing the hits that were found + * + */ + public void makeClusters(DataEvent event, HitFinder hitfinder) { + + //A list of clusters is built for each event + clusters.clear(); + + //Getting the list of hits, they must have been ordered by energy already + ArrayList wedge_hits = hitfinder.getWedgeHits(); + ArrayList bar_hits = hitfinder.getBarHits(); + + //Looping through wedge hits first + for (int i_wedge = 0; i_wedge < wedge_hits.size(); i_wedge++) { + ATOFHit this_wedge_hit = wedge_hits.get(i_wedge); + //Make a cluster for each wedge hit that has not been previously clustered + if (this_wedge_hit.getIsInACluster()) { + continue; + } + + //Holding onto the hits composing the cluster + ArrayList this_cluster_wedge_hits = new ArrayList<>(); + ArrayList this_cluster_bar_hits = new ArrayList<>(); + + //Indicate that this hit now is in a cluster + this_wedge_hit.setIsInACluster(true); + //And store it + this_cluster_wedge_hits.add(this_wedge_hit); + + //Check if other wedge hits should be clustered with the current one + //Start from the index of the current one and look at less energetic hits + for (int j_wedge = i_wedge + 1; j_wedge < wedge_hits.size(); j_wedge++) { + ATOFHit other_wedge_hit = wedge_hits.get(j_wedge); + //If that other hit is already involved in a cluster, skip it + if (other_wedge_hit.getIsInACluster()) { + continue; + } + //Check the distance between the hits + //For now we use phi module and z component differences from what is observed in simu + int delta_module = Math.abs(this_wedge_hit.computeModuleIndex() - other_wedge_hit.computeModuleIndex()); + if (delta_module > 30) { + delta_module = 60 - delta_module; + } + int delta_component = Math.abs(this_wedge_hit.getComponent() - other_wedge_hit.getComponent()); + //Later we could use z and phi threshold + //double delta_Phi = Math.abs(this_wedge_hit.getPhi() - other_wedge_hit.getPhi()); + //double delta_Z = Math.abs(this_wedge_hit.getZ() - other_wedge_hit.getZ()); + //Time matching + double delta_T = Math.abs(this_wedge_hit.getTime() - other_wedge_hit.getTime()); + + if (delta_module <= Parameters.SIGMA_MODULE_CLUSTERING) { + if (delta_component <= Parameters.SIGMA_COMPONENT_CLUSTERING)//delta_Z <= sigma_Z) + { + if (delta_T < Parameters.SIGMA_T_CLUSTERING) { + other_wedge_hit.setIsInACluster(true); + this_cluster_wedge_hits.add(other_wedge_hit); + } + } + } + } + + //After clustering wedge hits, check if bar hits should be clustered with them + for (int j_bar = 0; j_bar < bar_hits.size(); j_bar++) { + BarHit other_bar_hit = bar_hits.get(j_bar); + //Skip already clustered hits + if (other_bar_hit.getIsInACluster()) { + continue; + } + //Check the distance between the hits + //For now we use phi module difference from what is observed in simu + int delta_module = Math.abs(this_wedge_hit.computeModuleIndex() - other_bar_hit.computeModuleIndex()); + if (delta_module > 30) { + delta_module = 60 - delta_module; + } + //Later we could use phi threshold + //double delta_Phi = Math.abs(this_wedge_hit.getPhi() - other_wedge_hit.getPhi()); + double delta_Z = Math.abs(this_wedge_hit.getZ() - other_bar_hit.getZ()); + //Time matching + double delta_T = Math.abs(this_wedge_hit.getTime() - other_bar_hit.getTime()); + if (delta_module <= Parameters.SIGMA_MODULE_CLUSTERING) { + if (delta_Z < Parameters.SIGMA_Z_CLUSTERING) { + if (delta_T < Parameters.SIGMA_T_CLUSTERING) { + other_bar_hit.setIsInACluster(true); + this_cluster_bar_hits.add(other_bar_hit); + } + } + } + }//End loop bar hits + + //After all wedge and bar hits have been grouped, build the cluster + ATOFCluster cluster = new ATOFCluster(this_cluster_bar_hits, this_cluster_wedge_hits, event); + //And add it to the list of clusters + clusters.add(cluster); + }//End loop on all wedge hits + //Now make clusters from bar hits that are not associated with wedge hits + //Loop through all bar hits + for (int i_bar = 0; i_bar < bar_hits.size(); i_bar++) { + BarHit this_bar_hit = bar_hits.get(i_bar); + //Skip hits that have already been clustered + if (this_bar_hit.getIsInACluster()) { + continue; + } + + ArrayList this_cluster_wedge_hits = new ArrayList<>(); + ArrayList this_cluster_bar_hits = new ArrayList<>(); + this_bar_hit.setIsInACluster(true); + this_cluster_bar_hits.add(this_bar_hit); + + //Loop through less energetic clusters + for (int j_bar = i_bar + 1; j_bar < bar_hits.size(); j_bar++) { + BarHit other_bar_hit = bar_hits.get(j_bar); + //Skip already clustered hits + if (other_bar_hit.getIsInACluster()) { + continue; + } + + //Check the distance between the hits + //For now we use phi module difference from what is observed in simu + int delta_module = Math.abs(this_bar_hit.computeModuleIndex() - other_bar_hit.computeModuleIndex()); + if (delta_module > 30) { + delta_module = 60 - delta_module; + } + //Later we could use phi threshold + //double delta_Phi = Math.abs(this_wedge_hit.getPhi() - other_wedge_hit.getPhi()); + double delta_Z = Math.abs(this_bar_hit.getZ() - other_bar_hit.getZ()); + //Time matching + double delta_T = Math.abs(this_bar_hit.getTime() - other_bar_hit.getTime()); + + if (delta_module <= Parameters.SIGMA_MODULE_CLUSTERING) { + if (delta_Z < Parameters.SIGMA_Z_CLUSTERING) { + if (delta_T < Parameters.SIGMA_T_CLUSTERING) { + other_bar_hit.setIsInACluster(true); + this_cluster_bar_hits.add(other_bar_hit); + } + } + } + } + ATOFCluster cluster = new ATOFCluster(this_cluster_bar_hits, this_cluster_wedge_hits, event); + clusters.add(cluster); + } + } + + /** + * Default constructor that initializes the list clusters as new empty + * list. + */ + public ClusterFinder() { + clusters = new ArrayList<>(); + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + } +} diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/constants/Parameters.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/constants/Parameters.java new file mode 100644 index 0000000000..9a5868f82a --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/constants/Parameters.java @@ -0,0 +1,45 @@ +package org.jlab.rec.atof.constants; + +/** + * + * @author npilleux + */ +public class Parameters { + + //In millimiters + public static final double BAR_INNER_RADIUS = 77;//mm + public static final double WEDGE_INNER_RADIUS = 80;//mm + public static final double BAR_THICKNESS = 3;//mm + public static final double WEDGE_THICKNESS = 20;//mm + public static final double BAR_MIDDLE_RADIUS = BAR_INNER_RADIUS + BAR_THICKNESS / 2; + public static final double WEDGE_MIDDLE_RADIUS = WEDGE_INNER_RADIUS + WEDGE_THICKNESS / 2; + + + public static final double VEFF = 200.0;//mm/ns + public static final double TDC2TIME = 0.015625;//ns per channel bin + public static final double ATT_L = 1600.0;//mm + public static final double TOT2ENERGY_BAR = 1.956 * 0.3 /1000;//to MeV + public static final double TOT2ENERGY_WEDGE = 1.956 * 2.0 /1000;//to MeV + + public static double LENGTH_ATOF = 279.7; //detector length in mm + + public static double SIGMA_PHI_TRACK_MATCHING_BAR = 180 * Math.PI/180.;//in rad + public static double SIGMA_PHI_TRACK_MATCHING_WEDGE = 180 * Math.PI/180.;//in rad + + public static double SIGMA_Z_TRACK_MATCHING_BAR = 200;//in mm + public static double SIGMA_Z_TRACK_MATCHING_WEDGE = 200;//in mm + + public static double SIGMA_PHI_CLUSTERING = 6;//in deg + public static double SIGMA_Z_CLUSTERING = 200;//in mm + public static double SIGMA_MODULE_CLUSTERING = 1; + public static double SIGMA_COMPONENT_CLUSTERING = 1; + public static double SIGMA_T_CLUSTERING = 100;// in ns + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + // TODO code application logic here + } + +} diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/ATOFHit.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/ATOFHit.java new file mode 100644 index 0000000000..c0ffadd359 --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/ATOFHit.java @@ -0,0 +1,368 @@ +package org.jlab.rec.atof.hit; + +import org.jlab.geom.base.*; +import org.jlab.geom.prim.Point3D; +import org.jlab.rec.atof.constants.Parameters; + +/** + * + * Represents a hit in the atof. Stores info about the sector, layer, component, + * order, TDC, ToT. Type is wedge/bar up/bar down/ bar Spatial coordinates are + * computed from atof detector object using the geometry service Stores whether + * the hit is part of a cluster. Calculates time, energy based on TDC/ToT. + * + * @author npilleux + */ +public class ATOFHit { + + private int sector, layer, component, order; + private int tdc, tot; + private double time, energy, x, y, z; + private String type; + private boolean isInACluster; + + public int getSector() { + return sector; + } + + public void setSector(int sector) { + this.sector = sector; + } + + public int getLayer() { + return layer; + } + + public void setLayer(int layer) { + this.layer = layer; + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public int getComponent() { + return component; + } + + public void setComponent(int component) { + this.component = component; + } + + public int getTdc() { + return tdc; + } + + public void setTdc(int tdc) { + this.tdc = tdc; + } + + public int getTot() { + return tot; + } + + public void setTot(int tot) { + this.tot = tot; + } + + public double getTime() { + return time; + } + + public void setTime(double time) { + this.time = time; + } + + public double getEnergy() { + return energy; + } + + public void setEnergy(double energy) { + this.energy = energy; + } + + public double getX() { + return x; + } + + public void setX(double x) { + this.x = x; + } + + public double getY() { + return y; + } + + public void setY(double y) { + this.y = y; + } + + public double getZ() { + return z; + } + + public void setZ(double z) { + this.z = z; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public boolean getIsInACluster() { + return isInACluster; + } + + public void setIsInACluster(boolean is_in_a_cluster) { + this.isInACluster = is_in_a_cluster; + } + + /** + * Computes the module index for the hit. + * + */ + public int computeModuleIndex() { + //Index ranging 0 to 60 for each wedge+bar module + return 4 * this.sector + this.layer; + } + + /** + * Assigns a type to the hit. + * + */ + public final String makeType() { + //Type of hit can be wedge, bar up, bar down or bar. + //Avoids testing components and order every time. + String itype = "undefined"; + if (this.component == 10 && this.order == 1) { + itype = "bar down"; + } else if (this.component == 10 && this.order == 0) { + itype = "bar up"; + } else if (this.component < 10) { + itype = "wedge"; + } + this.type = itype; + return itype; + } + + /** + * Converts TDC to time (ns). Sets the hit time parameter to a raw time for + * up/down bar hits or to the time corrected for the propagation for wedge + * hits. + * + * @return 0 if the time was successfully set, or 1 if the hit type is + * unsupported. + */ + public final int convertTdcToTime() { + double tdc2time, veff, distance_to_sipm; + if (null == this.type) { + System.out.print("Null hit type, cannot convert tdc to time."); + return 1; + } else { + switch (this.type) { + case "wedge" -> { + tdc2time = Parameters.TDC2TIME; + veff = Parameters.VEFF; + //Wedge hits are placed at the center of wedges and sipm at their top + distance_to_sipm = Parameters.WEDGE_THICKNESS / 2.; + } + case "bar up" -> { + tdc2time = Parameters.TDC2TIME; + veff = Parameters.VEFF; + //The distance will be computed at barhit level when z information is available + distance_to_sipm = 0; + } + case "bar down" -> { + tdc2time = Parameters.TDC2TIME; + veff = Parameters.VEFF; + //The distance will be computed at barhit level when z information is available + distance_to_sipm = 0; + } + case "bar" -> { + System.out.print("Bar hit type, cannot convert tdc to time."); + return 1; + } + default -> { + System.out.print("Undefined hit type, cannot convert tdc to time."); + return 1; + } + } + } + //Hit time. Will need implementation of offsets. + this.time = tdc2time * this.tdc - distance_to_sipm / veff; + return 0; + } + + /** + * Converts ToT to energy (MeV). Sets the hit energy parameter to a raw + * energy for up/down bar hits or to the energy corrected for the + * attenuation for wedge hits. + * + * @return 0 if the energy was successfully set, or 1 if the hit type is + * unsupported. + */ + public final int convertTotToEnergy() { + double tot2energy; + if (null == this.type) { + System.out.print("Null hit type, cannot convert tot to energy."); + return 1; + } else { + switch (this.type) { + case "wedge" -> { + tot2energy = Parameters.TOT2ENERGY_WEDGE; + //For now hits are considered in the middle of the wedge + //And the SiPM on top + double distance_hit_to_sipm = Parameters.WEDGE_THICKNESS / 2.; + this.energy = tot2energy * this.tot * Math.exp(distance_hit_to_sipm / Parameters.ATT_L); + } + case "bar up" -> { + tot2energy = Parameters.TOT2ENERGY_BAR; + //only half the information in the bar, + //the attenuation will be computed when the full hit is formed + this.energy = tot2energy * this.tot; + } + case "bar down" -> { + tot2energy = Parameters.TOT2ENERGY_BAR; + //only half the information in the bar, + //the attenuation will be computed when the full hit is formed + this.energy = tot2energy * this.tot; + } + case "bar" -> { + System.out.print("Bar hit type, cannot convert tot to energy."); + return 1; + } + default -> { + System.out.print("Undefined hit type, cannot convert tot to energy."); + return 1; + } + } + } + return 0; + } + + /** + * Calculates spatial coordinates for the hit based on associated detector + * component. Retrieves the midpoint of the atof component to assign the + * corresponding x, y, z coordinates to the hit (mm). + * + * + * @param atof The Detector object representing the atof. + * @return 0 if the coordinates were successfully set, or 1 if the hit type + * is undefined or unsupported. + */ + public final int convertSLCToXYZ(Detector atof) { + int sl; + if (null == this.type) { + return 1; + } else { + switch (this.type) { + case "wedge" -> + sl = 1; + case "bar up", "bar down", "bar" -> + sl = 0; + default -> { + return 1; + } + } + } + Component comp = atof.getSector(this.sector).getSuperlayer(sl).getLayer(this.layer).getComponent(this.component); + Point3D midpoint = comp.getMidpoint(); + //Midpoints defined in the system were z=0 is the upstream end of the atof + //Translation to the system were z=0 is the center of the atof + //Units are mm + this.x = midpoint.x(); + this.y = midpoint.y(); + this.z = midpoint.z() - Parameters.LENGTH_ATOF / 2.; + return 0; + } + + /** + * Compares two ATOFHit objects to check if they match in the bar. + *
    + *
  • If the sector or layer of the two hits do not match, the method + * returns {@code false}.
  • + *
  • If either hit is not in the bar (component must be 10), the method + * returns {@code false}.
  • + *
  • If both hits are in the same SiPM (i.e., their order is the same), + * or have incorrect order, the method returns {@code false}.
  • + *
+ * If none of these conditions are violated, the method returns + * {@code true}, indicating the two hits match. + * + * @param hit2match The ATOFHit object to compare with the current instance. + * @return {@code true} if the hits match; {@code false} otherwise. + */ + public boolean matchBar(ATOFHit hit2match) { + if (this.getSector() != hit2match.getSector()) { + //Two hits in different sectors + return false; + } else if (this.getLayer() != hit2match.getLayer()) { + //Two hits in different layers + return false; + } else if (this.getComponent() != 10 || hit2match.getComponent() != 10) { + //At least one hit not in the bar + return false; + } else if (this.getOrder() > 1 || hit2match.getOrder() > 1) { + //At least one hit has incorrect order + return false; + } else { + //Match if one is order 0 and the other is order 1 + return this.getOrder() != hit2match.getOrder(); + } + } + + /** + * Computes the azimuthal angle (phi) of the hit in rad. + * + * @return The azimuthal angle (phi) in radians, in the range [-π, π]. + */ + public double getPhi() { + return Math.atan2(this.y, this.x); + } + + /** + * Constructor for a hit in the atof. Initializes the hit's sector, layer, + * component, order, TDC, ToT. Sets the hit's initial state regarding + * clustering. Set up the hit's type, time, energy, and spatial coordinates. + * + * @param sector The sector of the detector where the hit occurred. + * @param layer The layer of the detector where the hit was detected. + * @param component The component within the layer that registered the hit. + * @param order Order of the hit. + * @param tdc TDC value. + * @param tot ToT value. + * @param atof Detector object representing the atof, used to calculate + * spatial coordinates. + */ + public ATOFHit(int sector, int layer, int component, int order, int tdc, int tot, Detector atof) { + this.sector = sector; + this.layer = layer; + this.component = component; + this.order = order; + this.tdc = tdc; + this.tot = tot; + this.isInACluster = false; + + this.makeType(); + this.convertTdcToTime(); + this.convertTotToEnergy(); + this.convertSLCToXYZ(atof); + } + + public ATOFHit(){ + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + } +} diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/BarHit.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/BarHit.java new file mode 100644 index 0000000000..bbd8fd5316 --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/BarHit.java @@ -0,0 +1,107 @@ +package org.jlab.rec.atof.hit; + +import org.jlab.rec.atof.constants.Parameters; + +/** + * + * Represents a hit in the atof bar. Extends class ATOFHit. Is further defined + * by the two hits upstream and downstream composing a full bar hit. z position, + * time and energy are defined from the up/down hits. + * + * @author npilleux + */ +public class BarHit extends ATOFHit { + + //A bar hit is the combination of a downstream and upstream hits + private ATOFHit hitUp, hitDown; + + public ATOFHit getHitUp() { + return hitUp; + } + + public void setHitUp(ATOFHit hit_up) { + this.hitUp = hit_up; + } + + public ATOFHit getHitDown() { + return hitDown; + } + + public void setHitDown(ATOFHit hit_down) { + this.hitDown = hit_down; + } + + /** + * Computes bar hit z coordinate from up/downstream hit times. + * + */ + public final void computeZ() { + this.setZ(Parameters.VEFF/2. * (hitUp.getTime() - hitDown.getTime())); + } + + /** + * Computes bar hit time from up/downstream hit times. + * The time is set as the time of the most energetic hit. + * It is corrected for propagation time. + * + */ + public final void computeTime() { + //We pick the most energetic signal as the timing signal + double time_at_sipm, distance_to_sipm; + if(this.hitDown.getEnergy() > this.hitUp.getEnergy()) { + time_at_sipm = this.hitDown.getTime(); + distance_to_sipm = Parameters.LENGTH_ATOF/2. - this.getZ(); + } + else { + time_at_sipm = this.hitUp.getTime(); + distance_to_sipm = Parameters.LENGTH_ATOF/2. + this.getZ(); + } + this.setTime(time_at_sipm - distance_to_sipm/Parameters.VEFF); + } + + /** + * Computes bar hit energy from up/downstream hits. + * The energy of the up/downstream hits is corrected for attenuation now that z is known. + * The energy of the bar hit is the sum of the energy of the up/downstream hits. + * + */ + public final void computeEnergy() { + this.computeZ(); + double distance_hit_to_sipm_up = Parameters.LENGTH_ATOF / 2. + this.getZ(); + double distance_hit_to_sipm_down = Parameters.LENGTH_ATOF / 2. - this.getZ(); + double Edep_up = hitUp.getEnergy() * Math.exp(distance_hit_to_sipm_up / Parameters.ATT_L); + double Edep_down = hitDown.getEnergy() * Math.exp(distance_hit_to_sipm_down / Parameters.ATT_L); + this.setEnergy(Edep_up + Edep_down); + } + + public BarHit(ATOFHit hit_down, ATOFHit hit_up) { + boolean hits_match = hit_down.matchBar(hit_up); + if (!hits_match) { + throw new UnsupportedOperationException("Hits do not match \n"); + } + this.setType("bar"); + this.setOrder(2);//Fake order for bar hits + this.hitUp = hit_up; + this.hitDown = hit_down; + this.setLayer(hit_up.getLayer()); + this.setSector(hit_up.getSector()); + this.setComponent(10); + this.setX(hit_up.getX()); + this.setY(hit_up.getY()); + this.computeZ(); + this.computeTime(); + this.computeEnergy(); + } + + public BarHit() { + super(); + this.setType("bar"); + this.setOrder(2);//Fake order for bar hits + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + } +} diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/HitFinder.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/HitFinder.java new file mode 100644 index 0000000000..4a9592cb21 --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/hit/HitFinder.java @@ -0,0 +1,135 @@ +package org.jlab.rec.atof.hit; + +import java.util.ArrayList; +import java.util.Collections; +import org.jlab.geom.base.Detector; +import org.jlab.io.base.DataBank; +import org.jlab.io.base.DataEvent; + +/** + * The {@code HitFinder} class finds hits in the atof. + * + *

+ * Uses atof tdc bank information + * + * Creates a {@link ArrayList} of {@link BarHit} for bar hits read. + * Creates a {@link ArrayList} of {@link ATOFHit} for wedge hits read. + * + *

+ * + * @author pilleux + */ +public class HitFinder { + + /** + * list of bar hits + */ + private ArrayList barHits; + /** + * list of wedge hits + */ + private ArrayList wedgeHits; + + /** + * Default constructor that initializes the list of hits as new empty + * lists. + */ + public HitFinder() { + this.barHits = new ArrayList<>(); + this.wedgeHits = new ArrayList<>(); + } + + // Getter and Setter for barHits + public ArrayList getBarHits() { + return barHits; + } + + public void setBarHits(ArrayList bar_hits) { + this.barHits = bar_hits; + } + + public ArrayList getWedgeHits() { + return wedgeHits; + } + + public void setWedgeHits(ArrayList wedge_hits) { + this.wedgeHits = wedge_hits; + } + + /** + * Find hits in the event, matches them to tracks found in the ahdc + * and build their properties. + * + * @param event the {@link DataEvent} containing hits. + * @param atof the {@link Detector} representing the atof geometry to match + * the sector/layer/component to x/y/z. + */ + public void findHits(DataEvent event, Detector atof) { + //For each event a list of bar hits and a list of wedge hits are filled + this.barHits.clear(); + this.wedgeHits.clear(); + //They are read from the ATOF TDC bank + DataBank bank = event.getBank("ATOF::tdc"); + int nt = bank.rows(); // number of hits + //Hits in the bar downstream and upstream will be matched + ArrayList hit_up = new ArrayList<>(); + ArrayList hit_down = new ArrayList<>(); + //Looping through all hits + for (int i = 0; i < nt; i++) { + //Getting their properties + int sector = bank.getInt("sector", i); + int layer = bank.getInt("layer", i); + int component = bank.getInt("component", i); + int order = bank.getInt("order", i); + int tdc = bank.getInt("TDC", i); + int tot = bank.getInt("ToT", i); + //Building a Hit + ATOFHit hit = new ATOFHit(sector, layer, component, order, tdc, tot, atof); + if (hit.getEnergy() < 0.01) { + continue; //energy threshold + } + //Sorting the hits into wedge, upstream and downstream bar hits + //Lists are built for up/down bar to match them after + //Wedge hits are mayched to ahdc tracks and listed + if (null == hit.getType()) { + System.out.print("Undefined hit type \n"); + } else { + switch (hit.getType()) { + case "bar up" -> + hit_up.add(hit); + case "bar down" -> + hit_down.add(hit); + case "wedge" -> { + this.wedgeHits.add(hit); + } + default -> + System.out.print("Undefined hit type \n"); + } + } + }//End loop through all hits + + //Starting loop through up hits in the bar + for (int i_up = 0; i_up < hit_up.size(); i_up++) { + ATOFHit this_hit_up = hit_up.get(i_up); + //Starting loop through down hits in the bar + for (int i_down = 0; i_down < hit_down.size(); i_down++) { + ATOFHit this_hit_down = hit_down.get(i_down); + //Matching the hits: if same module and different order, they make up a bar hit + if (this_hit_up.matchBar(this_hit_down)) { + //Bar hits are matched to ahdc tracks and listed + BarHit this_bar_hit = new BarHit(this_hit_up, this_hit_down); + this.barHits.add(this_bar_hit); + } + } + } + //Once all has been listed, hits are sorted by energy + Collections.sort(this.barHits, (hit1, hit2) -> Double.compare(hit2.getEnergy(), hit1.getEnergy())); + Collections.sort(this.wedgeHits, (hit1, hit2) -> Double.compare(hit2.getEnergy(), hit1.getEnergy())); + } + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + } +} diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/trackMatch/TrackProjection.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/trackMatch/TrackProjection.java new file mode 100644 index 0000000000..f6da1eacf3 --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/trackMatch/TrackProjection.java @@ -0,0 +1,175 @@ +package org.jlab.rec.atof.trackMatch; + +import org.jlab.geom.prim.Point3D; + +/** + * The {@code TrackProjection} class holds ahdc track information relevant for atof analysis + * i.e projected to the surfaces of the bar and wedges + * @author pilleux + */ + +public class TrackProjection { + + /** + * Intersection point of the track with the middle surface of the bar. + */ + private Point3D barIntersect = new Point3D(); + + /** + * Intersection point of the track with the middle surface of the wedges. + */ + private Point3D wedgeIntersect = new Point3D(); + + /** + * Path length of the track from the DOCA to the beam line + * to the entrance surface of the bar. + */ + Float barPathLength; + + /** + * Path length of the track from the DOCA to the beam line + * to the entrance surface of the wedges. + */ + Float wedgePathLength; + + /** + * Path length inside the bar. + */ + Float barInPathLength; + + /** + * Path length inside the wedge. + */ + Float wedgeInPathLength; + + + /** + * Default constructor that initializes the intersection points and path lengths to {@code NaN}. + */ + public TrackProjection() { + barIntersect = new Point3D(Double.NaN, Double.NaN, Double.NaN); + wedgeIntersect = new Point3D(Double.NaN, Double.NaN, Double.NaN); + barPathLength = Float.NaN; + wedgePathLength = Float.NaN; + barInPathLength = Float.NaN; + wedgeInPathLength = Float.NaN; + } + + /** + * Gets the intersection point of the track with the middle surface of the bar. + * + * @return {@link Point3D} bar's intersection point. + */ + public Point3D getBarIntersect() { + return barIntersect; + } + + /** + * Gets the intersection point of the track with the middle surface of the wedges. + * + * @return {@link Point3D} wedge's intersection point. + */ + public Point3D getWedgeIntersect() { + return wedgeIntersect; + } + + /** + * Gets the path length of the track from the DOCA to the beam line to the inner surface of the bar. + * + * @return {@code Float} path length to the bar's middle surface. + */ + public Float getBarPathLength() { + return barPathLength; + } + + /** + * Gets the path length of the track from the inner surface of the bar + * to its middle surface. + * + * @return {@code Float} path length inside the bar. + */ + public Float getBarInPathLength() { + return barInPathLength; + } + + /** + * Gets the path length of the track from the DOCA to the beam line to the inner surface of the wedges. + * + * @return {@code Float} path length to the wedge's middle surface. + */ + public Float getWedgePathLength() { + return wedgePathLength; + } + + /** + * Gets the path length of the track from the the inner surface of the wedge + * to its middle surface. + * + * @return {@code Float} path length inside the wedge. + */ + public Float getWedgeInPathLength() { + return wedgeInPathLength; + } + + /** + * Sets the intersection point of the track with the middle surface of the bar. + * + * @param BarIntersect {@link Point3D} intersection with the bar. + */ + public void setBarIntersect(Point3D BarIntersect) { + this.barIntersect = BarIntersect; + } + + /** + * Sets the intersection point of the track with the middle surface of the wedges. + * + * @param WedgeIntersect {@link Point3D} intersection with the wedge. + */ + public void setWedgeIntersect(Point3D WedgeIntersect) { + this.wedgeIntersect = WedgeIntersect; + } + + /** + * Sets the path length of the track from the DOCA to the beam line to the inner surface of the bar. + * + * @param BarPathLength {@code Float} path length to the bar inner surface. + */ + public void setBarPathLength(Float BarPathLength) { + this.barPathLength = BarPathLength; + } + + /** + * Sets the path length of the track from the DOCA to the beam line to the inner surface of the wedges. + * + * @param WedgePathLength {@code Float} path length to the wedge inner surface. + */ + public void setWedgePathLength(Float WedgePathLength) { + this.wedgePathLength = WedgePathLength; + } + + /** + * Sets the path length of the track inside the bar. + * + * @param BarInPathLength {@code Float} path length inside the bar. + */ + public void setBarInPathLength(Float BarInPathLength) { + this.barInPathLength = BarInPathLength; + } + + /** + * Sets the path length of the track inside the wedges. + * + * @param WedgeInPathLength {@code Float} path length inside the wedge. + */ + public void setWedgeInPathLength(Float WedgeInPathLength) { + this.wedgeInPathLength = WedgeInPathLength; + } + + /** + * testing purposes. + * + * @param arg command-line arguments. + */ + public static void main(String arg[]) { + } +} \ No newline at end of file diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/atof/trackMatch/TrackProjector.java b/reconstruction/alert/src/main/java/org/jlab/rec/atof/trackMatch/TrackProjector.java new file mode 100644 index 0000000000..6db18a154d --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/atof/trackMatch/TrackProjector.java @@ -0,0 +1,209 @@ +package org.jlab.rec.atof.trackMatch; + +import java.util.ArrayList; + +import org.jlab.io.base.DataBank; +import org.jlab.io.base.DataEvent; +import org.jlab.clas.tracking.trackrep.Helix; +import org.jlab.clas.tracking.kalmanfilter.Units; +import org.jlab.rec.atof.constants.Parameters; + +/** + * The {@code TrackProjector} class projects ahdc tracks to the inner surfaces + * of the bar and wedges of the atof + * + *

+ * Uses ahdc track bank information (for now position, momentum) Creates a + * {@link TrackProjection} for each track. + *

+ * + *

+ * TO DO: - replace hardcoded values with database values. - magnetic field ? + * use swimmer tools? - charge ? + *

+ * + * @author pilleux + */ +public class TrackProjector { + + /** + * projections of tracks. + */ + private ArrayList projections; + + /** + * solenoid magnitude + */ + private Double b; + + /** + * Default constructor that initializes the list of projections as new empty + * list and the magnetic field to 5T. + */ + public TrackProjector() { + projections = new ArrayList(); + this.b = 5.0; + } + + /** + * Gets the list of track projections. + * + * @return a {@link List} of {@link TrackProjection} objects representing + * the projections. + */ + public ArrayList getProjections() { + return projections; + } + + /** + * Gets the solenoid magnitude + * + * @return solenoid magnitude + */ + public Double getB() { + return b; + } + + /** + * Sets the list of track projections. + * + * @param Projections a {@link List} of {@link TrackProjection}. + */ + public void setProjections(ArrayList Projections) { + this.projections = Projections; + } + + /** + * Sets the solenoid magnitude. + * + * @param B a double. + */ + public void setB(Double B) { + this.b = B; + } + + /** + * Projects the ahdc tracks in the event onto the atof using a {@link Helix} + * model. + * + * @param event the {@link DataEvent} containing track data to be projected. + */ + public void projectTracks(DataEvent event) {//, CalibrationConstantsLoader ccdb) { + + projections.clear(); + + String track_bank_name = "AHDC::Track"; + + if (event == null) { // check if there is an event + //System.out.print(" no event \n"); + } else if (event.hasBank(track_bank_name) == false) { + // check if there are ahdc tracks in the event + //System.out.print("no tracks \n"); + } else { + DataBank bank = event.getBank(track_bank_name); + int nt = bank.rows(); // number of tracks + TrackProjection projection = new TrackProjection(); + for (int i = 0; i < nt; i++) { + + double x = bank.getFloat("x", i); + double y = bank.getFloat("y", i); + double z = bank.getFloat("z", i); + double px = bank.getFloat("px", i); + double py = bank.getFloat("py", i); + double pz = bank.getFloat("pz", i); + + int q = -1; //need the charge sign from tracking + + Units units = Units.MM; //can be MM or CM. + + double xb = 0; + double yb = 0; + + //momenta must be in GeV for the helix class + Helix helix = new Helix(x, y, z, px/1000., py/1000., pz/1000., q, b, xb, yb, units); + + //Intersection points with the middle of the bar or wedge + projection.setBarIntersect(helix.getHelixPointAtR(Parameters.BAR_MIDDLE_RADIUS)); + projection.setWedgeIntersect(helix.getHelixPointAtR(Parameters.WEDGE_MIDDLE_RADIUS)); + + //Path length to the middle of the bar or wedge + projection.setBarPathLength((float) Math.abs(helix.getLAtR(Parameters.BAR_INNER_RADIUS))); + projection.setWedgePathLength((float) Math.abs(helix.getLAtR(Parameters.WEDGE_INNER_RADIUS))); + + //Path length from the inner radius to the middle radius + projection.setBarInPathLength((float) Math.abs(helix.getLAtR(Parameters.BAR_MIDDLE_RADIUS)) - projection.getBarPathLength()); + projection.setWedgeInPathLength((float) Math.abs(helix.getLAtR(Parameters.WEDGE_MIDDLE_RADIUS)) - projection.getWedgePathLength()); + projections.add(projection); + } + } + } + + /** + * Projects the MC particles onto the atof using a {@link Helix} + * model. + * + * @param event the {@link DataEvent} containing track data to be projected. + */ + public void projectMCTracks(DataEvent event) {//, CalibrationConstantsLoader ccdb) { + + projections.clear(); + + String track_bank_name = "MC::Particle"; + if (event == null) { // check if there is an event + //System.out.print(" no event \n"); + } else if (event.hasBank(track_bank_name) == false) { + // check if there are ahdc tracks in the event + //System.out.print("no tracks \n"); + } else { + DataBank bank = event.getBank(track_bank_name); + int nt = bank.rows(); // number of tracks + TrackProjection projection = new TrackProjection(); + DataBank outputBank = event.createBank("ALERT::Projections", nt); + + for (int i = 0; i < nt; i++) { + + double x = bank.getFloat("vx", i); + double y = bank.getFloat("vy", i); + double z = bank.getFloat("vz", i); + double px = bank.getFloat("px", i); + double py = bank.getFloat("py", i); + double pz = bank.getFloat("pz", i); + + //Put everything in MM + + x = x*10; + y = y*10; + z = z*10; + + Units units = Units.MM; + + int q = -1; //need the charge sign from tracking + + double xb = 0; + double yb = 0; + + //momenta must be in GeV for the helix class + Helix helix = new Helix(x, y, z, px, py, pz, q, b, xb, yb, units); + + //Intersection points with the middle of the bar or wedge + projection.setBarIntersect(helix.getHelixPointAtR(Parameters.BAR_MIDDLE_RADIUS)); + projection.setWedgeIntersect(helix.getHelixPointAtR(Parameters.WEDGE_MIDDLE_RADIUS)); + + //Path length to the middle of the bar or wedge + + projection.setBarPathLength((float) Math.abs(helix.getLAtR(Parameters.BAR_INNER_RADIUS))); + projection.setWedgePathLength((float) Math.abs(helix.getLAtR(Parameters.WEDGE_INNER_RADIUS))); + + //Path length from the inner radius to the middle radius + + projection.setBarInPathLength((float) Math.abs(helix.getLAtR(Parameters.BAR_MIDDLE_RADIUS)) - projection.getBarPathLength()); + projection.setWedgeInPathLength((float) Math.abs(helix.getLAtR(Parameters.WEDGE_MIDDLE_RADIUS)) - projection.getWedgePathLength()); + projections.add(projection); + } + } + } + + public static void main(String arg[]) { + + } +} diff --git a/reconstruction/alert/src/main/java/org/jlab/rec/service/ATOFEngine.java b/reconstruction/alert/src/main/java/org/jlab/rec/service/ATOFEngine.java new file mode 100644 index 0000000000..117af7ba61 --- /dev/null +++ b/reconstruction/alert/src/main/java/org/jlab/rec/service/ATOFEngine.java @@ -0,0 +1,122 @@ +package org.jlab.rec.service; + +import java.util.ArrayList; + +import org.jlab.clas.reco.ReconstructionEngine; +import org.jlab.io.base.DataBank; +import org.jlab.io.base.DataEvent; + +import java.util.concurrent.atomic.AtomicInteger; +import org.jlab.clas.swimtools.Swim; +import org.jlab.detector.calib.utils.DatabaseConstantProvider; +import org.jlab.geom.base.Detector; +import org.jlab.geom.detector.alert.ATOF.AlertTOFFactory; +import org.jlab.io.hipo.HipoDataSource; +import org.jlab.rec.atof.banks.RecoBankWriter; +import org.jlab.rec.atof.cluster.ATOFCluster; +import org.jlab.rec.atof.cluster.ClusterFinder; +import org.jlab.rec.atof.hit.ATOFHit; +import org.jlab.rec.atof.hit.BarHit; +import org.jlab.rec.atof.hit.HitFinder; +import org.jlab.rec.atof.trackMatch.TrackProjector; + +/** + * Service to return reconstructed ATOF hits and clusters + * + * @author npilleux + * + */ +public class ATOFEngine extends ReconstructionEngine { + + public ATOFEngine() { + super("ATOF", "pilleux", "1.0"); + } + + RecoBankWriter rbc; + + private final AtomicInteger run = new AtomicInteger(0); + private Detector ATOF; + private double b; //Magnetic field + + public void setB(double B) { + this.b = B; + } + public double getB() { + return b; + } + public void setATOF(Detector ATOF) { + this.ATOF = ATOF; + } + public Detector getATOF() { + return ATOF; + } + + @Override + public boolean processDataEvent(DataEvent event) { + + if (!event.hasBank("RUN::config")) { + return true; + } + + DataBank bank = event.getBank("RUN::config"); + + int newRun = bank.getInt("run", 0); + if (newRun == 0) { + return true; + } + + if (run.get() == 0 || (run.get() != 0 && run.get() != newRun)) { + run.set(newRun); + } + + //Do we need to read the event vx,vy,vz? + //If not, this part can be moved in the initialization of the engine. + double eventVx=0,eventVy=0,eventVz=0; //They should be in CM + //Track Projector Initialisation with b field + Swim swim = new Swim(); + float magField[] = new float[3]; + swim.BfieldLab(eventVx, eventVy, eventVz, magField); + this.b = Math.sqrt(Math.pow(magField[0],2) + Math.pow(magField[1],2) + Math.pow(magField[2],2)); + TrackProjector projector = new TrackProjector(); + projector.setB(this.b); + projector.projectTracks(event); + rbc.appendMatchBanks(event, projector.getProjections()); + //Hit finder init + HitFinder hitfinder = new HitFinder(); + hitfinder.findHits(event, ATOF); + + ArrayList WedgeHits = hitfinder.getWedgeHits(); + ArrayList BarHits = hitfinder.getBarHits(); + + //Exit if hit lists are empty + if (WedgeHits.isEmpty() && BarHits.isEmpty()) { + // System.out.println("No hits : "); + // event.show(); + return true; + } + + ClusterFinder clusterFinder = new ClusterFinder(); + clusterFinder.makeClusters(event,hitfinder); + ArrayList Clusters = clusterFinder.getClusters(); + + if (WedgeHits.size() != 0 || BarHits.size() != 0) { + rbc.appendATOFBanks(event, WedgeHits, BarHits, Clusters); + } + return true; + } + + @Override + public boolean init() { + rbc = new RecoBankWriter(); + + AlertTOFFactory factory = new AlertTOFFactory(); + DatabaseConstantProvider cp = new DatabaseConstantProvider(11, "default"); + this.ATOF = factory.createDetectorCLAS(cp); + this.registerOutputBank("ATOF::hits", "ATOF::clusters"); + + return true; + } + + public static void main(String arg[]) { + } +}