10 #include "TDatabasePDG.h" 13 #include "TPolyLine.h" 14 #include "TPolyLine3D.h" 15 #include "TPolyMarker.h" 16 #include "TPolyMarker3D.h" 33 #include "nuevdb/EventDisplayBase/View2D.h" 34 #include "nuevdb/EventDisplayBase/View3D.h" 48 mf::LogWarning(
"SimulationDrawer") <<
"SimulationDrawer::" << fcn <<
" failed with message:\n" 68 for (
size_t cryoIdx = 0; cryoIdx < geom->
Ncryostats(); cryoIdx++) {
71 for (
size_t tpcIdx = 0; tpcIdx < cryoGeo.
NTPC(); tpcIdx++) {
75 <<
"Cryo/TPC idx: " << cryoIdx <<
"/" << tpcIdx <<
", TPC center: " << tpc.
GetCenter()[0]
97 <<
" minx/maxx: " <<
minx <<
"/" <<
maxx <<
", miny/maxy: " <<
miny <<
"/" <<
maxy 119 std::vector<const simb::MCTruth*> mctruth;
122 for (
unsigned int i = 0; i < mctruth.size(); ++i) {
125 bool firstout =
true;
131 int jmax = TMath::Min(20, mctruth[i]->NParticles());
132 for (
int j = 0; j < jmax; ++j) {
137 "#color[%d]{%s #scale[0.75]{[%.1f GeV/c]}}",
149 if (firstin ==
false) incoming +=
" + ";
154 if (firstout ==
false) outgoing +=
" + ";
159 if (origin ==
"" && incoming ==
"") { mctext = outgoing; }
161 mctext = origin + incoming +
" #rightarrow " + outgoing;
163 TLatex& latex = view->AddLatex(0.03, 0.2, mctext.c_str());
164 latex.SetTextSize(0.6);
180 std::vector<const simb::MCTruth*> mctruth;
182 std::cout <<
"\nMCTruth Ptcl trackID PDG P T Moth Process\n";
183 for (
unsigned int i = 0; i < mctruth.size(); ++i) {
184 for (
int j = 0; j < mctruth[i]->NParticles(); ++j) {
187 int KE = 1000 * (p.
E() - p.
Mass());
201 std::cout <<
"Note: Momentum, P, and kinetic energy, T, in MeV/c\n";
215 if (drawopt->fShowMCTruthVectors > 3) {
216 std::cout <<
"Unsupported ShowMCTruthVectors option (> 2)\n";
223 double xyz1[3] = {0.};
224 double xyz2[3] = {0.};
229 static bool first =
true;
232 <<
"******** Show MCTruth (Genie) particles when ShowMCTruthVectors = 1 or 3 ******** \n";
233 std::cout <<
" MCTruth vectors corrected for space charge? " << sce->
EnableCorrSCE()
234 <<
" and shifted by " << xShift <<
" cm in X\n";
235 std::cout <<
" Neutrons and photons drawn with dotted lines. \n";
236 std::cout <<
" Red = e+/-, nue, nuebar. Blue = mu+/-, numu, numubar. Green = tau+/-, nutau, " 238 std::cout <<
" Yellow = photons. Magenta = pions, protons and nuetrons.\n";
239 std::cout <<
"******** Show MCParticle (Geant) decay photons (e.g. from pizeros) when " 240 "ShowMCTruthVectors = 2 or 3 ******** \n";
241 std::cout <<
" Photons > 50 MeV are drawn as dotted lines corrected for space charge and " 242 "are not shifted.\n";
243 std::cout <<
" Decay photon end points are drawn at 2 interaction lengths (44 cm) from the " 245 std::cout <<
" Color: Green = (50 < E_photon < 100 MeV), Blue = (100 MeV < E_photon < 200 " 246 "MeV), Red = (E_photon > 300 MeV).\n";
249 bool showTruth = (drawopt->fShowMCTruthVectors == 1 || drawopt->fShowMCTruthVectors == 3);
250 bool showPhotons = (drawopt->fShowMCTruthVectors > 1);
257 std::vector<const simb::MCTruth*> mctruth;
260 for (
size_t i = 0; i < mctruth.size(); ++i) {
262 for (
int j = 0; j < mctruth[i]->NParticles(); ++j) {
268 double r = p.
P() * 10.0;
275 xyz1[0] = p.
Vx() - sceOffset.X();
276 xyz1[1] = p.
Vy() + sceOffset.Y();
277 xyz1[2] = p.
Vz() + sceOffset.Z();
278 xyz2[0] = xyz1[0] + r * p.
Px() / p.
P();
279 xyz2[1] = xyz1[1] + r * p.
Py() / p.
P();
280 xyz2[2] = xyz1[2] + r * p.
Pz() / p.
P();
288 detProp.ConvertXToTicks(xyz1[0] + xShift, (
int)plane, rawopt->
fTPC, rawopt->
fCryostat);
290 detProp.ConvertXToTicks(xyz2[0] + xShift, (
int)plane, rawopt->
fTPC, rawopt->
fCryostat);
293 TLine&
l = view->AddLine(w1, time, w2, time2);
297 TLine&
l = view->AddLine(time, w1, time2, w2);
309 sim::ParticleList
const& plist = pi_serv->
ParticleList();
310 if (plist.empty())
return;
318 if (p->
PdgCode() != 22)
continue;
319 if (p->
Process() !=
"Decay")
continue;
320 int TMeV = 1000 * (p->
E() - p->
Mass());
321 if (TMeV < 30)
continue;
325 xyz1[0] = p->
Vx() - sceOffset.X();
326 xyz1[1] = p->
Vy() + sceOffset.Y();
327 xyz1[2] = p->
Vz() + sceOffset.Z();
328 xyz2[0] = xyz1[0] + r * p->
Px() / p->
P();
329 xyz2[1] = xyz1[1] + r * p->
Py() / p->
P();
330 xyz2[2] = xyz1[2] + r * p->
Pz() / p->
P();
333 double t1 = detProp.ConvertXToTicks(xyz1[0], (
int)plane, rawopt->
fTPC, rawopt->
fCryostat);
336 double t2 = detProp.ConvertXToTicks(xyz2[0], (
int)plane, rawopt->
fTPC, rawopt->
fCryostat);
337 TLine&
l = view->AddLine(w1, t1, w2, t2);
339 l.SetLineStyle(kDotted);
340 if (TMeV < 100) { l.SetLineColor(kGreen); }
341 else if (TMeV < 200) {
342 l.SetLineColor(kBlue);
345 l.SetLineColor(kRed);
371 std::vector<const simb::MCParticle*> plist;
375 int neutralColor(12);
377 int neutrinoColor(38);
384 <<
"Starting loop over " << plist.size() <<
" McParticles, voxel list size is " 397 std::map<int, const simb::MCParticle*> trackToMcParticleMap;
400 double minPartEnergy(0.01);
402 for (
size_t p = 0;
p < plist.size(); ++
p) {
403 trackToMcParticleMap[plist[
p]->TrackId()] = plist[
p];
411 int pdgCode(mcPart->
PdgCode());
414 double partCharge = partPDG ? partPDG->Charge() : 0.;
415 double partEnergy = mcPart->
E();
419 if (!mcTraj.
empty() && partEnergy > minPartEnergy && mcPart->
TrackId() < 100000000) {
420 double g4Ticks(clockData.TPCG4Time2Tick(mcPart->
T()) -
trigger_offset(clockData));
422 double xPosMinTick = 0.;
426 int numTrajPoints = mcTraj.
size();
428 std::unique_ptr<double[]> hitPositions(
new double[3 * numTrajPoints]);
431 for (
int hitIdx = 0; hitIdx < numTrajPoints; hitIdx++) {
432 double xPos = mcTraj.
X(hitIdx);
433 double yPos = mcTraj.
Y(hitIdx);
434 double zPos = mcTraj.
Z(hitIdx);
445 xPosMinTick = detProp.ConvertTicksToX(0, planeID);
446 xPosMaxTick = detProp.ConvertTicksToX(detProp.NumberTimeSamples(), planeID);
447 xOffset = detProp.ConvertTicksToX(g4Ticks, planeID) - xPosMinTick;
449 if (xPosMaxTick < xPosMinTick)
std::swap(xPosMinTick, xPosMaxTick);
459 if (xPos > xPosMinTick && xPos < xPosMaxTick) {
469 hitPositions[3 * hitCount] = xPos;
470 hitPositions[3 * hitCount + 1] = yPos;
471 hitPositions[3 * hitCount + 2] = zPos;
476 TPolyLine3D& pl(view->AddPolyLine3D(1, colorIdx, 1, 1));
479 if (partCharge == 0.) {
480 pl.SetLineColor(neutralColor);
484 pl.SetPolyLine(hitCount, hitPositions.get(),
"");
490 std::map<const simb::MCParticle*, std::vector<std::vector<double>>> partToPosMap;
493 for (vxitr = voxels.
begin(); vxitr != voxels.
end(); vxitr++) {
498 int trackId = vxd.
TrackID(partIdx);
503 partToPosMap[mcPart].push_back(std::vector<double>(3));
505 partToPosMap[mcPart].back()[0] = vxd.
VoxelID().
X();
506 partToPosMap[mcPart].back()[1] = vxd.
VoxelID().
Y();
507 partToPosMap[mcPart].back()[2] = vxd.
VoxelID().
Z();
514 std::map<const simb::MCParticle*, std::vector<std::vector<double>>>
::iterator partToPosMapItr;
516 for (partToPosMapItr = partToPosMap.begin(); partToPosMapItr != partToPosMap.end();
522 if (!mcPart || partToPosMapItr->second.empty())
continue;
524 double g4Ticks(clockData.TPCG4Time2Tick(mcPart->
T()) -
trigger_offset(clockData));
526 double xPosMinTick = 0.;
530 int markerIdx(kFullDotSmall);
534 colorIdx = grayedColor;
539 std::unique_ptr<double[]> hitPositions(
new double[3 * partToPosMapItr->second.size()]);
543 for (
size_t posIdx = 0; posIdx < partToPosMapItr->second.size(); posIdx++) {
544 const std::vector<double>& posVec = partToPosMapItr->second[posIdx];
547 geo::Point_t hitLocation(posVec[0], posVec[1], posVec[2]);
553 xPosMinTick = detProp.ConvertTicksToX(0, planeID);
554 xPosMaxTick = detProp.ConvertTicksToX(detProp.NumberTimeSamples(), planeID);
555 xOffset = detProp.ConvertTicksToX(g4Ticks, planeID) - xPosMinTick;
557 if (xPosMaxTick < xPosMinTick)
std::swap(xPosMinTick, xPosMaxTick);
563 double xCoord = posVec[0] + xOffset;
567 if (xCoord > xPosMinTick && xCoord < xPosMaxTick) {
568 hitPositions[3 * hitCount] = xCoord;
569 hitPositions[3 * hitCount + 1] = posVec[1];
570 hitPositions[3 * hitCount + 2] = posVec[2];
575 TPolyMarker3D&
pm = view->AddPolyMarker3D(1, colorIdx, markerIdx, markerSize);
576 pm.SetPolyMarker(hitCount, hitPositions.get(), markerIdx);
580 std::vector<const simb::MCTruth*> mctruth;
584 for (
unsigned int idx = 0; idx < mctruth.size(); idx++) {
586 for (
int particleIdx = 0; particleIdx < mctruth[idx]->NParticles(); particleIdx++) {
594 TVector3 particlePosition(mcPart.
Vx(), mcPart.
Vy(), mcPart.
Vz());
597 TVector3 oppPartDir(-mcPart.
Px(), -mcPart.
Py(), -mcPart.
Pz());
599 if (oppPartDir.Mag2() > 0.) oppPartDir.SetMag(1.);
601 double arcLenToDraw = -particlePosition.Z() / oppPartDir.CosTheta();
604 if (arcLenToDraw > 0.) {
606 TPolyLine3D& pl(view->AddPolyLine3D(2, neutrinoColor, 1, 2));
608 pl.SetPoint(0, particlePosition.X(), particlePosition.Y(), particlePosition.Z());
610 particlePosition +=
std::min(arcLenToDraw + 10., 1000.) * oppPartDir;
612 pl.SetPoint(1, particlePosition.X(), particlePosition.Y(), particlePosition.Z());
645 std::vector<const simb::MCParticle*> plist;
650 double xMinimum(-1. * (
maxx -
minx));
651 double xMaximum(2. * (
maxx -
minx));
660 <<
"Starting loop over " << plist.size() <<
" McParticles, voxel list size is " 673 std::map<int, const simb::MCParticle*> trackToMcParticleMap;
676 bool displayMcTrajectories(
true);
677 double minPartEnergy(0.025);
679 double tpcminx = 1.0;
680 double tpcmaxx = -1.0;
681 double xOffset = 0.0;
682 double g4Ticks = 0.0;
684 double readoutwindowsize = 0.0;
685 double vtx[3] = {0.0, 0.0, 0.0};
686 for (
size_t p = 0;
p < plist.size(); ++
p) {
687 trackToMcParticleMap[plist[
p]->TrackId()] = plist[
p];
690 if (displayMcTrajectories) {
695 int pdgCode(mcPart->
PdgCode());
697 double partCharge = partPDG ? partPDG->Charge() : 0.;
698 double partEnergy = mcPart->
E();
700 if (!mcTraj.
empty() && partEnergy > minPartEnergy && mcPart->
TrackId() < 100000000) {
702 int numTrajPoints = mcTraj.
size();
704 std::unique_ptr<double[]> hitPosX(
new double[numTrajPoints]);
705 std::unique_ptr<double[]> hitPosY(
new double[numTrajPoints]);
706 std::unique_ptr<double[]> hitPosZ(
new double[numTrajPoints]);
709 double xPos = mcTraj.
X(0);
710 double yPos = mcTraj.
Y(0);
711 double zPos = mcTraj.
Z(0);
721 readoutwindowsize = 0.0;
722 for (
int hitIdx = 0; hitIdx < numTrajPoints; hitIdx++) {
723 xPos = mcTraj.
X(hitIdx);
724 yPos = mcTraj.
Y(hitIdx);
725 zPos = mcTraj.
Z(hitIdx);
728 if (xPos < minx || xPos >
maxx || yPos < miny || yPos >
maxy || zPos <
minz ||
732 if ((xPos < tpcminx) || (xPos > tpcmaxx)) {
740 unsigned int tpc = tpcid.
TPC;
742 tpcminx = tpcgeo.
MinX();
743 tpcmaxx = tpcgeo.
MaxX();
745 coeff = detProp.GetXTicksCoefficient(tpc, cryo);
747 detProp.ConvertTicksToX(detProp.ReadOutWindowSize(), 0, tpc, cryo);
752 g4Ticks = clockData.TPCG4Time2Tick(mcPart->
T()) +
753 detProp.GetXTicksOffset(0, tpc, cryo) -
trigger_offset(clockData);
755 xOffset = detProp.ConvertTicksToX(g4Ticks, 0, tpc, cryo);
762 readoutwindowsize = 0.0;
769 bool inreadoutwindow =
false;
771 if ((xPos > readoutwindowsize) && (xPos < tpcmaxx)) inreadoutwindow =
true;
773 else if (coeff > 0) {
774 if ((xPos > tpcminx) && (xPos < readoutwindowsize)) inreadoutwindow =
true;
777 if (!inreadoutwindow)
continue;
780 if (xPos > xMinimum && xPos < xMaximum) {
781 hitPosX[hitCount] = xPos;
782 hitPosY[hitCount] = yPos;
783 hitPosZ[hitCount] = zPos;
788 TPolyLine& pl = view->AddPolyLine(
792 if (partCharge == 0.) {
799 pl.SetPolyLine(hitCount, hitPosX.get(), hitPosY.get(),
"");
801 pl.SetPolyLine(hitCount, hitPosZ.get(), hitPosX.get(),
"");
803 pl.SetPolyLine(hitCount, hitPosZ.get(), hitPosY.get(),
"");
809 std::map<const simb::MCParticle*, std::vector<std::vector<double>>> partToPosMap;
812 for (vxitr = voxels.
begin(); vxitr != voxels.
end(); vxitr++) {
817 int trackId = vxd.
TrackID(partIdx);
822 partToPosMap[mcPart].push_back(std::vector<double>(3));
824 partToPosMap[mcPart].back()[0] = vxd.
VoxelID().
X();
825 partToPosMap[mcPart].back()[1] = vxd.
VoxelID().
Y();
826 partToPosMap[mcPart].back()[2] = vxd.
VoxelID().
Z();
833 std::map<const simb::MCParticle*, std::vector<std::vector<double>>>
::iterator partToPosMapItr;
835 for (partToPosMapItr = partToPosMap.begin(); partToPosMapItr != partToPosMap.end();
841 if (!mcPart || partToPosMapItr->second.empty())
continue;
847 std::vector<std::array<double, 3>> posVecCorr;
848 posVecCorr.reserve(partToPosMapItr->second.size());
850 readoutwindowsize = 0.0;
853 for (
size_t posIdx = 0; posIdx < partToPosMapItr->second.size(); posIdx++) {
854 const std::vector<double>& posVec = partToPosMapItr->second[posIdx];
856 if ((posVec[0] < tpcminx) || (posVec[0] > tpcmaxx)) {
864 unsigned int tpc = tpcid.
TPC;
867 tpcminx = tpcgeo.
MinX();
868 tpcmaxx = tpcgeo.
MaxX();
870 coeff = detProp.GetXTicksCoefficient(tpc, cryo);
871 readoutwindowsize = detProp.ConvertTicksToX(detProp.ReadOutWindowSize(), 0, tpc, cryo);
875 g4Ticks = clockData.TPCG4Time2Tick(mcPart->
T()) +
876 detProp.GetXTicksOffset(0, tpc, cryo) -
trigger_offset(clockData);
878 xOffset = detProp.ConvertTicksToX(g4Ticks, 0, tpc, cryo);
885 readoutwindowsize = 0.0;
889 double xCoord = posVec[0] + xOffset;
891 bool inreadoutwindow =
false;
893 if ((xCoord > readoutwindowsize) && (xCoord < tpcmaxx)) inreadoutwindow =
true;
895 else if (coeff > 0) {
896 if ((xCoord > tpcminx) && (xCoord < readoutwindowsize)) inreadoutwindow =
true;
899 if (inreadoutwindow && (xCoord > xMinimum && xCoord < xMaximum)) {
900 posVecCorr.push_back({{xCoord, posVec[1], posVec[2]}});
904 TPolyMarker&
pm = view->AddPolyMarker(posVecCorr.size(),
909 for (
size_t p = 0;
p < posVecCorr.size(); ++
p) {
911 pm.SetPoint(
p, posVecCorr[
p][0], posVecCorr[p][1]);
913 pm.SetPoint(p, posVecCorr[p][2], posVecCorr[p][0]);
915 pm.SetPoint(p, posVecCorr[p][2], posVecCorr[p][1]);
932 std::vector<const simb::MCParticle*>
temp;
938 for (
unsigned int i = 0; i < plcol.
vals().size(); ++i) {
939 temp.push_back(plcol.
vals().at(i));
944 writeErrMsg(
"GetRawDigits", e);
959 std::vector<const simb::MCTruth*>
temp;
961 std::vector<art::Handle<std::vector<simb::MCTruth>>> mctcol;
965 mctcol = evt.
getMany<std::vector<simb::MCTruth>>();
966 for (
size_t mctc = 0; mctc < mctcol.size(); ++mctc) {
969 for (
size_t i = 0; i < mclistHandle->size(); ++i) {
970 temp.push_back(&(mclistHandle->at(i)));
976 writeErrMsg(
"GetMCTruth", e);
std::map< int, bool > fHighlite
double E(const int i=0) const
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
double Z(const size_type i) const
double X(const size_type i) const
Point GetActiveVolumeCenter() const
Returns the center of the TPC active volume in world coordinates [cm].
double Py(const int i=0) const
void MCTruthLongText(const art::Event &evt, evdb::View2D *view)
CryostatGeo const & GetElement(geo::CryostatID const &cryoid) const
unsigned int fTPC
TPC number to draw, typically set by TWQProjectionView.
void HiLite(int trkId, bool hlt=true)
Container of LAr voxel information.
double ActiveHalfHeight() const
Half height (associated with y coordinate) of active TPC volume [cm].
const simb::MCTrajectory & Trajectory() const
simb::Origin_t Origin() const
double MinX() const
Returns the world x coordinate of the start of the box.
The data type to uniquely identify a Plane.
bool isValid
Whether this ID points to a valid element.
Geometry information for a single TPC.
double Px(const int i=0) const
static sim::LArVoxelList GetLArVoxelList(const art::Event &evt, std::string moduleLabel)
int GetMCTruth(const art::Event &evt, std::vector< const simb::MCTruth * > &mctruth)
art::InputTag fG4ModuleLabel
module label producing sim::SimChannel objects
geo::TPCID PositionToTPCID(geo::Point_t const &point) const
Returns the ID of the TPC at specified location.
double MaxX() const
Returns the world x coordinate of the end of the box.
static void FromPDG(TLine &line, int pdgcode)
Geometry information for a single cryostat.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
std::string Process() const
void MCTruth3D(const art::Event &evt, evdb::View3D *view)
art framework interface to geometry description
double Length() const
Length is associated with z coordinate [cm].
list_type::const_iterator const_iterator
virtual bool EnableCorrSCE() const =0
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
virtual geo::Vector_t GetPosOffsets(geo::Point_t const &point) const =0
double Y(const size_type i) const
Encapsulates the information we want store for a voxel.
void swap(Handle< T > &a, Handle< T > &b)
unsigned int fCryostat
Cryostat number to draw, typically set by TWQProjectionView.
const art::Ptr< simb::MCTruth > & TrackIdToMCTruth_P(int id) const
std::vector< Handle< PROD > > getMany(SelectorBase const &selector=MatchAllSelector{}) const
double ActiveHalfWidth() const
Half width (associated with x coordinate) of active TPC volume [cm].
int GetParticle(const art::Event &evt, std::vector< const simb::MCParticle * > &plist)
double P(const int i=0) const
static int ColorFromPDG(int pdgcode)
double T(const int i=0) const
double fMinEnergyDeposition
bool fShowMCTruthTrajectories
unsigned int NTPC() const
Number of TPCs in this cryostat.
size_type NumberParticles() const
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
static int max(int a, int b)
The data type to uniquely identify a TPC.
Description of geometry of one entire detector.
double ActiveLength() const
Length (associated with z coordinate) of active TPC volume [cm].
void MCTruthShortText(const art::Event &evt, evdb::View2D *view)
Q_EXPORT QTSManip setw(int w)
const sim::ParticleList & ParticleList() const
double HalfHeight() const
Height is associated with y coordinate [cm].
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
double Vx(const int i=0) const
mapped_type Energy() const
art::InputTag fSimChannelLabel
SimChannels may be independent of MC stuff.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc'th TPC in the cryostat.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
static const char * LatexName(int pdgcode)
Convert PDG code to a latex string (root-style)
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
double Pz(const int i=0) const
int fAxisOrientation
0 = TDC values on y-axis, wire number on x-axis, 1 = swapped
double Vz(const int i=0) const
int trigger_offset(DetectorClocksData const &data)
void MCTruthOrtho(const art::Event &evt, evd::OrthoProj_t proj, double msize, evdb::View2D *view)
void MCTruthVectors2D(const art::Event &evt, evdb::View2D *view, unsigned int plane)
sim::LArVoxelID VoxelID() const
std::size_t getView(std::string const &moduleLabel, std::string const &productInstanceName, std::string const &processName, std::vector< ELEMENT const * > &result) const
TPCID_t TPC
Index of the TPC within its cryostat.
LArSoft geometry interface.
geo::CryostatID::CryostatID_t FindCryostatAtPosition(geo::Point_t const &worldLoc) const
Returns the index of the cryostat at specified location.
double Vy(const int i=0) const
double HalfWidth() const
Width is associated with x coordinate [cm].
constexpr Point origin()
Returns a origin position with a point of the specified type.
cet::coded_exception< error, detail::translate > exception
QTextStream & endl(QTextStream &s)
Encapsulate the construction of a single detector plane.
bool fShowMCTruthFullSize
const key_type & TrackID(const size_type) const
Point GetCenter() const
Returns the center of the TPC volume in world coordinates [cm].