DLG4::VolumeBuilders
A fluent interface for Geant4 geometry definition.
Loading...
Searching...
No Matches
Classes | Namespaces | Typedefs | Functions | Variables
DLG4Units.hh File Reference
#include "G4Types.hh"
#include "G4ExceptionSeverity.hh"
#include "globals.hh"
#include <CLHEP/Units/SystemOfUnits.h>
#include <G4ThreeVector.hh>
#include <optional>
Include dependency graph for DLG4Units.hh:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  UnitTag
 
class  Unit< T >
 
struct  Unit< T >::PropertySetter
 
class  Length
 
class  Mass
 
class  Volume
 
class  Density
 
struct  UnitOrValue< T >
 
class  Unit3Vec
 

Namespaces

namespace  DLG4
 
namespace  DLG4::Units
 

Typedefs

using Length3Vec = Unit3Vec
 
template<typename T , typename U >
using ResultType = std::conditional_t< std::is_base_of_v< UnitTag, T >, T, U >
 
using UnitlessG4Transform3D = G4Transform3D
 

Functions

Density operator/ (Mass m, Volume v)
 
template<typename T , typename U , typename = std::enable_if_t<std::is_base_of_v<UnitTag, T> != std::is_base_of_v<UnitTag, U>>>
auto operator* (const T &a, const U &b)
 
template<typename T , typename U , typename = std::enable_if_t<std::is_base_of_v<UnitTag, T> && !std::is_base_of_v<UnitTag, U>>>
auto operator/ (const T &a, const U &b)
 
template<typename T , typename = std::enable_if_t<std::is_base_of_v<UnitTag, T>>>
operator+ (const T &a, const T &b)
 
template<typename T , typename = std::enable_if_t<std::is_base_of_v<UnitTag, T>>>
operator- (const T &a, const T &b)
 
Unit3Vec operator* (const G4ThreeVector &v, const Length &u)
 
Unit3Vec operator* (const Unit3Vec &v, G4double scalar)
 
Unit3Vec operator* (G4double scalar, const Unit3Vec &v)
 
Unit3Vec operator/ (const Unit3Vec &v, G4double scalar)
 
template<typename T >
void SetGlobalDefaultUnit (T unit)
 

Variables

template<typename T >
G4double global_default_unit = 1.0
 

Detailed Description

Typesafe units, for VolumeBuilders, Geant, ETC !! No accidental mixing values and units.

These are type-safe, non-implicitly convertible units/measures.

Motivation: In geant you cannot distinguish between a length and a unitless value. You can multiply mm * mm and treat that as a length. You can have the Native number 12 and treat that as a length. At some low level the computer only knows numbers but we can do better at the API and avoid these bugs. For positive values, a Unit Length is the same a Length. And in VB a Length is in fact(derives from) a Unit<Length> !! Unitless doubles are things that multiply lengths to describe other lengths in reference to that Unit<Length>. The result is also a Unit<Lenght>.

Usage:

Setting a Dimensioned length:

And this is how VB works... You can only consruct a Length from an existing Length and a double All of these are equivalent: cpp #include <DLG4Units.hh> using DLG4::Units; Length x = 5.0 * Length::mm; // No different from Geant syntax! but we used a typed unit (not double) !! Length x = 5.0 * Unit<Length>::mm; // Same thing. Length is a Unit<Length> Length x = Length( 5.0, Length::mm ); // constructor version.

----------—THE SAFETY NET ----------------—

cpp Length x = 5.0 * Length::mm; // No different from Geant syntax! but we used a typed unit (not double) !! Length y = (5.0 + x ) * Length::mm; // ******* THIS WON'T COMPILE!!! x is ALREADY A LENGHT!!!!******** Length y = x * Length::m; // Even this won't. Even if we later support this multiplication, it wouldn't assign to a Length.

Setting with Native/legacy/system values:

The one escape hatch is you can explicitly define a Length in system units in any of these explicit ways, ordered by preference: cpp Length x.Native = some_geant_double; Length x = some_geant_double * Length::native; Length x = Length::FromNative(some_geant_double); Length x = Length( some_geant_double, Length::native ); Where one_geant_double may have passed from other code as 5.0 * CLHEP::mm for instance, but it's still a double, not a DLG4::Units::Length until you make it one. So simply assinging to x.Native allows interfacing with legacy code. You almost CANNOT mess this up. If you try to assign legacy values (doubles) to x directly it will fail.

Retrieving Values in designated units:

cpp x = 5.0 * Length::mm; G4double y= x.InUnits(length::cm); y is now 0.5 cpp SetGlobalDefaultUnit(Length::mm); x = 5.0 * Length::mm; G4double y= x.InUnits(length::cm); G4double z= x.InDefaultUnits(); y is no 0.5 and z is 5.0

Retrieving/Passing Values as/to system units:

for the same x as above: cpp G4Box* box = new G4Box("MyBox", x.Native(), x.Native(), x.Native()); That's it, and again you almost cannot mess this up. If you try to pass x, it will fail. You'd have to intentionally use x.InUnits(...) to mess it up.

 ### Type safety:
 In VolumeBuilders you cannot pass a Length to a double parameter or a double to a Length parameter
 and a Units::Length::mm * Units::Lentgh::mm  is not a length (or presently even valid)
 And so you cannot accidentally multiply by the unit twice, OR forget to multiply and still
 assign to your target Length.  Ex:      10*length_obj  is assignable to a length, but length_obj*lenght_obj is not.
 moss/volume is presently assignable to a density.

 ### Avoiding CLHEP units
The .Native interface is necessary for interface withing shared variables and Geant calls,
but can also be abused, causing loss of type safety
```
 Length x.Native =  5.0 *  CLHEP::mm );  // this IS still valid and correct, but poor form now.

*******THIS COMPILES JUST FINE BUT IS WRONG********** Length y.Native = (5.0 + x.Native ) * CLHEP::mm; // And this is why using CLHEP will lead to bugs. ``` So just don't. Type .Native only when needed, and never use CLHEP units.

Vectors

The Unit3Vec (typdefed Length3Vec) behaves almost exactly the same. It provides standard G4ThreeVector through .Native , including calls like .Native().x() and it is typed and can be multiplied with Length objects. It has a few extra convenience constructors that are self explanitory.

#Usage in VolumeBuilders DLG4::VolumeBuilders takes units and values natively and distinguishes them, so no .Native use is needed except for direct geant calls. If you're working with raw numbers and default units of mm, you will just need to translate shared (context/global) values with .InDefaultUnits() after setting your the default for your local method. Shared variables can be of type Length and used in either VB or traditional code.

Definition in file DLG4Units.hh.