Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/examples/advanced/fastAerosol/src/FADetectorConstruction.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  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 // (adapted from B1DetectorConstruction)
 28 // Author: A.Knaian (ara@nklabs.com), N.MacFadden (natemacfadden@gmail.com)
 29 
 30 #include "FADetectorConstruction.hh"
 31 #include "FADetectorConstructionMessenger.hh"
 32 
 33 #include "G4RunManager.hh"
 34 #include "G4NistManager.hh"
 35 
 36 #include "G4LogicalVolume.hh"
 37 #include "G4PVPlacement.hh"
 38 #include "G4SystemOfUnits.hh"
 39 
 40 // shapes
 41 #include "G4Box.hh"
 42 #include "G4Cons.hh"
 43 #include "G4Orb.hh"
 44 #include "G4Sphere.hh"
 45 #include "G4Trd.hh"
 46 #include "G4Tubs.hh"
 47 #include "G4Ellipsoid.hh"
 48 
 49 // to build FastAerosol cloud
 50 #include "FastAerosolSolid.hh"
 51 
 52 // to build parameterised cloud
 53 #include "FACloudParameterisation.hh"
 54 #include "G4PVParameterised.hh"
 55 #include <fstream>
 56 
 57 // step limits
 58 #include "G4UserLimits.hh"
 59 
 60 // visualization
 61 #include "G4VisAttributes.hh"
 62 #include "G4Colour.hh"
 63 
 64 // to save distribution
 65 #include <sys/stat.h>
 66 #include <ctime>    
 67 // for measuring FastAerosol droplet center population time
 68 
 69 DetectorConstruction::DetectorConstruction()
 70 : G4VUserDetectorConstruction(),
 71 fScoringVolume(nullptr)
 72 { 
 73 fMessenger = new DetectorConstructionMessenger(this);
 74 }
 75 
 76 DetectorConstruction::~DetectorConstruction()
 77 {
 78  delete fMessenger;
 79  delete fStepLimits;
 80  delete fCloudShape;
 81  delete fDropletShape;
 82  delete fCloud;
 83 }
 84 
 85 G4VPhysicalVolume* DetectorConstruction::Construct()
 86 {
 87  //
 88  // Check cloud build settings
 89  //
 90  if (fFastAerosolCloud + fParameterisedCloud + fSmoothCloud > 1)
 91  {
 92  std::ostringstream message;
 93   message << "Must select at most one build type! Selections:" << G4endl
 94     << "     fFastAerosolCloud = " << fFastAerosolCloud << G4endl
 95     << "     fParameterisedCloud = " << fParameterisedCloud << G4endl
 96     << "     fSmoothCloud = " << fSmoothCloud << G4endl;
 97      G4Exception("DetectorConstruction::Construct()", "GeomSolids0002",
 98           FatalException, message);
 99   }
100  //
101  // Get nist material manager
102  //
103  G4NistManager* nist = G4NistManager::Instance();
104  //
105  // Option to switch on/off checking of volumes overlaps
106  //
107  G4bool checkOverlaps = false;
108  //
109  // Large scale geometry dimensions
110  //
111  G4double cloud_sizeXY = 0.5*m;
112  G4double cloud_sizeZ = 5.0*m;
113 
114  G4double world_sizeXY = 1.1*(cloud_sizeXY);
115  G4double world_sizeZ= 1.1*(cloud_sizeZ);
116  //
117  // Cloud shape
118  //
119  if (fCloudShapeStr == "box")
120  {
121  G4cout << "Cloud shape = box" << G4endl;
122   fCloudShape = new G4Box("cloudShape", 0.5*cloud_sizeXY, 0.5*cloud_sizeXY, 0.5*cloud_sizeZ);
123  }
124  else if (fCloudShapeStr == "ellipsoid")
125  {
126    G4cout << "Cloud shape = ellipsoid" << G4endl;
127    fCloudShape = new G4Ellipsoid("cloudShape", 0.5*cloud_sizeXY, 0.5*cloud_sizeXY, 0.5*cloud_sizeZ, 0, 0);
128  }
129  else if (fCloudShapeStr == "cylinder")
130  {
131  G4cout << "Cloud shape = cylinder" << G4endl;
132   fCloudShape = new G4Tubs("cloudShape", 0.0, 0.5*cloud_sizeXY, 0.5*cloud_sizeZ, 0, 360*deg);
133   }
134  else if (fCloudShapeStr == "pipe")
135  {
136   G4cout << "Cloud shape = pipe" << G4endl;
137   fCloudShape = new G4Tubs("cloudShape", 0.25*cloud_sizeXY, 0.5*cloud_sizeXY, 0.5*cloud_sizeZ, 0, 360.*deg);
138  }
139  else
140  {
141   std::ostringstream message;
142   message << "Invalid cloud shape = " << fCloudShapeStr << "!";
143   G4Exception("DetectorConstruction::Construct()", "GeomSolids0002",
144   FatalException, message);
145   }
146 
147  //
148  // Droplet Shape
149  //
150 
151 // The difference in radii of the maximal sphere (centered at the origin) contained in the droplet and the minimal sphere (centered at the origin) containing the droplet
152  G4double sphericalUncertainty = 0.0;
153  if (fDropletShapeStr == "sphere")
154  {
155   G4cout << "Droplet shape = sphere" << G4endl;
156   fDropletShape = new G4Orb("dropletSV", fDropletR);
157   sphericalUncertainty = 0.0;
158  }
159  else if (fDropletShapeStr == "halfSphere")
160  {
161   G4cout << "Droplet shape = halfSphere" << G4endl;
162   fDropletShape = new G4Sphere("dropletSV", 0.0, fDropletR,                 0.0, 180.*deg, 0.0, 180.*deg);
163   sphericalUncertainty = fDropletR;
164  }
165  else if (fDropletShapeStr == "cylinder")
166  {
167   G4cout << "Droplet shape = cylinder" << G4endl;
168   fDropletShape = new G4Tubs("dropletSV", 0, fDropletR/std::sqrt(3), fDropletR/std::sqrt(3), 0, 360.*deg);
169   sphericalUncertainty = fDropletR*(1-1/std::sqrt(3));
170  }
171  else if (fDropletShapeStr == "box")
172  {
173   G4cout << "Droplet shape = box" << G4endl;
174   fDropletShape = new G4Box("dropletSV", fDropletR/std::sqrt(3), fDropletR/std::sqrt(3), fDropletR/std::sqrt(3));
175   sphericalUncertainty = fDropletR*(1-1/std::sqrt(3));
176  }
177  else
178  {
179   std::ostringstream message;
180    message << "Invalid droplet shape = " << fCloudShapeStr << "!";
181     G4Exception("DetectorConstruction::Construct()", "GeomSolids0002",
182           FatalException, message);
183   }
184 
185 //
186 // Materials
187 //
188 // Compute the density of air at 14 km using the Barometric formula
189 // see, e.g., https://en.wikipedia.org/wiki/Density_of_air
190 G4double h = 14.0*km;
191 G4double p0 = 101325*hep_pascal;
192 G4double T0 = 288.15*kelvin;
193 G4double grav = 9.80665*m/(s*s);
194 G4double La = 0.0065*kelvin/m;
195 G4double R = 8.31447*joule/(mole*kelvin);
196 G4double M = 0.0289644*kg/mole;
197 G4double T = T0 - La*h;
198 G4double p = p0*std::pow(1-La*h/T0,grav*M/(R*La));
199 G4double air_density = p*M/(R*T);
200 
201 // make materials and set densities
202 G4Material* air_mat = nist->BuildMaterialWithNewDensity("Atmosphere","G4_AIR",air_density);
203 G4Material* water_mat = nist->FindOrBuildMaterial("G4_WATER");
204 
205 G4double water_density = water_mat->GetDensity();
206 G4double ice_density = 0.9168*g/cm3;
207   
208 G4Material* ice_mat = new G4Material("Water ice ", ice_density, 1, kStateSolid, T, p);
209 ice_mat->AddMaterial(water_mat, 1.);
210 
211 //
212 // Droplets
213 //
214 G4double droplet_density = water_density;
215 G4Material* droplet_mat = water_mat;
216 
217 G4double droplet_count = fDropletNumDens*(fCloudShape->GetCubicVolume());
218 
219 G4double droplet_volume = fDropletShape->GetCubicVolume();
220 G4double droplet_total_volume = droplet_count*droplet_volume;
221 
222 G4double droplet_total_mass =  droplet_total_volume*droplet_density;
223 
224 //
225 // Cloud macroscopic quantities
226 //
227 G4double cloud_volume = fCloudShape->GetCubicVolume();
228 G4double cloud_air_volume = cloud_volume - droplet_total_volume;
229 G4double cloud_air_mass = air_density*cloud_air_volume;
230 
231 //
232 // Step limit
233 //
234 fStepLimits = new G4UserLimits(fStepLim);
235 
236 //
237 // Build world
238 //
239 G4Box* solidWorld =new G4Box("World",//its name
240             0.5*world_sizeXY,//half x-span
241             0.5*world_sizeXY,//half y-span
242             0.5*world_sizeZ);//half z-span
243 
244 G4LogicalVolume* logicWorld =            
245     new G4LogicalVolume(solidWorld, //its solid
246                         air_mat, //its material
247                         "World");//its name
248 
249 logicWorld->SetUserLimits(fStepLimits);
250                    
251 G4VPhysicalVolume* physWorld = new G4PVPlacement(nullptr,//no rotation
252              G4ThreeVector(),//at (0,0,0)
253  logicWorld,//its logical volume
254  "World",//its name
255 nullptr,//its mothervolume
256 false,//no boolean operation             
257 0, //copy number
258 checkOverlaps); //overlaps checking
259 
260 //
261 // Build cloud
262 //
263 G4LogicalVolume* logicCloud;
264 
265 // **********************************************************
266 // 
267 // Build the cloud using the FastAerosol geometry class
268 // 
269 // ***********************************************************
270 
271 if (fFastAerosolCloud) 
272 {
273 G4cout << "\nFastAerosol geometry with n=" << fDropletNumDens*mm3 << "/mm3, r=" << fDropletR/mm << "mm spheres.\n" << G4endl;
274     
275 fCloud = new FastAerosol("cloud",                  fCloudShape,//cloud shape            
276 fDropletR, //bounding radius of droplets
277                    fMinSpacing,//minimum spacing between droplets
278                                  fDropletNumDens, //approximate number of droplets in cloud
279                    sphericalUncertainty); //uncertainty in distance to droplet surface from outside using just droplet's origin as info
280 fCloud->SetDropletsPerVoxel(4);
281 
282 FastAerosolSolid* solidCloud = new FastAerosolSolid("cloudSV",//its name                
283 fCloud, //its shape
284 fDropletShape); //its droplets
285 
286 solidCloud->SetStepLim(fStepLim);
287 //FastAerosol can use step limit to speed calculations
288 
289 logicCloud = new G4LogicalVolume(solidCloud,//its solid
290                            droplet_mat,//its material
291         "cloudLV");//its name
292 logicCloud->SetUserLimits(fStepLimits);
293 logicCloud->SetVisAttributes(G4VisAttributes(G4Colour(0.0,0.0,1.0,0.4)));
294 
295 new G4PVPlacement(nullptr, G4ThreeVector(), logicCloud,                 "cloudPV", //its name
296 logicWorld,//its mother volume
297 false, //no boolean operation
298 0,//copy number 
299 checkOverlaps);//overlaps checking
300 
301 fCloud->SetSeed(fCloudSeed);
302 
303 // fPrePopulate = whether to populate all voxels at the beginning or on the fly
304 if (fPrePopulate) 
305 {
306  // populate (proving it to the user by printing population reports)
307  clock_t t;
308  t = clock();
309 
310  G4cout << "\nBefore populating" << G4endl;
311  G4cout <<   "=================" << G4endl;
312  fCloud->PrintPopulationReport();
313  G4cout << "\nPopulating..." << G4endl;
314  fCloud->PopulateAllGrids();
315  G4cout << "\nAfter populating" << G4endl;
316  G4cout <<   "================" << G4endl;
317  fCloud->PrintPopulationReport();
318  G4cout << G4endl;
319 
320  t = clock() - t;
321 
322  G4cout << "\nThis took " << ((float)t)/CLOCKS_PER_SEC << "s\n" << G4endl;
323 
324  // make filename variables to save data
325  G4String rStr = std::to_string(fDropletR/mm);
326  rStr.erase ( rStr.find_last_not_of('0') + 1, std::string::npos );  // drop trailing 0
327  replace( rStr.begin(), rStr.end(), '.', 'p');
328  if (rStr.back() == 'p') { rStr.pop_back(); } // don't write "3p" for 3.0, just write "3"
329 
330  // want to represent the number density as 1E-ApB for some A, B
331 G4int order10 = (G4int) -round(10*std::log10(fDropletNumDens*mm3)); // gives 10x the exponent rounded to the int (10x so we get two decimals)
332 G4int leading = order10 / 10; // first number
333 G4int trailing = order10 % 10;  // second number
334 G4String nStr = "1E-" + std::to_string(leading) + "p" + std::to_string(trailing);   
335 
336 // save population time
337 std::ofstream file;
338 file.open("popTime_r" + rStr + "mm_n" + nStr + "mm-3.csv");
339 file << ((float)t)/CLOCKS_PER_SEC;
340 file.close();
341 
342 // save distribution
343 G4String fName = "distribution_r" + rStr + "mm_n" + nStr + "mm-3.csv";
344 fCloud->SaveToFile(fName);
345  }
346 }
347 // **********************************************************
348 // 
349 // (For comparision/benchmarking) Build the cloud using G4VParameterized (does not use FastAerosol)
350 // 
351 // ***********************************************************
352 // the droplet positions for this cloud are those saved in the "distribution" folder of our data
353 // this is to make comparable simulations between FastAerosol and parameterised clouds
354 // this requires that we first simulate FastAerosol (pre-populated) to generate the positions
355   
356 else if (fParameterisedCloud)
357  {
358  G4cout << "\nParameterised geometry with n=" << fDropletNumDens*mm3 << "/mm3 and r=" << fDropletR/mm << "mm spheres.\n" << G4endl;
359     std::vector<G4ThreeVector> positions;
360     G4double x,y,z;
361 
362  // load distribution file
363  G4String fName;
364  G4String rStr = std::to_string(fDropletR/mm);
365     rStr.erase ( rStr.find_last_not_of('0') + 1, std::string::npos ); // drop trailing 0
366     replace( rStr.begin(), rStr.end(), '.', 'p');
367     if (rStr.back() == 'p') { rStr.pop_back(); }  // don't write "3p" for 3.0, just write "3"
368 
369  // want to represent the number density as 1E-ApB for some A, B
370  G4int order10 = (G4int) -round(10*std::log10(fDropletNumDens*mm3));  // gives 10x the exponent rounded to the int (10x so we get two decimals)
371  G4int leading = order10 / 10;  // first number
372  G4int trailing = order10 % 10; // second number
373  G4String nStr = "1E-" + std::to_string(leading) + "p" + std::to_string(trailing);
374 
375  fName = "distribution_r" + rStr + "mm_n" + nStr + "mm-3.csv";
376  std::ifstream infile(fName);
377  std::string line;
378     
379  while (getline(infile,line)) {
380  std::istringstream stream(line);
381  std::string field;
382  getline(stream,field,','); x = stod(field)*mm;
383  getline(stream,field,','); y = stod(field)*mm;
384  getline(stream,field,','); z = stod(field)*mm;
385 
386  positions.push_back(G4ThreeVector(x,y,z));
387     }
388 
389  G4VPVParameterisation* cloudParam =
390       new CloudParameterisation(positions);
391 
392  G4Box* cloudBounding = new G4Box("cloudBounding",//its name
393                       0.5*cloud_sizeXY,//half x-span
394           0.5*cloud_sizeXY, //half y-span
395           0.5*cloud_sizeZ); //half z-span
396             
397  logicCloud = new G4LogicalVolume(cloudBounding,  //its solid
398               air_mat,//its material
399         "cloudLV");//its name
400 
401  logicCloud->SetSmartless(fSmartless);
402  logicCloud->SetUserLimits(fStepLimits);
403  logicCloud->SetVisAttributes(G4VisAttributes(false));
404 
405  new G4PVPlacement(nullptr,//no rotation
406        G4ThreeVector(),//at position
407        logicCloud,//its logical volume
408        "cloudPV",//its name
409        logicWorld,  //its mothervolume
410        false, //no boolean operation
411         0,//copy number
412        checkOverlaps);//overlaps checking
413 
414  G4LogicalVolume* logicDroplet = 
415       new G4LogicalVolume(fDropletShape,//its solid
416       droplet_mat,//its material
417       "dropletLV");//its name
418 
419  logicDroplet->SetUserLimits(fStepLimits);
420 
421  new G4PVParameterised("droplets",//its name
422       logicDroplet,//droplet logical volume
423       logicCloud,//mother logical volume    
424             kUndefined,//droplets placed along this axis
425             positions.size(),//number of droplets
426              cloudParam);//the parametrisation 
427  }
428 // **********************************************************
429 // 
430 // (For comparision/benchmarking) Simulate the cloud by smearing droplets out into a single solid (does not use FastAerosol)
431 // 
432 // ***********************************************************
433 else if (fSmoothCloud)  
434  {
435   G4cout << "\nSmooth geometry based on a cloud of n=" << fDropletNumDens*mm3 << "/mm3 and r=" << fDropletR/mm << "mm spheres.\n" << G4endl;
436 // build cloud by smearing the droplets uniformly across the cloud volume, for comparison/benchmarking purposes (does not use FastAerosol)
437 G4Material* cloud_mat = new G4Material("Cloud", (droplet_total_mass+cloud_air_mass)/cloud_volume, 2);
438 
439 cloud_mat->AddMaterial(droplet_mat, droplet_total_mass/(cloud_air_mass+droplet_total_mass));
440 
441 cloud_mat->AddMaterial(air_mat, cloud_air_mass/(cloud_air_mass+droplet_total_mass));
442               
443  logicCloud = new G4LogicalVolume(fCloudShape,  //its solid
444           cloud_mat,  //its material
445           "cloudLV"); //its name
446 
447  logicCloud->SetUserLimits(fStepLimits);
448  logicCloud->SetVisAttributes(G4VisAttributes(G4Colour(0.0,0.0,1.0,0.4)));
449            
450  new G4PVPlacement(nullptr, //no rotation
451        G4ThreeVector(), //at position
452        logicCloud,//its logical volume
453        "cloudPV", //its name
454         logicWorld, //its mothervolume
455               false,  //no boolean operation
456         0,//copy number
457         checkOverlaps); //overlaps checking
458  }
459  else
460  {
461  G4cout << "\nNo cloud.\n" << G4endl;
462  }  
463 
464  //
465  // Build detector
466  //
467  G4double detector_sizeXY = cloud_sizeXY;
468  G4double detector_sizeZ = 0.05*m;
469  G4Material* detector_mat = nist->FindOrBuildMaterial("G4_Al");
470  G4ThreeVector detector_pos = G4ThreeVector(0, 0, 0.5*1.05*cloud_sizeZ);
471 
472  G4Box* soldDetector =  new G4Box("detectorSV", //its name
473            0.5*detector_sizeXY, //half x-span
474            0.5*detector_sizeXY, //half y-span
475            0.5*detector_sizeZ); //half z-span
476             
477  G4LogicalVolume* logicDetector =            
478     new G4LogicalVolume(soldDetector, //its solid
479             detector_mat, //its material
480             "detectorLV");  //its name
481 
482  logicDetector->SetUserLimits(fStepLimits);
483          
484  new G4PVPlacement(nullptr,//no rotation
485        detector_pos,    //at position
486        logicDetector,   //its logical volume
487        "detectorPV",    //its name
488              logicWorld,      //its mothervolume
489        false,  //no boolean operation
490       0,  //copy number
491        checkOverlaps);    //overlaps checking
492 //
493 // Scoring Volume
494 //
495 fScoringVolume = logicDetector;
496 
497 return physWorld;
498 }
499 
500