Skip to content

Commit

Permalink
Implement conversion of G4PVReplica to VecGeom PlacedVolumes (#25)
Browse files Browse the repository at this point in the history
* Import GDML generated from Geant4 Basic Example B5 as of v11.3

Generated by modifying `DetectorConstruction::Construct()` with:

```c++
G4GDMLParser parser;
parser.Write("B5.gdml", worldPhysical);
```

immediately before returning `worldPhysical`.

* Support conversion of G4PVReplica to VecGeom placements

Need identified in AdePT/Celeritas benchmarks using Geant4's example
B5, which uses `G4PVReplica` to model some of its geometry components.
The conversion will fail as `G4PVReplica` has no direct equivalent in
VecGeom.

Implement conversion of `G4PVReplica` by creating individual placements
of the replicated logical volumes. Use `G4ReplicaNavigation` to transform
the volume before creating the placement with this transform. Note that
this only works with rotational or linear replication. Radial replication
implies changes to the underlying solid's dimensions.

Use exported B5 geometry GDML file to implement a unit test of the
conversion. NB: this currently fails due to a seemingly issue with treatment
of pointers in the name of the top volume.

* Remove pointer from main setup volume name

Follows pattern in other test files and needed to get ReplicaTest
unit test to pass.
  • Loading branch information
drbenmorgan authored Feb 21, 2025
1 parent 638c273 commit b962627
Show file tree
Hide file tree
Showing 3 changed files with 906 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/g4vg_impl/Converter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#include <G4LogicalVolumeStore.hh>
#include <G4PVDivision.hh>
#include <G4PVPlacement.hh>
#include <G4PVReplica.hh>
#include <G4ReflectionFactory.hh>
#include <G4ReplicaNavigation.hh>
#include <G4VPhysicalVolume.hh>
#include <VecGeom/management/Logger.h>
#include <VecGeom/management/ReflFactory.h>
Expand Down Expand Up @@ -308,6 +310,18 @@ auto Converter::build_with_daughters(G4LogicalVolume const* mother_g4lv)
place_daughter(g4pv);
}
}
else if (auto* replica = dynamic_cast<G4PVReplica*>(g4pv))
{
// TODO: check and error if the replica uses the kRaxis replication
G4ReplicaNavigation replica_navigator;
for (size_type j = 0, jmax = replica->GetMultiplicity(); j != jmax;
++j)
{
replica_navigator.ComputeTransformation(j, replica);
replica->SetCopyNo(j);
place_daughter(replica);
}
}
else
{
TypeDemangler<G4VPhysicalVolume> demangle_pv_type;
Expand Down
87 changes: 87 additions & 0 deletions test/G4VG.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,93 @@ TEST_F(CmsEeBackDeeTest, no_refl_factory)
result.expect_eq(this->base_ref());
}

//---------------------------------------------------------------------------//
class ReplicaTest : public G4VGTestBase
{
protected:
std::string basename() const override { return "B5"; }

static TestResult base_ref();
};

TestResult ReplicaTest::base_ref()
{
TestResult ref;
ref.lv_name = {
"magneticLogical",
"hodoscope1Logical",
"wirePlane1Logical",
"chamber1Logical",
"firstArmLogical",
"hodoscope2Logical",
"wirePlane2Logical",
"chamber2Logical",
"cellLogical",
"EMcalorimeterLogical",
"HadCalScintiLogical",
"HadCalLayerLogical",
"HadCalCellLogical",
"HadCalColumnLogical",
"HadCalorimeterLogical",
"secondArmLogical",
"worldLogical",
};
ref.solid_capacity = {
6283185307.179586,
400000.0,
240000.0,
2.4e+07,
3.6e+10,
400000.0,
360000.0,
3.6e+07,
6.75e+06,
5.4e+08,
900000.0,
4.5e+06,
9e+07,
1.8e+08,
1.8e+09,
1.12e+11,
2.4e+12,
};
ref.pv_name = {
"magneticPhysical",
};
// 15 direct placements
ref.pv_name.insert(ref.pv_name.end(), 15, "hodoscope1Physical");
ref.pv_name.push_back("wirePlane1Physical");
// 5 direct placements
ref.pv_name.insert(ref.pv_name.end(), 5, "chamber1Physical");
ref.pv_name.push_back("firstArmPhysical");
// 25 direct placements
ref.pv_name.insert(ref.pv_name.end(), 25, "hodoscope2Physical");
ref.pv_name.push_back("wirePlane2Physical");
// 5 direct placements
ref.pv_name.insert(ref.pv_name.end(), 5, "chamber2Physical");
// 20x4 = 80 parameterized placements of cellLogical
ref.pv_name.insert(ref.pv_name.end(), 80, "cellLogical_param");
ref.pv_name.push_back("EMcalorimeterPhysical");
ref.pv_name.push_back("HadCalScintiPhysical");
// 20 replicas of HadCalLayerLogical
ref.pv_name.insert(ref.pv_name.end(), 20, "HadCalLayerLogical_PV");
// 2 replicas of HadCalCellLogical
ref.pv_name.insert(ref.pv_name.end(), 2, "HadCalCellLogical_PV");
// 10 replicas of HadCalColumnLogical
ref.pv_name.insert(ref.pv_name.end(), 10, "HadCalColumnLogical_PV");
ref.pv_name.push_back("HadCalorimeterPhysical");
ref.pv_name.push_back("fSecondArmPhys");
ref.pv_name.push_back("worldLogical_PV");

return ref;
}

TEST_F(ReplicaTest, default_options)
{
auto result = this->run(Options{});
result.expect_eq(this->base_ref());
}

//---------------------------------------------------------------------------//
} // namespace test
} // namespace g4vg
Loading

0 comments on commit b962627

Please sign in to comment.