This method will group TPCs into drift volumes (these are regions of the detector that share a common drift direction, common range of X coordinates, and common detector parameters such as wire pitch and wire angle).
236 if (!driftVolumeList.empty())
238 <<
" LArPandoraGeometry::LoadGeometry --- detector geometry has already been loaded ";
240 typedef std::set<unsigned int> UIntSet;
245 const float wirePitchU(detType->WirePitchU());
246 const float wirePitchV(detType->WirePitchV());
247 const float wirePitchW(detType->WirePitchW());
248 const float maxDeltaTheta(0.01
f);
251 for (
unsigned int icstat = 0; icstat < theGeometry->
Ncryostats(); ++icstat) {
255 for (
unsigned int itpc1 = 0; itpc1 < theGeometry->
NTPC(icstat); ++itpc1) {
256 if (cstatList.end() != cstatList.find(itpc1))
continue;
260 cstatList.insert(itpc1);
262 const float wireAngleU(detType->WireAngleU(itpc1, icstat));
263 const float wireAngleV(detType->WireAngleV(itpc1, icstat));
264 const float wireAngleW(detType->WireAngleW(itpc1, icstat));
266 double localCoord1[3] = {0., 0., 0.};
267 double worldCoord1[3] = {0., 0., 0.};
270 float driftMinX(useActiveBoundingBox ? theTpc1.ActiveBoundingBox().MinX() :
271 (worldCoord1[0] - theTpc1.ActiveHalfWidth()));
272 float driftMaxX(useActiveBoundingBox ? theTpc1.ActiveBoundingBox().MaxX() :
273 (worldCoord1[0] + theTpc1.ActiveHalfWidth()));
274 float driftMinY(useActiveBoundingBox ? theTpc1.ActiveBoundingBox().MinY() :
275 (worldCoord1[1] - theTpc1.ActiveHalfHeight()));
276 float driftMaxY(useActiveBoundingBox ? theTpc1.ActiveBoundingBox().MaxY() :
277 (worldCoord1[1] + theTpc1.ActiveHalfHeight()));
278 float driftMinZ(useActiveBoundingBox ? theTpc1.ActiveBoundingBox().MinZ() :
279 (worldCoord1[2] - 0.5f * theTpc1.ActiveLength()));
280 float driftMaxZ(useActiveBoundingBox ? theTpc1.ActiveBoundingBox().MaxZ() :
281 (worldCoord1[2] + 0.5f * theTpc1.ActiveLength()));
284 useActiveBoundingBox ?
285 (0.5 * (driftMinX + driftMaxX) - 0.25 * std::fabs(driftMaxX - driftMinX)) :
286 (worldCoord1[0] - 0.5 * theTpc1.ActiveHalfWidth()));
288 useActiveBoundingBox ?
289 (0.5 * (driftMinX + driftMaxX) + 0.25 * std::fabs(driftMaxX - driftMinX)) :
290 (worldCoord1[0] + 0.5 * theTpc1.ActiveHalfWidth()));
292 const bool isPositiveDrift(theTpc1.DriftDirection() ==
geo::kPosX);
295 tpcList.insert(itpc1);
298 tpcVolumeList.emplace_back(LArDaughterDriftVolume(icstat,
300 0.5
f * (driftMaxX + driftMinX),
301 0.5
f * (driftMaxY + driftMinY),
302 0.5
f * (driftMaxZ + driftMinZ),
303 (driftMaxX - driftMinX),
304 (driftMaxY - driftMinY),
305 (driftMaxZ - driftMinZ)));
308 for (
unsigned int itpc2 = itpc1 + 1; itpc2 < theGeometry->
NTPC(icstat); ++itpc2) {
309 if (cstatList.end() != cstatList.find(itpc2))
continue;
313 if (theTpc1.DriftDirection() != theTpc2.DriftDirection())
continue;
315 const float dThetaU(detType->WireAngleU(itpc1, icstat) -
316 detType->WireAngleU(itpc2, icstat));
317 const float dThetaV(detType->WireAngleV(itpc1, icstat) -
318 detType->WireAngleV(itpc2, icstat));
319 const float dThetaW(detType->WireAngleW(itpc1, icstat) -
320 detType->WireAngleW(itpc2, icstat));
321 if (dThetaU > maxDeltaTheta || dThetaV > maxDeltaTheta || dThetaW > maxDeltaTheta)
324 double localCoord2[3] = {0., 0., 0.};
325 double worldCoord2[3] = {0., 0., 0.};
328 const float driftMinX2(useActiveBoundingBox ?
329 theTpc2.ActiveBoundingBox().MinX() :
330 (worldCoord2[0] - theTpc2.ActiveHalfWidth()));
331 const float driftMaxX2(useActiveBoundingBox ?
332 theTpc2.ActiveBoundingBox().MaxX() :
333 (worldCoord2[0] + theTpc2.ActiveHalfWidth()));
336 useActiveBoundingBox ?
337 (0.5 * (driftMinX2 + driftMaxX2) - 0.25 * std::fabs(driftMaxX2 - driftMinX2)) :
338 (worldCoord2[0] - 0.5 * theTpc2.ActiveHalfWidth()));
340 useActiveBoundingBox ?
341 (0.5 * (driftMinX2 + driftMaxX2) + 0.25 * std::fabs(driftMaxX2 - driftMinX2)) :
342 (worldCoord2[0] + 0.5 * theTpc2.ActiveHalfWidth()));
344 if ((min2 > max1) || (min1 > max2))
continue;
346 cstatList.insert(itpc2);
347 tpcList.insert(itpc2);
349 const float driftMinY2(useActiveBoundingBox ?
350 theTpc2.ActiveBoundingBox().MinY() :
351 (worldCoord2[1] - theTpc2.ActiveHalfHeight()));
352 const float driftMaxY2(useActiveBoundingBox ?
353 theTpc2.ActiveBoundingBox().MaxY() :
354 (worldCoord2[1] + theTpc2.ActiveHalfHeight()));
355 const float driftMinZ2(useActiveBoundingBox ?
356 theTpc2.ActiveBoundingBox().MinZ() :
357 (worldCoord2[2] - 0.5f * theTpc2.ActiveLength()));
358 const float driftMaxZ2(useActiveBoundingBox ?
359 theTpc2.ActiveBoundingBox().MaxZ() :
360 (worldCoord2[2] + 0.5f * theTpc2.ActiveLength()));
362 driftMinX =
std::min(driftMinX, driftMinX2);
363 driftMaxX =
std::max(driftMaxX, driftMaxX2);
364 driftMinY =
std::min(driftMinY, driftMinY2);
365 driftMaxY =
std::max(driftMaxY, driftMaxY2);
366 driftMinZ =
std::min(driftMinZ, driftMinZ2);
367 driftMaxZ =
std::max(driftMaxZ, driftMaxZ2);
369 tpcVolumeList.emplace_back(LArDaughterDriftVolume(icstat,
371 0.5
f * (driftMaxX2 + driftMinX2),
372 0.5
f * (driftMaxY2 + driftMinY2),
373 0.5
f * (driftMaxZ2 + driftMinZ2),
374 (driftMaxX2 - driftMinX2),
375 (driftMaxY2 - driftMinY2),
376 (driftMaxZ2 - driftMinZ2)));
380 driftVolumeList.emplace_back(driftVolumeList.size(),
388 0.5f * (driftMaxX + driftMinX),
389 0.5
f * (driftMaxY + driftMinY),
390 0.5f * (driftMaxZ + driftMinZ),
391 (driftMaxX - driftMinX),
392 (driftMaxY - driftMinY),
393 (driftMaxZ - driftMinZ),
394 (wirePitchU + wirePitchV + wirePitchW + 0.1f),
399 if (driftVolumeList.empty())
400 throw cet::exception(
"LArPandora") <<
" LArPandoraGeometry::LoadGeometry --- failed to find " 401 "any drift volumes in this detector geometry ";
Geometry information for a single TPC.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
static int max(int a, int b)
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
std::vector< LArDaughterDriftVolume > LArDaughterDriftVolumeList
LArPandoraDetectorType * GetDetectorType()
Factory class that returns the correct detector type interface.
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Drift towards positive X values.
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
void LocalToWorld(const double *tpc, double *world) const
Transform point from local TPC frame to world frame.
cet::coded_exception< error, detail::translate > exception