remage
Simulation framework for HPGe-based experiments
Loading...
Searching...
No Matches
RMGVertexConfinement.hh
1// Copyright (C) 2022 Luigi Pertoldi <https://orcid.org/0000-0002-0467-2571>
2//
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the GNU Lesser General Public License as published by the Free
5// Software Foundation, either version 3 of the License, or (at your option) any
6// later version.
7//
8// This program is distributed in the hope that it will be useful, but WITHOUT
9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11// details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program. If not, see <https://www.gnu.org/licenses/>.
15
16#ifndef _RMG_VERTEX_CONFINEMENT_HH_
17#define _RMG_VERTEX_CONFINEMENT_HH_
18
19#include <atomic>
20#include <chrono>
21#include <memory>
22#include <optional>
23#include <regex>
24#include <string>
25#include <vector>
26
27#include "G4AutoLock.hh"
28#include "G4GenericMessenger.hh"
29#include "G4RotationMatrix.hh"
30#include "G4ThreeVector.hh"
31
32#include "RMGVVertexGenerator.hh"
33
35class G4VSolid;
36
39class RMGVertexConfinement : public RMGVVertexGenerator {
40
41 public:
42
45 kSphere,
46 kCylinder,
47 kBox,
48 };
49
52 GeometricalSolidType solid_type = GeometricalSolidType::kBox;
53 G4ThreeVector volume_center = G4ThreeVector(0, 0, 0);
54 double sphere_inner_radius = 0;
55 double sphere_outer_radius = -1;
56 double cylinder_inner_radius = 0;
57 double cylinder_outer_radius = -1;
58 double cylinder_height = -1;
59 double cylinder_starting_angle = 0;
60 double cylinder_spanning_angle = CLHEP::twopi;
61 double box_x_length = -1;
62 double box_y_length = -1;
63 double box_z_length = -1;
64 };
65
76 enum class SamplingMode {
77 kIntersectPhysicalWithGeometrical,
78 kUnionAll,
79 kSubtractGeometrical,
80 };
81
84 enum class VolumeType {
85 kPhysical,
86 kGeometrical,
87 kUnset,
88 };
89
115
126
129
136 double mean = 0;
137
143 double sigma = 0;
144
150 double range_lo = 0;
151
157 double range_hi = 0;
158
172 [[nodiscard]] double Sample() const;
173
182 void Validate() const;
183 };
184
185 RMGVertexConfinement();
186
187 void BeginOfRunAction(const G4Run* run) override;
188 void EndOfRunAction(const G4Run* run) override;
189
192 bool GenerateVertex(G4ThreeVector& v) override;
193
203 void AddPhysicalVolumeNameRegex(std::string name, std::string copy_nr = ".*");
204
205 void AddGeometricalVolume(GenericGeometricalSolidData& data) {
206 fGeomVolumeData.emplace_back(data);
207 }
208 void Reset();
209
210 void SetSamplingMode(SamplingMode mode) { fSamplingMode = mode; }
211 void SetFirstSamplingVolumeType(VolumeType type) { fFirstSamplingVolumeType = type; }
212 void SetWeightByMass(bool mode) { fWeightByMass = mode; }
213 void SetWeightByMassIsotope(int z, int n) {
214 fWeightByMass = true;
215 fWeightByMassIsotopeZ = z;
216 fWeightByMassIsotopeN = n;
217 }
218
219 std::vector<GenericGeometricalSolidData>& GetGeometricalSolidDataList() {
220 return fGeomVolumeData;
221 }
222
233 struct SampleableObject {
234
235 SampleableObject() = default;
236 SampleableObject(const SampleableObject&) = default;
237
249 SampleableObject(
250 G4VPhysicalVolume* physvol,
251 G4RotationMatrix rot,
252 G4ThreeVector trans,
253 G4VSolid* solid,
254 bool is_native_sampleable = false,
255 bool on_surface = false
256 );
257
258 // NOTE: G4 volume/solid pointers should be fully owned by G4, avoid trying to delete them
259 ~SampleableObject() = default;
260
266 [[nodiscard]] bool IsInside(const G4ThreeVector& vertex) const;
267
285 [[nodiscard]] bool Sample(
286 G4ThreeVector& vertex,
287 size_t max_attempts,
288 bool force_containment_check,
289 size_t& n_trials
290 ) const;
291
305 [[nodiscard]] bool GenerateSurfacePoint(
306 G4ThreeVector& vertex,
307 size_t max_attempts,
308 size_t max_intersections
309 ) const;
310
311 // methods for the generic surface sampling
326 [[nodiscard]] std::vector<G4ThreeVector> GetIntersections(
327 G4ThreeVector start,
328 G4ThreeVector dir
329 ) const;
330
341 void GetDirection(G4ThreeVector& dir, G4ThreeVector& pos) const;
342
354 void ApplyDepthProfile(G4ThreeVector& local_vertex, const G4VSolid* solid) const;
355
356 void RecalcMass(int z, int n);
357
358 G4VPhysicalVolume* physical_volume = nullptr;
359 G4VSolid* sampling_solid = nullptr;
360 G4RotationMatrix rotation;
361 G4ThreeVector translation;
362
363 double volume = -1;
364 double mass = -1;
365 double surface = -1;
366
367 bool surface_sample = false;
368 bool native_sample = false;
369 size_t max_num_intersections = 0;
370
377 };
378
382 struct SampleableObjectCollection {
383
384 SampleableObjectCollection() = default;
385 ~SampleableObjectCollection() { data.clear(); }
386
390 [[nodiscard]] const SampleableObject& SurfaceWeightedRand() const;
391
396 [[nodiscard]] const SampleableObject& VolumeWeightedRand(bool weight_by_mass) const;
397 [[nodiscard]] bool IsInside(const G4ThreeVector& vertex) const;
398
399 // emulate @c std::vector
400 [[nodiscard]] size_t size() const { return data.size(); }
401 SampleableObject& at(size_t i) { return data.at(i); }
402 template<typename... Args> void emplace_back(Args&&... args);
403 [[nodiscard]] bool empty() const { return data.empty(); }
404 SampleableObject& back() { return data.back(); }
405 void clear() {
406 data.clear();
407 total_volume = 0;
408 total_mass = 0;
409 total_surface = 0;
410 }
411 void insert(SampleableObjectCollection& other) {
412 data.reserve(this->size() + other.size());
413 for (size_t i = 0; i < other.size(); ++i) this->emplace_back(other.at(i));
414 this->total_volume += other.total_volume;
415 this->total_mass += other.total_mass;
416 this->total_surface += other.total_surface;
417 }
418
419 void recalc_total(bool weigh_by_mass, int mass_isotope_z, int mass_istotope_n);
420
421 std::vector<SampleableObject> data;
422 double total_volume = 0;
423 double total_mass = 0;
424 double total_surface = 0;
425 };
426
427 private:
428
429 void InitializePhysicalVolumes();
430 void InitializeGeometricalVolumes(bool use_excluded_volumes);
431 bool ActualGenerateVertex(G4ThreeVector& v);
432
433 std::vector<std::string> fPhysicalVolumeNameRegexes;
434 std::vector<std::string> fPhysicalVolumeCopyNrRegexes;
435
436 std::vector<GenericGeometricalSolidData> fGeomVolumeData;
437 std::vector<GenericGeometricalSolidData> fExcludedGeomVolumeData;
438
439 static G4Mutex fGeometryMutex;
440 // the final geometry data is shared between all threads and protected by fGeometryMutex.
441 // this is to prevent problems in G4SolidStore, which is apparently not safe to mutate from
442 // multiple threads. note that some operations that just appear to read static data might also
443 // mutate the G4SolidStore temporarily, e.g. G4SubstractionSolid::GetCubicVolume()
444 static SampleableObjectCollection fPhysicalVolumes;
445 static SampleableObjectCollection fGeomVolumeSolids;
446 static SampleableObjectCollection fExcludedGeomVolumeSolids;
447 // cached merged collection used by the default kUnionAll mode.
448 static SampleableObjectCollection fUnionVolumes;
449
450 // solids allocated by this class (bounding boxes and geometrical sampling shapes). They are
451 // registered in the G4SolidStore and must be de-registered and freed on Reset().
452 static std::vector<G4VSolid*> fOwnedSolids;
453
454 static std::atomic<bool> fVolumesInitialized;
455
456 SamplingMode fSamplingMode = SamplingMode::kUnionAll;
457 VolumeType fFirstSamplingVolumeType = VolumeType::kUnset;
458 bool fWeightByMass = false;
459 int fWeightByMassIsotopeZ = 0;
460 int fWeightByMassIsotopeN = 0;
461
462 bool fOnSurface = false;
463 bool fForceContainmentCheck = false;
464 bool fLastSolidExcluded = false;
465 size_t fSurfaceSampleMaxIntersections = 0;
466
468 DepthProfile fDepthProfile = {};
469
470 // counters used for the current run.
471 size_t fTrials = 0;
472 std::chrono::nanoseconds fVertexGenerationTime{};
473
474 std::vector<std::unique_ptr<G4GenericMessenger>> fMessengers;
475 void SetSamplingModeString(std::string mode);
476 void SetFirstSamplingVolumeTypeString(std::string type);
477
478 void AddGeometricalVolumeString(std::string solid);
479 void AddExcludedGeometricalVolumeString(std::string solid);
480
482 std::optional<GeometricalSolidType> solid_type = std::nullopt
483 );
484
485 // FIXME: there is no easy way to set the position vector all at once with
486 // G4GenericMessenger. Only ::DeclarePropertyWithUnit() accepts vectors and
487 // one cannot call functions with more than 2 arguments (3 coordinated + 1
488 // units needed). Ugly!
489 void SetGeomVolumeCenter(const G4ThreeVector& v) { this->SafeBack().volume_center = v; }
490 void SetGeomVolumeCenterX(double x) { this->SafeBack().volume_center.setX(x); }
491 void SetGeomVolumeCenterY(double y) { this->SafeBack().volume_center.setY(y); }
492 void SetGeomVolumeCenterZ(double z) { this->SafeBack().volume_center.setZ(z); }
493
494 void SetGeomSphereInnerRadius(double r) {
495 this->SafeBack(GeometricalSolidType::kSphere).sphere_inner_radius = r;
496 }
497 void SetGeomSphereOuterRadius(double r) {
498 this->SafeBack(GeometricalSolidType::kSphere).sphere_outer_radius = r;
499 }
500
501 void SetGeomCylinderInnerRadius(double r) {
502 this->SafeBack(GeometricalSolidType::kCylinder).cylinder_inner_radius = r;
503 }
504 void SetGeomCylinderOuterRadius(double r) {
505 this->SafeBack(GeometricalSolidType::kCylinder).cylinder_outer_radius = r;
506 }
507 void SetGeomCylinderHeight(double h) {
508 this->SafeBack(GeometricalSolidType::kCylinder).cylinder_height = h;
509 }
510 void SetGeomCylinderStartingAngle(double a) {
511 this->SafeBack(GeometricalSolidType::kCylinder).cylinder_starting_angle = a;
512 }
513 void SetGeomCylinderSpanningAngle(double a) {
514 this->SafeBack(GeometricalSolidType::kCylinder).cylinder_spanning_angle = a;
515 }
516
517 void SetGeomBoxXLength(double x) {
518 this->SafeBack(GeometricalSolidType::kBox).box_x_length = x;
519 }
520 void SetGeomBoxYLength(double y) {
521 this->SafeBack(GeometricalSolidType::kBox).box_y_length = y;
522 }
523 void SetGeomBoxZLength(double z) {
524 this->SafeBack(GeometricalSolidType::kBox).box_z_length = z;
525 }
526
527 void DefineCommands();
528
529 void SetDepthProfileTypeString(std::string type);
530 void SetDepthProfileMean(double mean) { fDepthProfile.mean = mean; }
531 void SetDepthProfileSigma(double sigma) { fDepthProfile.sigma = sigma; }
532 void SetDepthProfileRangeLo(double lo) { fDepthProfile.range_lo = lo; }
533 void SetDepthProfileRangeHi(double hi) { fDepthProfile.range_hi = hi; }
534};
535
536#endif
537
538// vim: tabstop=2 shiftwidth=2 expandtab
VolumeType
Types of volume to sample, either physical (a volume in the geometry), geometrical (defined by the us...
Definition RMGVertexConfinement.hh:84
GeometricalSolidType
Different types of geometrical (user) defined solids.
Definition RMGVertexConfinement.hh:44
void AddPhysicalVolumeNameRegex(std::string name, std::string copy_nr=".*")
Definition RMGVertexConfinement.cc:1190
SamplingMode
Strategy for sampling physical and geometrical volumes.
Definition RMGVertexConfinement.hh:76
bool GenerateVertex(G4ThreeVector &v) override
Generate the actual vertex, according to the sampling mode (see RMGVertexConfinement::SamplingMode).
Definition RMGVertexConfinement.cc:915
Depth profile for displacing surface-sampled vertices into the material.
Definition RMGVertexConfinement.hh:114
double Sample() const
Sample a depth value from the configured distribution.
Definition RMGVertexConfinement.cc:110
void Validate() const
Validate the configured parameters, aborting with a fatal error on bad input.
Definition RMGVertexConfinement.cc:152
Type type
Distribution type. Defaults to kNone (no displacement).
Definition RMGVertexConfinement.hh:128
double sigma
Standard deviation for the truncated-Gaussian distribution.
Definition RMGVertexConfinement.hh:143
Type
Distribution type for the depth profile.
Definition RMGVertexConfinement.hh:120
@ kNone
No depth profile: vertex remains on the surface.
Definition RMGVertexConfinement.hh:121
@ kUniform
Uniform distribution over [range_lo, range_hi].
Definition RMGVertexConfinement.hh:124
@ kExponential
Exponential distribution parametrised by mean.
Definition RMGVertexConfinement.hh:122
@ kTruncatedGaussian
Gaussian distribution truncated to [range_lo, range_hi].
Definition RMGVertexConfinement.hh:123
double range_hi
Upper bound of the depth range for uniform and truncated-Gaussian distributions.
Definition RMGVertexConfinement.hh:157
double mean
Mean depth for the exponential and truncated-Gaussian distributions.
Definition RMGVertexConfinement.hh:136
double range_lo
Lower bound of the depth range for uniform and truncated-Gaussian distributions.
Definition RMGVertexConfinement.hh:150
Information about the geometrical (user) defined solids.
Definition RMGVertexConfinement.hh:51
A collection of SampleableObject objects. It can be used to sample from by selecting a volume weighte...
Definition RMGVertexConfinement.hh:382
const SampleableObject & SurfaceWeightedRand() const
Select a SampleableObject from the collection, weighted by surface area.
Definition RMGVertexConfinement.cc:195
const SampleableObject & VolumeWeightedRand(bool weight_by_mass) const
Select a SampleableObject from the collection, weighted by volume.
Definition RMGVertexConfinement.cc:219
Definition RMGVertexConfinement.hh:233
bool Sample(G4ThreeVector &vertex, size_t max_attempts, bool force_containment_check, size_t &n_trials) const
Generate a sample from the solid.
Definition RMGVertexConfinement.cc:413
void GetDirection(G4ThreeVector &dir, G4ThreeVector &pos) const
Get a position and direction for the generic surface sampling algorithm.
Definition RMGVertexConfinement.cc:317
bool GenerateSurfacePoint(G4ThreeVector &vertex, size_t max_attempts, size_t max_intersections) const
Generate a point on the surface of the solid.
Definition RMGVertexConfinement.cc:356
std::vector< G4ThreeVector > GetIntersections(G4ThreeVector start, G4ThreeVector dir) const
Get the number of intersections between the solid and the line starting at start with direction dir.
Definition RMGVertexConfinement.cc:263
DepthProfile depth_profile
Depth profile applied when displacing vertices inward from the surface.
Definition RMGVertexConfinement.hh:376
void ApplyDepthProfile(G4ThreeVector &local_vertex, const G4VSolid *solid) const
Displace a surface point inward according to depth_profile.
Definition RMGVertexConfinement.cc:178
bool IsInside(const G4ThreeVector &vertex) const
Check if the vertex is inside the solid.
Definition RMGVertexConfinement.cc:249