Skip to content

Commit 82c95df

Browse files
Implement nested volumes (#141)
* make PopulateFromGeant4World dive into daughter volumes recursevily and extract Geant4 volume paths * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * process daughters first to preserve same volume ID as before * avoid blank name for world_PV * traverse the volumes just once and use the reverse mapping fNewPhysicalToGeant4PhysicalNameMap * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix filling of fPhysicalToPositionInWorldMap * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 3d0fdb6 commit 82c95df

File tree

1 file changed

+68
-37
lines changed

1 file changed

+68
-37
lines changed

src/DetectorConstruction.cxx

Lines changed: 68 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,16 @@ G4VPhysicalVolume* DetectorConstruction::GetPhysicalVolume(const G4String& physi
241241
for (physicalVolume = physicalVolumeStore->begin(); physicalVolume != physicalVolumeStore->end();
242242
physicalVolume++) {
243243
auto name = (*physicalVolume)->GetName();
244-
auto alternativeName = (G4String)geometryInfo.GetAlternativeNameFromGeant4PhysicalName(name);
245-
if (name == physicalVolumeName || alternativeName == physicalVolumeName) {
244+
if (name == physicalVolumeName) {
246245
return *physicalVolume;
247246
}
247+
// physical volumes with the same Geant4 name are the same G4VPhysicalVolume pointer
248+
auto alternativeNames = geometryInfo.GetAlternativeNamesFromGeant4PhysicalName(name);
249+
for (const auto& alternativeName : alternativeNames) {
250+
if ((G4String)alternativeName == physicalVolumeName) {
251+
return *physicalVolume;
252+
}
253+
}
248254
}
249255

250256
return nullptr;
@@ -312,40 +318,65 @@ void TRestGeant4GeometryInfo::PopulateFromGeant4World(const G4VPhysicalVolume* w
312318
auto detector = (DetectorConstruction*)G4RunManager::GetRunManager()->GetUserDetectorConstruction();
313319
TRestGeant4Metadata* restG4Metadata = detector->fSimulationManager->GetRestMetadata();
314320

315-
const size_t n = int(world->GetLogicalVolume()->GetNoDaughters());
316-
for (size_t i = 0; i < n + 1; i++) { // world is the + 1
317-
G4VPhysicalVolume* volume;
318-
if (i == n) {
319-
volume = const_cast<G4VPhysicalVolume*>(world);
320-
} else {
321-
volume = world->GetLogicalVolume()->GetDaughter(i);
322-
}
323-
TString namePhysical = (TString)volume->GetName();
324-
if (fGdmlNewPhysicalNames.size() > i) {
325-
// it has been filled
326-
fGeant4PhysicalNameToNewPhysicalNameMap[namePhysical] = fGdmlNewPhysicalNames[i];
327-
}
328-
TString physicalNewName = GetAlternativeNameFromGeant4PhysicalName(namePhysical);
329-
TString nameLogical = (TString)volume->GetLogicalVolume()->GetName();
330-
TString nameMaterial = (TString)volume->GetLogicalVolume()->GetMaterial()->GetName();
331-
auto position = volume->GetTranslation();
332-
333-
fPhysicalToLogicalVolumeMap[physicalNewName] = nameLogical;
334-
fLogicalToMaterialMap[nameLogical] = nameMaterial;
335-
fLogicalToPhysicalMap[nameLogical].emplace_back(namePhysical);
336-
fPhysicalToPositionInWorldMap[physicalNewName] = {position.x(), position.y(), position.z()};
337-
InsertVolumeName(i, physicalNewName);
338-
339-
if (!fIsAssembly && GetAlternativeNameFromGeant4PhysicalName(namePhysical) != namePhysical) {
340-
fIsAssembly = true;
341-
342-
const auto geant4MajorVersionNumber = restG4Metadata->GetGeant4VersionMajor();
343-
if (geant4MajorVersionNumber < 11) {
344-
cout << "User geometry consists of assembly which is not supported for this rest / Geant4 "
345-
"version combination. Please upgrade to Geant4 11.0.0 or more to use this feature"
346-
<< endl;
347-
// exit(1);
321+
// Recursive function to traverse the nested volume geometry
322+
std::function<void(const G4VPhysicalVolume*, size_t&, const G4String pathSoFar, const G4ThreeVector&)>
323+
ProcessVolumeRecursively = [&](const G4VPhysicalVolume* volume, size_t& index,
324+
const G4String pathSoFar, const G4ThreeVector& parentPosition) {
325+
G4String currentPath = pathSoFar;
326+
if (volume->GetName() != world->GetName()) { // avoid all paths including 'world_PV/' at the
327+
// beginning
328+
currentPath += (currentPath.empty() ? "" : fPathSeparator.Data()) + volume->GetName();
348329
}
349-
}
350-
}
330+
G4ThreeVector positionInWorld = volume->GetTranslation() + parentPosition;
331+
332+
// First process the daughters to have the same order in volume IDs as before
333+
G4LogicalVolume* logVol = volume->GetLogicalVolume();
334+
for (size_t i = 0; i < logVol->GetNoDaughters(); ++i) {
335+
G4VPhysicalVolume* daughter = logVol->GetDaughter(i);
336+
ProcessVolumeRecursively(daughter, index, currentPath, positionInWorld);
337+
}
338+
339+
// Process this volume
340+
G4String namePhysical = volume->GetName();
341+
TString physicalNewName = GetAlternativePathFromGeant4Path(currentPath);
342+
if (namePhysical == world->GetName()) {
343+
physicalNewName = namePhysical; // avoid blank name for World_PV
344+
}
345+
fNewPhysicalToGeant4PhysicalNameMap[physicalNewName] = namePhysical;
346+
347+
TString nameLogical = (TString)volume->GetLogicalVolume()->GetName();
348+
TString nameMaterial = (TString)volume->GetLogicalVolume()->GetMaterial()->GetName();
349+
fPhysicalToLogicalVolumeMap[physicalNewName] = nameLogical;
350+
fLogicalToMaterialMap[nameLogical] = nameMaterial;
351+
fLogicalToPhysicalMap[nameLogical].emplace_back(namePhysical);
352+
fPhysicalToPositionInWorldMap[physicalNewName] = {positionInWorld.x(), positionInWorld.y(),
353+
positionInWorld.z()};
354+
InsertVolumeName(index, physicalNewName);
355+
/*
356+
std::cout << "Index: " << index << std::endl;
357+
std::cout << "\tG4name: " << namePhysical << std::endl;
358+
std::cout << "\tgdmlName: " << physicalNewName << std::endl;
359+
std::cout << "\tLogical: " << nameLogical << std::endl;
360+
std::cout << "\tMaterial: " << nameMaterial << std::endl;
361+
std::cout << "\tPosition: (" << positionInWorld.x() << ", " << positionInWorld.y() << ", " <<
362+
positionInWorld.z() << ")mm" << std::endl;
363+
*/
364+
if (!fIsAssembly &&
365+
GetAlternativeNameFromGeant4PhysicalName(namePhysical).Data() != namePhysical) {
366+
fIsAssembly = true;
367+
const auto geant4MajorVersionNumber = restG4Metadata->GetGeant4VersionMajor();
368+
if (geant4MajorVersionNumber < 11) {
369+
cout
370+
<< "User geometry consists of assembly which is not supported for this rest / Geant4 "
371+
"version combination. Please upgrade to Geant4 11.0.0 or more to use this feature"
372+
<< endl;
373+
// exit(1);
374+
}
375+
}
376+
++index;
377+
};
378+
379+
// Start recursion from world volume
380+
size_t index = 0;
381+
ProcessVolumeRecursively(world, index, "", G4ThreeVector(0, 0, 0));
351382
}

0 commit comments

Comments
 (0)