19#include "BDSAcceleratorModel.hh"
20#include "BDSApertureInfo.hh"
21#include "BDSBeamline.hh"
22#include "BDSBeamlineElement.hh"
23#include "BDSBeamPipeInfo.hh"
25#include "BDSDetectorConstruction.hh"
26#include "BDSExtent.hh"
27#include "BDSException.hh"
28#include "BDSGlobalConstants.hh"
29#include "BDSOutput.hh"
30#include "BDSParallelWorldSampler.hh"
31#include "BDSParser.hh"
32#include "BDSSampler.hh"
33#include "BDSSamplerCustom.hh"
34#include "BDSSamplerCylinder.hh"
35#include "BDSSamplerInfo.hh"
36#include "BDSSamplerPlane.hh"
37#include "BDSSamplerRegistry.hh"
38#include "BDSSamplerSphere.hh"
39#include "BDSSamplerType.hh"
40#include "BDSSDSampler.hh"
41#include "BDSUtilities.hh"
42#include "BDSWarning.hh"
44#include "parser/samplerplacement.h"
47#include "G4LogicalVolume.hh"
48#include "G4PVPlacement.hh"
49#include "G4Transform3D.hh"
50#include "G4VisAttributes.hh"
51#include "G4VPhysicalVolume.hh"
52#include "G4VUserParallelWorld.hh"
60 G4VUserParallelWorld(
"SamplerWorld_" + name),
62 samplerWorldVis(nullptr),
63 generalPlane(nullptr),
64 samplerWorldLV(nullptr)
67BDSParallelWorldSampler::~BDSParallelWorldSampler()
80 G4VPhysicalVolume* samplerWorld = GetWorld();
81 samplerWorldLV = samplerWorld->GetLogicalVolume();
83 samplerWorldVis =
new G4VisAttributes(*(globals->VisibleDebugVisAttr()));
87 const G4double samplerRadius = 0.5*globals->SamplerDiameter();
89 const G4bool checkOverlaps = globals->CheckOverlaps();
95 std::map<int, std::set<int>> filterIDToSet =
BDSParser::Instance()->GetSamplerFilterIDToSet();
96 for (
const auto& kv : filterIDToSet)
101 samplerInstances[(G4int)kv.first] = samp;
106 if (beamline !=
nullptr)
108 for (
auto element : *beamline)
109 {
Place(element, samplerRadius);}
115 for (
const auto& samplerPlacement : samplerPlacements)
117 G4String sn = samplerPlacement.name;
118 G4cout <<
"User placed sampler: \"" << sn <<
"\"" << G4endl;
122 G4cerr << __METHOD_NAME__ <<
"invalid sampler name \"" << sn <<
"\"" << G4endl;
130 BDSSamplerType st = BDS::DetermineSamplerType(samplerPlacement.samplerType);
143 if (uniqueName != sn)
144 {BDS::Warning(
"Sampler placement with name \"" + sn +
"\" will be named \"" + uniqueName +
"\" in the output");}
146 G4PVPlacement* pl =
new G4PVPlacement(transform,
158 const G4String& variableName,
159 const G4String& objectName)
const
162 {
throw BDSException(
"\"" + variableName +
"\" is <= 0 and must be > 0 in samplerplacement \"" + objectName +
"\"");}
167 G4double& radius)
const
170 G4String samplerName = G4String(samplerPlacement.
name);
174 case BDSSamplerType::plane:
177 if (samplerPlacement.apertureModel.empty())
180 samplerPlacement.aper1 * CLHEP::m,
181 samplerPlacement.aper2 * CLHEP::m,
182 samplerPlacement.aper3 * CLHEP::m,
183 samplerPlacement.aper4 * CLHEP::m,
187 {shape = BDSAcceleratorModel::Instance()->
Aperture(samplerPlacement.apertureModel);}
192 case BDSSamplerType::cylinder:
196 G4double startAnglePhi = samplerPlacement.startAnglePhi * CLHEP::rad;
197 G4double sweepAnglePhi = samplerPlacement.sweepAnglePhi * CLHEP::rad;
198 if (sweepAnglePhi <= 0)
199 {sweepAnglePhi = CLHEP::twopi;}
200 else if (sweepAnglePhi > CLHEP::twopi + 1e-6)
201 {
throw BDSException(__METHOD_NAME__,
"\"sweepAnglePhi\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
204 samplerPlacement.aper1 * CLHEP::m,
205 2 * samplerPlacement.aper2 * CLHEP::m,
209 radius = samplerPlacement.aper1 * CLHEP::m;
212 case BDSSamplerType::cylinderforward:
217 {BDS::Warning(
"\"startAnglePhi\" in samplerplacement \""+samplerName+
"\" != 0 -> this has no effect for a cylinderforward sampler");}
219 G4double sweepAnglePhi = samplerPlacement.sweepAnglePhi * CLHEP::rad;
220 if (sweepAnglePhi <= 0)
221 {sweepAnglePhi = CLHEP::twopi;}
222 else if (sweepAnglePhi > CLHEP::twopi + 1e-6)
223 {
throw BDSException(__METHOD_NAME__,
"\"sweepAnglePhi\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
224 G4double startAnglePhi = -0.5*sweepAnglePhi;
227 samplerPlacement.aper1 * CLHEP::m,
228 2 * samplerPlacement.aper2 * CLHEP::m,
232 radius = samplerPlacement.aper1 * CLHEP::m;
235 case BDSSamplerType::sphere:
238 G4double startAnglePhi = samplerPlacement.startAnglePhi * CLHEP::rad;
239 G4double sweepAnglePhi = samplerPlacement.sweepAnglePhi * CLHEP::rad;
240 if (sweepAnglePhi <= 0)
241 {sweepAnglePhi = CLHEP::twopi;}
242 else if (sweepAnglePhi > CLHEP::twopi + 1e-6)
243 {
throw BDSException(__METHOD_NAME__,
"\"sweepAnglePhi\" must be in range (0 to 2 pi] in samplerplacement \"" + samplerName +
"\"");}
244 G4double startAngleTheta = samplerPlacement.startAngleTheta * CLHEP::rad;
245 if (startAngleTheta < 0)
246 {
throw BDSException(__METHOD_NAME__,
"\"startAngleTheta\" must be in the range [0 to pi] in samplerplacement \"" + samplerName +
"\"");}
247 G4double sweepAngleTheta = samplerPlacement.sweepAngleTheta * CLHEP::rad;
248 if (sweepAngleTheta <= 0)
249 {sweepAngleTheta = CLHEP::pi;}
250 else if (sweepAngleTheta > CLHEP::pi + 1e-6)
251 {
throw BDSException(__METHOD_NAME__,
"\"sweepAngleTheta\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
252 else if (sweepAngleTheta - startAngleTheta > CLHEP::pi + 1e-6)
253 {
throw BDSException(__METHOD_NAME__,
"\"startAngleTheta\" + \"sweepAngleTheta\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
256 samplerPlacement.aper1 * CLHEP::m,
262 radius = samplerPlacement.aper1 * CLHEP::m;
265 case BDSSamplerType::sphereforward:
269 {BDS::Warning(
"\"startAnglePhi\" in samplerplacement \""+samplerName+
"\" != 0 -> this has no effect for a sphereforward sampler");}
271 {BDS::Warning(
"\"startAngleTheta\" in samplerplacement \""+samplerName+
"\" != 0 -> this has no effect for a sphereforward sampler");}
273 G4double sweepAnglePhi = samplerPlacement.sweepAnglePhi * CLHEP::rad;
274 if (sweepAnglePhi <= 0)
275 {sweepAnglePhi = CLHEP::twopi;}
276 else if (sweepAnglePhi > CLHEP::twopi + 1e-6)
277 {
throw BDSException(__METHOD_NAME__,
"\"sweepAnglePhi\" must be in range (0 to 2 pi] in samplerplacement \"" + samplerName +
"\"");}
278 G4double sweepAngleTheta = samplerPlacement.sweepAngleTheta * CLHEP::rad;
279 if (sweepAngleTheta <= 0)
280 {sweepAngleTheta = CLHEP::pi;}
281 else if (sweepAngleTheta > CLHEP::pi + 1e-6)
282 {
throw BDSException(__METHOD_NAME__,
"\"sweepAngleTheta\" must be in range (0 to pi] in samplerplacement \"" + samplerName +
"\"");}
284 G4double startAngleTheta = CLHEP::halfpi -0.5*sweepAngleTheta;
285 G4double startAnglePhi = -0.5*sweepAnglePhi;
288 samplerPlacement.aper1 * CLHEP::m,
294 radius = samplerPlacement.aper1 * CLHEP::m;
306 case BDSSamplerType::cylinderforward:
308 auto rmExisting = trans.getRotation();
310 rm.rotate(-CLHEP::halfpi, {0,0,1});
311 rm.rotate(-CLHEP::halfpi, {1,0,0});
313 trans = G4Transform3D(rmExisting, trans.getTranslation());
316 case BDSSamplerType::sphereforward:
318 auto rmExisting = trans.getRotation();
320 rm.rotate(-CLHEP::halfpi, {0,1,0});
322 trans = G4Transform3D(rmExisting, trans.getTranslation());
331 G4double samplerRadius)
337 if (samplerType == BDSSamplerType::none)
341 G4String name = samplerInfo->name;
347 case BDSSamplerType::plane:
348 {sampler = samplerInstances[samplerInfo->pdgSetID];
break;}
349 case BDSSamplerType::cylinder:
353 if (boundingRadius > 0)
354 {samplerRadius = boundingRadius;}
357 G4double angle = element->
GetAngle();
358 if (samplerInfo->startElement && samplerInfo->finishElement)
360 const auto startElement = samplerInfo->startElement;
361 const auto finishElement = samplerInfo->finishElement;
362 G4ThreeVector connectingVector = finishElement->
GetReferencePositionEnd() - startElement->GetReferencePositionStart();
363 G4double chordLength = connectingVector.mag();
365 G4ThreeVector directionFrameStart = G4ThreeVector(0,0,1).transform(*(startElement->GetReferenceRotationStart()));
366 G4ThreeVector directionFrameFinish = G4ThreeVector(0,0,1).transform(*(finishElement->GetReferenceRotationEnd()));
368 G4ThreeVector dChordFrameStart = connectingVector.unit() - directionFrameStart;
369 G4ThreeVector dChordFrameFinish = connectingVector.unit() - directionFrameFinish;
373 G4ThreeVector ipfnCSampler = G4ThreeVector(0,0,-1) + dChordFrameStart;
374 G4ThreeVector opfnCSampler = G4ThreeVector(0,0,1) - dChordFrameFinish;
382 samplerInfo->pdgSetID);
395 samplerInfo->pdgSetID);
403 samplerInfo->pdgSetID);
423 G4VPhysicalVolume* samplerWorld = GetWorld();
424 samplerWorldLV = samplerWorld->GetLogicalVolume();
427 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())