/* 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 {
// Urk! This needs serious refactor
// abstract out to
// "TrackMatch which takes a track hypothesis and returns the resultant track + boolean pass/fail"
// These counters are for debugging porpoises
int TrackMatching::through_track_propagate_no_ds = 0;
int TrackMatching::through_track_propagate_passes = 0;
int TrackMatching::through_track_tof_passes = 0;
int TrackMatching::through_track_trials = 0;
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,
energy_loss_algorithm energy_loss, bool residuals, TrackMatching::geometry_algorithm geo_algo,
std::vector extra_z_planes, TrackMatching::through_track_algorithm through_algo) {
_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;
_residuals = residuals;
_geo_algo = geo_algo;
_extra_z_planes = extra_z_planes;
_through_algo = through_algo;
}
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 = NULL;
if (!no_check) {
// Load the magnetic field for RK4 propagation
field = Globals::GetMCFieldConstructor();
_field = field;
}
// 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);
// Create Primary Chain for this tracker track, declare as orphan initially,
// change later if matched
DataStructure::Global::PrimaryChain* us_primary_chain =
new DataStructure::Global::PrimaryChain("MapCppGlobalTrackMatching",
DataStructure::Global::kUSOrphan);
// 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");
hypothesis_track->set_pid(pids[i]);
hypothesis_track->set_p_value(tracker0_track->get_p_value());
hypothesis_track->set_tracker_clusters(tracker0_track->get_tracker_clusters());
// 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;
// first we make the track time self-consistent with station 5
// next we try to tie into TOF1
MatchTrackPoint(position, momentum, TOF1_sp, pids[i], field, "TOF1",
hypothesis_track);
std::vector ht_tof1_tps =
hypothesis_track->GetTrackPoints(DataStructure::Global::kTOF1);
bool velocity_match_tof0 = false;
if (velocity_match_tof0 && 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 {
MatchTrackPoint(position, momentum, TOF0_sp, pids[i], field, "TOF0",
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);
}
}
// 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",
mass, hypothesis_track);
// Add reference to the tracker track to the hypothesis track
hypothesis_track->AddTrack(tracker0_track);
FixTrackerTime(hypothesis_track, true, pids[i]);
us_primary_chain->AddMatchedTrack(hypothesis_track);
// We had to add TOF0 before TOF1, and then TKU, so the order isn't right
hypothesis_track->SortTrackPointsByZ();
// Apply the timing offset to make the propagated times consistent with
// TOF1
OffsetTOFTime("TOF1", hypothesis_track);
_global_event->add_track_recursive(hypothesis_track);
}
// Only add to global event if we have at least one matched track
if (us_primary_chain->GetMatchedTracks().size() > 0) {
_global_event->add_primary_chain(us_primary_chain);
}
}
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.second) {
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 = NULL;
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);
// Create Primary Chain for this tracker track, declare as orphan initially,
// change later if matched
DataStructure::Global::PrimaryChain* ds_primary_chain =
new DataStructure::Global::PrimaryChain("MapCppGlobalTrackMatching",
DataStructure::Global::kDSOrphan);
// 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();
FixTrackerTime(tracker1_track, false, pids[i]);
hypothesis_track->set_mapper_name("MapCppGlobalTrackMatching");
hypothesis_track->set_pid(pids[i]);
hypothesis_track->set_p_value(tracker1_track->get_p_value());
hypothesis_track->set_tracker_clusters(tracker1_track->get_tracker_clusters());
// This time we add in the tracker trackpoints first
double mass = Particle::GetInstance().GetMass(pids[i]);
AddTrackerTrackPoints(tracker1_track, "MapCppGlobalTrackMatching",
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);
}
Squeak::mout(Squeak::debug) << "TrackMatching: EMR Added (No Check)" << std::endl;
}
}
// Add reference to the tracker track to the hypothesis track
hypothesis_track->AddTrack(tracker1_track);
// Apply the timing offset to make the propagated times consistent with
// TOF2
OffsetTOFTime("TOF2", hypothesis_track);
ds_primary_chain->AddMatchedTrack(hypothesis_track);
_global_event->add_track_recursive(hypothesis_track);
std::vector tp = hypothesis_track->GetTrackPoints();
}
// Only add to global event if we have at least one matched track
if (ds_primary_chain->GetMatchedTracks().size() > 0) {
_global_event->add_primary_chain(ds_primary_chain);
}
}
delete scifi_track_array;
delete emr_track_array;
}
std::ostream& operator<<(std::ostream& out, const TLorentzVector& vec) {
out << vec.X() << " " << vec.Y() << " " << vec.Z() << "; " << vec.T();
return out;
}
bool TrackMatching::throughMatchPropagate(
DataStructure::Global::Track* us_track,
DataStructure::Global::Track* ds_track,
DataStructure::Global::PID pid,
DataStructure::Global::Track* through_track) {
using DataStructure::Global::TrackPoint;
if (!us_track or
!us_track->HasDetector(DataStructure::Global::kGlobalTracker0_1)) {
Squeak::mout(Squeak::debug) << "ThroughMatch (Propagate) missing TKU track" << std::endl;
return false;
}
if (through_track == NULL) {
return false;
}
ClearVirtualTrackPoints();
const MAUS::DataStructure::Global::TrackPoint* us_tp_1 =
us_track->GetTrackPoints(DataStructure::Global::kGlobalTracker0_1).back();
through_track->set_mapper_name("MapCppGlobalTrackMatching");
through_track->set_pid(pid);
std::vector tp_vecs;
if (ds_track) {
tp_vecs = ds_track->GetTrackPoints();
}
TLorentzVector pos_us = us_tp_1->get_position();
TLorentzVector mom_us = us_tp_1->get_momentum();
double mass = Particle::GetInstance().GetMass(pid);
double energy = ::sqrt(mom_us.Rho()*mom_us.Rho() + mass*mass);
double x_in[] = {pos_us.T(), pos_us.X(), pos_us.Y(), pos_us.Z(),
energy, mom_us.X(), mom_us.Y(), mom_us.Z()};
for (size_t i = 0; i < tp_vecs.size(); ++i) {
if (tp_vecs[i]->get_detector() == DataStructure::Global::kVirtual) {
// we propagate to real detectors only; we should pick up
// virtuals anyway by the "AddVirtualTrackPoints" mechanism
continue;
}
if (static_cast(tp_vecs[i]->get_detector())
>= DataStructure::Global::kGlobalOffset) {
// we propagate to real detectors only; we should pick up
// global detectors when we cross the real detectors
continue;
}
double target_z = tp_vecs[i]->get_position().Z();
try {
Propagate(x_in, _field, pid, target_z);
} catch (std::exception& exc) {
break;
}
if (fabs(x_in[3] - target_z) > 1e-9) {
break;
}
TLorentzVector pos_ds(x_in[1], x_in[2], x_in[3], x_in[0]); // x, y, z, t
TLorentzVector mom_ds(x_in[5], x_in[6], x_in[7], x_in[4]); // px, py, pz, E
MAUS::DataStructure::Global::TrackPoint* tp =
new MAUS::DataStructure::Global::TrackPoint();
tp->set_position(pos_ds);
tp->set_momentum(mom_ds);
tp->set_charge(through_track->get_charge());
tp->set_mapper_name(through_track->get_mapper_name());
tp->set_space_point(tp_vecs[i]->get_space_point());
tp->set_detector(convertToGlobal(tp_vecs[i]->get_detector()));
tp->set_particle_event(tp_vecs[i]->get_particle_event());
through_track->AddTrackPoint(tp);
TrackPoint* det_tp = const_cast(tp_vecs[i]);
through_track->AddTrackPoint(det_tp);
}
// always propagate to the last extra_z_plane
if (_extra_z_planes.size() > 0 && _extra_z_planes.back() > x_in[3]) {
Propagate(x_in, _field, pid, _extra_z_planes.back());
}
addTrackRecursive(through_track, us_track, false, true);
AddVirtualTrackPoints(through_track);
ClearVirtualTrackPoints();
through_track->SortTrackPointsByZ();
if (not through_track->HasDetector(DataStructure::Global::kTracker1_1)) {
Squeak::mout(Squeak::debug) << "ThroughMatch (Propagate) missing TKD track" << std::endl;
return false; // tracking failed
}
double pos_tolerance = _matching_tolerances.at("TKD").first;
double mom_tolerance = _matching_tolerances.at("TKD").second;
if (!ds_track->HasDetector(DataStructure::Global::kGlobalTracker1_1) or
!through_track->HasDetector(DataStructure::Global::kGlobalTracker1_1)) {
Squeak::mout(Squeak::debug)
<< "ThroughMatch (Propagate) missing TKD track point" << std::endl;
return false; // tracking failed
}
const MAUS::DataStructure::Global::TrackPoint* ds_recon =
ds_track->GetTrackPoints(DataStructure::Global::kGlobalTracker1_1)[0];
const MAUS::DataStructure::Global::TrackPoint* ds_through =
through_track->GetTrackPoints(DataStructure::Global::kGlobalTracker1_1)[0];
TVector3 dpos = ds_recon->get_position().Vect() - ds_through->get_position().Vect();
TVector3 dmom = ds_recon->get_momentum().Vect() - ds_through->get_momentum().Vect();
Squeak::mout(Squeak::debug) << "ThroughMatch (Propagate) "
<< "checking tolerances " << std::endl;
Squeak::mout(Squeak::debug) << " Recon Pos: " << ds_recon->get_position()
<< " Mom: " <get_momentum() << std::endl;
Squeak::mout(Squeak::debug) << " Thru Pos: " << ds_through->get_position()
<< " Mom: " <get_momentum() << std::endl;
Squeak::mout(Squeak::debug) << " Deltas r: " << dpos.Mag()
<< " p: " << dmom.Mag() << std::endl;
Squeak::mout(Squeak::debug) << " Tolerances r: " << pos_tolerance
<< " p: " << mom_tolerance << std::endl;
dpos.SetZ(0.);
if (dpos.Mag() < pos_tolerance and dmom.Mag() < mom_tolerance) {
Squeak::mout(Squeak::debug) << " Accepted" << std::endl;
// Assemble through track from trackpoints from the matched US and DS tracks
Squeak::mout(Squeak::debug) << "TrackMatching: US & DS Matched" << std::endl;
// so that user can distinguish between TKU extrapolated to TKD/TOF2 and
// TKD extrapolated to TOF2, we leave the TKD extrapolated in the child
// track; note that this is different behaviour to throughMatchTOF.
through_track->AddTrack(ds_track);
through_track->SortTrackPointsByZ();
return true;
} else {
// There may be a small memory leak here because the US and DS tracks don't get
// deleted, deleting them here manually causes a segfault. TODO: Investigate
Squeak::mout(Squeak::debug) << " Rejected" << std::endl;
return false;
}
}
bool TrackMatching::throughMatchTOF(
DataStructure::Global::Track* us_track,
DataStructure::Global::Track* ds_track,
DataStructure::Global::PID pid,
DataStructure::Global::Track* through_track) {
if (!us_track or !ds_track) {
return false;
}
ofstream throughfile;
if (_residuals) {
throughfile.open("match_through.csv", std::ios::out | std::ios::app);
}
if (!us_track->HasDetector(DataStructure::Global::kTOF1) or
!ds_track->HasDetector(DataStructure::Global::kTOF2)) {
return false;
}
// Get TOF1&2 times to calculate effective particle speed between detectors
DataStructure::Global::TrackPointCPArray us_trackpoints = us_track->GetTrackPoints();
DataStructure::Global::TrackPointCPArray ds_trackpoints = ds_track->GetTrackPoints();
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 (_residuals) {
throughfile << TOFdT/_matching_tolerances.at("TOF12dT").second << "\n";
}
if ((TOFdT > _matching_tolerances.at("TOF12dT").first) and
(TOFdT < _matching_tolerances.at("TOF12dT").second)) {
Squeak::mout(Squeak::debug) << "TrackMatching (TOF12): US & DS Matched" << std::endl;
through_track->set_mapper_name("MapCppGlobalTrackMatching");
through_track->set_pid(pid);
addTrackRecursive(through_track, us_track, false, true);
addTrackRecursive(through_track, ds_track, true, true);
return true;
} else {
return false;
}
}
void TrackMatching::addTrackRecursive(DataStructure::Global::Track* parent,
DataStructure::Global::Track* child,
bool doEMR, bool addVirtualTrackPoints) {
parent->AddTrack(child);
DataStructure::Global::TrackPointCPArray tps = child->GetTrackPoints();
for (auto trackpoint_iter = tps.begin();
trackpoint_iter != tps.end();
++trackpoint_iter) {
if (!addVirtualTrackPoints and
(*trackpoint_iter)->get_detector() == DataStructure::Global::kVirtual) {
continue;
}
parent->AddTrackPoint(
const_cast(*trackpoint_iter));
}
if (doEMR) {
parent->set_emr_range_primary(child->get_emr_range_primary());
parent->set_emr_plane_density(child->get_emr_plane_density());
}
}
void TrackMatching::throughTrack() {
if (_through_algo == kNoThroughMatching) {
return;
}
std::vector us_chains =
_global_event->GetUSPrimaryChainOrphans();
std::vector ds_chains =
_global_event->GetDSPrimaryChainOrphans();
std::vector pids = PIDHypotheses(0, _pid_hypothesis_string);
for (auto us_chain_iter = us_chains.begin();
us_chain_iter != us_chains.end(); ++us_chain_iter) {
// if there is no downstream track and propagation is enable, we at least propagate
// the upstream track through to virtual detectors
if (ds_chains.size() == 0 &&
(_through_algo == kPropagate || _through_algo == kPropagateAndTOF12)) {
for (size_t i = 0; i < pids.size(); i++) {
DataStructure::Global::Track* us_track =
(*us_chain_iter)->GetMatchedTrack(pids[i]);
DataStructure::Global::Track* propagate_track =
new DataStructure::Global::Track();
throughMatchPropagate(us_track, NULL, pids[i], propagate_track);
if (propagate_track->GetTrackPoints().size() == 0) {
continue;
}
Squeak::mout(Squeak::debug) << "Made Unmatched track between"
<< propagate_track->GetTrackPoints()[0]->get_position().Z()
<< " and "
<< propagate_track->GetTrackPoints().back()->get_position().Z()
<< std::endl;
_global_event->add_track_recursive(propagate_track);
through_track_propagate_no_ds += 1;
}
}
through_track_trials += 1;
// if there is a downstream track, we attempt to match it
bool passed_through_track = false;
for (auto ds_chain_iter = ds_chains.begin();
ds_chain_iter != ds_chains.end(); ++ds_chain_iter) {
DataStructure::Global::PrimaryChain* through_primary_chain =
new DataStructure::Global::PrimaryChain("MapCppGlobalTrackMatching",
MAUS::DataStructure::Global::kThrough);
for (size_t i = 0; i < pids.size(); i++) {
DataStructure::Global::Track* us_track =
(*us_chain_iter)->GetMatchedTrack(pids[i]);
DataStructure::Global::Track* ds_track =
(*ds_chain_iter)->GetMatchedTrack(pids[i]);
DataStructure::Global::Track* propagate_track = NULL;
DataStructure::Global::Track* tof12_track = NULL;
bool tof12_match = false;
bool propagate_match = false;
if (_through_algo == kTOF12 ||
_through_algo == kPropagateRequiringTOF12 ||
_through_algo == kPropagateAndTOF12) {
tof12_track = new DataStructure::Global::Track();
tof12_match = throughMatchTOF(us_track, ds_track, pids[i], tof12_track);
_global_event->add_track_recursive(tof12_track);
}
if ((_through_algo == kPropagateRequiringTOF12 && tof12_match) ||
_through_algo == kPropagate ||
_through_algo == kPropagateAndTOF12) {
propagate_track = new DataStructure::Global::Track();
propagate_match = throughMatchPropagate(us_track, ds_track, pids[i], propagate_track);
_global_event->add_track_recursive(propagate_track);
}
if (propagate_match) {
passed_through_track = true;
through_primary_chain->AddMatchedTrack(propagate_track);
} else if (tof12_match) {
through_primary_chain->AddMatchedTrack(tof12_track);
}
}
if (passed_through_track) {
through_track_propagate_passes += 1;
}
if (through_primary_chain->GetMatchedTracks().size() > 0) {
(*us_chain_iter)->set_chain_type(DataStructure::Global::kUS);
(*ds_chain_iter)->set_chain_type(DataStructure::Global::kDS);
through_primary_chain->SetUSDaughter(*us_chain_iter);
through_primary_chain->SetDSDaughter(*ds_chain_iter);
_global_event->add_primary_chain(through_primary_chain);
}
}
}
CheckChainMultiplicity();
}
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();
if (imported_tracks == NULL) {
return track_array;
}
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();
if (global_spacepoint_array == NULL) {
return space_points;
}
for (size_t i = 0; i < global_spacepoint_array->size(); i++) {
if (global_spacepoint_array->at(i) &&
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;
}
bool IsTracker(DataStructure::Global::DetectorPoint det) {
if (static_cast(det) < 22 and static_cast(det) > 9) {
return true;
}
return false;
}
void TrackMatching::FixTrackerTime(
DataStructure::Global::Track* hypothesis_track,
bool is_upstream,
DataStructure::Global::PID pid) {
using DataStructure::Global::TrackPoint;
hypothesis_track->SortTrackPointsByZ();
std::vector tp_vec = hypothesis_track->GetTrackPoints();
// hack up reverse iterator when we are going backwards
std::vector elements;
if (is_upstream) {
for (size_t i = 0; i < tp_vec.size(); ++i) {
bool is_tracker = IsTracker(tp_vec.at(i)->get_detector());
if (is_tracker) {
elements.push_back(i);
}
}
} else {
for (size_t i = 0; i < tp_vec.size(); ++i) {
bool is_tracker = IsTracker(tp_vec.at(i)->get_detector());
if (is_tracker) {
elements.push_back(tp_vec.size() - i - 1);
}
}
}
if (elements.size() == 0) { // no tracker trackpoints
return;
}
std::vector new_track_points;
double mass = Particle::GetInstance().GetMass(pid);
TrackPoint* tp = new TrackPoint(*tp_vec[elements[0]]);
TLorentzVector pos = tp->get_position();
TLorentzVector mom = tp->get_momentum();
tp->set_detector(convertToGlobal(tp->get_detector()));
new_track_points.push_back(tp);
for (size_t i = 1; i < elements.size(); ++i) {
mom.SetT(::sqrt(mom.Rho()*mom.Rho() + mass*mass));
size_t index = elements[i];
tp = new TrackPoint(*tp_vec[index]);
double x_in[] = {pos.T(), pos.X(), pos.Y(), pos.Z(),
mom.T(), mom.X(), mom.Y(), mom.Z()};
Propagate(x_in, _field, hypothesis_track->get_pid(), tp->get_position().Z());
pos = tp->get_position();
mom = tp->get_momentum();
pos.SetT(x_in[0]);
tp->set_position(pos);
tp->set_detector(convertToGlobal(tp->get_detector()));
new_track_points.push_back(tp);
}
for (size_t i = 0; i < new_track_points.size(); ++i) {
hypothesis_track->AddTrackPoint(new_track_points[i]);
}
AddVirtualTrackPoints(hypothesis_track);
ClearVirtualTrackPoints();
hypothesis_track->SortTrackPointsByZ();
}
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[] = {position.T(), position.X(), position.Y(), position.Z(),
energy, momentum.X(), momentum.Y(), momentum.Z()};
ofstream tof1file;
ofstream tof2file;
ofstream klfile;
if (_residuals) {
tof1file.open("match_tof1.csv", std::ios::out | std::ios::app);
tof2file.open("match_tof2.csv", std::ios::out | std::ios::app);
klfile.open("match_kl.csv", std::ios::out | std::ios::app);
}
if (spacepoints.size() > 0) {
double target_z = spacepoints.at(0)->get_position().Z();
try {
ClearVirtualTrackPoints();
Propagate(x_in, field, pid, target_z);
// To avoid doing the same propagation again for the same point, store the propagated
// values back in the TLorentzVectors
position.SetT(x_in[0]);
position.SetX(x_in[1]);
position.SetY(x_in[2]);
position.SetZ(x_in[3]);
momentum.SetT(x_in[4]);
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++) {
if (_residuals) {
if (detector_name == "TOF1") {
tof1file << spacepoints.at(i)->get_position().X() - x_in[1] << " "
<< spacepoints.at(i)->get_position().Y() - x_in[2] << "\n";
} else if (detector_name == "TOF2") {
tof2file << spacepoints.at(i)->get_position().X() - x_in[1] << " "
<< spacepoints.at(i)->get_position().Y() - x_in[2] << "\n";
} else if (detector_name == "KL") {
klfile << spacepoints.at(i)->get_position().Y() - x_in[2] << " " << x_in[4] << "\n";
}
}
// Check if TrackPoints match and if yes, collect them to later check for consistency
if (detector_name == "TOF0" or
(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;
}
// try to catch virtual plane on US edge of TOF0
if (detector_name == "TOF0") {
Propagate(x_in, field, pid, target_z-100.);
}
}
// If there are multiple matches, this checks if they could have been from the same particle
AddIfConsistent(temp_spacepoints, position, momentum, hypothesis_track);
if (detector_name != "TOF1" and detector_name != "TOF2") {
return;
}
if (temp_spacepoints.size() == 0) {
return;
}
// set the time to be consistent with any tof1 track points
double temp_sp_time = temp_spacepoints.at(0)->get_position().T();
double thisDeltaT = x_in[0] - temp_sp_time;
if (detector_name == "TOF1") {
_upstreamDeltaT = thisDeltaT;
} else {
_downstreamDeltaT = thisDeltaT;
}
} catch (Exceptions::Exception exc) {
Squeak::mout(Squeak::debug) << exc.what() << std::endl;
}
}
}
void TrackMatching::OffsetTOFTime(
std::string detector_name,
DataStructure::Global::Track* hypothesis_track) {
using DataStructure::Global::TrackPoint;
double thisDeltaT = 0.;
if (detector_name == "TOF1") {
thisDeltaT = _upstreamDeltaT;
} else if (detector_name == "TOF2") {
thisDeltaT = _downstreamDeltaT;
}
for (size_t i = 0; i < hypothesis_track->GetTrackPoints().size(); ++i) {
TrackPoint* tp =
const_cast(hypothesis_track->GetTrackPoints()[i]);
DataStructure::Global::DetectorPoint det = tp->get_detector();
// if it is a real detector hit, don't change it
if (det != DataStructure::Global::kVirtual and
det < DataStructure::Global::kGlobalOffset) {
continue;
}
TLorentzVector pos_vector = tp->get_position();
pos_vector.SetT(pos_vector.T()-thisDeltaT);
tp->set_position(pos_vector);
}
}
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) {
ofstream tof0file;
if (_residuals) {
tof0file.open("match_tof0.csv", std::ios::out | std::ios::app);
}
double mass = Particle::GetInstance().GetMass(pid);
double energy = ::sqrt(momentum.Rho()*momentum.Rho() + mass*mass);
if (spacepoints.size() > 0) {
double x_in[] = {position.T(), 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 {
ClearVirtualTrackPoints();
Propagate(x_in, field, pid, tof1_z - 25.0);
} catch (Exceptions::Exception exc) {
Squeak::mout(Squeak::debug) << 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 (_residuals) {
tof0file << deltaT - (z_distance/velocity) << " " << deltaT + x_in[0] << "\n";
}
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;
}
}
TLorentzVector position, momentum;
position.SetZ(spacepoints.at(0)->get_position().Z());
position.SetT(tof1_t-(z_distance/velocity));
momentum.SetZ(x_in[7]);
momentum.SetT(x_in[4]);
AddIfConsistent(temp_spacepoints, position, momentum, hypothesis_track);
}
}
void MatchTOF0Alt(
const TLorentzVector &position, const TLorentzVector &momentum,
DataStructure::Global::PID pid,
DataStructure::Global::Track* 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;
ofstream emrfile;
if (_residuals) {
emrfile.open("match_emr.csv", std::ios::out | std::ios::app);
}
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 {
ClearVirtualTrackPoints();
Propagate(x_in, field, pid, target_z);
if (_residuals) {
emrfile << first_hit_pos.X() - x_in[1] << " " << first_hit_pos.Y() - x_in[2] << "\n";
}
if (GlobalTools::approx(x_in[1], first_hit_pos.X(), _matching_tolerances.at("EMR").first) and
GlobalTools::approx(x_in[2], first_hit_pos.Y(), _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());
hypothesis_track->set_emr_plane_density(
(*emr_track_iter)->get_emr_plane_density());
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);
}
AddVirtualTrackPoints(hypothesis_track);
ClearVirtualTrackPoints();
} 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::debug) << 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);
}
}
int TrackMatching::PropagateStep(double* x_in,
BTFieldConstructor* field,
DataStructure::Global::PID pid,
double target_z) {
int success = GlobalTools::propagate(x_in, target_z, field, _max_step_size, pid,
_energy_loss, static_cast(_geo_algo));
if (success == 1) { // something went wrong...
return success;
}
DataStructure::Global::TrackPoint tp;
tp.set_position(TLorentzVector(x_in[1], x_in[2], x_in[3], x_in[0]));
tp.set_momentum(TLorentzVector(x_in[5], x_in[6], x_in[7], x_in[4]));
_virtual_track_points.push_back(tp);
return success;
}
void TrackMatching::Propagate(double* x_in,
BTFieldConstructor* field,
DataStructure::Global::PID pid,
double target_z) {
std::vector::iterator start, end;
int success = 0;
if (target_z > x_in[3]) {
start = std::lower_bound(_extra_z_planes.begin(),
_extra_z_planes.end(), x_in[3]);
end = std::lower_bound(_extra_z_planes.begin(),
_extra_z_planes.end(), target_z);
for (/**/; start <= end && start < _extra_z_planes.end() && success == 0; ++start) {
success = PropagateStep(x_in, field, pid, *start);
}
success = GlobalTools::propagate(x_in, target_z, field, _max_step_size, pid,
_energy_loss, static_cast(_geo_algo));
} else {
start = std::lower_bound(_extra_z_planes.begin(),
_extra_z_planes.end(), target_z)+1;
end = std::lower_bound(_extra_z_planes.begin(),
_extra_z_planes.end(), x_in[3]);
for (/**/; start <= end && end >= _extra_z_planes.begin() && success == 0; --end) {
success = PropagateStep(x_in, field, pid, *end);
}
success = GlobalTools::propagate(x_in, target_z, field, _max_step_size, pid,
_energy_loss, static_cast(_geo_algo));
}
}
void TrackMatching::AddVirtualTrackPoints(DataStructure::Global::Track* hypothesis_track) {
int particle_event = -1;
if (hypothesis_track->GetTrackPoints().size() > 0) {
particle_event = hypothesis_track->GetTrackPoints()[0]->get_particle_event();
}
for (size_t i = 0; i < _virtual_track_points.size(); ++i) {
DataStructure::Global::SpacePoint* sp =
new DataStructure::Global::SpacePoint();
sp->set_detector(DataStructure::Global::kVirtual);
sp->set_charge(hypothesis_track->get_charge());
sp->set_mapper_name(_mapper_name);
DataStructure::Global::TrackPoint* tp =
new DataStructure::Global::TrackPoint(_virtual_track_points[i]);
tp->set_detector(DataStructure::Global::kVirtual);
tp->set_charge(hypothesis_track->get_charge());
tp->set_mapper_name(_mapper_name);
tp->set_space_point(sp);
tp->set_particle_event(particle_event);
hypothesis_track->AddTrackPoint(tp);
}
}
DataStructure::Global::DetectorPoint TrackMatching::convertToGlobal(
DataStructure::Global::DetectorPoint det) const {
int int_det = static_cast(det);
int_det += MAUS::DataStructure::Global::kGlobalOffset;
if (int_det > MAUS::DataStructure::Global::kDetectorPointSize) {
return det;
}
MAUS::DataStructure::Global::DetectorPoint global_det =
static_cast(int_det);
return global_det;
}
void TrackMatching::ClearVirtualTrackPoints() {
_virtual_track_points = std::vector();
}
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;
}
bool TrackMatching::AddIfConsistent(std::vector spacepoints,
TLorentzVector extrapolated_position,
TLorentzVector extrapolated_momentum,
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);
DataStructure::Global::TrackPoint* extrapolated_tp =
new DataStructure::Global::TrackPoint(*trackpoint);
extrapolated_tp->set_position(extrapolated_position);
extrapolated_tp->set_momentum(extrapolated_momentum);
extrapolated_tp->set_detector(convertToGlobal(trackpoint->get_detector()));
hypothesis_track->AddTrackPoint(extrapolated_tp);
}
AddVirtualTrackPoints(hypothesis_track);
ClearVirtualTrackPoints();
}
return consistent;
}
void TrackMatching::CheckChainMultiplicity() {
std::vector through_chains =
_global_event->GetThroughPrimaryChains();
std::vector > multiplicities
(through_chains.size(), std::make_pair(false, false));
// Last execution won't reach the inner loop but is necessary for assignment of enums at the end
for (size_t i = 0; i < through_chains.size(); i++) {
for (size_t j = i + 1; j < through_chains.size(); j++) {
if (through_chains.at(i)->GetUSDaughter() == through_chains.at(j)->GetUSDaughter()) {
multiplicities.at(i).first = true;
multiplicities.at(j).first = true;
}
if (through_chains.at(i)->GetDSDaughter() == through_chains.at(j)->GetDSDaughter()) {
multiplicities.at(i).second = true;
multiplicities.at(j).second = true;
}
}
if (multiplicities.at(i).first and multiplicities.at(i).second) {
through_chains.at(i)->set_multiplicity(DataStructure::Global::kMultipleBoth);
} else if (multiplicities.at(i).first) {
through_chains.at(i)->set_multiplicity(DataStructure::Global::kMultipleUS);
} else if (multiplicities.at(i).second) {
through_chains.at(i)->set_multiplicity(DataStructure::Global::kMultipleDS);
}
}
}
} // ~namespace global
} // ~namespace recon
} // ~namespace MAUS