BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSGeometryFactoryGDML.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) BDSIM Collaboration, 2001 - 2026.
3
4This file is part of BDSIM.
5
6BDSIM is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation version 3 of the License.
9
10BDSIM is distributed in the hope that it will be useful, but
11WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
17*/
18#ifdef USE_GDML
19#include "BDSAcceleratorModel.hh"
20#include "BDSColourFromMaterial.hh"
21#include "BDSColours.hh"
22#include "BDSDebug.hh"
23#include "BDSException.hh"
24#include "BDSGeometryExternal.hh"
25#include "BDSGeometryFactoryGDML.hh"
26#include "BDSGeometryInspector.hh"
27#include "BDSGeometryWriter.hh" // for BDSGeometryWriter::auxType
28#include "BDSGDMLPreprocessor.hh" // also only available with USE_GDML
29#include "BDSGlobalConstants.hh"
30#include "BDSMaterials.hh"
31#include "BDSWarning.hh"
32
33#include "globals.hh"
34#include "G4Colour.hh"
35#include "G4GDMLParser.hh"
36#include "G4LogicalVolume.hh"
37#include "G4UserLimits.hh"
38#include "G4VisAttributes.hh"
39#include "G4VPhysicalVolume.hh"
40
41#include <array>
42#include <exception>
43#include <fstream>
44#include <iostream>
45#include <iterator>
46#include <set>
47#include <sstream>
48#include <string>
49#include <utility>
50#include <vector>
51
52class G4VisAttributes;
53class G4VSolid;
54
55
56BDSGeometryFactoryGDML::BDSGeometryFactoryGDML()
57{;}
58
60 G4String fileName,
61 std::map<G4String, G4Colour*>* mapping,
62 G4bool autoColour,
63 G4double /*suggestedLength*/,
64 G4double /*suggestedHorizontalWidth*/,
65 std::vector<G4String>* namedVacuumVolumes,
66 G4bool makeSensitive,
67 BDSSDType sensitivityType,
68 BDSSDType vacuumSensitivityType,
69 G4UserLimits* userLimitsToAttachToAllLVs)
70{
71 CleanUp();
72
73 // Compensate for G4GDMLParser deficiency in loading more than one file with similar names
74 // in objects. Prepend all names with component name.
75 G4String processedFile;
76 G4bool preprocessGDML = BDSGlobalConstants::Instance()->PreprocessGDML();
77 G4bool preprocessGDMLSchema = BDSGlobalConstants::Instance()->PreprocessGDMLSchema();
78 if (preprocessGDML)
79 {processedFile = BDS::PreprocessGDML(fileName, componentName, preprocessGDMLSchema);} // use all in one method
80 else if (preprocessGDMLSchema) // generally don't process the file but process the schema to local copy only
81 {processedFile = BDS::PreprocessGDMLSchemaOnly(fileName);} // use schema only method
82 else // no processing
83 {processedFile = fileName;}
84 G4String preprocessNameToStrip = preprocessGDML ? componentName+"_" : "";
85
86 G4GDMLParser* parser = new G4GDMLParser();
87 parser->SetOverlapCheck(BDSGlobalConstants::Instance()->CheckOverlaps());
88 parser->Read(processedFile, /*validate=*/true);
89
90 G4VPhysicalVolume* containerPV = parser->GetWorldVolume();
91 G4LogicalVolume* containerLV = containerPV->GetLogicalVolume();
92 G4VSolid* containerSolid = containerLV->GetSolid();
93 G4ThreeVector gdmlWorldOrigin = G4ThreeVector();
94 if (containerPV->GetName() == "world_volume_lv_PV")
95 {
96 gdmlWorldOrigin = parser->GetPosition("PygdmlOrigin"); // TODO check if Pygdml geometry
97 gdmlWorldOrigin[2] = 0.0;
98 }
99
100 // record all pvs and lvs used in this loaded geometry
101 std::set<G4VPhysicalVolume*> pvsGDML;
102 std::set<G4LogicalVolume*> lvsGDML;
103 std::map<G4String, G4Material*> materialsGDML;
104 GetAllLogicalPhysicalAndMaterials(containerPV, pvsGDML, lvsGDML, materialsGDML);
107
108 std::map<G4String, G4Colour*> gdmlColours = BuildColourMap(lvsGDML, parser, componentName);
109 if (mapping)
110 {gdmlColours.insert(mapping->begin(), mapping->end());}
111
112 G4cout << "Loaded GDML file \"" << processedFile << "\" containing:" << G4endl;
113 G4cout << pvsGDML.size() << " physical volumes, and " << lvsGDML.size() << " logical volumes" << G4endl;
114
115 auto visesGDML = ApplyColourMapping(lvsGDML, gdmlColours, autoColour, preprocessNameToStrip);
116
117 G4UserLimits* ul = userLimitsToAttachToAllLVs ? userLimitsToAttachToAllLVs : BDSGlobalConstants::Instance()->DefaultUserLimits();
118 ApplyUserLimits(lvsGDML, ul);
119
120 // make sure container is visible - Geant4 always makes the container invisible.
121 G4Colour* c = BDSColourFromMaterial::Instance()->GetColour(containerLV->GetMaterial(), preprocessNameToStrip);
122 G4VisAttributes* vis = new G4VisAttributes(*c);
123 vis->SetVisibility(true);
124 visesGDML.insert(vis);
125 containerLV->SetVisAttributes(vis);
126
127 std::pair<BDSExtent, BDSExtent> outerInner = BDS::DetermineExtents(containerSolid);
128
129 BDSGeometryExternal* result = new BDSGeometryExternal(containerSolid, containerLV,
130 outerInner.first, /*outer*/
131 outerInner.second, /*inner*/
132 gdmlWorldOrigin);
133 result->RegisterLogicalVolume(lvsGDML);
134 result->RegisterPhysicalVolume(pvsGDML);
135 result->RegisterVisAttributes(visesGDML);
136 result->RegisterVacuumVolumes(GetVolumes(lvsGDML, namedVacuumVolumes, preprocessGDML, componentName));
137
138 if (makeSensitive)
139 {
140 const auto &vacuumVolumes = result->VacuumVolumes();
141 ApplySensitivity(result,
142 result->GetAllLogicalVolumes(),
143 sensitivityType,
144 vacuumVolumes,
145 vacuumSensitivityType);
146 }
147
148 delete parser;
149 return result;
150}
151
152std::map<G4String, G4Colour*> BDSGeometryFactoryGDML::BuildColourMap(const std::set<G4LogicalVolume*>& lvsGDML,
153 G4GDMLParser* parser,
154 const G4String& componentName)
155{
156 std::map<G4String, G4Colour*> result;
157 G4int iColour = 0;
158 for (auto lv : lvsGDML)
159 {
160 auto auxInfo = parser->GetVolumeAuxiliaryInformation(lv);
161 for (const auto& af : auxInfo)
162 {
163 if (af.type == "colour")
164 {
165 std::stringstream ss(af.value);
166 std::vector<G4String> colVals((std::istream_iterator<G4String>(ss)), std::istream_iterator<G4String>());
167 if (colVals.size() != 4)
168 {BDS::Warning(__METHOD_NAME__, "invalid number of colour values for logical volume " + lv->GetName());}
169 G4String colourName = componentName + "_colour_"+std::to_string(iColour);
170 iColour++;
171 G4String colourString = colourName + ":";
172 for (const auto& c : colVals)
173 {colourString += " " + c;}
174 // false = don't normalise to 255 as already done so
175 G4Colour* colour = BDSColours::Instance()->GetColour(colourString, false);
176 result[lv->GetName()] = colour;
177 }
178 else if (af.type == BDSGeometryWriter::auxType)
179 {
180 G4bool visible = false;
181 std::array<G4double, 4> rgba = VRGBAStringAndUnitToColourAndStyle(af.value, visible);
182 if (visible)
183 {
184 G4Colour* colour = BDSColours::Instance()->GetColour(rgba[0], rgba[1], rgba[2], rgba[3]);
185 result[lv->GetName()] = colour;
186 }
187 }
188 }
189 }
190 return result;
191}
192
193std::array<G4double, 4> BDSGeometryFactoryGDML::VRGBAStringAndUnitToColourAndStyle(const G4String& value,
194 G4bool& visible)
195{
196 std::array<G4double, 4> result{0,0,0,0};
197 std::stringstream ss(value);
198 try
199 {
200 ss >> visible;
201 G4int i = 0;
202 G4double v = 0;
203 while (ss >> v)
204 {
205 if (i > 3)
206 {break;}
207 result[i] = v;
208 i++;
209 }
210 }
211 catch (std::exception& e)
212 {throw BDSException(__METHOD_NAME__, "error in colour definition " + value);}
213 return result;
214}
215
216G4String BDSGeometryFactoryGDML::PreprocessedName(const G4String& objectName,
217 const G4String& acceleratorComponentName) const
218{return BDSGDMLPreprocessor::ProcessedNodeName(objectName, acceleratorComponentName);}
219
221 std::set<G4VPhysicalVolume*>& pvsIn,
222 std::set<G4LogicalVolume*>& lvsIn,
223 std::map<G4String, G4Material*>& materialsGDML)
224{
225 const auto& lv = volume->GetLogicalVolume();
226 lvsIn.insert(lv);
227 G4Material* mat = lv->GetMaterial();
228 materialsGDML[mat->GetName()] = mat;
229 for (G4int i = 0; i < (G4int)lv->GetNoDaughters(); i++)
230 {
231 const auto& pv = lv->GetDaughter(i);
232 pvsIn.insert(pv);
233 GetAllLogicalPhysicalAndMaterials(pv, pvsIn, lvsIn, materialsGDML); // recurse into daughter
234 }
235}
236
238 const G4String& outputFileName,
239 const G4String& key,
240 const G4String& replacement)
241{
242 // open input file in read mode
243 std::ifstream ifs(fileName);
244
245 // verify file open.
246 if (!ifs.is_open())
247 {throw BDSException(__METHOD_NAME__, "Cannot open file \"" + fileName + "\"");}
248
249 std::ofstream fout(outputFileName);
250#ifdef BDSDEBUG
251 G4cout << __METHOD_NAME__ << "Original file: " << fileName << G4endl;
252 G4cout << __METHOD_NAME__ << "Temporary file: " << outputFileName << G4endl;
253#endif
254
255 int lenOfKey = (int)key.size();
256
257 // loop over and replace
258 std::string buffer;
259 while (std::getline(ifs, buffer))
260 {// if we find key, replace it
261 int f = (int)buffer.find(key);
262 if (f != -1)
263 {
264 std::string outputString = std::string(buffer);
265 outputString.replace(f, lenOfKey, replacement);
266 fout << outputString << "\n"; // getline strips \n
267 }
268 else // copy line to temp file as is
269 {fout << buffer << "\n";}
270 }
271
272 // clean up
273 ifs.close();
274 fout.close();
275}
276
277#else
278// insert empty function to avoid no symbols warning
279void _SymbolToPreventWarningGeomFacGDML(){;}
280#endif
static BDSColourFromMaterial * Instance()
Singleton pattern.
G4Colour * GetColour(const G4Material *material, const G4String &prefixToStripFromName="")
Get colour from name.
G4Colour * GetColour(G4double red, G4double green, G4double blue, G4double alpha=1)
Get a cached anonymous colour by values.
static BDSColours * Instance()
singleton pattern
Definition BDSColours.cc:32
General exception with possible name of object and message.
static G4String ProcessedNodeName(const G4String &nodeName, const G4String &prefix)
void RegisterLogicalVolume(G4LogicalVolume *logicalVolume)
virtual std::set< G4LogicalVolume * > GetAllLogicalVolumes() const
Access all logical volumes belonging to this component.
void RegisterPhysicalVolume(G4VPhysicalVolume *physicalVolume)
void RegisterVisAttributes(G4VisAttributes *visAttribute)
A loaded piece of externally provided geometry.
void RegisterVacuumVolumes(const std::set< G4LogicalVolume * > &vacuumVolumesIn)
Register a set of volumes to be identified as vacuum volumes for the BDSAcceleratorComponent.
const std::set< G4LogicalVolume * > & VacuumVolumes() const
Access the vacuum volumes.
virtual void ApplySensitivity(BDSGeometryExternal *result, const std::set< G4LogicalVolume * > &allLogicalVolumesIn, BDSSDType generalSensitivity, const std::set< G4LogicalVolume * > &vacuumLogicalVolumes, BDSSDType vacuumSensitivity)
Attach the relevant general and vacuum sensitivity to each volume.
std::set< G4LogicalVolume * > GetVolumes(const std::set< G4LogicalVolume * > &allLVs, std::vector< G4String > *volumeNames, G4bool preprocessGDML, const G4String &componentName) const
Get the volumes that match the name. Volume names are matched exactly and are case sensitive.
virtual void CleanUp()
Virtual clean up that derived classes can override that calls CleanUpBase().
virtual void ApplyUserLimits(const std::set< G4LogicalVolume * > &lvsIn, G4UserLimits *userLimits)
Attach a set of user limits to every logical volume supplied.
virtual std::set< G4VisAttributes * > ApplyColourMapping(const std::set< G4LogicalVolume * > &lvs, const std::map< G4String, G4Colour * > &mapping, G4bool autoColour, const G4String &preprocessPrefix="")
void GetAllLogicalPhysicalAndMaterials(const G4VPhysicalVolume *volume, std::set< G4VPhysicalVolume * > &pvs, std::set< G4LogicalVolume * > &lvs, std::map< G4String, G4Material * > &materialsGDML)
static std::array< G4double, 4 > VRGBAStringAndUnitToColourAndStyle(const G4String &value, G4bool &visible)
virtual BDSGeometryExternal * Build(G4String componentName, G4String fileName, std::map< G4String, G4Colour * > *colourMapping=nullptr, G4bool autoColour=true, G4double suggestedLength=0, G4double suggestedHorizontalWidth=0, std::vector< G4String > *namedVacuumVolumes=nullptr, G4bool makeSensitive=true, BDSSDType sensitivityType=BDSSDType::energydep, BDSSDType vacuumSensitivityType=BDSSDType::energydepvacuum, G4UserLimits *userLimitsToAttachToAllLVs=nullptr)
virtual G4String PreprocessedName(const G4String &objectName, const G4String &acceleratorComponentName) const
Use the GDML preprocessing scheme to prepare the preprocessed volume names.
void ReplaceStringInFile(const G4String &filename, const G4String &outputFileName, const G4String &key, const G4String &replacement)
static const G4String auxType
"bds_vrgba" - short to minimise output file size: "bdsim visibility rgba"
static BDSGlobalConstants * Instance()
Access method.
static BDSMaterials * Instance()
Singleton pattern access.
void CacheMaterialsFromGDML(const std::map< G4String, G4Material * > &materialsGDML)
Introduce materials loaded from GDML into this instance.
void CheckForConflictingMaterialsAfterLoad(const G4String &geometryFileName, const G4String &componentName) const
Improve type-safety of native enum data type in C++.
std::pair< BDSExtent, BDSExtent > DetermineExtents(const G4VSolid *solid)