DLG4::VolumeBuilders
A fluent interface for Geant4 geometry definition.
Loading...
Searching...
No Matches
DLG4Units.hh
Go to the documentation of this file.
1// DLG4Units.hh
2// Created by D.S. Leonard on 5/10/26.
3//
4#ifndef DLG4MODUSIM_DLG4UNITS_HH
5#define DLG4MODUSIM_DLG4UNITS_HH
6#include "G4Types.hh"
7#include "G4ExceptionSeverity.hh" // For FatalException, JustWarning, etc.
8#include "globals.hh" // For G4Exception and G4double
9#include <CLHEP/Units/SystemOfUnits.h>
10#include <G4ThreeVector.hh>
11#include <optional>
12//#include <VolumeBuilderConfigs.hh>
13
14
118// TODO, doxygen all this.
119// TODO document usage like this
120// if (!(context->GetExtraOpt("z_gap_mm") >> context->z_gap.InUnits(VB::Length::mm))) {
121
122namespace VB = DLG4::VolumeBuilders;
123namespace DLG4::Units {
124 template<typename T>
125 class Unit;
126 class Length;
127 class Mass;
128 class Volume;
129 class Density;
130 class Unit3Vec;
133 class ThreeVecDimensioner;
134
135
136 template <typename T>
137 inline G4double global_default_unit = 1.0;
138
139 // Set the default value for the global default unit.
140 // (The default for the default for the default).
141 template <> inline G4double global_default_unit<Units::Length> = CLHEP::mm;
142 template <> inline G4double global_default_unit<Units::Mass> = CLHEP::g;
143 template <> inline G4double global_default_unit<Units::Volume> = CLHEP::mL;
144
146 struct UnitTag {
147 };
148
153 template<class T>
154 class Unit : public UnitTag {
155 using Derived = T;
156 // --- THE ACCESS PORT (The Translator) ---
157 public:
160 G4double scale;
161
162 // Still non-copyable for safety
165
166 // This is the "magic" for z_gap.Native = 10
167 void operator=(G4double val) { parent.NativeValue_ = val * scale; }
168
169 // Extraction and implicit conversion
170 G4double operator()() const { return parent.GetScaled(1.0 / scale); }
171 operator G4double() const { return (*this)(); }
172
173 // Stream support
174 friend std::istream& operator>>(std::istream& is, const PropertySetter& ap) {
175 G4double val;
176 if (is >> val) ap.parent.NativeValue_ = val * ap.scale;
177 return is;
178 }
179 };
180
181 // --- THE PROPERTY OBJECTS ---
183 PropertySetter InUnits(const Unit<T>& u) { return {*this, u.NativeValue()}; }
184 PropertySetter InDefaultUnits() { return {*this, GetGlobalDefault().NativeValue()}; }
185
186 // Const factory: Returns a raw double (Read-Only)
187 G4double InUnits(const Unit<T>& u) const { return GetScaled(1.0 / u.NativeValue()); }
188 G4double InDefaultUnits() const { return InUnits(GetGlobalDefault()); }
189
190 protected:
191 // Required for internal static unit definitions (mm, cm, etc)
192 [[nodiscard]] G4double NativeValue() const { return GetScaled(1.0); }
193 explicit operator G4double() const { return GetScaled(1.0); }
194
195 public:
196 static inline T native{1.0};
197 static T FromNative(G4double);
198
199 virtual ~Unit() = default;
200
201 Unit(const Unit &other)
202 : Native{*this, 1.0}, NativeValue_(other.NativeValue_) {
203 }
204
205 Unit &operator=(const Unit &other) {
206 if (this != &other) {
207 this->NativeValue_ = other.NativeValue_;
208 }
209 return *this;
210 }
211
212 Unit() : Native{*this, 1.0}, NativeValue_(std::nullopt) {}
213
214 explicit Unit(double f, Derived u)
215 : Native{*this, 1.0}, NativeValue_(f * u.NativeValue()) {
216 }
217
218 private:
219 virtual G4double GetScaled(G4double scalar) const {
220 if (NativeValue_.has_value()) {
221 if (scalar > 0.0) {
222 return NativeValue_.value() * scalar;
223 } else {
224 G4Exception("Unit::GetScaled", "InvalidScale", FatalException,
225 "\n Attempted to scale a Measure by a negative Unit\n");
226 exit(1);
227 }
228 } else {
229 G4Exception("Unit::GetScaled", "InvalidScale", FatalException,
230 "\n Attempted to read a Unit (or measure) before setting it;\n");
231 exit(1);
232 }
233 }
234
235 virtual void ScaleSet(G4double value, G4double scale) {
236 NativeValue_ = value * scale;
237 };
238
239 protected:
240 // The public can only make units from existing units, not doubles!!
241 explicit Unit<T>(G4double f)
242 : Native{*this, 1.0}, NativeValue_(f) {
243 };
244
246
247 std::optional<G4double> NativeValue_;
248 };
249
250
251 // Delete all those duplicate FromNative blocks and use this:
252 template<typename T>
253 inline T DLG4::Units::Unit<T>::FromNative(G4double native_value) {
254 // This calls the protected explicit Unit(double) constructor
255 return T(native_value);
256 }
257
258
259 //#########################################################################//
260 //*********************************Length***************************#
261 //#########################################################################//
262 class Length : public Unit<Length> {
263 friend Unit<Length>;
264 private:
265 explicit Length(double Native)
266 : Unit(Native) {
267 }
268
269 public:
270 explicit Length(double raw, Length u)
271 : Unit<Length>(raw, u) {
272 }
273
275
276 // Deeclare essentially named singleton factories:
277 static const Length fermi;
278 static const Length angstrom;
279 static const Length nm;
280 static const Length pm;
281 static const Length um;
282 static const Length micron;
283 static const Length mm;
284 static const Length cm;
285 static const Length dm;
286 static const Length m;
287 static const Length km;
288
289 // Imperial
290 static const Length mil;
291 static const Length inch;
292 static const Length foot;
293 static const Length feet;
294
295 };
296
297
298 template <typename T>
299 inline T Unit<T>::GetGlobalDefault() { return T(global_default_unit<T>); }
300
301
302 //#########################################################################//
303 // ******************Mass Class
304 //#########################################################################//
305 class Mass : public Unit<Mass> {
306 friend Unit<Mass>;
307 private:
308 explicit Mass(double Native)
309 : Unit(Native) {
310 }
311
312 public:
314
315 explicit Mass(double raw, Mass u)
316 : Unit(raw, u) {
317 }
318
319 static const Mass g, mg, kg;
320 };
321
322 //#########################################################################//
323 // ******************Volume Class
324 //#########################################################################//
325 class Volume : public Unit<Volume> {
326 friend Unit<Volume>;
327 private:
328 explicit Volume(double Native)
329 : Unit(Native) {
330 }
331
332 public:
333 Volume() { NativeValue_ = CLHEP::cm3; };
334
335 explicit Volume(double raw, Volume u)
336 : Unit(raw, u) {
337 }
338
339 static const Volume cm3, mL, L;
340 };
341
342
343 //#########################################################################//
344 // ******************Density Class
345 //#########################################################################//
346 class Density : public Unit<Density> {
347 friend Unit<Density>;
348 private:
349 explicit Density(double Native)
350 : Unit(Native) {
351 }
352
353 public:
355
356 explicit Density(double raw, Density u)
357 : Unit(raw, u) {
358 }
359
360 static const Density g_per_cm3;
361 static const Density g_per_L; // Same as mg_cm3
362 static const Density mg_per_cm3;
363 };
364
365
368 return x;
369 }
370
371
372 // Definitions
373 inline const Length Length::fermi{CLHEP::fermi};
374 inline const Length Length::angstrom{CLHEP::angstrom};
375 inline const Length Length::nm{CLHEP::nanometer};
376 inline const Length Length::pm{1e-9 * CLHEP::mm};
377 inline const Length Length::um{CLHEP::micrometer};
378 inline const Length Length::micron{CLHEP::micrometer}; // Safe alias to um
379 inline const Length Length::mm{CLHEP::mm};
380 inline const Length Length::cm{CLHEP::cm};
381 inline const Length Length::m{CLHEP::m};
382 inline const Length Length::km{CLHEP::kilometer};
383
384 // Imperial Logic: 1 inch = 25.4 mm
385 inline const Length Length::mil{0.0254}; // 1/1000 of an inch
386 inline const Length Length::inch{25.4}; // CLHEP::inch
387 inline const Length Length::foot{304.8}; // 12 inches
388 inline const Length Length::feet{304.8}; // 12 inches
389
390 inline const Mass Mass::mg{CLHEP::mg};
391 inline const Mass Mass::g{CLHEP::g};
392 inline const Mass Mass::kg{CLHEP::kg};
393
394 inline const Volume Volume::mL{CLHEP::mL};
395 inline const Volume Volume::cm3{CLHEP::mL};
396 inline const Volume Volume::L{CLHEP::L};
397
398 inline const Density Density::g_per_cm3{CLHEP::g / CLHEP::cm3};
399 inline const Density Density::g_per_L{CLHEP::g / CLHEP::liter};
400 inline const Density Density::mg_per_cm3{CLHEP::mg / CLHEP::cm3};
401
405 template<class T>
406 struct UnitOrValue {
407 double val;
408 UnitOrValue(const Unit<T> &u) : val(u.Native()) {}
409 // Catch any numeric scalar (int, float, etc.)
410 template<typename Scalar, typename = std::enable_if_t<std::is_arithmetic_v<Scalar>>>
411 UnitOrValue(Scalar d) : val(static_cast<double>(d)) {}
412 };
413
414
415 // Mutliplication and division of scalar and unit create Unit.
416 // Which one is the Unit?
417 template<typename T, typename U>
418 using ResultType = std::conditional_t<std::is_base_of_v<UnitTag, T>, T, U>;
419
420 // --- Multiplication: (Unit * Scalar) or (Scalar * Unit) ---
421 template<typename T, typename U,
422 typename = std::enable_if_t<std::is_base_of_v<UnitTag, T> != std::is_base_of_v<UnitTag, U>> >
423 inline auto operator*(const T &a, const U &b) {
424 using R = ResultType<T, U>;
425 return R(UnitOrValue<T>(a).val * UnitOrValue<U>(b).val, R::native);
426 }
427
428 // --- Division: (Unit / Scalar) ---
429 template<typename T, typename U,
430 typename = std::enable_if_t<std::is_base_of_v<UnitTag, T> && !std::is_base_of_v<UnitTag, U>> >
431 inline auto operator/(const T &a, const U &b) {
432 // T is the Unit, U is the Scalar
433 return T(UnitOrValue<T>(a).val / static_cast<double>(b), T::native);
434 }
435
436 // --- Addition: T + T (where T inherits from UnitTag) ---
437 template <typename T, typename = std::enable_if_t<std::is_base_of_v<UnitTag, T>>>
438 inline T operator+(const T& a, const T& b) {
439 // Uses the protected constructor/FromNative to return a new dimensioned object
440 return T::FromNative(a.Native() + b.Native());
441 }
442
443 // --- Subtraction: T - T (where T inherits from UnitTag) ---
444 template <typename T, typename = std::enable_if_t<std::is_base_of_v<UnitTag, T>>>
445 inline T operator-(const T& a, const T& b) {
446 return T::FromNative(a.Native() - b.Native());
447 }
448
452 class Unit3Vec {
453 public:
454 Unit3Vec() = default;
455
456 Unit3Vec(const Unit3Vec &other)
457 : NativeVec_(other.NativeVec_),
459 }
460
461 // Assignment Operator (for completeness)
462
463 Unit3Vec &operator=(const Unit3Vec &other) {
464 if (this != &other) {
465 NativeVec_ = other.NativeVec_;
467 }
468 return *this;
469 }
470
471 Unit3Vec(double x, double y, double z, const Length &u) {
472 NativeVec_ = G4ThreeVector(x, y, z) * u.Native;
473 }
474
475 Unit3Vec(const G4ThreeVector &v, const Length &u) {
476 NativeVec_ = v * u.Native;
477 }
478
479 Unit3Vec FromNative(const G4ThreeVector &v) {
480 return Unit3Vec(v, Length::native);
481 }
482
483 // components as Length types...
484 Length x() const { return Length::FromNative(Native().x()); }
485 Length y() const { return Length::FromNative(Native().y()); }
486 Length z() const { return Length::FromNative(Native().z()); }
487
488 void x(const Length& val) { EnsureInternalVec().setX(val.Native); }
489 void y(const Length& val) { EnsureInternalVec().setY(val.Native); }
490 void z(const Length& val) { EnsureInternalVec().setZ(val.Native); }
491
492 Unit3Vec(const Length& x, const Length& y, const Length& z) {
493 NativeVec_ = G4ThreeVector(x.Native, y.Native, z.Native);
494 }
495 // Extraction back to G4ThreeVector
496 G4ThreeVector InUnits() const { return InUnits(default_length_); }
497
498 G4ThreeVector InUnits(const Length &u) const {
499 if (!NativeVec_.has_value()) {
500 G4Exception("Unit3Vec::InUnits", "Uninitialized", FatalException,
501 "Attempted to read Unit3Vec before setting it.");
502 }
503 return (*NativeVec_) / u.Native;
504 }
505
506 // The "Geant4 Internal" accessor
507 G4ThreeVector Native() const {
508 if (!NativeVec_.has_value()) {
509 G4Exception("Unit3Vec::GetRaw", "Uninitialized", FatalException,
510 "Attempted to read Unit3Vec before setting it.");
511 }
512 return *NativeVec_;
513 }
514
515 protected:
516 std::optional<G4ThreeVector> NativeVec_;
518 private:
519 // Helper to ensure the optional is initialized before we write to it
520 G4ThreeVector& EnsureInternalVec() {
521 if (!NativeVec_.has_value()) {
522 NativeVec_ = G4ThreeVector(0, 0, 0);
523 }
524 return *NativeVec_;
525 }
526 };
527
528 inline Unit3Vec operator*(const G4ThreeVector& v, const Length& u) {
529 return Unit3Vec(v, u);
530 }
531
532 inline Unit3Vec operator*(const Unit3Vec& v, G4double scalar) {
533 // We use the FromNative-style construction to wrap the scaled vector
534 return Unit3Vec(v.Native() * scalar, Length::native);
535 }
536
537 inline Unit3Vec operator*(G4double scalar, const Unit3Vec& v) {
538 return v * scalar; // Just reuse the one above
539 }
540
541 inline Unit3Vec operator/(const Unit3Vec& v, G4double scalar) {
542 return Unit3Vec(v.Native() / scalar, Length::native);
543 }
544
545 using UnitlessG4Transform3D = G4Transform3D;
546 using Length3Vec = Unit3Vec;
547
552 template <typename T>
553 inline void SetGlobalDefaultUnit(T unit) {
554 // Compile-time gate
555 static_assert(std::is_base_of_v<DLG4::Units::UnitTag, T>,
556 "\n\n ERROR: SetGlobalDefaultUnit only accepts DLG4Unit types! \n"
557 " You tried to pass a type that does not inherit from UnitTag.\n");
558 DLG4::Units::global_default_unit<T> = unit.Native;
559 }
560
561
562
563}
564
565#endif //HPGESIM_DLG4UNITS_HH
static const Density g_per_cm3
Definition DLG4Units.hh:360
Density(double raw, Density u)
Definition DLG4Units.hh:356
static const Density mg_per_cm3
Definition DLG4Units.hh:362
static const Density g_per_L
Definition DLG4Units.hh:361
static const Length nm
Definition DLG4Units.hh:279
static const Length feet
Definition DLG4Units.hh:293
static const Length mil
Definition DLG4Units.hh:290
static const Length fermi
Definition DLG4Units.hh:277
Length(double raw, Length u)
Definition DLG4Units.hh:270
static const Length um
Definition DLG4Units.hh:281
static const Length mm
Definition DLG4Units.hh:283
static const Length dm
Definition DLG4Units.hh:285
static const Length m
Definition DLG4Units.hh:286
static const Length angstrom
Definition DLG4Units.hh:278
static const Length foot
Definition DLG4Units.hh:292
static const Length inch
Definition DLG4Units.hh:291
static const Length km
Definition DLG4Units.hh:287
static const Length pm
Definition DLG4Units.hh:280
static const Length micron
Definition DLG4Units.hh:282
static const Length cm
Definition DLG4Units.hh:284
static const Mass mg
Definition DLG4Units.hh:319
static const Mass kg
Definition DLG4Units.hh:319
Mass(double raw, Mass u)
Definition DLG4Units.hh:315
static const Mass g
Definition DLG4Units.hh:319
A 3 vector that is scalable with/to Units.
Definition DLG4Units.hh:452
Unit3Vec(const Length &x, const Length &y, const Length &z)
Definition DLG4Units.hh:492
Length x() const
Definition DLG4Units.hh:484
void y(const Length &val)
Definition DLG4Units.hh:489
G4ThreeVector InUnits(const Length &u) const
Definition DLG4Units.hh:498
Unit3Vec FromNative(const G4ThreeVector &v)
Definition DLG4Units.hh:479
Unit3Vec(const G4ThreeVector &v, const Length &u)
Definition DLG4Units.hh:475
Length y() const
Definition DLG4Units.hh:485
Length z() const
Definition DLG4Units.hh:486
void x(const Length &val)
Definition DLG4Units.hh:488
Unit3Vec(const Unit3Vec &other)
Definition DLG4Units.hh:456
Unit3Vec & operator=(const Unit3Vec &other)
Definition DLG4Units.hh:463
std::optional< G4ThreeVector > NativeVec_
Definition DLG4Units.hh:516
Unit3Vec(double x, double y, double z, const Length &u)
Definition DLG4Units.hh:471
G4ThreeVector InUnits() const
Definition DLG4Units.hh:496
void z(const Length &val)
Definition DLG4Units.hh:490
G4ThreeVector Native() const
Definition DLG4Units.hh:507
CRTP base methods for Unit classes.
Definition DLG4Units.hh:154
static T FromNative(G4double)
Definition DLG4Units.hh:253
std::optional< G4double > NativeValue_
Definition DLG4Units.hh:247
PropertySetter InUnits(const Unit< T > &u)
Definition DLG4Units.hh:183
G4double NativeValue() const
Definition DLG4Units.hh:192
G4double InDefaultUnits() const
Definition DLG4Units.hh:188
Unit(const Unit &other)
Definition DLG4Units.hh:201
Unit(double f, Derived u)
Definition DLG4Units.hh:214
static Derived GetGlobalDefault()
Definition DLG4Units.hh:299
virtual ~Unit()=default
PropertySetter Native
Definition DLG4Units.hh:182
PropertySetter InDefaultUnits()
Definition DLG4Units.hh:184
Unit & operator=(const Unit &other)
Definition DLG4Units.hh:205
G4double InUnits(const Unit< T > &u) const
Definition DLG4Units.hh:187
static const Volume L
Definition DLG4Units.hh:339
static const Volume cm3
Definition DLG4Units.hh:339
Volume(double raw, Volume u)
Definition DLG4Units.hh:335
static const Volume mL
Definition DLG4Units.hh:339
void SetGlobalDefaultUnit(T unit)
Set the default unit for all VolumeBuilder methods.
Definition DLG4Units.hh:553
Typesafe units!! No accidental mixing values and units.
Definition DLG4Units.hh:123
T operator+(const T &a, const T &b)
Definition DLG4Units.hh:438
G4double global_default_unit
Definition DLG4Units.hh:137
T operator-(const T &a, const T &b)
Definition DLG4Units.hh:445
G4Transform3D UnitlessG4Transform3D
Definition DLG4Units.hh:545
std::conditional_t< std::is_base_of_v< UnitTag, T >, T, U > ResultType
Definition DLG4Units.hh:418
auto operator*(const T &a, const U &b)
Definition DLG4Units.hh:423
Density operator/(Mass m, Volume v)
Definition DLG4Units.hh:366
DLG4::Units::Density Density
Type-erases unit or value to just a value.
Definition DLG4Units.hh:406
UnitOrValue(const Unit< T > &u)
Definition DLG4Units.hh:408
Tag type for inheritance.
Definition DLG4Units.hh:146
PropertySetter(const PropertySetter &)=delete
friend std::istream & operator>>(std::istream &is, const PropertySetter &ap)
Definition DLG4Units.hh:174
PropertySetter & operator=(const PropertySetter &)=delete