Create more than 16 Scoring Meshes in Geant4
Geant4 simulation framework provides Scoring Meshes functionality to visualize desired physical quantities in a binned Physical Volume. Meshes can be defined in various shapes — Box, Cylinder or Cube. All these C++ classes ( G4ScoringBox
, G4ScoringCylinder
, G4ScoringProbe
) are derived from the base G4ScoringMesh
class.
We ran into an issue with defining multiple Scoring Meshes. Currently, when number of defined meshes is more than 16, Geant4 throws following error:
Here is the essence of the problem. By default, in Geant4 every Scoring Mesh is created in a separate Parallel World. Every Parallel World eventually creates a new instance of G4Navigator
. Unfortunately the maximum number of Navigators is hard coded in the Geant4 source code in G4PathFinder::fMaxNav
variable and set to 16:
class G4PathFinder {
...
static const G4int fMaxNav = 16;
}
One solution would be to download Geant4 source code, manually increase above value and compile your modified version of Geant4. However this option is not always possible. For instance, if using Geant4 on some computational environment provided by your institution.
Luckily there is a workaround. We can define multiple Scoring Meshes in a single Parallel World. There is one condition though. Scoring Meshes defined in this single Parallel World should not overlap with each other.
Below I will provide a snippet of code that clarifies implementation details. Firstly, we create a namespace to store Scoring Meshes’ names that will reside inside a same parallel world. Function getMeshName
appends mesh number to the “base” mesh name.
namespace MeshNames {
inline static const G4String BASE_NAME = "myMesh";
inline static G4String getMeshName(G4int i) {
return BASE_NAME + std::to_string(i+1);
}
};
Next, we will define meshes with the above subset of names in a single parallel world. In order to do so we customize the ConstructScoringWorlds()
function of the Geant4's Run Manager class. Namely, we override it by creating a custom RunManager
class:
MyRunManager.hh:
#ifndef GLASS_SRC_MYRUNMANAGER_HH_
#define GLASS_SRC_MYRUNMANAGER_HH_
#include <G4RunManager.hh>
#include "ActionInitialization.hh"
class MyRunManager : public G4RunManager {
public:
MyRunManager();
virtual ~MyRunManager(){};
void ConstructScoringWorlds() override;private:
G4String mySingleParallelWorldName;
};
#endif /* GLASS_SRC_MYRUNMANAGER_HH_ */
Definition of the custom ConstructScoringWorlds()
goes in MyRunManager.cc:
#include "MYRunManager.hh"
// include other required headers ...
MyRunManager::MyRunManager() : G4RunManager() {
mySingleParallelWorldName = "mySingleParallelWorld";
}
// Define meshes "myMesh1", "myMesh2", ... in single parallel world
// Copy below function from G4RunManager::ConstructScoringWorlds()
// But with a few modifications listed belowvoid MyRunManager::ConstructScoringWorlds() {
...
for (G4int iw = 0; iw < nPar; iw++) {
// We replace ScM->GetWorldName(iw) with the name of our
// single custom world for a subset of non-overlapping meshes
// named "myMesh1", "myMesh2", etc:
G4String worldName =
(mesh->GetWorldName().find(MeshNames::BASE_NAME) !=
std::string::npos) ? mySingleParallelWorldName :
ScM->GetWorldName(iw);
// Next in the code replace every occurance
// of "ScM->GetWorldName(iw)" with "worldName"
...
}
}
I would like to stress again that meshes named here as “myMesh1”, “myMesh2” etc.. that we defined within a single Parallel World named “mySingleParallelWorld” should not overlap between each other. Screenshot below demonstrates the overlap issues:
If your implementation requires overlapping meshes please construct separate parallel worlds for them (or better for the groups of non-overlapping meshes). Just keep in mind that the maximum number of available Parallel Worlds at the moment is 16.
Note: I only tested the results in single-threaded simulation. It is expected that similar modifications are required in G4MTRunManager.cc
to run the simulation in Multi-Threaded (MT) mode.
This is pretty much it. Make sure you instantiate your modified MyRunManager
class instead of the default Geant4’s G4RunManager
in your main()
or elsewhere.