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