9 #include <framework/logging/Logger.h>
10 #include <framework/gearbox/GearDir.h>
11 #include <framework/database/IntervalOfValidity.h>
12 #include <geometry/GeometryManager.h>
13 #include <geometry/Materials.h>
14 #include <geometry/CreatorManager.h>
15 #include <geometry/CreatorBase.h>
16 #include <geometry/utilities.h>
17 #include <geometry/dbobjects/GeoConfiguration.h>
18 #include <geometry/bfieldmap/BFieldMap.h>
19 #include <geometry/bfieldmap/BFieldFrameworkInterface.h>
20 #include <framework/dbobjects/MagneticField.h>
21 #include <framework/database/DBStore.h>
24 #include "G4ThreeVector.hh"
25 #include "G4LogicalVolume.hh"
26 #include "G4PVPlacement.hh"
28 #include "G4RunManager.hh"
29 #include "G4GeometryManager.hh"
30 #include "G4PhysicalVolumeStore.hh"
31 #include "G4LogicalVolumeStore.hh"
32 #include "G4SolidStore.hh"
33 #include "G4RegionStore.hh"
34 #include "G4SurfaceProperty.hh"
35 #include "G4LogicalBorderSurface.hh"
36 #include "G4LogicalSkinSurface.hh"
37 #include "G4VisAttributes.hh"
38 #include "G4VoxelLimits.hh"
41 #include "Geant4GM/volumes/Factory.h"
42 #include "RootGM/volumes/Factory.h"
43 #include "VGM/volumes/IPlacement.h"
44 #include "TGeoManager.h"
55 using namespace gearbox;
67 double getTopMinSize(
const std::string& name, EAxis axis, G4LogicalVolume* volume,
double current)
69 G4VoxelLimits dummyLimits;
71 for (
size_t i = 0; i < volume->GetNoDaughters(); ++i) {
72 G4VPhysicalVolume* daughter = volume->GetDaughter(i);
73 G4AffineTransform trans(daughter->GetRotation(), daughter->GetTranslation());
74 double vmin{0}, vmax{0};
75 daughter->GetLogicalVolume()->GetSolid()->CalculateExtent((EAxis) axis, dummyLimits, trans, vmin, vmax);
76 extent = std::max({extent, std::fabs(vmin), std::fabs(vmax)});
78 B2DEBUG(100,
"Current global volume size in " << name <<
": " << std::fixed
79 << std::setprecision(std::numeric_limits<double>::max_digits10)
80 << current <<
", needed: " << extent);
81 if (current < extent && (extent - current) > Unit::um) {
83 B2WARNING(
"Global volume not large enough in " << name <<
" direction, enlarging from "
84 << current <<
" mm to " << extent <<
" mm");
86 B2DEBUG(10,
"Setting global volume size to " << name <<
"= +-" << extent <<
" mm");
102 void GeometryManager::clear()
104 B2DEBUG(50,
"Cleaning up Geometry");
105 for (G4VisAttributes* visAttr : m_VisAttributes)
delete visAttr;
106 m_VisAttributes.clear();
107 for (
CreatorBase* creator : m_creators)
delete creator;
109 m_topVolume =
nullptr;
111 G4GeometryManager::GetInstance()->OpenGeometry();
112 G4PhysicalVolumeStore::Clean();
113 G4LogicalVolumeStore::Clean();
114 G4SolidStore::Clean();
115 G4LogicalBorderSurface::CleanSurfaceTable();
116 G4LogicalSkinSurface::CleanSurfaceTable();
117 G4SurfaceProperty::CleanSurfacePropertyTable();
119 Materials::getInstance().clear();
124 std::string detectorName;
126 detectorName = detectorDir.
getString(
"Name");
127 B2DEBUG(50,
"Creating geometry for detector: " << detectorName);
128 }
catch (gearbox::PathEmptyError& e) {
129 B2FATAL(
"Could not read detector name, make sure gearbox is connected and "
130 << detectorDir.
getPath() <<
" points to the geometry description");
133 const double globalWidth = detectorDir.
getLength(
"Global/width", 0);
134 const double globalHeight = detectorDir.
getLength(
"Global/height", 0);
135 const double globalLength = detectorDir.
getLength(
"Global/length", 0);
136 const std::string globalMaterial = detectorDir.
getString(
"Global/material",
"Air");
138 GeoConfiguration config(detectorName, globalWidth, globalHeight, globalLength, globalMaterial);
141 Materials& materials = Materials::getInstance();
143 for (
const GearDir& mat : matlist.getNodes(
"Material")) {
145 config.addMaterial(material);
149 std::set<std::string> componentNames = m_components;
150 std::set<std::string> excludedNames = m_excluded;
151 std::set<std::string> additionalNames = m_additional;
152 if (!m_components.empty() && !m_additional.empty()) {
153 B2WARNING(
"Additional components are ignored when a list of components is provided.");
157 for (
const GearDir& component : detectorDir.
getNodes(
"DetectorComponent")) {
161 name = component.getString(
"@name");
162 creatorName = component.getString(
"Creator");
163 }
catch (gearbox::PathEmptyError& e) {
164 B2ERROR(
"Could not find required element Name or Creator for " << component.getPath());
167 const bool isDefault = component.getBool(
"@isDefault",
true);
170 componentNames.erase(name);
171 excludedNames.erase(name);
172 additionalNames.erase(name);
173 if (!m_components.empty() && m_components.count(name) == 0) {
174 B2DEBUG(50,
"DetectorComponent " << name <<
" not in list of components, skipping");
177 if (m_components.empty() && !isDefault) {
178 if (m_additional.count(name) == 0) {
179 B2DEBUG(50,
"DectorComponent " << name <<
" is not enabled by default, skipping");
182 B2DEBUG(50,
"DectorComponent " << name <<
" is enabled in addition to the default components");
185 if (!m_excluded.empty() && m_excluded.count(name) > 0) {
186 B2DEBUG(10,
"DetectorComponent " << name <<
" in list of excluded components, skipping");
190 string libraryName = component.getString(
"Creator/@library",
"");
192 CreatorBase* creator = CreatorManager::getCreator(creatorName, libraryName);
196 B2ERROR(
"Could not load creator " << creatorName <<
" from " << libraryName);
199 config.addComponent({name, creatorName, libraryName});
205 auto checkRemaining = [](
const std::string & type,
const std::set<std::string>& remainingNames) {
206 for (
const std::string& name : remainingNames) {
207 B2ERROR(
"Geometry '" << name <<
"' is specified in list of "
208 << type <<
" but could not be found");
212 checkRemaining(
"components", componentNames);
213 checkRemaining(
"excluded components", excludedNames);
214 checkRemaining(
"additional components", additionalNames);
222 createGeometry(config, type,
false);
232 BFieldMap::Instance().clear();
236 DBStore::Instance().addConstantOverride(
"MagneticField", fieldmap,
false);
240 G4RunManager* runManager = G4RunManager::GetRunManager();
241 if (runManager) runManager->ReinitializeGeometry(
true,
true);
244 B2DEBUG(10,
"Creating geometry for detector: " << config.getName());
247 Materials& materials = Materials::getInstance();
248 for (
const GeoMaterial& mat : config.getMaterials()) {
254 G4Material* top_mat = Materials::get(config.getGlobalMaterial());
255 double xHalfLength = config.getGlobalWidth() / Unit::cm * CLHEP::cm;
256 double yHalfLength = config.getGlobalHeight() / Unit::cm * CLHEP::cm;
257 double zHalfLength = config.getGlobalLength() / Unit::cm * CLHEP::cm;
261 G4Box* top_box =
new G4Box(
"Top", xHalfLength > 0 ? xHalfLength : 1,
262 yHalfLength > 0 ? yHalfLength : 1,
263 zHalfLength > 0 ? zHalfLength : 1);
264 G4LogicalVolume* top_log =
new G4LogicalVolume(top_box, top_mat,
"Top",
nullptr,
nullptr,
nullptr);
266 m_topVolume =
new G4PVPlacement(
nullptr, G4ThreeVector(), top_log,
"Top",
nullptr,
false, 0);
267 B2DEBUG(10,
"Created top volume with x= +-" << config.getGlobalWidth() <<
" cm, y= +-"
268 << config.getGlobalHeight() <<
" cm, z= +-" << config.getGlobalLength() <<
" cm");
271 auto getDensityScale = [
this](
const std::string & name) {
272 std::optional<double> scale;
273 if (
auto it = m_densityScaling.find(name); it != m_densityScaling.end()) {
278 auto globalScale = getDensityScale(
"*");
280 for (
const GeoComponent& component : config.getComponents()) {
281 CreatorBase* creator = CreatorManager::getCreator(component.getCreator(), component.getLibrary());
284 auto componentScale = getDensityScale(component.getName());
285 if (componentScale or globalScale) {
286 double scale = globalScale ? *globalScale : 1.0;
287 if (componentScale) scale *= *componentScale;
288 Materials::getInstance().setDensityScale(scale);
291 int oldSolids = G4SolidStore::GetInstance()->size();
292 int oldLogical = G4LogicalVolumeStore::GetInstance()->size();
293 int oldPhysical = G4PhysicalVolumeStore::GetInstance()->size();
295 if (!useDB)
throw CreatorBase::DBNotImplemented();
296 creator->
createFromDB(component.getName(), *top_log, type);
297 B2DEBUG(50,
"called creator " << component.getCreator() <<
" to create component " << component.getName() <<
" from DB");
299 }
catch (CreatorBase::DBNotImplemented& e) {
300 GearDir parameters = Gearbox::getInstance().getDetectorComponent(component.getName());
301 creator->
create(parameters, *top_log, type);
302 B2DEBUG(50,
"called creator " << component.getCreator() <<
" to create component " << component.getName() <<
" from Gearbox");
304 int newSolids = G4SolidStore::GetInstance()->size() - oldSolids;
305 int newLogical = G4LogicalVolumeStore::GetInstance()->size() - oldLogical;
306 int newPhysical = G4PhysicalVolumeStore::GetInstance()->size() - oldPhysical;
307 B2DEBUG(50,
"DetectorComponent " << component.getName() <<
" created " << newSolids
308 <<
" solids, " << newLogical <<
" logical volumes and "
309 << newPhysical <<
" physical volumes");
310 m_creators.push_back(creator);
312 Materials::getInstance().resetDensityScale();
313 if (m_assignRegions) {
315 G4Region* region {
nullptr};
318 for (
size_t i = 0; i < top_log->GetNoDaughters(); ++i) {
319 G4LogicalVolume* vol = top_log->GetDaughter(i)->GetLogicalVolume();
321 if (!vol->GetRegion()) {
323 if (!region) region = G4RegionStore::GetInstance()->FindOrCreateRegion(component.getName());
324 vol->SetRegion(region);
326 region->AddRootLogicalVolume(vol);
333 int newSolids = G4SolidStore::GetInstance()->size();
334 int newLogical = G4LogicalVolumeStore::GetInstance()->size();
335 int newPhysical = G4PhysicalVolumeStore::GetInstance()->size();
336 B2DEBUG(50,
"Created a total of " << newSolids <<
" solids, " << newLogical
337 <<
" logical volumes and " << newPhysical <<
" physical volumes");
340 top_box->SetXHalfLength(getTopMinSize(
"x", kXAxis, top_log, xHalfLength));
341 top_box->SetYHalfLength(getTopMinSize(
"y", kYAxis, top_log, yHalfLength));
342 top_box->SetZHalfLength(getTopMinSize(
"z", kZAxis, top_log, zHalfLength));
344 B2DEBUG(50,
"Optimizing geometry and creating lookup tables ...");
345 G4GeometryManager::GetInstance()->CloseGeometry(
true, LogSystem::Instance().isLevelEnabled(LogConfig::c_Debug, 200, PACKAGENAME()));
348 void GeometryManager::createTGeoRepresentation()
351 B2ERROR(
"No Geometry found, please create a geometry before converting it to ROOT::TGeo");
355 Geant4GM::Factory g4Factory;
356 if (LogSystem::Instance().isLevelEnabled(LogConfig::c_Debug, 200, PACKAGENAME())) {
357 g4Factory.SetDebug(1);
359 g4Factory.Import(m_topVolume);
360 RootGM::Factory rtFactory;
361 rtFactory.SetIgnore(1);
362 if (LogSystem::Instance().isLevelEnabled(LogConfig::c_Debug, 200, PACKAGENAME())) {
363 rtFactory.SetDebug(1);
365 g4Factory.Export(&rtFactory);
366 gGeoManager->CloseGeometry();
367 delete g4Factory.Top();
368 delete rtFactory.Top();
371 G4VisAttributes* GeometryManager::newVisAttributes()
373 m_VisAttributes.push_back(
new G4VisAttributes());
374 return m_VisAttributes.back();
Simple BFieldComponent to just wrap the existing BFieldMap with the new BFieldManager.
GearDir is the basic class used for accessing the parameter store.
virtual std::string getString(const std::string &path="") const noexcept(false) override
Get the parameter path as a string.
Describe one component of the Geometry.
configuration of the geometry
Class to represent a material informaion in the Database.
A class that describes the interval of experiments/runs for which an object in the database is valid.
std::string getPath() const
Return path of the current interface.
double getLength(const std::string &path="") const noexcept(false)
Get the parameter path as a double converted to the standard length unit.
std::vector< GearDir > getNodes(const std::string &path="") const
Get vector of GearDirs which point to all the nodes the given path evaluates to.
Pure virtual base class for all geometry creators.
virtual void createFromDB(const std::string &name, G4LogicalVolume &topVolume, GeometryTypes type)
Function to create the geometry from the Database.
virtual void create(const GearDir &content, G4LogicalVolume &topVolume, GeometryTypes type)=0
Function to actually create the geometry, has to be overridden by derived classes.
virtual void createPayloads(const GearDir &content, const IntervalOfValidity &iov)
Function to create the geometry database.
Class to manage the creation and conversion of the geometry.
Thin wrapper around the Geant4 Material system.
GeoMaterial createMaterialConfig(const gearbox::Interface ¶meters)
Create Material from XML description.
G4Material * createMaterial(const gearbox::Interface ¶meters)
Create a material from the parameters specified by parameters.
void setVisibility(G4LogicalVolume &volume, bool visible)
Helper function to quickly set the visibility of a given volume.
GeometryTypes
Flag indiciating the type of geometry to be used.
Abstract base class for different kinds of events.