l Scoring geometry implementation
|
Important: Every time you open a new shell you need to set your
environment up correctly. |
By the end of this Hands-on you should be able to:
l Implement
a spherical parameterised geometry to be used for scoring
l Construct
a sensitive detector (G4MultiFunctionalDetector) and attach scorers
l Implement
a user defined run class
l Construct
scorer filters based on particle type and energy
This exercise builds on the HandsOn3 exercise. It is based on an experimental setup developed for bremsstrahlung benchmarking at UCSF. The simplified experiment is made up of the following components:
l Vacuum
beam pipe
l Titanium
beam window
l Iron
evacuation chamber window
l Silicon
monitor
l Beryllium
target
Electrons are generated with an energy of 15 MeV in the beam pipe. The electrons interact with the target and generate bremsstrahlung photons. A spherical, parameterised, air filled scoring geometry is also implemented. The number of photons crossing this scoring volume is counted in ten theta bins and ten energy bins. The diagram below demonstrates the simulated experiment.

The following files are provided with the exercise:
l beamTest.cc - main program
l BeamTestDetectorConstruction – material, geometry , sensitive detector and scorer definitions
l BeamTestPrimaryGeneratorAction - primary particle generator
l BeamTestPhysicsList - user defined physics list
l BeamTestRun - user defined run class
l BeamTestRunAction - G4UserRunAction class
l BeamTestScoreParameterisation – scoring volume parameterisation
All the geometries except the spherical scoring geometry are implemented. The scoring geometry, sensitive detector, scorers and filters are implemented over the course of the exercise.
If using windows, make sure G4UI_USE_TCSH is not set.
To start this exercise, unpack HandsOn4.tgz to your working directory.
Compile and link it using following commands:
$ cd HandsOn4
$ make
Once you have successfully compiled and linked the code, try it to see how it runs:
$ ./bin/$G4SYSTEM/beamTest
run.mac
This will produce files named G4Data0.heprep and G4Data1.heprep, which can be viewed by invoking the Wired visualization tool.
$ wired G4Data0.heprep
You should be able to view the following:

You can see that all the components with the exception of the scoring volume have been implemented.
The mother scoring volume is defined as a thin air filled sphere. It has an inner radius of 1 m, an outer radius of 1.001 m, and is centered in the world volume. Ten scoring rings are placed within the mother scoring volume. Each ring covers 6 degrees in theta and is constructed of air with an inner radius of 1m and an outer radius of 1.001 m. G4PVPlacement is used to construct the mother sphere, while G4PVParameterised is used to construct the rings. BeamTestScoreParameterisation is used for the ring parameterisation.
The implementation, along with visualisation attributes is shown below.
|
BeamTestDetectorConstruction.cc |
|
----- snipped ----- #include
"G4Tubs.hh" #include
"G4VisAttributes.hh" // HandsOn4: Scoring
volumes #include
"BeamTestScoreParameterisation.hh" #include
"G4PVParameterised.hh" #include
"G4Sphere.hh" ----- snipped ----- //////////////////////////////////////////////////////////////////////// // HandsOn4: Scoring volumes // Mother sphere G4double innerRadius = 1.0*m; G4double outerRadius = 1.001*m; G4VSolid* sphereSolid = new
G4Sphere("Sphere_Solid", // Name
innerRadius,
// Inner radius
outerRadius,
// Outer radius
0.*deg, // Starting phi
360.*deg, // Delta phi
0.*deg, // Starting
theta
180.*deg); // Delta theta G4LogicalVolume* sphereLogical = new
G4LogicalVolume(sphereSolid, air, "Sphere_Logical"); new G4PVPlacement(0, G4ThreeVector(),
sphereLogical, "Sphere_Physical", fpWorldLogical, false,
0); // 10 scoring rings G4double deltaTheta = 6.*deg; G4VSolid* scoreSolid = new
G4Sphere("Score_Solid",
// Name
innerRadius, //
Inner radius
outerRadius, //
Outer radius 0.*deg,
// Starting phi
360.*deg, // Delta phi 0.*deg,
// Starting theta deltaTheta); // Delta theta G4LogicalVolume* fScoreLogical = new
G4LogicalVolume(scoreSolid, air, "scoreLog"); BeamTestScoreParameterisation* param
= new
BeamTestScoreParameterisation(innerRadius, outerRadius, deltaTheta); new
G4PVParameterised("scorePhys", // Name fScoreLogical,
// Logical volume sphereLogical,
// Mother volume kZAxis,
// Axis 10,
// Number of replicas param);
// Parameterisation ----- snipped ----- // HandsOn4: Scoring volume
attributes // Mother sphere G4VisAttributes* sphereAttributes = new
G4VisAttributes(G4Colour(1.0,1.0,1.0,0.2));
sphereAttributes->SetVisibility(false);
sphereLogical->SetVisAttributes(sphereAttributes); // Ring scoring volumes. Green with
transparancy. G4VisAttributes* scoreAttributes = new
G4VisAttributes(G4Colour(0.0,1.0,0.0,0.2));
scoreAttributes->SetVisibility(true);
fScoreLogical->SetVisAttributes(scoreAttributes); |
Implement the above and compile, link and run the program. Use Wired to check that all the scoring geometries are now in place. You should be able to see something like:

Note that the mother scoring sphere has been made invisible by default. You can change this by checking the Sphere_Physical[0] box.
We are interested in counting the number of photons per unit area which cross the inner surface of each scoring ring. To do this we need to:
l Create a G4MultiFunctionalDetector detector
l Register the detector with the sensitive detector manager (G4SDManager)
l Attach the detector to the parameterised scoring volume
l Create
a primitive scorer for scoring surface current
l Register the primitive scorer with the detector
We will use the G4PSSphereSurfaceCurrent scorer to count the number of photons crossing each scoring ring. Since the ten scoring rings are replicas, we only need to create one scorer. This scorer will automatically record the current as a function of replica copy number.
The implementation is shown below.
|
BeamTestDetectorConstruction.cc |
|
----- snipped ----- // HandsOn4: Scoring
components #include
"G4MultiFunctionalDetector.hh" #include
"G4PSSphereSurfaceCurrent.hh" #include
"G4SDManager.hh" ----- snipped ----- new
G4PVParameterised("scorePhys", // Name fScoreLogical,
// Logical volume sphereLogical,
// Mother volume kZAxis,
// Axis 10,
// Number of replicas param);
// Parameterisation // HandsOn4: Construct scoring
components SetupScoring(fScoreLogical); //////////////////////////////////////////////////////////////////////// // Target (Default parameters for Be ) G4Material* beryllium =
G4Material::GetMaterial("Beryllium"); ----- snipped ----- void
BeamTestDetectorConstruction::SetupScoring(G4LogicalVolume* scoringVolume) { // HandsOn4: Construct scoring
components // Create a new sensitive detector
named "MyDetector" G4MultiFunctionalDetector* detector =
new
G4MultiFunctionalDetector("MyDetector"); // Get pointer to detector manager G4SDManager* manager =
G4SDManager::GetSDMpointer();
// Register detector with manager manager->AddNewDetector(detector); // Attach detector to scoring volume
scoringVolume->SetSensitiveDetector(detector); // Create a primitive Scorer named
myScorer G4PSSphereSurfaceCurrent* scorer =
new G4PSSphereSurfaceCurrent("myScorer",
fCurrent_In); // Register scorer with detector
detector->RegisterPrimitive(scorer); G4cout<<"Created
G4MultiFunctionalDetector named "
<<detector->GetName()<<", and a
G4PSSphereSurfaceCurrent scorer "
<<"named "<<scorer->GetName()<<G4endl; } |
After implementing the above, compile, link and run the program. Check that the sensitive detector and scorer names are printed out, as shown below.
|
Printout showing detector and scorer details |
|
----- snipped ----- Material: Vacuum density: 0.010 mg/cm3 temperature: 273.15 K pressure: 0.02 atm
RadLength: 36.786 km ---> Element: Nitrogen (N) Z = 7.0 N
= 14.0 A =
14.01 g/mole fractionMass: 70.00 % Abundance
72.71 % ---> Element: Oxygen (O) Z = 8.0 N
= 16.0 A =
16.00 g/mole
fractionMass: 30.00
% Abundance 27.29 % Created G4MultiFunctionalDetector named MyDetector, and a
G4PSSphereSurfaceCurrent scorer named myScorer BeamTestPhysicsList::SetCuts:CutLength
: 1 mm ----- snipped ----- |
The scorer implemented in the previous section will accumulate data over a single event, but we are more interested in data accumulated over an entire run. Therefore, we need to create our own run class, inheriting from G4Run. This class will be responsible for merging the scorer data for all events.
A partially implemented user run class called BeamTestRun is provided with the example. Also included is a BeamTestRunAction class which inherits from G4UserRunAction. BeamTestRunAction is responsible for creating an instance of BeamTestRun, and is an example of one of the optional user action classes. BeamTestRunAction needs to be registered with the run manager in the main program, as shown below.
|
beamTest.cc |
|
----- snipped ----- #include
"BeamTestPrimaryGeneratorAction.hh" // HandsOn4: User defined
run action #include
"BeamTestRunAction.hh" #include
"G4RunManager.hh" ----- snipped ----- // User action classes runManager->SetUserAction(new
BeamTestPrimaryGeneratorAction()); // HandsOn4: User defined run action runManager->SetUserAction(new
BeamTestRunAction); // Initialize G4 kernel |
After implementing the above, compile, link and run the program. Check that you get printout shown below.
|
Printout showing user defined BeamTestRun class creation |
|
Voxelisation: top memory users:
Percent
Memory
Heads
Nodes Pointers Total CPU Volume
-------
--------
------ ------ -------- ---------- ---------- 67.84 0k
3
14 36
0.00
World_Logical 32.16 0k
1 7
20
0.00
Sphere_Logical Creating user define run class
BeamTestRun Start Run processing. HepRepFile writing to G4Data1.heprep |
The event by event scorer data merging still needs to be implemented in BeamTestRun. This class has a data member, fMap, which is used to hold the accumulated data. fMap is just a map between hit collection idÕs and scorer data (G4THitsMap<G4double>). Merging of scorer data is done in the BeamTestRun::RecordEvent(const G4Event* anEvent) method, and involves:
l Accessing the hit collection for the event (G4HCofThisEvent object)
l Using
the G4HCofThisEvent object to access the G4THitsMap<double> data for each
registered scorer
l Accumulating
the hit map data
The implementation is shown below.
|
BeamTestRun.cc |
|
----- snipped ----- void
BeamTestRun::RecordEvent(const G4Event* anEvent) { numberOfEvent++; // HandsOn4: Merging event data // Get the hits collection G4HCofThisEvent* eventHitCollection =
anEvent->GetHCofThisEvent(); if (!eventHitCollection) return; // Update our private fMap std::map< G4int,
G4THitsMap<G4double>* >::iterator iter = fMap.begin(); while (iter != fMap.end()) { G4int id =
iter->first; // Get the hit collection
corresponding to "id"
G4THitsMap<G4double>* eventHitsMap =
dynamic_cast< G4THitsMap<G4double>*
>(eventHitCollection->GetHC(id)); // Expect this to exist assert (0 !=
eventHitsMap); // Accumulate event data
into our G4THitsMap<G4double> map *(iter->second) +=
*eventHitsMap; iter++; } } |
After implementing the above, modify the run.mac macro to run for 1000 events. If you donÕt want to visualise the results, disable the visualisation system by adding the command /vis/disable to run.mac. This will also speed up the processing.
Compile, link and run the program. Check that you get data printed out as shown below. Theta bins corresponding to the ten scoring rings are listed in the first column. The corresponding number of photons per unit area (mm-2) crossing the scoring ring are listed the second column.
|
Printout showing current printout in theta bin |
|
Number of
Events Processed:1000 events. Theta myScorer 0 0.00227 1 0.00115 2
0.000476 3
0.000327 4
0.000244 5
0.000162 6
0.000111 7
9.89e-05 8
9.78e-05 9
8.34e-05 Graphics systems
deleted. Visualization Manager
deleting... |
So far we have only used one scorer to count all tracks crossing each of the scoring rings. It is possible to attach a filter to a scorer, so that only hits passing the filter will be processed. For example, if we are only interested in scoring photons within a given energy range, we would attach a suitably configured G4SDParticleWithEnergyFilter filter to the scorer. If we are interested in scoring a number of different energy ranges we can create multiple scorers, each with its own filter. This is demonstrated below, where ten scorers filtering on photons in 1.2 MeV energy bins are generated and registered with the G4MultiFunctionalDetector.
|
BeamTestDetectorConstruction.cc |
|
----- snipped ----- // HandsOn4: Filter #include
"G4SDParticleWithEnergyFilter.hh" ----- snipped ----- void
BeamTestDetectorConstruction::SetupScoring(G4LogicalVolume* scoringVolume) { // HandsOn4: Construct scoring
components // Create a new sensitive detector
named "MyDetector" G4MultiFunctionalDetector* detector =
new
G4MultiFunctionalDetector("MyDetector"); // Get pointer to detector manager G4SDManager* manager =
G4SDManager::GetSDMpointer();
// Register detector with manager manager->AddNewDetector(detector); // Attach detector to scoring volume
scoringVolume->SetSensitiveDetector(detector); // HandsOn4: Applying filters to
scorers G4int nEnergyBins = 10; G4int i(0); for (i=0; i<nEnergyBins; i++) { char name[10];
std::sprintf(name,"Scorer%i", i); // Create a primitive
Scorer G4PSSphereSurfaceCurrent*
scorer = new
G4PSSphereSurfaceCurrent(name, fCurrent_In); // Create a filter
G4SDParticleWithEnergyFilter* filter = new G4SDParticleWithEnergyFilter("Gamma
Filter"); // Filter will pass only
gammas
filter->add("gamma"); // Set energy range of
gammas filter will accept G4double minEnergy =
i*1.2*MeV; G4double maxEnergy =
(i+1)*1.2*MeV; filter->SetKineticEnergy(minEnergy,
maxEnergy); // Attach filter to
scorer. Scorer will only process hits which pass // the filter
scorer->SetFilter(filter);
G4cout<<"Created scorer with name "<<name; G4cout<<",
covering energy range "<<minEnergy*MeV; G4cout<<" :
"<<maxEnergy*MeV<<" MeV"<<G4endl; // Register scorer with
detector
detector->RegisterPrimitive(scorer); } } |
After implementing the above, compile, link and run the program for around 10000 events. Check that you see the new scorers registered, and that you see the current printed out for each theta and energy bin, as shown below.
|
Printout showing current in each theta and energy bin |
|
----- snipped ----- ---> Element: Nitrogen (N) Z = 7.0 N
= 14.0 A = 14.01
g/mole fractionMass: 70.00 % Abundance
72.71 % ---> Element: Oxygen (O) Z = 8.0 N
= 16.0 A =
16.00 g/mole
fractionMass: 30.00
% Abundance 27.29 % Created scorer with name Scorer0, covering energy range 0 :
1.2 MeV Created scorer with name Scorer1, covering energy range 1.2
: 2.4 MeV Created scorer with name Scorer2, covering energy range 2.4
: 3.6 MeV Created scorer with name Scorer3, covering energy range 3.6
: 4.8 MeV Created scorer with name Scorer4, covering energy range 4.8 :
6 MeV Created scorer with name Scorer5, covering energy range 6 :
7.2 MeV Created scorer with name Scorer6, covering energy range 7.2
: 8.4 MeV Created scorer with name Scorer7, covering energy range 8.4
: 9.6 MeV Created scorer with name Scorer8, covering energy range 9.6
: 10.8 MeV Created scorer with name Scorer9, covering energy range 10.8
: 12 MeV BeamTestPhysicsList::SetCuts:CutLength : 1 mm ----- snipped ----- Number of Events Processed:10000 events.
Theta Scorer0 Scorer1 Scorer2
Scorer3 Scorer4 Scorer5 Scorer6
Scorer7 Scorer8 Scorer9 0 0.0132
0.00378 0.00215 0.00093 0.000581 0.000436 0.000407
0.000378 0.000349 0.000174 1 0.00724
0.00145 0.000573 0.000457 0.000185 0.000214 0.000126 0.000156 5.83e-05
1.94e-05 2 0.0041 0.000693 0.00027 0.0002 0.000106 0.000112 4.11e-05 2.35e-05 1.76e-05
1.76e-05 3 0.00272
0.00031 0.00014 6.36e-05
2.97e-05 2.55e-05 2.55e-05 4.24e-06 8.49e-06 4.24e-06 4 0.00201 0.000191 6.03e-05 2.34e-05 1.34e-05 2.01e-05
0 1e-05
3.35e-06 0 5 0.00138 0.000131 4.75e-05 1.68e-05 2.79e-06 5.58e-06
0 0
0 0 6 0.00113 8.94e-05 3.14e-05 9.66e-06 4.83e-06 0 0
2.42e-06 0 0
7 0.00101 4.52e-05 6.45e-06 4.3e-06 0 0
0 0 0
2.15e-06 8 0.000927 4.11e-05 3.91e-06
3.91e-06 1.96e-06 1.96e-06 0
0 0 0
9 0.000722 2.72e-05 7.25e-06
1.81e-06 0
0
0
0 0 0
Graphics systems deleted. |
An output file called output.csv (Comma Separated Variables) should also be produced. This can be loaded into for example, OpenOffice or Excel, to make a plot of the data. The plot below shows the data for 104 events plotted for a selection of energy bins.

You can download the complete source of this exercise from HandsOn4_complete.tgz
Geant4 Tutorial Course
Gean4.v8.0p01
May 2006
Jane Tinslay – Heavily based on a tutorial given at
a SLAC in March 2006 by Tsukasa
Aso