00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
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
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
00106
00107
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,
00124 const G4Material* 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,
00150 const G4Material* material,
00151 G4double kineticEnergy) {
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,
00197 const G4Material* 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,
00211 const G4Material* 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
00224
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
00231
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
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,
00330 const G4Material* 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,
00378 const G4Material* 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
00414
00415
00416
00417
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,
00445 const G4Material* material,
00446 G4double lowerBoundary,
00447 G4double upperBoundary,
00448 G4int nmbBins,
00449 G4bool logScaleEnergy) {
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
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,
00518 const G4Material* 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,
00534 const G4Material* 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