BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSDetectorConstruction.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2023.
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#include "BDSAcceleratorComponent.hh"
20#include "BDSAcceleratorComponentRegistry.hh"
21#include "BDSAcceleratorModel.hh"
22#include "BDSApertureInfo.hh"
23#include "BDSAuxiliaryNavigator.hh"
24#include "BDSBeamline.hh"
25#include "BDSBeamlineBLMBuilder.hh"
26#include "BDSBeamlineEndPieceBuilder.hh"
27#include "BDSBeamlineElement.hh"
28#include "BDSBeamlinePlacementBuilder.hh"
29#include "BDSBeamlineSet.hh"
30#include "BDSBeamPipeInfo.hh"
31#include "BDSBLM.hh"
32#include "BDSBLMRegistry.hh"
33#include "BDSBOptrMultiParticleChangeCrossSection.hh"
34#include "BDSComponentFactory.hh"
35#include "BDSComponentFactoryUser.hh"
36#include "BDSCurvilinearBuilder.hh"
37#include "BDSDebug.hh"
38#include "BDSDetectorConstruction.hh"
39#include "BDSException.hh"
40#include "BDSExtent.hh"
41#include "BDSFieldBuilder.hh"
42#include "BDSFieldObjects.hh"
43#include "BDSFieldQuery.hh"
44#include "BDSFieldQueryInfo.hh"
45#include "BDSFieldLoaderQueryPoints.hh"
46#include "BDSGap.hh"
47#include "BDSGeometryComponent.hh"
48#include "BDSGeometryExternal.hh"
49#include "BDSGeometryFactory.hh"
50#include "BDSGlobalConstants.hh"
51#include "BDSHistBinMapper.hh"
52#include "BDSIntegratorSet.hh"
53#include "BDSLine.hh"
54#include "BDSMaterials.hh"
55#include "BDSParser.hh"
56#include "BDSPhysicalVolumeInfo.hh"
57#include "BDSPhysicalVolumeInfoRegistry.hh"
58#include "BDSRegion.hh"
59#include "BDSSamplerInfo.hh"
60#include "BDSSamplerType.hh"
61#include "BDSScorerFactory.hh"
62#include "BDSScorerInfo.hh"
63#include "BDSScorerMeshInfo.hh"
64#include "BDSScoringMeshBox.hh"
65#include "BDSScoringMeshCylinder.hh"
66#include "BDSSDEnergyDeposition.hh"
67#include "BDSSDManager.hh"
68#include "BDSSDType.hh"
69#include "BDSSurvey.hh"
70#include "BDSTeleporter.hh"
71#include "BDSTrajectoryPoint.hh"
72#include "BDSTunnelBuilder.hh"
73#include "BDSUtilities.hh"
74#include "BDSWarning.hh"
75
76#include "parser/blmplacement.h"
77#include "parser/element.h"
78#include "parser/fastlist.h"
79#include "parser/options.h"
80#include "parser/physicsbiasing.h"
81#include "parser/placement.h"
82#include "parser/samplerplacement.h"
83#include "parser/scorermesh.h"
84
85#include "globals.hh"
86#include "G4AffineTransform.hh"
87#include "G4Box.hh"
88#include "G4LogicalVolume.hh"
89#include "G4Material.hh"
90#include "G4ProductionCuts.hh"
91#include "G4PVPlacement.hh"
92#include "G4VPrimitiveScorer.hh"
93#include "G4Region.hh"
94#include "G4ScoringManager.hh"
95#include "G4String.hh"
96#include "G4Transform3D.hh"
97#include "G4Version.hh"
98#include "G4VisAttributes.hh"
99#include "G4VPhysicalVolume.hh"
100#if G4VERSION_NUMBER > 1039
101#include "G4ChannelingOptrMultiParticleChangeCrossSection.hh"
102#endif
103#if G4VERSION_NUMBER > 1109
104#include "G4HadronicParameters.hh"
105#endif
106
107#ifdef BDSCHECKUSERLIMITS
108#include "G4UserLimits.hh"
109#endif
110
111#include "CLHEP/Units/SystemOfUnits.h"
112#include "CLHEP/Vector/EulerAngles.h"
113
114#include <iterator>
115#include <limits>
116#include <list>
117#include <map>
118#include <set>
119#include <sstream>
120#include <string>
121#include <utility>
122#include <vector>
123
124
125BDSDetectorConstruction::BDSDetectorConstruction(BDSComponentFactoryUser* userComponentFactoryIn):
126 placementBL(nullptr),
127 designParticle(nullptr),
128 userComponentFactory(userComponentFactoryIn),
129 nSamplers(0),
130 buildPlacementFieldsWorld(false),
131 worldLogicalVolume(nullptr)
132{
134 verbose = globals->Verbose();
135 checkOverlaps = globals->CheckOverlaps();
136 circular = globals->Circular();
137
138 if (globals->RestoreFTPFDiffractionForAGreater10())
139#if G4VERSION_NUMBER > 1109
140 {
141 G4cout << __METHOD_NAME__ << "restoring diffraction for target / projectiles with A > 10 in the FTFP hadronic model (even if not used)" << G4endl;
142 G4HadronicParameters::Instance()->SetEnableDiffDissociationForBGreater10(true);
143 }
144#else
145 {
146 if (globals->RestoreFTPFDiffractionForAGreater10Set()) // shouldn't warn about default being on
147 {BDS::Warning(__METHOD_NAME__, "\"restoreFTPFDiffractionForAGreater10\" is only available for Geant4 v11.1 and later");}
148 }
149#endif
150
151 BDSTrajectoryPoint::dEThresholdForScattering = globals->DEThresholdForScattering();
152
153 // instantiate the accelerator model holding class
154 acceleratorModel = BDSAcceleratorModel::Instance();
155 canSampleAngledFaces = true;
156 BDSIntegratorSetType integratorSetType = globals->IntegratorSet();
157 if ( (integratorSetType == BDSIntegratorSetType::bdsimtwo)
158 || (integratorSetType == BDSIntegratorSetType::geant4)
159#if G4VERSION_NUMBER > 1039
160 || (integratorSetType == BDSIntegratorSetType::geant4dp)
161#endif
162 )
163 { // set to be value of option, default is false.
164 canSampleAngledFaces = globals->SampleElementsWithPoleface();
165 }
166
167 UpdateSamplerDiameterAndCountSamplers();
168 PrepareExtraSamplerSDs();
169 CountPlacementFields();
170}
171
173{
174 nSamplers = 0;
175 auto beamline = BDSParser::Instance()->GetBeamline(); // main beam line
176 G4double maxBendingRatio = 1e-9;
177 for (const auto& blElement : beamline)
178 {
179 // count number of samplers
180 auto st = BDS::DetermineSamplerType(blElement.samplerType);
181 if (st != BDSSamplerType::none)
182 {nSamplers++;}
183
184 G4double length = blElement.l;
185 G4double angle = blElement.angle;
186 if (!BDS::IsFinite(length))
187 {continue;} // avoid divide by 0
188 G4double ratio = angle / length;
189 maxBendingRatio = std::max(maxBendingRatio, ratio);
190 }
191
193 G4double curvilinearRadius = 0.5*globals->CurvilinearDiameter();
194 G4double tolerance = 0.9; // 10% tolerance -> factor of 0.9
195 if (maxBendingRatio > 0.4*tolerance) // max ratio for a 2.5m sampler diameter
196 {
197 G4double curvilinearRadiusBends = (tolerance / maxBendingRatio)*CLHEP::m;
198 if (curvilinearRadiusBends < curvilinearRadius)
199 {
200 G4cout << __METHOD_NAME__ << "Reducing curvilinear diameter from " << 2*curvilinearRadius / CLHEP::m
201 << "m to " << 2*curvilinearRadiusBends / CLHEP::m << "m" << G4endl;
202 globals->SetCurvilinearDiameter(2*curvilinearRadiusBends);
204 }
205 G4double sd = globals->SamplerDiameter();
206 if (curvilinearRadius*2 < sd)
207 {
208 G4cout << __METHOD_NAME__ << "Reducing sampler diameter from " << sd / CLHEP::m << "m to the same" << G4endl;
209 globals->SetSamplerDiameter(2*curvilinearRadius);
210 }
211 }
212
213 // add number of sampler placements to count of samplers
215}
216
218{
219 const auto& samplerFilterIDtoPDGSet = BDSParser::Instance()->GetSamplerFilterIDToSet();
220 BDSSDManager::Instance()->ConstructSamplerSDsForParticleSets(samplerFilterIDtoPDGSet);
221}
222
224{
225 G4int nFields = 0;
226 const auto& placements = BDSParser::Instance()->GetPlacements();
227 for (const auto& placement : placements)
228 {// here we assume if a bdsim element is used at all that it's active even though it may not be
229 if (!placement.fieldAll.empty() || !placement.bdsimElement.empty())
230 {nFields++;}
231 }
232 buildPlacementFieldsWorld = nFields > 0;
233}
234
236{
237 if (verbose || debug)
238 {G4cout << __METHOD_NAME__ << "starting accelerator geometry construction\n" << G4endl;}
239
240 // construct all parser defined regions
242
243 // construct all parser defined aperture objects
245
246 // construct the main beam line and any other secondary beam lines
248
249 // construct placement geometry from parser
250 BDSBeamline* mainBeamLine = BDSAcceleratorModel::Instance()->BeamlineSetMain().massWorld;
251 auto componentFactory = new BDSComponentFactory(designParticle, userComponentFactory, false); // false for printing out integrator set again
253 mainBeamLine,
254 componentFactory);
255 BDSAcceleratorModel::Instance()->RegisterPlacementBeamline(placementBL); // Acc model owns it
256 delete componentFactory;
257
259 mainBeamLine);
260 if (blms)
261 {BDSAcceleratorModel::Instance()->RegisterBLMs(blms);} // Acc model owns it
262
263 // build the tunnel and supports
265 {BuildTunnel();}
266
267 // build world and calculate coordinates
268 auto worldPV = BuildWorld();
269
270 // placement procedure - put everything in the world
271 ComponentPlacement(worldPV);
272
273 if (verbose || debug)
274 {G4cout << __METHOD_NAME__ << "detector Construction done" << G4endl;}
275
276 fieldQueries = BDSDetectorConstruction::PrepareFieldQueries(mainBeamLine);
279
280#ifdef BDSDEBUG
281 G4cout << G4endl << __METHOD_NAME__ << "printing material table" << G4endl;
282 G4cout << *(G4Material::GetMaterialTable()) << G4endl << G4endl;
283 if (verbose || debug) {G4cout << "Finished listing materials, returning physiWorld" << G4endl;}
284#endif
285#ifdef BDSCHECKUSERLIMITS
286 PrintUserLimitsSummary(worldPV);
287#endif
288 return worldPV;
289}
290
291BDSDetectorConstruction::~BDSDetectorConstruction()
292{
293#if G4VERSION_NUMBER > 1009
294 // delete bias objects
295 for (auto i : biasObjects)
296 {delete i;}
297#endif
298 for (auto q : fieldQueries)
299 {delete q;}
300}
301
303{
304 BDSRegion* defaultRegion = new BDSRegion("default");
305 for (const GMAD::Region& r : BDSParser::Instance()->GetRegions())
306 {
307 BDSRegion* reg = new BDSRegion(r, defaultRegion);
308 G4cout << "New region defined: " << G4endl << *reg << G4endl;
310 }
311 delete defaultRegion;
312}
313
315{
316 std::map<G4String, BDSApertureInfo*> apertures;
317 for (const GMAD::Aperture& a : BDSParser::Instance()->GetApertures())
318 {
319 BDSApertureInfo* ap = new BDSApertureInfo(a.apertureType,
320 a.aper1 * CLHEP::m,
321 a.aper2 * CLHEP::m,
322 a.aper3 * CLHEP::m,
323 a.aper4 * CLHEP::m,
324 a.name);
325 apertures[a.name] = ap;
326 }
328}
329
331{
332 // build main beam line
333 if (verbose || debug)
334 {G4cout << "parsing the beamline element list..."<< G4endl;}
335 G4Transform3D initialTransform = BDSGlobalConstants::Instance()->BeamlineTransform();
336 G4double initialS = BDSGlobalConstants::Instance()->BeamlineS();
337
338 BDSBeamlineSet mainBeamline = BuildBeamline(BDSParser::Instance()->GetBeamline(),
339 "main beam line",
340 initialTransform,
341 initialS,
342 circular);
343
344#ifdef BDSDEBUG
345 G4cout << "Registry size "
347 G4cout << "Parser beam line size "
348 << BDSParser::Instance()->GetBeamline().size() << G4endl;
350#endif
351
352 // print warning if beam line is approximately circular but flag isn't specified
353 if (!circular && mainBeamline.massWorld)
354 {
355 if (mainBeamline.massWorld->ElementAnglesSumToCircle())
356 {BDS::Warning("Total sum of all element angles is approximately 2*pi but the circular option was not specified, this simulation may run indefinitely");}
357 }
358
359 // register the beam line in the holder class for the full model
361
362 // build secondary beam lines
363 // loop over placements and check if any are beam lines (have sequences specified)
364 auto placements = BDSParser::Instance()->GetPlacements();
365 for (const auto& placement : placements)
366 {
367 if (placement.sequence.empty())
368 {continue;} // no sequence specified -> just a placement
369 auto parserLine = BDSParser::Instance()->GetSequence(placement.sequence);
370
371 // determine offset in world for extra beam line
372 const BDSBeamline* mbl = mainBeamline.massWorld;
373 // TODO - so by default if placement.s is finite, it'll be made w.r.t. the main beam line
374 // but this could be any beam line in future if we find the right beam line to pass in.
375 G4Transform3D startTransform = CreatePlacementTransform(placement, mbl);
376 G4double startS = mbl ? mbl->back()->GetSPositionEnd() : 0;
377
378 // aux beam line must be non-circular by definition to branch off of beam line (for now)
379 // TODO - the naming convention here is repeated in BDSParallelWorldInfo which is registered
380 // beforehand separately - fix by making the information originate in one place despite
381 // the parallel world instantiated first before Construct() in this class is called.
382 G4String beamlineName = placement.name + "_" + placement.sequence;
383 BDSBeamlineSet extraBeamline = BuildBeamline(parserLine,
384 beamlineName,
385 startTransform,
386 startS,
387 false, // circular
388 true); // is placement
389
390 acceleratorModel->RegisterBeamlineSetExtra(beamlineName, extraBeamline);
391 }
392}
393
395{
396 BDSSamplerType sType = BDS::DetermineSamplerType(element->samplerType);
397 if (sType == BDSSamplerType::none)
398 {return nullptr;}
399 BDSSamplerInfo* result = new BDSSamplerInfo(element->samplerName,
400 sType,
401 (G4int)element->samplerParticleSetID);
402 return result;
403}
404
406 const G4String& name,
407 const G4Transform3D& initialTransform,
408 G4double initialS,
409 G4bool beamlineIsCircular,
410 G4bool isPlacementBeamline)
411{
412 if (beamLine.empty()) // note a line always has a 'line' element first so an empty line will not be 'empty'
413 {return BDSBeamlineSet();}
414
415 if (userComponentFactory)
416 {userComponentFactory->SetDesignParticle(designParticle);}
417 BDSComponentFactory* theComponentFactory = new BDSComponentFactory(designParticle, userComponentFactory);
418 BDSBeamline* massWorld = new BDSBeamline(initialTransform, initialS);
419
420 if (beamlineIsCircular)
421 {
422 G4bool unsuitable = UnsuitableFirstElement(beamLine.begin());
423 if (unsuitable)
424 {
425 G4cerr << "The first element in the beam line is unsuitable for a circular "
426 << "model as the first element will " << G4endl << "overlap with the "
427 << "teleporter and terminator - the necessary mechanics for a circular "
428 << "model in Geant4" << G4endl;
429 throw BDSException(__METHOD_NAME__, "check construction for circular machine");
430 }
431 }
432
433 if (beamLine.size() <= 1) // if an empty LINE it still has 1 item in it
434 {throw BDSException(__METHOD_NAME__, "BDSIM requires the sequence defined with the use command to have at least one element.");}
435
436 for (auto elementIt = beamLine.begin(); elementIt != beamLine.end(); ++elementIt)
437 {
438 // find next and previous element, but ignore special elements or thin elements.
439 const GMAD::Element* prevElement = nullptr;
440 auto prevIt = elementIt;
441 while (prevIt != beamLine.begin())
442 {
443 --prevIt;
444 if (prevIt->isSpecial() == false && prevIt->l > BDSGlobalConstants::Instance()->ThinElementLength())
445 {
446 prevElement = &(*prevIt);
447 break;
448 }
449 }
450
451 const GMAD::Element* nextElement = nullptr;
452 auto nextIt = elementIt;
453 ++nextIt;
454 G4double nextElementInputFace = 0; // get poleface angle for next element whilst testing if next element exists
455 while (nextIt != beamLine.end())
456 {
457 if (nextIt->isSpecial() == false && nextIt->l > BDSGlobalConstants::Instance()->ThinElementLength())
458 {
459 nextElement = &(*nextIt);
460 //rotated entrance face of the next element may modify the exit face of the current element.
461 nextElementInputFace = nextElement->e1;
462 break;
463 }
464 ++nextIt;
465 }
466 G4double currentArcLength = massWorld->GetTotalArcLength();
467 BDSAcceleratorComponent* temp = theComponentFactory->CreateComponent(&(*elementIt),
468 prevElement,
469 nextElement,
470 currentArcLength);
471 if(temp)
472 {
473 G4bool forceNoSamplerOnThisElement = false;
474 if ((!canSampleAngledFaces) && (BDS::IsFinite((*elementIt).e2)))
475 {forceNoSamplerOnThisElement = true;}
476 if ((!canSampleAngledFaces) && (BDS::IsFinite(nextElementInputFace)))
477 {forceNoSamplerOnThisElement = true;}
478 if (temp->GetType() == "dump") // don't sample after a dump as there'll be nothing
479 {forceNoSamplerOnThisElement = true;}
480 BDSSamplerInfo* samplerInfo = forceNoSamplerOnThisElement ? nullptr : BuildSamplerInfo(&(*elementIt));
481 BDSTiltOffset* tiltOffset = BDSComponentFactory::CreateTiltOffset(&(*elementIt));
482 massWorld->AddComponent(temp, tiltOffset, samplerInfo);
483 }
484 }
485
486 // Special circular machine bits
487 // Add terminator to do ring turn counting logic and kill particles
488 // Add teleporter to account for slight ring offset
489 if (beamlineIsCircular && !massWorld->empty())
490 {
491#ifdef BDSDEBUG
492 G4cout << __METHOD_NAME__ << "Circular machine - creating terminator & teleporter" << G4endl;
493#endif
494 G4double teleporterLength = 0;
495 G4Transform3D teleporterTransform = BDS::CalculateTeleporterDelta(massWorld, teleporterLength);
496
497 auto hasBeamPipeInfo = [](BDSBeamlineElement* ble) {return ble->GetBeamPipeInfo() != nullptr;};
498 auto firstElementWithBPInfo = std::find_if(massWorld->begin(), massWorld->end(), hasBeamPipeInfo);
499 auto lastElementWithBPInfo = std::find_if(massWorld->rbegin(), massWorld->rend(), hasBeamPipeInfo);
500
501 G4double firstbeamPipeMaxExtent = (*firstElementWithBPInfo)->GetBeamPipeInfo()->Extent().MaximumAbsTransverse();
502 G4double lastbeamPipeMaxExtent = (*lastElementWithBPInfo)->GetBeamPipeInfo()->Extent().MaximumAbsTransverse();
503
504 // the extent is a half width, so we double it - also the terminator width.
505 G4double teleporterHorizontalWidth = 2 * std::max(firstbeamPipeMaxExtent, lastbeamPipeMaxExtent);
506
507 BDSAcceleratorComponent* terminator = theComponentFactory->CreateTerminator(teleporterHorizontalWidth);
508 if (terminator)
509 {
510 terminator->Initialise();
511 massWorld->AddComponent(terminator);
512 }
513
514 BDSAcceleratorComponent* teleporter = theComponentFactory->CreateTeleporter(teleporterLength,
515 teleporterHorizontalWidth,
516 teleporterTransform);
517 if (teleporter)
518 {
519 teleporter->Initialise();
520 massWorld->AddComponent(teleporter);
521 }
522 }
523
524 if (BDSGlobalConstants::Instance()->Survey())
525 {
526 G4String surveyFileName = BDSGlobalConstants::Instance()->SurveyFileName() + ".dat";
527 if (isPlacementBeamline)
528 {surveyFileName = BDSGlobalConstants::Instance()->SurveyFileName() + "_" + name + ".dat";}
529 BDSSurvey* survey = new BDSSurvey(surveyFileName);
530 survey->Write(massWorld);
531 delete survey;
532 }
533 delete theComponentFactory;
534
535 // print summary
536 G4cout << __METHOD_NAME__ << "\"" << name << "\" " << G4endl << *massWorld;
537
538 // Build curvilinear geometry w.r.t. beam line.
540 BDSBeamline* clBeamline = clBuilder->BuildCurvilinearBeamLine1To1(massWorld, beamlineIsCircular);
541 BDSBeamline* clBridgeBeamline = clBuilder->BuildCurvilinearBridgeBeamLine(clBeamline);
542 delete clBuilder;
543
544 // construct beamline of end pieces
545 BDSBeamline* endPieces = BDS::BuildEndPieceBeamline(massWorld, circular);
546 BDSBeamlineSet beamlineSet;
547 beamlineSet.massWorld = massWorld;
548 beamlineSet.curvilinearWorld = clBeamline;
549 beamlineSet.curvilinearBridgeWorld = clBridgeBeamline;
550 beamlineSet.endPieces = endPieces;
551 return beamlineSet;
552}
553
555{
556 const BDSBeamline* mainBeamLine = acceleratorModel->BeamlineMain();
557 BDSBeamline* tunnelBeamline;
558 BDSTunnelBuilder* tb = new BDSTunnelBuilder(BDSGlobalConstants::Instance()->TunnelMaxSegmentLength());
559 tunnelBeamline = tb->BuildTunnelSections(mainBeamLine);
560 delete tb;
561
563}
564
566{
567 // shortcut
569
570 // calculate extents of everything we need to place in the world first
571 std::vector<BDSExtentGlobal> extents;
572
573 // these beam lines should always exist so are safe to access.
574 const auto& blMain = acceleratorModel->BeamlineSetMain();
575 blMain.GetExtentGlobals(extents);
576
577 // check optional placement beam line (like vector of placements)
579 if (plBeamline) // optional - may be nullptr
580 {extents.push_back(plBeamline->GetExtentGlobal());}
581
582 // check tunnel beam line
583 BDSBeamline* tunnelBeamline = acceleratorModel->TunnelBeamline();
584 if (tunnelBeamline)
585 {extents.push_back(tunnelBeamline->GetExtentGlobal());}
586
587 // check extra beam lines
588 const auto& extras = BDSAcceleratorModel::Instance()->ExtraBeamlines();
589 // extras is a map, so iterator has first and second for key and value
590 for (const auto& bl : extras)
591 {bl.second.GetExtentGlobals(extents);}
592
593 // inspect any sampler placements and calculate their extent without constructing them
594 extents.push_back(CalculateExtentOfSamplerPlacements(blMain.massWorld));
595
596 // inspect any scoring meshes and calculate their extent without constructing them
597 extents.push_back(CalculateExtentOfScorerMeshes(blMain.massWorld));
598
599 // Expand to maximum extents of each beam line.
600 G4ThreeVector worldR;
601 // loop over all extents from all beam lines
602 for (const auto& ext : extents)
603 {
604 for (G4int i = 0; i < 3; i++)
605 {worldR[i] = std::max(worldR[i], ext.GetMaximumExtentAbsolute()[i]);} // expand with the maximum
606 }
607
608 G4String worldName = "World";
609 G4VSolid* worldSolid = nullptr;
610 G4LogicalVolume* worldLV = nullptr;
611
612 G4String worldGeometryFile = globals->WorldGeometryFile();
613 if (!worldGeometryFile.empty())
614 {
615 if (globals->WorldMaterialSet())
616 {BDS::Warning(__METHOD_NAME__, "conflicting options - world material option specified but material will be taken from world GDML file");}
617 G4bool ac = globals->AutoColourWorldGeometryFile();
618
619 std::vector<G4String> namedWorldVacuumVolumes = BDS::SplitOnWhiteSpace(globals->WorldVacuumVolumeNames());
620
622 worldGeometryFile,
623 nullptr,
624 ac,
625 0, 0,
626 &namedWorldVacuumVolumes,
627 true,
628 BDSSDType::energydepworldcontents,
629 BDSSDType::energydepvacuum);
630
631 // get list of 'material' and 'vacuum' volumes for possible biasing of this geometry
632 worldVacuumLogicalVolumes = geom->VacuumVolumes();
633 auto allWorldVolumes = geom->GetAllLogicalVolumes();
634 allWorldVolumes.erase(geom->GetContainerLogicalVolume());
635 for (auto volume : worldVacuumLogicalVolumes)
636 {allWorldVolumes.erase(volume);}
637 worldContentsLogicalVolumes = allWorldVolumes; // cache volumes for biasing
638
639 worldExtent = geom->GetExtent();
640 BDSExtentGlobal worldExtentGlobal = BDSExtentGlobal(worldExtent, G4Transform3D());
641 G4bool worldContainsAllBeamlines = worldExtentGlobal.Encompasses(extents);
642
643 G4cout << "External world geometry: \"" << worldGeometryFile << "\"" << G4endl;
644 G4cout << "Loaded world extent: \n" << worldExtent << G4endl;
645
646 // cannot construct world if any beamline extent is greater than the world extents
647 if (!worldContainsAllBeamlines)
648 {
649 G4String message = "Beamlines cannot be constructed, beamline extents are larger than \n";
650 message += "the extents of the external world";
651 throw BDSException(__METHOD_NAME__, message);
652 }
653
654 worldSolid = geom->GetContainerSolid();
655 worldLV = geom->GetContainerLogicalVolume();
656
657 // make the world sensitive to energy deposition with its own unique hits collection
658 // this will be a nullptr depending on the options.
659 // make world sensitive if importance sampling is needed
660 if (globals->StoreELossWorld()
661 || globals->StoreELossWorldIntegral()
662 || globals->UseImportanceSampling()
663 || globals->StoreELossWorldContents()
664 || globals->StoreELossWorldContentsIntegral())
665 {
667 // override the logical volume itself with a specific SD
668 worldLV->SetSensitiveDetector(BDSSDManager::Instance()->WorldComplete());
669 }
670 }
671 else
672 {
673 // add on margin for constructed world volume
674 G4double margin = globals->WorldVolumeMargin();
675 margin = std::max(margin, 2*CLHEP::m); // minimum margin of 2m.
676 worldR += G4ThreeVector(margin,margin,margin); //add 5m extra in every dimension
677
678 G4cout << __METHOD_NAME__ << "World dimensions: " << worldR / CLHEP::m << " m" << G4endl;
679
680 G4String worldMaterialName = globals->WorldMaterial();
681 G4Material* worldMaterial = BDSMaterials::Instance()->GetMaterial(worldMaterialName);
682 worldExtent = BDSExtent(worldR);
683 worldSolid = new G4Box(worldName + "_solid", worldR.x(), worldR.y(), worldR.z());
684
685
686 worldLV = new G4LogicalVolume(worldSolid, // solid
687 worldMaterial, // material
688 worldName + "_lv"); // name
689
690 // make the world sensitive to energy deposition with its own unique hits collection
691 // note with our world, there are no 'contents' to also consider
692 if (globals->StoreELossWorld() || globals->StoreELossWorldIntegral())
693 {worldLV->SetSensitiveDetector(BDSSDManager::Instance()->WorldComplete());}
694 }
695
696 // visual attributes
697 // copy the debug vis attributes but change to force wireframe
698 G4VisAttributes* debugWorldVis = new G4VisAttributes(*(globals->ContainerVisAttr()));
699 debugWorldVis->SetForceWireframe(true);//just wireframe so we can see inside it
700 worldLV->SetVisAttributes(debugWorldVis);
701
702 // set limits
703 worldLV->SetUserLimits(globals->DefaultUserLimits());
704
705 // place the world
706 G4VPhysicalVolume* worldPV = new G4PVPlacement(nullptr, // no rotation
707 G4ThreeVector(), // at (0,0,0)
708 worldLV, // its logical volume
709 worldName, // its name
710 nullptr, // its mother volume
711 false, // no boolean operation
712 0, // copy number
713 checkOverlaps); // overlap checking
714
715 // Register the lv & pvs to our holder class for the model
719
720 // Register world PV with our auxiliary navigator so steppers and magnetic
721 // fields know which geometry to navigate to get local / global transforms.
722 // This is the regular world used as a backup to the curvilinear world.
725
728
729 worldLogicalVolume = worldLV; // set for possible biasing
730 return worldPV;
731}
732
733void BDSDetectorConstruction::ComponentPlacement(G4VPhysicalVolume* worldPV)
734{
735 // We musn't place parallel world geometry here - their world is produced by
736 // Geant4 at the right time, so we have a separate placement call for them
737 BDSBeamlineSet mainBL = BDSAcceleratorModel::Instance()->BeamlineSetMain();
738 PlaceBeamlineInWorld(mainBL.massWorld,
739 worldPV, checkOverlaps, true, false, false, false, true); // record pv set to element for output
740 PlaceBeamlineInWorld(mainBL.endPieces,
741 worldPV, checkOverlaps);
743 {
745 worldPV, checkOverlaps);
746 }
747 // No energy counter SD added here as individual placements have that attached
748 // during construction time
749 PlaceBeamlineInWorld(placementBL, worldPV, checkOverlaps, false, false, false, false, true);
750
751 // Place BLMs. Similarly, no sensitivity set here - done at construction time.
752 PlaceBeamlineInWorld(BDSAcceleratorModel::Instance()->BLMsBeamline(),
753 worldPV,
755 false,
756 false,
757 false,
758 true); // use incremental copy numbers
759
760 const auto& extras = BDSAcceleratorModel::Instance()->ExtraBeamlines();
761 for (auto const& bl : extras)
762 {// extras is a map so iterator has first and second for key and value
763 // note these are currently not sensitive as there's no CL frame for them
764 PlaceBeamlineInWorld(bl.second.massWorld, worldPV, checkOverlaps, false, false, false, false, true);
765 PlaceBeamlineInWorld(bl.second.endPieces, worldPV, checkOverlaps);
766 }
767}
768
770 G4VPhysicalVolume* containerPV,
771 G4bool checkOverlaps,
772 G4bool setRegions,
773 G4bool registerInfo,
774 G4bool useCLPlacementTransform,
775 G4bool useIncrementalCopyNumbers,
776 G4bool registerPlacementNamesForOutput)
777{
778 if (!beamline)
779 {return;}
780
781 G4int i = 0;
782 for (auto element : *beamline)
783 {
784 // Do nothing for gap element
785 if (dynamic_cast<BDSGap*>(element->GetAcceleratorComponent()))
786 {continue;}
787
788 if (setRegions)
789 {
790 auto accComp = element->GetAcceleratorComponent();
791 const G4String regionName = accComp->GetRegion();
792 if (!regionName.empty()) // ie string is defined so we should attach region
793 {
794 G4Region* region = BDSAcceleratorModel::Instance()->Region(regionName);
795 auto contLV = accComp->GetContainerLogicalVolume();
796 contLV->SetRegion(region);
797 region->AddRootLogicalVolume(contLV);
798 }
799 }
800
801 // setup the sensitivity
802 element->GetAcceleratorComponent()->AttachSensitiveDetectors();
803
804 // make the placement
805 G4int copyNumber = useIncrementalCopyNumbers ? i : element->GetCopyNo();
806 G4String placementName = element->GetPlacementName() + "_pv";
807 std::set<G4VPhysicalVolume*> pvs = element->PlaceElement(placementName, containerPV, useCLPlacementTransform,
808 copyNumber, checkOverlaps);
809
810 if (registerInfo)
811 {
812 BDSPhysicalVolumeInfo* theinfo = new BDSPhysicalVolumeInfo(element->GetName(),
813 placementName,
814 element->GetSPositionMiddle(),
815 element->GetIndex(),
816 beamline);
817
819 }
820 if (registerPlacementNamesForOutput)
822 i++; // for incremental copy numbers
823 }
824}
825
827 const BDSBeamline* beamLine,
828 G4double* S,
829 BDSExtent* placementExtent,
830 const G4String& objectTypeForErrorMsg)
831{
832 G4Transform3D result;
833
834 // 3 scenarios
835 // 1) global placement X,Y,Z + rotation
836 // 2) w.r.t. beam line placement x,y,S + rotation
837 // 3) w.r.t. element in beam line placement elementName + x,y,s + rotation
838
839 // in all cases, need the rotation
840 G4RotationMatrix rm = G4RotationMatrix();
841 if (placement.axisAngle)
842 {
843 G4ThreeVector axis = G4ThreeVector(placement.axisX,
844 placement.axisY,
845 placement.axisZ);
846 rm = G4RotationMatrix(axis, placement.angle*CLHEP::rad);
847 }
848 else
849 {
850 if (BDS::IsFinite(placement.phi) ||
851 BDS::IsFinite(placement.theta) ||
852 BDS::IsFinite(placement.psi))
853 {// only build if finite
854 CLHEP::HepEulerAngles ang = CLHEP::HepEulerAngles(placement.phi*CLHEP::rad,
855 placement.theta*CLHEP::rad,
856 placement.psi*CLHEP::rad);
857 rm = G4RotationMatrix(ang);
858 }
859 }
860
861 // create a transform w.r.t. the beam line if s is finite and it's not w.r.t a
862 // particular element. If it's w.r.t. a particular element, treat s as local curvilinear
863 // s and use as local 'z' in the transform.
864 if (!placement.referenceElement.empty())
865 {// scenario 3
866 if (!beamLine)
867 {throw BDSException(__METHOD_NAME__, "no valid beam line yet for " + objectTypeForErrorMsg + " w.r.t. a beam line.");}
868 const BDSBeamlineElement* element = beamLine->GetElement(placement.referenceElement,
869 placement.referenceElementNumber);
870 if (!element)
871 {
872 G4cerr << __METHOD_NAME__ << "No element named \"" << placement.referenceElement << "\" (instance #"
873 << placement.referenceElementNumber << ") in " << objectTypeForErrorMsg << " \""
874 << placement.name << "\"" << G4endl;
875 G4cout << "Note, this may be because the element is a bend and split into " << G4endl;
876 G4cout << "multiple sections with unique names. Run the visualiser to get " << G4endl;
877 G4cout << "the name of the segment, or place w.r.t. the element before / after." << G4endl;
878 throw BDSException("Error in "+objectTypeForErrorMsg+".");
879 }
880 // in this case we should use s for longitudinal offset - warn user if mistakenly using z
881 if (BDS::IsFinite(placement.z))
882 {
883 G4String message = objectTypeForErrorMsg + " \"" + placement.name + "\" is placed using";
884 message += " a referenceElement but the z offset is\n non zero. Note, s should be used to";
885 message += " offset the placement in this case and z will\n have no effect.";
886 BDS::Warning(message);
887 }
888 G4double sCoordinate = element->GetSPositionMiddle(); // start from middle of element
889 sCoordinate += placement.s * CLHEP::m; // add on (what's considered) 'local' s from the placement
890 if (S)
891 {*S = sCoordinate;}
892
893 G4ThreeVector offset = G4ThreeVector();
894 if (placementExtent)
895 {offset = SideToLocalOffset(placement, beamLine, *placementExtent);}
896
897 G4Transform3D beamlinePart = beamLine->GetGlobalEuclideanTransform(sCoordinate,
898 placement.x * CLHEP::m + offset.x(),
899 placement.y * CLHEP::m + offset.y());
900 G4Transform3D localRotation(rm, G4ThreeVector());
901 result = beamlinePart * localRotation;
902 }
903 else if (BDS::IsFinite(placement.s))
904 {// scenario 2
905 if (!beamLine)
906 {throw BDSException(__METHOD_NAME__, "no valid beam line yet placement w.r.t. a beam line.");}
907 G4ThreeVector offset = G4ThreeVector();
908 if (placementExtent)
909 {offset = SideToLocalOffset(placement, beamLine, *placementExtent);}
910
911 G4Transform3D beamlinePart = beamLine->GetGlobalEuclideanTransform(placement.s * CLHEP::m,
912 placement.x * CLHEP::m + offset.x(),
913 placement.y * CLHEP::m + offset.y());
914
915 G4Transform3D localRotation(rm, G4ThreeVector());
916 result = beamlinePart * localRotation;
917 if (S)
918 {*S = placement.s*CLHEP::m;}
919 }
920 else
921 {// scenario 1
922 G4ThreeVector translation = G4ThreeVector(placement.x*CLHEP::m,
923 placement.y*CLHEP::m,
924 placement.z*CLHEP::m);
925
926
927 result = G4Transform3D(rm, translation);
928 if (S)
929 {*S = -1000;} // default
930 }
931
932 return result;
933}
934
936 const BDSBeamline* beamLine,
937 G4double* S)
938{
939 // convert a scorermesh to a general placement for generation of the transform only.
940 GMAD::Placement convertedPlacement(scorerMesh);
941 return CreatePlacementTransform(convertedPlacement, beamLine, S, nullptr, "scorermesh");
942}
943
945 const BDSBeamline* beamLine,
946 G4double* S)
947{
948 // convert a sampler placement to a general placement for generation of the transform only.
949 GMAD::Placement convertedPlacement(samplerPlacement);
950 return CreatePlacementTransform(convertedPlacement, beamLine, S, nullptr, "samplerplacement");
951}
952
954 const BDSBeamline* beamLine,
955 G4double* S,
956 BDSExtent* blmExtent)
957{
958 // convert a sampler placement to a general placement for generation of the transform.
959 GMAD::Placement convertedPlacement(blmPlacement);
960 return CreatePlacementTransform(convertedPlacement, beamLine, S, blmExtent, "blm");
961}
962
964 const BDSBeamline* beamLine,
965 G4double* S)
966{
967 GMAD::Placement convertedPlacement(queryPlacement);
968 return CreatePlacementTransform(convertedPlacement, beamLine, S, nullptr, "query");
969}
970
972 const BDSBeamline* beamLine,
973 const BDSExtent& placementExtent)
974{
975 G4ThreeVector result = G4ThreeVector();
976 G4String side = G4String(placement.side);
977 side = BDS::LowerCase(side);
978
979 // Get the iterators pointing to the first and last elements
980 // that the placement lines up with.
981 G4double pathLength = placement.s*CLHEP::m;
982 std::pair<G4double, G4double> extentZ = placementExtent.ExtentZ();
983 G4double sLow = pathLength + extentZ.first;
984 G4double sHigh = pathLength + extentZ.second;
985 // iterator pointing to lower bound
986 auto start = beamLine->FindFromS(sLow);
987 auto end = beamLine->FindFromS(sHigh);
988 if (end != beamLine->end())
989 {end++;}
990
991 // Fold across the extents returning the greatest extent. The transverse extents
992 // will give be the transverse extents of the beamline section.
993 BDSExtent sectionMaxExtent = BDSExtent();
994 for (auto iter = start; iter != end; ++iter)
995 {sectionMaxExtent = BDS::MaximumCombinedExtent((*iter)->GetExtent(), sectionMaxExtent);}
996
997 // Multiplied by 5 because it works...
998 G4double ls = 5 * BDSGlobalConstants::Instance()->LengthSafetyLarge();
999
1000 if (BDS::IsFinite(placement.sideOffset))
1001 {ls = placement.sideOffset * CLHEP::m;}
1002
1003 if (side == "top")
1004 {
1005 result.setY(sectionMaxExtent.YPos() + placementExtent.YPos() + ls);
1006 G4double xOffset = sectionMaxExtent.XPos() - 0.5*sectionMaxExtent.DX();
1007 result.setX(xOffset);
1008 }
1009 else if (side == "bottom")
1010 {
1011 result.setY(sectionMaxExtent.YNeg() + placementExtent.YNeg() - ls);
1012 G4double xOffset = sectionMaxExtent.XPos() - 0.5*sectionMaxExtent.DX();
1013 result.setX(xOffset);
1014 }
1015 else if (side == "left")
1016 {result.setX(sectionMaxExtent.XPos() + placementExtent.XPos() + ls);}
1017 else if (side == "right")
1018 {result.setX(sectionMaxExtent.XNeg() + placementExtent.XNeg() - ls);}
1019 else if (side != "")
1020 {throw BDSException(std::string("Unknown side in placement: " + side));}
1021 return result;
1022}
1023
1025{
1026 BDSExtent apertureExtent;
1027 if (sp.apertureModel.empty())
1028 {
1029 if (sp.samplerType == "plane")
1030 {
1031 BDSApertureInfo aperture = BDSApertureInfo(sp.shape,
1032 sp.aper1 * CLHEP::m,
1033 sp.aper2 * CLHEP::m,
1034 sp.aper3 * CLHEP::m,
1035 sp.aper4 * CLHEP::m,
1036 sp.name);
1037 apertureExtent = aperture.Extent();
1038 }
1039 else if (sp.samplerType == "cylinder" || sp.samplerType == "cylinderforward") // we ignore the possibility of only a part-cylinder
1040 {apertureExtent = BDSExtent(sp.aper1*CLHEP::m, sp.aper1*CLHEP::m, sp.aper2*CLHEP::m);}
1041 else if (sp.samplerType == "sphere" || sp.samplerType == "sphereforward") // we ignore the possibility of only a part-sphere
1042 {apertureExtent = BDSExtent(sp.aper1*CLHEP::m, sp.aper1*CLHEP::m, sp.aper1*CLHEP::m);}
1043 else
1044 {throw BDSException(__METHOD_NAME__, "unknown samplerType \"" + sp.samplerType + "\" in samplerplacement \"" + sp.name + "\"");}
1045 }
1046 else
1047 {
1048 BDSApertureInfo* aperture = BDSAcceleratorModel::Instance()->Aperture(sp.apertureModel);
1049 apertureExtent = aperture->Extent();
1050 }
1051
1052 // aperture is only transverse - fiddle z
1053 BDSExtent result = BDSExtent(apertureExtent.XNeg(), apertureExtent.XPos(),
1054 apertureExtent.YNeg(), apertureExtent.YPos(),
1055 1*CLHEP::um, 1*CLHEP::um);
1056 return result;
1057}
1058
1060{
1061 BDSExtentGlobal result;
1062 std::vector<GMAD::SamplerPlacement> samplerPlacements = BDSParser::Instance()->GetSamplerPlacements();
1063 for (const auto& samplerPlacement : samplerPlacements)
1064 {
1065 BDSExtent samplerExtent = CalculateExtentOfSamplerPlacement(samplerPlacement);
1066 G4Transform3D placementTransform = CreatePlacementTransform(samplerPlacement, beamLine);
1067 BDSExtentGlobal samplerExtentG = BDSExtentGlobal(samplerExtent, placementTransform);
1068 result = result.ExpandToEncompass(samplerExtentG);
1069 }
1070 return result;
1071}
1072
1074{
1075 BDSScorerMeshInfo recipe(sm);
1076 return recipe.Extent();
1077}
1078
1080{
1081 BDSExtentGlobal result;
1082 std::vector<GMAD::ScorerMesh> scorerMeshes = BDSParser::Instance()->GetScorerMesh();
1083 for (const auto& mesh : scorerMeshes)
1084 {
1085 BDSExtent meshExtent = CalculateExtentOfScorerMesh(mesh);
1086 G4Transform3D placementTransform = CreatePlacementTransform(mesh, beamLine);
1087 BDSExtentGlobal meshExtentG = BDSExtentGlobal(meshExtent, placementTransform);
1088 result = result.ExpandToEncompass(meshExtentG);
1089 }
1090 return result;
1091}
1092
1093#if G4VERSION_NUMBER > 1009
1095BDSDetectorConstruction::BuildCrossSectionBias(const std::list<std::string>& biasList,
1096 const std::list<std::string>& defaultBias,
1097 const G4String& elementName)
1098{
1099 // no accelerator components to bias
1100 if (biasList.empty() && defaultBias.empty())
1101 {return nullptr;}
1102
1103 std::list<std::string> biasesAll = biasList.empty() ? defaultBias : biasList;
1104
1105 // build a unique 'key' as the sorted set of bias names
1106 std::set<std::string> biasNamesSorted = {biasesAll.begin(), biasesAll.end()};
1107 G4String biasSetKey;
1108 G4String biasSetPrintOut;
1109 for (const auto& n : biasNamesSorted)
1110 {
1111 biasSetKey += n + "_";
1112 biasSetPrintOut += n + " ";
1113 }
1114 biasSetKey = BDS::StrStrip(biasSetKey, '_', BDS::StringStripType::trailing);
1115
1116 auto exists = biasSetObjects.find(biasSetKey);
1117 if (exists != biasSetObjects.end())
1118 {return exists->second;}
1119
1120 // loop over all physics biasing
1121 G4cout << "Bias> Creating unique set of bias objects ( " << biasSetPrintOut << ")" << G4endl;
1123
1124 const auto& biasObjectList = BDSParser::Instance()->GetBiasing();
1125 for (std::string const & bs : biasesAll)
1126 {
1127 auto result = biasObjectList.find(bs);
1128 if (result == biasObjectList.end())
1129 {throw BDSException("Error: bias named \"" + bs + "\" not found for element named \"" + elementName + "\"");}
1130 const GMAD::PhysicsBiasing& pb = *result;
1131
1132 if(debug)
1133 {G4cout << __METHOD_NAME__ << "bias loop : " << bs << " " << pb.particle << " " << pb.process << G4endl;}
1134
1135 eg->AddParticle(pb.particle);
1136
1137 // loop through all processes
1138 if (pb.flag.size() != pb.processList.size())
1139 {throw BDSException(__METHOD_NAME__, "number of flag entries in \"" + pb.name + "\" doesn't match number of processes");}
1140 if (pb.factor.size() != pb.processList.size())
1141 {throw BDSException(__METHOD_NAME__, "number of factor entries in \"" + pb.name + "\" doesn't match number of processes");}
1142 for (unsigned int p = 0; p < pb.processList.size(); ++p)
1143 {eg->SetBias(bs, pb.particle,pb.processList[p],pb.factor[p],(G4int)pb.flag[p]);}
1144 }
1145
1146 biasObjects.push_back(eg);
1147 biasSetObjects[biasSetKey] = eg; // cache it
1148 return eg;
1149}
1150#endif
1151
1153{
1154#if G4VERSION_NUMBER > 1009
1156 if (debug)
1157 {G4cout << __METHOD_NAME__ << "registry=" << registry << G4endl;}
1158
1159#if G4VERSION_NUMBER > 1039
1160 // only available in 4.10.4 onwards
1161 // crystal biasing necessary for implementation of variable density
1162 std::set<G4LogicalVolume*>* crystals = BDSAcceleratorModel::Instance()->VolumeSet("crystals");
1163 if (!crystals->empty())
1164 {
1165 G4cout << __METHOD_NAME__ << "Using crystal biasing: true" << G4endl; // to match print out style further down
1166 auto crystalBiasing = new G4ChannelingOptrMultiParticleChangeCrossSection();
1167 for (auto crystal : *crystals)
1168 {crystalBiasing->AttachTo(crystal);}
1169 }
1170#endif
1171
1172 auto blmSet = BDSBLMRegistry::Instance()->BLMs();
1173 for (auto blm : blmSet)
1174 {
1175 G4String biasNamesS = blm->Bias();
1176 if (biasNamesS.empty())
1177 {continue;}
1178 auto biasNamesV = BDS::SplitOnWhiteSpace(biasNamesS);
1179 std::list<std::string> biasNames = {biasNamesV.begin(), biasNamesV.end()};
1180 std::list<std::string> emptyDefaultBias;
1181 auto biasForBLM = BuildCrossSectionBias(biasNames, emptyDefaultBias, blm->GetName());
1182 for (auto lv : blm->GetAllLogicalVolumes())
1183 {biasForBLM->AttachTo(lv);}
1184 biasForBLM->AttachTo(blm->GetContainerLogicalVolume()); // in some cases it's just a single volume
1185 }
1186
1188 G4String defaultBiasVacuum = BDSParser::Instance()->GetOptions().defaultBiasVacuum;
1189 auto defaultBiasVacuumVector = BDS::SplitOnWhiteSpace(defaultBiasVacuum);
1190 auto defaultBiasVacuumList = std::list<std::string>(defaultBiasVacuumVector.begin(), defaultBiasVacuumVector.end());
1191 G4String defaultBiasMaterial = BDSParser::Instance()->GetOptions().defaultBiasMaterial;
1192 auto defaultBiasMaterialVector = BDS::SplitOnWhiteSpace(defaultBiasMaterial);
1193 auto defaultBiasMaterialList = std::list<std::string>(defaultBiasMaterialVector.begin(), defaultBiasMaterialVector.end());
1194 G4String biasForWorldVolume = g->BiasForWorldVolume();
1195 auto biasForWorldVolumeVector = BDS::SplitOnWhiteSpace(biasForWorldVolume);
1196 auto biasForWorldVolumeList = std::list<std::string>(biasForWorldVolumeVector.begin(), biasForWorldVolumeVector.end());
1197 G4String biasForWorldContents = g->BiasForWorldContents();
1198 auto biasForWorldContentsVector = BDS::SplitOnWhiteSpace(biasForWorldContents);
1199 auto biasForWorldContentsList = std::list<std::string>(biasForWorldContentsVector.begin(), biasForWorldContentsVector.end());
1200 G4String biasForWorldVacuum = g->BiasForWorldVacuum();
1201 auto biasForWorldVacuumVector = BDS::SplitOnWhiteSpace(biasForWorldVacuum);
1202 auto biasForWorldVacuumList = std::list<std::string>(biasForWorldVacuumVector.begin(), biasForWorldVacuumVector.end());
1203
1204 G4bool useDefaultBiasVacuum = !defaultBiasVacuum.empty();
1205 G4bool useDefaultBiasMaterial = !defaultBiasMaterial.empty();
1206 const auto& biasObjectList = BDSParser::Instance()->GetBiasing();
1207 G4bool useBiasForWorldVolume = !biasForWorldVolume.empty();
1208 G4bool useBiasForWorldContents = !biasForWorldContents.empty();
1209 G4bool useBiasForWorldVacuum = !biasForWorldVacuum.empty();
1210 G4bool biasesDefined = !biasObjectList.empty();
1211
1212 G4bool overallUseBiasing = useDefaultBiasVacuum || useDefaultBiasMaterial || biasesDefined || useBiasForWorldVolume || useBiasForWorldContents;
1213 G4cout << __METHOD_NAME__ << "Using generic biasing: " << BDS::BoolToString(overallUseBiasing) << G4endl;
1214 if (!overallUseBiasing)
1215 {return;} // no biasing used -> dont attach as just overhead for no reason
1216
1217 // apply per element biases
1218 std::map<G4String, BDSAcceleratorComponent*> allAcceleratorComponents = registry->AllComponentsIncludingUnique();
1219 for (auto const & item : allAcceleratorComponents)
1220 {
1221 if (debug)
1222 {G4cout << __METHOD_NAME__ << "checking component named: " << item.first << G4endl;}
1223 BDSAcceleratorComponent* accCom = item.second;
1224 BDSLine* l = dynamic_cast<BDSLine*>(accCom);
1225 if (l)
1226 {continue;} // do nothing for lines because each sub-component already has all definitions
1227 G4String accName = accCom->GetName();
1228 std::set<G4LogicalVolume*> vacuumLVs = accCom->GetAcceleratorVacuumLogicalVolumes();
1229
1230 // Build vacuum bias object based on vacuum bias list in the component
1231 auto vacuumBiasList = accCom->GetBiasVacuumList();
1232 if (!vacuumBiasList.empty() && vacuumLVs.empty())
1233 {BDS::Warning("biasVacuum set for component \"" + accName + "\" but there's no 'vacuum' volume for it and it can't be biased.\nRemove biasVacuum or name it with the namedVacuumVolumes parameter.");}
1234 if ((!vacuumBiasList.empty() || useDefaultBiasVacuum) && !vacuumLVs.empty())
1235 {
1236 auto egVacuum = BuildCrossSectionBias(vacuumBiasList, defaultBiasVacuumList, accName);
1237 for (auto lv : vacuumLVs)
1238 {
1239 if (debug)
1240 {G4cout << __METHOD_NAME__ << "vacuum volume name: " << lv << " " << lv->GetName() << G4endl;}
1241 egVacuum->AttachTo(lv);
1242 }
1243 }
1244
1245 // Build material bias object based on material bias list in the component
1246 auto materialBiasList = accCom->GetBiasMaterialList();
1247 if (!materialBiasList.empty() || useDefaultBiasMaterial)
1248 {
1249 auto egMaterial = BuildCrossSectionBias(materialBiasList, defaultBiasMaterialList, accName);
1250 auto allLVs = accCom->GetAcceleratorMaterialLogicalVolumes();
1251 if (debug)
1252 {G4cout << __METHOD_NAME__ << "# of logical volumes for biasing under 'material': " << allLVs.size() << G4endl;}
1253 for (auto lv : allLVs)
1254 {// BDSAcceleratorComponent automatically removes 'vacuum' volumes from all so we don't need to check
1255 if (debug)
1256 {G4cout << __METHOD_NAME__ << "Biasing 'material' logical volume: " << lv << " " << lv->GetName() << G4endl;}
1257 egMaterial->AttachTo(lv);
1258 }
1259 }
1260 }
1261
1262 if (useBiasForWorldContents)
1263 {
1264 std::list<std::string> emptyList;
1265 auto egWC = BuildCrossSectionBias(emptyList, biasForWorldContentsList, "world_contents_bias");
1266 for (auto lv : worldContentsLogicalVolumes)
1267 {egWC->AttachTo(lv);}
1268 }
1269 if (useBiasForWorldVolume)
1270 {
1271 std::list<std::string> emptyList;
1272 auto egWV = BuildCrossSectionBias(emptyList, biasForWorldVolumeList, "world_volume_bias");
1273 egWV->AttachTo(worldLogicalVolume);
1274 }
1275 if (useBiasForWorldVacuum)
1276 {
1277 std::list<std::string> emptyList;
1278 auto egWVac = BuildCrossSectionBias(emptyList, biasForWorldVacuumList, "world_vacuum_bias");
1279 for (auto lv : worldVacuumLogicalVolumes)
1280 {egWVac->AttachTo(lv);}
1281 }
1282#endif
1283}
1284
1286{
1287 auto flds = BDSFieldBuilder::Instance()->CreateAndAttachAll(); // avoid shadowing 'fields'
1289
1291}
1292
1293G4bool BDSDetectorConstruction::UnsuitableFirstElement(GMAD::FastList<GMAD::Element>::FastListConstIterator element)
1294{
1295 // skip past any line elements in parser to find first non-line element
1296 while ((*element).type == GMAD::ElementType::_LINE)
1297 {element++;}
1298
1299 if ((*element).type == GMAD::ElementType::_RBEND)
1300 {return true;} // unsuitable
1301 else if (BDS::IsFinite((*element).e1))
1302 {return true;} // unsuitable
1303 else
1304 {return false;} // suitable
1305}
1306
1308{
1309 // needed for filtering
1310 G4LogicalVolume* worldLV = acceleratorModel->WorldLV();
1311
1312 std::vector<GMAD::ScorerMesh> scoringMeshes = BDSParser::Instance()->GetScorerMesh();
1313 std::vector<GMAD::Scorer> scorers = BDSParser::Instance()->GetScorers();
1314
1315 if (scoringMeshes.empty())
1316 {return;}
1317
1318 G4ScoringManager* scManager = G4ScoringManager::GetScoringManager();
1319 scManager->SetVerboseLevel(1);
1320
1321 // convert all the parser scorer definitions into recipes (including parameter checking)
1322 std::map<G4String, BDSScorerInfo> scorerRecipes;
1323 for (const auto& scorer : scorers)
1324 {
1325 BDSScorerInfo si = BDSScorerInfo(scorer, true); // true = upgrade to 3d as required for 3d mesh here
1326 scorerRecipes.insert(std::make_pair(si.name, si));
1327 }
1328
1329 // construct meshes
1330 BDSScorerFactory scorerFactory;
1331 for (const auto& mesh : scoringMeshes)
1332 {
1333 // convert to recipe class as this checks parameters
1334 BDSScorerMeshInfo meshRecipe = BDSScorerMeshInfo(mesh);
1335
1336 // name we'll use for the mesh
1337 G4String meshName = meshRecipe.name;
1338
1339 // TBC - could be any beam line in future - just w.r.t. main beam line just now
1340 const BDSBeamline* mbl = BDSAcceleratorModel::Instance()->BeamlineMain();
1341 G4Transform3D placement = CreatePlacementTransform(mesh, mbl);
1342
1343 BDSScoringMeshBox* scorerBox = nullptr;
1344 BDSScoringMeshCylinder* scorerCylindrical = nullptr;
1345 const BDSHistBinMapper* mapper = nullptr;
1346
1347 G4String geometryType = BDS::LowerCase(G4String(mesh.geometryType));
1348
1349 if (geometryType == "box")
1350 {// create a scoring box
1351 scorerBox = new BDSScoringMeshBox(meshName, meshRecipe, placement);
1352 mapper = scorerBox->Mapper();
1353 }
1354 else if (geometryType == "cylindrical")
1355 {// create a scoring cylinder
1356 scorerCylindrical = new BDSScoringMeshCylinder(meshName, meshRecipe, placement);
1357 mapper = scorerCylindrical->Mapper();
1358 }
1359 else
1360 {
1361 G4String msg = "mesh geometry type \"" + geometryType + "\" is not correct. The possible options are \"box\" and \"cylindrical\"";
1362 throw BDSException(__METHOD_NAME__, msg);
1363 }
1364
1365 // add the scorer(s) to the scoring mesh
1366 std::vector<G4String> meshPrimitiveScorerNames; // final vector of unique mesh + ps names
1367 std::vector<G4double> meshPrimitiveScorerUnits;
1368 std::vector<G4String> scorerNames;
1369
1370 std::vector<G4String> words = BDS::SplitOnWhiteSpace(mesh.scoreQuantity);
1371 for (const auto& word : words)
1372 {
1373 auto search = scorerRecipes.find(word);
1374 if (search == scorerRecipes.end())
1375 {throw BDSException(__METHOD_NAME__, "scorerQuantity \"" + word + "\" for mesh \"" + meshName + "\" not found.");}
1376
1377 G4double psUnit = 1.0;
1378 G4VPrimitiveScorer* ps = scorerFactory.CreateScorer(&(search->second), mapper, &psUnit, worldLV);
1379 // The mesh internally creates a multifunctional detector which is an SD and has
1380 // the name of the mesh. Any primitive scorer attached is added to the mfd. To get
1381 // the hits map we need the full name of the unique primitive scorer so we build that
1382 // name here and store it.
1383 G4String uniqueName = meshName + "/" + ps->GetName();
1384 meshPrimitiveScorerNames.push_back(uniqueName);
1385 meshPrimitiveScorerUnits.push_back(psUnit);
1386
1387 // sets the current ps but appends to list of multiple
1388 if (geometryType == "box")
1389 {scorerBox->SetPrimitiveScorer(ps);}
1390 else if (geometryType == "cylindrical")
1391 {scorerCylindrical->SetPrimitiveScorer(ps);}
1392
1393 BDSScorerHistogramDef outputHistogram(meshRecipe, uniqueName, ps->GetName(), psUnit, *mapper);
1394 BDSAcceleratorModel::Instance()->RegisterScorerHistogramDefinition(outputHistogram);
1395 BDSAcceleratorModel::Instance()->RegisterScorerPlacement(meshName, placement);
1396 }
1397
1398 if (geometryType == "box")
1399 {scManager->RegisterScoringMesh(scorerBox);} // sets the current ps but appends to list of multiple
1400 else if (geometryType == "cylindrical")
1401 {scManager->RegisterScoringMesh(scorerCylindrical);}// sets the current ps but appends to list of multiple
1402
1403 // register it with the sd manager as this is where we get all collection IDs from
1404 // in the end of event action. This must come from the mesh as it creates the
1405 // multifunctionaldetector and therefore has the complete name of the scorer collection
1406 BDSSDManager::Instance()->RegisterPrimitiveScorerNames(meshPrimitiveScorerNames, &meshPrimitiveScorerUnits);
1407 }
1408}
1409
1410std::vector<BDSFieldQueryInfo*> BDSDetectorConstruction::PrepareFieldQueries(const BDSBeamline* mainBeamline)
1411{
1412 std::vector<BDSFieldQueryInfo*> result;
1413 const std::vector<GMAD::Query>& parserQueries = BDSParser::Instance()->GetQuery();
1414 for (const auto& def : parserQueries)
1415 {
1416 if (!def.queryMagneticField && !def.queryElectricField)
1417 {throw BDSException(__METHOD_NAME__, "neither \"queryMagneticField\" nor \"queryElectricField\" are true (=1) - one must be turned on.");}
1418
1419 if (!def.pointsFile.empty())
1420 {
1421 std::vector<G4String> columnNames;
1422 auto points = BDS::LoadFieldQueryPoints(G4String(def.pointsFile), &columnNames);
1423 result.emplace_back(new BDSFieldQueryInfo(G4String(def.name),
1424 G4String(def.outfileMagnetic),
1425 G4String(def.outfileElectric),
1426 G4bool(def.queryMagneticField),
1427 G4bool(def.queryElectricField),
1428 points,
1429 columnNames,
1430 G4bool(def.overwriteExistingFiles),
1431 G4String(def.fieldObject),
1432 def.checkParameters,
1433 def.drawArrows,
1434 def.drawZeroValuePoints,
1435 def.drawBoxes,
1436 def.boxAlpha));
1437 }
1438 else
1439 {
1440 G4Transform3D globalTransform3D = CreatePlacementTransform(def, mainBeamline);
1441 auto rot = globalTransform3D.getRotation();
1442 rot = rot.inverse();
1443 G4AffineTransform globalTransform(rot, globalTransform3D.getTranslation());
1444
1445 result.emplace_back(new BDSFieldQueryInfo(G4String(def.name),
1446 G4String(def.outfileMagnetic),
1447 G4String(def.outfileElectric),
1448 G4bool(def.queryMagneticField),
1449 G4bool(def.queryElectricField),
1450 {def.nx, def.xmin*CLHEP::m, def.xmax*CLHEP::m},
1451 {def.ny, def.ymin*CLHEP::m, def.ymax*CLHEP::m},
1452 {def.nz, def.zmin*CLHEP::m, def.zmax*CLHEP::m},
1453 {def.nt, def.tmin*CLHEP::ns, def.tmax*CLHEP::ns},
1454 globalTransform,
1455 G4bool(def.overwriteExistingFiles),
1456 G4String(def.fieldObject),
1457 G4bool(def.printTransform),
1458 def.checkParameters,
1459 def.drawArrows,
1460 def.drawZeroValuePoints,
1461 def.drawBoxes,
1462 def.boxAlpha));
1463 }
1464 }
1465 return result;
1466}
1467
1468#ifdef BDSCHECKUSERLIMITS
1469void BDSDetectorConstruction::PrintUserLimitsSummary(const G4VPhysicalVolume* world) const
1470{
1471 G4cout << "USERLIMITS START" << G4endl;
1472 G4double globalMinEK = BDSGlobalConstants::Instance()->MinimumKineticEnergy();
1473 PrintUserLimitsPV(world, globalMinEK);
1474 G4cout << "USERLIMITS END" << G4endl;
1475}
1476
1477void BDSDetectorConstruction::PrintUserLimitsPV(const G4VPhysicalVolume* aPV, G4double globalMinEK) const
1478{
1479 const auto lv = aPV->GetLogicalVolume();
1480 const auto ul = lv->GetUserLimits();
1481 if (ul)
1482 {
1483 G4Track dummyTrack;
1484 G4double ekUL = ul->GetUserMinEkine(dummyTrack);
1485 //G4cout << lv->GetName() << " Ek Min: " << ekUL << G4endl;
1486 if (ekUL < globalMinEK)
1487 {G4cout << lv->GetName() << " Ek Min: " << ekUL << " MeV < global: " << globalMinEK << " MeV" << G4endl;}
1488 }
1489 else
1490 {G4cout << lv->GetName() << " no G4UserLimits" << G4endl;}
1491 for (G4int i = 0; i < (G4int)lv->GetNoDaughters(); i++)
1492 {PrintUserLimitsPV(lv->GetDaughter(i), globalMinEK);}
1493}
1494#endif
1495
1497{
1498 if (!worldLogicalVolume)
1499 {return;}
1500 G4cout << "\nSensitivity Summary:\n" << G4endl;
1501 PrintSensitiveDetectorsOfLV(worldLogicalVolume, 0);
1502 G4cout << "\n\n" << G4endl;
1503}
1504
1505void BDSDetectorConstruction::PrintSensitiveDetectorsOfLV(const G4LogicalVolume* lv, G4int currentDepth) const
1506{
1507 for (G4int i = 0; i < currentDepth; i++)
1508 {G4cout << "-> ";}
1509 G4cout << lv->GetName() << " ";
1510 auto sensitiveDetector = lv->GetSensitiveDetector();
1511 if (sensitiveDetector)
1512 {G4cout << sensitiveDetector->GetName();}
1513 else
1514 {G4cout << "none";}
1515 G4cout << G4endl;
1516
1517 for (std::size_t i = 0; i < lv->GetNoDaughters(); i++)
1518 {PrintSensitiveDetectorsOfLV(lv->GetDaughter(i)->GetLogicalVolume(), currentDepth+1);}
1519}
A registry of constructed BDSAcceleratorComponent instances that can be searched.
static BDSAcceleratorComponentRegistry * Instance()
Singleton accessor.
std::map< G4String, BDSAcceleratorComponent * > AllComponentsIncludingUnique() const
void PrintNumberOfEachType() const
Print out the number of each type of component registered.
Abstract class that represents a component of an accelerator.
virtual G4String GetName() const
The name of the component without modification.
virtual std::set< G4LogicalVolume * > GetAcceleratorVacuumLogicalVolumes() const
Access the 'vacuum' volume(s) in this component if any. Default is empty set.
virtual std::set< G4LogicalVolume * > GetAcceleratorMaterialLogicalVolumes() const
Return a set of logical volumes excluding the ones in the 'vacuum' set.
std::list< std::string > GetBiasVacuumList() const
Access the bias list copied from parser.
G4String GetType() const
Get a string describing the type of the component.
std::list< std::string > GetBiasMaterialList() const
Access the bias list copied from parser.
void RegisterFields(std::vector< BDSFieldObjects * > &fieldsIn)
Register all field objects.
void RegisterBeamlineSetExtra(const G4String &name, const BDSBeamlineSet &setIn)
Register a set of beam lines to be managed and cleared up at the end of the simulation.
void RegisterWorldLV(G4LogicalVolume *worldIn)
Register constituent of world.
std::set< G4LogicalVolume * > * VolumeSet(const G4String &name)
Returns pointer to a set of logical volumes. If no set by that name exits, create it.
BDSApertureInfo * Aperture(G4String name) const
const std::map< G4String, BDSBeamlineSet > & ExtraBeamlines() const
Accessor.
BDSBeamline * TunnelBeamline() const
Access the beam line containing all the tunnel segments.
void RegisterApertures(const std::map< G4String, BDSApertureInfo * > &aperturesIn)
Register a map of apertures with associated names.
void RegisterScorerPlacement(const G4String &meshName, const G4Transform3D &placement)
Register a copy of the scorer placement so it can be used in the output.
const BDSBeamlineSet & BeamlineSetMain() const
Accessor.
const BDSBeamline * BeamlineMain() const
Accessor.
void RegisterTunnelBeamline(BDSBeamline *beamlineIn)
Register the beam line containing all the tunnel segments.
BDSBeamline * PlacementBeamline() const
Access the beam line of arbitrary placements.
void RegisterWorldPV(G4VPhysicalVolume *worldIn)
Register constituent of world.
void RegisterPlacementBeamline(BDSBeamline *placementBLIn)
Register the beam line of arbitrary placements.
void RegisterBeamlineSetMain(const BDSBeamlineSet &setIn)
Register the main beam line set.
void RegisterScorerHistogramDefinition(const BDSScorerHistogramDef &def)
G4LogicalVolume * WorldLV() const
Access the logical volume of the world.
void RegisterBLMs(BDSBeamline *blmsIn)
Register a beam line of blm placements.
G4Region * Region(const G4String &name) const
Access region information. Will exit if not found.
void RegisterWorldSolid(G4VSolid *worldIn)
Register constituent of world.
void RegisterRegion(BDSRegion *region)
Register a region.
Holder class for all information required to describe an aperture.
BDSExtent Extent() const
static void AttachWorldVolumeToNavigator(G4VPhysicalVolume *worldPVIn)
Setup the navigator w.r.t. to a world volume - typically real world.
static BDSBLMRegistry * Instance()
Accessor for registry.
A class that holds a fully constructed BDSAcceleratorComponent as well as any information relevant to...
G4double GetSPositionEnd() const
Accessor.
G4double GetSPositionMiddle() const
Accessor.
Simple struct to return a beamline plus associated beam lines.
void GetExtentGlobals(std::vector< BDSExtentGlobal > &extents) const
Append global extents of all beamlines to supplied vector.
A vector of BDSBeamlineElement instances - a beamline.
Definition: BDSBeamline.hh:61
const BDSBeamlineElement * GetElement(G4String acceleratorComponentName, G4int i=0) const
Get the ith placement of an element in the beam line. Returns null pointer if not found.
Definition: BDSBeamline.cc:739
BDSBeamlineElement * back() const
Return a reference to the last element.
Definition: BDSBeamline.hh:214
G4bool ElementAnglesSumToCircle() const
Check if the sum of the angle of all elements is two pi.
Definition: BDSBeamline.cc:922
reverse_iterator rend()
Iterator mechanics.
Definition: BDSBeamline.hh:172
const_iterator FindFromS(G4double S) const
Returns an iterator to the beamline element at s.
Definition: BDSBeamline.cc:681
G4bool empty() const
Iterator mechanics.
Definition: BDSBeamline.hh:175
G4Transform3D GetGlobalEuclideanTransform(G4double s, G4double x=0, G4double y=0, G4int *indexOfFoundElement=nullptr) const
Definition: BDSBeamline.cc:601
BDSExtentGlobal GetExtentGlobal() const
Get the global extents for this beamline.
Definition: BDSBeamline.cc:927
reverse_iterator rbegin()
Iterator mechanics.
Definition: BDSBeamline.hh:171
iterator begin()
Iterator mechanics.
Definition: BDSBeamline.hh:167
void AddComponent(BDSAcceleratorComponent *component, BDSTiltOffset *tiltOffset=nullptr, BDSSamplerInfo *samplerInfo=nullptr)
Definition: BDSBeamline.cc:124
iterator end()
Iterator mechanics.
Definition: BDSBeamline.hh:168
G4double GetTotalArcLength() const
Get the total ARC length for the beamline - ie the maximum s position.
Definition: BDSBeamline.hh:139
Factory for user specified accelerator components.
void SetDesignParticle(const BDSParticleDefinition *designParticleIn)
Update values for nominal rigidity and relativisitic beta of the beam particle.
Factory to produce all types of BDSAcceleratorComponents.
BDSAcceleratorComponent * CreateTeleporter(const G4double teleporterLength, const G4double teleporterWidth, const G4Transform3D &transformIn)
BDSAcceleratorComponent * CreateTerminator(G4double witdth)
BDSAcceleratorComponent * CreateComponent(GMAD::Element const *elementIn, GMAD::Element const *prevElementIn, GMAD::Element const *nextElementIn, G4double currentArcLengthIn=0)
static BDSTiltOffset * CreateTiltOffset(GMAD::Element const *el)
Create the tilt and offset information object by inspecting the parser element.
Factory for simple parallel geometry for curvilinear coordinates.
BDSBeamline * BuildCurvilinearBeamLine1To1(BDSBeamline const *const beamline, const G4bool circular)
Build a beam line of curvilinear geometry based on another beam line.
BDSBeamline * BuildCurvilinearBridgeBeamLine(BDSBeamline const *const beamline)
Build bridging volumes to join the curvilinear ones.
G4bool circular
Whether or not we're building a circular machine.
BDSBeamlineSet BuildBeamline(const GMAD::FastList< GMAD::Element > &beamLine, const G4String &name, const G4Transform3D &initialTransform=G4Transform3D(), G4double initialS=0.0, G4bool beamlineIsCircular=false, G4bool isPlacementBeamline=false)
BDSBOptrMultiParticleChangeCrossSection * BuildCrossSectionBias(const std::list< std::string > &biasList, const std::list< std::string > &defaultBias, const G4String &elementName)
Function that creates physics biasing cross section.
void InitialiseRegions()
Create and set parameters for various G4Regions.
std::vector< BDSBOptrMultiParticleChangeCrossSection * > biasObjects
List of bias objects - for memory management.
BDSExtent CalculateExtentOfScorerMesh(const GMAD::ScorerMesh &sm) const
Calculate local extent of scorer mesh in 3D.
BDSAcceleratorModel * acceleratorModel
Accelerator model pointer.
static G4ThreeVector SideToLocalOffset(const GMAD::Placement &placement, const BDSBeamline *beamLine, const BDSExtent &placementExtent)
Attach component with extent2 to component with extent1 with placement.
G4bool verbose
Variable copied from global constants.
static std::vector< BDSFieldQueryInfo * > PrepareFieldQueries(const BDSBeamline *mainBeamline)
Prepare field queries from parser information.
G4VPhysicalVolume * BuildWorld()
void VerboseSensitivity() const
Print out the sensitivity of every single volume so far constructed in the world.
void InitialiseApertures()
Create all aperture definitions from parser and store in BDSAcceleratorModel.
void CountPlacementFields()
Count number of fields required for placements.
G4bool canSampleAngledFaces
Whether the integrator set permits sampling elements with angled faces.
BDSExtent worldExtent
Record of the world extent.
std::set< G4LogicalVolume * > worldContentsLogicalVolumes
Cache of possibly loaded logical volumes from a world geometry file - used for biasing.
static BDSSamplerInfo * BuildSamplerInfo(const GMAD::Element *element)
BDSExtent CalculateExtentOfSamplerPlacement(const GMAD::SamplerPlacement &sp) const
Calculate local extent of custom user sampler.
void ConstructScoringMeshes()
Construct scoring meshes.
BDSExtentGlobal CalculateExtentOfScorerMeshes(const BDSBeamline *bl) const
G4bool checkOverlaps
Variable copied from global constants.
G4int nSamplers
Count of number of samplers to be built.
void ComponentPlacement(G4VPhysicalVolume *worldPV)
Place beam line, tunnel beam line, end pieces and placements in world.
void BuildBeamlines()
Build the main beam line and then any other required beam lines.
const BDSParticleDefinition * designParticle
Particle definition all components are built w.r.t. Includes rigidity etc.
void BuildTunnel()
Build the tunnel around the already constructed flat beam line.
virtual void ConstructSDandField()
Construct sensitive detectors and fields.
void PrintSensitiveDetectorsOfLV(const G4LogicalVolume *lv, G4int currentDepth) const
Recursive function to print out each sensitive detector name.
static void PlaceBeamlineInWorld(BDSBeamline *beamline, G4VPhysicalVolume *containerPV, G4bool checkOverlaps=false, G4bool setRegions=false, G4bool registerInfo=false, G4bool useCLPlacementTransform=false, G4bool useIncrementalCopyNumbers=false, G4bool registerPlacementNamesForOutput=false)
virtual G4VPhysicalVolume * Construct()
static G4Transform3D CreatePlacementTransform(const GMAD::Placement &placement, const BDSBeamline *beamLine, G4double *S=nullptr, BDSExtent *placementExtent=nullptr, const G4String &objectTypeForErrorMsg="placement")
G4bool UnsuitableFirstElement(std::list< GMAD::Element >::const_iterator element)
BDSExtentGlobal CalculateExtentOfSamplerPlacements(const BDSBeamline *beamLine) const
General exception with possible name of object and message.
Definition: BDSException.hh:35
Holder for +- extents in 3 dimensions with a rotation and translation.
BDSExtentGlobal ExpandToEncompass(const BDSExtentGlobal &other) const
Return a copy of this extent but expanded to encompass another global extent.
G4bool Encompasses(const BDSExtentGlobal &otherExtent)
Return whether the extent encompasses another extent.
Holder for +- extents in 3 dimensions.
Definition: BDSExtent.hh:39
G4double XPos() const
Accessor.
Definition: BDSExtent.hh:66
G4double XNeg() const
Accessor.
Definition: BDSExtent.hh:65
G4double YNeg() const
Accessor.
Definition: BDSExtent.hh:67
std::pair< G4double, G4double > ExtentZ() const
Accessor.
Definition: BDSExtent.hh:63
G4double DX() const
The difference in a dimension.
Definition: BDSExtent.hh:83
G4double YPos() const
Accessor.
Definition: BDSExtent.hh:68
static BDSFieldBuilder * Instance()
Singleton pattern accessor.
Holder class for all information required for a field query.
static void AttachWorldVolumeToNavigator(G4VPhysicalVolume *worldPVIn)
Setup the navigator w.r.t. to a world volume.
Gap in accelerator beamline.
Definition: BDSGap.hh:32
G4LogicalVolume * GetContainerLogicalVolume() const
Accessor - see member for more info.
BDSExtent GetExtent() const
Accessor - see member for more info.
virtual void AttachSensitiveDetectors()
Attach a sensitive detector class to all registered sensitive volumes in this component.
virtual std::set< G4LogicalVolume * > GetAllLogicalVolumes() const
Access all logical volumes belonging to this component.
G4VSolid * GetContainerSolid() const
Accessor - see member for more info.
A loaded piece of externally provided geometry.
const std::set< G4LogicalVolume * > & VacuumVolumes() const
Access the vacuum volumes.
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.
A class that holds global options and constants.
void SetCurvilinearDiameterShrunkForBends()
Setter.
static BDSGlobalConstants * Instance()
Access method.
void SetCurvilinearDiameter(G4double curvilinearDiameterIn)
Setter.
void SetSamplerDiameter(G4double samplerDiameterIn)
Setter.
G4bool UseImportanceSampling() const
Is importance sampling being used.
Mapping from axis indices to 1D index.
A class that hold multiple accelerator components.
Definition: BDSLine.hh:38
static BDSMaterials * Instance()
Singleton pattern access.
Definition: BDSMaterials.cc:39
G4Material * GetMaterial(G4String material) const
Get material by name.
const GMAD::FastList< GMAD::Element > & GetSequence(const std::string &name)
Return sequence.
Definition: BDSParser.hh:81
std::vector< GMAD::Scorer > GetScorers() const
Return the parser list of that object.
Definition: BDSParser.hh:107
static BDSParser * Instance()
Access method.
Definition: BDSParser.cc:28
const GMAD::Options & GetOptions() const
Return options.
Definition: BDSParser.hh:50
std::vector< GMAD::Query > GetQuery() const
Return the parser list of that object.
Definition: BDSParser.hh:104
std::vector< GMAD::SamplerPlacement > GetSamplerPlacements() const
Return the parser list of that object.
Definition: BDSParser.hh:106
const GMAD::FastList< GMAD::PhysicsBiasing > & GetBiasing() const
Return biasing list.
Definition: BDSParser.hh:92
std::vector< GMAD::ScorerMesh > GetScorerMesh() const
Return the parser list of that object.
Definition: BDSParser.hh:108
std::vector< GMAD::Placement > GetPlacements() const
Return the parser list of that object.
Definition: BDSParser.hh:103
void RegisterPVsForOutput(const BDSBeamlineElement *element, const std::set< G4VPhysicalVolume * > &physicalVolumes)
void RegisterExcludedPV(G4VPhysicalVolume *physicalVolume)
void RegisterInfo(G4VPhysicalVolume *physicalVolume, BDSPhysicalVolumeInfo *info, G4bool isReadOutVolume=false, G4bool isTunnel=false)
static BDSPhysicalVolumeInfoRegistry * Instance()
Singleton accessor.
A class holding any information pertaining to a particular physical volume in a BDSIM geant4 model.
Range cuts for a region. Help with defaults.
Definition: BDSRegion.hh:41
void ConstructSamplerSDsForParticleSets(const std::map< int, std::set< int > > &samplerFilterIDtoPDGSetIn)
void RegisterPrimitiveScorerNames(const std::vector< G4String > &namesIn, const std::vector< G4double > *units=nullptr)
Loop over a vector and apply above single name function.
All info required to build a sampler but not place it.
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.
Definition for a scorer histogram.
Recipe class for scorer. Checks values.
G4String name
Scorer name.
Recipe class for a scoring mesh.
Wrapper for G4ScoringBox to allow full access to placement.
Wrapper for G4ScoringCylinder to allow full access to placement.
A class of functions to output Geant4/Mokka/BDSIM parameters for the beamline.
Definition: BDSSurvey.hh:39
void Write(BDSBeamlineElement *beamlineElement)
write line
Definition: BDSSurvey.cc:109
A holder for any placement offsets and rotations for a BDSAcceleratorComponent.
static G4double dEThresholdForScattering
A class that constructs tunnel segments around a beamline.
BDSBeamline * BuildTunnelSections(const BDSBeamline *flatBeamLine) const
Aperture class.
Definition: aperture.h:38
blm for parser.
Definition: blmplacement.h:39
List with Efficient Lookup.
Definition: fastlist.h:42
FastListIterator begin()
Definition: fastlist.h:215
FastListIterator end()
Definition: fastlist.h:220
bool empty() const
Whether the list is empty.
Definition: fastlist.h:68
FastListConstIterator find(std::string name, unsigned int count=1) const
Definition: fastlist.h:245
int size() const
size of list
Definition: fastlist.h:164
const FastList< Element > & GetBeamline() const
Definition: parser.cc:903
Physics biasing class for parser.
std::vector< double > factor
factors corresponding to process
std::vector< PhysicsBiasingType > flag
flag which particles are biased
std::string particle
particle name
std::string process
geant4 process: single string, but can have multiple processes separated with a space
Placement class for parser.
Definition: placement.h:41
bool axisAngle
Flag to use the axis angle construction of rotation.
Definition: placement.h:65
double axisZ
Definition: placement.h:61
std::string name
Name of this placement.
Definition: placement.h:43
std::string side
which side to attach to: top, bottom, left, right.
Definition: placement.h:66
double theta
Euler angle for rotation.
Definition: placement.h:55
double sideOffset
Gap between side and component.
Definition: placement.h:67
double psi
Euler angle for rotation.
Definition: placement.h:56
double y
Offset in y.
Definition: placement.h:51
double s
Curvilinear s position to place w.r.t..
Definition: placement.h:49
double axisY
Definition: placement.h:60
double angle
Definition: placement.h:62
double x
Offset in x.
Definition: placement.h:50
int referenceElementNumber
Index of repetition of element if there are multiple uses.
Definition: placement.h:48
double phi
Euler angle for rotation.
Definition: placement.h:54
std::string referenceElement
Name of reference element w.r.t. to place to.
Definition: placement.h:47
double axisX
Definition: placement.h:59
Query structure class for parser.
Definition: query.h:37
Region class for parser.
Definition: region.h:36
Sampler placement class for parser.
std::string name
Name of this samplerplacement.
std::string samplerType
Plane, Cylinder, Sphere.
ScorerMesh class for parser.
Definition: scorermesh.h:38
BDSBeamline * BuildEndPieceBeamline(const BDSBeamline *beamline, const G4bool circularMachine)
G4Transform3D CalculateTeleporterDelta(const BDSBeamline *beamline, G4double &teleporterLength)
std::vector< BDSFourVector< G4double > > LoadFieldQueryPoints(const G4String &fileName, std::vector< G4String > *columnNamesIn)
BDSExtent MaximumCombinedExtent(const BDSExtent &first, const BDSExtent &second)
Returns the extent which is the greatest extent in all six directions.
Definition: BDSExtent.cc:248
BDSBeamline * BuildPlacementGeometry(const std::vector< GMAD::Placement > &placements, const BDSBeamline *parentBeamLine, BDSComponentFactory *componentFactory)
G4String LowerCase(const G4String &str)
Utility function to simplify lots of syntax changes for pedantic g4 changes.
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())
G4String StrStrip(const G4String &str, char ch, StringStripType stripType=StringStripType::both)
Utility function to simplify lots of syntax changes for pedantic g4 changes.
Definition: BDSUtilities.cc:98
Element class.
Definition: element.h:43
std::string samplerType
element has a sampler of this type (default "none")
Definition: element.h:202
int samplerParticleSetID
Definition: element.h:207
double e1
input pole face rotation for bends
Definition: element.h:60
std::string samplerName
name of sampler (default empty)
Definition: element.h:201