18#include "BDSAcceleratorModel.hh"
19#include "BDSApertureInfo.hh"
20#include "BDSBeamline.hh"
21#include "BDSBeamlineElement.hh"
22#include "BDSBeamPipeInfo.hh"
24#include "BDSDetectorConstruction.hh"
25#include "BDSExtent.hh"
26#include "BDSException.hh"
27#include "BDSGlobalConstants.hh"
28#include "BDSOutput.hh"
29#include "BDSParallelWorldSampler.hh"
30#include "BDSParser.hh"
31#include "BDSSampler.hh"
32#include "BDSSamplerCustom.hh"
33#include "BDSSamplerCylinder.hh"
34#include "BDSSamplerInfo.hh"
35#include "BDSSamplerPlane.hh"
36#include "BDSSamplerRegistry.hh"
37#include "BDSSamplerSphere.hh"
38#include "BDSSamplerType.hh"
39#include "BDSSDSampler.hh"
40#include "BDSUtilities.hh"
41#include "BDSWarning.hh"
43#include "parser/samplerplacement.h"
46#include "G4LogicalVolume.hh"
47#include "G4PVPlacement.hh"
48#include "G4Transform3D.hh"
49#include "G4VisAttributes.hh"
50#include "G4VPhysicalVolume.hh"
51#include "G4VUserParallelWorld.hh"
59 G4VUserParallelWorld(
"SamplerWorld_" + name),
61 samplerWorldVis(nullptr),
62 generalPlane(nullptr),
63 samplerWorldLV(nullptr)
66BDSParallelWorldSampler::~BDSParallelWorldSampler()
79 G4VPhysicalVolume* samplerWorld = GetWorld();
80 samplerWorldLV = samplerWorld->GetLogicalVolume();
82 samplerWorldVis =
new G4VisAttributes(*(globals->VisibleDebugVisAttr()));
86 const G4double samplerRadius = 0.5*globals->SamplerDiameter();
88 const G4bool checkOverlaps = globals->CheckOverlaps();
94 std::map<int, std::set<int>> filterIDToSet =
BDSParser::Instance()->GetSamplerFilterIDToSet();
95 for (
const auto& kv : filterIDToSet)
100 samplerInstances[(G4int)kv.first] = samp;
105 if (beamline !=
nullptr)
107 for (
auto element : *beamline)
108 {
Place(element, samplerRadius);}
114 for (
const auto& samplerPlacement : samplerPlacements)
116 G4String sn = samplerPlacement.name;
117 G4cout <<
"User placed sampler: \"" << sn <<
"\"" << G4endl;
121 G4cerr << __METHOD_NAME__ <<
"invalid sampler name \"" << sn <<
"\"" << G4endl;
129 BDSSamplerType st = BDS::DetermineSamplerType(samplerPlacement.samplerType);
142 if (uniqueName != sn)
143 {BDS::Warning(
"Sampler placement with name \"" + sn +
"\" will be named \"" + uniqueName +
"\" in the output");}
145 G4PVPlacement* pl =
new G4PVPlacement(transform,
157 const G4String& variableName,
158 const G4String& objectName)
const
161 {
throw BDSException(
"\"" + variableName +
"\" is <= 0 and must be > 0 in samplerplacement \"" + objectName +
"\"");}
166 G4double& radius)
const
169 G4String samplerName = G4String(samplerPlacement.
name);
173 case BDSSamplerType::plane:
176 if (samplerPlacement.apertureModel.empty())
179 samplerPlacement.aper1 * CLHEP::m,
180 samplerPlacement.aper2 * CLHEP::m,
181 samplerPlacement.aper3 * CLHEP::m,
182 samplerPlacement.aper4 * CLHEP::m,
186 {shape = BDSAcceleratorModel::Instance()->
Aperture(samplerPlacement.apertureModel);}
191 case BDSSamplerType::cylinder:
195 G4double startAnglePhi = samplerPlacement.startAnglePhi * CLHEP::rad;
196 G4double sweepAnglePhi = samplerPlacement.sweepAnglePhi * CLHEP::rad;
197 if (sweepAnglePhi <= 0)
198 {sweepAnglePhi = CLHEP::twopi;}
199 else if (sweepAnglePhi > CLHEP::twopi + 1e-6)
200 {
throw BDSException(__METHOD_NAME__,
"\"sweepAnglePhi\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
203 samplerPlacement.aper1 * CLHEP::m,
204 2 * samplerPlacement.aper2 * CLHEP::m,
208 radius = samplerPlacement.aper1 * CLHEP::m;
211 case BDSSamplerType::cylinderforward:
216 {BDS::Warning(
"\"startAnglePhi\" in samplerplacement \""+samplerName+
"\" != 0 -> this has no effect for a cylinderforward sampler");}
218 G4double sweepAnglePhi = samplerPlacement.sweepAnglePhi * CLHEP::rad;
219 if (sweepAnglePhi <= 0)
220 {sweepAnglePhi = CLHEP::twopi;}
221 else if (sweepAnglePhi > CLHEP::twopi + 1e-6)
222 {
throw BDSException(__METHOD_NAME__,
"\"sweepAnglePhi\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
223 G4double startAnglePhi = -0.5*sweepAnglePhi;
226 samplerPlacement.aper1 * CLHEP::m,
227 2 * samplerPlacement.aper2 * CLHEP::m,
231 radius = samplerPlacement.aper1 * CLHEP::m;
234 case BDSSamplerType::sphere:
237 G4double startAnglePhi = samplerPlacement.startAnglePhi * CLHEP::rad;
238 G4double sweepAnglePhi = samplerPlacement.sweepAnglePhi * CLHEP::rad;
239 if (sweepAnglePhi <= 0)
240 {sweepAnglePhi = CLHEP::twopi;}
241 else if (sweepAnglePhi > CLHEP::twopi + 1e-6)
242 {
throw BDSException(__METHOD_NAME__,
"\"sweepAnglePhi\" must be in range (0 to 2 pi] in samplerplacement \"" + samplerName +
"\"");}
243 G4double startAngleTheta = samplerPlacement.startAngleTheta * CLHEP::rad;
244 if (startAngleTheta < 0)
245 {
throw BDSException(__METHOD_NAME__,
"\"startAngleTheta\" must be in the range [0 to pi] in samplerplacement \"" + samplerName +
"\"");}
246 G4double sweepAngleTheta = samplerPlacement.sweepAngleTheta * CLHEP::rad;
247 if (sweepAngleTheta <= 0)
248 {sweepAngleTheta = CLHEP::pi;}
249 else if (sweepAngleTheta > CLHEP::pi + 1e-6)
250 {
throw BDSException(__METHOD_NAME__,
"\"sweepAngleTheta\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
251 else if (sweepAngleTheta - startAngleTheta > CLHEP::pi + 1e-6)
252 {
throw BDSException(__METHOD_NAME__,
"\"startAngleTheta\" + \"sweepAngleTheta\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
255 samplerPlacement.aper1 * CLHEP::m,
261 radius = samplerPlacement.aper1 * CLHEP::m;
264 case BDSSamplerType::sphereforward:
268 {BDS::Warning(
"\"startAnglePhi\" in samplerplacement \""+samplerName+
"\" != 0 -> this has no effect for a sphereforward sampler");}
270 {BDS::Warning(
"\"startAngleTheta\" in samplerplacement \""+samplerName+
"\" != 0 -> this has no effect for a sphereforward sampler");}
272 G4double sweepAnglePhi = samplerPlacement.sweepAnglePhi * CLHEP::rad;
273 if (sweepAnglePhi <= 0)
274 {sweepAnglePhi = CLHEP::twopi;}
275 else if (sweepAnglePhi > CLHEP::twopi + 1e-6)
276 {
throw BDSException(__METHOD_NAME__,
"\"sweepAnglePhi\" must be in range (0 to 2 pi] in samplerplacement \"" + samplerName +
"\"");}
277 G4double sweepAngleTheta = samplerPlacement.sweepAngleTheta * CLHEP::rad;
278 if (sweepAngleTheta <= 0)
279 {sweepAngleTheta = CLHEP::pi;}
280 else if (sweepAngleTheta > CLHEP::pi + 1e-6)
281 {
throw BDSException(__METHOD_NAME__,
"\"sweepAngleTheta\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
283 G4double startAngleTheta = CLHEP::halfpi -0.5*sweepAngleTheta;
284 G4double startAnglePhi = -0.5*sweepAnglePhi;
287 samplerPlacement.aper1 * CLHEP::m,
293 radius = samplerPlacement.aper1 * CLHEP::m;
305 case BDSSamplerType::cylinderforward:
307 auto rmExisting = trans.getRotation();
309 rm.rotate(-CLHEP::halfpi, {0,0,1});
310 rm.rotate(-CLHEP::halfpi, {1,0,0});
312 trans = G4Transform3D(rmExisting, trans.getTranslation());
315 case BDSSamplerType::sphereforward:
317 auto rmExisting = trans.getRotation();
319 rm.rotate(-CLHEP::halfpi, {0,1,0});
321 trans = G4Transform3D(rmExisting, trans.getTranslation());
330 G4double samplerRadius)
336 if (samplerType == BDSSamplerType::none)
340 G4String name = samplerInfo->name;
346 case BDSSamplerType::plane:
347 {sampler = samplerInstances[samplerInfo->pdgSetID];
break;}
348 case BDSSamplerType::cylinder:
352 if (boundingRadius > 0)
353 {samplerRadius = boundingRadius;}
356 G4double angle = element->
GetAngle();
357 if (samplerInfo->startElement && samplerInfo->finishElement)
359 const auto startElement = samplerInfo->startElement;
360 const auto finishElement = samplerInfo->finishElement;
361 G4ThreeVector connectingVector = finishElement->
GetReferencePositionEnd() - startElement->GetReferencePositionStart();
362 G4double chordLength = connectingVector.mag();
364 G4ThreeVector directionFrameStart = G4ThreeVector(0,0,1).transform(*(startElement->GetReferenceRotationStart()));
365 G4ThreeVector directionFrameFinish = G4ThreeVector(0,0,1).transform(*(finishElement->GetReferenceRotationEnd()));
367 G4ThreeVector dChordFrameStart = connectingVector.unit() - directionFrameStart;
368 G4ThreeVector dChordFrameFinish = connectingVector.unit() - directionFrameFinish;
372 G4ThreeVector ipfnCSampler = G4ThreeVector(0,0,-1) + dChordFrameStart;
373 G4ThreeVector opfnCSampler = G4ThreeVector(0,0,1) - dChordFrameFinish;
381 samplerInfo->pdgSetID);
394 samplerInfo->pdgSetID);
402 samplerInfo->pdgSetID);
422 G4VPhysicalVolume* samplerWorld = GetWorld();
423 samplerWorldLV = samplerWorld->GetLogicalVolume();
426 G4PVPlacement* pl =
new G4PVPlacement(*pt,
G4ThreeVector OutputFaceNormal() const
G4ThreeVector InputFaceNormal() const
BDSApertureInfo * Aperture(G4String name) const
const BDSBeamline * BeamlineMain() const
Accessor.
Holder class for all information required to describe an aperture.
A class that holds a fully constructed BDSAcceleratorComponent as well as any information relevant to...
G4double GetChordLength() const
Accessor.
G4double GetAngle() const
Accessor.
G4ThreeVector GetReferencePositionEnd() const
Accessor.
BDSExtent GetExtent() const
Accessor.
BDSSamplerInfo * GetSamplerInfo() const
Accessor.
G4double GetSPositionEnd() const
Accessor.
BDSAcceleratorComponent * GetAcceleratorComponent() const
Accessor.
G4Transform3D * GetSamplerPlacementTransform() const
Accessor.
A vector of BDSBeamlineElement instances - a beamline.
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.
G4double TransverseBoundingRadius() const
Return a radius that would encompass the maximum x,y extent.
G4LogicalVolume * GetContainerLogicalVolume() const
Accessor - see member for more info.
A class that holds global options and constants.
static BDSGlobalConstants * Instance()
Access method.
static void PrintProtectedNames(std::ostream &out)
Feedback for protected names.
static G4bool InvalidSamplerName(const G4String &samplerName)
Test whether a sampler name is invalid or not.
BDSParallelWorldSampler()=delete
No default constructor.
BDSSamplerPlane * generalPlane
General single sampler we use for plane samplers.
void AdjustTransform(G4Transform3D &trans, BDSSamplerType st) const
void ErrorNonPositive(G4double value, const G4String &variableName, const G4String &objectName) const
Utility function to reduce code.
void Place(const BDSBeamlineElement *element, G4double samplerRadius)
Place a sampler from a single element.
std::vector< G4VPhysicalVolume * > placements
Cache of the placements to clean up at the end.
BDSSampler * BuildSampler(const GMAD::SamplerPlacement &samplerPlacement, BDSSamplerType st, G4double &radius) const
Construct the geometry for a sampler. Update 'radius' by reference if applicable.
G4VisAttributes * samplerWorldVis
Visualisation attributes for the sampler world.
static BDSParser * Instance()
Access method.
std::vector< GMAD::SamplerPlacement > GetSamplerPlacements() const
Return the parser list of that object.
Custom shaped sampler with fixed thickness.
Cylindrical sampler around an object.
All info required to build a sampler but not place it.
Rectangular sampler with fixed thickness but variable x,y.
static BDSSamplerRegistry * Instance()
Accessor for registry.
G4String GetNameUnique(G4int index) const
Accessor.
G4int RegisterSampler(const G4String &name, BDSSampler *sampler, const G4Transform3D &transform=G4Transform3D(), G4double S=-1000, const BDSBeamlineElement *element=nullptr, BDSSamplerType type=BDSSamplerType::plane, G4double radius=0)
Spherical sampler around an object.
Base class and registry of sampler instances.
type underlying() const
return underlying value (can be used in switch statement)
Sampler placement class for parser.
std::string name
Name of this samplerplacement.
int partIDSetID
The unique ID of the particle set given by the parser.
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())