26.2. Creating the Water Phantom
Table of Contents
Concept of a Water Phantom
In this example the water phantom represents a simple, uniform volume of liquid water that mimics a patient or tissue-equivalent medium. The goal is not anatomical realism but a clean and controllable geometry that allows you to study how protons lose energy in water as a function of depth.
In practice you will create the phantom as a single Geant4 volume with material set to water, large enough so that the entire proton Bragg peak is contained inside it. All later scoring of energy deposition and depth dose will happen inside this phantom.
Choosing Phantom Size and Placement
Before you write any code, decide on the basic dimensions and where to place the phantom in the world.
For a monoenergetic proton beam, the range in water depends on the energy. For example, a 150 MeV proton has a range of about 15 cm in water. To be safe, the phantom should extend beyond the expected range so that nearly all protons stop in the water.
A typical beginner choice is:
- A rectangular water box, for example 30 cm long along the beam direction and 20 cm by 20 cm in the transverse directions.
- The proton beam will enter through one face of the box and travel along its long axis, for instance along the positive $z$ axis.
You can position the phantom so that its entrance face is near the world origin and the beam starts just in front of it. A simple option is to center the phantom at $z = 0$ and let the beam start at some negative $z$ position. Another common approach is to put the entrance face at $z = 0$ and extend the phantom in the positive $z$ direction.
Whatever you choose, keep the coordinate system simple, because you will later interpret depth in water directly from the $z$ coordinate.
Choose phantom dimensions so that the proton range is fully contained in water with extra margin, for example at least 2 times the expected range along the beam direction.
Implementing the Phantom in DetectorConstruction
The water phantom is defined in your DetectorConstruction class, typically derived from G4VUserDetectorConstruction. Inside the Construct() method you will first build the world volume, then place the water phantom inside it.
In code, the phantom is represented by a solid, a logical volume, and a physical placement.
A minimal sequence is:
- Create the world box and its logical and physical volumes.
- Obtain the water material.
- Create a box solid for the phantom with half-lengths in $x$, $y$, and $z$.
- Create a
G4LogicalVolumefor the phantom using the water material. - Place the phantom logical volume inside the world using
G4PVPlacement.
You do not need to connect any sensitive detectors yet. The phantom at this stage is only a passive volume that will host the future scoring of energy deposition.
Every volume must follow the pattern: solid → logical volume → physical placement. Forgetting any of these steps will prevent the phantom from appearing in the geometry.
Using Water from the NIST Database
For a realistic water material you should use the NIST material database provided by Geant4 rather than defining water manually. This guarantees that the density and composition are consistent with physics models and with other examples.
Inside DetectorConstruction::Construct(), after including the appropriate headers, you can obtain water with:
auto nist = G4NistManager::Instance();
G4Material* water = nist->FindOrBuildMaterial("G4_WATER");
The string "G4_WATER" is a predefined material name in the NIST database. You do not need to specify elements or density by hand.
If you want to double-check, you can print material properties during initialization using methods from G4Material, but this belongs to general material handling and not specifically to the phantom.
Always prefer G4NistManager materials like "G4_WATER" for standard materials to ensure correct density and composition.
World and Phantom Geometry in Code
A concrete implementation of the world and phantom might look like this, focusing only on the essential geometry:
G4VPhysicalVolume* DetectorConstruction::Construct()
{
// Get NIST manager
auto nist = G4NistManager::Instance();
// World parameters
G4double worldSizeXY = 1.0*m;
G4double worldSizeZ = 1.0*m;
G4Material* worldMat = nist->FindOrBuildMaterial("G4_AIR");
// World solid / logical / physical
auto solidWorld =
new G4Box("World", // name
0.5*worldSizeXY, // half x
0.5*worldSizeXY, // half y
0.5*worldSizeZ); // half z
auto logicWorld =
new G4LogicalVolume(solidWorld, // solid
worldMat, // material
"World"); // name
auto physWorld =
new G4PVPlacement(nullptr, // no rotation
G4ThreeVector(), // at (0,0,0)
logicWorld, // logical volume
"World", // name
nullptr, // no mother volume
false, // no boolean operation
0, // copy number
true); // check overlaps
// Phantom dimensions
G4double phantomSizeXY = 20.0*cm;
G4double phantomSizeZ = 30.0*cm;
// Phantom material
G4Material* water = nist->FindOrBuildMaterial("G4_WATER");
// Phantom solid / logical
auto solidPhantom =
new G4Box("WaterPhantom",
0.5*phantomSizeXY,
0.5*phantomSizeXY,
0.5*phantomSizeZ);
auto logicPhantom =
new G4LogicalVolume(solidPhantom,
water,
"WaterPhantom");
// Place phantom at center of world
new G4PVPlacement(nullptr,
G4ThreeVector(0., 0., 0.),
logicPhantom,
"WaterPhantom",
logicWorld,
false,
0,
true);
return physWorld;
}In this example the phantom is centered at the origin. With this choice, depth in water runs from negative to positive $z$, and you can map the Bragg peak location by converting $z$ to an absolute depth using $z + 0.5 \times \text{phantomSizeZ}$ if needed.
If you prefer depth to match directly with positive $z$ from the entrance face, you could shift the phantom so that its entrance face is at $z = 0$:
G4double zPos = 0.5*phantomSizeZ; // center at z = +half length
new G4PVPlacement(nullptr,
G4ThreeVector(0., 0., zPos),
logicPhantom,
"WaterPhantom",
logicWorld,
false,
0,
true);Now the entrance face is at $z = 0$, and depth in water is simply the $z$ coordinate inside the phantom.
Always ensure that the phantom fits entirely inside the world volume. World half-lengths must be larger than the phantom half-lengths in every dimension.
Checking the Phantom with Visualization
Once the phantom is implemented, you should verify it visually. After you have configured a visualization driver, you can run a few basic commands in a macro to display the geometry:
Use for example:
/vis/open OGL
/vis/drawVolume
/vis/viewer/setStyle wireframe
You should see a large world volume and inside it a smaller rectangular volume which is the water phantom. Later, when you fire the proton beam, tracks should enter this phantom and stop inside it.
If the phantom does not appear, common issues include:
- A typo in the material name so that water is not created properly.
- Not returning the world physical volume from
Construct(). - Incorrect placement such that the phantom is outside the world bounds.
Checking the geometry now will save time when you start scoring energy deposition in later steps of the example.
Views: 10
KAHIBARO