Geant4 Cross Reference |
1 // 1 // 2 // ******************************************* 2 // ******************************************************************** 3 // * License and Disclaimer 3 // * License and Disclaimer * 4 // * 4 // * * 5 // * The Geant4 software is copyright of th 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/ 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. 9 // * include a list of copyright holders. * 10 // * 10 // * * 11 // * Neither the authors of this software syst 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing fin 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warran 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assum 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitatio 16 // * for the full disclaimer and the limitation of liability. * 17 // * 17 // * * 18 // * This code implementation is the result 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboratio 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distri 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you ag 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publicati 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Sof 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************* 24 // ******************************************************************** 25 // 25 // 26 // 26 // 27 // 27 // 28 // << 28 // 29 ////////////////////////////////////////////// 29 //////////////////////////////////////////////////////////////////////// 30 // Optical Photon Rayleigh Scattering Class Im 30 // Optical Photon Rayleigh Scattering Class Implementation 31 ////////////////////////////////////////////// 31 //////////////////////////////////////////////////////////////////////// 32 // 32 // 33 // File: G4OpRayleigh.cc 33 // File: G4OpRayleigh.cc 34 // Description: Discrete Process -- Rayleigh s 34 // Description: Discrete Process -- Rayleigh scattering of optical 35 // photons 35 // photons 36 // Version: 1.0 36 // Version: 1.0 37 // Created: 1996-05-31 37 // Created: 1996-05-31 38 // Author: Juliet Armstrong 38 // Author: Juliet Armstrong 39 // Updated: 2014-10-10 - This version cal << 39 // Updated: 2014-10-10 - This version calculates the Rayleigh scattering 40 // length for more materials than 40 // length for more materials than just Water (although the Water 41 // default is kept). To do this t 41 // default is kept). To do this the user would need to specify the 42 // ISOTHERMAL_COMPRESSIBILITY as 42 // ISOTHERMAL_COMPRESSIBILITY as a material property and 43 // optionally an RS_SCALE_LENGTH 43 // optionally an RS_SCALE_LENGTH (useful for testing). Code comes 44 // from Philip Graham (Queen Mary 44 // from Philip Graham (Queen Mary University of London). 45 // 2010-06-11 - Fix Bug 207; Than 45 // 2010-06-11 - Fix Bug 207; Thanks to Xin Qian 46 // (Kellogg Radiation Lab of Calt 46 // (Kellogg Radiation Lab of Caltech) 47 // 2005-07-28 - add G4ProcessType 47 // 2005-07-28 - add G4ProcessType to constructor 48 // 2001-10-18 by Peter Gumplinger 48 // 2001-10-18 by Peter Gumplinger 49 // eliminate unused variable warn 49 // eliminate unused variable warning on Linux (gcc-2.95.2) 50 // 2001-09-18 by mma 50 // 2001-09-18 by mma 51 // >numOfMaterials=G4Material::Ge << 51 // >numOfMaterials=G4Material::GetNumberOfMaterials() in BuildPhy 52 // 2001-01-30 by Peter Gumplinger 52 // 2001-01-30 by Peter Gumplinger 53 // > allow for positiv and negati 53 // > allow for positiv and negative CosTheta and force the 54 // > new momentum direction to be 54 // > new momentum direction to be in the same plane as the 55 // > new and old polarization vec 55 // > new and old polarization vectors 56 // 2001-01-29 by Peter Gumplinger 56 // 2001-01-29 by Peter Gumplinger 57 // > fix calculation of SinTheta 57 // > fix calculation of SinTheta (from CosTheta) 58 // 1997-04-09 by Peter Gumplinger 58 // 1997-04-09 by Peter Gumplinger 59 // > new physics/tracking scheme 59 // > new physics/tracking scheme >> 60 // mail: gum@triumf.ca 60 // 61 // 61 ////////////////////////////////////////////// 62 //////////////////////////////////////////////////////////////////////// 62 63 63 #include "G4OpRayleigh.hh" 64 #include "G4OpRayleigh.hh" >> 65 64 #include "G4ios.hh" 66 #include "G4ios.hh" 65 #include "G4PhysicalConstants.hh" 67 #include "G4PhysicalConstants.hh" 66 #include "G4SystemOfUnits.hh" 68 #include "G4SystemOfUnits.hh" 67 #include "G4OpticalParameters.hh" << 68 #include "G4OpProcessSubType.hh" 69 #include "G4OpProcessSubType.hh" 69 70 70 //....oooOO0OOooo........oooOO0OOooo........oo 71 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... >> 72 71 G4OpRayleigh::G4OpRayleigh(const G4String& pro 73 G4OpRayleigh::G4OpRayleigh(const G4String& processName, G4ProcessType type) 72 : G4VDiscreteProcess(processName, type) << 74 : G4VDiscreteProcess(processName, type) 73 { 75 { 74 Initialise(); << 75 SetProcessSubType(fOpRayleigh); 76 SetProcessSubType(fOpRayleigh); >> 77 76 thePhysicsTable = nullptr; 78 thePhysicsTable = nullptr; 77 79 78 if(verboseLevel > 0) << 80 if (verboseLevel > 0) { 79 { << 80 G4cout << GetProcessName() << " is created 81 G4cout << GetProcessName() << " is created " << G4endl; 81 } 82 } 82 } 83 } 83 84 84 //....oooOO0OOooo........oooOO0OOooo........oo 85 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 85 G4OpRayleigh::~G4OpRayleigh() << 86 { << 87 // VI: inside this PhysicsTable all properti << 88 // it is not possible to destroy << 89 delete thePhysicsTable; << 90 } << 91 86 92 //....oooOO0OOooo........oooOO0OOooo........oo << 87 G4OpRayleigh::~G4OpRayleigh() 93 void G4OpRayleigh::PreparePhysicsTable(const G << 94 { 88 { 95 Initialise(); << 89 if (thePhysicsTable) { >> 90 thePhysicsTable->clearAndDestroy(); >> 91 delete thePhysicsTable; >> 92 } 96 } 93 } 97 94 98 //....oooOO0OOooo........oooOO0OOooo........oo 95 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 99 void G4OpRayleigh::Initialise() << 100 { << 101 SetVerboseLevel(G4OpticalParameters::Instanc << 102 } << 103 96 104 //....oooOO0OOooo........oooOO0OOooo........oo << 97 G4VParticleChange* 105 G4VParticleChange* G4OpRayleigh::PostStepDoIt( << 98 G4OpRayleigh::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep) 106 << 107 { 99 { 108 aParticleChange.Initialize(aTrack); 100 aParticleChange.Initialize(aTrack); >> 101 109 const G4DynamicParticle* aParticle = aTrack. 102 const G4DynamicParticle* aParticle = aTrack.GetDynamicParticle(); 110 103 111 if(verboseLevel > 1) << 104 if (verboseLevel >0 ) { 112 { << 105 G4cout << "Scattering Photon!" << G4endl; 113 G4cout << "OpRayleigh: Scattering Photon!" << 106 G4cout << "Old Momentum Direction: " 114 << "Old Momentum Direction: " << aP << 107 << aParticle->GetMomentumDirection() << G4endl; 115 << G4endl << "Old Polarization: " < << 108 G4cout << "Old Polarization: " 116 << G4endl; << 109 << aParticle->GetPolarization() << G4endl; 117 } 110 } 118 111 119 G4double cosTheta; 112 G4double cosTheta; 120 G4ThreeVector oldMomDir, newMomDir; << 113 G4ThreeVector OldMomentumDirection, NewMomentumDirection; 121 G4ThreeVector oldPol, newPol; << 114 G4ThreeVector OldPolarization, NewPolarization; 122 G4double rand; << 123 G4double cost, sint, sinphi, cosphi; << 124 << 125 do << 126 { << 127 // Try to simulate the scattered photon mo << 128 // w.r.t. the initial photon momentum dire << 129 cost = G4UniformRand(); << 130 sint = std::sqrt(1. - cost * cost); << 131 // consider for the angle 90-180 degrees << 132 if(G4UniformRand() < 0.5) << 133 cost = -cost; << 134 << 135 // simulate the phi angle << 136 rand = twopi * G4UniformRand(); << 137 sinphi = std::sin(rand); << 138 cosphi = std::cos(rand); << 139 << 140 // construct the new momentum direction << 141 newMomDir.set(sint * cosphi, sint * sinphi << 142 oldMomDir = aParticle->GetMomentumDirectio << 143 newMomDir.rotateUz(oldMomDir); << 144 << 145 // calculate the new polarization directio << 146 // The new polarization needs to be in the << 147 // momentum direction and the old polariza << 148 oldPol = aParticle->GetPolarization(); << 149 newPol = (oldPol - newMomDir.dot(oldPol) * << 150 << 151 // There is a corner case, where the new m << 152 // is the same as old polarization directi << 153 // random generate the azimuthal angle w.r << 154 if(newPol.mag() == 0.) << 155 { << 156 rand = G4UniformRand() * twopi; << 157 newPol.set(std::cos(rand), std::sin(rand << 158 newPol.rotateUz(newMomDir); << 159 } << 160 else << 161 { << 162 // There are two directions perpendicula << 163 if(G4UniformRand() < 0.5) << 164 newPol = -newPol; << 165 } << 166 115 167 // simulate according to the distribution << 116 G4double rand, constant; 168 cosTheta = newPol.dot(oldPol); << 117 G4double CosTheta, SinTheta, SinPhi, CosPhi, unit_x, unit_y, unit_z; 169 // Loop checking, 13-Aug-2015, Peter Gumpl << 170 } while(std::pow(cosTheta, 2) < G4UniformRan << 171 118 172 aParticleChange.ProposePolarization(newPol); << 119 do { 173 aParticleChange.ProposeMomentumDirection(new << 120 // Try to simulate the scattered photon momentum direction >> 121 // w.r.t. the initial photon momentum direction >> 122 >> 123 CosTheta = G4UniformRand(); >> 124 SinTheta = std::sqrt(1.-CosTheta*CosTheta); >> 125 // consider for the angle 90-180 degrees >> 126 if (G4UniformRand() < 0.5) CosTheta = -CosTheta; >> 127 >> 128 // simulate the phi angle >> 129 rand = twopi*G4UniformRand(); >> 130 SinPhi = std::sin(rand); >> 131 CosPhi = std::cos(rand); >> 132 >> 133 // start constructing the new momentum direction >> 134 unit_x = SinTheta * CosPhi; >> 135 unit_y = SinTheta * SinPhi; >> 136 unit_z = CosTheta; >> 137 NewMomentumDirection.set (unit_x,unit_y,unit_z); >> 138 >> 139 // Rotate the new momentum direction into global reference system >> 140 OldMomentumDirection = aParticle->GetMomentumDirection(); >> 141 OldMomentumDirection = OldMomentumDirection.unit(); >> 142 NewMomentumDirection.rotateUz(OldMomentumDirection); >> 143 NewMomentumDirection = NewMomentumDirection.unit(); >> 144 >> 145 // calculate the new polarization direction >> 146 // The new polarization needs to be in the same plane as the new >> 147 // momentum direction and the old polarization direction >> 148 OldPolarization = aParticle->GetPolarization(); >> 149 constant = -NewMomentumDirection.dot(OldPolarization); >> 150 >> 151 NewPolarization = OldPolarization + constant*NewMomentumDirection; >> 152 NewPolarization = NewPolarization.unit(); >> 153 >> 154 // There is a corner case, where the Newmomentum direction >> 155 // is the same as oldpolariztion direction: >> 156 // random generate the azimuthal angle w.r.t. Newmomentum direction >> 157 if (NewPolarization.mag() == 0.) { >> 158 rand = G4UniformRand()*twopi; >> 159 NewPolarization.set(std::cos(rand),std::sin(rand),0.); >> 160 NewPolarization.rotateUz(NewMomentumDirection); >> 161 } else { >> 162 // There are two directions which are perpendicular >> 163 // to the new momentum direction >> 164 if (G4UniformRand() < 0.5) NewPolarization = -NewPolarization; >> 165 } >> 166 >> 167 // simulate according to the distribution cos^2(theta) >> 168 cosTheta = NewPolarization.dot(OldPolarization); >> 169 // Loop checking, 13-Aug-2015, Peter Gumplinger >> 170 } while (std::pow(cosTheta,2) < G4UniformRand()); >> 171 >> 172 aParticleChange.ProposePolarization(NewPolarization); >> 173 aParticleChange.ProposeMomentumDirection(NewMomentumDirection); >> 174 >> 175 if (verboseLevel > 0) { >> 176 G4cout << "New Polarization: " >> 177 << NewPolarization << G4endl; >> 178 G4cout << "Polarization Change: " >> 179 << *(aParticleChange.GetPolarization()) << G4endl; >> 180 G4cout << "New Momentum Direction: " >> 181 << NewMomentumDirection << G4endl; >> 182 G4cout << "Momentum Change: " >> 183 << *(aParticleChange.GetMomentumDirection()) << G4endl; >> 184 } 174 185 175 if(verboseLevel > 1) << 186 return G4VDiscreteProcess::PostStepDoIt(aTrack, aStep); 176 { << 177 G4cout << "New Polarization: " << newPol < << 178 << "Polarization Change: " << *(aPa << 179 << G4endl << "New Momentum Directio << 180 << "Momentum Change: " << *(aPartic << 181 << G4endl; << 182 } << 183 << 184 return G4VDiscreteProcess::PostStepDoIt(aTra << 185 } 187 } 186 188 187 //....oooOO0OOooo........oooOO0OOooo........oo 189 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... >> 190 188 void G4OpRayleigh::BuildPhysicsTable(const G4P 191 void G4OpRayleigh::BuildPhysicsTable(const G4ParticleDefinition&) 189 { 192 { 190 if(thePhysicsTable) << 193 if (thePhysicsTable) { 191 { << 194 thePhysicsTable->clearAndDestroy(); 192 // thePhysicsTable->clearAndDestroy(); << 193 delete thePhysicsTable; 195 delete thePhysicsTable; 194 thePhysicsTable = nullptr; 196 thePhysicsTable = nullptr; 195 } 197 } 196 198 197 const G4MaterialTable* theMaterialTable = G4 199 const G4MaterialTable* theMaterialTable = G4Material::GetMaterialTable(); 198 const size_t numOfMaterials = G4 << 200 const G4int numOfMaterials = G4Material::GetNumberOfMaterials(); 199 thePhysicsTable = ne << 200 201 201 for(size_t i = 0; i < numOfMaterials; ++i) << 202 thePhysicsTable = new G4PhysicsTable(numOfMaterials); >> 203 >> 204 for (G4int iMaterial = 0; iMaterial < numOfMaterials; ++iMaterial) 202 { 205 { 203 G4Material* material = (*the << 206 G4Material* material = (*theMaterialTable)[iMaterial]; 204 G4MaterialPropertiesTable* matProp = mater << 207 G4MaterialPropertiesTable* materialProperties = 205 G4PhysicsFreeVector* rayleigh = nullptr; << 208 material->GetMaterialPropertiesTable(); 206 if(matProp) << 209 G4PhysicsOrderedFreeVector* rayleigh = nullptr; 207 { << 210 if (materialProperties) { 208 rayleigh = matProp->GetProperty(kRAYLEIG << 211 rayleigh = materialProperties->GetProperty(kRAYLEIGH); 209 if(rayleigh == nullptr) << 212 if (rayleigh == nullptr) rayleigh = CalculateRayleighMeanFreePaths(material); 210 rayleigh = CalculateRayleighMeanFreePa << 211 } 213 } 212 thePhysicsTable->insertAt(i, rayleigh); << 214 thePhysicsTable->insertAt(iMaterial, rayleigh); 213 } 215 } 214 } 216 } 215 217 216 //....oooOO0OOooo........oooOO0OOooo........oo 218 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 217 G4double G4OpRayleigh::GetMeanFreePath(const G << 219 >> 220 G4double G4OpRayleigh::GetMeanFreePath(const G4Track& aTrack, >> 221 G4double , 218 G4Force 222 G4ForceCondition*) 219 { 223 { 220 auto rayleigh = static_cast<G4PhysicsFreeVec << 224 const G4DynamicParticle* particle = aTrack.GetDynamicParticle(); 221 (*thePhysicsTable)(aTrack.GetMaterial()- << 225 const G4double photonMomentum = particle->GetTotalMomentum(); >> 226 const G4Material* material = aTrack.GetMaterial(); >> 227 >> 228 G4PhysicsOrderedFreeVector* rayleigh = >> 229 static_cast<G4PhysicsOrderedFreeVector*> >> 230 ((*thePhysicsTable)(material->GetIndex())); 222 231 223 G4double rsLength = DBL_MAX; 232 G4double rsLength = DBL_MAX; 224 if(rayleigh) << 233 if (rayleigh) rsLength = rayleigh->Value(photonMomentum); 225 { << 226 rsLength = rayleigh->Value(aTrack.GetDynam << 227 idx_rslength); << 228 } << 229 return rsLength; 234 return rsLength; 230 } 235 } 231 236 232 //....oooOO0OOooo........oooOO0OOooo........oo 237 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 233 G4PhysicsFreeVector* G4OpRayleigh::CalculateRa << 238 G4PhysicsOrderedFreeVector* 234 const G4Material* material) const << 239 G4OpRayleigh::CalculateRayleighMeanFreePaths(const G4Material* material) const 235 { 240 { 236 G4MaterialPropertiesTable* MPT = material->G << 241 G4MaterialPropertiesTable* materialProperties = >> 242 material->GetMaterialPropertiesTable(); 237 243 238 // Retrieve the beta_T or isothermal compres 244 // Retrieve the beta_T or isothermal compressibility value. For backwards 239 // compatibility use a constant if the mater 245 // compatibility use a constant if the material is "Water". If the material 240 // doesn't have an ISOTHERMAL_COMPRESSIBILIT 246 // doesn't have an ISOTHERMAL_COMPRESSIBILITY constant then return 241 G4double betat; 247 G4double betat; 242 if(material->GetName() == "Water") << 248 if (material->GetName() == "Water") { 243 { << 249 betat = 7.658e-23*m3/MeV; 244 betat = 7.658e-23 * m3 / MeV; << 245 } 250 } 246 else if(MPT->ConstPropertyExists(kISOTHERMAL << 251 else if (materialProperties->ConstPropertyExists("ISOTHERMAL_COMPRESSIBILITY")) { 247 { << 252 betat = materialProperties->GetConstProperty(kISOTHERMAL_COMPRESSIBILITY); 248 betat = MPT->GetConstProperty(kISOTHERMAL_ << 249 } 253 } 250 else << 254 else { 251 { << 252 return nullptr; 255 return nullptr; 253 } 256 } 254 257 255 // If the material doesn't have a RINDEX pro 258 // If the material doesn't have a RINDEX property vector then return 256 G4MaterialPropertyVector* rIndex = MPT->GetP << 259 G4MaterialPropertyVector* rIndex = materialProperties->GetProperty(kRINDEX); 257 if(rIndex == nullptr) << 260 if (rIndex == nullptr) return nullptr; 258 return nullptr; << 259 261 260 // Retrieve the optional scale factor (scale << 262 // Retrieve the optional scale factor, (this just scales the scattering length 261 G4double scaleFactor = 1.0; 263 G4double scaleFactor = 1.0; 262 if(MPT->ConstPropertyExists(kRS_SCALE_FACTOR << 264 if (materialProperties->ConstPropertyExists("RS_SCALE_FACTOR")) { 263 { << 265 scaleFactor = materialProperties->GetConstProperty(kRS_SCALE_FACTOR); 264 scaleFactor = MPT->GetConstProperty(kRS_SC << 265 } 266 } 266 267 267 // Retrieve the material temperature. For ba 268 // Retrieve the material temperature. For backwards compatibility use a 268 // constant if the material is "Water" 269 // constant if the material is "Water" 269 G4double temperature; 270 G4double temperature; 270 if(material->GetName() == "Water") << 271 if (material->GetName() == "Water") { 271 { << 272 temperature = 283.15*kelvin; // Temperature of water is 10 degrees celsius 272 temperature = << 273 283.15 * kelvin; // Temperature of wate << 274 } 273 } 275 else << 274 else { 276 { << 277 temperature = material->GetTemperature(); 275 temperature = material->GetTemperature(); 278 } 276 } 279 277 280 auto rayleighMFPs = new G4PhysicsFreeVector( << 278 G4PhysicsOrderedFreeVector* rayleighMeanFreePaths = >> 279 new G4PhysicsOrderedFreeVector(); 281 // This calculates the meanFreePath via the 280 // This calculates the meanFreePath via the Einstein-Smoluchowski formula 282 const G4double c1 = << 281 const G4double c1 = scaleFactor * betat * temperature * k_Boltzmann / 283 scaleFactor * betat * temperature * k_Bolt << 282 ( 6.0 * pi ); 284 283 285 for(size_t uRIndex = 0; uRIndex < rIndex->Ge << 284 for (size_t uRIndex = 0; uRIndex < rIndex->GetVectorLength(); ++uRIndex) 286 { 285 { 287 const G4double energy = rIndex->Ene << 286 const G4double energy = rIndex->Energy(uRIndex); 288 const G4double rIndexSquared = (*rIndex)[u 287 const G4double rIndexSquared = (*rIndex)[uRIndex] * (*rIndex)[uRIndex]; 289 const G4double xlambda = h_Planck * << 288 const G4double xlambda = h_Planck * c_light / energy; 290 const G4double c2 = std::pow(tw << 289 const G4double c2 = std::pow(twopi/xlambda,4); 291 const G4double c3 = 290 const G4double c3 = 292 std::pow(((rIndexSquared - 1.0) * (rInde << 291 std::pow(((rIndexSquared-1.0)*(rIndexSquared+2.0 )/3.0),2); 293 292 294 const G4double meanFreePath = 1.0 / (c1 * << 293 const G4double meanFreePath = 1.0 / ( c1 * c2 * c3 ); 295 294 296 if(verboseLevel > 0) << 295 if( verboseLevel > 0) { 297 { << 298 G4cout << energy << "MeV\t" << meanFreeP 296 G4cout << energy << "MeV\t" << meanFreePath << "mm" << G4endl; 299 } 297 } 300 298 301 rayleighMFPs->InsertValues(energy, meanFre << 299 rayleighMeanFreePaths->InsertValues(energy, meanFreePath); 302 } 300 } 303 301 304 return rayleighMFPs; << 302 return rayleighMeanFreePaths; 305 } << 306 << 307 //....oooOO0OOooo........oooOO0OOooo........oo << 308 void G4OpRayleigh::SetVerboseLevel(G4int verbo << 309 { << 310 verboseLevel = verbose; << 311 G4OpticalParameters::Instance()->SetRayleigh << 312 } 303 } 313 304