/* This file is part of MAUS: http://micewww.pp.rl.ac.uk:8080/projects/maus
*
* MAUS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MAUS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAUS. If not, see .
*
*/
#include
#include "CLHEP/Units/PhysicalConstants.h"
#include "Geant4/G4NistManager.hh"
#include "src/common_cpp/Recon/Global/GlobalTools.hh"
#include "src/common_cpp/Recon/Global/Particle.hh"
#include "src/common_cpp/Utils/Globals.hh"
#include "src/common_cpp/Utils/Exception.hh"
#include "src/legacy/BeamTools/BTFieldConstructor.hh"
#include "Utils/Squeak.hh"
#include "src/common_cpp/Recon/Global/TrackMatching.hh"
namespace MAUS {
namespace recon {
namespace global {
TrackMatching::TrackMatching(GlobalEvent* global_event, std::string mapper_name,
std::string pid_hypothesis_string, int beamline_polarity,
std::map > matching_tolerances,
double max_step_size, std::pair > no_check_settings,
bool energy_loss) {
_global_event = global_event;
_mapper_name = mapper_name;
_pid_hypothesis_string = pid_hypothesis_string;
_beamline_polarity = beamline_polarity;
_matching_tolerances = matching_tolerances;
_max_step_size = max_step_size;
_energy_loss = energy_loss;
_no_check_settings = no_check_settings;
}
void TrackMatching::USTrack() {
// Get all Tracker 0 tracks
DataStructure::Global::TrackPArray *scifi_track_array =
GetDetectorTrackArray(DataStructure::Global::kTracker0);
// Get Spacepoints for TOF0/1 and convert them to TrackPoints
std::vector TOF0_sp =
GetDetectorSpacePoints(DataStructure::Global::kTOF0);
std::vector TOF1_sp =
GetDetectorSpacePoints(DataStructure::Global::kTOF1);
// Ckov Spacepoints
std::vector CkovA_sp =
GetDetectorSpacePoints(DataStructure::Global::kCherenkovA);
std::vector CkovB_sp =
GetDetectorSpacePoints(DataStructure::Global::kCherenkovB);
// Here we check whether we actually want to use propagation for TrackMatching
// or if we can just assume that all hits are from the same particle
bool no_check = false;
if (_no_check_settings.first) {
if (scifi_track_array->size() == 1 and TOF0_sp.size() < 2 and TOF1_sp.size() < 2 and
CkovA_sp.size() < 2 and CkovB_sp.size() < 2) {
no_check = true;
}
}
BTFieldConstructor* field;
if (!no_check) {
// Load the magnetic field for RK4 propagation
field = Globals::GetMCFieldConstructor();
}
// Iterate over all Tracker0 Tracks (typically 1)
for (auto scifi_track_iter = scifi_track_array->begin();
scifi_track_iter != scifi_track_array->end();
++scifi_track_iter) {
// Pull out the track so we're not making a mess with ressources
DataStructure::Global::Track* tracker0_track = (*scifi_track_iter);
// Create the list of PIDs for which we want to create hypothesis tracks
int charge_hypothesis = tracker0_track->get_charge();
if (charge_hypothesis == 0) {
charge_hypothesis = _beamline_polarity;
}
std::vector pids = PIDHypotheses(
charge_hypothesis, _pid_hypothesis_string);
// Iterate over all possible PIDs and create an hypothesis track for each
for (size_t i = 0; i < pids.size(); i++) {
DataStructure::Global::Track* hypothesis_track =
new DataStructure::Global::Track();
hypothesis_track->set_mapper_name("MapCppGlobalTrackMatching_US");
hypothesis_track->set_pid(pids[i]);
// No matching criterion for Cherenkov hits, so if they exist, we add them
if (CkovA_sp.size() > 0) {
Squeak::mout(Squeak::debug) << "TrackMatching: CkovA Added" << std::endl;
DataStructure::Global::TrackPoint* CkovA_tp =
new DataStructure::Global::TrackPoint(CkovA_sp.at(0));
hypothesis_track->AddTrackPoint(CkovA_tp);
}
if (CkovB_sp.size() > 0) {
Squeak::mout(Squeak::debug) << "TrackMatching: CkovB Added" << std::endl;
DataStructure::Global::TrackPoint* CkovB_tp =
new DataStructure::Global::TrackPoint(CkovB_sp.at(0));
hypothesis_track->AddTrackPoint(CkovB_tp);
}
// Now match TOF1 and then TOF0
if (!no_check) {
// Extract four-position and momentum from first track point (i.e. most
// upstream)
TLorentzVector position;
TLorentzVector momentum;
DataStructure::Global::TrackPoint* first_tracker_tp =
GlobalTools::GetNearestZTrackPoint(tracker0_track, 0);
position = first_tracker_tp->get_position();
momentum = first_tracker_tp->get_momentum();
delete first_tracker_tp;
MatchTrackPoint(position, momentum, TOF1_sp, pids[i], field, "TOF1",
hypothesis_track);
std::vector ht_tof1_tps =
hypothesis_track->GetTrackPoints(DataStructure::Global::kTOF1);
if (ht_tof1_tps.size() > 0) {
double tof1_z = ht_tof1_tps[0]->get_position().Z();
double tof1_t = ht_tof1_tps[0]->get_position().T();
MatchTOF0(position, momentum, tof1_z, tof1_t, TOF0_sp, pids[i], field, hypothesis_track);
}
} else {
if (TOF0_sp.size() == 1) {
Squeak::mout(Squeak::debug) << "TrackMatching: TOF 0 Added (No Check)" << std::endl;
DataStructure::Global::TrackPoint* TOF0_tp =
new DataStructure::Global::TrackPoint(TOF0_sp.at(0));
hypothesis_track->AddTrackPoint(TOF0_tp);
}
if (TOF1_sp.size() == 1) {
Squeak::mout(Squeak::debug) << "TrackMatching: TOF 1 Added (No Check)" << std::endl;
DataStructure::Global::TrackPoint* TOF1_tp =
new DataStructure::Global::TrackPoint(TOF1_sp.at(0));
hypothesis_track->AddTrackPoint(TOF1_tp);
}
}
// We had to add TOF0 before TOF1, so the order isn't right
hypothesis_track->SortTrackPointsByZ();
// Now we fill the track with trackpoints from the tracker with energy
// calculated from p and m, trackpoints are cloned as we want everything
// in the hypothesis track to be "fresh"
double mass = Particle::GetInstance().GetMass(pids[i]);
AddTrackerTrackPoints(tracker0_track, "MapCppGlobalTrackMatching_US",
mass, hypothesis_track);
_global_event->add_track_recursive(hypothesis_track);
}
_global_event->add_track_recursive(tracker0_track);
}
delete scifi_track_array;
}
void TrackMatching::DSTrack() {
// Get all Tracker 1 tracks
DataStructure::Global::TrackPArray *scifi_track_array =
GetDetectorTrackArray(DataStructure::Global::kTracker1);
// Get all EMR tracks
DataStructure::Global::TrackPArray *emr_track_array =
GetDetectorTrackArray(DataStructure::Global::kEMR);
// Get Spacepoints for TOF0/1 and convert them to TrackPoints
std::vector TOF2_sp =
GetDetectorSpacePoints(DataStructure::Global::kTOF2);
std::vector KL_sp =
GetDetectorSpacePoints(DataStructure::Global::kCalorimeter);
// Here we check whether we actually want to use propagation for TrackMatching
// or if we can just assume that all hits are from the same particle
bool no_check = false;
if (_no_check_settings.first) {
if (scifi_track_array->size() == 1 and TOF2_sp.size() < 2 and KL_sp.size() < 2 and
emr_track_array->size() < 2) {
no_check = true;
}
}
BTFieldConstructor* field;
if (!no_check) {
// Load the magnetic field for RK4 propagation
field = Globals::GetMCFieldConstructor();
}
// Iterate over all Tracker1 Tracks (typically 1)
for (auto scifi_track_iter = scifi_track_array->begin();
scifi_track_iter != scifi_track_array->end();
++scifi_track_iter) {
// Pull out the track so we're not making a mess with ressources
DataStructure::Global::Track* tracker1_track = (*scifi_track_iter);
// Create the list of PIDs for which we want to create hypothesis tracks
int charge_hypothesis = tracker1_track->get_charge();
if (charge_hypothesis == 0) {
charge_hypothesis = _beamline_polarity;
}
std::vector pids = PIDHypotheses(
charge_hypothesis, _pid_hypothesis_string);
// Iterate over all possible PIDs and create an hypothesis track for each
for (size_t i = 0; i < pids.size(); i++) {
DataStructure::Global::Track* hypothesis_track =
new DataStructure::Global::Track();
hypothesis_track->set_mapper_name("MapCppGlobalTrackMatching_DS");
hypothesis_track->set_pid(pids[i]);
// This time we add in the tracker trackpoints first
double mass = Particle::GetInstance().GetMass(pids[i]);
AddTrackerTrackPoints(tracker1_track, "MapCppGlobalTrackMatching_DS",
mass, hypothesis_track);
if (!no_check) {
// Extract four-position and momentum from last track point (i.e. most
// downstream
TLorentzVector position;
TLorentzVector momentum;
DataStructure::Global::TrackPoint* last_tracker_tp =
GlobalTools::GetNearestZTrackPoint(tracker1_track, 100000);
position = last_tracker_tp->get_position();
momentum = last_tracker_tp->get_momentum();
delete last_tracker_tp;
// TOF2
MatchTrackPoint(position, momentum, TOF2_sp, pids[i], field, "TOF2",
hypothesis_track);
// KL
MatchTrackPoint(position, momentum, KL_sp, pids[i], field, "KL",
hypothesis_track);
// EMR
MatchEMRTrack(position, momentum, emr_track_array, pids[i], field,
hypothesis_track);
} else {
if (TOF2_sp.size() == 1) {
Squeak::mout(Squeak::debug) << "TrackMatching: TOF 2 Added (No Check)" << std::endl;
DataStructure::Global::TrackPoint* TOF2_tp =
new DataStructure::Global::TrackPoint(TOF2_sp.at(0));
hypothesis_track->AddTrackPoint(TOF2_tp);
}
if (KL_sp.size() == 1) {
Squeak::mout(Squeak::debug) << "TrackMatching: KL Added (No Check)" << std::endl;
DataStructure::Global::TrackPoint* KL_tp =
new DataStructure::Global::TrackPoint(KL_sp.at(0));
hypothesis_track->AddTrackPoint(KL_tp);
}
if (emr_track_array->size() == 1) {
hypothesis_track->set_emr_range_primary(emr_track_array->at(0)->get_emr_range_primary());
hypothesis_track->set_emr_plane_density(emr_track_array->at(0)->get_emr_plane_density());
std::vector emr_trackpoints =
emr_track_array->at(0)->GetTrackPoints();
for (size_t i = 0; i < emr_trackpoints.size(); i++) {
DataStructure::Global::TrackPoint* emr_tp =
emr_trackpoints[i]->Clone();
emr_tp->set_mapper_name("MapCppGlobalTrackMatching_DS");
TLorentzVector momentum = emr_tp->get_momentum();
double energy = ::sqrt(momentum.Rho()*momentum.Rho() + mass*mass);
momentum.SetE(energy);
emr_tp->set_momentum(momentum);
hypothesis_track->AddTrackPoint(emr_tp);
}
}
}
_global_event->add_track_recursive(hypothesis_track);
}
}
delete scifi_track_array;
delete emr_track_array;
}
void TrackMatching::throughTrack() {
// import tracks already created by tracker recon
DataStructure::Global::TrackPArray* global_tracks =
_global_event->get_tracks();
// Typically used for no fields so we can't discriminate by charge hypothesis
std::vector pids = PIDHypotheses(0,
_pid_hypothesis_string);
// Iterate over all PIDs
for (size_t i = 0; i < pids.size(); i++) {
DataStructure::Global::TrackPArray* us_tracks =
new DataStructure::Global::TrackPArray();
DataStructure::Global::TrackPArray* ds_tracks =
new DataStructure::Global::TrackPArray();
// Loop over all global tracks and sort into US and DS tracks by mapper name
// provided they have the correct PID and hits in TOF1/2 to match by dT
USDSTracks(global_tracks, pids[i], us_tracks, ds_tracks);
// Do we have both US and DS tracks in the event?
if ((us_tracks->size() > 0) and
(ds_tracks->size() > 0)) {
// Iterate over all possible combinations of US and DS tracks
for (auto us_track_iter = us_tracks->begin();
us_track_iter != us_tracks->end();
++us_track_iter) {
for (auto ds_track_iter = ds_tracks->begin();
ds_track_iter != ds_tracks->end();
++ds_track_iter) {
// Going to assume that if several TrackPoints for the same TOF are in
// the track that they have been checked to be sensible (TODO above)
if (((*us_track_iter)->GetTrackPoints().size() > 0) and
((*ds_track_iter)->GetTrackPoints().size() > 0)) {
MatchUSDS((*us_track_iter), (*ds_track_iter), pids[i]);
}
}
}
}
}
}
DataStructure::Global::TrackPArray* TrackMatching::GetDetectorTrackArray(
DataStructure::Global::DetectorPoint detector) {
DataStructure::Global::TrackPArray *imported_tracks =
_global_event->get_tracks();
DataStructure::Global::TrackPArray *track_array =
new DataStructure::Global::TrackPArray();
for (auto imported_track_iter = imported_tracks->begin();
imported_track_iter != imported_tracks->end();
++imported_track_iter) {
DataStructure::Global::Track* imported_track = (*imported_track_iter);
// Check that track is from correct detector
if (imported_track->HasDetector(detector)) {
// Exclude EMR secondary tracks (tracker tracks also have this at 0 by
// default)
if (imported_track->get_emr_range_secondary() < 0.001) {
track_array->push_back(imported_track);
}
}
}
return track_array;
}
std::vector
TrackMatching::GetDetectorSpacePoints(
DataStructure::Global::DetectorPoint detector) {
std::vector space_points;
std::vector *global_spacepoint_array =
_global_event->get_space_points();
for (size_t i = 0; i < global_spacepoint_array->size(); i++) {
if (global_spacepoint_array->at(i)->get_detector() == detector) {
space_points.push_back(global_spacepoint_array->at(i));
}
}
return space_points;
}
std::vector TrackMatching::PIDHypotheses(
int charge_hypothesis, std::string pid_hypothesis_string) {
std::vector pids;
// First check if a specific PID has been forced by the configuration
if (pid_hypothesis_string == "kEPlus") {
pids.push_back(DataStructure::Global::kEPlus);
} else if (pid_hypothesis_string == "kEMinus") {
pids.push_back(DataStructure::Global::kEMinus);
} else if (pid_hypothesis_string == "kMuPlus") {
pids.push_back(DataStructure::Global::kMuPlus);
} else if (pid_hypothesis_string == "kMuMinus") {
pids.push_back(DataStructure::Global::kMuMinus);
} else if (pid_hypothesis_string == "kPiPlus") {
pids.push_back(DataStructure::Global::kPiPlus);
} else if (pid_hypothesis_string == "kPiMinus") {
pids.push_back(DataStructure::Global::kPiMinus);
} else {
// No specific PID forced, hence we assign by charge hypothesis
if (charge_hypothesis != -1) {
pids.push_back(DataStructure::Global::kEPlus);
pids.push_back(DataStructure::Global::kMuPlus);
pids.push_back(DataStructure::Global::kPiPlus);
}
if (charge_hypothesis != 1) {
pids.push_back(DataStructure::Global::kEMinus);
pids.push_back(DataStructure::Global::kMuMinus);
pids.push_back(DataStructure::Global::kPiMinus);
}
}
return pids;
}
void TrackMatching::MatchTrackPoint(
TLorentzVector &position, TLorentzVector &momentum,
const std::vector &spacepoints,
DataStructure::Global::PID pid, BTFieldConstructor* field,
std::string detector_name, DataStructure::Global::Track* hypothesis_track) {
double mass = Particle::GetInstance().GetMass(pid);
double energy = ::sqrt(momentum.Rho()*momentum.Rho() + mass*mass);
double x_in[] = {0., position.X(), position.Y(), position.Z(),
energy, momentum.X(), momentum.Y(), momentum.Z()};
if (spacepoints.size() > 0) {
double target_z = spacepoints.at(0)->get_position().Z();
try {
GlobalTools::propagate(x_in, target_z, field, _max_step_size, pid,
_energy_loss);
// To avoid doing the same propagation again for the same point, store the propagated
// values back in the TLorentzVectors
position.SetX(x_in[1]);
position.SetY(x_in[2]);
position.SetZ(x_in[3]);
momentum.SetX(x_in[5]);
momentum.SetY(x_in[6]);
momentum.SetZ(x_in[7]);
// Temporary container for trackpoints for checking if multiple matches are compatible
std::vector temp_spacepoints;
for (size_t i = 0; i < spacepoints.size(); i++) {
// Check if TrackPoints match and if yes, collect them to later check for consistency
if (GlobalTools::approx(x_in[1], spacepoints.at(i)->get_position().X(),
_matching_tolerances.at(detector_name).first) and
GlobalTools::approx(x_in[2], spacepoints.at(i)->get_position().Y(),
_matching_tolerances.at(detector_name).second)) {
temp_spacepoints.push_back(spacepoints.at(i));
Squeak::mout(Squeak::debug) << "TrackMatching: "
<< detector_name << " Match" << std::endl;
} else {
Squeak::mout(Squeak::debug) << "TrackMatching: " << detector_name
<< " Mismatch, dx, dy are:\n"
<< x_in[1] - spacepoints.at(i)->get_position().X() << " "
<< x_in[2] - spacepoints.at(i)->get_position().Y() << std::endl;
}
}
// If there are multiple matches, this checks if they could have been from the same particle
AddIfConsistent(temp_spacepoints, hypothesis_track);
} catch (Exceptions::Exception exc) {
Squeak::mout(Squeak::error) << exc.what() << std::endl;
}
}
}
void TrackMatching::MatchTOF0(
const TLorentzVector &position, const TLorentzVector &momentum,
double tof1_z, double tof1_t,
const std::vector &spacepoints,
DataStructure::Global::PID pid, BTFieldConstructor* field,
DataStructure::Global::Track* hypothesis_track) {
double mass = Particle::GetInstance().GetMass(pid);
double energy = ::sqrt(momentum.Rho()*momentum.Rho() + mass*mass);
if (spacepoints.size() > 0) {
double x_in[] = {0., position.X(), position.Y(), position.Z(),
energy, momentum.X(), momentum.Y(), momentum.Z()};
// First propagate to just upstream of TOF1 to get the energy during TOF0-1 transit
try {
GlobalTools::propagate(x_in, tof1_z - 25.0, field, _max_step_size, pid,
_energy_loss);
} catch (Exceptions::Exception exc) {
Squeak::mout(Squeak::error) << exc.what() << std::endl;
}
// Calculate the distance to TOF0 and the approximate distance the particle travelled
double z_distance = tof1_z - spacepoints.at(0)->get_position().Z();
double approx_travel_distance =
z_distance*std::sqrt(x_in[5]*x_in[5] + x_in[6]*x_in[6] + x_in[7]*x_in[7])/x_in[7];
// To account for energy loss in air, calculate approximate energy loss for half the distance
// travelled (to obtain ~average velocity)
G4NistManager* manager = G4NistManager::Instance();
G4Material* air = manager->FindOrBuildMaterial("G4_AIR");
double air_E_loss = GlobalTools::dEdx(air, energy, mass)*approx_travel_distance*0.5;
GlobalTools::changeEnergy(x_in, air_E_loss, mass);
double velocity = (x_in[7] / x_in[4]) * CLHEP::c_light;
// Compare reconstructed delta T with expected travel time
// Change later to be set by datacards
double deltaTMin = (z_distance/velocity) - _matching_tolerances.at("TOF0").first;
double deltaTMax = (z_distance/velocity) + _matching_tolerances.at("TOF0").first;
// Temporary container for trackpoints for checking if multiple matches are compatible
std::vector temp_spacepoints;
for (size_t i = 0; i < spacepoints.size(); i++) {
double deltaT = tof1_t - spacepoints.at(i)->get_position().T();
if (deltaT > deltaTMin and deltaT < deltaTMax) {
temp_spacepoints.push_back(spacepoints.at(i));
Squeak::mout(Squeak::debug) << "TrackMatching: TOF0 Match"
<< std::endl;
} else {
Squeak::mout(Squeak::debug) << "TrackMatching: TOF0 Mismatch, "
<< "dT is " << deltaT << " when expected between " << deltaTMin
<< " and " << deltaTMax << std::endl;
}
}
AddIfConsistent(temp_spacepoints, hypothesis_track);
}
}
void TrackMatching::MatchEMRTrack(
const TLorentzVector &position, const TLorentzVector &momentum,
DataStructure::Global::TrackPArray* emr_track_array,
DataStructure::Global::PID pid, BTFieldConstructor* field,
DataStructure::Global::Track* hypothesis_track) {
double mass = Particle::GetInstance().GetMass(pid);
double energy = ::sqrt(momentum.Rho()*momentum.Rho() + mass*mass);
// Here we need to iterate over the EMR tracks first, as they might have
// different starting z. Given expected particle rates at the EMR and the
// way the EMR would handle multiple particles, we don't need to take great
// care with multiple matches and will just stop iterating after the first
// match
bool matched = false;
for (auto emr_track_iter = emr_track_array->begin();
emr_track_iter != emr_track_array->end();
++emr_track_iter) {
std::vector emr_trackpoints =
(*emr_track_iter)->GetTrackPoints();
double x_in[] = {0., position.X(), position.Y(), position.Z(),
energy, momentum.X(), momentum.Y(), momentum.Z()};
TLorentzVector first_hit_pos = emr_trackpoints[0]->get_position();
TLorentzVector first_hit_pos_err = emr_trackpoints[0]->get_position_error();
double target_z = first_hit_pos.Z();
try {
GlobalTools::propagate(x_in, target_z, field, _max_step_size, pid,
_energy_loss);
if (GlobalTools::approx(x_in[1], first_hit_pos.X(),
first_hit_pos_err.X()*::sqrt(12)*
_matching_tolerances.at("EMR").first) and
GlobalTools::approx(x_in[2], first_hit_pos.Y(),
first_hit_pos_err.Y()*::sqrt(12)*
_matching_tolerances.at("EMR").second)) {
matched = true;
Squeak::mout(Squeak::debug) << "TrackMatching: EMR Match" << std::endl;
hypothesis_track->set_emr_range_primary(
(*emr_track_iter)->get_emr_range_primary());
for (size_t i = 0; i < emr_trackpoints.size(); i++) {
DataStructure::Global::TrackPoint* emr_tp =
emr_trackpoints[i]->Clone();
emr_tp->set_mapper_name("MapCppGlobalTrackMatching_DS");
TLorentzVector momentum = emr_tp->get_momentum();
double energy = ::sqrt(momentum.Rho()*momentum.Rho() + mass*mass);
momentum.SetE(energy);
emr_tp->set_momentum(momentum);
hypothesis_track->AddTrackPoint(emr_tp);
}
} else {
Squeak::mout(Squeak::debug)
<< "TrackMatching: EMR Mismatch, dx, dy are:\n"
<< x_in[1] - first_hit_pos.X() << " "
<< x_in[2] - first_hit_pos.Y() << std::endl;
}
} catch (Exceptions::Exception exc) {
Squeak::mout(Squeak::error) << exc.what() << std::endl;
}
if (matched) {
break;
}
}
}
void TrackMatching::AddTrackerTrackPoints(
DataStructure::Global::Track* tracker_track, std::string mapper_name,
double mass, DataStructure::Global::Track* hypothesis_track) {
std::vector tracker_trackpoints =
tracker_track->GetTrackPoints();
std::sort(tracker_trackpoints.begin(), tracker_trackpoints.end(),
GlobalTools::TrackPointSort);
for (size_t i = 0; i < tracker_trackpoints.size(); i++) {
DataStructure::Global::TrackPoint* tracker_tp =
tracker_trackpoints[i]->Clone();
tracker_tp->set_mapper_name(mapper_name);
TLorentzVector momentum = tracker_tp->get_momentum();
double energy = ::sqrt(momentum.Rho()*momentum.Rho() + mass*mass);
momentum.SetE(energy);
tracker_tp->set_momentum(momentum);
hypothesis_track->AddTrackPoint(tracker_tp);
}
}
void TrackMatching::USDSTracks(
DataStructure::Global::TrackPArray* global_tracks,
DataStructure::Global::PID pid,
DataStructure::Global::TrackPArray* us_tracks,
DataStructure::Global::TrackPArray* ds_tracks) {
for (auto global_track_iter = global_tracks->begin();
global_track_iter != global_tracks->end();
++global_track_iter) {
if (((*global_track_iter)->get_mapper_name() ==
"MapCppGlobalTrackMatching_US") and
((*global_track_iter)->HasDetector(DataStructure::Global::kTOF1)) and
((*global_track_iter)->get_pid() == pid)) {
us_tracks->push_back(*global_track_iter);
} else if (((*global_track_iter)->get_mapper_name() ==
"MapCppGlobalTrackMatching_DS") and
((*global_track_iter)->HasDetector(
DataStructure::Global::kTOF2)) and
((*global_track_iter)->get_pid() == pid)) {
ds_tracks->push_back(*global_track_iter);
}
}
}
void TrackMatching::MatchUSDS(
DataStructure::Global::Track* us_track,
DataStructure::Global::Track* ds_track,
DataStructure::Global::PID pid) {
DataStructure::Global::TrackPointCPArray us_trackpoints =
us_track->GetTrackPoints();
DataStructure::Global::TrackPointCPArray ds_trackpoints =
ds_track->GetTrackPoints();
// Obtain TOF1 and TOF2 times to calculate the effective speed of the particle
// between the detectors
double TOF1_time = TOFTimeFromTrackPoints(us_trackpoints,
DataStructure::Global::kTOF1);
double TOF2_time = TOFTimeFromTrackPoints(ds_trackpoints,
DataStructure::Global::kTOF2);
double TOFdT = TOF2_time - TOF1_time;
if ((TOFdT > _matching_tolerances.at("TOF12dT").first) and
(TOFdT < _matching_tolerances.at("TOF12dT").second)) {
DataStructure::Global::Track* through_track =
new DataStructure::Global::Track();
through_track->set_mapper_name("MapCppGlobalTrackMatching_Through");
through_track->set_pid(pid);
Squeak::mout(Squeak::debug) << "TrackMatching: US & DS Matched"
<< std::endl;
// Assemble through track from trackpoints from the matched US and DS tracks
for (auto trackpoint_iter = us_trackpoints.begin();
trackpoint_iter != us_trackpoints.end();
++trackpoint_iter) {
through_track->AddTrackPoint(
const_cast(*trackpoint_iter));
}
for (auto trackpoint_iter = ds_trackpoints.begin();
trackpoint_iter != ds_trackpoints.end();
++trackpoint_iter) {
through_track->AddTrackPoint(
const_cast(*trackpoint_iter));
}
through_track->set_emr_range_primary(ds_track->get_emr_range_primary());
through_track->set_emr_plane_density(ds_track->get_emr_plane_density());
through_track->AddTrack(us_track);
through_track->AddTrack(ds_track);
_global_event->add_track(through_track);
} else {
// There is a small memory leak here, but deleting the tracks here won't work
// Might require a fair bit of rewrite, so not sure right now if worth it.
// delete us_track;
// delete ds_track;
}
}
double TrackMatching::TOFTimeFromTrackPoints(
DataStructure::Global::TrackPointCPArray trackpoints,
DataStructure::Global::DetectorPoint detector) {
double TOF_time = 0.0;
for (auto trackpoint_iter = trackpoints.begin();
trackpoint_iter != trackpoints.end();
++trackpoint_iter) {
if ((*trackpoint_iter)->get_detector() == detector) {
TOF_time = (*trackpoint_iter)->get_position().T();
}
}
return TOF_time;
}
void TrackMatching::AddIfConsistent(std::vector spacepoints,
DataStructure::Global::Track* hypothesis_track) {
bool consistent = true;
// If there are no trackpoints, we don't have to add anything, if there is
// exactly one, we leave consistent at true so that it gets added in the end
if (spacepoints.size() < 1) {
consistent = false;
} else if (spacepoints.size() > 1) {
// For the KL, we can only compare by y position
if (spacepoints.at(0)->get_detector() == DataStructure::Global::kCalorimeter) {
for (size_t i = 0; i < spacepoints.size() - 1; i++) {
for (size_t j = i + 1; j < spacepoints.size(); j++) {
if (!(GlobalTools::approx(spacepoints.at(i)->get_position().Y(),
spacepoints.at(j)->get_position().Y(), 50.0))) {
consistent = false;
}
}
}
} else {
// Though the detector granularity is different for TOF0, we can use the same
// x and y allowance for all TOFs, 70mm is above one slab and below two slabs
// for all TOFs
for (size_t i = 0; i < spacepoints.size() - 1; i++) {
for (size_t j = i + 1; j < spacepoints.size(); j++) {
if (!(GlobalTools::approx(spacepoints.at(i)->get_position().X(),
spacepoints.at(j)->get_position().X(), 70.0))) {
consistent = false;
}
if (!(GlobalTools::approx(spacepoints.at(i)->get_position().Y(),
spacepoints.at(j)->get_position().Y(), 70.0))) {
consistent = false;
}
if (!(GlobalTools::approx(spacepoints.at(i)->get_position().T(),
spacepoints.at(j)->get_position().T(), 0.5))) {
consistent = false;
}
}
}
}
}
// If we only have one point or multiple consistent ones, we add everything to
// the hypothesis track, else we don't add anything as we can't tell which
// trackpoint actually belongs to the track
if (consistent) {
for (size_t i = 0; i < spacepoints.size(); i++) {
DataStructure::Global::TrackPoint* trackpoint =
new DataStructure::Global::TrackPoint(spacepoints.at(i));
trackpoint->set_mapper_name(_mapper_name);
hypothesis_track->AddTrackPoint(trackpoint);
}
}
return;
}
} // ~namespace global
} // ~namespace recon
} // ~namespace MAUS