Import Geant4 10.7.0.beta source tree

This commit is contained in:
Gabriele Cosmo
2020-06-26 10:23:25 +02:00
parent c02c370437
commit 67ba86d073
1871 changed files with 174422 additions and 131884 deletions
@@ -0,0 +1,59 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// (copied from B1ActionInitialization)
#include "FAActionInitialization.hh"
#include "FAPrimaryGeneratorAction.hh"
#include "FARunAction.hh"
#include "FAEventAction.hh"
#include "FASteppingAction.hh"
ActionInitialization::ActionInitialization()
: G4VUserActionInitialization()
{}
ActionInitialization::~ActionInitialization()
{}
void ActionInitialization::BuildForMaster() const
{
RunAction* runAction = new RunAction;
SetUserAction(runAction);
}
void ActionInitialization::Build() const
{
SetUserAction(new PrimaryGeneratorAction);
RunAction* runAction = new RunAction;
SetUserAction(runAction);
EventAction* eventAction = new EventAction(runAction);
SetUserAction(eventAction);
SetUserAction(new SteppingAction(eventAction));
}
@@ -0,0 +1,51 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// (adapted from B2bChamberParameterisation)
// Author: A.Knaian (ara@nklabs.com), N.MacFadden (natemacfadden@gmail.com)
#include "FACloudParameterisation.hh"
#include "G4VPhysicalVolume.hh"
#include "G4ThreeVector.hh"
#include "G4Sphere.hh"
#include "G4SystemOfUnits.hh"
CloudParameterisation::CloudParameterisation(
const std::vector<G4ThreeVector>& positions)
: G4VPVParameterisation()
{
fPositions = positions;
}
CloudParameterisation::~CloudParameterisation()
{ }
void CloudParameterisation::ComputeTransformation
(const G4int copyNo, G4VPhysicalVolume* physVol) const
{
physVol->SetTranslation(fPositions[copyNo]);
}
@@ -0,0 +1,561 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// (adapted from B1DetectorConstruction)
// Author: A.Knaian (ara@nklabs.com), N.MacFadden (natemacfadden@gmail.com)
#include "FADetectorConstruction.hh"
#include "FADetectorConstructionMessenger.hh"
#include "G4RunManager.hh"
#include "G4NistManager.hh"
#include "G4LogicalVolume.hh"
#include "G4PVPlacement.hh"
#include "G4SystemOfUnits.hh"
// shapes
#include "G4Box.hh"
#include "G4Cons.hh"
#include "G4Orb.hh"
#include "G4Sphere.hh"
#include "G4Trd.hh"
#include "G4Tubs.hh"
#include "G4Ellipsoid.hh"
// to build FastAerosol cloud
#include "FastAerosolSolid.hh"
// to build parameterised cloud
#include "FACloudParameterisation.hh"
#include "G4PVParameterised.hh"
#include <fstream>
// step limits
#include "G4UserLimits.hh"
// visualization
#include "G4VisAttributes.hh"
#include "G4Colour.hh"
// to save distribution
#include <sys/stat.h>
#include <ctime> // for measuring FastAerosol droplet center population time
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
DetectorConstruction::DetectorConstruction()
: G4VUserDetectorConstruction(),
fScoringVolume(0)
{
fMessenger = new DetectorConstructionMessenger(this);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
DetectorConstruction::~DetectorConstruction()
{
delete fMessenger;
delete fStepLimits;
delete fCloudShape;
delete fDropletShape;
delete fCloud;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4VPhysicalVolume* DetectorConstruction::Construct()
{
//
// Check cloud build settings
//
if (fFastAerosolCloud + fParameterisedCloud + fSmoothCloud > 1)
{
std::ostringstream message;
message << "Must select at most one build type! Selections:" << G4endl
<< " fFastAerosolCloud = " << fFastAerosolCloud << G4endl
<< " fParameterisedCloud = " << fParameterisedCloud << G4endl
<< " fSmoothCloud = " << fSmoothCloud << G4endl;
G4Exception("DetectorConstruction::Construct()", "GeomSolids0002",
FatalException, message);
}
//
// Get nist material manager
//
G4NistManager* nist = G4NistManager::Instance();
//
// Option to switch on/off checking of volumes overlaps
//
G4bool checkOverlaps = false;
//
// Large scale geometry dimensions
//
G4double cloud_sizeXY = 0.5*m;
G4double cloud_sizeZ = 5.0*m;
G4double world_sizeXY = 1.1*(cloud_sizeXY);
G4double world_sizeZ= 1.1*(cloud_sizeZ);
//
// Cloud shape
//
if (fCloudShapeStr == "box")
{
G4cout << "Cloud shape = box" << G4endl;
fCloudShape = new G4Box("cloudShape", 0.5*cloud_sizeXY, 0.5*cloud_sizeXY, 0.5*cloud_sizeZ);
}
else if (fCloudShapeStr == "ellipsoid")
{
G4cout << "Cloud shape = ellipsoid" << G4endl;
fCloudShape = new G4Ellipsoid("cloudShape", 0.5*cloud_sizeXY, 0.5*cloud_sizeXY, 0.5*cloud_sizeZ, 0, 0);
}
else if (fCloudShapeStr == "cylinder")
{
G4cout << "Cloud shape = cylinder" << G4endl;
fCloudShape = new G4Tubs("cloudShape", 0.0, 0.5*cloud_sizeXY, 0.5*cloud_sizeZ, 0, 360*deg);
}
else if (fCloudShapeStr == "pipe")
{
G4cout << "Cloud shape = pipe" << G4endl;
fCloudShape = new G4Tubs("cloudShape", 0.25*cloud_sizeXY, 0.5*cloud_sizeXY, 0.5*cloud_sizeZ, 0, 360.*deg);
}
else
{
std::ostringstream message;
message << "Invalid cloud shape = " << fCloudShapeStr << "!";
G4Exception("DetectorConstruction::Construct()", "GeomSolids0002",
FatalException, message);
}
//
// Droplet Shape
//
// 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
G4double sphericalUncertainty = 0.0;
if (fDropletShapeStr == "sphere")
{
G4cout << "Droplet shape = sphere" << G4endl;
fDropletShape = new G4Orb("dropletSV", fDropletR);
sphericalUncertainty = 0.0;
}
else if (fDropletShapeStr == "halfSphere")
{
G4cout << "Droplet shape = halfSphere" << G4endl;
fDropletShape = new G4Sphere("dropletSV", 0.0, fDropletR,
0.0, 180.*deg,
0.0, 180.*deg);
sphericalUncertainty = fDropletR;
}
else if (fDropletShapeStr == "cylinder")
{
G4cout << "Droplet shape = cylinder" << G4endl;
fDropletShape = new G4Tubs("dropletSV", 0, fDropletR/std::sqrt(3), fDropletR/std::sqrt(3), 0, 360.*deg);
sphericalUncertainty = fDropletR*(1-1/std::sqrt(3));
}
else if (fDropletShapeStr == "box")
{
G4cout << "Droplet shape = box" << G4endl;
fDropletShape = new G4Box("dropletSV", fDropletR/std::sqrt(3), fDropletR/std::sqrt(3), fDropletR/std::sqrt(3));
sphericalUncertainty = fDropletR*(1-1/std::sqrt(3));
}
else
{
std::ostringstream message;
message << "Invalid droplet shape = " << fCloudShapeStr << "!";
G4Exception("DetectorConstruction::Construct()", "GeomSolids0002",
FatalException, message);
}
//
// Materials
//
// Compute the density of air at 14 km using the Barometric formula
// see, e.g., https://en.wikipedia.org/wiki/Density_of_air
G4double h = 14.0*km;
G4double p0 = 101325*hep_pascal;
G4double T0 = 288.15*kelvin;
G4double grav = 9.80665*m/(s*s);
G4double La = 0.0065*kelvin/m;
G4double R = 8.31447*joule/(mole*kelvin);
G4double M = 0.0289644*kg/mole;
G4double T = T0 - La*h;
G4double p = p0*std::pow(1-La*h/T0,grav*M/(R*La));
G4double air_density = p*M/(R*T);
// make materials and set densities
G4Material* air_mat = nist->BuildMaterialWithNewDensity("Atmosphere","G4_AIR",air_density);
G4Material* water_mat = nist->FindOrBuildMaterial("G4_WATER");
G4double water_density = water_mat->GetDensity();
G4double ice_density = 0.9168*g/cm3;
G4Material* ice_mat = new G4Material("Water ice ", ice_density, 1, kStateSolid, T, p);
ice_mat->AddMaterial(water_mat, 1.);
//
// Droplets
//
G4double droplet_density = water_density;
G4Material* droplet_mat = water_mat;
G4double droplet_count = fDropletNumDens*(fCloudShape->GetCubicVolume());
G4double droplet_volume = fDropletShape->GetCubicVolume();
G4double droplet_total_volume = droplet_count*droplet_volume;
G4double droplet_total_mass = droplet_total_volume*droplet_density;
//
// Cloud macroscopic quantities
//
G4double cloud_volume = fCloudShape->GetCubicVolume();
G4double cloud_air_volume = cloud_volume - droplet_total_volume;
G4double cloud_air_mass = air_density*cloud_air_volume;
//
// Step limit
//
fStepLimits = new G4UserLimits(fStepLim);
//
// Build world
//
G4Box* solidWorld =
new G4Box("World", //its name
0.5*world_sizeXY, //half x-span
0.5*world_sizeXY, //half y-span
0.5*world_sizeZ); //half z-span
G4LogicalVolume* logicWorld =
new G4LogicalVolume(solidWorld, //its solid
air_mat, //its material
"World"); //its name
logicWorld->SetUserLimits(fStepLimits);
G4VPhysicalVolume* physWorld =
new G4PVPlacement(0, //no rotation
G4ThreeVector(), //at (0,0,0)
logicWorld, //its logical volume
"World", //its name
0, //its mothervolume
false, //no boolean operation
0, //copy number
checkOverlaps); //overlaps checking
//
// Build cloud
//
G4LogicalVolume* logicCloud;
// **********************************************************
//
// Build the cloud using the FastAerosol geometry class
//
// ***********************************************************
if (fFastAerosolCloud) {
G4cout << "\nFastAerosol geometry with n=" << fDropletNumDens*mm3 << "/mm3, r=" << fDropletR/mm << "mm spheres.\n" << G4endl;
fCloud = new FastAerosol("cloud",
fCloudShape, //cloud shape
fDropletR, //bounding radius of droplets
fMinSpacing, //minimum spacing between droplets
fDropletNumDens, //approximate number of droplets in cloud
sphericalUncertainty); //uncertainty in distance to droplet surface from outside using just droplet's origin as info
fCloud->SetDropletsPerVoxel(4);
/*
fCloud = new FastAerosol("fCloud",
fCloudShape, //cloud shape
fDropletR, //bounding radius of droplets
fMinSpacing, //minimum spacing between droplets
fDropletNumDens, //approximate number of droplets in cloud
sphericalUncertainty, //uncertainty in distance to droplet surface from outside using just droplet's origin as info
[](G4ThreeVector pos) {return pos.x();}); //number density distribution function
*/
FastAerosolSolid* solidCloud =
new FastAerosolSolid("cloudSV", //its name
fCloud, //its shape
fDropletShape); //its droplets
/*
FastAerosolSolid* solidCloud =
new FastAerosolSolid("cloudSV", //its name
fCloud, //its shape
fDropletShape, //its droplets
[](G4ThreeVector) {G4RotationMatrix rotm = G4RotationMatrix(); rotm.rotateY(90.0*deg); return rotm;}); //droplet rotation function
*/
solidCloud->SetStepLim(fStepLim); //FastAerosol can use step limit to speed calculations
logicCloud =
new G4LogicalVolume(solidCloud, //its solid
droplet_mat, //its material
"cloudLV"); //its name
logicCloud->SetUserLimits(fStepLimits);
logicCloud->SetVisAttributes(G4VisAttributes(G4Colour(0.0,0.0,1.0,0.4)));
new G4PVPlacement(0, //no rotation
G4ThreeVector(), //at position
logicCloud, //its logical volume
"cloudPV", //its name
logicWorld, //its mother volume
false, //no boolean operation
0, //copy number
checkOverlaps); //overlaps checking
fCloud->SetSeed(fCloudSeed);
// fPrePopulate = whether to populate all voxels at the beginning or on the fly
if (fPrePopulate) {
// populate (proving it to the user by printing population reports)
clock_t t;
t = clock();
G4cout << "\nBefore populating" << G4endl;
G4cout << "=================" << G4endl;
fCloud->PrintPopulationReport();
G4cout << "\nPopulating..." << G4endl;
fCloud->PopulateAllGrids();
G4cout << "\nAfter populating" << G4endl;
G4cout << "================" << G4endl;
fCloud->PrintPopulationReport();
G4cout << G4endl;
t = clock() - t;
G4cout << "\nThis took " << ((float)t)/CLOCKS_PER_SEC << "s\n" << G4endl;
// make filename variables to save data
G4String rStr = std::to_string(fDropletR/mm);
rStr.erase ( rStr.find_last_not_of('0') + 1, std::string::npos ); // drop trailing 0
replace( rStr.begin(), rStr.end(), '.', 'p');
if (rStr.back() == 'p') { rStr.pop_back(); } // don't write "3p" for 3.0, just write "3"
// want to represent the number density as 1E-ApB for some A, B
G4int order10 = (G4int) -round(10*std::log10(fDropletNumDens*mm3)); // gives 10x the exponent rounded to the int (10x so we get two decimals)
G4int leading = order10 / 10; // first number
G4int trailing = order10 % 10; // second number
G4String nStr = "1E-" + std::to_string(leading) + "p" + std::to_string(trailing);
// save population time
std::ofstream file;
file.open("popTime_r" + rStr + "mm_n" + nStr + "mm-3.csv");
file << ((float)t)/CLOCKS_PER_SEC;
file.close();
// save distribution
G4String fName = "distribution_r" + rStr + "mm_n" + nStr + "mm-3.csv";
fCloud->SaveToFile(fName);
}
}
// **********************************************************
//
// (For comparision/benchmarking) Build the cloud using G4VParameterized (does not use FastAerosol)
//
// ***********************************************************
// the droplet positions for this cloud are those saved in the "distribution" folder of our data
// this is to make comparable simulations between FastAerosol and parameterised clouds
// this requires that we first simulate FastAerosol (pre-populated) to generate the positions
else if (fParameterisedCloud)
{
G4cout << "\nParameterised geometry with n=" << fDropletNumDens*mm3 << "/mm3 and r=" << fDropletR/mm << "mm spheres.\n" << G4endl;
std::vector<G4ThreeVector> positions;
G4double x,y,z;
// load distribution file
G4String fName;
G4String rStr = std::to_string(fDropletR/mm);
rStr.erase ( rStr.find_last_not_of('0') + 1, std::string::npos ); // drop trailing 0
replace( rStr.begin(), rStr.end(), '.', 'p');
if (rStr.back() == 'p') { rStr.pop_back(); } // don't write "3p" for 3.0, just write "3"
// want to represent the number density as 1E-ApB for some A, B
G4int order10 = (G4int) -round(10*std::log10(fDropletNumDens*mm3)); // gives 10x the exponent rounded to the int (10x so we get two decimals)
G4int leading = order10 / 10; // first number
G4int trailing = order10 % 10; // second number
G4String nStr = "1E-" + std::to_string(leading) + "p" + std::to_string(trailing);
fName = "distribution_r" + rStr + "mm_n" + nStr + "mm-3.csv";
std::ifstream infile(fName);
std::string line;
while (getline(infile,line)) {
std::istringstream stream(line);
std::string field;
getline(stream,field,','); x = stod(field)*mm;
getline(stream,field,','); y = stod(field)*mm;
getline(stream,field,','); z = stod(field)*mm;
positions.push_back(G4ThreeVector(x,y,z));
}
G4VPVParameterisation* cloudParam =
new CloudParameterisation(positions);
G4Box* cloudBounding =
new G4Box("cloudBounding", //its name
0.5*cloud_sizeXY, //half x-span
0.5*cloud_sizeXY, //half y-span
0.5*cloud_sizeZ); //half z-span
logicCloud =
new G4LogicalVolume(cloudBounding, //its solid
air_mat, //its material
"cloudLV"); //its name
logicCloud->SetSmartless(fSmartless);
logicCloud->SetUserLimits(fStepLimits);
logicCloud->SetVisAttributes(G4VisAttributes(false));
new G4PVPlacement(0, //no rotation
G4ThreeVector(), //at position
logicCloud, //its logical volume
"cloudPV", //its name
logicWorld, //its mothervolume
false, //no boolean operation
0, //copy number
checkOverlaps); //overlaps checking
G4LogicalVolume* logicDroplet =
new G4LogicalVolume(fDropletShape, //its solid
droplet_mat, //its material
"dropletLV"); //its name
logicDroplet->SetUserLimits(fStepLimits);
/*G4PVParameterised* paramDroplet =*/
new G4PVParameterised("droplets", //its name
logicDroplet, //droplet logical volume
logicCloud, //mother logical volume
kUndefined, //droplets placed along this axis
positions.size(), //number of droplets
cloudParam); //the parametrisation
}
// **********************************************************
//
// (For comparision/benchmarking) Simulate the cloud by smearing droplets out into a single solid (does not use FastAerosol)
//
// ***********************************************************
else if (fSmoothCloud)
{
G4cout << "\nSmooth geometry based on a cloud of n=" << fDropletNumDens*mm3 << "/mm3 and r=" << fDropletR/mm << "mm spheres.\n" << G4endl;
// build cloud by smearing the droplets uniformly across the cloud volume, for comparison/benchmarking purposes (does not use FastAerosol)
G4Material* cloud_mat = new G4Material("Cloud", (droplet_total_mass+cloud_air_mass)/cloud_volume, 2);
cloud_mat->AddMaterial(droplet_mat, droplet_total_mass/(cloud_air_mass+droplet_total_mass));
cloud_mat->AddMaterial(air_mat, cloud_air_mass/(cloud_air_mass+droplet_total_mass));
logicCloud =
new G4LogicalVolume(fCloudShape, //its solid
cloud_mat, //its material
"cloudLV"); //its name
logicCloud->SetUserLimits(fStepLimits);
logicCloud->SetVisAttributes(G4VisAttributes(G4Colour(0.0,0.0,1.0,0.4)));
new G4PVPlacement(0, //no rotation
G4ThreeVector(), //at position
logicCloud, //its logical volume
"cloudPV", //its name
logicWorld, //its mothervolume
false, //no boolean operation
0, //copy number
checkOverlaps); //overlaps checking
}
else
{
G4cout << "\nNo cloud.\n" << G4endl;
}
//
// Build detector
//
G4double detector_sizeXY = cloud_sizeXY;
G4double detector_sizeZ = 0.05*m;
G4Material* detector_mat = nist->FindOrBuildMaterial("G4_Al");
G4ThreeVector detector_pos = G4ThreeVector(0, 0, 0.5*1.05*cloud_sizeZ);
G4Box* soldDetector =
new G4Box("detectorSV", //its name
0.5*detector_sizeXY, //half x-span
0.5*detector_sizeXY, //half y-span
0.5*detector_sizeZ); //half z-span
G4LogicalVolume* logicDetector =
new G4LogicalVolume(soldDetector, //its solid
detector_mat, //its material
"detectorLV"); //its name
logicDetector->SetUserLimits(fStepLimits);
new G4PVPlacement(0, //no rotation
detector_pos, //at position
logicDetector, //its logical volume
"detectorPV", //its name
logicWorld, //its mothervolume
false, //no boolean operation
0, //copy number
checkOverlaps); //overlaps checking
//
// Scoring Volume
//
fScoringVolume = logicDetector;
return physWorld;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
@@ -0,0 +1,216 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// (adapted from B2aDetectorMessenger)
// Author: A.Knaian (ara@nklabs.com), N.MacFadden (natemacfadden@gmail.com)
#include "FADetectorConstructionMessenger.hh"
#include "FADetectorConstruction.hh"
#include "G4UIcmdWithAnInteger.hh"
#include "G4UIcmdWithADoubleAndUnit.hh"
#include "G4UIcmdWithADouble.hh"
#include "G4UIcmdWithABool.hh"
#include "G4UIcmdWithAString.hh"
DetectorConstructionMessenger::DetectorConstructionMessenger(DetectorConstruction* detectorIn)
: G4UImessenger()
{
fDetector = detectorIn;
// Directory
//
// /geometry
fGeometryDirectory = new G4UIdirectory("/geometry/");
fGeometryDirectory->SetGuidance("Geometry setup.");
// Physics
//
// /geometry/stepLim
fStepLimCmd = new G4UIcmdWithADoubleAndUnit("/geometry/stepLim",this);
fStepLimCmd->SetGuidance("Maximum step length.");
fStepLimCmd->SetParameterName("stepLim",false);
fStepLimCmd->SetRange("stepLim>=0.");
fStepLimCmd->SetDefaultValue(DBL_MAX);
fStepLimCmd->SetDefaultUnit("mm");
fStepLimCmd->AvailableForStates(G4State_PreInit);
// Cloud droplet settings
// /geometry/dropletR
fDropletRCmd = new G4UIcmdWithADoubleAndUnit("/geometry/dropletR",this);
fDropletRCmd->SetGuidance("Minimal bounding radius of droplet.");
fDropletRCmd->SetParameterName("dropletR",false);
fDropletRCmd->SetRange("dropletR>0.");
fDropletRCmd->SetDefaultValue(1.0);
fDropletRCmd->SetDefaultUnit("mm");
fDropletRCmd->AvailableForStates(G4State_PreInit);
// /geometry/dropletNumDens
fDropletNumDensCmd = new G4UIcmdWithADouble("/geometry/dropletNumDens", this);
fDropletNumDensCmd->SetGuidance("Number of droplets per mm^3."); // would be nice to have official number density units
fDropletNumDensCmd->SetParameterName("dropletCOunt",false);
fDropletNumDensCmd->SetDefaultValue(0);
fDropletNumDensCmd->AvailableForStates(G4State_PreInit);
// Cloud build type
//
// /geometry/fastAerosol
fFastAerosolCloudCmd = new G4UIcmdWithABool("/geometry/fastAerosolCloud",this);
fFastAerosolCloudCmd->SetGuidance("Whether or not to build the fastAerosol cloud.");
fFastAerosolCloudCmd->SetParameterName("fastAerosol",false);
fFastAerosolCloudCmd->SetDefaultValue(false);
fFastAerosolCloudCmd->AvailableForStates(G4State_PreInit);
// /geometry/parameterisedCloud
fParameterisedCloudCmd = new G4UIcmdWithABool("/geometry/parameterisedCloud",this);
fParameterisedCloudCmd->SetGuidance("Whether or not to build the parameterised cloud.");
fParameterisedCloudCmd->SetParameterName("parameterisedCloud",false);
fParameterisedCloudCmd->SetDefaultValue(false);
fParameterisedCloudCmd->AvailableForStates(G4State_PreInit);
// /geometry/smoothCloud
fSmoothCloudCmd = new G4UIcmdWithABool("/geometry/smoothCloud",this);
fSmoothCloudCmd->SetGuidance("Whether or not to build the smooth cloud.");
fSmoothCloudCmd->SetParameterName("smoothCloud",false);
fSmoothCloudCmd->SetDefaultValue(false);
fSmoothCloudCmd->AvailableForStates(G4State_PreInit);
// fastAerosol cloud details
//
// /geometry/cloudShape
fCloudShapeCmd = new G4UIcmdWithAString("/geometry/cloudShape",this);
fCloudShapeCmd->SetGuidance("Cloud bulk shape");
fCloudShapeCmd->SetParameterName("cloudShapeStr",false);
fCloudShapeCmd->AvailableForStates(G4State_PreInit);
// /geometry/dropletShape
fDropletShapeCmd = new G4UIcmdWithAString("/geometry/dropletShape",this);
fDropletShapeCmd->SetGuidance("Cloud droplet shape");
fDropletShapeCmd->SetParameterName("dropletShapeStr",false);
fDropletShapeCmd->AvailableForStates(G4State_PreInit);
// /geometry/prePopulate
fPrePopulateCmd = new G4UIcmdWithABool("/geometry/prePopulate",this);
fPrePopulateCmd->SetGuidance("Whether or not to populate the cloud at the beginning.");
fPrePopulateCmd->SetParameterName("prePopulate",false);
fPrePopulateCmd->SetDefaultValue(false);
fPrePopulateCmd->AvailableForStates(G4State_PreInit);
// /geometry/minSpacing
fMinSpacingCmd = new G4UIcmdWithADoubleAndUnit("/geometry/minSpacing",this);
fMinSpacingCmd->SetGuidance("Minimum spacing between surfaces of spheres when generating random cloud of spheres.");
fMinSpacingCmd->SetParameterName("minSpacing",false);
fMinSpacingCmd->SetRange("minSpacing>0.");
fMinSpacingCmd->SetDefaultValue(10.);
fMinSpacingCmd->SetDefaultUnit("micrometer");
fMinSpacingCmd->AvailableForStates(G4State_PreInit);
// /geometry/setSmartless
fSmartlessCmd = new G4UIcmdWithADouble("/geometry/smartless", this);
fSmartlessCmd->SetGuidance("Set the 'smartless' parameter for the parameterised cloud.");
fSmartlessCmd->SetParameterName("smartless",false);
fSmartlessCmd->SetRange("smartless>0.");
fSmartlessCmd->SetDefaultValue(2.0);
fSmartlessCmd->AvailableForStates(G4State_PreInit);
// /geometry/cloudSeed
fCloudSeedCmd = new G4UIcmdWithAnInteger("/geometry/cloudSeed", this);
fCloudSeedCmd->SetGuidance("Base of the random seed for the cloud sphere positions.");
fCloudSeedCmd->SetParameterName("cloudSeed",false);
fCloudSeedCmd->SetDefaultValue(0);
fCloudSeedCmd->AvailableForStates(G4State_PreInit);
}
DetectorConstructionMessenger::~DetectorConstructionMessenger()
{
delete fGeometryDirectory;
delete fStepLimCmd;
delete fDropletRCmd;
delete fDropletNumDensCmd;
delete fFastAerosolCloudCmd;
delete fParameterisedCloudCmd;
delete fSmoothCloudCmd;
delete fCloudShapeCmd;
delete fDropletShapeCmd;
delete fPrePopulateCmd;
delete fMinSpacingCmd;
//delete fGridPitchCmd;
delete fSmartlessCmd;
delete fCloudSeedCmd;
}
void DetectorConstructionMessenger::SetNewValue( G4UIcommand* command, G4String newValue)
{
// Geometry Commands
if( command == fFastAerosolCloudCmd ) {
fDetector->fFastAerosolCloud = (fFastAerosolCloudCmd->GetNewBoolValue(newValue));
}
if( command == fStepLimCmd ) {
fDetector->fStepLim = (fStepLimCmd->GetNewDoubleValue(newValue));
}
if( command == fDropletRCmd ) {
fDetector->fDropletR = (fDropletRCmd->GetNewDoubleValue(newValue));
}
if( command == fDropletNumDensCmd ) {
fDetector->fDropletNumDens = (fDropletNumDensCmd->GetNewDoubleValue(newValue));
}
if( command == fParameterisedCloudCmd ) {
fDetector->fParameterisedCloud = (fParameterisedCloudCmd->GetNewBoolValue(newValue));
}
if( command == fSmoothCloudCmd ) {
fDetector->fSmoothCloud = (fSmoothCloudCmd->GetNewBoolValue(newValue));
}
if( command == fPrePopulateCmd ) {
fDetector->fPrePopulate = (fPrePopulateCmd->GetNewBoolValue(newValue));
}
if( command == fCloudShapeCmd ) {
fDetector->fCloudShapeStr = newValue;
}
if( command == fDropletShapeCmd ) {
fDetector->fDropletShapeStr = newValue;
}
if( command == fMinSpacingCmd ) {
fDetector->fMinSpacing = (fMinSpacingCmd->GetNewDoubleValue(newValue));
}
if( command == fSmartlessCmd ) {
fDetector->fSmartless = (fSmartlessCmd->GetNewDoubleValue(newValue));
}
if( command == fCloudSeedCmd ) {
fDetector->fCloudSeed = (fCloudSeedCmd->GetNewIntValue(newValue));
}
}
@@ -0,0 +1,52 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// (copied from B1EventAction)
#include "FAEventAction.hh"
#include "FARunAction.hh"
#include "G4Event.hh"
#include "G4RunManager.hh"
EventAction::EventAction(RunAction* runAction)
: G4UserEventAction(),
fRunAction(runAction),
fEdep(0.)
{}
EventAction::~EventAction()
{}
void EventAction::BeginOfEventAction(const G4Event*)
{
fEdep = 0.;
}
void EventAction::EndOfEventAction(const G4Event*)
{
// accumulate statistics in run action
fRunAction->AddEdep(fEdep);
}
@@ -0,0 +1,99 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// (adapted from B1PrimaryGeneratorAction)
// Author: A.Knaian (ara@nklabs.com), N.MacFadden (natemacfadden@gmail.com)
#include "FAPrimaryGeneratorAction.hh"
#include "G4LogicalVolumeStore.hh"
#include "G4LogicalVolume.hh"
#include "G4Box.hh"
#include "G4RunManager.hh"
#include "G4ParticleGun.hh"
#include "G4ParticleTable.hh"
#include "G4ParticleDefinition.hh"
#include "G4SystemOfUnits.hh"
#include "Randomize.hh"
PrimaryGeneratorAction::PrimaryGeneratorAction()
: G4VUserPrimaryGeneratorAction(),
fParticleGun(0),
fWorldBox(0)
{
G4int n_particle = 1;
fParticleGun = new G4ParticleGun(n_particle);
// default particle kinematic
G4ParticleTable* particleTable = G4ParticleTable::GetParticleTable();
G4String particleName;
G4ParticleDefinition* particle
= particleTable->FindParticle(particleName="proton");
fParticleGun->SetParticleDefinition(particle);
fParticleGun->SetParticleMomentumDirection(G4ThreeVector(0.,0.,1.));
fParticleGun->SetParticleEnergy(50.*MeV);
}
PrimaryGeneratorAction::~PrimaryGeneratorAction()
{
delete fParticleGun;
}
void PrimaryGeneratorAction::GeneratePrimaries(G4Event* anEvent)
{
G4double worldSizeXY = 0;
G4double worldSizeZ = 0;
if (!fWorldBox)
{
G4LogicalVolume* worldLV
= G4LogicalVolumeStore::GetInstance()->GetVolume("World");
if ( worldLV ) fWorldBox = dynamic_cast<G4Box*>(worldLV->GetSolid());
}
if ( fWorldBox ) {
worldSizeXY = fWorldBox->GetXHalfLength()*2.;
worldSizeZ = fWorldBox->GetZHalfLength()*2.;
}
else {
G4ExceptionDescription msg;
msg << "World volume of box shape not found.\n";
msg << "Perhaps you have changed geometry.\n";
msg << "The gun will be place at the center.";
G4Exception("PrimaryGeneratorAction::GeneratePrimaries()",
"MyCode0002",JustWarning,msg);
}
// shoot on XY disk centered on Z-axis behind the cloud
G4double sigma = worldSizeXY/10.0; // spread in x and y
G4double x0 = G4RandGauss::shoot(0,sigma);
G4double y0 = G4RandGauss::shoot(0,sigma);
G4double z0 = 0.95 * (-0.5) * worldSizeZ;
fParticleGun->SetParticlePosition(G4ThreeVector(x0,y0,z0));
fParticleGun->GeneratePrimaryVertex(anEvent);
}
@@ -0,0 +1,148 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// (copied from B1RunAction)
#include "FARunAction.hh"
#include "FAPrimaryGeneratorAction.hh"
#include "FADetectorConstruction.hh"
#include "G4RunManager.hh"
#include "G4Run.hh"
#include "G4AccumulableManager.hh"
#include "G4LogicalVolumeStore.hh"
#include "G4LogicalVolume.hh"
#include "G4UnitsTable.hh"
#include "G4SystemOfUnits.hh"
RunAction::RunAction()
: G4UserRunAction(),
fEdep(0.),
fEdep2(0.)
{
// add new units for dose
//
const G4double milligray = 1.e-3*gray;
const G4double microgray = 1.e-6*gray;
const G4double nanogray = 1.e-9*gray;
const G4double picogray = 1.e-12*gray;
new G4UnitDefinition("milligray", "milliGy" , "Dose", milligray);
new G4UnitDefinition("microgray", "microGy" , "Dose", microgray);
new G4UnitDefinition("nanogray" , "nanoGy" , "Dose", nanogray);
new G4UnitDefinition("picogray" , "picoGy" , "Dose", picogray);
// Register accumulable to the accumulable manager
G4AccumulableManager* accumulableManager = G4AccumulableManager::Instance();
accumulableManager->RegisterAccumulable(fEdep);
accumulableManager->RegisterAccumulable(fEdep2);
}
RunAction::~RunAction()
{}
void RunAction::BeginOfRunAction(const G4Run*)
{
// inform the runManager to save random number seed
G4RunManager::GetRunManager()->SetRandomNumberStore(false);
// reset accumulables to their initial values
G4AccumulableManager* accumulableManager = G4AccumulableManager::Instance();
accumulableManager->Reset();
}
void RunAction::EndOfRunAction(const G4Run* run)
{
G4int nofEvents = run->GetNumberOfEvent();
if (nofEvents == 0) return;
// Merge accumulables
G4AccumulableManager* accumulableManager = G4AccumulableManager::Instance();
accumulableManager->Merge();
// Compute dose = total energy deposit in a run and its variance
//
G4double edep = fEdep.GetValue();
G4double edep2 = fEdep2.GetValue();
G4double rms = edep2 - edep*edep/nofEvents;
if (rms > 0.) rms = std::sqrt(rms); else rms = 0.;
const DetectorConstruction* detectorConstruction
= static_cast<const DetectorConstruction*>
(G4RunManager::GetRunManager()->GetUserDetectorConstruction());
G4double mass = detectorConstruction->GetScoringVolume()->GetMass();
G4double dose = edep/mass;
G4double rmsDose = rms/mass;
// Run conditions
// note: There is no primary generator action object for "master"
// run manager for multi-threaded mode.
const PrimaryGeneratorAction* generatorAction
= static_cast<const PrimaryGeneratorAction*>
(G4RunManager::GetRunManager()->GetUserPrimaryGeneratorAction());
G4String runCondition;
if (generatorAction)
{
const G4ParticleGun* particleGun = generatorAction->GetParticleGun();
runCondition += particleGun->GetParticleDefinition()->GetParticleName();
runCondition += " of ";
G4double particleEnergy = particleGun->GetParticleEnergy();
runCondition += G4BestUnit(particleEnergy,"Energy");
}
// Print
//
if (IsMaster()) {
G4cout
<< G4endl
<< "--------------------End of Global Run-----------------------";
}
else {
G4cout
<< G4endl
<< "--------------------End of Local Run------------------------";
}
G4cout
<< G4endl
<< " The run consists of " << nofEvents << " "<< runCondition
<< G4endl
<< " Cumulated dose per run, in scoring volume : "
<< G4BestUnit(dose,"Dose") << " rms = " << G4BestUnit(rmsDose,"Dose")
<< G4endl
<< "------------------------------------------------------------"
<< G4endl
<< G4endl;
}
void RunAction::AddEdep(G4double edep)
{
fEdep += edep;
fEdep2 += edep*edep;
}
@@ -0,0 +1,69 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// (copied from B1SteppingAction)
#include "FASteppingAction.hh"
#include "FAEventAction.hh"
#include "FADetectorConstruction.hh"
#include "G4Step.hh"
#include "G4Event.hh"
#include "G4RunManager.hh"
#include "G4LogicalVolume.hh"
SteppingAction::SteppingAction(EventAction* eventAction)
: G4UserSteppingAction(),
fEventAction(eventAction),
fScoringVolume(0)
{}
SteppingAction::~SteppingAction()
{}
void SteppingAction::UserSteppingAction(const G4Step* step)
{
if (!fScoringVolume) {
const DetectorConstruction* detectorConstruction
= static_cast<const DetectorConstruction*>
(G4RunManager::GetRunManager()->GetUserDetectorConstruction());
fScoringVolume = detectorConstruction->GetScoringVolume();
}
// get volume of the current step
G4LogicalVolume* volume
= step->GetPreStepPoint()->GetTouchableHandle()
->GetVolume()->GetLogicalVolume();
// check if we are in scoring volume
if (volume != fScoringVolume) return;
// collect energy deposited in this step
G4double edepStep = step->GetTotalEnergyDeposit();
fEventAction->AddEdep(edepStep);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,456 @@
//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// --------------------------------------------------------------------
// Implementation for FastAerosolSolid class
// Author: A.Knaian (ara@nklabs.com), N.MacFadden (natemacfadden@gmail.com)
// --------------------------------------------------------------------
#include "FastAerosolSolid.hh"
#include "G4SystemOfUnits.hh"
// calculate extent
#include "G4BoundingEnvelope.hh"
#include "G4AffineTransform.hh"
#include "G4VoxelLimits.hh"
// visualization
#include "G4VGraphicsScene.hh"
#include "G4VisExtent.hh"
// polyhedron
#include "G4AutoLock.hh"
#include "G4Polyhedron.hh"
#include "HepPolyhedronProcessor.h"
namespace
{
G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
}
///////////////////////////////////////////////////////////////////////////////
//
// Constructor
//
FastAerosolSolid::FastAerosolSolid(const G4String& pName,
FastAerosol* pCloud,
G4VSolid* pDroplet,
std::function<G4RotationMatrix (G4ThreeVector)> pRotation)
: G4VSolid(pName), fCloud(pCloud), fDroplet(pDroplet), fRotation(pRotation), fRebuildPolyhedron(false), fpPolyhedron(0)
{
// Get cloud size from fCloud
G4ThreeVector cloudPMin, cloudPMax;
fCloud->GetBoundingLimits(cloudPMin, cloudPMax);
fVisDx = cloudPMax.x();
fVisDy = cloudPMax.y();
fVisDz = cloudPMax.z();
// Check and set droplet radius
G4double pR = fCloud->GetRadius();
// would be nice to add a check to make sure pDroplet fits in sphere of radius pR
fR = pR;
fBulk = fCloud->GetBulk();
farFromCloudDist = fCloud->GetPreSphereR()*fR;
}
///////////////////////////////////////////////////////////////////////////////
//
// Alternative constructor (constant rotation function)
//
FastAerosolSolid::FastAerosolSolid(const G4String& pName,
FastAerosol* pCloud,
G4VSolid* pDroplet):
FastAerosolSolid(pName, pCloud, pDroplet,
[](G4ThreeVector) {return G4RotationMatrix();})
{}
///////////////////////////////////////////////////////////////////////////////
//
// Fake default constructor - sets only member data and allocates memory
// for usage restricted to object persistency.
//
FastAerosolSolid::FastAerosolSolid( __void__& a )
: G4VSolid(a), fCloud(nullptr), fDroplet(nullptr),
fBulk(nullptr), fR(0.),
fVisDx(0.), fVisDy(0.), fVisDz(0.),
fCubicVolume(0.), fSurfaceArea(0.),
farFromCloudDist(0.),
fRotation([](G4ThreeVector) {return G4RotationMatrix();}),
fRebuildPolyhedron(false), fpPolyhedron(0)
{
}
///////////////////////////////////////////////////////////////////////////////
//
// Destructor
//
FastAerosolSolid::~FastAerosolSolid() {
}
///////////////////////////////////////////////////////////////////////////////
//
// Copy constructor
//
FastAerosolSolid::FastAerosolSolid(const FastAerosolSolid &rhs)
: G4VSolid(rhs), fCloud(rhs.fCloud), fDroplet(rhs.fDroplet),
fBulk(rhs.fBulk), fR(rhs.fR),
fVisDx(rhs.fVisDx), fVisDy(rhs.fVisDy), fVisDz(rhs.fVisDz),
fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
farFromCloudDist(rhs.farFromCloudDist),
fRotation(rhs.fRotation),
fRebuildPolyhedron(rhs.fRebuildPolyhedron), fpPolyhedron(rhs.fpPolyhedron)
{
}
//////////////////////////////////////////////////////////////////////////
//
// Assignment operator
//
FastAerosolSolid &FastAerosolSolid::operator = (const FastAerosolSolid &rhs)
{
// Check assignment to self
//
if (this == &rhs)
{
return *this;
}
// Copy base class data
//
G4VSolid::operator=(rhs);
// Copy data
//
fCloud = rhs.fCloud;
fDroplet = rhs.fDroplet;
fBulk = rhs.fBulk;
fR = rhs.fR;
fVisDx = rhs.fVisDx;
fVisDy = rhs.fVisDy;
fVisDz = rhs.fVisDz;
fCubicVolume = rhs.fCubicVolume;
fSurfaceArea = rhs.fSurfaceArea;
farFromCloudDist = rhs.farFromCloudDist;
fRotation = rhs.fRotation;
fRebuildPolyhedron = rhs.fRebuildPolyhedron;
fpPolyhedron = rhs.fpPolyhedron;
return *this;
}
///////////////////////////////////////////////////////////////////////////////
//
// Calculate extent under transform and specified limit
//
G4bool FastAerosolSolid::CalculateExtent(const EAxis pAxis,
const G4VoxelLimits &pVoxelLimit,
const G4AffineTransform &pTransform,
G4double &pMin, G4double &pMax) const
{
// Get smallest box to fully contain the cloud of objects, not just the centers
//
G4ThreeVector bmin, bmax;
fCloud->GetBoundingLimits(bmin, bmax);
// Find extent
//
G4BoundingEnvelope bbox(bmin, bmax);
return bbox.CalculateExtent(pAxis, pVoxelLimit, pTransform, pMin, pMax);
}
///////////////////////////////////////////////////////////////////////////////
//
// Return whether point inside/outside/on surface
//
// This function assumes the cloud has at least 1 droplet
//
EInside FastAerosolSolid::Inside(const G4ThreeVector &p) const
{
G4ThreeVector center;
G4double closestDistance;
fCloud->GetNearestDroplet(p, center, closestDistance, fR, fDroplet, fRotation);
if (closestDistance==0.0)
{
G4RotationMatrix irotm = fRotation(center).inverse();
return fDroplet->Inside( irotm*(p - center) );
}
else
{
return kOutside;
}
}
/////////////////////////////////////////////////////////////////////
//
// Return unit normal of surface closest to p
//
// This function assumes the cloud has at least 1 droplet
//
G4ThreeVector FastAerosolSolid::SurfaceNormal(const G4ThreeVector &p) const
{
G4ThreeVector center;
G4double closestDistance;
fCloud->GetNearestDroplet(p, center, closestDistance, DBL_MAX, fDroplet, fRotation);
G4RotationMatrix rotm = fRotation(center);
return rotm*( fDroplet->SurfaceNormal( rotm.inverse()*(p - center) ) );
}
///////////////////////////////////////////////////////////////////////////////
//
// Calculate distance to shape from outside, along normalised vector
//
// This CANNOT be an underestimate
//
G4double FastAerosolSolid::DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
{
G4ThreeVector center;
G4double closestDistance;
if (fCloud->GetNearestDroplet(p, v, center, closestDistance, fStepLim, fDroplet, fRotation)) // if we found a droplet within fStepLim of query
{
return closestDistance;
}
else if (fCloud->DistanceToCloud(p,v)<DBL_MAX) // if there is cloud in front of us
{
return 1.1*fStepLim;
}
else // flying away from cloud
{
return kInfinity;
}
}
//////////////////////////////////////////////////////////////////////
//
// Calculate distance (<= actual) to closest surface of shape from outside
//
// This function assumes the cloud has at least 1 droplet
//
// This can be an underestimate
//
G4double FastAerosolSolid::DistanceToIn(const G4ThreeVector &p) const
{
G4ThreeVector center;
G4double closestDistance;
G4double distanceToCloud = fBulk->DistanceToIn(p);
if (fBulk->Inside(p)==kOutside && distanceToCloud>=farFromCloudDist)
{
return distanceToCloud;
}
else if (fCloud->GetNearestDroplet(p, center, closestDistance, fStepLim, fDroplet, fRotation)) // if we found a droplet within fStepLim of query
{
return closestDistance;
}
else
{
return 1.1*fStepLim;
}
}
//////////////////////////////////////////////////////////////////////
//
// Calculate distance (<= actual) to closest surface of shape from inside
//
// Despite being a vector distance, we find the absolutely closest
// droplet to our point since we assume that p is in a droplet and p
// could be past the center
//
// This CANNOT be an underestimate
//
G4double FastAerosolSolid::DistanceToOut(const G4ThreeVector &p,
const G4ThreeVector &v,
const G4bool calcNorm,
G4bool *validNorm,
G4ThreeVector *n) const
{
G4ThreeVector center;
G4double distanceToIn; // should be 0
fCloud->GetNearestDroplet(p, center, distanceToIn, fR, fDroplet, fRotation); // if we call this function, must be inside and thus must have a droplet within fR
G4RotationMatrix rotm = fRotation(center);
G4RotationMatrix irotm = rotm.inverse();
G4ThreeVector relPos = irotm*(p-center);
if (fDroplet->Inside(relPos) == kOutside) // something went wrong... we should be inside
{
std::ostringstream message;
message << std::setprecision(15) << "The particle at point p = " << p/mm << "mm"
<< std::setprecision(15) << " called DistanceToOut(p,v) and found the closest droplet to be at center = " << center/mm << "mm"
<< " but p is outside the droplet!";
G4Exception("FastAerosolSolid::DistanceToOut()", "GeomSolids0002",
FatalErrorInArgument, message);
}
G4double dist = fDroplet->DistanceToOut(relPos, irotm*v, calcNorm, validNorm, n);
*n = rotm*(*n);
*validNorm = false; // even if droplet is convex, the aerosol isn't
return dist;
}
/////////////////////////////////////////////////////////////////////////
//
// Calculate distance (<=actual) to closest surface of shape from inside
//
// This can be an underestimate
//
G4double FastAerosolSolid::DistanceToOut(const G4ThreeVector &p) const
{
G4ThreeVector center;
G4double distanceToIn; // should be 0
fCloud->GetNearestDroplet(p, center, distanceToIn, fR, fDroplet, fRotation); // if we call this function, must be inside and thus must have a droplet within fR
G4RotationMatrix irotm = fRotation(center).inverse();
G4ThreeVector relPos = irotm*(p-center);
if (fDroplet->Inside(relPos) == kOutside) // something went wrong... we should be inside
{
std::ostringstream message;
message << "The particle at point p = " << p/mm << "mm"
<< " called DistanceToOut(p) and found the closest droplet to be at center = " << center/mm << "mm"
<< " but p is outside the droplet!";
G4Exception("FastAerosolSolid::DistanceToOut()", "GeomSolids0002",
FatalErrorInArgument, message);
}
return fDroplet->DistanceToOut(relPos);
}
//////////////////////////////////////////////////////////////////////////
//
// G4EntityType
//
G4GeometryType FastAerosolSolid::GetEntityType() const
{
return G4String("FastAerosolSolid");
}
//////////////////////////////////////////////////////////////////////////
//
// G4EntityType
//
G4VSolid* FastAerosolSolid::Clone() const
{
return new FastAerosolSolid(*this);
}
//////////////////////////////////////////////////////////////////////////
//
// Stream object contents to an output stream
//
std::ostream &FastAerosolSolid::StreamInfo(std::ostream &os) const
{
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << GetName() << " ***\n"
<< " ===================================================\n"
<< " Solid type: FastAerosolSolid\n"
<< " Parameters: \n"
<< " numDroplets: " << fCloud->GetNumDroplets() << "\n"
<< " fDroplet type: " << fDroplet->GetName() << "\n"
<< " fDroplet parameters: \n";
fDroplet->StreamInfo(os);
os << "-----------------------------------------------------------\n";
return os;
}
////////////////////////////////////////////////////////////////////////////////
//
// GetPointOnSurface
//
// Currently hardcoded to look at all droplets, not just the populated ones
//
G4ThreeVector FastAerosolSolid::GetPointOnSurface() const
{
G4ThreeVector center;
G4double closestDistance;
G4double fDx = fCloud->GetXHalfLength();
G4double fDy = fCloud->GetYHalfLength();
G4double fDz = fCloud->GetZHalfLength();
G4ThreeVector p(2.0*fDx*G4UniformRand(),2.0*fDy*G4UniformRand(),2.0*fDz*G4UniformRand());
p -= G4ThreeVector(fDx, fDy, fDz);
fCloud->GetNearestDroplet(p, center, closestDistance, DBL_MAX, fDroplet, fRotation);
return(center + fRotation(center)*fDroplet->GetPointOnSurface());
}
/////////////////////////////////////////////////////////////////////////////
//
// Methods for visualisation
//
void FastAerosolSolid::DescribeYourselfTo (G4VGraphicsScene& scene) const
{
scene.AddSolid(*this);
}
G4VisExtent FastAerosolSolid::GetExtent() const
{
return G4VisExtent (-fVisDx, fVisDx, -fVisDy, fVisDy, -fVisDz, fVisDz);
}
G4Polyhedron* FastAerosolSolid::CreatePolyhedron () const
{
return fBulk->CreatePolyhedron();
}
// copied from G4Ellipsoid
G4Polyhedron* FastAerosolSolid::GetPolyhedron () const
{
if (!fpPolyhedron ||
fRebuildPolyhedron ||
fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
fpPolyhedron->GetNumberOfRotationSteps())
{
G4AutoLock l(&polyhedronMutex);
delete fpPolyhedron;
fpPolyhedron = CreatePolyhedron();
fRebuildPolyhedron = false;
l.unlock();
}
return fpPolyhedron;
}