All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LArPandoraInput.cxx
Go to the documentation of this file.
1 /**
2  * @file larpandora/LArPandoraInterface/LArPandoraInput.cxx
3  *
4  * @brief Helper functions for providing inputs to pandora
5  */
6 
8 
14 
16 
19 
20 #include "nusimdata/SimulationBase/MCTruth.h"
21 
23 
27 
28 #include "Api/PandoraApi.h"
29 #include "Managers/PluginManager.h"
30 #include "Plugins/LArTransformationPlugin.h"
31 
33 
37 
38 #include "messagefacility/MessageLogger/MessageLogger.h"
39 
40 #include <limits>
41 
42 namespace lar_pandora {
43 
44  void
46  const Settings& settings,
47  const LArDriftVolumeMap& driftVolumeMap,
48  const HitVector& hitVector,
49  IdToHitMap& idToHitMap)
50  {
51  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraHits2D(...) *** "
52  << std::endl;
53 
54  if (!settings.m_pPrimaryPandora)
55  throw cet::exception("LArPandora")
56  << "CreatePandoraHits2D - primary Pandora instance does not exist ";
57 
58  const pandora::Pandora* pPandora(settings.m_pPrimaryPandora);
59 
60  art::ServiceHandle<geo::Geometry const> theGeometry;
61  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(e);
63 
64  // Loop over ART hits
65  int hitCounter(settings.m_hitCounterOffset);
66 
67  lar_content::LArCaloHitFactory caloHitFactory;
68 
69  for (HitVector::const_iterator iter = hitVector.begin(), iterEnd = hitVector.end();
70  iter != iterEnd;
71  ++iter) {
72  const art::Ptr<recob::Hit> hit = *iter;
73  const geo::WireID hit_WireID(hit->WireID());
74 
75  // Get basic hit properties (view, time, charge)
76  const geo::View_t hit_View(hit->View());
77  const double hit_Charge(hit->Integral());
78  const double hit_Time(hit->PeakTime());
79  const double hit_TimeStart(hit->PeakTimeMinusRMS());
80  const double hit_TimeEnd(hit->PeakTimePlusRMS());
81 
82  // Get hit X coordinate and, if using a single global drift volume, remove any out-of-time hits here
83  const double xpos_cm(
84  detProp.ConvertTicksToX(hit_Time, hit_WireID.Plane, hit_WireID.TPC, hit_WireID.Cryostat));
85  const double dxpos_cm(
86  std::fabs(detProp.ConvertTicksToX(
87  hit_TimeEnd, hit_WireID.Plane, hit_WireID.TPC, hit_WireID.Cryostat) -
88  detProp.ConvertTicksToX(
89  hit_TimeStart, hit_WireID.Plane, hit_WireID.TPC, hit_WireID.Cryostat)));
90 
91  // Get hit Y and Z coordinates, based on central position of wire
92  double xyz[3];
93  theGeometry->Cryostat(hit_WireID.Cryostat)
94  .TPC(hit_WireID.TPC)
95  .Plane(hit_WireID.Plane)
96  .Wire(hit_WireID.Wire)
97  .GetCenter(xyz);
98  const double y0_cm(xyz[1]);
99  const double z0_cm(xyz[2]);
100 
101  // Get other hit properties here
102  const double wire_pitch_cm(theGeometry->WirePitch(hit_View)); // cm
103  const double mips(LArPandoraInput::GetMips(detProp, settings, hit_Charge, hit_View));
104 
105  // Create Pandora CaloHit
106  lar_content::LArCaloHitParameters caloHitParameters;
107 
108  try {
109  caloHitParameters.m_expectedDirection = pandora::CartesianVector(0., 0., 1.);
110  caloHitParameters.m_cellNormalVector = pandora::CartesianVector(0., 0., 1.);
111  caloHitParameters.m_cellSize0 = settings.m_dx_cm;
112  caloHitParameters.m_cellSize1 = (settings.m_useHitWidths ? dxpos_cm : settings.m_dx_cm);
113  caloHitParameters.m_cellThickness = wire_pitch_cm;
114  caloHitParameters.m_cellGeometry = pandora::RECTANGULAR;
115  caloHitParameters.m_time = 0.;
116  caloHitParameters.m_nCellRadiationLengths = settings.m_dx_cm / settings.m_rad_cm;
117  caloHitParameters.m_nCellInteractionLengths = settings.m_dx_cm / settings.m_int_cm;
118  caloHitParameters.m_isDigital = false;
119  caloHitParameters.m_hitRegion = pandora::SINGLE_REGION;
120  caloHitParameters.m_layer = 0;
121  caloHitParameters.m_isInOuterSamplingLayer = false;
122  caloHitParameters.m_inputEnergy = hit_Charge;
123  caloHitParameters.m_mipEquivalentEnergy = mips;
124  caloHitParameters.m_electromagneticEnergy = mips * settings.m_mips_to_gev;
125  caloHitParameters.m_hadronicEnergy = mips * settings.m_mips_to_gev;
126  caloHitParameters.m_pParentAddress = (void*)((intptr_t)(++hitCounter));
127  caloHitParameters.m_larTPCVolumeId =
128  LArPandoraGeometry::GetVolumeID(driftVolumeMap, hit_WireID.Cryostat, hit_WireID.TPC);
130  driftVolumeMap, hit_WireID.Cryostat, hit_WireID.TPC);
131 
132  if (hit_View == detType->TargetViewW(hit_WireID.TPC, hit_WireID.Cryostat)) {
133  caloHitParameters.m_hitType = pandora::TPC_VIEW_W;
134  const double wpos_cm(
135  pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoW(y0_cm, z0_cm));
136  caloHitParameters.m_positionVector = pandora::CartesianVector(xpos_cm, 0., wpos_cm);
137  }
138  else if (hit_View == detType->TargetViewU(hit_WireID.TPC, hit_WireID.Cryostat)) {
139  caloHitParameters.m_hitType = pandora::TPC_VIEW_U;
140  const double upos_cm(
141  pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoU(y0_cm, z0_cm));
142  caloHitParameters.m_positionVector = pandora::CartesianVector(xpos_cm, 0., upos_cm);
143  }
144  else if (hit_View == detType->TargetViewV(hit_WireID.TPC, hit_WireID.Cryostat)) {
145  caloHitParameters.m_hitType = pandora::TPC_VIEW_V;
146  const double vpos_cm(
147  pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoV(y0_cm, z0_cm));
148  caloHitParameters.m_positionVector = pandora::CartesianVector(xpos_cm, 0., vpos_cm);
149  }
150  else {
151  throw cet::exception("LArPandora")
152  << "CreatePandoraHits2D - this wire view not recognised (View=" << hit_View << ") ";
153  }
154  }
155  catch (const pandora::StatusCodeException&) {
156  mf::LogWarning("LArPandora")
157  << "CreatePandoraHits2D - invalid calo hit parameter provided, all assigned values must "
158  "be finite, calo hit omitted "
159  << std::endl;
160  continue;
161  }
162 
163  // Store the hit address
164  if (hitCounter >= settings.m_uidOffset)
165  throw cet::exception("LArPandora")
166  << "CreatePandoraHits2D - detected an excessive number of hits (" << hitCounter << ") ";
167 
168  idToHitMap[hitCounter] = hit;
169 
170  // Create the Pandora hit
171  try {
172  PANDORA_THROW_RESULT_IF(
173  pandora::STATUS_CODE_SUCCESS,
174  !=,
175  PandoraApi::CaloHit::Create(*pPandora, caloHitParameters, caloHitFactory));
176  }
177  catch (const pandora::StatusCodeException&) {
178  mf::LogWarning("LArPandora") << "CreatePandoraHits2D - unable to create calo hit, "
179  "insufficient or invalid information supplied "
180  << std::endl;
181  continue;
182  }
183  }
184  }
185 
186  //------------------------------------------------------------------------------------------------------------------------------------------
187 
188  void
190  const LArDriftVolumeList& driftVolumeList)
191  {
192  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraLArTPCs(...) *** "
193  << std::endl;
194 
195  if (!settings.m_pPrimaryPandora)
196  throw cet::exception("LArPandora")
197  << "CreatePandoraDetectorGaps - primary Pandora instance does not exist ";
198 
199  const pandora::Pandora* pPandora(settings.m_pPrimaryPandora);
200 
201  for (const LArDriftVolume& driftVolume : driftVolumeList) {
203 
204  try {
205  parameters.m_larTPCVolumeId = driftVolume.GetVolumeID();
206  parameters.m_centerX = driftVolume.GetCenterX();
207  parameters.m_centerY = driftVolume.GetCenterY();
208  parameters.m_centerZ = driftVolume.GetCenterZ();
209  parameters.m_widthX = driftVolume.GetWidthX();
210  parameters.m_widthY = driftVolume.GetWidthY();
211  parameters.m_widthZ = driftVolume.GetWidthZ();
212  parameters.m_wirePitchU = driftVolume.GetWirePitchU();
213  parameters.m_wirePitchV = driftVolume.GetWirePitchV();
214  parameters.m_wirePitchW = driftVolume.GetWirePitchW();
215  parameters.m_wireAngleU = driftVolume.GetWireAngleU();
216  parameters.m_wireAngleV = driftVolume.GetWireAngleV();
217  parameters.m_wireAngleW = driftVolume.GetWireAngleW();
218  parameters.m_sigmaUVW = driftVolume.GetSigmaUVZ();
219  parameters.m_isDriftInPositiveX = driftVolume.IsPositiveDrift();
220  }
221  catch (const pandora::StatusCodeException&) {
222  mf::LogWarning("LArPandora") << "CreatePandoraLArTPCs - invalid tpc parameter provided, "
223  "all assigned values must be finite, tpc omitted "
224  << std::endl;
225  continue;
226  }
227 
228  try {
229  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
230  !=,
231  PandoraApi::Geometry::LArTPC::Create(*pPandora, parameters));
232  }
233  catch (const pandora::StatusCodeException&) {
234  mf::LogWarning("LArPandora") << "CreatePandoraLArTPCs - unable to create tpc, insufficient "
235  "or invalid information supplied "
236  << std::endl;
237  continue;
238  }
239  }
240  }
241 
242  //------------------------------------------------------------------------------------------------------------------------------------------
243 
244  void
246  const LArDriftVolumeList& driftVolumeList,
247  const LArDetectorGapList& listOfGaps)
248  {
249  //ATTN - Unlike SP, DP detector gaps are not in the drift direction
250  art::ServiceHandle<geo::Geometry const> theGeometry;
252 
253  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraDetectorGaps(...) *** "
254  << std::endl;
255 
256  if (!settings.m_pPrimaryPandora)
257  throw cet::exception("LArPandora")
258  << "CreatePandoraDetectorGaps - primary Pandora instance does not exist ";
259 
260  const pandora::Pandora* pPandora(settings.m_pPrimaryPandora);
261 
262  for (const LArDetectorGap& gap : listOfGaps) {
264 
265  try {
266  parameters = detType->CreateLineGapParametersFromDetectorGaps(gap);
267  }
268  catch (const pandora::StatusCodeException&) {
269  mf::LogWarning("LArPandora")
270  << "CreatePandoraDetectorGaps - invalid line gap parameter provided, all assigned values "
271  "must be finite, line gap omitted "
272  << std::endl;
273  continue;
274  }
275  try {
276  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
277  !=,
278  PandoraApi::Geometry::LineGap::Create(*pPandora, parameters));
279  }
280  catch (const pandora::StatusCodeException&) {
281  mf::LogWarning("LArPandora") << "CreatePandoraDetectorGaps - unable to create line gap, "
282  "insufficient or invalid information supplied "
283  << std::endl;
284  continue;
285  }
286  }
287  }
288 
289  //------------------------------------------------------------------------------------------------------------------------------------------
290 
291  void
293  const LArDriftVolumeMap& driftVolumeMap)
294  {
295  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraReadoutGaps(...) *** "
296  << std::endl;
297 
298  if (!settings.m_pPrimaryPandora)
299  throw cet::exception("LArPandora")
300  << "CreatePandoraReadoutGaps - primary Pandora instance does not exist ";
301 
302  const pandora::Pandora* pPandora(settings.m_pPrimaryPandora);
303 
304  art::ServiceHandle<geo::Geometry const> theGeometry;
305  const lariov::ChannelStatusProvider& channelStatus(
306  art::ServiceHandle<lariov::ChannelStatusService const>()->GetProvider());
307 
309 
310  for (unsigned int icstat = 0; icstat < theGeometry->Ncryostats(); ++icstat) {
311  for (unsigned int itpc = 0; itpc < theGeometry->NTPC(icstat); ++itpc) {
312  const geo::TPCGeo& TPC(theGeometry->TPC(itpc));
313 
314  for (unsigned int iplane = 0; iplane < TPC.Nplanes(); ++iplane) {
315  const geo::PlaneGeo& plane(TPC.Plane(iplane));
316  const float halfWirePitch(0.5f * theGeometry->WirePitch(plane.View()));
317  const unsigned int nWires(theGeometry->Nwires(plane.ID()));
318 
319  int firstBadWire(-1), lastBadWire(-1);
320 
321  for (unsigned int iwire = 0; iwire < nWires; ++iwire) {
322  const raw::ChannelID_t channel(
323  theGeometry->PlaneWireToChannel(iplane, iwire, itpc, icstat));
324  const bool isBadChannel(channelStatus.IsBad(channel));
325  const bool isLastWire(nWires == (iwire + 1));
326 
327  if (isBadChannel && (firstBadWire < 0)) firstBadWire = iwire;
328 
329  if (isBadChannel || isLastWire) lastBadWire = iwire;
330 
331  if (isBadChannel && !isLastWire) continue;
332 
333  if ((firstBadWire < 0) || (lastBadWire < 0)) continue;
334 
335  double firstXYZ[3], lastXYZ[3];
336  theGeometry->Cryostat(icstat)
337  .TPC(itpc)
338  .Plane(iplane)
339  .Wire(firstBadWire)
340  .GetCenter(firstXYZ);
341  theGeometry->Cryostat(icstat)
342  .TPC(itpc)
343  .Plane(iplane)
344  .Wire(lastBadWire)
345  .GetCenter(lastXYZ);
346 
347  firstBadWire = -1;
348  lastBadWire = -1;
349 
351 
352  try {
353  float xFirst(-std::numeric_limits<float>::max());
354  float xLast(std::numeric_limits<float>::max());
355 
356  const unsigned int volumeId(
357  LArPandoraGeometry::GetVolumeID(driftVolumeMap, icstat, itpc));
358  LArDriftVolumeMap::const_iterator volumeIter(driftVolumeMap.find(volumeId));
359 
360  if (driftVolumeMap.end() != volumeIter) {
361  xFirst = volumeIter->second.GetCenterX() - 0.5f * volumeIter->second.GetWidthX();
362  xLast = volumeIter->second.GetCenterX() + 0.5f * volumeIter->second.GetWidthX();
363  }
364 
365  const geo::View_t iview = plane.View();
366  parameters = detType->CreateLineGapParametersFromReadoutGaps(
367  iview, itpc, icstat, firstXYZ, lastXYZ, halfWirePitch, xFirst, xLast, pPandora);
368  }
369  catch (const pandora::StatusCodeException&) {
370  mf::LogWarning("LArPandora")
371  << "CreatePandoraReadoutGaps - invalid line gap parameter provided, all assigned "
372  "values must be finite, line gap omitted "
373  << std::endl;
374  continue;
375  }
376 
377  try {
378  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS,
379  !=,
380  PandoraApi::Geometry::LineGap::Create(*pPandora, parameters));
381  }
382  catch (const pandora::StatusCodeException&) {
383  mf::LogWarning("LArPandora") << "CreatePandoraReadoutGaps - unable to create line "
384  "gap, insufficient or invalid information supplied "
385  << std::endl;
386  continue;
387  }
388  }
389  }
390  }
391  }
392  }
393 
394  //------------------------------------------------------------------------------------------------------------------------------------------
395 
396  void
398  const MCTruthToMCParticles& truthToParticleMap,
399  const MCParticlesToMCTruth& particleToTruthMap,
400  const RawMCParticleVector& generatorMCParticleVector)
401  {
402  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraMCParticles(...) *** "
403  << std::endl;
404  art::ServiceHandle<cheat::ParticleInventoryService const> particleInventoryService;
405 
406  if (!settings.m_pPrimaryPandora)
407  throw cet::exception("LArPandora")
408  << "CreatePandoraMCParticles - primary Pandora instance does not exist ";
409 
410  const pandora::Pandora* pPandora(settings.m_pPrimaryPandora);
411 
412  // Make indexed list of MC particles
413  MCParticleMap particleMap;
414 
415  for (MCParticlesToMCTruth::const_iterator iter = particleToTruthMap.begin(),
416  iterEnd = particleToTruthMap.end();
417  iter != iterEnd;
418  ++iter) {
419  const art::Ptr<simb::MCParticle> particle = iter->first;
420  particleMap[particle->TrackId()] = particle;
421  }
422 
423  // Loop over MC truth objects
424  int neutrinoCounter(0);
425 
426  lar_content::LArMCParticleFactory mcParticleFactory;
427 
428  for (MCTruthToMCParticles::const_iterator iter1 = truthToParticleMap.begin(),
429  iterEnd1 = truthToParticleMap.end();
430  iter1 != iterEnd1;
431  ++iter1) {
432  const art::Ptr<simb::MCTruth> truth = iter1->first;
433 
434  if (truth->NeutrinoSet()) {
435  const simb::MCNeutrino neutrino(truth->GetNeutrino());
436  ++neutrinoCounter;
437 
438  if (neutrinoCounter >= settings.m_uidOffset)
439  throw cet::exception("LArPandora")
440  << "CreatePandoraMCParticles - detected an excessive number of mc neutrinos ("
441  << neutrinoCounter << ")";
442 
443  const int neutrinoID(neutrinoCounter + 9 * settings.m_uidOffset);
444 
445  // Create Pandora 3D MC Particle
446  lar_content::LArMCParticleParameters mcParticleParameters;
447 
448  try {
449  mcParticleParameters.m_nuanceCode = neutrino.InteractionType();
450  mcParticleParameters.m_process = lar_content::MC_PROC_INCIDENT_NU;
451  mcParticleParameters.m_energy = neutrino.Nu().E();
452  mcParticleParameters.m_momentum =
453  pandora::CartesianVector(neutrino.Nu().Px(), neutrino.Nu().Py(), neutrino.Nu().Pz());
454  mcParticleParameters.m_vertex =
455  pandora::CartesianVector(neutrino.Nu().Vx(), neutrino.Nu().Vy(), neutrino.Nu().Vz());
456  mcParticleParameters.m_endpoint =
457  pandora::CartesianVector(neutrino.Nu().Vx(), neutrino.Nu().Vy(), neutrino.Nu().Vz());
458  mcParticleParameters.m_particleId = neutrino.Nu().PdgCode();
459  mcParticleParameters.m_mcParticleType = pandora::MC_3D;
460  mcParticleParameters.m_pParentAddress = (void*)((intptr_t)neutrinoID);
461  }
462  catch (const pandora::StatusCodeException&) {
463  mf::LogWarning("LArPandora")
464  << "CreatePandoraMCParticles - invalid mc neutrino parameter provided, all assigned "
465  "values must be finite, mc neutrino omitted "
466  << std::endl;
467  continue;
468  }
469 
470  try {
471  PANDORA_THROW_RESULT_IF(
472  pandora::STATUS_CODE_SUCCESS,
473  !=,
474  PandoraApi::MCParticle::Create(*pPandora, mcParticleParameters, mcParticleFactory));
475  }
476  catch (const pandora::StatusCodeException&) {
477  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - unable to create mc "
478  "neutrino, insufficient or invalid information supplied "
479  << std::endl;
480  continue;
481  }
482 
483  // Loop over associated particles
484  const MCParticleVector& particleVector = iter1->second;
485 
486  for (MCParticleVector::const_iterator iter2 = particleVector.begin(),
487  iterEnd2 = particleVector.end();
488  iter2 != iterEnd2;
489  ++iter2) {
490  const art::Ptr<simb::MCParticle> particle = *iter2;
491  const int trackID(particle->TrackId());
492 
493  // Mother/Daughter Links
494  if (particle->Mother() == 0) {
495  try {
496  PANDORA_THROW_RESULT_IF(
497  pandora::STATUS_CODE_SUCCESS,
498  !=,
499  PandoraApi::SetMCParentDaughterRelationship(
500  *pPandora, (void*)((intptr_t)neutrinoID), (void*)((intptr_t)trackID)));
501  }
502  catch (const pandora::StatusCodeException&) {
503  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - unable to create mc "
504  "particle relationship, invalid information supplied "
505  << std::endl;
506  continue;
507  }
508  }
509  }
510  }
511  }
512 
513  mf::LogDebug("LArPandora") << " Number of Pandora neutrinos: " << neutrinoCounter
514  << std::endl;
515 
516  // Loop over G4 particles
517  int particleCounter(0);
518 
519  // Find Primary Generator Particles
520  std::map<const simb::MCParticle, bool> primaryGeneratorMCParticleMap;
521  LArPandoraInput::FindPrimaryParticles(generatorMCParticleVector, primaryGeneratorMCParticleMap);
522 
523  for (MCParticleMap::const_iterator iterI = particleMap.begin(), iterEndI = particleMap.end();
524  iterI != iterEndI;
525  ++iterI) {
526  const art::Ptr<simb::MCParticle> particle = iterI->second;
527 
528  if (particle->TrackId() != iterI->first)
529  throw cet::exception("LArPandora") << "CreatePandoraMCParticles - mc truth information "
530  "appears to be scrambled in this event";
531 
532  if (particle->TrackId() >= settings.m_uidOffset)
533  throw cet::exception("LArPandora")
534  << "CreatePandoraMCParticles - detected an excessive number of MC particles ("
535  << particle->TrackId() << ")";
536 
537  ++particleCounter;
538 
539  // Find start and end trajectory points
540  int firstT(-1), lastT(-1);
541  LArPandoraInput::GetTrueStartAndEndPoints(settings, particle, firstT, lastT);
542 
543  if (firstT < 0 && lastT < 0) {
544  firstT = 0;
545  lastT = 0;
546  }
547 
548  // Lookup position and kinematics at start and end points
549  const float vtxX(particle->Vx(firstT));
550  const float vtxY(particle->Vy(firstT));
551  const float vtxZ(particle->Vz(firstT));
552 
553  const float endX(particle->Vx(lastT));
554  const float endY(particle->Vy(lastT));
555  const float endZ(particle->Vz(lastT));
556 
557  const float pX(particle->Px(firstT));
558  const float pY(particle->Py(firstT));
559  const float pZ(particle->Pz(firstT));
560  const float E(particle->E(firstT));
561 
562  // Find the source of the mc particle
563  int nuanceCode(0);
564  const int trackID(particle->TrackId());
565  const simb::Origin_t origin(particleInventoryService->TrackIdToMCTruth(trackID).Origin());
566 
567  if (LArPandoraInput::IsPrimaryMCParticle(particle, primaryGeneratorMCParticleMap)) {
568  nuanceCode = 2001;
569  }
570  else if (simb::kCosmicRay == origin) {
571  nuanceCode = 3000;
572  }
573  else if (simb::kSingleParticle == origin) {
574  nuanceCode = 2000;
575  }
576 
577  // Create 3D Pandora MC Particle
578  lar_content::LArMCParticleParameters mcParticleParameters;
579 
580  try {
581  MCProcessMap processMap;
582  FillMCProcessMap(processMap);
583  mcParticleParameters.m_nuanceCode = nuanceCode;
584  if (processMap.find(particle->Process()) != processMap.end()) {
585  mcParticleParameters.m_process = processMap[particle->Process()];
586  }
587  else {
588  mcParticleParameters.m_process = lar_content::MC_PROC_UNKNOWN;
589  mf::LogWarning("LArPandora")
590  << "CreatePandoraMCParticles - found an unknown process" << std::endl;
591  }
592  mcParticleParameters.m_energy = E;
593  mcParticleParameters.m_particleId = particle->PdgCode();
594  mcParticleParameters.m_momentum = pandora::CartesianVector(pX, pY, pZ);
595  mcParticleParameters.m_vertex = pandora::CartesianVector(vtxX, vtxY, vtxZ);
596  mcParticleParameters.m_endpoint = pandora::CartesianVector(endX, endY, endZ);
597  mcParticleParameters.m_mcParticleType = pandora::MC_3D;
598  mcParticleParameters.m_pParentAddress = (void*)((intptr_t)particle->TrackId());
599  }
600  catch (const pandora::StatusCodeException&) {
601  mf::LogWarning("LArPandora")
602  << "CreatePandoraMCParticles - invalid mc particle parameter provided, all assigned "
603  "values must be finite, mc particle omitted "
604  << std::endl;
605  continue;
606  }
607 
608  try {
609  PANDORA_THROW_RESULT_IF(
610  pandora::STATUS_CODE_SUCCESS,
611  !=,
612  PandoraApi::MCParticle::Create(*pPandora, mcParticleParameters, mcParticleFactory));
613  }
614  catch (const pandora::StatusCodeException&) {
615  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - unable to create mc particle, "
616  "insufficient or invalid information supplied "
617  << std::endl;
618  continue;
619  }
620 
621  // Create Mother/Daughter Links between 3D MC Particles
622  const int id_mother(particle->Mother());
623  MCParticleMap::const_iterator iterJ = particleMap.find(id_mother);
624 
625  if (iterJ != particleMap.end()) {
626  try {
627  PANDORA_THROW_RESULT_IF(
628  pandora::STATUS_CODE_SUCCESS,
629  !=,
630  PandoraApi::SetMCParentDaughterRelationship(
631  *pPandora, (void*)((intptr_t)id_mother), (void*)((intptr_t)particle->TrackId())));
632  }
633  catch (const pandora::StatusCodeException&) {
634  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - Unable to create mc particle "
635  "relationship, invalid information supplied "
636  << std::endl;
637  continue;
638  }
639  }
640  }
641 
642  mf::LogDebug("LArPandora") << "Number of mc particles: " << particleCounter << std::endl;
643  }
644 
645  //------------------------------------------------------------------------------------------------------------------------------------------
646 
647  void
649  const RawMCParticleVector& mcParticleVector,
650  std::map<const simb::MCParticle, bool>& primaryMCParticleMap)
651  {
652  for (const simb::MCParticle& mcParticle : mcParticleVector) {
653  if ("primary" == mcParticle.Process()) {
654  primaryMCParticleMap.emplace(std::make_pair(mcParticle, false));
655  }
656  }
657  }
658 
659  //------------------------------------------------------------------------------------------------------------------------------------------
660 
661  bool
662  LArPandoraInput::IsPrimaryMCParticle(const art::Ptr<simb::MCParticle>& mcParticle,
663  std::map<const simb::MCParticle, bool>& primaryMCParticleMap)
664  {
665  for (auto& mcParticleIter : primaryMCParticleMap) {
666  if (!mcParticleIter.second) {
667  const simb::MCParticle primaryMCParticle(mcParticleIter.first);
668 
669  if (std::fabs(primaryMCParticle.Px() - mcParticle->Px()) <
670  std::numeric_limits<double>::epsilon() &&
671  std::fabs(primaryMCParticle.Py() - mcParticle->Py()) <
672  std::numeric_limits<double>::epsilon() &&
673  std::fabs(primaryMCParticle.Pz() - mcParticle->Pz()) <
674  std::numeric_limits<double>::epsilon()) {
675  mcParticleIter.second = true;
676  return true;
677  }
678  }
679  }
680  return false;
681  }
682 
683  //------------------------------------------------------------------------------------------------------------------------------------------
684 
685  void
687  const IdToHitMap& idToHitMap,
688  const HitsToTrackIDEs& hitToParticleMap)
689  {
690  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraMCLinks(...) *** "
691  << std::endl;
692 
693  if (!settings.m_pPrimaryPandora)
694  throw cet::exception("LArPandora")
695  << "CreatePandoraMCLinks2D - primary Pandora instance does not exist ";
696 
697  const pandora::Pandora* pPandora(settings.m_pPrimaryPandora);
698 
699  for (IdToHitMap::const_iterator iterI = idToHitMap.begin(), iterEndI = idToHitMap.end();
700  iterI != iterEndI;
701  ++iterI) {
702  const int hitID(iterI->first);
703  const art::Ptr<recob::Hit> hit(iterI->second);
704  // const geo::WireID hit_WireID(hit->WireID());
705 
706  // Get list of associated MC particles
707  HitsToTrackIDEs::const_iterator iterJ = hitToParticleMap.find(hit);
708 
709  if (hitToParticleMap.end() == iterJ) continue;
710 
711  const TrackIDEVector& trackCollection = iterJ->second;
712 
713  if (trackCollection.size() == 0)
714  throw cet::exception("LArPandora")
715  << "CreatePandoraMCLinks2D - found a hit without any associated MC truth information ";
716 
717  // Create links between hits and MC particles
718  for (unsigned int k = 0; k < trackCollection.size(); ++k) {
719  const sim::TrackIDE trackIDE(trackCollection.at(k));
720  const int trackID(std::abs(trackIDE.trackID)); // TODO: Find out why std::abs is needed
721  const float energyFrac(trackIDE.energyFrac);
722 
723  try {
724  PANDORA_THROW_RESULT_IF(
725  pandora::STATUS_CODE_SUCCESS,
726  !=,
727  PandoraApi::SetCaloHitToMCParticleRelationship(
728  *pPandora, (void*)((intptr_t)hitID), (void*)((intptr_t)trackID), energyFrac));
729  }
730  catch (const pandora::StatusCodeException&) {
731  mf::LogWarning("LArPandora") << "CreatePandoraMCLinks2D - unable to create calo hit to "
732  "mc particle relationship, invalid information supplied "
733  << std::endl;
734  continue;
735  }
736  }
737  }
738  }
739 
740  //------------------------------------------------------------------------------------------------------------------------------------------
741 
742  void
744  const art::Ptr<simb::MCParticle>& particle,
745  int& firstT,
746  int& lastT)
747  {
748  art::ServiceHandle<geo::Geometry const> theGeometry;
749  firstT = -1;
750  lastT = -1;
751 
752  for (unsigned int icstat = 0; icstat < theGeometry->Ncryostats(); ++icstat) {
753  for (unsigned int itpc = 0; itpc < theGeometry->NTPC(icstat); ++itpc) {
754  int thisfirstT(-1), thislastT(-1);
755  LArPandoraInput::GetTrueStartAndEndPoints(icstat, itpc, particle, thisfirstT, thislastT);
756 
757  if (thisfirstT < 0) continue;
758 
759  if (firstT < 0 || thisfirstT < firstT) firstT = thisfirstT;
760 
761  if (lastT < 0 || thislastT > lastT) lastT = thislastT;
762  }
763  }
764  }
765 
766  //------------------------------------------------------------------------------------------------------------------------------------------
767 
768  void
770  const unsigned int tpc,
771  const art::Ptr<simb::MCParticle>& particle,
772  int& startT,
773  int& endT)
774  {
775  art::ServiceHandle<geo::Geometry const> theGeometry;
776 
777  bool foundStartPosition(false);
778  const int numTrajectoryPoints(static_cast<int>(particle->NumberTrajectoryPoints()));
779 
780  for (int nt = 0; nt < numTrajectoryPoints; ++nt) {
781  const double pos[3] = {particle->Vx(nt), particle->Vy(nt), particle->Vz(nt)};
782  geo::TPCID tpcID = theGeometry->FindTPCAtPosition(pos);
783 
784  if (!tpcID.isValid) continue;
785 
786  if (!(cstat == tpcID.Cryostat && tpc == tpcID.TPC)) continue;
787 
788  endT = nt;
789 
790  if (!foundStartPosition) {
791  startT = endT;
792  foundStartPosition = true;
793  }
794  }
795  }
796 
797  //------------------------------------------------------------------------------------------------------------------------------------------
798 
799  float
800  LArPandoraInput::GetTrueX0(const art::Event& e,
801  const art::Ptr<simb::MCParticle>& particle,
802  const int nt)
803  {
804  art::ServiceHandle<geo::Geometry const> theGeometry;
805  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(e);
806  auto const det_prop =
807  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(e, clock_data);
808 
809  unsigned int which_tpc(0);
810  unsigned int which_cstat(0);
811  double pos[3] = {particle->Vx(nt), particle->Vy(nt), particle->Vz(nt)};
812  theGeometry->PositionToTPC(pos, which_tpc, which_cstat);
813 
814  const float vtxT(particle->T(nt));
815  const float vtxTDC(clock_data.TPCG4Time2Tick(vtxT));
816  const float vtxTDC0(trigger_offset(clock_data));
817 
818  const geo::TPCGeo& theTpc = theGeometry->Cryostat(which_cstat).TPC(which_tpc);
819  const float driftDir((theTpc.DriftDirection() == geo::kNegX) ? +1.0 : -1.0);
820  return (driftDir * (vtxTDC - vtxTDC0) * det_prop.GetXTicksCoefficient());
821  }
822 
823  //------------------------------------------------------------------------------------------------------------------------------------------
824 
825  double
827  const Settings& settings,
828  const double hit_Charge,
829  const geo::View_t hit_View)
830  {
831  art::ServiceHandle<geo::Geometry const> theGeometry;
832 
833  // TODO: Unite this procedure with other calorimetry procedures under development
834  const double dQdX(hit_Charge / (theGeometry->WirePitch(hit_View))); // ADC/cm
835  const double dQdX_e(dQdX /
836  (detProp.ElectronsToADC() * settings.m_recombination_factor)); // e/cm
837  const double dEdX(settings.m_useBirksCorrection ?
838  detProp.BirksCorrection(dQdX_e) :
839  dQdX_e * 1000. / util::kGeVToElectrons); // MeV/cm
840  double mips(dEdX / settings.m_dEdX_mip);
841 
842  if (mips < 0.) mips = settings.m_mips_if_negative;
843 
844  if (mips > settings.m_mips_max) mips = settings.m_mips_max;
845 
846  return mips;
847  }
848 
849  //------------------------------------------------------------------------------------------------------------------------------------------
850 
851  void
853  {
854  // QGSP_BERT and EM standard physics list mappings
855  processMap["unknown"] = lar_content::MC_PROC_UNKNOWN;
856  processMap["primary"] = lar_content::MC_PROC_PRIMARY;
857  processMap["compt"] = lar_content::MC_PROC_COMPT;
858  processMap["phot"] = lar_content::MC_PROC_PHOT;
859  processMap["annihil"] = lar_content::MC_PROC_ANNIHIL;
860  processMap["eIoni"] = lar_content::MC_PROC_E_IONI;
861  processMap["eBrem"] = lar_content::MC_PROC_E_BREM;
862  processMap["conv"] = lar_content::MC_PROC_CONV;
863  processMap["muIoni"] = lar_content::MC_PROC_MU_IONI;
864  processMap["muMinusCaptureAtRest"] = lar_content::MC_PROC_MU_MINUS_CAPTURE_AT_REST;
865  processMap["neutronInelastic"] = lar_content::MC_PROC_NEUTRON_INELASTIC;
866  processMap["nCapture"] = lar_content::MC_PROC_N_CAPTURE;
867  processMap["hadElastic"] = lar_content::MC_PROC_HAD_ELASTIC;
868  processMap["Decay"] = lar_content::MC_PROC_DECAY;
869  processMap["CoulombScat"] = lar_content::MC_PROC_COULOMB_SCAT;
870  processMap["muBrems"] = lar_content::MC_PROC_MU_BREM;
871  processMap["muPairProd"] = lar_content::MC_PROC_MU_PAIR_PROD;
872  processMap["PhotonInelastic"] = lar_content::MC_PROC_PHOTON_INELASTIC;
873  processMap["hIoni"] = lar_content::MC_PROC_HAD_IONI;
874  processMap["protonInelastic"] = lar_content::MC_PROC_PROTON_INELASTIC;
875  processMap["pi+Inelastic"] = lar_content::MC_PROC_PI_PLUS_INELASTIC;
876  processMap["CHIPSNuclearCaptureAtRest"] = lar_content::MC_PROC_CHIPS_NUCLEAR_CAPTURE_AT_REST;
877  processMap["pi-Inelastic"] = lar_content::MC_PROC_PI_MINUS_INELASTIC;
878  processMap["Transportation"] = lar_content::MC_PROC_TRANSPORTATION;
879  processMap["Rayl"] = lar_content::MC_PROC_RAYLEIGH;
880  processMap["hBrems"] = lar_content::MC_PROC_HAD_BREM;
881  processMap["hPairProd"] = lar_content::MC_PROC_HAD_PAIR_PROD;
882  processMap["ionIoni"] = lar_content::MC_PROC_ION_IONI;
883  processMap["nKiller"] = lar_content::MC_PROC_NEUTRON_KILLER;
884  processMap["ionInelastic"] = lar_content::MC_PROC_ION_INELASTIC;
885  processMap["He3Inelastic"] = lar_content::MC_PROC_HE3_INELASTIC;
886  processMap["alphaInelastic"] = lar_content::MC_PROC_ALPHA_INELASTIC;
887  processMap["anti_He3Inelastic"] = lar_content::MC_PROC_ANTI_HE3_INELASTIC;
888  processMap["anti_alphaInelastic"] = lar_content::MC_PROC_ANTI_ALPHA_INELASTIC;
889  processMap["hFritiofCaptureAtRest"] = lar_content::MC_PROC_HAD_FRITIOF_CAPTURE_AT_REST;
890  processMap["anti_deuteronInelastic"] = lar_content::MC_PROC_ANTI_DEUTERON_INELASTIC;
891  processMap["anti_neutronInelastic"] = lar_content::MC_PROC_ANTI_NEUTRON_INELASTIC;
892  processMap["anti_protonInelastic"] = lar_content::MC_PROC_ANTI_PROTON_INELASTIC;
893  processMap["anti_tritonInelastic"] = lar_content::MC_PROC_ANTI_TRITON_INELASTIC;
894  processMap["dInelastic"] = lar_content::MC_PROC_DEUTERON_INELASTIC;
895  processMap["electronNuclear"] = lar_content::MC_PROC_ELECTRON_NUCLEAR;
896  processMap["photonNuclear"] = lar_content::MC_PROC_PHOTON_NUCLEAR;
897  processMap["kaon+Inelastic"] = lar_content::MC_PROC_KAON_PLUS_INELASTIC;
898  processMap["kaon-Inelastic"] = lar_content::MC_PROC_KAON_MINUS_INELASTIC;
899  processMap["hBertiniCaptureAtRest"] = lar_content::MC_PROC_HAD_BERTINI_CAPTURE_AT_REST;
900  processMap["lambdaInelastic"] = lar_content::MC_PROC_LAMBDA_INELASTIC;
901  processMap["muonNuclear"] = lar_content::MC_PROC_MU_NUCLEAR;
902  processMap["tInelastic"] = lar_content::MC_PROC_TRITON_INELASTIC;
903  processMap["primaryBackground"] = lar_content::MC_PROC_PRIMARY_BACKGROUND;
904  }
905 
906  //------------------------------------------------------------------------------------------------------------------------------------------
907  //------------------------------------------------------------------------------------------------------------------------------------------
908 
910  : m_pPrimaryPandora(nullptr)
911  , m_useHitWidths(true)
912  , m_useBirksCorrection(false)
913  , m_useActiveBoundingBox(false)
914  , m_uidOffset(100000000)
915  , m_hitCounterOffset(0)
916  , m_dx_cm(0.5)
917  , m_int_cm(84.)
918  , m_rad_cm(14.)
919  , m_dEdX_mip(2.)
920  , m_mips_max(50.)
921  , m_mips_if_negative(0.)
922  , m_mips_to_gev(3.5e-4)
923  , m_recombination_factor(0.63)
924  {}
925 
926 } // namespace lar_pandora
Interface class for LArPandora producer modules, which reconstruct recob::PFParticles from recob::Hit...
static void CreatePandoraMCParticles(const Settings &settings, const MCTruthToMCParticles &truthToParticles, const MCParticlesToMCTruth &particlesToTruth, const RawMCParticleVector &generatorMCParticleVector)
Create the Pandora MC particles from the MC particles.
static void CreatePandoraDetectorGaps(const Settings &settings, const LArDriftVolumeList &driftVolumeList, const LArDetectorGapList &listOfGaps)
Create pandora line gaps to cover dead regions between TPCs in a global drift volume approach...
virtual bool IsBad(raw::ChannelID_t channel) const =0
Returns whether the specified channel is bad in the current run.
virtual geo::View_t TargetViewW(const geo::TPCID::TPCID_t tpc, const geo::CryostatID::CryostatID_t cstat) const =0
Map a LArSoft view to Pandora&#39;s W view.
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
std::map< unsigned int, LArDriftVolume > LArDriftVolumeMap
Header file for the lar calo hit class.
static float GetTrueX0(const art::Event &evt, const art::Ptr< simb::MCParticle > &particle, const int nT)
Use detector and time services to get a true X offset for a given trajectory point.
Declaration of signal hit object.
std::map< art::Ptr< simb::MCParticle >, art::Ptr< simb::MCTruth > > MCParticlesToMCTruth
Empty interface to map pandora to specifics in the LArSoft geometry.
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:211
Geometry information for a single TPC.
Definition: TPCGeo.h:38
std::vector< LArDriftVolume > LArDriftVolumeList
static void FindPrimaryParticles(const RawMCParticleVector &mcParticleVector, std::map< const simb::MCParticle, bool > &primaryMCParticleMap)
Find all primary MCParticles in a given vector of MCParticles.
const pandora::Pandora * m_pPrimaryPandora
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
static unsigned int GetVolumeID(const LArDriftVolumeMap &driftVolumeMap, const unsigned int cstat, const unsigned int tpc)
Get drift volume ID from a specified cryostat/tpc pair.
std::map< int, art::Ptr< recob::Hit > > IdToHitMap
Definition: ILArPandora.h:21
process_name E
pandora::InputUInt m_larTPCVolumeId
The lar tpc volume id.
Definition: LArCaloHit.h:30
process_name hit
Definition: cheaterreco.fcl:51
Drift towards negative X values.
Definition: geo_types.h:162
virtual geo::View_t TargetViewU(const geo::TPCID::TPCID_t tpc, const geo::CryostatID::CryostatID_t cstat) const =0
Map a LArSoft view to Pandora&#39;s U view.
pandora::InputInt m_process
The process creating the particle.
Definition: LArMCParticle.h:86
BEGIN_PROLOG TPC
static bool IsPrimaryMCParticle(const art::Ptr< simb::MCParticle > &mcParticle, std::map< const simb::MCParticle, bool > &primaryMCParticleMap)
Check whether an MCParticle can be found in a given map.
std::map< int, art::Ptr< simb::MCParticle > > MCParticleMap
std::map< art::Ptr< recob::Hit >, TrackIDEVector > HitsToTrackIDEs
static unsigned int GetDaughterVolumeID(const LArDriftVolumeMap &driftVolumeMap, const unsigned int cstat, const unsigned int tpc)
Get daughter volume ID from a specified cryostat/tpc pair.
LAr calo hit parameters.
Definition: LArCaloHit.h:27
T abs(T value)
static double GetMips(const detinfo::DetectorPropertiesData &detProp, const Settings &settings, const double hit_Charge, const geo::View_t hit_View)
Convert charge in ADCs to approximate MIPs.
constexpr double kGeVToElectrons
23.6eV per ion pair, 1e9 eV/GeV
std::vector< simb::MCParticle > RawMCParticleVector
pandora::InputUInt m_daughterVolumeId
The daughter volume id.
Definition: LArCaloHit.h:31
std::map< art::Ptr< simb::MCTruth >, MCParticleVector > MCTruthToMCParticles
static void CreatePandoraMCLinks2D(const Settings &settings, const HitMap &hitMap, const HitsToTrackIDEs &hitToParticleMap)
Create links between the 2D hits and Pandora MC particles.
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:82
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
const Cut kCosmicRay
std::vector< sim::TrackIDE > TrackIDEVector
static void FillMCProcessMap(MCProcessMap &processMap)
Populate a map from MC process string to enumeration.
Class providing information about the quality of channels.
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
DriftDirection_t DriftDirection() const
Returns an enumerator value describing the drift direction.
Definition: TPCGeo.h:144
virtual PandoraApi::Geometry::LineGap::Parameters CreateLineGapParametersFromReadoutGaps(const geo::View_t view, const geo::TPCID::TPCID_t tpc, const geo::CryostatID::CryostatID_t cstat, const double firstXYZ[3], const double lastXYZ[3], const float halfWirePitch, const float xFirst, const float xLast, const pandora::Pandora *pPandora) const =0
Create the line gap parameters to give to the pandora API.
LArMCParticleFactory responsible for object creation.
static void CreatePandoraReadoutGaps(const Settings &settings, const LArDriftVolumeMap &driftVolumeMap)
Create pandora line gaps to cover any (continuous regions of) bad channels.
virtual geo::View_t TargetViewV(const geo::TPCID::TPCID_t tpc, const geo::CryostatID::CryostatID_t cstat) const =0
Map a LArSoft view to Pandora&#39;s V view.
fhicl::Table< sbnd::crt::CRTDetSimParams > Parameters
LAr mc particle parameters.
Definition: LArMCParticle.h:82
std::vector< art::Ptr< recob::Hit > > HitVector
static void CreatePandoraLArTPCs(const Settings &settings, const LArDriftVolumeList &driftVolumeList)
Create pandora LArTPCs to represent the different drift volumes in use.
LArPandoraDetectorType * GetDetectorType()
Factory class that returns the correct detector type interface.
Encapsulate the construction of a single detector plane.
std::map< std::string, lar_content::MCProcess > MCProcessMap
std::vector< LArDetectorGap > LArDetectorGapList
Helper functions for providing inputs to pandora.
double BirksCorrection(double dQdX) const
dQ/dX in electrons/cm, returns dE/dX in MeV/cm.
pandora::InputInt m_nuanceCode
The nuance code.
Definition: LArMCParticle.h:85
Interface for experiment-specific channel quality info provider.
do i e
int trigger_offset(DetectorClocksData const &data)
static void CreatePandoraHits2D(const art::Event &evt, const Settings &settings, const LArDriftVolumeMap &driftVolumeMap, const HitVector &hitVector, IdToHitMap &idToHitMap)
Create the Pandora 2D hits from the ART hits.
LArCaloHitFactory responsible for object creation.
Definition: LArCaloHit.h:110
drift volume class to hold properties of drift volume
pdgs k
Definition: selectors.fcl:22
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
Interface for experiment-specific service for channel quality info.
Collection of Physical constants used in LArSoft.
Helper functions for extracting detector geometry for use in reconsruction.
Ionization energy from a Geant4 track.
Definition: SimChannel.h:26
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true
art framework interface to geometry description
auto const detProp
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:227
static void GetTrueStartAndEndPoints(const Settings &settings, const art::Ptr< simb::MCParticle > &particle, int &startT, int &endT)
Loop over MC trajectory points and identify start and end points within the detector.
virtual PandoraApi::Geometry::LineGap::Parameters CreateLineGapParametersFromDetectorGaps(const LArDetectorGap &gap) const =0
Create the line gap parameters to give to the pandora API.
drift volume class to hold properties of drift volume
Encapsulate the construction of a single detector plane.