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