BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSBeamlineBLMBuilder.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#include "BDSBeamline.hh"
19#include "BDSBeamlineElement.hh"
20#include "BDSBeamlineBLMBuilder.hh"
21#include "BDSBLM.hh"
22#include "BDSBLMFactory.hh"
23#include "BDSBLMRegistry.hh"
24#include "BDSDebug.hh"
25#include "BDSDetectorConstruction.hh"
26#include "BDSException.hh"
27#include "BDSExtent.hh"
28#include "BDSGeometryFactory.hh"
29#include "BDSParser.hh"
30#include "BDSScorerFactory.hh"
31#include "BDSScorerInfo.hh"
32#include "BDSSDManager.hh"
33#include "BDSSimpleComponent.hh"
34#include "BDSUtilities.hh"
35
36#include "parser/blmplacement.h"
37#include "parser/scorer.h"
38
39#include "CLHEP/Units/SystemOfUnits.h"
40
41#include "globals.hh"
42#include "G4MultiFunctionalDetector.hh"
43#include "G4RotationMatrix.hh"
44#include "G4SDManager.hh"
45#include "G4ThreeVector.hh"
46#include "G4Transform3D.hh"
47#include "G4VSensitiveDetector.hh"
48
49#include <map>
50#include <set>
51#include <string>
52#include <utility>
53#include <vector>
54
55
56BDSBeamline* BDS::BuildBLMs(const std::vector<GMAD::BLMPlacement>& blmPlacements,
57 const BDSBeamline* parentBeamLine)
58{
59 if (blmPlacements.empty())
60 {return nullptr;} // don't do anything - no placements
61
62 // loop over blm placements - if any have external geometry, force the loading of it now so any materials
63 // that could be used in the BDSScorerInfo filters will be defined first by the load. The geometry is cached
64 // so it won't be loaded twice.
65 for (const auto& bp : blmPlacements)
66 {
67 if (!bp.geometryFile.empty())
68 {BDSGeometryFactory::Instance()->BuildGeometry(G4String(bp.name), G4String(bp.geometryFile));}
69 }
70
71 // we need to loop over all the blm definitions to work out the unique combinations of
72 // scorers that need to be created. multiple scorers for a single blm ultimately have to be
73 // in one G4MultiFunctionalSD sensitive detector.
74 std::vector<GMAD::Scorer> scorers = BDSParser::Instance()->GetScorers();
75 // convert all the parser scorer definitions into recipes (including parameter checking)
76 std::map<G4String, BDSScorerInfo> scorerRecipes;
77 for (const auto& scorer : scorers)
78 {
79 BDSScorerInfo si = BDSScorerInfo(scorer);
80 scorerRecipes.insert(std::make_pair(si.name, si));
81 }
82
83 std::set<std::set<G4String> > scorerSetsToMake;
84 // cache a map of set of scorers and combined name by BLM name so we don't have to do it later again
85 std::map<std::string, std::pair<std::set<G4String>, G4String> >blmScoringInfo;
86 for (const auto& bp : blmPlacements)
87 {
88 std::vector<G4String> scorersForThisBLM = BDS::SplitOnWhiteSpace(G4String(bp.scoreQuantity));
89 std::set<G4String> requiredScorers;
90 for (const auto& name : scorersForThisBLM)
91 {
92 auto search = scorerRecipes.find(name);
93 if (search == scorerRecipes.end())
94 {throw BDSException(__METHOD_NAME__, "scorerQuantity \"" + name + "\" for blm \"" + bp.name + "\" not found.");}
95 else
96 {requiredScorers.insert(name);}
97 }
98 // no BDS::Warning here as that slows down print out - could be all the blms turned off
99 if (requiredScorers.empty())
100 {G4cout << "Warning - no scoreQuantity specified for blm \"" << bp.name << "\" - it will only be passive material" << G4endl;}
101 scorerSetsToMake.insert(requiredScorers);
102
103 // the set by definition orders its contents, so we iterate through it to form a uniquely
104 // ordered combined name for the set.
105 G4String combinedName = "";
106 for (const auto& n : requiredScorers)
107 {combinedName += n;}
108 blmScoringInfo[bp.name] = std::make_pair(requiredScorers, combinedName);
109 }
110#ifdef BDSDEBUG
111 G4cout << "Unqiue combinations of scorers: " << scorerSetsToMake.size() << G4endl;
112#endif
113 if (scorerSetsToMake.empty())
114 {G4cout << "Warning - all BLMs have no scoreQuantity specified so are only passive material." << G4endl;}
115
116 // construct SDs
117 BDSScorerFactory scorerFactory;
118 std::map<G4String, G4MultiFunctionalDetector*> sensitiveDetectors;
119 std::vector<G4String> uniquePrimitiveScorerNames;
120 std::vector<G4double> scorerUnits;
121 G4SDManager* SDMan = G4SDManager::GetSDMpointer();
122 for (const auto& ssAndCombinedName : blmScoringInfo)
123 {
124 G4String combinedName = ssAndCombinedName.second.second;
125#ifdef BDSDEBUG
126 G4cout << __METHOD_NAME__ << "Making unique SD " << combinedName << G4endl;
127#endif
128 // If the sensitive detector with a unique combination of scorers is constructed already, skip
129 if (sensitiveDetectors.count(combinedName) > 0)
130 {continue;}
131
132 G4MultiFunctionalDetector* sd = new G4MultiFunctionalDetector("blm_"+combinedName);
133 for (const auto& name : ssAndCombinedName.second.first)
134 {
135 const auto& recipe = scorerRecipes.at(name); // safe as in previous loop we ensure it exists
136 G4double unit = 1.0;
137 G4VPrimitiveScorer* ps = scorerFactory.CreateScorer(&recipe, nullptr, &unit);
138 sd->RegisterPrimitive(ps);
139 // We rely on the prefix "blm_" here to intercept scorer hits in BDSOutput so if
140 // this changes, that matching must be done there too. It's to distinguish them
141 // from 3D mesh hits and put them in the BLM output.
142 uniquePrimitiveScorerNames.emplace_back("blm_"+combinedName+"/"+name);
143 scorerUnits.push_back(unit);
144 }
145 sensitiveDetectors[combinedName] = sd;
146 SDMan->AddNewDetector(sd);
147 }
148
149 BDSSDManager::Instance()->RegisterPrimitiveScorerNames(uniquePrimitiveScorerNames, &scorerUnits);
150
151 BDSBeamline* blms = new BDSBeamline();
152 BDSBLMFactory factory;
153 for (const auto& bp : blmPlacements)
154 {
155 // form a set of score quantities again
156 const auto& v = blmScoringInfo.at(bp.name);
157 std::set<G4String> requiredScorers = v.first;
158 G4String combinedName = v.second;
159
160 auto sdSearch = sensitiveDetectors.find(combinedName);
161 if (sdSearch == sensitiveDetectors.end())
162 {throw BDSException(__METHOD_NAME__, "unknown set of scorers");}
163 G4MultiFunctionalDetector* sd = sdSearch->second;
164
165 BDSBLM* blm = factory.CreateBLM(bp, sd);
166 BDSExtent blmExtent = blm->GetExtent();
167 G4double length = blmExtent.DZ();
168 if (!BDS::IsFinite(length))
169 {throw BDSException(__METHOD_NAME__, "BLM: " + bp.name + " has 0 extent");}
171 blm,
172 length);
173 comp->Initialise();
174
175 G4double S = -1000;
176 G4Transform3D transform = BDSDetectorConstruction::CreatePlacementTransform(bp, parentBeamLine,
177 &S, &blmExtent);
178 // do a little checking here as transform code in CreatePlacement can't
179 // know who's calling it to warn
180 if (BDS::IsFinite(bp.s) && transform == G4Transform3D::Identity)
181 {
182 G4String msg = "the S coordinate (" + std::to_string(bp.s) + " m) for blm \"" + bp.name;
183 msg += "\" was not found in the beam line - please check";
184 throw BDSException(__METHOD_NAME__, msg);
185 }
186
187 BDSBLMRegistry::Instance()->RegisterBLM(bp.name, blm, S);
188
191 G4ThreeVector halfLengthBeg = G4ThreeVector(0,0,-length*0.5);
192 G4ThreeVector halfLengthEnd = G4ThreeVector(0,0, length*0.5);
193 G4ThreeVector midPos = transform.getTranslation();
194 G4ThreeVector startPos = midPos + transform * (HepGeom::Point3D<G4double>)halfLengthBeg;
195 G4ThreeVector endPos = midPos + transform * (HepGeom::Point3D<G4double>)halfLengthEnd;
196 G4RotationMatrix* rm = new G4RotationMatrix(transform.getRotation());
197
199 startPos,
200 midPos,
201 endPos,
202 rm,
203 new G4RotationMatrix(*rm),
204 new G4RotationMatrix(*rm),
205 startPos,
206 midPos,
207 endPos,
208 new G4RotationMatrix(*rm),
209 new G4RotationMatrix(*rm),
210 new G4RotationMatrix(*rm),
211 -1,-1,-1, 0);
212
213 blms->AddBeamlineElement(el);
214 }
215
216 return blms;
217}
Factory for building BLMs.
static BDSBLMRegistry * Instance()
Accessor for registry.
A beam loss monitor.
Definition BDSBLM.hh:41
A class that holds a fully constructed BDSAcceleratorComponent as well as any information relevant to...
A vector of BDSBeamlineElement instances - a beamline.
void AddBeamlineElement(BDSBeamlineElement *element)
static G4Transform3D CreatePlacementTransform(const GMAD::Placement &placement, const BDSBeamline *beamLine, G4double *S=nullptr, BDSExtent *placementExtent=nullptr, const G4String &objectTypeForErrorMsg="placement")
General exception with possible name of object and message.
Holder for +- extents in 3 dimensions.
Definition BDSExtent.hh:38
G4double DZ() const
The difference in a dimension.
Definition BDSExtent.hh:84
BDSExtent GetExtent() const
Accessor - see member for more info.
virtual G4String GetName() const
Accessor - see member for more info.
BDSGeometryExternal * BuildGeometry(G4String componentName, const G4String &formatAndFilePath, 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, G4bool stripOuterVolumeAndMakeAssembly=false, G4UserLimits *userLimitsToAttachToAllLVs=nullptr, G4bool dontReloadGeometry=false)
static BDSGeometryFactory * Instance()
Singleton accessor.
std::vector< GMAD::Scorer > GetScorers() const
Return the parser list of that object.
Definition BDSParser.hh:110
static BDSParser * Instance()
Access method.
Definition BDSParser.cc:29
void RegisterPrimitiveScorerNames(const std::vector< G4String > &namesIn, const std::vector< G4double > *units=nullptr)
Loop over a vector and apply above single name function.
Create primitive scorers on demand.
G4VPrimitiveScorer * CreateScorer(const BDSScorerInfo *info, const BDSHistBinMapper *mapper, G4double *unit=nullptr, G4LogicalVolume *worldLV=nullptr)
Main function to create a scorer.
Recipe class for scorer. Checks values.
G4String name
Scorer name.
A BDSAcceleratorComponent wrapper for BDSGeometryComponent.
std::vector< G4String > SplitOnWhiteSpace(const G4String &input)
Split a string on whitespace and return a vector of these 'words'.
BDSBeamline * BuildBLMs(const std::vector< GMAD::BLMPlacement > &blmPlacements, const BDSBeamline *parentBeamLine)
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())