Progressive enhancement philosophy :
start simple and then refine...
├── include │ └── MCHSimulation
│ ├── Detector.h │ ├── Geometry.h │ ├── GeometryTest.h │ └── Hit.h
├── macros │ ├── drawMCHGeometry.C ├── src │ ├── Detector.cxx │ ├── Geometry.cxx │ ├── GeometryTest.cxx │ ├── Hit.cxx │ ├── Materials.cxx │ ├── Materials.h │ ├── Station1Geometry.cxx │ ├── Station1Geometry.h │ ├── Station2Geometry.cxx │ ├── Station2Geometry.h │ ├── Station345Geometry.cxx │ ├── Station345Geometry.h │ ├── Stepper.cxx │ └── Stepper.h └── test ├── CMakeLists.txt └── testGeometry.cxx
Geometry.h
namespace o2 { namespace mch {
/// createGeometry creates MCH geometry and attach it to existing topVolume
void createGeometry(TGeoVolume& topVolume);
/// get a list of MCH sensitive volumes
std::vector<TGeoVolume*> getSensitiveVolumes();
/// get the local-to-global transformation for a given detection element
o2::Transform3D getTransformation(int detElemId, const TGeoManager& geo);
}}
Hit.h
namespace o2 { namespace mch {
class Hit : public ::o2::BasicXYZEHit<float>
{
public:
Hit(int trackId = 0,
short detElemId = 0,
Point3D<float> entrancePoint = {},
const Point3D<float> exitPoint = {},
float eloss = 0.0,
float length = 0.0,
float tof = 0.0);
Point3D<float> entrancePoint() const;
Point3D<float> exitPoint() const;
short detElemId() const;
private:
float mLength = {};
Point3D<float> mExitPoint = {};
ClassDefNV(Hit, 1);
};
}}
Detector
= {geo creation (functions), hit creation (class)}
namespace o2 { namespace mch {
Detector::Detector(bool active)
: o2::Base::DetImpl<Detector>("MCH", active), mStepper{ new o2::mch::Stepper } {}
void Detector::defineSensitiveVolumes() {
for (auto* vol : getSensitiveVolumes()) {
AddSensitiveVolume(vol);
}
}
void Detector::Initialize() {
defineSensitiveVolumes();
o2::Base::Detector::Initialize();
}
void Detector::ConstructGeometry() {
createGeometry(*top);
}
Bool_t Detector::ProcessHits(FairVolume* v) {
mStepper->process(*fMC);
return kTRUE;
}
std::vector<o2::mch::Hit>* Detector::getHits(int i) {
if (i == 0) {
return mStepper->getHits();
}
return nullptr;
}
void Detector::Register()
{
// TODO : get another way to do I/O (i.e. separate concerns)
mStepper->registerHits(addNameTo("Hit").c_str());
}
void Detector::EndOfEvent() { mStepper->resetHits(); }
}}
GeometryTest.h
namespace o2 { namespace mch { namespace test {
/// creates MCH geometry from scratch (i.e. from a null TGeoManager)
/// usefull for tests or drawing for instance.
void createStandaloneGeometry();
/// tree like textual dump of the geometry nodes
void showGeometryAsTextTree(const char* fromPath = "", int maxdepth = 2, std::ostream& out = std::cout);
/// basic drawing of the geometry
void drawGeometry();
/// set the volume and daughter visibility for all volumes with a name matching the regexp pattern
void setVolumeVisibility(const char* pattern, bool visible, bool visibleDaughters);
/// set the volume line and fill for all volumes with a name matching the regexp pattern
void setVolumeColor(const char* pattern, int lineColor, int fillColor);
inline void setVolumeColor(const char* pattern, int color)
{
setVolumeColor(pattern, color, color);
}
/// get a radlen radiograph of a given detection element within box with the given granularity
TH2* getRadio(int detElemId, float xmin, float ymin, float xmax, float ymax, float xstep, float ystep, float thickness = 5 /* cm */);
}}}
<X/X0>
for detection elementsBoth are linked
Ideally informed by next test beam
Not before automn ?
void createStandaloneGeometry()
{
if (gGeoManager && gGeoManager->GetTopVolume()) {
std::cerr << "Can only call this function with an empty geometry, i.e. gGeoManager==nullptr "
<< " or gGeoManager->GetTopVolume()==nullptr\n";
}
TGeoManager* g = new TGeoManager("MCH-ONLY", "ALICE MCH Standalone Geometry");
TGeoVolume* top = createAirVacuumCave("cave");
g->SetTopVolume(top);
o2::mch::createGeometry(*top);
}
easy to include in a unit test
[build] Starting build
[proc] Executing command: /usr/local/bin/cmake --build /Users/laurent/alice/sw/BUILD/O2-latest-dpl-mch-test/O2 --config RelWithDebInfo --target all -- -j 10
[build] [1/11] Running utility command for svnheader
[build] [2/11] Building CXX object Detectors/MUON/MCH/Simulation/CMakeFiles/MCHSimulation.dir/src/GeometryTest.cxx.o
[build] [3/11] Linking CXX shared library lib/libMCHSimulation.dylib
[build] [4/11] Linking CXX executable bin/o2sim_parallel
[build] [5/11] Linking CXX executable bin/o2sim
[build] [6/11] Linking CXX executable bin/o2ITSClusterizers
[build] [7/11] Linking CXX executable bin/runTPC
[build] [8/11] Linking CXX executable bin/o2TPCSimulation
[build] [9/11] Linking CXX executable bin/O2HitMergerRunner
[build] [10/11] Linking CXX executable bin/O2PrimaryServerDeviceRunner
[build] [11/11] Linking CXX executable bin/O2SimDeviceRunner
[build] Build finished with exit code 0
root [0] o2::mch::test::createStandaloneGeometry()
root [1] o2::mch::test::showGeometryAsTextTree("/cave",2)
cave_1
├──SC01I_0
│ ├──Quadrant (chamber 1)_101
│ └──Quadrant (chamber 1)_102
├──SC01O_1
│ ├──Quadrant (chamber 1)_100
│ └──Quadrant (chamber 1)_103
...
├──SC05I_8
│ ├──Chamber 5 support panel_8
│ ├──122000SR1_500
│ ├──112200SR2_501
│ ├──122200S_502
│ ├──222000N_503
│ ├──220000N_504
│ ├──220000N_514