G4IonDEDXHandler.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 //
00027 //
00028 // ===========================================================================
00029 // GEANT4 class source file
00030 //
00031 // Class:                G4IonDEDXHandler
00032 //
00033 // Author:               Anton Lechner (Anton.Lechner@cern.ch)
00034 //
00035 // First implementation: 11. 03. 2009
00036 //
00037 // Modifications: 12. 11 .2009 - Function BuildDEDXTable: Using adapted build 
00038 //                               methods of stopping power classes according
00039 //                               to interface change in G4VIonDEDXTable.
00040 //                               Function UpdateCacheValue: Using adapted
00041 //                               ScalingFactorEnergy function according to
00042 //                               interface change in G4VIonDEDXScaling-
00043 //                               Algorithm (AL)
00044 //
00045 // Class description:
00046 //    Ion dE/dx table handler. 
00047 //
00048 // Comments:
00049 //
00050 // =========================================================================== 
00051 
00052 #include <iomanip>
00053 
00054 #include "G4IonDEDXHandler.hh"
00055 #include "G4SystemOfUnits.hh"
00056 #include "G4VIonDEDXTable.hh"
00057 #include "G4VIonDEDXScalingAlgorithm.hh"
00058 #include "G4ParticleDefinition.hh"
00059 #include "G4Material.hh"
00060 #include "G4LPhysicsFreeVector.hh"
00061 
00062 //#define PRINT_DEBUG
00063 
00064 
00065 // #########################################################################
00066 
00067 G4IonDEDXHandler::G4IonDEDXHandler(
00068                             G4VIonDEDXTable* ionTable,
00069                             G4VIonDEDXScalingAlgorithm* ionAlgorithm,
00070                             const G4String& name,
00071                             G4int maxCacheSize,
00072                             G4bool splines) :
00073   table(ionTable),
00074   algorithm(ionAlgorithm),
00075   tableName(name),
00076   useSplines(splines),
00077   maxCacheEntries(maxCacheSize) {
00078 
00079   if(table == 0) {
00080      G4cerr << "G4IonDEDXHandler::G4IonDEDXHandler() "
00081             << " Pointer to G4VIonDEDXTable object is null-pointer." 
00082             << G4endl;
00083   }
00084 
00085   if(algorithm == 0) {
00086      G4cerr << "G4IonDEDXHandler::G4IonDEDXHandler() "
00087             << " Pointer to G4VIonDEDXScalingAlgorithm object is null-pointer." 
00088             << G4endl;
00089   }
00090 
00091   if(maxCacheEntries <= 0) {
00092      G4cerr << "G4IonDEDXHandler::G4IonDEDXHandler() "
00093             << " Cache size <=0. Resetting to 5." 
00094             << G4endl;
00095      maxCacheEntries = 5;
00096   }
00097 }
00098 
00099 // #########################################################################
00100 
00101 G4IonDEDXHandler::~G4IonDEDXHandler() {
00102 
00103   ClearCache();
00104 
00105   // All stopping power vectors built according to Bragg's addivitiy rule
00106   // are deleted. All other stopping power vectors are expected to be
00107   // deleted by their creator class (sub-class of G4VIonDEDXTable). 
00108   DEDXTableBraggRule::iterator iter = stoppingPowerTableBragg.begin();
00109   DEDXTableBraggRule::iterator iter_end = stoppingPowerTableBragg.end();
00110 
00111   for(;iter != iter_end; iter++) delete iter -> second;
00112   stoppingPowerTableBragg.clear();
00113 
00114   stoppingPowerTable.clear();
00115 
00116   if(table != 0) delete table;
00117   if(algorithm != 0) delete algorithm;
00118 }
00119 
00120 // #########################################################################
00121 
00122 G4bool G4IonDEDXHandler::IsApplicable(
00123                  const G4ParticleDefinition* particle,  // Projectile (ion) 
00124                  const G4Material* material) {          // Target material 
00125 
00126   G4bool isApplicable = true; 
00127 
00128   if(table == 0 || algorithm == 0) {
00129      isApplicable = false;
00130   }
00131   else {
00132 
00133      G4int atomicNumberIon = particle -> GetAtomicNumber();
00134      G4int atomicNumberBase = 
00135                 algorithm -> AtomicNumberBaseIon(atomicNumberIon, material);
00136 
00137      G4IonKey key = std::make_pair(atomicNumberBase, material);
00138 
00139      DEDXTable::iterator iter = stoppingPowerTable.find(key);
00140      if(iter == stoppingPowerTable.end()) isApplicable = false; 
00141   }
00142 
00143   return isApplicable; 
00144 }
00145 
00146 // #########################################################################
00147 
00148 G4double G4IonDEDXHandler::GetDEDX(
00149                  const G4ParticleDefinition* particle,  // Projectile (ion) 
00150                  const G4Material* material,   // Target material 
00151                  G4double kineticEnergy) {     // Kinetic energy of projectile
00152 
00153   G4double dedx = 0.0;
00154 
00155   G4CacheValue value = GetCacheValue(particle, material); 
00156      
00157   if(kineticEnergy <= 0.0) dedx = 0.0;
00158   else if(value.dedxVector != 0) {
00159  
00160      G4bool b;
00161      G4double factor = value.density;
00162 
00163      factor *= algorithm -> ScalingFactorDEDX(particle, 
00164                                              material,
00165                                              kineticEnergy);
00166      G4double scaledKineticEnergy = kineticEnergy * value.energyScaling;
00167 
00168      if(scaledKineticEnergy < value.lowerEnergyEdge) {
00169 
00170         factor *= std::sqrt(scaledKineticEnergy / value.lowerEnergyEdge);
00171         scaledKineticEnergy = value.lowerEnergyEdge;
00172      }
00173 
00174      dedx = factor * value.dedxVector -> GetValue(scaledKineticEnergy, b);
00175 
00176      if(dedx < 0.0) dedx = 0.0;
00177   }
00178   else dedx = 0.0;
00179 
00180 #ifdef PRINT_DEBUG
00181      G4cout << "G4IonDEDXHandler::GetDEDX() E = " 
00182             << kineticEnergy / MeV << " MeV * "
00183             << value.energyScaling << " = "
00184             << kineticEnergy * value.energyScaling / MeV 
00185             << " MeV, dE/dx = " << dedx / MeV * cm << " MeV/cm"
00186             << ", material = " << material -> GetName()
00187             << G4endl;
00188 #endif
00189 
00190   return dedx;
00191 }
00192 
00193 // #########################################################################
00194 
00195 G4bool G4IonDEDXHandler::BuildDEDXTable(
00196                  const G4ParticleDefinition* particle,  // Projectile (ion) 
00197                  const G4Material* material) {          // Target material 
00198 
00199   G4int atomicNumberIon = particle -> GetAtomicNumber();
00200 
00201   G4bool isApplicable = BuildDEDXTable(atomicNumberIon, material);
00202 
00203   return isApplicable;
00204 }
00205 
00206 
00207 // #########################################################################
00208 
00209 G4bool G4IonDEDXHandler::BuildDEDXTable(
00210                  G4int atomicNumberIon,                // Projectile (ion) 
00211                  const G4Material* material) {         // Target material 
00212 
00213   G4bool isApplicable = true; 
00214 
00215   if(table == 0 || algorithm == 0) {
00216      isApplicable = false;
00217      return isApplicable;
00218   }
00219 
00220   G4int atomicNumberBase = 
00221                 algorithm -> AtomicNumberBaseIon(atomicNumberIon, material);
00222 
00223   // Checking if vector is already built, and returns if this is indeed 
00224   // the case
00225   G4IonKey key = std::make_pair(atomicNumberBase, material);
00226 
00227   DEDXTable::iterator iter = stoppingPowerTable.find(key);
00228   if(iter != stoppingPowerTable.end()) return isApplicable;
00229 
00230   // Checking if table contains stopping power vector for given material name
00231   // or chemical formula
00232   const G4String& chemFormula = material -> GetChemicalFormula();
00233   const G4String& materialName = material -> GetName();
00234 
00235   isApplicable = table -> BuildPhysicsVector(atomicNumberBase, chemFormula);
00236 
00237   if(isApplicable) { 
00238      stoppingPowerTable[key] = 
00239               table -> GetPhysicsVector(atomicNumberBase, chemFormula);
00240      return isApplicable;
00241   }
00242 
00243   isApplicable = table -> BuildPhysicsVector(atomicNumberBase, materialName);
00244   if(isApplicable) { 
00245      stoppingPowerTable[key] = 
00246               table -> GetPhysicsVector(atomicNumberBase, materialName);
00247      return isApplicable;
00248   }
00249 
00250   // Building the stopping power vector based on Bragg's additivity rule
00251   const G4ElementVector* elementVector = material -> GetElementVector() ;
00252 
00253   std::vector<G4PhysicsVector*> dEdxTable;
00254 
00255   size_t nmbElements = material -> GetNumberOfElements();
00256 
00257   for(size_t i = 0; i < nmbElements; i++) {
00258 
00259       G4int atomicNumberMat = G4int((*elementVector)[i] -> GetZ());
00260 
00261       isApplicable = table -> BuildPhysicsVector(atomicNumberBase, atomicNumberMat);
00262 
00263       if(isApplicable) { 
00264 
00265          G4PhysicsVector* dEdx = 
00266                   table -> GetPhysicsVector(atomicNumberBase, atomicNumberMat);
00267          dEdxTable.push_back(dEdx);
00268       }
00269       else {
00270 
00271          dEdxTable.clear();
00272          break;
00273       }
00274   }
00275      
00276   if(isApplicable) {
00277 
00278      if(dEdxTable.size() > 0) {
00279 
00280         size_t nmbdEdxBins = dEdxTable[0] -> GetVectorLength();
00281         G4double lowerEdge = dEdxTable[0] -> GetLowEdgeEnergy(0);
00282         G4double upperEdge = dEdxTable[0] -> GetLowEdgeEnergy(nmbdEdxBins-1);
00283 
00284         G4LPhysicsFreeVector* dEdxBragg = 
00285                     new G4LPhysicsFreeVector(nmbdEdxBins,
00286                                              lowerEdge,
00287                                              upperEdge);
00288         dEdxBragg -> SetSpline(useSplines);
00289 
00290         const G4double* massFractionVector = material -> GetFractionVector();
00291 
00292         G4bool b;
00293         for(size_t j = 0; j < nmbdEdxBins; j++) {
00294 
00295             G4double edge = dEdxTable[0] -> GetLowEdgeEnergy(j);
00296 
00297             G4double value = 0.0;
00298             for(size_t i = 0; i < nmbElements; i++) {
00299  
00300                 value += (dEdxTable[i] -> GetValue(edge ,b)) *
00301                                                        massFractionVector[i];
00302             }
00303 
00304             dEdxBragg -> PutValues(j, edge, value); 
00305         }
00306 
00307 #ifdef PRINT_DEBUG
00308         G4cout << "G4IonDEDXHandler::BuildPhysicsVector() for ion with Z="
00309                << atomicNumberBase << " in "
00310                << material -> GetName()
00311                << G4endl;
00312 
00313         G4cout << *dEdxBragg;
00314 #endif
00315 
00316         stoppingPowerTable[key] = dEdxBragg;
00317         stoppingPowerTableBragg[key] = dEdxBragg;
00318      }
00319   }  
00320 
00321   ClearCache();
00322 
00323   return isApplicable;
00324 }
00325 
00326 // #########################################################################
00327 
00328 G4CacheValue G4IonDEDXHandler::UpdateCacheValue(
00329               const G4ParticleDefinition* particle,  // Projectile (ion) 
00330               const G4Material* material) {          // Target material 
00331 
00332   G4CacheValue value;
00333 
00334   G4int atomicNumberIon = particle -> GetAtomicNumber();
00335   G4int atomicNumberBase = 
00336                 algorithm -> AtomicNumberBaseIon(atomicNumberIon, material);
00337 
00338   G4IonKey key = std::make_pair(atomicNumberBase, material);
00339 
00340   DEDXTable::iterator iter = stoppingPowerTable.find(key);
00341 
00342   if(iter != stoppingPowerTable.end()) {
00343      value.dedxVector = iter -> second;
00344  
00345      G4double nmbNucleons = G4double(particle -> GetAtomicMass());
00346      value.energyScaling = 
00347            algorithm -> ScalingFactorEnergy(particle, material) / nmbNucleons;
00348 
00349      size_t nmbdEdxBins = value.dedxVector -> GetVectorLength();
00350      value.lowerEnergyEdge = value.dedxVector -> GetLowEdgeEnergy(0);
00351    
00352      value.upperEnergyEdge = 
00353                        value.dedxVector -> GetLowEdgeEnergy(nmbdEdxBins-1);
00354      value.density = material -> GetDensity();
00355   }
00356   else {
00357      value.dedxVector = 0;
00358      value.energyScaling = 0.0; 
00359      value.lowerEnergyEdge = 0.0;
00360      value.upperEnergyEdge = 0.0;
00361      value.density = 0.0;
00362   }
00363 
00364 #ifdef PRINT_DEBUG
00365   G4cout << "G4IonDEDXHandler::UpdateCacheValue() for " 
00366          << particle -> GetParticleName() << " in "
00367          << material -> GetName() 
00368          << G4endl;
00369 #endif
00370 
00371   return value;
00372 }
00373 
00374 // #########################################################################
00375 
00376 G4CacheValue G4IonDEDXHandler::GetCacheValue(
00377               const G4ParticleDefinition* particle,  // Projectile (ion) 
00378               const G4Material* material) {          // Target material 
00379 
00380   G4CacheKey key = std::make_pair(particle, material);
00381 
00382   G4CacheEntry entry;
00383   CacheEntryList::iterator* pointerIter = 
00384                   (CacheEntryList::iterator*) cacheKeyPointers[key];
00385 
00386   if(!pointerIter) {
00387       entry.value = UpdateCacheValue(particle, material);
00388 
00389       entry.key = key;
00390       cacheEntries.push_front(entry);
00391 
00392       CacheEntryList::iterator* pointerIter1 = 
00393                                    new CacheEntryList::iterator();
00394       *pointerIter1 = cacheEntries.begin();
00395       cacheKeyPointers[key] = pointerIter1;
00396 
00397       if(G4int(cacheEntries.size()) > maxCacheEntries) {
00398 
00399          G4CacheEntry lastEntry = cacheEntries.back();
00400                   
00401          void* pointerIter2 = cacheKeyPointers[lastEntry.key];
00402          CacheEntryList::iterator* listPointerIter = 
00403                           (CacheEntryList::iterator*) pointerIter2;
00404 
00405          cacheEntries.erase(*listPointerIter);
00406 
00407          delete listPointerIter;
00408          cacheKeyPointers.erase(lastEntry.key);
00409       }
00410   }
00411   else {
00412       entry = *(*pointerIter);
00413       // Cache entries are currently not re-ordered. 
00414       // Uncomment for activating re-ordering:
00415       //      cacheEntries.erase(*pointerIter);
00416       //      cacheEntries.push_front(entry);
00417       //      *pointerIter = cacheEntries.begin();
00418   }
00419   return entry.value;
00420 }
00421 
00422 // #########################################################################
00423 
00424 void G4IonDEDXHandler::ClearCache() {
00425 
00426   CacheIterPointerMap::iterator iter = cacheKeyPointers.begin();
00427   CacheIterPointerMap::iterator iter_end = cacheKeyPointers.end();
00428   
00429   for(;iter != iter_end; iter++) {
00430       void* pointerIter = iter -> second;
00431       CacheEntryList::iterator* listPointerIter = 
00432                           (CacheEntryList::iterator*) pointerIter;
00433 
00434       delete listPointerIter;
00435   }
00436  
00437   cacheEntries.clear();
00438   cacheKeyPointers.clear();
00439 }
00440 
00441 // #########################################################################
00442 
00443 void G4IonDEDXHandler::PrintDEDXTable(
00444                   const G4ParticleDefinition* particle,  // Projectile (ion) 
00445                   const G4Material* material,  // Target material
00446                   G4double lowerBoundary,      // Minimum energy per nucleon
00447                   G4double upperBoundary,      // Maximum energy per nucleon
00448                   G4int nmbBins,               // Number of bins
00449                   G4bool logScaleEnergy) {     // Logarithmic scaling of energy
00450 
00451   G4double atomicMassNumber = particle -> GetAtomicMass();
00452   G4double materialDensity = material -> GetDensity();
00453 
00454   G4cout << "# dE/dx table for " << particle -> GetParticleName() 
00455          << " in material " << material -> GetName()
00456          << " of density " << materialDensity / g * cm3
00457          << " g/cm3"
00458          << G4endl
00459          << "# Projectile mass number A1 = " << atomicMassNumber
00460          << G4endl
00461          << "# Energy range (per nucleon) of tabulation: " 
00462          << GetLowerEnergyEdge(particle, material) / atomicMassNumber / MeV
00463          << " - " 
00464          << GetUpperEnergyEdge(particle, material) / atomicMassNumber / MeV
00465          << " MeV"
00466          << G4endl
00467          << "# ------------------------------------------------------"
00468          << G4endl;
00469   G4cout << "#"
00470          << std::setw(13) << std::right << "E"
00471          << std::setw(14) << "E/A1"
00472          << std::setw(14) << "dE/dx"
00473          << std::setw(14) << "1/rho*dE/dx"
00474          << G4endl;
00475   G4cout << "#"
00476          << std::setw(13) << std::right << "(MeV)"
00477          << std::setw(14) << "(MeV)"
00478          << std::setw(14) << "(MeV/cm)"
00479          << std::setw(14) << "(MeV*cm2/mg)"
00480          << G4endl
00481          << "# ------------------------------------------------------"
00482          << G4endl;
00483 
00484   //G4CacheValue value = GetCacheValue(particle, material); 
00485 
00486   G4double energyLowerBoundary = lowerBoundary * atomicMassNumber;
00487   G4double energyUpperBoundary = upperBoundary * atomicMassNumber; 
00488 
00489   if(logScaleEnergy) {
00490 
00491      energyLowerBoundary = std::log(energyLowerBoundary);
00492      energyUpperBoundary = std::log(energyUpperBoundary); 
00493   }
00494 
00495   G4double deltaEnergy = (energyUpperBoundary - energyLowerBoundary) / 
00496                                                            G4double(nmbBins);
00497 
00498   G4cout.precision(6);
00499   for(int i = 0; i < nmbBins + 1; i++) {
00500 
00501       G4double energy = energyLowerBoundary + i * deltaEnergy;
00502       if(logScaleEnergy) energy = std::exp(energy);
00503 
00504       G4double loss = GetDEDX(particle, material, energy);
00505 
00506       G4cout << std::setw(14) << std::right << energy / MeV
00507              << std::setw(14) << energy / atomicMassNumber / MeV
00508              << std::setw(14) << loss / MeV * cm
00509              << std::setw(14) << loss / materialDensity / (MeV*cm2/(0.001*g)) 
00510              << G4endl;
00511   }
00512 }
00513 
00514 // #########################################################################
00515 
00516 G4double G4IonDEDXHandler::GetLowerEnergyEdge(
00517                  const G4ParticleDefinition* particle,  // Projectile (ion) 
00518                  const G4Material* material) {          // Target material 
00519 
00520   G4double edge = 0.0; 
00521 
00522   G4CacheValue value = GetCacheValue(particle, material); 
00523      
00524   if(value.energyScaling > 0) 
00525           edge = value.lowerEnergyEdge / value.energyScaling;
00526 
00527   return edge;
00528 }
00529 
00530 // #########################################################################
00531 
00532 G4double G4IonDEDXHandler::GetUpperEnergyEdge(
00533                  const G4ParticleDefinition* particle,  // Projectile (ion) 
00534                  const G4Material* material) {          // Target material 
00535 
00536   G4double edge = 0.0; 
00537 
00538   G4CacheValue value = GetCacheValue(particle, material); 
00539      
00540   if(value.energyScaling > 0) 
00541           edge = value.upperEnergyEdge / value.energyScaling;
00542 
00543   return edge;
00544 }
00545 
00546 // #########################################################################
00547 
00548 G4String G4IonDEDXHandler::GetName() {
00549 
00550   return tableName;
00551 }
00552 
00553 // #########################################################################

Generated on Mon May 27 17:48:39 2013 for Geant4 by  doxygen 1.4.7