Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HadrontherapyDetectorConstruction.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 // This is the *BASIC* version of Hadrontherapy, a Geant4-based application
27 // See more at: http://g4advancedexamples.lngs.infn.it/Examples/hadrontherapy
28 //
29 // Visit the Hadrontherapy web site (http://www.lns.infn.it/link/Hadrontherapy) to request
30 // the *COMPLETE* version of this program, together with its documentation;
31 // Hadrontherapy (both basic and full version) are supported by the Italian INFN
32 // Institute in the framework of the MC-INFN Group
33 //
34 
36 
37 #include "G4SDManager.hh"
38 #include "G4RunManager.hh"
39 #include "G4GeometryManager.hh"
40 #include "G4SolidStore.hh"
41 #include "G4PhysicalVolumeStore.hh"
42 #include "G4LogicalVolumeStore.hh"
43 #include "G4Box.hh"
44 #include "G4LogicalVolume.hh"
45 #include "G4ThreeVector.hh"
46 #include "G4PVPlacement.hh"
47 #include "globals.hh"
48 #include "G4Transform3D.hh"
49 #include "G4RotationMatrix.hh"
50 #include "G4Colour.hh"
51 #include "G4UserLimits.hh"
52 #include "G4UnitsTable.hh"
53 #include "G4VisAttributes.hh"
54 #include "G4NistManager.hh"
55 
60 #include "HadrontherapyMatrix.hh"
62 
63 #include <cmath>
64 
67  : motherPhys(physicalTreatmentRoom), // pointer to WORLD volume
68  detectorSD(0), detectorROGeometry(0), matrix(0),
69  phantom(0), detector(0),
70  phantomLogicalVolume(0), detectorLogicalVolume(0),
71  phantomPhysicalVolume(0), detectorPhysicalVolume(0),
72  aRegion(0)
73 {
75 
76  /* NOTE! that the HadrontherapyDetectorConstruction class
77  * does NOT inherit from G4VUserDetectorConstruction G4 class
78  * So the Construct() mandatory virtual method is inside another geometric class
79  * like the passiveProtonBeamLIne, ...
80  */
81 
82  // Messenger to change parameters of the phantom/detector geometry
83  detectorMessenger = new HadrontherapyDetectorMessenger(this);
84 
85  // Default detector voxels size
86  // 200 slabs along the beam direction (X)
87  sizeOfVoxelAlongX = 200 *CLHEP::um;
88  sizeOfVoxelAlongY = 4 *CLHEP::cm;
89  sizeOfVoxelAlongZ = 4 *CLHEP::cm;
90 
91  // Define here the material of the water phantom and of the detector
92  SetPhantomMaterial("G4_WATER");
93  // Construct geometry (messenger commands)
94  SetDetectorSize(4.*CLHEP::cm, 4.*CLHEP::cm, 4.*CLHEP::cm);
95  SetPhantomSize(40. *CLHEP::cm, 40. *CLHEP::cm, 40. *CLHEP::cm);
96  SetPhantomPosition(G4ThreeVector(20. *CLHEP::cm, 0. *CLHEP::cm, 0. *CLHEP::cm));
97  SetDetectorToPhantomPosition(G4ThreeVector(0. *CLHEP::cm, 18. *CLHEP::cm, 18. *CLHEP::cm));
98 
99 
100  // Write virtual parameters to the real ones and check for consistency
101  UpdateGeometry();
102 }
103 
106 {
107  delete detectorROGeometry;
108  delete matrix;
109  delete detectorMessenger;
110 }
111 
113 // ConstructPhantom() is the method that reconstuct a water box (called phantom
114 // (or water phantom) in the usual Medical physicists slang).
115 // A water phantom can be considered a good
116 // approximation of a an human body.
117 void HadrontherapyDetectorConstruction::ConstructPhantom()
118 {
119  // Definition of the solid volume of the Phantom
120  phantom = new G4Box("Phantom",
121  phantomSizeX/2,
122  phantomSizeY/2,
123  phantomSizeZ/2);
124 
125 // Definition of the logical volume of the Phantom
126  phantomLogicalVolume = new G4LogicalVolume(phantom,
127  phantomMaterial,
128  "phantomLog", 0, 0, 0);
129 
130  // Definition of the physics volume of the Phantom
131  phantomPhysicalVolume = new G4PVPlacement(0,
132  phantomPosition,
133  "phantomPhys",
134  phantomLogicalVolume,
135  motherPhys,
136  false,
137  0);
138 
139 // Visualisation attributes of the phantom
140  red = new G4VisAttributes(G4Colour(255/255., 0/255. ,0/255.));
141  red -> SetVisibility(true);
142  red -> SetForceSolid(true);
143  red -> SetForceWireframe(true);
144  phantomLogicalVolume -> SetVisAttributes(red);
145 }
146 
148 // ConstructDetector() it the method the reconstruct a detector region
149 // inside the water phantom. It is a volume, located inside the water phantom
150 // and with two coincident faces:
151 //
152 // **************************
153 // * water phantom *
154 // * *
155 // * *
156 // *--------------- *
157 // Beam * - *
158 // -----> * detector - *
159 // * - *
160 // *--------------- *
161 // * *
162 // * *
163 // * *
164 // **************************
165 //
166 // The detector is the volume that can be dived in slices or voxelized
167 // and in it we can collect a number of usefull information:
168 // dose distribution, fluence distribution, LET and so on
169 void HadrontherapyDetectorConstruction::ConstructDetector()
170 {
171 
172  // Definition of the solid volume of the Detector
173  detector = new G4Box("Detector",
174  detectorSizeX/2,
175  detectorSizeY/2,
176  detectorSizeZ/2);
177 
178  // Definition of the logic volume of the Phantom
179  detectorLogicalVolume = new G4LogicalVolume(detector,
180  detectorMaterial,
181  "DetectorLog",
182  0,0,0);
183 // Definition of the physical volume of the Phantom
184  detectorPhysicalVolume = new G4PVPlacement(0,
185  detectorPosition, // Setted by displacement
186  "DetectorPhys",
187  detectorLogicalVolume,
188  phantomPhysicalVolume,
189  false,0);
190 
191 // Visualisation attributes of the detector
192  skyBlue = new G4VisAttributes( G4Colour(135/255. , 206/255. , 235/255. ));
193  skyBlue -> SetVisibility(true);
194  skyBlue -> SetForceSolid(true);
195  //skyBlue -> SetForceWireframe(true);
196  detectorLogicalVolume -> SetVisAttributes(skyBlue);
197 
198  // **************
199  // Cut per Region
200  // **************
201 
202  // A smaller cut is fixed in the phantom to calculate the energy deposit with the
203  // required accuracy
204  if (!aRegion)
205  {
206  aRegion = new G4Region("DetectorLog");
207  detectorLogicalVolume -> SetRegion(aRegion);
208  aRegion -> AddRootLogicalVolume(detectorLogicalVolume);
209  }
210 
211 }
212 
214 
215 void HadrontherapyDetectorConstruction::ConstructSensitiveDetector(G4ThreeVector detectorToWorldPosition)
216 {
217  // Install new Sensitive Detector and ROGeometry
218  delete detectorROGeometry; // this should be safe in C++ also if we have a NULL pointer
219  //if (detectorSD) detectorSD->PrintAll();
220  //delete detectorSD;
221  // Sensitive Detector and ReadOut geometry definition
222  G4SDManager* sensitiveDetectorManager = G4SDManager::GetSDMpointer();
223 
224  static G4String sensitiveDetectorName = "Detector";
225  if (!detectorSD)
226  {
227  // The sensitive detector is instantiated
228  detectorSD = new HadrontherapyDetectorSD(sensitiveDetectorName);
229  }
230  // The Read Out Geometry is instantiated
231  static G4String ROGeometryName = "DetectorROGeometry";
232  detectorROGeometry = new HadrontherapyDetectorROGeometry(ROGeometryName,
233  detectorToWorldPosition,
234  detectorSizeX/2,
235  detectorSizeY/2,
236  detectorSizeZ/2,
237  numberOfVoxelsAlongX,
238  numberOfVoxelsAlongY,
239  numberOfVoxelsAlongZ);
240 
241  G4cout << "Instantiating new Read Out Geometry \"" << ROGeometryName << "\""<< G4endl;
242  // This will invoke Build() HadrontherapyDetectorROGeometry virtual method
243  detectorROGeometry -> BuildROGeometry();
244  // Attach ROGeometry to SDetector
245  detectorSD -> SetROgeometry(detectorROGeometry);
246  //sensitiveDetectorManager -> Activate(sensitiveDetectorName, true);
247  if (!sensitiveDetectorManager -> FindSensitiveDetector(sensitiveDetectorName, false))
248  {
249  G4cout << "Registering new DetectorSD \"" << sensitiveDetectorName << "\""<< G4endl;
250  // Register user SD
251  sensitiveDetectorManager -> AddNewDetector(detectorSD);
252  // Attach SD to detector logical volume
253  detectorLogicalVolume -> SetSensitiveDetector(detectorSD);
254  }
255 }
256 void HadrontherapyDetectorConstruction::ParametersCheck()
257 {
258  // Check phantom/detector sizes & relative position
259  if (!IsInside(detectorSizeX,
260  detectorSizeY,
261  detectorSizeZ,
262  phantomSizeX,
263  phantomSizeY,
264  phantomSizeZ,
265  detectorToPhantomPosition
266  ))
267  G4Exception("HadrontherapyDetectorConstruction::ParametersCheck()", "Hadrontherapy0001", FatalException, "Error: Detector is not fully inside Phantom!");
268 
269  // Check Detector sizes respect to the voxel ones
270 
271  if ( detectorSizeX < sizeOfVoxelAlongX) {
272  G4Exception("HadrontherapyDetectorConstruction::ParametersCheck()", "Hadrontherapy0002", FatalException, "Error: Detector X size must be bigger or equal than that of Voxel X!");
273  }
274  if ( detectorSizeY < sizeOfVoxelAlongY) {
275  G4Exception(" HadrontherapyDetectorConstruction::ParametersCheck()", "Hadrontherapy0003", FatalException, "Error: Detector Y size must be bigger or equal than that of Voxel Y!");
276  }
277  if ( detectorSizeZ < sizeOfVoxelAlongZ) {
278  G4Exception(" HadrontherapyDetectorConstruction::ParametersCheck()", "Hadrontherapy0004", FatalException, "Error: Detector Z size must be bigger or equal than that of Voxel Z!");
279  }
280 
281 }
283 // MESSENGERS //
285 
287 {
288 
289  if (G4Material* pMat = G4NistManager::Instance()->FindOrBuildMaterial(material, false) )
290  {
291  phantomMaterial = pMat;
292  detectorMaterial = pMat;
293  if (detectorLogicalVolume && phantomLogicalVolume)
294  {
295  detectorLogicalVolume -> SetMaterial(pMat);
296  phantomLogicalVolume -> SetMaterial(pMat);
297 
298  G4RunManager::GetRunManager() -> PhysicsHasBeenModified();
299  G4RunManager::GetRunManager() -> GeometryHasBeenModified();
300  G4cout << "The material of Phantom/Detector has been changed to " << material << G4endl;
301  }
302  }
303  else
304  {
305  G4cout << "WARNING: material \"" << material << "\" doesn't exist in NIST elements/materials"
306  " table [located in $G4INSTALL/source/materials/src/G4NistMaterialBuilder.cc]" << G4endl;
307  G4cout << "Use command \"/parameter/nist\" to see full materials list!" << G4endl;
308  return false;
309  }
310 
311  return true;
312 }
315 {
316  if (sizeX > 0.) phantomSizeX = sizeX;
317  if (sizeY > 0.) phantomSizeY = sizeY;
318  if (sizeZ > 0.) phantomSizeZ = sizeZ;
319 }
323 {
324  if (sizeX > 0.) {detectorSizeX = sizeX;}
325  if (sizeY > 0.) {detectorSizeY = sizeY;}
326  if (sizeZ > 0.) {detectorSizeZ = sizeZ;}
327  SetVoxelSize(sizeOfVoxelAlongX, sizeOfVoxelAlongY, sizeOfVoxelAlongZ);
328 }
330 
332 {
333  if (sizeX > 0.) {sizeOfVoxelAlongX = sizeX;}
334  if (sizeY > 0.) {sizeOfVoxelAlongY = sizeY;}
335  if (sizeZ > 0.) {sizeOfVoxelAlongZ = sizeZ;}
336 }
338 {
339  phantomPosition = pos;
340 }
341 
344 {
345  detectorToPhantomPosition = displ;
346 }
349 {
350  /*
351  * Check parameters consistency
352  */
353  ParametersCheck();
354 
355  G4GeometryManager::GetInstance() -> OpenGeometry();
356  if (phantom)
357  {
358  phantom -> SetXHalfLength(phantomSizeX/2);
359  phantom -> SetYHalfLength(phantomSizeY/2);
360  phantom -> SetZHalfLength(phantomSizeZ/2);
361  phantomPhysicalVolume -> SetTranslation(phantomPosition);
362  }
363  else ConstructPhantom();
364 
365  // Get the center of the detector
367  if (detector)
368  {
369  detector -> SetXHalfLength(detectorSizeX/2);
370  detector -> SetYHalfLength(detectorSizeY/2);
371  detector -> SetZHalfLength(detectorSizeZ/2);
372  detectorPhysicalVolume -> SetTranslation(detectorPosition);
373  }
374  else ConstructDetector();
375 
376  // Round to nearest integer number of voxel
377  numberOfVoxelsAlongX = G4lrint(detectorSizeX / sizeOfVoxelAlongX);
378  sizeOfVoxelAlongX = ( detectorSizeX / numberOfVoxelsAlongX );
379 
380  numberOfVoxelsAlongY = G4lrint(detectorSizeY / sizeOfVoxelAlongY);
381  sizeOfVoxelAlongY = ( detectorSizeY / numberOfVoxelsAlongY );
382 
383  numberOfVoxelsAlongZ = G4lrint(detectorSizeZ / sizeOfVoxelAlongZ);
384  sizeOfVoxelAlongZ = ( detectorSizeZ / numberOfVoxelsAlongZ );
385 
386  ConstructSensitiveDetector(GetDetectorToWorldPosition());
387 
388  volumeOfVoxel = sizeOfVoxelAlongX * sizeOfVoxelAlongY * sizeOfVoxelAlongZ;
389  massOfVoxel = detectorMaterial -> GetDensity() * volumeOfVoxel;
390  // This will clear the existing matrix (together with all data inside it)!
391  matrix = HadrontherapyMatrix::GetInstance(numberOfVoxelsAlongX,
392  numberOfVoxelsAlongY,
393  numberOfVoxelsAlongZ,
394  massOfVoxel);
395 
396  // Initialize analysis
397 #ifdef G4ANALYSIS_USE_ROOT
399  analysis -> flush(); // Finalize the root file
400  analysis -> book();
401 #endif
402  // Inform the kernel about the new geometry
403  G4RunManager::GetRunManager() -> GeometryHasBeenModified();
404  G4RunManager::GetRunManager() -> PhysicsHasBeenModified();
405 
406  PrintParameters();
407 }
408 
410 {
411 
412  G4cout << "The (X,Y,Z) dimensions of the phantom are : (" <<
413  G4BestUnit( phantom -> GetXHalfLength()*2., "Length") << ',' <<
414  G4BestUnit( phantom -> GetYHalfLength()*2., "Length") << ',' <<
415  G4BestUnit( phantom -> GetZHalfLength()*2., "Length") << ')' << G4endl;
416 
417  G4cout << "The (X,Y,Z) dimensions of the detector are : (" <<
418  G4BestUnit( detector -> GetXHalfLength()*2., "Length") << ',' <<
419  G4BestUnit( detector -> GetYHalfLength()*2., "Length") << ',' <<
420  G4BestUnit( detector -> GetZHalfLength()*2., "Length") << ')' << G4endl;
421 
422  G4cout << "Displacement between Phantom and World is: ";
423  G4cout << "DX= "<< G4BestUnit(phantomPosition.getX(),"Length") <<
424  "DY= "<< G4BestUnit(phantomPosition.getY(),"Length") <<
425  "DZ= "<< G4BestUnit(phantomPosition.getZ(),"Length") << G4endl;
426 
427  G4cout << "The (X,Y,Z) sizes of the Voxels are: (" <<
428  G4BestUnit(sizeOfVoxelAlongX, "Length") << ',' <<
429  G4BestUnit(sizeOfVoxelAlongY, "Length") << ',' <<
430  G4BestUnit(sizeOfVoxelAlongZ, "Length") << ')' << G4endl;
431 
432  G4cout << "The number of Voxels along (X,Y,Z) is: (" <<
433  numberOfVoxelsAlongX << ',' <<
434  numberOfVoxelsAlongY <<',' <<
435  numberOfVoxelsAlongZ << ')' << G4endl;
436 
437 }