Project
Loading...
Searching...
No Matches
ExternalModule.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12// Sandro Wenzel (CERN), 2026
13
16#include <fstream>
18#include <TGeoManager.h>
19#include <TGeoVolume.h>
20#include <TGeoMatrix.h>
21#include <rapidjson/document.h>
22#include <rapidjson/error/en.h>
23#include <rapidjson/istreamwrapper.h>
24
25// ClassImp(o2::passive::ExternalModule)
26
27namespace o2::passive
28{
29
30ExternalModule::ExternalModule(const char* name, const char* long_title, ExternalModuleOptions options) : PassiveBase(name, long_title), mOptions(options)
31{
32}
33
35{
36 // JIT the geom builder macro and obtain the top most module volume
37 auto module_top = o2::base::buildCADVolumeFromMacro(mOptions.root_macro_file, GetName());
38 if (!module_top) {
39 LOG(error) << "No module geometry could be built from " << mOptions.root_macro_file;
40 return;
41 }
42
43 // bring the CAD media under O2's MaterialManager
44 o2::base::remapCADMedia(module_top, GetName());
45
46 // place it into the provided anchor volume (needs to exist)
47 auto anchor = gGeoManager->FindVolumeFast(mOptions.anchor_volume.c_str());
48 if (!anchor) {
49 LOG(error) << "Anchor volume " << mOptions.anchor_volume << " not found. Aborting";
50 return;
51 }
52 anchor->AddNode(module_top, 1, const_cast<TGeoMatrix*>(mOptions.placement));
53}
54
55namespace
56{
57// Build a TGeoCombiTrans from an optional JSON "placement" object carrying
58// "translation":[x,y,z] (cm) and/or "rotation_deg":[rx,ry,rz] (deg, applied X,Y,Z).
59TGeoMatrix* makePlacementFromJSON(const rapidjson::Value& placement)
60{
61 auto combi = new TGeoCombiTrans();
62 if (placement.HasMember("rotation_deg") && placement["rotation_deg"].IsArray()) {
63 const auto& r = placement["rotation_deg"];
64 if (r.Size() == 3) {
65 combi->RotateX(r[0].GetDouble());
66 combi->RotateY(r[1].GetDouble());
67 combi->RotateZ(r[2].GetDouble());
68 } else {
69 LOG(warning) << "ExternalModule placement 'rotation_deg' must have 3 entries; ignoring";
70 }
71 }
72 if (placement.HasMember("translation") && placement["translation"].IsArray()) {
73 const auto& t = placement["translation"];
74 if (t.Size() == 3) {
75 combi->SetDx(t[0].GetDouble());
76 combi->SetDy(t[1].GetDouble());
77 combi->SetDz(t[2].GetDouble());
78 } else {
79 LOG(warning) << "ExternalModule placement 'translation' must have 3 entries; ignoring";
80 }
81 }
82 return combi;
83}
84} // namespace
85
86std::vector<ExternalModule*> ExternalModule::createFromJSON(const std::string& jsonfile)
87{
88 std::vector<ExternalModule*> result;
89
90 auto expanded = o2::utils::expandShellVarsInFileName(jsonfile);
91 std::ifstream fileStream(expanded, std::ios::in);
92 if (!fileStream.is_open()) {
93 LOG(error) << "Cannot open external geometry config file '" << expanded << "'";
94 return result;
95 }
96
97 rapidjson::IStreamWrapper isw(fileStream);
98 rapidjson::Document doc;
99 doc.ParseStream(isw);
100 if (doc.HasParseError()) {
101 LOG(error) << "Error parsing external geometry JSON '" << expanded << "': "
102 << rapidjson::GetParseError_En(doc.GetParseError())
103 << " (offset " << doc.GetErrorOffset() << ")";
104 return result;
105 }
106 if (!doc.HasMember("externalModules") || !doc["externalModules"].IsArray()) {
107 LOG(error) << "External geometry JSON '" << expanded << "' must contain an 'externalModules' array";
108 return result;
109 }
110
111 auto getString = [](const rapidjson::Value& v, const char* key) -> std::string {
112 if (v.HasMember(key) && v[key].IsString()) {
113 return v[key].GetString();
114 }
115 return std::string();
116 };
117
118 for (const auto& entry : doc["externalModules"].GetArray()) {
119 if (!entry.IsObject()) {
120 LOG(error) << "Skipping non-object entry in 'externalModules'";
121 continue;
122 }
123 const auto name = getString(entry, "name");
124 if (name.empty()) {
125 LOG(error) << "Skipping external module entry without 'name'";
126 continue;
127 }
128 ExternalModuleOptions options;
129 options.root_macro_file = getString(entry, "macro");
130 options.anchor_volume = getString(entry, "anchor");
131 if (options.root_macro_file.empty() || options.anchor_volume.empty()) {
132 LOG(error) << "External module '" << name << "' requires both 'macro' and 'anchor'; skipping";
133 continue;
134 }
135 if (entry.HasMember("placement") && entry["placement"].IsObject()) {
136 options.placement = makePlacementFromJSON(entry["placement"]);
137 }
138 auto title = getString(entry, "title");
139 if (title.empty()) {
140 title = name;
141 }
142 LOG(info) << "Configured external module '" << name << "' from macro '" << options.root_macro_file
143 << "' anchored to volume '" << options.anchor_volume << "'";
144 result.push_back(new ExternalModule(name.c_str(), title.c_str(), options));
145 }
146 return result;
147}
148
149} // namespace o2::passive
Helpers to inject CAD-derived (TGeo) geometry into O2 simulation.
StringRef key
static std::vector< ExternalModule * > createFromJSON(const std::string &jsonfile)
a common base class for passive modules - implementing generic functions
Definition PassiveBase.h:24
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint entry
Definition glcorearb.h:5735
const GLdouble * v
Definition glcorearb.h:832
GLuint const GLchar * name
Definition glcorearb.h:781
GLboolean r
Definition glcorearb.h:1233
TGeoVolume * buildCADVolumeFromMacro(const std::string &macroFile, const std::string &instanceTag)
void remapCADMedia(TGeoVolume *top, const char *modulename)
std::string expandShellVarsInFileName(std::string const &input)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"