LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
LArPandoraInput.cxx
Go to the documentation of this file.
1 
12 
14 
15 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h"
16 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h"
17 
19 
21 
25 
26 #include "Api/PandoraApi.h"
27 #include "Managers/PluginManager.h"
28 #include "Plugins/LArTransformationPlugin.h"
29 
32 
35 
36 #include <limits>
37 
38 namespace lar_pandora
39 {
40 
41 void LArPandoraInput::CreatePandoraHits2D(const Settings &settings, const LArDriftVolumeMap &driftVolumeMap, const HitVector &hitVector, IdToHitMap &idToHitMap)
42 {
43  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraHits2D(...) *** " << std::endl;
44 
45  if (!settings.m_pPrimaryPandora)
46  throw cet::exception("LArPandora") << "CreatePandoraHits2D - primary Pandora instance does not exist ";
47 
48  const pandora::Pandora *pPandora(settings.m_pPrimaryPandora);
49 
51  auto const* theDetector = lar::providerFrom<detinfo::DetectorPropertiesService>();
52 
53  // Loop over ART hits
54  int hitCounter(0);
55 
56  lar_content::LArCaloHitFactory caloHitFactory;
57 
58  for (HitVector::const_iterator iter = hitVector.begin(), iterEnd = hitVector.end(); iter != iterEnd; ++iter)
59  {
60  const art::Ptr<recob::Hit> hit = *iter;
61  const geo::WireID hit_WireID(hit->WireID());
62 
63  // Get basic hit properties (view, time, charge)
64  const geo::View_t hit_View(hit->View());
65  const double hit_Charge(hit->Integral());
66  const double hit_Time(hit->PeakTime());
67  const double hit_TimeStart(hit->PeakTimeMinusRMS());
68  const double hit_TimeEnd(hit->PeakTimePlusRMS());
69 
70  // Get hit X coordinate and, if using a single global drift volume, remove any out-of-time hits here
71  const double xpos_cm(theDetector->ConvertTicksToX(hit_Time, hit_WireID.Plane, hit_WireID.TPC, hit_WireID.Cryostat));
72  const double dxpos_cm(std::fabs(theDetector->ConvertTicksToX(hit_TimeEnd, hit_WireID.Plane, hit_WireID.TPC, hit_WireID.Cryostat) -
73  theDetector->ConvertTicksToX(hit_TimeStart, hit_WireID.Plane, hit_WireID.TPC, hit_WireID.Cryostat)));
74 
75  // Get hit Y and Z coordinates, based on central position of wire
76  double xyz[3];
77  theGeometry->Cryostat(hit_WireID.Cryostat).TPC(hit_WireID.TPC).Plane(hit_WireID.Plane).Wire(hit_WireID.Wire).GetCenter(xyz);
78  const double y0_cm(xyz[1]);
79  const double z0_cm(xyz[2]);
80 
81  // Get other hit properties here
82  const double wire_pitch_cm(theGeometry->WirePitch(hit_View)); // cm
83  const double mips(LArPandoraInput::GetMips(settings, hit_Charge, hit_View));
84 
85  // Create Pandora CaloHit
86  lar_content::LArCaloHitParameters caloHitParameters;
87 
88  try
89  {
90  caloHitParameters.m_expectedDirection = pandora::CartesianVector(0., 0., 1.);
91  caloHitParameters.m_cellNormalVector = pandora::CartesianVector(0., 0., 1.);
92  caloHitParameters.m_cellSize0 = settings.m_dx_cm;
93  caloHitParameters.m_cellSize1 = (settings.m_useHitWidths ? dxpos_cm : settings.m_dx_cm);
94  caloHitParameters.m_cellThickness = wire_pitch_cm;
95  caloHitParameters.m_cellGeometry = pandora::RECTANGULAR;
96  caloHitParameters.m_time = 0.;
97  caloHitParameters.m_nCellRadiationLengths = settings.m_dx_cm / settings.m_rad_cm;
98  caloHitParameters.m_nCellInteractionLengths = settings.m_dx_cm / settings.m_int_cm;
99  caloHitParameters.m_isDigital = false;
100  caloHitParameters.m_hitRegion = pandora::SINGLE_REGION;
101  caloHitParameters.m_layer = 0;
102  caloHitParameters.m_isInOuterSamplingLayer = false;
103  caloHitParameters.m_inputEnergy = hit_Charge;
104  caloHitParameters.m_mipEquivalentEnergy = mips;
105  caloHitParameters.m_electromagneticEnergy = mips * settings.m_mips_to_gev;
106  caloHitParameters.m_hadronicEnergy = mips * settings.m_mips_to_gev;
107  caloHitParameters.m_pParentAddress = (void*)((intptr_t)(++hitCounter));
108  caloHitParameters.m_larTPCVolumeId = LArPandoraGeometry::GetVolumeID(driftVolumeMap, hit_WireID.Cryostat, hit_WireID.TPC);
109 
110  const geo::View_t pandora_View(LArPandoraGeometry::GetGlobalView(hit_WireID.Cryostat, hit_WireID.TPC, hit_View));
111 
112  if (pandora_View == geo::kW)
113  {
114  caloHitParameters.m_hitType = pandora::TPC_VIEW_W;
115  const double wpos_cm(pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoW(y0_cm, z0_cm));
116  caloHitParameters.m_positionVector = pandora::CartesianVector(xpos_cm, 0., wpos_cm);
117  }
118  else if(pandora_View == geo::kU)
119  {
120  caloHitParameters.m_hitType = pandora::TPC_VIEW_U;
121  const double upos_cm(pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoU(y0_cm, z0_cm));
122  caloHitParameters.m_positionVector = pandora::CartesianVector(xpos_cm, 0., upos_cm);
123  }
124  else if(pandora_View == geo::kV)
125  {
126  caloHitParameters.m_hitType = pandora::TPC_VIEW_V;
127  const double vpos_cm(pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoV(y0_cm, z0_cm));
128  caloHitParameters.m_positionVector = pandora::CartesianVector(xpos_cm, 0., vpos_cm);
129  }
130  else
131  {
132  throw cet::exception("LArPandora") << "CreatePandoraHits2D - this wire view not recognised (View=" << hit_View << ") ";
133  }
134  }
135  catch (const pandora::StatusCodeException &)
136  {
137  mf::LogWarning("LArPandora") << "CreatePandoraHits2D - invalid calo hit parameter provided, all assigned values must be finite, calo hit omitted " << std::endl;
138  continue;
139  }
140 
141  // Store the hit address
142  if (hitCounter >= settings.m_uidOffset)
143  throw cet::exception("LArPandora") << "CreatePandoraHits2D - detected an excessive number of hits (" << hitCounter << ") ";
144 
145  idToHitMap[hitCounter] = hit;
146 
147  // Create the Pandora hit
148  try
149  {
150  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::CaloHit::Create(*pPandora, caloHitParameters, caloHitFactory));
151  }
152  catch (const pandora::StatusCodeException &)
153  {
154  mf::LogWarning("LArPandora") << "CreatePandoraHits2D - unable to create calo hit, insufficient or invalid information supplied " << std::endl;
155  continue;
156  }
157  }
158 }
159 
160 //------------------------------------------------------------------------------------------------------------------------------------------
161 
162 void LArPandoraInput::CreatePandoraLArTPCs(const Settings &settings, const LArDriftVolumeList &driftVolumeList)
163 {
164  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraLArTPCs(...) *** " << std::endl;
165 
166  if (!settings.m_pPrimaryPandora)
167  throw cet::exception("LArPandora") << "CreatePandoraDetectorGaps - primary Pandora instance does not exist ";
168 
169  const pandora::Pandora *pPandora(settings.m_pPrimaryPandora);
170 
171  for (const LArDriftVolume &driftVolume : driftVolumeList)
172  {
173  PandoraApi::Geometry::LArTPC::Parameters parameters;
174 
175  try
176  {
177  parameters.m_larTPCVolumeId = driftVolume.GetVolumeID();
178  parameters.m_centerX = driftVolume.GetCenterX();
179  parameters.m_centerY = driftVolume.GetCenterY();
180  parameters.m_centerZ = driftVolume.GetCenterZ();
181  parameters.m_widthX = driftVolume.GetWidthX();
182  parameters.m_widthY = driftVolume.GetWidthY();
183  parameters.m_widthZ = driftVolume.GetWidthZ();
184  parameters.m_wirePitchU = driftVolume.GetWirePitchU();
185  parameters.m_wirePitchV = driftVolume.GetWirePitchV();
186  parameters.m_wirePitchW = driftVolume.GetWirePitchW();
187  parameters.m_wireAngleU = driftVolume.GetWireAngleU();
188  parameters.m_wireAngleV = driftVolume.GetWireAngleV();
189  parameters.m_wireAngleW = driftVolume.GetWireAngleW();
190  parameters.m_sigmaUVW = driftVolume.GetSigmaUVZ();
191  parameters.m_isDriftInPositiveX = driftVolume.IsPositiveDrift();
192  }
193  catch (const pandora::StatusCodeException &)
194  {
195  mf::LogWarning("LArPandora") << "CreatePandoraLArTPCs - invalid tpc parameter provided, all assigned values must be finite, tpc omitted " << std::endl;
196  continue;
197  }
198 
199  try
200  {
201  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::LArTPC::Create(*pPandora, parameters));
202  }
203  catch (const pandora::StatusCodeException &)
204  {
205  mf::LogWarning("LArPandora") << "CreatePandoraLArTPCs - unable to create tpc, insufficient or invalid information supplied " << std::endl;
206  continue;
207  }
208  }
209 }
210 
211 //------------------------------------------------------------------------------------------------------------------------------------------
212 
213 void LArPandoraInput::CreatePandoraDetectorGaps(const Settings &settings, const LArDriftVolumeList &driftVolumeList, const LArDetectorGapList &listOfGaps)
214 {
215  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraDetectorGaps(...) *** " << std::endl;
216 
217  if (!settings.m_pPrimaryPandora)
218  throw cet::exception("LArPandora") << "CreatePandoraDetectorGaps - primary Pandora instance does not exist ";
219 
220  const pandora::Pandora *pPandora(settings.m_pPrimaryPandora);
221 
222  for (const LArDetectorGap &gap : listOfGaps)
223  {
224  PandoraApi::Geometry::LineGap::Parameters parameters;
225 
226  try
227  {
228  parameters.m_lineGapType = pandora::TPC_DRIFT_GAP;
229  parameters.m_lineStartX = gap.GetX1();
230  parameters.m_lineEndX = gap.GetX2();
231  parameters.m_lineStartZ = -std::numeric_limits<float>::max();
232  parameters.m_lineEndZ = std::numeric_limits<float>::max();
233  }
234  catch (const pandora::StatusCodeException &)
235  {
236  mf::LogWarning("LArPandora") << "CreatePandoraDetectorGaps - invalid line gap parameter provided, all assigned values must be finite, line gap omitted " << std::endl;
237  continue;
238  }
239 
240  try
241  {
242  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::LineGap::Create(*pPandora, parameters));
243  }
244  catch (const pandora::StatusCodeException &)
245  {
246  mf::LogWarning("LArPandora") << "CreatePandoraDetectorGaps - unable to create line gap, insufficient or invalid information supplied " << std::endl;
247  continue;
248  }
249  }
250 }
251 
252 //------------------------------------------------------------------------------------------------------------------------------------------
253 
254 void LArPandoraInput::CreatePandoraReadoutGaps(const Settings &settings, const LArDriftVolumeMap &driftVolumeMap)
255 {
256  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraReadoutGaps(...) *** " << std::endl;
257 
258  if (!settings.m_pPrimaryPandora)
259  throw cet::exception("LArPandora") << "CreatePandoraReadoutGaps - primary Pandora instance does not exist ";
260 
261  const pandora::Pandora *pPandora(settings.m_pPrimaryPandora);
262 
264  const lariov::ChannelStatusProvider &channelStatus(art::ServiceHandle<lariov::ChannelStatusService>()->GetProvider());
265 
266  for (unsigned int icstat = 0; icstat < theGeometry->Ncryostats(); ++icstat)
267  {
268  for (unsigned int itpc = 0; itpc < theGeometry->NTPC(icstat); ++itpc)
269  {
270  const geo::TPCGeo &TPC(theGeometry->TPC(itpc));
271 
272  for (unsigned int iplane = 0; iplane < TPC.Nplanes(); ++iplane)
273  {
274  const geo::PlaneGeo &plane(TPC.Plane(iplane));
275  const float halfWirePitch(0.5f * theGeometry->WirePitch(plane.View()));
276  const unsigned int nWires(theGeometry->Nwires(geo::PlaneID(icstat, itpc, plane.View())));
277 
278  int firstBadWire(-1), lastBadWire(-1);
279 
280  for (unsigned int iwire = 0; iwire < nWires; ++iwire)
281  {
282  const raw::ChannelID_t channel(theGeometry->PlaneWireToChannel(plane.View(), iwire, itpc, icstat));
283  const bool isBadChannel(channelStatus.IsBad(channel));
284  const bool isLastWire(nWires == (iwire + 1));
285 
286  if (isBadChannel && (firstBadWire < 0))
287  firstBadWire = iwire;
288 
289  if (isBadChannel || isLastWire)
290  lastBadWire = iwire;
291 
292  if (isBadChannel && !isLastWire)
293  continue;
294 
295  if ((firstBadWire < 0) || (lastBadWire < 0))
296  continue;
297 
298  double firstXYZ[3], lastXYZ[3];
299  theGeometry->Cryostat(icstat).TPC(itpc).Plane(iplane).Wire(firstBadWire).GetCenter(firstXYZ);
300  theGeometry->Cryostat(icstat).TPC(itpc).Plane(iplane).Wire(lastBadWire).GetCenter(lastXYZ);
301 
302  firstBadWire = -1; lastBadWire = -1;
303 
304  PandoraApi::Geometry::LineGap::Parameters parameters;
305 
306  try
307  {
308  parameters.m_lineStartX = -std::numeric_limits<float>::max();
309  parameters.m_lineEndX = std::numeric_limits<float>::max();
310 
311  const unsigned int volumeId(LArPandoraGeometry::GetVolumeID(driftVolumeMap, icstat, itpc));
312  LArDriftVolumeMap::const_iterator volumeIter(driftVolumeMap.find(volumeId));
313 
314  if (driftVolumeMap.end() != volumeIter)
315  {
316  parameters.m_lineStartX = volumeIter->second.GetCenterX() - 0.5f * volumeIter->second.GetWidthX();
317  parameters.m_lineEndX = volumeIter->second.GetCenterX() + 0.5f * volumeIter->second.GetWidthX();
318  }
319 
320  const geo::View_t iview = (geo::View_t)iplane;
321  const geo::View_t pandoraView(LArPandoraGeometry::GetGlobalView(icstat, itpc, iview));
322 
323  if (pandoraView == geo::kW)
324  {
325  const float firstW(firstXYZ[2]);
326  const float lastW(lastXYZ[2]);
327 
328  parameters.m_lineGapType = pandora::TPC_WIRE_GAP_VIEW_W;
329  parameters.m_lineStartZ = std::min(firstW, lastW) - halfWirePitch;
330  parameters.m_lineEndZ = std::max(firstW, lastW) + halfWirePitch;
331  }
332  else if (pandoraView == geo::kU)
333  {
334  const float firstU(pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoU(firstXYZ[1], firstXYZ[2]));
335  const float lastU(pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoU(lastXYZ[1], lastXYZ[2]));
336 
337  parameters.m_lineGapType = pandora::TPC_WIRE_GAP_VIEW_U;
338  parameters.m_lineStartZ = std::min(firstU, lastU) - halfWirePitch;
339  parameters.m_lineEndZ = std::max(firstU, lastU) + halfWirePitch;
340  }
341  else if (pandoraView == geo::kV)
342  {
343  const float firstV(pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoV(firstXYZ[1], firstXYZ[2]));
344  const float lastV(pPandora->GetPlugins()->GetLArTransformationPlugin()->YZtoV(lastXYZ[1], lastXYZ[2]));
345 
346  parameters.m_lineGapType = pandora::TPC_WIRE_GAP_VIEW_V;
347  parameters.m_lineStartZ = std::min(firstV, lastV) - halfWirePitch;
348  parameters.m_lineEndZ = std::max(firstV, lastV) + halfWirePitch;
349  }
350  }
351  catch (const pandora::StatusCodeException &)
352  {
353  mf::LogWarning("LArPandora") << "CreatePandoraReadoutGaps - invalid line gap parameter provided, all assigned values must be finite, line gap omitted " << std::endl;
354  continue;
355  }
356 
357  try
358  {
359  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::Geometry::LineGap::Create(*pPandora, parameters));
360  }
361  catch (const pandora::StatusCodeException &)
362  {
363  mf::LogWarning("LArPandora") << "CreatePandoraReadoutGaps - unable to create line gap, insufficient or invalid information supplied " << std::endl;
364  continue;
365  }
366  }
367  }
368  }
369  }
370 }
371 
372 //------------------------------------------------------------------------------------------------------------------------------------------
373 
374 void LArPandoraInput::CreatePandoraMCParticles(const Settings &settings, const MCTruthToMCParticles &truthToParticleMap,
375  const MCParticlesToMCTruth &particleToTruthMap, const RawMCParticleVector &generatorMCParticleVector)
376 {
377  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraMCParticles(...) *** " << std::endl;
379 
380  if (!settings.m_pPrimaryPandora)
381  throw cet::exception("LArPandora") << "CreatePandoraMCParticles - primary Pandora instance does not exist ";
382 
383  const pandora::Pandora *pPandora(settings.m_pPrimaryPandora);
384 
385  // Make indexed list of MC particles
386  MCParticleMap particleMap;
387 
388  for (MCParticlesToMCTruth::const_iterator iter = particleToTruthMap.begin(), iterEnd = particleToTruthMap.end(); iter != iterEnd; ++iter)
389  {
390  const art::Ptr<simb::MCParticle> particle = iter->first;
391  particleMap[particle->TrackId()] = particle;
392  }
393 
394  // Loop over MC truth objects
395  int neutrinoCounter(0);
396 
397  lar_content::LArMCParticleFactory mcParticleFactory;
398 
399  for (MCTruthToMCParticles::const_iterator iter1 = truthToParticleMap.begin(), iterEnd1 = truthToParticleMap.end(); iter1 != iterEnd1; ++iter1)
400  {
401  const art::Ptr<simb::MCTruth> truth = iter1->first;
402 
403  if (truth->NeutrinoSet())
404  {
405  const simb::MCNeutrino neutrino(truth->GetNeutrino());
406  ++neutrinoCounter;
407 
408  if (neutrinoCounter >= settings.m_uidOffset)
409  throw cet::exception("LArPandora") << "CreatePandoraMCParticles - detected an excessive number of mc neutrinos (" << neutrinoCounter << ")";
410 
411  const int neutrinoID(neutrinoCounter + 9 * settings.m_uidOffset);
412 
413  // Create Pandora 3D MC Particle
414  lar_content::LArMCParticleParameters mcParticleParameters;
415 
416  try
417  {
418  mcParticleParameters.m_nuanceCode = neutrino.InteractionType();
419  mcParticleParameters.m_energy = neutrino.Nu().E();
420  mcParticleParameters.m_momentum = pandora::CartesianVector(neutrino.Nu().Px(), neutrino.Nu().Py(), neutrino.Nu().Pz());
421  mcParticleParameters.m_vertex = pandora::CartesianVector(neutrino.Nu().Vx(), neutrino.Nu().Vy(), neutrino.Nu().Vz());
422  mcParticleParameters.m_endpoint = pandora::CartesianVector(neutrino.Nu().Vx(), neutrino.Nu().Vy(), neutrino.Nu().Vz());
423  mcParticleParameters.m_particleId = neutrino.Nu().PdgCode();
424  mcParticleParameters.m_mcParticleType = pandora::MC_3D;
425  mcParticleParameters.m_pParentAddress = (void*)((intptr_t)neutrinoID);
426  }
427  catch (const pandora::StatusCodeException &)
428  {
429  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - invalid mc neutrino parameter provided, all assigned values must be finite, mc neutrino omitted " << std::endl;
430  continue;
431  }
432 
433  try
434  {
435  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::MCParticle::Create(*pPandora, mcParticleParameters, mcParticleFactory));
436  }
437  catch (const pandora::StatusCodeException &)
438  {
439  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - unable to create mc neutrino, insufficient or invalid information supplied " << std::endl;
440  continue;
441  }
442 
443  // Loop over associated particles
444  const MCParticleVector &particleVector = iter1->second;
445 
446  for (MCParticleVector::const_iterator iter2 = particleVector.begin(), iterEnd2 = particleVector.end(); iter2 != iterEnd2; ++iter2)
447  {
448  const art::Ptr<simb::MCParticle> particle = *iter2;
449  const int trackID(particle->TrackId());
450 
451  // Mother/Daughter Links
452  if (particle->Mother() == 0)
453  {
454  try
455  {
456  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetMCParentDaughterRelationship(*pPandora,
457  (void*)((intptr_t)neutrinoID), (void*)((intptr_t)trackID)));
458  }
459  catch (const pandora::StatusCodeException &)
460  {
461  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - unable to create mc particle relationship, invalid information supplied " << std::endl;
462  continue;
463  }
464  }
465  }
466  }
467  }
468 
469  mf::LogDebug("LArPandora") << " Number of Pandora neutrinos: " << neutrinoCounter << std::endl;
470 
471  // Loop over G4 particles
472  int particleCounter(0);
473 
474  // Find Primary Generator Particles
475  std::map<const simb::MCParticle, bool> primaryGeneratorMCParticleMap;
476  LArPandoraInput::FindPrimaryParticles(generatorMCParticleVector, primaryGeneratorMCParticleMap);
477 
478  for (MCParticleMap::const_iterator iterI = particleMap.begin(), iterEndI = particleMap.end(); iterI != iterEndI; ++iterI)
479  {
480  const art::Ptr<simb::MCParticle> particle = iterI->second;
481 
482  if (particle->TrackId() != iterI->first)
483  throw cet::exception("LArPandora") << "CreatePandoraMCParticles - mc truth information appears to be scrambled in this event";
484 
485  if (particle->TrackId() >= settings.m_uidOffset)
486  throw cet::exception("LArPandora") << "CreatePandoraMCParticles - detected an excessive number of MC particles (" << particle->TrackId() << ")";
487 
488  ++particleCounter;
489 
490  // Find start and end trajectory points
491  int firstT(-1), lastT(-1);
492  LArPandoraInput::GetTrueStartAndEndPoints(settings, particle, firstT, lastT);
493 
494  if (firstT < 0 && lastT < 0)
495  {
496  firstT = 0; lastT = 0;
497  }
498 
499  // Lookup position and kinematics at start and end points
500  const float vtxX(particle->Vx(firstT));
501  const float vtxY(particle->Vy(firstT));
502  const float vtxZ(particle->Vz(firstT));
503 
504  const float endX(particle->Vx(lastT));
505  const float endY(particle->Vy(lastT));
506  const float endZ(particle->Vz(lastT));
507 
508  const float pX(particle->Px(firstT));
509  const float pY(particle->Py(firstT));
510  const float pZ(particle->Pz(firstT));
511  const float E(particle->E(firstT));
512 
513  // Find the source of the mc particle
514  int nuanceCode(0);
515  const int trackID(particle->TrackId());
516  const simb::Origin_t origin(particleInventoryService->TrackIdToMCTruth(trackID).Origin());
517 
518  if (LArPandoraInput::IsPrimaryMCParticle(particle, primaryGeneratorMCParticleMap))
519  {
520  nuanceCode = 2001;
521  }
522  else if (simb::kCosmicRay == origin)
523  {
524  nuanceCode = 3000;
525  }
526  else if (simb::kSingleParticle == origin)
527  {
528  nuanceCode = 2000;
529  }
530 
531  // Create 3D Pandora MC Particle
532  lar_content::LArMCParticleParameters mcParticleParameters;
533 
534  try
535  {
536  mcParticleParameters.m_nuanceCode = nuanceCode;
537  mcParticleParameters.m_energy = E;
538  mcParticleParameters.m_particleId = particle->PdgCode();
539  mcParticleParameters.m_momentum = pandora::CartesianVector(pX, pY, pZ);
540  mcParticleParameters.m_vertex = pandora::CartesianVector(vtxX, vtxY, vtxZ);
541  mcParticleParameters.m_endpoint = pandora::CartesianVector(endX, endY, endZ);
542  mcParticleParameters.m_mcParticleType = pandora::MC_3D;
543  mcParticleParameters.m_pParentAddress = (void*)((intptr_t)particle->TrackId());
544  }
545  catch (const pandora::StatusCodeException &)
546  {
547  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - invalid mc particle parameter provided, all assigned values must be finite, mc particle omitted " << std::endl;
548  continue;
549  }
550 
551  try
552  {
553  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::MCParticle::Create(*pPandora, mcParticleParameters, mcParticleFactory));
554  }
555  catch (const pandora::StatusCodeException &)
556  {
557  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - unable to create mc particle, insufficient or invalid information supplied " << std::endl;
558  continue;
559  }
560 
561  // Create Mother/Daughter Links between 3D MC Particles
562  const int id_mother(particle->Mother());
563  MCParticleMap::const_iterator iterJ = particleMap.find(id_mother);
564 
565  if (iterJ != particleMap.end())
566  {
567  try
568  {
569  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetMCParentDaughterRelationship(*pPandora,
570  (void*)((intptr_t)id_mother), (void*)((intptr_t)particle->TrackId())));
571  }
572  catch (const pandora::StatusCodeException &)
573  {
574  mf::LogWarning("LArPandora") << "CreatePandoraMCParticles - Unable to create mc particle relationship, invalid information supplied " << std::endl;
575  continue;
576  }
577  }
578  }
579 
580  mf::LogDebug("LArPandora") << "Number of mc particles: " << particleCounter << std::endl;
581 }
582 
583 //------------------------------------------------------------------------------------------------------------------------------------------
584 
585 void LArPandoraInput::FindPrimaryParticles(const RawMCParticleVector &mcParticleVector, std::map<const simb::MCParticle, bool> &primaryMCParticleMap)
586 {
587  for (const simb::MCParticle &mcParticle : mcParticleVector)
588  {
589  if ("primary" == mcParticle.Process())
590  {
591  primaryMCParticleMap.emplace(std::make_pair(mcParticle, false));
592  }
593  }
594 }
595 
596 //------------------------------------------------------------------------------------------------------------------------------------------
597 
598 bool LArPandoraInput::IsPrimaryMCParticle(const art::Ptr<simb::MCParticle> &mcParticle, std::map<const simb::MCParticle, bool> &primaryMCParticleMap)
599 {
600  for (auto &mcParticleIter : primaryMCParticleMap)
601  {
602  if (!mcParticleIter.second)
603  {
604  const simb::MCParticle primaryMCParticle(mcParticleIter.first);
605 
606  if (std::fabs(primaryMCParticle.Px() - mcParticle->Px()) < std::numeric_limits<double>::epsilon() &&
607  std::fabs(primaryMCParticle.Py() - mcParticle->Py()) < std::numeric_limits<double>::epsilon() &&
608  std::fabs(primaryMCParticle.Pz() - mcParticle->Pz()) < std::numeric_limits<double>::epsilon())
609  {
610  mcParticleIter.second = true;
611  return true;
612  }
613  }
614  }
615  return false;
616 }
617 
618 //------------------------------------------------------------------------------------------------------------------------------------------
619 
620 void LArPandoraInput::CreatePandoraMCLinks2D(const Settings &settings, const IdToHitMap &idToHitMap, const HitsToTrackIDEs &hitToParticleMap)
621 {
622  mf::LogDebug("LArPandora") << " *** LArPandoraInput::CreatePandoraMCLinks(...) *** " << std::endl;
623 
624  if (!settings.m_pPrimaryPandora)
625  throw cet::exception("LArPandora") << "CreatePandoraMCLinks2D - primary Pandora instance does not exist ";
626 
627  const pandora::Pandora *pPandora(settings.m_pPrimaryPandora);
628 
629  for (IdToHitMap::const_iterator iterI = idToHitMap.begin(), iterEndI = idToHitMap.end(); iterI != iterEndI ; ++iterI)
630  {
631  const int hitID(iterI->first);
632  const art::Ptr<recob::Hit> hit(iterI->second);
633  // const geo::WireID hit_WireID(hit->WireID());
634 
635  // Get list of associated MC particles
636  HitsToTrackIDEs::const_iterator iterJ = hitToParticleMap.find(hit);
637 
638  if (hitToParticleMap.end() == iterJ)
639  continue;
640 
641  const TrackIDEVector &trackCollection = iterJ->second;
642 
643  if (trackCollection.size() == 0)
644  throw cet::exception("LArPandora") << "CreatePandoraMCLinks2D - found a hit without any associated MC truth information ";
645 
646  // Create links between hits and MC particles
647  for (unsigned int k = 0; k < trackCollection.size(); ++k)
648  {
649  const sim::TrackIDE trackIDE(trackCollection.at(k));
650  const int trackID(std::abs(trackIDE.trackID)); // TODO: Find out why std::abs is needed
651  const float energyFrac(trackIDE.energyFrac);
652 
653  try
654  {
655  PANDORA_THROW_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, PandoraApi::SetCaloHitToMCParticleRelationship(*pPandora,
656  (void*)((intptr_t)hitID), (void*)((intptr_t)trackID), energyFrac));
657  }
658  catch (const pandora::StatusCodeException &)
659  {
660  mf::LogWarning("LArPandora") << "CreatePandoraMCLinks2D - unable to create calo hit to mc particle relationship, invalid information supplied " << std::endl;
661  continue;
662  }
663  }
664  }
665 }
666 
667 //------------------------------------------------------------------------------------------------------------------------------------------
668 
669 void LArPandoraInput::GetTrueStartAndEndPoints(const Settings &settings, const art::Ptr<simb::MCParticle> &particle, int &firstT, int &lastT)
670 {
672  firstT = -1; lastT = -1;
673 
674  for (unsigned int icstat = 0; icstat < theGeometry->Ncryostats(); ++icstat)
675  {
676  for (unsigned int itpc = 0; itpc < theGeometry->NTPC(icstat); ++itpc)
677  {
678  int thisfirstT(-1), thislastT(-1);
679  LArPandoraInput::GetTrueStartAndEndPoints(icstat, itpc, particle, thisfirstT, thislastT);
680 
681  if (thisfirstT < 0)
682  continue;
683 
684  if (firstT < 0 || thisfirstT < firstT)
685  firstT = thisfirstT;
686 
687  if (lastT < 0 || thislastT > lastT)
688  lastT = thislastT;
689  }
690  }
691 }
692 
693 //------------------------------------------------------------------------------------------------------------------------------------------
694 
695 void LArPandoraInput::GetTrueStartAndEndPoints(const unsigned int cstat, const unsigned int tpc, const art::Ptr<simb::MCParticle> &particle,
696  int &startT, int &endT)
697 {
699 
700  bool foundStartPosition(false);
701  const int numTrajectoryPoints(static_cast<int>(particle->NumberTrajectoryPoints()));
702 
703  for (int nt = 0; nt < numTrajectoryPoints; ++nt)
704  {
705  const double pos[3] = {particle->Vx(nt), particle->Vy(nt), particle->Vz(nt)};
706  geo::TPCID tpcID = theGeometry->FindTPCAtPosition(pos);
707 
708  if (!tpcID.isValid)
709  continue;
710 
711  if (!(cstat == tpcID.Cryostat && tpc == tpcID.TPC))
712  continue;
713 
714  endT = nt;
715 
716  if (!foundStartPosition)
717  {
718  startT = endT;
719  foundStartPosition = true;
720  }
721  }
722 }
723 
724 //------------------------------------------------------------------------------------------------------------------------------------------
725 
726 float LArPandoraInput::GetTrueX0(const art::Ptr<simb::MCParticle> &particle, const int nt)
727 {
729  auto const* theTime = lar::providerFrom<detinfo::DetectorClocksService>();
730  auto const* theDetector = lar::providerFrom<detinfo::DetectorPropertiesService>();
731 
732  unsigned int which_tpc(0);
733  unsigned int which_cstat(0);
734  double pos[3] = {particle->Vx(nt), particle->Vy(nt), particle->Vz(nt)};
735  theGeometry->PositionToTPC(pos, which_tpc, which_cstat);
736 
737  const float vtxT(particle->T(nt));
738  const float vtxTDC(theTime->TPCG4Time2Tick(vtxT));
739  const float vtxTDC0(theDetector->TriggerOffset());
740 
741  const geo::TPCGeo &theTpc = theGeometry->Cryostat(which_cstat).TPC(which_tpc);
742  const float driftDir((theTpc.DriftDirection() == geo::kNegX) ? +1.0 :-1.0);
743  return (driftDir * (vtxTDC - vtxTDC0) * theDetector->GetXTicksCoefficient());
744 }
745 
746 //------------------------------------------------------------------------------------------------------------------------------------------
747 
748 double LArPandoraInput::GetMips(const Settings &settings, const double hit_Charge, const geo::View_t hit_View)
749 {
751  auto const* theDetector = lar::providerFrom<detinfo::DetectorPropertiesService>();
752 
753  // TODO: Unite this procedure with other calorimetry procedures under development
754  const double dQdX(hit_Charge / (theGeometry->WirePitch(hit_View))); // ADC/cm
755  const double dQdX_e(dQdX / (theDetector->ElectronsToADC() * settings.m_recombination_factor)); // e/cm
756  const double dEdX(settings.m_useBirksCorrection ? theDetector->BirksCorrection(dQdX_e) : dQdX_e * 1000. / util::kGeVToElectrons); // MeV/cm
757  double mips(dEdX / settings.m_dEdX_mip);
758 
759  if (mips < 0.)
760  mips = settings.m_mips_if_negative;
761 
762  if (mips > settings.m_mips_max)
763  mips = settings.m_mips_max;
764 
765  return mips;
766 }
767 
768 //------------------------------------------------------------------------------------------------------------------------------------------
769 //------------------------------------------------------------------------------------------------------------------------------------------
770 
772  m_pPrimaryPandora(nullptr),
773  m_useHitWidths(true),
774  m_useBirksCorrection(false),
775  m_uidOffset(100000000),
776  m_dx_cm(0.5),
777  m_int_cm(84.),
778  m_rad_cm(14.),
779  m_dEdX_mip(2.),
780  m_mips_max(50.),
781  m_mips_if_negative(0.),
782  m_mips_to_gev(3.5e-4),
783  m_recombination_factor(0.63)
784 {
785 }
786 
787 } // namespace lar_pandora
double E(const int i=0) const
Definition: MCParticle.h:237
unsigned int NumberTrajectoryPoints() const
Definition: MCParticle.h:222
std::vector< sim::TrackIDE > TrackIDEVector
static geo::View_t GetGlobalView(const unsigned int cstat, const unsigned int tpc, const geo::View_t hit_View)
Convert to global coordinate system.
Interface class for LArPandora producer modules, which reconstruct recob::PFParticles from recob::Hit...
int PdgCode() const
Definition: MCParticle.h:216
std::map< art::Ptr< recob::Hit >, TrackIDEVector > HitsToTrackIDEs
const simb::MCNeutrino & GetNeutrino() const
Definition: MCTruth.h:74
double Py(const int i=0) const
Definition: MCParticle.h:235
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...
std::vector< LArDetectorGap > LArDetectorGapList
Float_t E
Definition: plot.C:23
static double GetMips(const Settings &settings, const double hit_Charge, const geo::View_t hit_View)
Convert charge in ADCs to approximate MIPs.
WireGeo const & Wire(unsigned int iwire) const
Definition: PlaneGeo.cxx:506
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Planes which measure V.
Definition: geo_types.h:77
std::map< unsigned int, LArDriftVolume > LArDriftVolumeMap
Header file for the lar calo hit class.
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
int Mother() const
Definition: MCParticle.h:217
std::map< art::Ptr< simb::MCTruth >, MCParticleVector > MCTruthToMCParticles
Declaration of signal hit object.
simb::Origin_t Origin() const
Definition: MCTruth.h:71
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:129
Geometry information for a single TPC.
Definition: TPCGeo.h:37
enum simb::_ev_origin Origin_t
event origin types
double Px(const int i=0) const
Definition: MCParticle.h:234
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:130
std::map< int, art::Ptr< simb::MCParticle > > MCParticleMap
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.
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:225
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:233
std::map< int, art::Ptr< recob::Hit > > IdToHitMap
Definition: ILArPandora.h:20
pandora::InputUInt m_larTPCVolumeId
The lar tpc volume id.
Definition: LArCaloHit.h:30
Drift towards negative X values.
Definition: geo_types.h:109
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
static void CreatePandoraHits2D(const Settings &settings, const LArDriftVolumeMap &driftVolumeMap, const HitVector &hitVector, IdToHitMap &idToHitMap)
Create the Pandora 2D hits from the ART hits.
std::vector< art::Ptr< simb::MCParticle > > MCParticleVector
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
std::map< art::Ptr< simb::MCParticle >, art::Ptr< simb::MCTruth > > MCParticlesToMCTruth
int TrackId() const
Definition: MCParticle.h:214
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.
geo::TPCGeo const & PositionToTPC(geo::Point_t const &point) const
Returns the TPC at specified location.
TFile f
Definition: plotHisto.C:6
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
LAr calo hit parameters.
Definition: LArCaloHit.h:27
Planes which measure U.
Definition: geo_types.h:76
simb::MCTruth TrackIdToMCTruth(int const &id)
constexpr double kGeVToElectrons
23.6eV per ion pair, 1e9 eV/GeV
Int_t max
Definition: plot.C:27
intermediate_table::const_iterator const_iterator
static float GetTrueX0(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.
single particles thrown at the detector
Definition: MCTruth.h:24
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:78
double T(const int i=0) const
Definition: MCParticle.h:228
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
The data type to uniquely identify a TPC.
Definition: geo_types.h:195
Header file for the lar mc particle class.
float PeakTimeMinusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
Definition: Hit.h:240
std::vector< art::Ptr< recob::Hit > > HitVector
LArMCParticleFactory responsible for object creation.
Definition: LArMCParticle.h:64
Detector simulation of raw signals on wires.
static void CreatePandoraReadoutGaps(const Settings &settings, const LArDriftVolumeMap &driftVolumeMap)
Create pandora line gaps to cover any (continuous regions of) bad channels.
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
std::vector< simb::MCParticle > RawMCParticleVector
LAr mc particle parameters.
Definition: LArMCParticle.h:27
double Vx(const int i=0) const
Definition: MCParticle.h:225
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
static void CreatePandoraLArTPCs(const Settings &settings, const LArDriftVolumeList &driftVolumeList)
Create pandora LArTPCs to represent the different drift volumes in use.
Encapsulate the construction of a single detector plane.
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
Int_t min
Definition: plot.C:26
Helper functions for providing inputs to pandora.
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
pandora::InputInt m_nuanceCode
The nuance code.
Definition: LArMCParticle.h:30
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
double Pz(const int i=0) const
Definition: MCParticle.h:236
double Vz(const int i=0) const
Definition: MCParticle.h:227
LArCaloHitFactory responsible for object creation.
Definition: LArCaloHit.h:64
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
drift volume class to hold properties of drift volume
Planes which measure W (third view for Bo, MicroBooNE, etc).
Definition: geo_types.h:78
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:298
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:68
bool NeutrinoSet() const
Definition: MCTruth.h:75
float PeakTimePlusRMS(float sigmas=+1.) const
Returns a time sigmas RMS away from the peak time.
Definition: Hit.h:237
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:27
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
Float_t e
Definition: plot.C:34
Event generator information.
Definition: MCNeutrino.h:18
Ionization energy from a Geant4 track.
Definition: SimChannel.h:28
double Vy(const int i=0) const
Definition: MCParticle.h:226
art framework interface to geometry description
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:230
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.
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
Cosmic rays.
Definition: MCTruth.h:22
drift volume class to hold properties of drift volume
Encapsulate the construction of a single detector plane.