Commit 2c6759e5 authored by Simon Spannagel's avatar Simon Spannagel
Browse files

Merge branch 'master' into eudaq_tags

parents e934aca5 fd1e6945
......@@ -169,9 +169,9 @@ The detector configuration consists of a set of sections describing the detector
Each section starts with a header describing the name used to identify the detector; all names are required to be unique.
Every detector should contain all of the following parameters:
\begin{itemize}
\item The \parameter{role} parameter is an array of strings indicating the function(s) of the respective detector. This can be \parameter{dut} or \parameter{reference}, the default is \parameter{none}. With the default, the respective detector participates in tracking but is neither used as reference plane for alignment and correlations, nur treated as DUT. As reference, the detector is used as anchor for relative alignments, and its position and orientation is used to produce correlation plots. As DUT, the detector is by default excluded from tracking, and all DUT-type modules are executed for this detector.
\item The \parameter{role} parameter is an array of strings indicating the function(s) of the respective detector. This can be \parameter{dut}, \parameter{reference} (\parameter{ref}) or \parameter{auxiliary} (\parameter{aux}), the default is \parameter{none}. With the default, the respective detector participates in tracking but is neither used as reference plane for alignment and correlations, nor treated as DUT. As reference, the detector is used as anchor for relative alignments, and its position and orientation is used to produce correlation plots. As DUT, the detector is by default excluded from tracking, and all DUT-type modules are executed for this detector. As auxiliary device, the detector may provide additional information but does not partake in the reconstruction, this is useful to e.g. include trigger logic units (TLUs) providing timing information.
\begin{warning}
There always has to be exactly \emph{one} reference detector in the setup. For setups with a single detector only, the role should be configured as \parameter{dut, reference} for the detector to act as both.
There always has to be exactly \emph{one} reference detector in the setup. For setups with a single detector only, the role should be configured as \parameter{dut, reference} for the detector to act as both. Auxiliary devices cannot have any other role simultaneously.
\end{warning}
\item The \parameter{type} parameter is a string describing the type of detector, e.g.\ \parameter{Timepix3} or \parameter{CLICpix2}. This value might be used by some modules to distinguish between different types.
......
......@@ -14,7 +14,12 @@ Some of these targets are used by the project's CI, others are intended for manu
Currently, the following targets are provided:
\begin{description}
\item[\command{make format}] invokes the \command{clang-format} tool to apply the project's coding style convention to all files of the code base. The format is defined in the \file{.clang-format} file in the root directory of the repository and mostly follows the suggestions defined by the standard LLVM style with minor modifications. Most notably are the consistent usage of four whitespace characters as indentation and the column limit of 125 characters.
\item[\command{make format}] invokes the \command{clang-format} tool to apply the project's coding style convention to all files of the code base. The format is defined in the \file{.clang-format} file in the root directory of the repository and mostly follows the suggestions defined by the standard LLVM style with minor modifications. Most notably are the consistent usage of four whitespace characters as indentation and the column limit of 125 characters.
This can be further simplified by installing the \emph{git hook} provided in the directory \dir{/etc/git-hooks/}. A hook is a script called by \command{git} before a certain action. In this case, it is a pre-commit hook which automatically runs \command{clang-format} in the background and offers to update the formatting of the code to be committed. It can be installed by calling
\begin{minted}[frame=single,framesep=3pt,breaklines=true,tabsize=2,linenos]{bash}
./etc/git-hooks/install-hooks.sh
\end{minted}
once.
\item[\command{make check-format}] also invokes the \command{clang-format} tool but does not apply the required changes to the code. Instead, it returns an exit code 0 (pass) if no changes are necessary and exit code 1 (fail) if changes are to be applied. This is used by the CI.
\item[\command{make lint}] invokes the \command{clang-tidy} tool to provide additional linting of the source code. The tool tries to detect possible errors (and thus potential bugs), dangerous constructs (such as uninitialized variables) as well as stylistic errors. In addition, it ensures proper usage of modern C++ standards. The configuration used for the \command{clang-tidy} command can be found in the \file{.clang-tidy} file in the root directory of the repository.
\item[\command{make check-lint}] also invokes the \command{clang-tidy} tool but does not report the issues found while parsing the code. Instead, it returns an exit code 0 (pass) if no errors have been produced and exit code 1 (fail) if issues are present. This is used by the CI.
......
......@@ -29,15 +29,22 @@ Detector::Detector(const Configuration& config) : m_role(DetectorRole::NONE) {
std::transform(role.begin(), role.end(), role.begin(), ::tolower);
if(role == "none") {
m_role |= DetectorRole::NONE;
} else if(role == "reference") {
} else if(role == "reference" || role == "ref") {
m_role |= DetectorRole::REFERENCE;
} else if(role == "dut") {
m_role |= DetectorRole::DUT;
} else if(role == "auxiliary" || role == "aux") {
m_role |= DetectorRole::AUXILIARY;
} else {
throw InvalidValueError(config, "role", "Detector role does not exist.");
}
}
// Auxiliary devices cannot hold other roles:
if(static_cast<bool>(m_role & DetectorRole::AUXILIARY) && m_role != DetectorRole::AUXILIARY) {
throw InvalidValueError(config, "role", "Auxiliary devices cannot hold any other detector role");
}
// Detector position and orientation
m_displacement = config.get<ROOT::Math::XYZPoint>("position", ROOT::Math::XYZPoint());
m_orientation = config.get<ROOT::Math::XYZVector>("orientation", ROOT::Math::XYZVector());
......@@ -105,6 +112,10 @@ bool Detector::isDUT() const {
return static_cast<bool>(m_role & DetectorRole::DUT);
}
bool Detector::isAuxiliary() const {
return static_cast<bool>(m_role & DetectorRole::AUXILIARY);
}
// Functions to set and check channel masking
void Detector::setMaskFile(std::string file) {
m_maskfile = file;
......
......@@ -34,6 +34,8 @@ namespace corryvreckan {
NONE = 0x0, ///< No specific detector role
REFERENCE = 0x1, ///< Reference detector
DUT = 0x2, ///< Detector used as device under test
AUXILIARY = 0x4, ///< Auxiliary device which should not participate in regular reconstruction but might provide
/// additional information
};
inline constexpr DetectorRole operator&(DetectorRole x, DetectorRole y) {
......@@ -96,6 +98,12 @@ namespace corryvreckan {
*/
bool isDUT() const;
/**
* @brief Check whether detector is registered as auxiliary device and should not parttake in the reconstruction
* @return Auxiliary status
*/
bool isAuxiliary() const;
/**
* @brief Retrieve configuration object from detector, containing all (potentially updated) parameters
* @return Configuration object for this detector
......
......@@ -16,7 +16,6 @@ AlignmentMillepede::AlignmentMillepede(Configuration config, std::vector<std::sh
: Module(std::move(config), std::move(detectors)) {
m_excludeDUT = m_config.get<bool>("exclude_dut", false);
m_excludeTLU = m_config.get<bool>("exclude_tlu", true);
m_numberOfTracksForAlignment = m_config.get<size_t>("number_of_tracks", 20000);
m_dofs = m_config.getArray<bool>("dofs", {});
m_nIterations = m_config.get<size_t>("iterations", 5);
......@@ -104,8 +103,8 @@ void AlignmentMillepede::finalise() {
if(det->isDUT() && m_excludeDUT) {
nPlanes--;
}
if(det->type() == "TLU" && m_excludeTLU) {
LOG(DEBUG) << "Excluding TLU.";
if(det->isAuxiliary()) {
LOG(INFO) << "Excluding auxiliary detector " << det->name();
nPlanes--;
}
}
......
......@@ -155,8 +155,6 @@ namespace corryvreckan {
bool m_fix_all;
/// It can be also reasonable to include the DUT in the alignemnt
bool m_excludeDUT;
/// Flag to exclude the TLU from the alignment as it has not pixel hits anyway
bool m_excludeTLU;
};
} // namespace corryvreckan
......
......@@ -13,8 +13,6 @@ The modules stops if the convergence, i.e. the absolute sum of all corrections o
### Parameters
* `exclude_dut` : Exclude the DUT from the alignment procedure. Default value
is `false`.
* `exclude_tlu` : Exclude the TLU from the alignment procedure. Default value
is `true`.
* `number_of_tracks`: Number of tracks used in the alignment method chosen. Default value is `20000`.
* `iterations`: Number of times the chosen alignment method is to be iterated. Default value is `3`.
* `dofs`: Degrees of freedom to be aligned. This parameter should be given as vector of six boolean values for the parameters "Translation X", "Translation Y", "Translation Z", "Rotation X", "Rotation Y" and "Rotation Z". The default setting is an alignment of all parameters except for "Translation Z", i.e. `dofs = true, true, false, true, true, true`.
......
......@@ -11,6 +11,7 @@ AnalysisDUT::AnalysisDUT(Configuration config, std::shared_ptr<Detector> detecto
m_timeCutFrameEdge = m_config.get<double>("time_cut_frameedge", Units::get<double>(20, "ns"));
chi2ndofCut = m_config.get<double>("chi2ndof_cut", 3.);
useClosestCluster = m_config.get<bool>("use_closest_cluster", true);
}
void AnalysisDUT::initialise() {
......@@ -333,139 +334,118 @@ StatusCode AnalysisDUT::run(std::shared_ptr<Clipboard> clipboard) {
auto xmod = static_cast<double>(Units::convert(inpixel.X(), "um"));
auto ymod = static_cast<double>(Units::convert(inpixel.Y(), "um"));
// Get the DUT clusters from the clipboard
Clusters* clusters = reinterpret_cast<Clusters*>(clipboard->get(m_detector->name(), "clusters"));
if(clusters == nullptr) {
LOG(DEBUG) << " - no DUT clusters";
} else {
// Loop over all associated DUT clusters:
for(auto assoc_cluster : track->associatedClusters()) {
LOG(DEBUG) << " - Looking at next associated DUT cluster";
// Loop over all DUT clusters to find matches:
for(auto* cluster : (*clusters)) {
LOG(DEBUG) << " - Looking at next DUT cluster";
// Check distance between track and cluster
ROOT::Math::XYZPoint intercept = track->intercept(cluster->global().z());
// Correlation plots
hTrackCorrelationX->Fill(intercept.X() - cluster->global().x());
hTrackCorrelationY->Fill(intercept.Y() - cluster->global().y());
hTrackCorrelationTime->Fill(track->timestamp() - cluster->timestamp());
double posDiff = sqrt((intercept.X() - cluster->global().x()) * (intercept.X() - cluster->global().x()) +
(intercept.Y() - cluster->global().y()) * (intercept.Y() - cluster->global().y()));
hTrackCorrelationPos->Fill(posDiff);
hTrackCorrelationPosVsCorrelationTime->Fill(track->timestamp() - cluster->timestamp(), posDiff);
auto associated_clusters = track->associatedClusters();
if(std::find(associated_clusters.begin(), associated_clusters.end(), cluster) == associated_clusters.end()) {
LOG(DEBUG) << "No associated cluster found";
hUnassociatedTracksGlobalPosition->Fill(globalIntercept.X(), globalIntercept.Y());
// if closest cluster should be used continue if current associated cluster is not the closest one
if(useClosestCluster) {
if(track->getClosestCluster() != assoc_cluster) {
continue;
}
}
LOG(DEBUG) << "Found associated cluster";
double xdistance = intercept.X() - cluster->global().x();
double ydistance = intercept.Y() - cluster->global().y();
double xabsdistance = fabs(xdistance);
double yabsdistance = fabs(ydistance);
double tdistance = track->timestamp() - cluster->timestamp();
// We now have an associated cluster
has_associated_cluster = true;
// FIXME need to understand local coord of clusters - why shifted? what's normal?
auto clusterLocal = m_detector->globalToLocal(cluster->global());
hClusterMapAssoc->Fill(m_detector->getColumn(clusterLocal), m_detector->getRow(clusterLocal));
hClusterSizeMapAssoc->Fill(m_detector->getColumn(clusterLocal),
m_detector->getRow(clusterLocal),
static_cast<double>(cluster->size()));
// Cluster charge normalized to path length in sensor:
double norm = 1; // FIXME fabs(cos( turn*wt )) * fabs(cos( tilt*wt ));
// FIXME: what does this mean? To my understanding we have the correct charge here already...
auto normalized_charge = cluster->charge() * norm;
// clusterChargeAssoc->Fill(normalized_charge);
clusterChargeAssoc->Fill(cluster->charge());
hClusterChargeMapAssoc->Fill(
m_detector->getColumn(clusterLocal), m_detector->getRow(clusterLocal), cluster->charge());
// Fill per-pixel histograms
for(auto& pixel : (*cluster->pixels())) {
hHitMapAssoc->Fill(pixel->column(), pixel->row());
if(is_within_roi) {
hHitMapROI->Fill(pixel->column(), pixel->row());
}
hPixelRawValueAssoc->Fill(pixel->raw());
hPixelRawValueMapAssoc->Fill(pixel->column(), pixel->row(), pixel->raw());
}
associatedTracksVersusTime->Fill(static_cast<double>(Units::convert(track->timestamp(), "s")));
// Residuals
residualsX->Fill(xdistance);
residualsY->Fill(ydistance);
residualsPos->Fill(sqrt(xdistance * xdistance + ydistance * ydistance));
residualsPosVsresidualsTime->Fill(tdistance, sqrt(xdistance * xdistance + ydistance * ydistance));
if(cluster->size() == 1) {
residualsX1pix->Fill(xdistance);
residualsY1pix->Fill(ydistance);
}
if(cluster->size() == 2) {
residualsX2pix->Fill(xdistance);
residualsY2pix->Fill(ydistance);
// Check distance between track and cluster
ROOT::Math::XYZPoint intercept = track->intercept(assoc_cluster->global().z());
double xdistance = intercept.X() - assoc_cluster->global().x();
double ydistance = intercept.Y() - assoc_cluster->global().y();
double xabsdistance = fabs(xdistance);
double yabsdistance = fabs(ydistance);
double tdistance = track->timestamp() - assoc_cluster->timestamp();
double posDiff =
sqrt((intercept.X() - assoc_cluster->global().x()) * (intercept.X() - assoc_cluster->global().x()) +
(intercept.Y() - assoc_cluster->global().y()) * (intercept.Y() - assoc_cluster->global().y()));
// Correlation plots
hTrackCorrelationX->Fill(xdistance);
hTrackCorrelationY->Fill(ydistance);
hTrackCorrelationTime->Fill(tdistance);
hTrackCorrelationPos->Fill(posDiff);
hTrackCorrelationPosVsCorrelationTime->Fill(track->timestamp() - assoc_cluster->timestamp(), posDiff);
// FIXME need to understand local coord of clusters - why shifted? what's normal?
auto clusterLocal = m_detector->globalToLocal(assoc_cluster->global());
hClusterMapAssoc->Fill(m_detector->getColumn(clusterLocal), m_detector->getRow(clusterLocal));
hClusterSizeMapAssoc->Fill(m_detector->getColumn(clusterLocal),
m_detector->getRow(clusterLocal),
static_cast<double>(assoc_cluster->size()));
// Cluster charge normalized to path length in sensor:
double norm = 1; // FIXME fabs(cos( turn*wt )) * fabs(cos( tilt*wt ));
// FIXME: what does this mean? To my understanding we have the correct charge here already...
auto cluster_charge = assoc_cluster->charge();
auto normalized_charge = cluster_charge * norm;
// clusterChargeAssoc->Fill(normalized_charge);
clusterChargeAssoc->Fill(cluster_charge);
hClusterChargeMapAssoc->Fill(
m_detector->getColumn(clusterLocal), m_detector->getRow(clusterLocal), cluster_charge);
// Fill per-pixel histograms
for(auto& pixel : (*assoc_cluster->pixels())) {
hHitMapAssoc->Fill(pixel->column(), pixel->row());
if(is_within_roi) {
hHitMapROI->Fill(pixel->column(), pixel->row());
}
hPixelRawValueAssoc->Fill(pixel->raw());
hPixelRawValueMapAssoc->Fill(pixel->column(), pixel->row(), pixel->raw());
}
// Time residuals
residualsTime->Fill(tdistance);
residualsTimeVsTime->Fill(tdistance, track->timestamp());
residualsTimeVsSignal->Fill(tdistance, cluster->charge());
associatedTracksVersusTime->Fill(static_cast<double>(Units::convert(track->timestamp(), "s")));
clusterSizeAssoc->Fill(static_cast<double>(cluster->size()));
clusterSizeAssocNorm->Fill(static_cast<double>(cluster->size()));
clusterWidthRowAssoc->Fill(cluster->rowWidth());
clusterWidthColAssoc->Fill(cluster->columnWidth());
// Residuals
residualsX->Fill(xdistance);
residualsY->Fill(ydistance);
residualsPos->Fill(posDiff);
residualsPosVsresidualsTime->Fill(tdistance, posDiff);
// Fill in-pixel plots: (all as function of track position within pixel cell)
if(is_within_roi) {
qvsxmym->Fill(xmod, ymod, cluster->charge()); // cluster charge profile
qMoyalvsxmym->Fill(xmod, ymod, exp(-normalized_charge / 3.5)); // norm. cluster charge profile
// mean charge of cluster seed
pxqvsxmym->Fill(xmod, ymod, cluster->getSeedPixel()->charge());
// mean cluster size
npxvsxmym->Fill(xmod, ymod, static_cast<double>(cluster->size()));
if(cluster->size() == 1)
npx1vsxmym->Fill(xmod, ymod);
if(cluster->size() == 2)
npx2vsxmym->Fill(xmod, ymod);
if(cluster->size() == 3)
npx3vsxmym->Fill(xmod, ymod);
if(cluster->size() == 4)
npx4vsxmym->Fill(xmod, ymod);
// residual MAD x, y, combined (sqrt(x*x + y*y))
rmsxvsxmym->Fill(xmod, ymod, xabsdistance);
rmsyvsxmym->Fill(xmod, ymod, yabsdistance);
rmsxyvsxmym->Fill(xmod, ymod, fabs(sqrt(xdistance * xdistance + ydistance * ydistance)));
}
track->addAssociatedCluster(cluster);
hAssociatedTracksGlobalPosition->Fill(globalIntercept.X(), globalIntercept.Y());
hAssociatedTracksLocalPosition->Fill(m_detector->getColumn(localIntercept),
m_detector->getRow(localIntercept));
if(assoc_cluster->size() == 1) {
residualsX1pix->Fill(xdistance);
residualsY1pix->Fill(ydistance);
}
if(assoc_cluster->size() == 2) {
residualsX2pix->Fill(xdistance);
residualsY2pix->Fill(ydistance);
}
// Only allow one associated cluster per track
break;
// Time residuals
residualsTime->Fill(tdistance);
residualsTimeVsTime->Fill(tdistance, track->timestamp());
residualsTimeVsSignal->Fill(tdistance, cluster_charge);
clusterSizeAssoc->Fill(static_cast<double>(assoc_cluster->size()));
clusterSizeAssocNorm->Fill(static_cast<double>(assoc_cluster->size()));
clusterWidthRowAssoc->Fill(assoc_cluster->rowWidth());
clusterWidthColAssoc->Fill(assoc_cluster->columnWidth());
// Fill in-pixel plots: (all as function of track position within pixel cell)
if(is_within_roi) {
qvsxmym->Fill(xmod, ymod, cluster_charge); // cluster charge profile
qMoyalvsxmym->Fill(xmod, ymod, exp(-normalized_charge / 3.5)); // norm. cluster charge profile
// mean charge of cluster seed
pxqvsxmym->Fill(xmod, ymod, assoc_cluster->getSeedPixel()->charge());
// mean cluster size
npxvsxmym->Fill(xmod, ymod, static_cast<double>(assoc_cluster->size()));
if(assoc_cluster->size() == 1)
npx1vsxmym->Fill(xmod, ymod);
if(assoc_cluster->size() == 2)
npx2vsxmym->Fill(xmod, ymod);
if(assoc_cluster->size() == 3)
npx3vsxmym->Fill(xmod, ymod);
if(assoc_cluster->size() == 4)
npx4vsxmym->Fill(xmod, ymod);
// residual MAD x, y, combined (sqrt(x*x + y*y))
rmsxvsxmym->Fill(xmod, ymod, xabsdistance);
rmsyvsxmym->Fill(xmod, ymod, yabsdistance);
rmsxyvsxmym->Fill(xmod, ymod, fabs(sqrt(xdistance * xdistance + ydistance * ydistance)));
}
}
// Efficiency plots:
hGlobalEfficiencyMap->Fill(globalIntercept.X(), globalIntercept.Y(), has_associated_cluster);
hChipEfficiencyMap->Fill(
m_detector->getColumn(localIntercept), m_detector->getRow(localIntercept), has_associated_cluster);
hAssociatedTracksGlobalPosition->Fill(globalIntercept.X(), globalIntercept.Y());
hAssociatedTracksLocalPosition->Fill(m_detector->getColumn(localIntercept), m_detector->getRow(localIntercept));
// For pixels, only look at the ROI:
if(is_within_roi) {
......
......@@ -72,6 +72,7 @@ namespace corryvreckan {
// Member variables
double m_timeCutFrameEdge;
double chi2ndofCut;
bool useClosestCluster;
int num_tracks;
};
} // namespace corryvreckan
......
......@@ -10,6 +10,7 @@ Generic analysis module for all prototypes. This module is still work in progres
### Parameters
* `time_cut_frameedge`: Parameter to discard telescope tracks at the frame edges (start and end of the current CLICpix2 frame). Defaults to `20ns`.
* `chi2ndof_cut`: Acceptance criterion for telescope tracks, defaults to a value of `3`.
* `use_closest_cluster`: If a track has more than one associated cluster the cluster with the smallest distance to the track is used. Defaults to `true`
### Plots produced
* 2D Map of associated cluster positions
......
......@@ -308,6 +308,9 @@ StatusCode AnalysisEfficiency::run(std::shared_ptr<Clipboard> clipboard) {
return StatusCode::Success;
}
for(auto& pixel : (*pixels)) {
if(pixel->column() > m_detector->nPixels().X() || pixel->row() > m_detector->nPixels().Y()) {
continue;
}
prev_hit_ts.at(static_cast<size_t>(pixel->column())).at(static_cast<size_t>(pixel->row())) = pixel->timestamp();
}
......
......@@ -24,8 +24,8 @@ AnalysisTimingATLASpix::AnalysisTimingATLASpix(Configuration config, std::shared
using namespace ROOT::Math;
m_detector = detector;
m_timingCut = m_config.get<double>("timing_cut", static_cast<double>(Units::convert(1000, "ns")));
m_chi2ndofCut = m_config.get<double>("chi2_ndof_cut", 3.);
m_timeCutFrameEdge = m_config.get<double>("time_cut_frame_edge", static_cast<double>(Units::convert(20, "ns")));
m_chi2ndofCut = m_config.get<double>("chi2ndof_cut", 3.);
m_timeCutFrameEdge = m_config.get<double>("time_cut_frameedge", static_cast<double>(Units::convert(20, "ns")));
m_clusterChargeCut = m_config.get<double>("cluster_charge_cut", 100000.);
m_clusterSizeCut = m_config.get<size_t>("cluster_size_cut", static_cast<size_t>(100));
m_highTotCut = m_config.get<int>("high_tot_cut", 40);
......@@ -78,6 +78,12 @@ void AnalysisTimingATLASpix::initialise() {
hTrackCorrelationTimeAssoc->GetXaxis()->SetTitle("track time stamp - cluster time stamp [ns]");
hTrackCorrelationTimeAssoc->GetYaxis()->SetTitle("# events");
name = "hTrackCorrelationTimeAssocVsTime";
hTrackCorrelationTimeAssocVsTime = new TH2F(name.c_str(), name.c_str(), 3e3, 0, 3e3, 1e3, -5, 5);
hTrackCorrelationTimeAssocVsTime->GetYaxis()->SetTitle("track time stamp - cluster time stamp [us]");
hTrackCorrelationTimeAssocVsTime->GetXaxis()->SetTitle("time [s]");
hTrackCorrelationTimeAssocVsTime->GetZaxis()->SetTitle("# events");
name = "hTrackCorrelationTime_rowCorr";
std::string title = "hTrackCorrelationTime_rowCorr: row-by-row correction";
hTrackCorrelationTime_rowCorr =
......@@ -449,6 +455,8 @@ StatusCode AnalysisTimingATLASpix::run(std::shared_ptr<Clipboard> clipboard) {
double timeDiff = track->timestamp() - cluster->timestamp();
hTrackCorrelationTimeAssoc->Fill(timeDiff);
hTrackCorrelationTimeAssocVsTime->Fill(static_cast<double>(Units::convert(cluster->timestamp(), "s")),
static_cast<double>(Units::convert(timeDiff, "us")));
hTrackCorrelationTimeVsTot->Fill(timeDiff, cluster->getSeedPixel()->raw());
hTrackCorrelationTimeVsCol->Fill(timeDiff, cluster->getSeedPixel()->column());
......
......@@ -53,6 +53,7 @@ namespace corryvreckan {
TH1F* hClusterTimeMinusPixelTime;
// 2D histograms:
TH2F* hTrackCorrelationTimeAssocVsTime;
TH2F* hTrackCorrelationTimeVsCol; // control plot only
TH2F* hTrackCorrelationTimeVsRow;
TH2F* hTrackCorrelationTimeVsRow_1px;
......
......@@ -18,7 +18,7 @@ After this both corrections can be applied on top of each other.
### Parameters
* `timing_cut`: Timing cut for associating a track with an ATLASpix cluster. Defaults to `1us`.
* `chi2ndof_cut`: Acceptance criterion for telescope tracks, defaults to a value of `3`.
* `time_cut_frame_edge`: Parameter to discard telescope tracks at the frame edges (start and end of the current frame). Defaults to `20ns`.
* `time_cut_frameedge`: Parameter to discard telescope tracks at the frame edges (start and end of the current frame). Defaults to `20ns`.
* `cluster_charge_cut`: Parameter to discard clusters with a charge larger than the cut. Defaults to `100000e` (inifitely large).
* `cluster_size_cut`: Parameter to discard clusters with a size too large, only for debugging purposes, default is 100 (inifitely large).
* `high_tot_cut`: Cut dividing 'low' and 'high' ToT events (based on seed pixel ToT). Defaults to `40`.
......@@ -50,6 +50,7 @@ After this both corrections can be applied on top of each other.
* Cluster size for main peak events in time correlation (track timestamp - cluster timestamp > left_tail_cut)
* 2D histograms
* Track time correlation vs. time (track-associated clusters)
* Track time correlation vs. column (only control plot)
* Track time correlation vs. cluster row (for row correction)
* Track time correlation vs. cluster row (only single pixel clusters)
......
......@@ -8,7 +8,7 @@ DUTAssociation::DUTAssociation(Configuration config, std::shared_ptr<Detector> d
timingCut = m_config.get<double>("timing_cut", Units::get<double>(200, "ns"));
spatialCut = m_config.get<XYVector>("spatial_cut", 2 * m_detector->pitch());
useClusterCentre = m_config.get<bool>("use_cluster_centre", true);
useClusterCentre = m_config.get<bool>("use_cluster_centre", false);
}
void DUTAssociation::initialise() {
......@@ -18,20 +18,58 @@ void DUTAssociation::initialise() {
hCutHisto->GetXaxis()->SetBinLabel(1, "Spatial");
hCutHisto->GetXaxis()->SetBinLabel(2, "Timing");
hX1X2 = new TH1D("hX1X2", "hX1X2; xdistance(cluster) - xdistance(closest pixel) [um]; # events", 2000, -1000, 1000);
hY1Y2 = new TH1D("hY1Y2", "hY1Y2; ydistance(cluster) - ydistance(closest pixel) [um]; # events", 2000, -1000, 1000);
hX1X2_1px =
new TH1D("hX1X2_1px", "hX1X2_1px; xdistance(cluster) - xdistance(closest pixel) [um]; # events", 2000, -1000, 1000);
hY1Y2_1px =
new TH1D("hY1Y2_1px", "hY1Y2_1px; ydistance(cluster) - ydistance(closest pixel) [um]; # events", 2000, -1000, 1000);
hX1X2_2px =
new TH1D("hX1X2_2px", "hX1X2_2px; xdistance(cluster) - xdistance(closest pixel) [um]; # events", 2000, -1000, 1000);
hY1Y2_2px =
new TH1D("hY1Y2_2px", "hY1Y2_2px; ydistance(cluster) - ydistance(closest pixel) [um]; # events", 2000, -1000, 1000);
hX1X2_3px =
new TH1D("hX1X2_3px", "hX1X2_3px; xdistance(cluster) - xdistance(closest pixel) [um]; # events", 2000, -1000, 1000);
hY1Y2_3px =
new TH1D("hY1Y2_3px", "hY1Y2_3px; ydistance(cluster) - ydistance(closest pixel) [um]; # events", 2000, -1000, 1000);
hX1X2 = new TH1D("hX1X2",
"x distance of cluster centre minus closest pixel to track; xdistance(cluster) - xdistance(closest "
"pixel) [um]; # events",
2000,
-1000,
1000);
hY1Y2 = new TH1D("hY1Y2",
"y distance of cluster centre minus closest pixel to track; ydistance(cluster) - ydistance(closest "
"pixel) [um]; # events",
2000,
-1000,
1000);
hX1X2_1px = new TH1D("hX1X2_1px",
"x distance of cluster centre minus closest pixel to track - 1 pixel cluster; xdistance(cluster) - "
"xdistance(closest pixel) [um]; # events",
2000,
-1000,
1000);
hY1Y2_1px = new TH1D("hY1Y2_1px",
"y distance of cluster centre minus closest pixel to track - 1 pixel cluster; ydistance(cluster) - "
"ydistance(closest pixel) [um]; # events",
2000,
-1000,
1000);
hX1X2_2px = new TH1D("hX1X2_2px",
"x distance of cluster centre minus closest pixel to track - 2 pixel cluster; xdistance(cluster) - "
"xdistance(closest pixel) [um]; # events",
2000,
-1000,
1000);
hY1Y2_2px = new TH1D("hY1Y2_2px",
"y distance of cluster centre minus closest pixel to track - 2 pixel cluster; ydistance(cluster) - "
"ydistance(closest pixel) [um]; # events",
2000,
-1000,
1000);
hX1X2_3px = new TH1D("hX1X2_3px",
"x distance of cluster centre minus closest pixel to track - 3 pixel cluster; xdistance(cluster) - "
"xdistance(closest pixel) [um]; # events",
2000,
-1000,
1000);
hY1Y2_3px = new TH1D("hY1Y2_3px",
"y distance of cluster centre minus closest pixel to track - 3 pixel cluster; ydistance(cluster) - "
"ydistance(closest pixel) [um]; # events",
2000,
-1000,
1000);
// Nr of associated clusters per track
title = m_detector->name() + ": number of associated clusters per track;associated clusters;events";
hNoAssocCls = new TH1F("no_assoc_cls", title.c_str(), 10, 0, 10);
}
StatusCode DUTAssociation::run(std::shared_ptr<Clipboard> clipboard) {
......@@ -45,13 +83,18 @@ StatusCode DUTAssociation::run(std::shared_ptr<Clipboard> clipboard) {
// Get the DUT clusters from the clipboard
Clusters* clusters = reinterpret_cast<Clusters*>(clipboard->get(m_detector->name(), "clusters"));
if(clusters == nullptr) {
LOG(DEBUG) << "No DUT clusters on the clipboard";
return StatusCode::Success;
}
// Loop over all tracks
for(auto& track : (*tracks)) {
int assoc_cls_per_track = 0;
auto min_distance = std::numeric_limits<double>::max();
if(clusters == nullptr) {
hNoAssocCls->Fill(0);
LOG(DEBUG) << "No DUT clusters on the clipboard";
continue;
}
// Loop over all DUT clusters
for(auto& cluster : (*clusters)) {
// Check distance between track and cluster
......@@ -99,6 +142,7 @@ StatusCode DUTAssociation::run(std::shared_ptr<Clipboard> clipboard) {
// Check if the cluster is close in space (either use cluster centre of closest pixel to track)
auto xdistance = (useClusterCentre ? xdistance_centre : xdistance_nearest);
auto ydistance = (useClusterCentre ? ydistance_centre : ydistance_nearest);
auto distance = sqrt(xdistance * xdistance + ydistance * ydistance);
if(std::abs(xdistance) > spatialCut.x() || std::abs(ydistance) > spatialCut.y()) {
LOG(DEBUG) << "Discarding DUT cluster with distance (" << Units::display(std::abs(xdistance), {"um", "mm"})