ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FFDetectorConstruction.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FFDetectorConstruction.cc
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 // -------------------------------------------------------------
27 // =============== Begin Documentation Comments ===============
38 // ================ End Documentation Comments ================
39 //
40 // Modified:
41 //
42 // 23-06-14 BWendt
43 // Fixed issue with the automatic placement of the meat not working. Solution
44 // was to use the correct units "inch" in the y-direction as well.
45 // Coincidentally eliminated the need to using the 'std::abs()" from the
46 // "cmath" library.
47 // Implemented method "PlaceFuelPlates"
48 //
49 // -------------------------------------------------------------
50 
51 #include "globals.hh"
52 
53 #include "G4Box.hh"
54 #include "G4Element.hh"
55 #include "G4Isotope.hh"
56 #include "G4LogicalVolume.hh"
57 #include "G4NistManager.hh"
58 #include "G4PVPlacement.hh"
59 #include "G4SystemOfUnits.hh"
60 #include "G4Tubs.hh"
61 #include "G4VPhysicalVolume.hh"
62 
64 
65 
66 static const G4double inch = 2.54 * cm;
67 
68 
69 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
73 {
75 }
76 
77 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
80 {
82 #ifdef NDEBUG
83  G4bool const overlapChecking = false;
84 #else
85  G4bool const overlapChecking = true;
86 #endif // NDEBUG
87 
88  //
89  // Create the world
90  //
91  const G4double worldSize = 40.0 * inch;
92  G4Box* const solidWorld = new G4Box("World", // the name
93  worldSize, // x size
94  worldSize, // y size
95  worldSize); // z size
96  G4LogicalVolume* const logicalWorld
97  = new G4LogicalVolume(solidWorld, // the solid volume
98  fAir, // the material
99  solidWorld->GetName()); // the name
100  // Center at the origin
101  position.set(0.0, 0.0, 0.0);
102  G4VPhysicalVolume* const physicalWorld
103  = new G4PVPlacement(NULL, // no rotation
104  position, // must be at origin
105  logicalWorld, // the logical volume
106  logicalWorld->GetName(), // the name
107  NULL, // no mother volume
108  false, // no boolean ops
109  0, // copy number
110  overlapChecking); // check for overlaps
111 
112  //
113  // Create the graphite pile that the subcritical assembly rests on.
114  //
115  const G4double floorH = 30.0 * inch;
116  const G4ThreeVector floorPosition(0.0, 0.0, 0.0);
117  G4Box* const solidFloor = new G4Box("Floor", // the name
118  worldSize, // x size
119  worldSize, // y size
120  floorH * 0.5); // z size
121  G4LogicalVolume* const logicalFloor
122  = new G4LogicalVolume(solidFloor, // the solid volume
123  fGraphite, // the material
124  solidFloor->GetName()); // the name
125  // Shift down so the top is at the origin
126  position.set(0.0, 0.0, -floorH * 0.5);
127  new G4PVPlacement(NULL, // no rotation
128  position, // position
129  logicalFloor, // the logical volume
130  logicalFloor->GetName(), // the name
131  logicalWorld, // the mother volume
132  false, // no boolean ops
133  0, // copy number
134  overlapChecking); // check for overlaps
135 
136  //
137  // Create the tank
138  //
139  const G4double tankWallThickness = 0.25 * inch;
140  const G4double tankOR = 18.0 * inch;
141  const G4double tankH = 39.0 * inch;
142  G4Tubs* const solidTank
143  = new G4Tubs("Tank_Wall", // the name
144  0.0, // inner radius
145  tankOR, // outer radius
146  tankH * 0.5, // half height
147  0.0 * deg, // start angle
148  360.0 * deg); // end angle
149  G4LogicalVolume* const logicalTank
150  = new G4LogicalVolume(solidTank, // the solid volume
151  fAluminum, // the material
152  solidTank->GetName()); // the name
153  // Shift up so the base is at the origin
154  position.set(0.0, 0.0, tankH * 0.5);
155  new G4PVPlacement(NULL, // no rotation
156  position, // shift up
157  logicalTank, // the logical volume
158  logicalTank->GetName(), // the name
159  logicalWorld, // the mother volume
160  false, // no boolean ops
161  0, // copy number
162  overlapChecking); // check for overlaps
163  // Top 3 inches are air
164  const G4double tankAirH = 3.0 * inch;
165  G4Tubs* const solidTankAir
166  = new G4Tubs("Tank_Air", // the name
167  0.0, // inner radius
168  tankOR - tankWallThickness, // outer radius
169  tankAirH * 0.5, // half height
170  0.0 * deg, // start angle
171  360.0 * deg); // end angle
172  G4LogicalVolume* const logicalTankAir
173  = new G4LogicalVolume(solidTankAir, // the solid volume
174  fAir, // the material
175  solidTankAir->GetName()); // the name
176  // Shift up so that the top of the air is the same as the top of the tank
177  position.set(0.0, 0.0, (tankH - tankAirH) * 0.5);
178  new G4PVPlacement(NULL, // no rotation
179  position, // shift ip
180  logicalTankAir, // the logical volume
181  logicalTankAir->GetName(), // the name
182  logicalTank, // the mother volume
183  false, // no boolean ops
184  0, // copy number
185  overlapChecking); // check for overlaps
186  // Fill remaining area with water
187  const G4double tankH2OH = (tankH - (tankAirH + tankWallThickness));
188  G4Tubs* const solidTankH2O
189  = new G4Tubs("Tank_H2O", // the name
190  0.0, // inner radius
191  tankOR - tankWallThickness, // outer radius
192  tankH2OH * 0.5, // half height
193  0.0 * deg, // start angle
194  360.0 * deg); // end angle
195  G4LogicalVolume* const logicalTankH2O
196  = new G4LogicalVolume(solidTankH2O, // the solid volume
197  fAluminum, // the material
198  solidTankH2O->GetName()); // the name
199  // Shift up so that the top of the water is at the bottom of the air
200  const G4double centerOfH2O = (tankH - tankH2OH) * 0.5 - tankAirH;
201  position.set(0.0, 0.0, centerOfH2O);
202  new G4PVPlacement(NULL, // no rotation
203  position, // shift to origin
204  logicalTankH2O, // the logical volume
205  logicalTankH2O->GetName(), // the name
206  logicalTank, // the mother volume
207  false, // no boolean ops
208  0, // copy number
209  overlapChecking); // check for overlaps
210 
211  //
212  // Fuel plates
213  //
214  const G4double plateX = 3.0 * inch;
215  const G4double plateY = 0.08 * inch;
216  const G4double plateZ = 26.0 * inch;
217  const G4double meatX = 2.75 * inch;
218  const G4double meatY = 0.04 * inch;
219  const G4double meatZ = 24.0 * inch;
220  const G4double xSpacing = 5.0 * inch;
221  const G4double ySpacing = 0.3 * inch;
222  const G4double plateRadius = 12.0 * inch;
223  // Define the aluminim claddiing
224  G4Box* const solidPlate
225  = new G4Box("Plate_Cladding", // the name
226  plateX * 0.5, // x size
227  plateY * 0.5, // y size
228  plateZ * 0.5); // z size
229  G4LogicalVolume* const logicalPlate
230  = new G4LogicalVolume(solidPlate, // the solid volume
231  fAluminum, // the material
232  solidPlate->GetName()); // the name
233  // Place the meat inside the cladding
234  G4Box* const solidMeat
235  = new G4Box("Plate_Meat", // the name
236  meatX * 0.5, // x size
237  meatY * 0.5, // y size
238  meatZ * 0.5); // z size
239  G4LogicalVolume* const logicalMeat
240  = new G4LogicalVolume(solidMeat, // the solid volume
241  fUO2_20E, // the material
242  solidMeat->GetName()); // the name
243  // The meat goes into the exact center of the plate
244  position.set(0.0, 0.0, 0.0);
245  new G4PVPlacement(NULL, // no rotation
246  position, // position
247  logicalMeat, // the logical volume
248  logicalMeat->GetName(), // the name
249  logicalPlate, // the mother volume
250  false, // no boolean ops
251  0, // copy number
252  overlapChecking); // check for overlaps
253  // The plate will be centered in the z-direction within the water
254  // Simulate a subcritical assembly loading within a radius of 12 inches
255  bool placeMe;
256 
257  position.setZ(0.0);
258  fCopyNumber = 0;
259  for(double x = 0.0;
260  x <= plateRadius;
261  x += xSpacing)
262  {
263  // 5 rows of plates
264  for(double y = 0.0;
265  y <= plateRadius;
266  y += ySpacing)
267  {
268  placeMe = false;
269 
270  // Fuel plate must be completely within the radius to be placed
271  if(std::sqrt(x * x + y * y) < plateRadius)
272  {
273  // Leave a 1 inch radius opening in the middle for the neutron
274  // source
275  if(std::sqrt(x * x + y * y) > 1.0 * inch)
276  {
277  placeMe = true;
278  }
279  }
280 
281  if(placeMe)
282  {
284  y,
285  logicalPlate,
286  logicalTankH2O);
288  -y,
289  logicalPlate,
290  logicalTankH2O);
291  if(x > 0.0)
292  {
293  PlaceFuelPlate(-x,
294  y,
295  logicalPlate,
296  logicalTankH2O);
297  PlaceFuelPlate(-x,
298  -y,
299  logicalPlate,
300  logicalTankH2O);
301  }
302  }
303  }
304  }
305  G4cout << fCopyNumber << " plates were added to the subcritical assembly"
306  << G4endl;
307 
308  //
309  // Neutron Source
310  //
311  // TODO create the AmBe material in DefineMaterials() and use it here
312  // For now steel is used, but the logical volume is used in the
313  // PrimaryGeneratorAction to know where to emit the neutrons from
314  const G4double sourceH = 2 * inch;
315  const G4double sourceR = 0.2 * inch;
316  G4Tubs* const solidSource
317  = new G4Tubs("NeutronSource", // the name
318  0.0, // inner radius
319  sourceR, // outer radius
320  sourceH * 0.5, // half height
321  0.0 * deg, // start angle
322  360.0 * deg); // end angle
323  G4LogicalVolume* const logicalSource
324  = new G4LogicalVolume(solidSource, // the solid volume
325  fStainlessSteel, // the material
326  solidSource->GetName()); // the name
327  // Place in the exact center of the water tank
328  position.set(0.0, 0.0, 0.0);
329  new G4PVPlacement(NULL, // no rotation
330  position, // shift to origin
331  logicalSource, // the logical volume
332  logicalSource->GetName(), // the name
333  logicalTankH2O, // the mother volume
334  false, // no boolean ops
335  0, // copy number
336  overlapChecking); // check for overlaps
337 
338  //
339  // Detector Tower
340  //
341  const G4double polyS = 3.0 * inch;
342  const G4double polyH = 18.0 * inch;
343  G4Box* const solidPoly
344  = new G4Box("Poly", // the name
345  polyS, // x size
346  polyS, // y size
347  polyH); // z size
348  G4LogicalVolume* const logicalPoly
349  = new G4LogicalVolume(solidPoly, // the solid volume
350  fPolyethylene, // the material
351  solidPoly->GetName()); // the name
352  // The polyethylene detector tower goes just outside the tank at 45 deg
353  G4double radiusToPolyCenter = (tankOR / std::sqrt(2.0)) + std::sqrt(2.0) * polyS;
354  position.set(-radiusToPolyCenter, radiusToPolyCenter, polyH);
355  new G4PVPlacement(NULL, // no rotation
356  position, // position
357  logicalPoly, // the logical volume
358  logicalPoly->GetName(), // the name
359  logicalWorld, // the mother volume
360  false, // no boolean ops
361  0, // copy number
362  overlapChecking); // check for overlaps
363  // Create the detector shell
364  G4double shellR = 0.3 * inch;
365  G4double shellH = 6.5 * inch;
366  G4Tubs* const solidShell
367  = new G4Tubs("Detector_Shell", // the name
368  0.0, // inner radius
369  shellR, // outer radius
370  shellH * 0.5, // half height
371  0.0 * deg, // start angle
372  360.0 * deg); // end angle
373  G4LogicalVolume* const logicalShell
374  = new G4LogicalVolume(solidShell, // the solid volume
375  fStainlessSteel, // the material
376  solidShell->GetName()); // the name
377  // Place in the exact center of the polyethylene tower
378  position.set(0.0, 0.0, 0.0);
379  new G4PVPlacement(NULL, // no rotation
380  position, // shift to origin
381  logicalShell, // the logical volume
382  logicalShell->GetName(), // the name
383  logicalPoly, // the mother volume
384  false, // no boolean ops
385  0, // copy number
386  overlapChecking); // check for overlaps
387  // Create the BF3 detector
388  G4double BF3R = 0.2 * inch;
389  G4double BF3H = 6.0 * inch;
390  G4Tubs* const solidBF3
391  = new G4Tubs("Detector_BF3_Core", // the name
392  0.0, // inner radius
393  BF3R, // outer radius
394  BF3H * 0.5, // half height
395  0.0 * deg, // start angle
396  360.0 * deg); // end angle
397  G4LogicalVolume* const logicalBF3
398  = new G4LogicalVolume(solidBF3, // the solid volume
399  fBF3_96E, // the material
400  solidBF3->GetName()); // the name
401  // Place in the exact center of the shell
402  position.set(0.0, 0.0, 0.0);
403  new G4PVPlacement(NULL, // no rotation
404  position, // shift to origin
405  logicalBF3, // the logical volume
406  logicalBF3->GetName(), // the name
407  logicalShell, // the mother volume
408  false, // no boolean ops
409  0, // copy number
410  overlapChecking); // check for overlaps
411 
412  return physicalWorld;
413 }
414 
415 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
418 {
419  static G4NistManager* const nist = G4NistManager::Instance();
420 
421  fAir = nist->FindOrBuildMaterial("G4_AIR");
422  fAluminum = nist->FindOrBuildMaterial("G4_Al");
423  fGraphite = nist->FindOrBuildMaterial("G4_GRAPHITE");
424  fPolyethylene = nist->FindOrBuildMaterial("G4_POLYETHYLENE");
425  fStainlessSteel = nist->FindOrBuildMaterial("G4_STAINLESS-STEEL");
426  fWater = nist->FindOrBuildMaterial("G4_WATER");
427 
428  /*// List available materials
429  std::vector< G4String > materials = nist->GetNistMaterialNames();
430  for(unsigned int i = 0;
431  i < materials.size();
432  ++i)
433  {
434  G4cout << materials[i] << G4endl;
435  }*/
436 
437  //
438  // Define the 20% enriched UO2
439  //
440  // First we need to start by creating the isotopes
441  G4double const U235Enrichment = 0.2;
442  G4double const U238Enrichment = 0.8;
443  G4Isotope* const iU235
444  = new G4Isotope("iU235", // name
445  92, // ZZZ
446  235, // AAA
447  235.053930 * (g / mole)); // molecular weight
448  G4Isotope* const iU238
449  = new G4Isotope("iU238", // name
450  92, // ZZZ
451  238, // AAA
452  238.050788 * (g / mole)); // molecular weight
453  // Now create the elements and add the isotopes
454  G4Element* const U235
455  = new G4Element("U235", // name
456  "U235", // symbol
457  1); // number of isotopes
458  U235->AddIsotope(iU235, // isotope
459  1.0); // abundance
460  G4Element* const U238
461  = new G4Element("U238", // name
462  "U238", // symbol
463  1); // number of isotopes
464  U238->AddIsotope(iU238, // isotope
465  1.0); // abundance
466  G4Element* const oxygen = nist->FindOrBuildElement("O");
467  // Calculate the mass fractions
468  const G4double UO2MolecularWeight = U235->GetA() * U235Enrichment
469  + U238->GetA() * U238Enrichment
470  + oxygen->GetA() * 2;
471  const G4double U235MassFraction = (U235->GetA() * U235Enrichment)
472  / UO2MolecularWeight;
473  const G4double U238MassFraction = (U238->GetA() * U238Enrichment)
474  / UO2MolecularWeight;
475  const G4double oxygenMassFraction = (oxygen->GetA() * 2)
476  / UO2MolecularWeight;
477  // create the material and add the elements
478  fUO2_20E = new G4Material("UO2_20E", // name
479  10.97 * (g / cm3), // density
480  3); // number of components
481  fUO2_20E->AddElement(U235, // element
482  U235MassFraction); // mass fraction
483  fUO2_20E->AddElement(U238, // element
484  U238MassFraction); // mass fraction
485  fUO2_20E->AddElement(oxygen, // element
486  oxygenMassFraction); // mass fraction
487 
488  //
489  // Define the BF3
490  //
491  // The BF3 is B-10 enriched
492  // http://www.orau.org/ptp/collection/proportional%20counters/bf3info.htm
493  G4double const B10Enrichment = 0.96;
494  G4double const B11Enrichment = 0.04;
495  G4Isotope* const iB10
496  = new G4Isotope("iB10", // name
497  5, // ZZZ
498  10, // AAA
499  10.0129370 * (g / mole)); // molecular weight
500  G4Isotope* const iB11
501  = new G4Isotope("iB11", // name
502  5, // ZZZ
503  11, // AAA
504  11.0093054 * (g / mole)); // molecular weight
505  // Now create the elements and add the isotopes
506  G4Element* const B10
507  = new G4Element("B10", // name
508  "B10", // symbol
509  1); // number of isotopes
510  B10->AddIsotope(iB10, // isotope
511  1.0); // abundance
512  G4Element* const B11
513  = new G4Element("B11", // name
514  "B11", // symbol
515  1); // number of isotopes
516  B11->AddIsotope(iB11, // isotope
517  1.0); // abundance
518  G4Element* const flouride = nist->FindOrBuildElement("F");
519  // Calculate the mass fractions
520  const G4double BF3MolecularWeight = B10->GetA() * B10Enrichment
521  + B11->GetA() * B11Enrichment
522  + flouride->GetA() * 3;
523  const G4double B10MassFraction = (B10->GetA() * B10Enrichment)
524  / BF3MolecularWeight;
525  const G4double B11MassFraction = (B11->GetA() * B11Enrichment)
526  / BF3MolecularWeight;
527  const G4double flourideMassFraction = (flouride->GetA() * 3)
528  / BF3MolecularWeight;
529  // create the material and add the elements
530  fBF3_96E = new G4Material("BF3_96E", // name
531  2.5 * (kg / m3), // density
532  3); // number of components
533  fBF3_96E->AddElement(B10, // element
534  B10MassFraction); // mass fraction
535  fBF3_96E->AddElement(B11, // element
536  B11MassFraction); // mass fraction
537  fBF3_96E->AddElement(flouride, // element
538  flourideMassFraction); // mass fraction
539 }
540 
541 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
544  double y,
545  G4LogicalVolume* const myLogicalVolume,
546  G4LogicalVolume* const parentLogicalVolume)
547 {
548  char copyName[64];
549  G4ThreeVector position(x, y);
550 
551  sprintf(copyName,
552  "Plate@Location X:%.2f Y:%.2f",
553  x / inch,
554  y / inch);
555 
556  new G4PVPlacement(NULL, // no rotation
557  position, // position
558  myLogicalVolume, // the logical volume
559  copyName, // the name
560  parentLogicalVolume, // the mother volume
561  false, // no boolean ops
562  fCopyNumber++, // copy number
563  true); // check for overlaps
564 }
565 
566 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
569 {
570  // Nothing here
571 }
572 
573