nain4
is an API and accompanying set of libraries whose aim is to make it
easier to write, test and deploy Geant4
applications.
The documentation for nain4
is gradually being written
here.
Nain4 uses Nix
to manage dependencies, installation and
provision of the development environment. The value proposition is: If you
install nix on
your machine we can provide a zero-effort means of installing Geant4 plus
dependencies and development tools, and making sure that everything has
compatible versions and works together in harmony1.
For HPC systems on which installing Nix might be problematic:
- nix-portable works well in many situations
- we provide the means to generate Singularity/Apptainer containers.
Nain4 is a collection of utilities whose aim is to
- make it significantly easier to write Geant4 applications, in code that is much more robust, readable and self-documenting;
- make it possible/easy to write unit and integration tests for Geant4 application code;
- make it more difficult to write invalid Geant4 code by promoting errors to compile time;
As a quick taster, here is a translation of the detector geometry from Geant4 example basic/B1
into nain4
:
// Materials
auto water = n4::material("G4_WATER");
auto air = n4::material("G4_AIR");
auto tissue = n4::material("G4_A-150_TISSUE");
auto bone = n4::material("G4_BONE_COMPACT_ICRU");
// Dimensions
// ...
// world_sizeXY = ... unremarkable value settings elided for brevity
// ...
// Volumes
auto world = n4::box ("World" ).xy(world_sizeXY).z(world_sizeZ) .volume(air);
auto envelope = n4::box ("Envelope").xy( env_sizeXY).z( env_sizeZ) .volume(water);
auto trapezoid = n4::trd ("Bone" ).x1(trd_dxa).x2(trd_dxb)
.y1(trd_dya).y2(trd_dyb).z(trd_dz).volume(bone);
// If no handle is needed for a logical volume, it can be placed immediately
n4::cons("Tissue").r1(cone_rmaxa).r2(cone_rmaxb).z(cone_hz).place(tissue).in(envelope).at_yz(2*cm, -7*cm).now();
// Set Trapezoid as scoring volume
this -> fScoringVolume = trapezoid;
// Placement
n4:: place(envelope) .in(world) .now();
n4:: place(trapezoid).in(envelope).at_yz(-1*cm, 7*cm).now();
return n4::place(world) .now();
This is the complete (except for setting of the values like world_sizeXYZ
) nain4
implementation of DetectorConstruction::Construct()
.
These 13 lines of code (without comments or blank lines) correspond to 62 lines in the original example.
In Geant4's interfaces, you have to remember (or look up) the order of the parameters of the shape constructors, and you must provide values for each parameter, even when you want to use an obvious default value (such as inner radius
being zero, or phi
covering 2π
); in nain4
the parameters have clear names and can be provided in any order that you find convenient; obvious default values can be omitted.
Geant4 obliges you to express everything in (frequently annoying) half-lengths; nain4
gives you the choice: .x
vs .half_x
.
The whole2 B1 example is translated into nain4 here, and, even though it is written in a style that places almost every argument on a separate line, it fits in a single file in under 150 lines, compared to the 1138 lines spread over 13 files in the original Geant4 rendition.
-
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
-
Bootstrap a new
nain4
project:nix run github:jacg/nain4#bootstrap-client-project path/to/your-new-project your-project-name "Your project description"
This step will take a while as it downloads and compiles Geant4.
A new directory
path/to/your-new-project
will be created. Adapt this path to your needs before executing the command.Also adapt
your-project-name
(used in various identifiers and path components inside your project) and"Your project description"
before executing the command. -
cd
intopath/to/your-new-project
-
Type
nix develop
3Start a new
bash
shell in which all the required dependencies are available. Exiting this shell makes these dependencies invisible once more. Thus, the installation of these dependencies does not interfere with anything else you may have on your system. -
Type
just run -g -n 10
.This step compiles the example application in your new project and runs it in interactive mode. A visualization window should pop up.
If all this worked, hooray! You have a git repository containing a development
environment in which you can use to evolve, test and deploy your nain4
-based
Geant4 application.
If not, read on to see possible problems and fixes.
As it stands you have to write nix develop
in order to activate the
environment necessary to run and develop this code. What is more, nix develop
places you in a minimal bash shell in which any personal configurations you may
be used to, will be missing.
Both of these problems can be fixed with direnv which:
- automatically enables the environment when you enter the directory (asking your permission, the first time)
- updates the environment in whatever shell you happen to be using, thus allowing you to enjoy your previous settings.
To use direnv
:
-
Make sure that it is installed on your system. If you have got this far, then you have already installed the Nix package manager on your machine, so you could use it to install
direnv
like this:nix profile install nixpkgs#direnv
-
Don't forget to hook
direnv
into your shell. Depending on which shell you are using, this will involve adding one of the following lines to the end of your shell configuration file:eval "$(direnv hook bash)" # in ~/.bashrc eval "$(direnv hook zsh)" # in ~/.zshrc eval `direnv hook tcsh` # in ~/.cshrc
The first time direnv
wants to perform an automatic switch in a new
context (combination of directory + .envrc
contents), it asks you
for permission to do so. You can give it permission by typing direnv allow
in the shell. The message that direnv
gives you at this stage
is pretty clear, but it's usually written in red, thus you might get
the mistaken impression that there is an error.
-
Linux: This code is developed and tested on Linux. If the above procedure didn't work, it's a bug. Please report it.
-
Windows: It should work equally well in WSL2 on Windows.
Caveat: if you are going to install Nix in multi-user mode, make sure that
systemd
is enabled. In short, this requires you to ensure that the file/etc/wsl.conf
exists in your in-WSL linux and that it contains the lines[boot] systemd=true
-
MacOS: Everything seems to work on macOS, with both Intel processors and Apple Silicon, but it has not been tested as extensively as on Linux.
The interactive mode uses a Qt-based GUI. This requires the correct graphics drivers to be installed in a location known to Nix. This should work out of the box on
- NixOS
- MacOS
On other systems, that is to say non-NixOS Linuxes and WSL2 on Windows, the
environment will try to use nixGL
to
provide the appropriate drivers. WARNING: the first time nixGL
is needed, it
will take a long time to download and compile.
Footnotes
-
Somewhere in the repository, we have provided the means to install nain4 without the use of Nix, but we do not have the resources or the motivation to maintain this. If something in
nain4
is broken when using it via Nix, then we will aim to fix it; if something is broken when usingnain4
without Nix, then we won't be able to help. ↩ -
This is not strictly true. The original B1 example caters for multiprocessing. As we actively discourage (TODO link to section in docs) using multiprocessing in Geant4, this translation into nain4 is not exactly equivalent. However, the differences are absolutely minimal. ↩
-
see the section on direnv for a more ergonomic alternative ↩