diff --git a/docs/_dependencies.md b/docs/_dependencies.md index ab74da2d..531a5363 100644 --- a/docs/_dependencies.md +++ b/docs/_dependencies.md @@ -1,7 +1,7 @@ ### Required dependencies - [CMake] 3.14 or higher -- [Geant4] 11.2.2 or higher +- [Geant4] 11.2.2 or higher, recommended 11.3 - Python3 interpreter ### Optional dependencies diff --git a/docs/conf.py.in b/docs/conf.py.in index 8bf716d9..831e4e6a 100644 --- a/docs/conf.py.in +++ b/docs/conf.py.in @@ -191,6 +191,8 @@ class Geant4MacroLexer(RegexLexer): (r"#.*$", Comment), # command name at start of line (r"^(/\S+)", Name.Function), + # geant4 alias + (r"\{\w+\}", Name.Variable), # any other text (r".", Text), ], diff --git a/docs/index.md b/docs/index.md index b0773b34..1149db98 100644 --- a/docs/index.md +++ b/docs/index.md @@ -34,6 +34,8 @@ commands, as well as the [remage macro interface](./rmg-commands). useful examples of complex experimental setup implementations. - [reboost](https://github.com/legend-exp/reboost): post-processing and analysis of remage output. +- [revertex](https://github.com/legend-exp/revertex): generator for input vertex + files for remage. ## Next steps diff --git a/docs/manual/analysis.md b/docs/manual/analysis.md index 60a1e278..e93899b2 100644 --- a/docs/manual/analysis.md +++ b/docs/manual/analysis.md @@ -5,6 +5,7 @@ :::{todo} - pointers to useful tools (reboost or pygama), once they are in place +- this needs considerable rework ::: diff --git a/docs/manual/confinement.md b/docs/manual/confinement.md index 60684cd6..7baec422 100644 --- a/docs/manual/confinement.md +++ b/docs/manual/confinement.md @@ -5,7 +5,6 @@ :::{todo} - examples -- tricks for vertex visualization ::: @@ -167,6 +166,13 @@ All sampling modes described above are available, with few notes/limitations: to sample the candidate surface vertices from must be set with . This is not optional. +- The value of + + should be set to the maximum number of times a line can intersect with the + surface of the volume. For example this is 2 for a sphere or cube. The + supplied value can be an overestimate. For slight overestimates this is comes + with a small but usually acceptable performance cost, however very large + values can significantly slow down the simulation. ## Vertices from external files @@ -174,6 +180,21 @@ For more complicated vertex confinement _remage_ supports the possibility to read in directly event primary positions from input files, as described in {ref}`manual-input-vertex`. +## Visualization + +You can use `legend-pygeom-vis` from the +[_legend-pygeom-tools_](https://github.com/legend-exp/legend-pygeom-tools) +package to visualize the simulated vertices your generated output files: + +```console +$ remage -o {RMG_OUTPUT_FILE} -g {GDML_FILE} -- ... +$ legend-pygeom-vis --add_points {RMG_OUTPUT_FILE} {GDML_FILE} +``` + +If you want to only show the vertices without the run-time overhead of actually +simulating any physics, you could consider switching to generating only +geantinos instead of your usual physics. + [^1]: J. A. Detwiler, R. Henning, R. A. Johnson and M. G. Marino, in IEEE Transactions on Nuclear Science, vol. 55, no. 4, pp. 2329-2333, Aug. 2008, diff --git a/docs/manual/generators.md b/docs/manual/generators.md index be20bf2c..9740154f 100644 --- a/docs/manual/generators.md +++ b/docs/manual/generators.md @@ -79,6 +79,8 @@ too (`/RMG/Generator/Select G4Gun`), a more basic alternative to the GPS. ::: +(manual-generators-decays)= + ## Generating nuclear decays A special case of the GPS can be used to generate radioactive decays. This is diff --git a/docs/manual/input.md b/docs/manual/input.md index e7dbd46a..03ffacf1 100644 --- a/docs/manual/input.md +++ b/docs/manual/input.md @@ -7,6 +7,11 @@ The python package [_revertex_](https://revertex.readthedocs.io/en/latest/) contains functionality for generating input files in the correct format. +If you generate the input files on your own without _revertex_, you have to +ensure that all data types and units are as defined here. The input reader does +not support dynamic type conversions, as you would expect for example for python +(i.e. float32 to float64)! + ::: (manual-input-vertex)= @@ -23,15 +28,24 @@ between the particles produced in the event. The input file can be selected with the macro command : -```remage +```geant4 /RMG/Generator/Confine FromFile /RMG/Generator/Confinement/FromFile/FileName {FILE} ``` The vertex input file should be an LH5 table with the following columns: -- `xloc`, `yloc`, `zloc` (with units): the global position of the particle - emission +``` +/ +└── vtx + └── vtx · table{xloc,yloc,zloc} + ├── xloc · array<1>{real} ── {'units': 'm'} + ├── yloc · array<1>{real} ── {'units': 'm'} + └── zloc · array<1>{real} ── {'units': 'm'} +``` + +- `xloc`, `yloc`, `zloc` (double, with units): the global position of the + particle emission (manual-input-kinetics)= @@ -46,7 +60,7 @@ format. ``` / └── vtx - └── kin · table{px,py,pz,ekin,g4_pid} + └── kin · table{ekin,g4_pid,n_part,px,py,pz} ├── ekin · array<1>{real} ── {'units': 'keV'} ├── g4_pid · array<1>{real} ├── px · array<1>{real} @@ -69,6 +83,23 @@ Each event starts with a row with `n_part` > 0. This specifies the count of rows that will be read in for this event. The following rows for this event are then required to set `n_part` to zero. +Once this input file is created it can be read into _remage_ as an event +generator using the macro command +: + +```geant4 +/RMG/Generator/Select FromFile +/RMG/Generator/FromFile/FileName {FILE_PATH} +``` + +Where `{FILE_PATH}` is the path to the input LH5 file. + +## Combining vertex and kinematics input + +Combining vertex and kinetics input is possible, even from the same file. +However, by design, each event can only have a single vertex, that will be +shared between all particles for an event from the kinetics file. + :::{warning} In a multithreaded run, the consistent iteration between vertex and kinetic @@ -78,13 +109,17 @@ statistically dependent on their location. ::: -Once this input file is created it can be read into _remage_ as an event -generator using the macro command -: +:::{tip} + +When you want to simulate kinetics from a file at a specific point instead of +confined to volume, you cannot use `/gps/position` to set the position. You can +however use ```geant4 -/RMG/Generator/Select FromFile -/RMG/Generator/FromFile/FileName {FILE_PATH} +/RMG/Vertex/Select FromPoint +/RMG/Vertex/FromPoint/Position {x} {y} {z} ``` -Where `{FILE_PATH}` is the path to the input LH5 file. +to set a constant position for all events. + +::: diff --git a/docs/manual/install.md b/docs/manual/install.md index 9f1d3ed1..3de8ffb1 100644 --- a/docs/manual/install.md +++ b/docs/manual/install.md @@ -2,8 +2,29 @@ # Installation -The recommended and fastest way of running _remage_ is through pre-built -software containers. Alternatively, the project can be built from source. +The recommended and fastest way of running _remage_ is through the pre-built +packages on conda-forge; alternatively through our pre-built software container +images. Alternatively, the project can be built from source. + +## Pre-built packages on conda-forge + +Stable releases are made available +[on conda-forge](https://anaconda.org/conda-forge/remage) for Linux and macOS +systems. To install the latest version of remage into your environment, use pixi +or conda: + +```console +$ pixi add remage +# or +$ conda install conda-forge::remage +``` + +:::{note} + +The conda-forge provided binaries do not support the ROOT output format, but +fully supports LH5/HDF5. + +::: ## Pre-built container images @@ -27,23 +48,6 @@ More information is available in {ref}`manual-containers`. If containers do not work for you, see the next section to learn how to build and install from source or from conda-forge. -## Pre-built packages on conda-forge - -Stable releases are made available -[on conda-forge](https://anaconda.org/conda-forge/remage) for Linux and macOS -systems. To install the latest version use: - -```console -$ conda install conda-forge::remage -``` - -:::{note} - -The conda-forge provided binaries does not support the ROOT output format, but -fully supports LH5/HDF5. - -::: - ## Building from source In preparation for the actual build, users are required to obtain some diff --git a/docs/manual/output.md b/docs/manual/output.md index 35c5d569..f842d61a 100644 --- a/docs/manual/output.md +++ b/docs/manual/output.md @@ -2,12 +2,6 @@ # Output -:::{todo} - -- isotope filtering - -::: - _remage_ mainly supports the [LH5](https://legend-exp.github.io/legend-data-format-specs/dev/hdf5) output format. This is the only format we can provide the convenient output reshaping @@ -172,7 +166,7 @@ occur. The macro commands and : -```remage +```geant4 /RMG/Output/Germanium/AddDetectorForEdepThreshold {UID} /RMG/Output/Germanium/EdepCutLow {ELOW} /RMG/Output/Germanium/EdepCutHigh {EHIGH} @@ -338,6 +332,8 @@ UID through the symbolic stored in the `/stp/__by_uid__` group. ## Data reduction methods +### Step (pre-)clustering + Often Geant4 takes steps much shorter than those that are meaningful in a HPGe or a scintillation detector. For example the typical dimension of charge clouds produced by interactions in germanium are 1-2 mm, so we are not sensitive to @@ -478,6 +474,55 @@ step length. ::: +### Output filtering + +Another strategy for output file size reduction is to filter out unwanted events +before even writing them to disk. In _remage_, these filters can be registered +as optional "output" schemes (do not get confused by the name, they will not +produce any additional output). + +#### Isotope filter + +The isotope filter is rather simple and can be enabled and used like this: + +```geant4 +/RMG/Output/ActivateOutputScheme IsotopeFilter +/RMG/Output/IsotopeFilter/AddIsotope {A} {Z} +``` + +Adds an isotope to the list. Only events that have a track with this isotope at +any point in time will be persisted. + +#### Particle filter + +The particle filter does not only affect the output files, but actually works on +the track level. Tracks matching the defined criteria will not be simulated. +With this, it not only reduces output file size, but also reduces the necessary +simulation run time. + +```geant4 +/RMG/Output/ActivateOutputScheme ParticleFilter +/RMG/Output/ParticleFilter/AddParticle {PDG_CODE} +``` + +Only particles with the PDG encoding `{PDG_CODE}` will be considered to be +filtered out (the command can be used multiple times). This can be chained with +additional constraints by physical volume in which the particle was created or +by creator process: + +- disables the + filtering in the specified volume; whereas + only + performs the filtering in this volume (the two commands cannot be combined). +- will only + keep the specified particles when they were created by the specified + process(es). + will not + simulate the particles when they were created by the specified process (the + two commands cannot be combined). + +Filtering by process and process can be combined. + ## LH5 output [LH5 (LEGEND-HDF5)](https://legend-exp.github.io/legend-data-format-specs/dev/hdf5/) diff --git a/docs/manual/physicslist.md b/docs/manual/physicslist.md index c2b7e6d7..7dc46576 100644 --- a/docs/manual/physicslist.md +++ b/docs/manual/physicslist.md @@ -1,31 +1,130 @@ # Physics list -:::{todo} +_remage_ uses a custom modular physics list built on top of Geant4’s standard +physics constructors. It mostly is based on the physics list implemented in +_MaGe_. It combines: + +- Configurable **electromagnetic physics** (standard, low-energy, Livermore, + Penelope, polarized) +- Optional **optical physics** (scintillation, Cherenkov, absorption, Rayleigh, + WLS) +- Configurable **hadronic physics lists**, including high-precision neutron + models +- **Radioactive decay** with extended control over decay time thresholds +- It contains Multiple **custom processes**: + - Inner Bremsstrahlung for beta decay + - Custom neutron capture with gamma cascades loaded from a Grabmayr file + - Custom wavelength-shifting (WLS) optical process +- Production cuts are managed explicitly per-region, including a dedicated + **SensitiveRegion**. + +This physics list is designed and adjusted for: + +- Low-energy nuclear and particle physics +- Underground or low-background experiments +- Precision gamma and beta spectroscopy +- Optical detector simulations +- Long-lived radioactive decay chains -- summary and peculiarities -- optional components and options (hadronic, leptonic, optical) -- production cuts and step limits -- custom WLS optical process -- custom Grabmayr gammacascades -- simulating radioactive decay chains +## Electromagnetic (Leptonic & EM Physics) -::: +The electromagnetic physics is configurable via the + command. -## optional components +Available options: -:::{todo} +- `None` → `G4EmStandardPhysics` +- `Option{1,2,3,4}` → `G4EmStandardPhysics_option{1,2,3,4}` +- `Penelope` → `G4EmPenelopePhysics` +- `Livermore` → `G4EmLivermorePhysics` (**default**) +- `LivermorePolarized` → `G4EmLivermorePolarizedPhysics` -- optional components and options (hadronic, leptonic, optical) +Some additional EM features from `G4EmExtraPhysics` are always enabled: -::: +- Synchrotron radiation +- Gamma-nuclear interactions +- Muon-nuclear interactions +- e± nuclear interactions -### hadronic physics options +## Optical Physics -:::{todo} +Optical physics is optional and can be enabled by +. -- hadronic physics options +This option enables the following physics processes: Boundary interactions, +Scintillation, Cherenkov radiation, Optical absorption, Rayleigh scattering and +Wavelength shifting. The wavelength shifting is either the default +implementation or a custom WLS process. -::: +Global optical settings: + +- Track scintillation secondaries first +- Enable scintillation by particle type +- Boundary process invokes sensitive detectors + +### Custom optical wave length shifting (WLS) process + +An optional custom wavelength-shifting process {cpp:class}`RMGOpWLSProcess` is +available and enabled by default. It can be disabled with +, if +necessary. + +It wraps the standard `G4OpWLS` process, but ensures at most one secondary +photon is produced per WLS interaction. For all our materials with a WLS +efficiency below one, this ensures that no extra photons are generated just by +setting this efficiency as in the stock process. This also matches our +expectation, as we do not expect that the emission of multiple photons in a WLS +material should be described by a Poisson distribution. + +## Hadronic Physics + +Hadronic physics can be completely disabled or configured via predefined physics +lists. + +If enabled, the following processes are included: + +- Hadronic elastic scattering (`G4HadronElasticPhysicsHP`) +- Optional thermal neutron scattering (`G4ThermalNeutrons`) +- Hadronic inelastic physics (selectable) +- Stopping physics (`G4StoppingPhysics`) +- Ion physics (`G4IonPhysics`) +- High-precision neutron cross sections (HP) + +### Hadronic Physics Options + +A hadronic physics option can be selected with +. Available options are + +| Option | Description | +| -------------- | --------------------------------------------------- | +| `None` | No hadronic physics (**default**) | +| `QGSP_BIC_HP` | Quark-Gluon String + Binary Cascade + HP neutrons | +| `QGSP_BERT_HP` | QGSP with Bertini cascade + HP neutrons | +| `FTFP_BERT_HP` | Fritiof string model + Bertini + HP neutrons | +| `Shielding` | Optimized shielding list with HP neutrons (default) | + +An addition option, +, enables +thermal scattering kernels for low-energy neutrons. + +### Custom Grabmayr Gamma Cascades + +When enabled with +, _remage_ +replaces the standard neutron capture process (`nCapture`) with a custom one +that will generate gamma cascaded for specific isotopes from files as provided +by P. Grabmayr _et al._. For all other isotopes, this process exactly behaves +the same. + +This option is primarily intended for scimulation sceneraios that require +precision gamma spectroscopy following neutron capture. + +The gamma cascade files are not shipped with _remage_ by default, but have to be +provided and registered by the user. For this, the command + can be +added to a macro file. + +## Radioactive decays Geant4 changed the default time threshold for radioactive decays in the 11.2 minor update to 1 year. _remage_ automatically reverts this change and sets the @@ -33,14 +132,22 @@ threshold to the old default of Geant4 before 11.2, being `1.0e+27 ns`. This threshold can be adjusted using the built-in command `/process/had/rdm/thresholdForVeryLongDecayTime` after `/run/initialize`. -### Internal Bremsstrahlung - -:::{todo} +:::{seealso} -- Internal Bremsstrahlung options +Primary particle generation for decay chains is handled by +{ref}`generators `. ::: +### Gamma angular correlations + +When using Geant4 11.3 or higher, the simulation of angular correlations between +gammas emitted coincident with a radioative decay are enabled. This can be +controlled by +. + +### Internal Bremsstrahlung + Internal Bremsstrahlung is a radiative correction to beta decay where a photon is emitted along with the beta particle and neutrino. Unlike external bremsstrahlung (which occurs when the beta particle interacts with matter after @@ -50,11 +157,45 @@ the decay process itself. The IB photon energy spectrum is continuous, extending from zero up to the Q-value of the decay. For Ar-39 (Q = 565 keV), the IB photons are typically soft (low energy), with most photons below 0.5 MeV. The spectrum is calculated based -on Hayen et al., Rev. Mod. Phys. 90, 015008 (2018). -https://journals.aps.org/rmp/abstract/10.1103/RevModPhys.90.015008 The -calculation is described in detail in Section V Radiative Correction. +on [^1]. The Inner Bremsstrahlung process is disabled by default in ReMage. To activate Inner Bremsstrahlung process, please use the command before `/run/initialize`. + +## Production Cuts and Step Limits + +### Production Cuts + +Production cuts are specified in **length units** (as usual in Geant4), and +applied per particle type (gamma, electron, positron, proton). + +Two regions are supported with separate production cuts, a default region (world +volume) and a sensitive region. + +```geant4 +/RMG/Processes/DefaultProductionCut {LENGTH} [mm] +/RMG/Processes/SensitiveProductionCut {LENGTH} [mm] +``` + +:::{note} + +- The default cuts are tuned for low-energy applications (≈ 100 keV in Ge) +- The energy range for production cuts is explicitly set for low energy physics + (200 eV to 100 GeV). +- All registered sensitive detectors will be automatically added to the + sensitive region. + +::: + +### Step Limits + +The `G4StepLimiterPhysics` is always added, but will not have an effect by +default. It allows volume-level step limits to be enforced if configured +elsewhere. + +[^1]: + Hayen et al., in Rev. Mod. Phys. 90, 015008 (2018). doi: + [10.1103/RevModPhys.90.015008](https://doi.org/10.1103/RevModPhys.90.015008). + The calculation is described in detail in Section V (Radiative Correction). diff --git a/docs/manual/running.md b/docs/manual/running.md index 40a66277..3536ce88 100644 --- a/docs/manual/running.md +++ b/docs/manual/running.md @@ -56,7 +56,14 @@ The most useful options include: ## Parallel execution _remage_ supports two ways of parallelising simulations, each with its own -advantages and limitations: +advantages and limitations. + +:::{admonition} In short + +If memory is the limiting factor, prefer `--threads`; otherwise, try `--procs` +for better throughput. See below for important notes. + +::: ### Geant4 multithreading @@ -81,10 +88,13 @@ independent _remage_ instances, each running a single process. This usually provides near 1:1 performance scaling but is more resource-hungry because every process carries a full memory footprint. -:::{admonition} In short +:::{warning} -If memory is the limiting factor, prefer `--threads`; otherwise, try `--procs` -for better throughput. +In the current design, a macro executed with multiple processes will simulate +more events than a single/multi-threaded mode with the same macro. The total +event count is increased by a factor of the number of processes. Example: with 5 +processes and `/run/beamOn 1000` in the macro, _remage_ will simulate 5000 +events. ::: diff --git a/docs/manual/visualization.md b/docs/manual/visualization.md index 3144a1e3..76677c8f 100644 --- a/docs/manual/visualization.md +++ b/docs/manual/visualization.md @@ -1,7 +1,129 @@ # Visualization -:::{todo} +## The `legend-pygeom-vis` viewer -- tips and tricks, even if duplicated (but hard to find) in the Geant4 docs +For simple geometry visualizatio without particle tracks, it is recommended to +use `legend-pygeom-vis` from the +[_legend-pygeom-tools_](https://github.com/legend-exp/legend-pygeom-tools) +package or the builtin visualization capabilities of your geometry creation +tool. This viewer also supports adding points from a LH5 file as an overlay over +the geometry. -::: +This VTK-based viewer can be run on any system, and _remage_ must not even be +installed on that device. In our experience, it might be easier to set up than +the Geant4-based visualization. + +## Built-in Geant4 visualization + +For more complex visualization, i.e., when you need to visualize the full +simulated tracks, you have to use the builtin visualization capabilities of +Geant4. For this it is useful to consult the [upstream visualization docs]. Only +the visualization backends compile into your Geant4 distribution are available +at runtime. For typical use cases, the OpenGL and ToolsSG drivers should be +sufficient. Whereas ToolsSG is suitable for offscreen rendering (i.e. on CI +pipelines), the OpenGL drivers typically require a running X11 session. + +Unlike the `legend-pygeom-vis` viewer, Geant4 cannot read the colors from the +GDML file, but requires expplicit color definition with macro commands. However, +such a coloring macro can also typically be generated from your GDML file +creation tool. + +The basic setup of a visualization macro needs to contain some commands to setup +the desired viewer to contain the geometry and the particle tracks: + +```geant4 +/vis/open OGL # or some other driver. +/vis/sceneHandler/attach + +/vis/drawVolume {root_volume_to_draw} + +/vis/viewer/set/defaultColour black +/vis/viewer/set/background white + +/vis/viewer/set/upVector 0 0 -1 +/vis/viewer/set/viewpointVector 1 1 0.5 +/vis/viewer/set/rotationStyle freeRotation + +/vis/scene/add/trajectories smooth +/vis/scene/add/hits +/vis/scene/endOfEventAction accumulate +# more commands... +/vis/viewer/flush +``` + +Individual volumes can be colored/shown/hidden...: + +```geant4 +# draw volume {volume} as a solid instead of wireframe. +/vis/geometry/set/forceSolid {volume} +# set the volume color of {volume} +/vis/geometry/set/colour {volume} 0 {r} {g} {b} {a} +# hide the volume {volume}. +/vis/geometry/set/visibility {volume} -1 false +``` + +The Geant4 visualization can also color tracks by properties of the particles. +The following example macro illustrates this in the case of optical photons, +colored by their wavelength. + +````{admonition} coloring photon tracks by wavelength +:class: dropdown + +```geant4 +/vis/modeling/trajectories/create/drawByAttribute +/vis/modeling/trajectories/select drawByAttribute-0 +/vis/modeling/trajectories/drawByAttribute-0/verbose false +/vis/modeling/trajectories/drawByAttribute-0/setAttribute IMag + +/vis/modeling/trajectories/drawByAttribute-0/addInterval vuviolet 6.53 eV 12.4 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval duviolet 4.43 eV 6.53 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval muviolet 3.94 eV 4.43 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval nuviolet 3.26 eV 3.94 eV + +/vis/modeling/trajectories/drawByAttribute-0/addInterval violet 2.85 eV 3.26 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval blue 2.48 eV 2.85 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval cyan 2.38 eV 2.48 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval green 2.19 eV 2.38 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval yellow 2.10 eV 2.19 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval orange 1.98 eV 2.10 eV +/vis/modeling/trajectories/drawByAttribute-0/addInterval red 1.59 eV 1.98 eV + +/vis/modeling/trajectories/drawByAttribute-0/vuviolet/setLineColourRGBA 0.29 0.00 0.51 1 +/vis/modeling/trajectories/drawByAttribute-0/duviolet/setLineColourRGBA 0.50 0.00 0.50 1 +/vis/modeling/trajectories/drawByAttribute-0/muviolet/setLineColourRGBA 0.58 0.00 0.83 1 +/vis/modeling/trajectories/drawByAttribute-0/nuviolet/setLineColourRGBA 0.73 0.33 0.83 1 + +/vis/modeling/trajectories/drawByAttribute-0/violet/setLineColourRGBA 0.93 0.51 0.93 1 +/vis/modeling/trajectories/drawByAttribute-0/blue/setLineColourRGBA 0.00 0.00 1.00 1 +/vis/modeling/trajectories/drawByAttribute-0/cyan/setLineColourRGBA 0.00 1.00 1.00 1 +/vis/modeling/trajectories/drawByAttribute-0/green/setLineColourRGBA 0.00 1.00 0.00 1 +/vis/modeling/trajectories/drawByAttribute-0/yellow/setLineColourRGBA 1.00 1.00 0.00 1 +/vis/modeling/trajectories/drawByAttribute-0/orange/setLineColourRGBA 1.00 0.65 0.00 1 +/vis/modeling/trajectories/drawByAttribute-0/red/setLineColourRGBA 1.00 0.00 0.00 1 +``` + +```` + +### Offscreen rendering with ToolsSG + +Using the ToolsSG offscreen rendering to render to a file is easy: + +```geant4 +# after /run/initialize +/vis/open TOOLSSG_OFFSCREEN 1500x1500 + +# your simulation commands here... +# /run/beamOn ... + +/vis/tsg/offscreen/set/file {filename}.jpeg +/vis/viewer/rebuild +``` + +## Interactive visualization + +The interactive mode `remage -i` can be used together with the visualization and +allows to input commands in a GUI window. There is no way to run a macro at +startup in this window, however. + +[upstream visualization docs]: + https://geant4-userdoc.web.cern.ch/UsersGuides/ForApplicationDeveloper/html/Visualization/visualization.html diff --git a/docs/rmg-commands.md b/docs/rmg-commands.md index 7971cb31..41d8edd2 100644 --- a/docs/rmg-commands.md +++ b/docs/rmg-commands.md @@ -526,7 +526,7 @@ Select primary confinement strategy * **Parameter** – `strategy` * **Parameter type** – `s` * **Omittable** – `False` - * **Candidates** – `UnConfined Volume FromFile` + * **Candidates** – `UnConfined Volume FromFile FromPoint` * **Allowed states** – `PreInit Idle` ### `/RMG/Generator/Select` @@ -549,6 +549,7 @@ Commands for controlling primary confinement * `/RMG/Generator/Confinement/Physical/` – Commands for setting physical volumes up for primary confinement * `/RMG/Generator/Confinement/Geometrical/` – Commands for setting geometrical volumes up for primary confinement * `/RMG/Generator/Confinement/FromFile/` – Commands for controlling reading event vertex positions from file +* `/RMG/Generator/Confinement/FromPoint/` – Commands for controlling vertex positions at fixed point **Commands:** @@ -949,6 +950,30 @@ Uses "vtx" by default * **Default value** – `vtx` * **Allowed states** – `PreInit Idle` +## `/RMG/Generator/Confinement/FromPoint/` + +Commands for controlling vertex positions at fixed point + + +**Commands:** + +* `Position` – Change the default input directory/group for ntuples. + +### `/RMG/Generator/Confinement/FromPoint/Position` + +Change the default input directory/group for ntuples. + +* **Parameter** – `pos` + * **Parameter type** – `d` + * **Omittable** – `False` +* **Parameter** – `valueY` + * **Parameter type** – `d` + * **Omittable** – `False` +* **Parameter** – `valueZ` + * **Parameter type** – `d` + * **Omittable** – `False` +* **Allowed states** – `PreInit Idle` + ## `/RMG/Generator/MUSUNCosmicMuons/` Commands for controlling the MUSUN µ generator diff --git a/docs/tutorial.md b/docs/tutorial.md index ffc814b1..c6d41173 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -217,8 +217,7 @@ radioactive source: The macro commands should be placed in a plain text file (conventionally ended with the `.mac` suffix). For example the complete macro file is shown below. -:::{admonition} Complete macro file (`vis-gammas.mac`) - +````{admonition} Complete macro file (vis-gammas.mac) :class: dropdown ```geant4 @@ -254,7 +253,7 @@ with the `.mac` suffix). For example the complete macro file is shown below. /run/beamOn 10 ``` -::: +```` We can finally pass the GDML geometry and the macro to the `remage` executable and look at the result! diff --git a/include/RMGMasterGenerator.hh b/include/RMGMasterGenerator.hh index a9d431e0..03fa4f27 100644 --- a/include/RMGMasterGenerator.hh +++ b/include/RMGMasterGenerator.hh @@ -34,8 +34,9 @@ class RMGMasterGenerator : public G4VUserPrimaryGeneratorAction { */ enum class Confinement { kUnConfined, ///< No confinement is applied here; the generator has the duty to sample a primary vertex. - kVolume, ///< The primary vertex is confined to a specific detector volume. - kFromFile ///< The primary vertex is read from an external file. + kVolume, ///< The primary vertex is confined to a specific detector volume. + kFromFile, ///< The primary vertex is read from an external file. + kFromPoint ///< The primary vertex is always at a fixed position. }; /** diff --git a/include/RMGVertexFromPoint.hh b/include/RMGVertexFromPoint.hh new file mode 100644 index 00000000..35679038 --- /dev/null +++ b/include/RMGVertexFromPoint.hh @@ -0,0 +1,53 @@ +// Copyright (C) 2025 Manuel Huber +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . + +#ifndef _RMG_VERTEX_FROM_POINT_HH_ +#define _RMG_VERTEX_FROM_POINT_HH_ + +#include + +#include "G4GenericMessenger.hh" +#include "G4ThreeVector.hh" + +#include "RMGVVertexGenerator.hh" + +class RMGVertexFromPoint : public RMGVVertexGenerator { + + public: + + RMGVertexFromPoint(); + ~RMGVertexFromPoint() = default; + + RMGVertexFromPoint(RMGVertexFromPoint const&) = delete; + RMGVertexFromPoint& operator=(RMGVertexFromPoint const&) = delete; + RMGVertexFromPoint(RMGVertexFromPoint&&) = delete; + RMGVertexFromPoint& operator=(RMGVertexFromPoint&&) = delete; + + bool GenerateVertex(G4ThreeVector& vertex) { + vertex = fVertex; + return true; + }; + + private: + + std::unique_ptr fMessenger = nullptr; + void DefineCommands(); + + G4ThreeVector fVertex = kDummyPrimaryPosition; +}; + +#endif + +// vim: tabstop=2 shiftwidth=2 expandtab diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 41ba6c56..d09406bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,6 +47,7 @@ set(PROJECT_PUBLIC_HEADERS ${_root}/include/RMGUserInit.hh ${_root}/include/RMGVertexConfinement.hh ${_root}/include/RMGVertexFromFile.hh + ${_root}/include/RMGVertexFromPoint.hh ${_root}/include/RMGVGenerator.hh ${_root}/include/RMGVOutputScheme.hh ${_root}/include/RMGVVertexGenerator.hh @@ -93,6 +94,7 @@ set(PROJECT_SOURCES ${_root}/src/RMGUserAction.cc ${_root}/src/RMGVertexConfinement.cc ${_root}/src/RMGVertexFromFile.cc + ${_root}/src/RMGVertexFromPoint.cc ${_root}/src/RMGVertexOutputScheme.cc) # Write RMGConfig.hh diff --git a/src/RMGMasterGenerator.cc b/src/RMGMasterGenerator.cc index e042b130..aabcd31e 100644 --- a/src/RMGMasterGenerator.cc +++ b/src/RMGMasterGenerator.cc @@ -34,6 +34,7 @@ #include "RMGVVertexGenerator.hh" #include "RMGVertexConfinement.hh" #include "RMGVertexFromFile.hh" +#include "RMGVertexFromPoint.hh" RMGMasterGenerator::RMGMasterGenerator() : fVertexGeneratorObj(nullptr), fGeneratorObj(nullptr) { @@ -85,6 +86,9 @@ void RMGMasterGenerator::SetConfinement(RMGMasterGenerator::Confinement code) { fVertexGeneratorObj = std::make_unique(); break; case Confinement::kFromFile: fVertexGeneratorObj = std::make_unique(); break; + case Confinement::kFromPoint: + fVertexGeneratorObj = std::make_unique(); + break; default: RMGLog::Out( RMGLog::fatal, diff --git a/src/RMGVertexFromPoint.cc b/src/RMGVertexFromPoint.cc new file mode 100644 index 00000000..42f0f084 --- /dev/null +++ b/src/RMGVertexFromPoint.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2025 Manuel Huber +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +// details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . + +#include "RMGVertexFromPoint.hh" + +#include "CLHEP/Units/SystemOfUnits.h" + +RMGVertexFromPoint::RMGVertexFromPoint() : RMGVVertexGenerator("FromPoint") { + this->DefineCommands(); +} + +void RMGVertexFromPoint::DefineCommands() { + + fMessenger = std::make_unique( + this, + "/RMG/Generator/Confinement/FromPoint/", + "Commands for controlling vertex positions at fixed point" + ); + + fMessenger->DeclareProperty("Position", fVertex) + .SetGuidance("Change the default input directory/group for ntuples.") + .SetParameterName("pos", false) + .SetStates(G4State_PreInit, G4State_Idle); +} diff --git a/src/remage-doc-dump.cc b/src/remage-doc-dump.cc index 515e69cb..be3bec11 100644 --- a/src/remage-doc-dump.cc +++ b/src/remage-doc-dump.cc @@ -43,6 +43,7 @@ #include "RMGVOutputScheme.hh" #include "RMGVertexConfinement.hh" #include "RMGVertexFromFile.hh" +#include "RMGVertexFromPoint.hh" #include "RMGVertexOutputScheme.hh" #include "CLI/CLI.hpp" @@ -67,6 +68,7 @@ void init_extra() { // confinments new RMGVertexConfinement(); new RMGVertexFromFile(); + new RMGVertexFromPoint(); // generators new RMGGeneratorMUSUNCosmicMuons(); new RMGGeneratorCosmicMuons(); diff --git a/tests/vertex/CMakeLists.txt b/tests/vertex/CMakeLists.txt index 0e6c8a60..f5728b17 100644 --- a/tests/vertex/CMakeLists.txt +++ b/tests/vertex/CMakeLists.txt @@ -27,7 +27,8 @@ set(_macros kin-lh5 kin-hdf5 kin2-lh5 - pos-kin-lh5) + pos-kin-lh5 + pos-kin-combined-lh5) foreach(_mac ${_macros}) add_test(NAME vertex/${_mac} COMMAND ${PYTHONPATH} run-vtx.py ${_mac} 1 st) diff --git a/tests/vertex/create-test-input.py b/tests/vertex/create-test-input.py index 5fe95c88..0cc0a90e 100755 --- a/tests/vertex/create-test-input.py +++ b/tests/vertex/create-test-input.py @@ -32,7 +32,7 @@ def _convert_lh5_to_hdf5(lh5_fn): # position input -def _create_pos_input(dtype, vtx_pos_file, units): +def _create_pos_input(dtype, vtx_pos_file: str, units: str, wo_mode: str = "of"): attrs = {"units": units} xloc = Array(np.linspace(0, 1000, INPUT_FILE_ROWS).astype(dtype), attrs=attrs) yloc = Array(rng.uniform(-1, 1, INPUT_FILE_ROWS).astype(dtype), attrs=attrs) @@ -42,7 +42,7 @@ def _create_pos_input(dtype, vtx_pos_file, units): Table({"xloc": xloc, "yloc": yloc, "zloc": zloc}), "vtx/pos", lh5_file=vtx_pos_file, - wo_mode="of", + wo_mode=wo_mode, ) _convert_lh5_to_hdf5(vtx_pos_file) @@ -53,54 +53,51 @@ def _create_pos_input(dtype, vtx_pos_file, units): # ================================================== # kinetics input. -p_theta = np.acos(rng.uniform(-1, 1, INPUT_FILE_ROWS)) -p_phi = rng.uniform(0, 2 * np.pi, INPUT_FILE_ROWS) - -px = Array(np.cos(p_phi) * np.sin(p_theta)) -py = Array(np.sin(p_phi) * np.sin(p_theta)) -pz = Array(np.cos(p_theta)) - -pdg = Array(np.ones(INPUT_FILE_ROWS, dtype=np.int64) * 11) -ekin = Array(np.linspace(1, 10, INPUT_FILE_ROWS), attrs={"units": "MeV"}) -time = Array(np.linspace(1, 10, INPUT_FILE_ROWS), attrs={"units": "ns"}) -n_part = Array(np.ones(INPUT_FILE_ROWS, dtype=np.int64)) - -vtx_kin_file = "macros/vtx-kin.lh5" -lh5.write( - Table( - { - "g4_pid": pdg, - "ekin": ekin, - "px": px, - "py": py, - "pz": pz, - "time": time, - "n_part": n_part, - } - ), - "vtx/kin", - lh5_file=vtx_kin_file, - wo_mode="of", -) -_convert_lh5_to_hdf5(vtx_kin_file) - -n_part.nda[1::2] = 0 -n_part.nda *= 2 -vtx_kin_file = "macros/vtx-kin2.lh5" -lh5.write( - Table( - { - "g4_pid": pdg, - "ekin": ekin, - "px": px, - "py": py, - "pz": pz, - "time": time, - "n_part": n_part, - } - ), - "vtx/kin", - lh5_file=vtx_kin_file, - wo_mode="of", -) -_convert_lh5_to_hdf5(vtx_kin_file) + +def _create_kin_input( + vtx_kin_file: str, wo_mode: str = "of", multiple_particles: bool = False +): + p_theta = np.acos(rng.uniform(-1, 1, INPUT_FILE_ROWS)) + p_phi = rng.uniform(0, 2 * np.pi, INPUT_FILE_ROWS) + + px = Array(np.cos(p_phi) * np.sin(p_theta)) + py = Array(np.sin(p_phi) * np.sin(p_theta)) + pz = Array(np.cos(p_theta)) + + pdg = Array(np.ones(INPUT_FILE_ROWS, dtype=np.int64) * 11) + ekin = Array(np.linspace(1, 10, INPUT_FILE_ROWS), attrs={"units": "MeV"}) + time = Array(np.linspace(1, 10, INPUT_FILE_ROWS), attrs={"units": "ns"}) + n_part = Array(np.ones(INPUT_FILE_ROWS, dtype=np.int64)) + + if multiple_particles: + n_part.nda[1::2] = 0 + n_part.nda *= 2 + + lh5.write( + Table( + { + "g4_pid": pdg, + "ekin": ekin, + "px": px, + "py": py, + "pz": pz, + "time": time, + "n_part": n_part, + } + ), + "vtx/kin", + lh5_file=vtx_kin_file, + wo_mode=wo_mode, + ) + _convert_lh5_to_hdf5(vtx_kin_file) + + +_create_kin_input("macros/vtx-kin.lh5") +_create_kin_input("macros/vtx-kin2.lh5", multiple_particles=True) + + +# ================================================== +# combined input in one file. + +_create_pos_input(np.float64, "macros/vtx-combined.lh5", "m") +_create_kin_input("macros/vtx-combined.lh5", wo_mode="write_safe") diff --git a/tests/vertex/macros/pos-kin-combined-lh5.mac b/tests/vertex/macros/pos-kin-combined-lh5.mac new file mode 100644 index 00000000..0bb80793 --- /dev/null +++ b/tests/vertex/macros/pos-kin-combined-lh5.mac @@ -0,0 +1,9 @@ +/control/execute macros/_init.mac + +/RMG/Generator/Confine FromFile +/RMG/Generator/Confinement/FromFile/FileName macros/vtx-combined.lh5 + +/RMG/Generator/Select FromFile +/RMG/Generator/FromFile/FileName macros/vtx-combined.lh5 + +/run/beamOn {events}