/* Copyright 2008-2014, Technische Universitaet Muenchen, Authors: Christian Hoeppner & Sebastian Neubert & Johannes Rauch This file is part of GENFIT. GENFIT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GENFIT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with GENFIT. If not, see . */ #include #include #include #include #include #include #include namespace genfit { double MeanExcEnergy_get(int Z); double MeanExcEnergy_get(TGeoMaterial*); bool TGeoMaterialInterface::initTrack(double posX, double posY, double posZ, double dirX, double dirY, double dirZ){ #ifdef DEBUG std::cout << "TGeoMaterialInterface::initTrack. \n"; std::cout << "Pos "; TVector3(posX, posY, posZ).Print(); std::cout << "Dir "; TVector3(dirX, dirY, dirZ).Print(); #endif // Move to the new point. bool result = !gGeoManager->IsSameLocation(posX, posY, posZ, kTRUE); // Set the intended direction. gGeoManager->SetCurrentDirection(dirX, dirY, dirZ); if (debugLvl_ > 0) { std::cout << " TGeoMaterialInterface::initTrack at \n"; std::cout << " position: "; TVector3(posX, posY, posZ).Print(); std::cout << " direction: "; TVector3(dirX, dirY, dirZ).Print(); } return result; } void TGeoMaterialInterface::getMaterialParameters(double& density, double& Z, double& A, double& radiationLength, double& mEE){ TGeoMaterial* mat = gGeoManager->GetCurrentVolume()->GetMedium()->GetMaterial(); density = mat->GetDensity(); Z = mat->GetZ(); A = mat->GetA(); radiationLength = mat->GetRadLen(); mEE = MeanExcEnergy_get(mat); } void TGeoMaterialInterface::getMaterialParameters(MaterialProperties& parameters) { TGeoMaterial* mat = gGeoManager->GetCurrentVolume()->GetMedium()->GetMaterial(); parameters.setMaterialProperties(mat->GetDensity(), mat->GetZ(), mat->GetA(), mat->GetRadLen(), MeanExcEnergy_get(mat)); } double TGeoMaterialInterface::findNextBoundary(const RKTrackRep* rep, const M1x7& stateOrig, double sMax, // signed bool varField) { const double delta(1.E-2); // cm, distance limit beneath which straight-line steps are taken. const double epsilon(1.E-1); // cm, allowed upper bound on arch // deviation from straight line M1x3 SA; M1x7 state7, oldState7; memcpy(oldState7, stateOrig, sizeof(state7)); int stepSign(sMax < 0 ? -1 : 1); double s = 0; // trajectory length to boundary const unsigned maxIt = 300; unsigned it = 0; // Initialize the geometry to the current location (set by caller). gGeoManager->FindNextBoundary(fabs(sMax) - s); double safety = gGeoManager->GetSafeDistance(); // >= 0 double slDist = gGeoManager->GetStep(); // this should not happen, but it happens sometimes. // The reason are probably overlaps in the geometry. // Without this "hack" many small steps with size of minStep will be made, // until eventually the maximum number of iterations are exceeded and the extrapolation fails if (slDist < safety) slDist = safety; double step = slDist; if (debugLvl_ > 0) std::cout << " safety = " << safety << "; step, slDist = " << step << "\n"; while (1) { if (++it > maxIt){ Exception exc("TGeoMaterialInterface::findNextBoundary ==> maximum number of iterations exceeded",__LINE__,__FILE__); exc.setFatal(); throw exc; } // No boundary in sight? if (s + safety > fabs(sMax)) { if (debugLvl_ > 0) std::cout << " next boundary is further away than sMax \n"; return stepSign*(s + safety); //sMax; } // Are we at the boundary? if (slDist < delta) { if (debugLvl_ > 0) std::cout << " very close to the boundary -> return" << " stepSign*(s + slDist) = " << stepSign << "*(" << s + slDist << ")\n"; return stepSign*(s + slDist); } // We have to find whether there's any boundary on our path. // Follow curved arch, then see if we may have missed a boundary. // Always propagate complete way from original start to avoid // inconsistent extrapolations. memcpy(state7, stateOrig, sizeof(state7)); rep->RKPropagate(state7, NULL, SA, stepSign*(s + step), varField); // Straight line distance² between extrapolation finish and // the end of the previously determined safe segment. double dist2 = (pow(state7[0] - oldState7[0], 2) + pow(state7[1] - oldState7[1], 2) + pow(state7[2] - oldState7[2], 2)); // Maximal lateral deviation². double maxDeviation2 = 0.25*(step*step - dist2); if (step > safety && maxDeviation2 > epsilon*epsilon) { // Need to take a shorter step to reliably estimate material, // but only if we didn't move by safety. In order to avoid // issues with roundoff we check 'step > safety' instead of // 'step != safety'. If we moved by safety, there couldn't have // been a boundary that we missed along the path, but we could // be on the boundary. // Take a shorter step, but never shorter than safety. step = std::max(step / 2, safety); } else { gGeoManager->PushPoint(); bool volChanged = initTrack(state7[0], state7[1], state7[2], stepSign*state7[3], stepSign*state7[4], stepSign*state7[5]); if (volChanged) { if (debugLvl_ > 0) std::cout << " volChanged\n"; // Move back to start. gGeoManager->PopPoint(); // Extrapolation may not take the exact step length we asked // for, so it can happen that a requested step < safety takes // us across the boundary. This is then the best estimate we // can get of the distance to the boundary with the stepper. if (step <= safety) { if (debugLvl_ > 0) std::cout << " step <= safety, return stepSign*(s + step) = " << stepSign*(s + step) << "\n"; return stepSign*(s + step); } // Volume changed during the extrapolation. Take a shorter // step, but never shorter than safety. step = std::max(step / 2, safety); } else { // we're in the new place, the step was safe, advance s += step; memcpy(oldState7, state7, sizeof(state7)); gGeoManager->PopDummy(); // Pop stack, but stay in place. gGeoManager->FindNextBoundary(fabs(sMax) - s); safety = gGeoManager->GetSafeDistance(); slDist = gGeoManager->GetStep(); // this should not happen, but it happens sometimes. // The reason are probably overlaps in the geometry. // Without this "hack" many small steps with size of minStep will be made, // until eventually the maximum number of iterations are exceeded and the extrapolation fails if (slDist < safety) slDist = safety; step = slDist; if (debugLvl_ > 0) std::cout << " safety = " << safety << "; step, slDist = " << step << "\n"; } } } } /* Reference for elemental mean excitation energies at: http://physics.nist.gov/PhysRefData/XrayMassCoef/tab1.html Code ported from GEANT 3 */ const int MeanExcEnergy_NELEMENTS = 93; // 0 = vacuum, 1 = hydrogen, 92 = uranium const double MeanExcEnergy_vals[MeanExcEnergy_NELEMENTS] = { 1.e15, 19.2, 41.8, 40.0, 63.7, 76.0, 78., 82.0, 95.0, 115.0, 137.0, 149.0, 156.0, 166.0, 173.0, 173.0, 180.0, 174.0, 188.0, 190.0, 191.0, 216.0, 233.0, 245.0, 257.0, 272.0, 286.0, 297.0, 311.0, 322.0, 330.0, 334.0, 350.0, 347.0, 348.0, 343.0, 352.0, 363.0, 366.0, 379.0, 393.0, 417.0, 424.0, 428.0, 441.0, 449.0, 470.0, 470.0, 469.0, 488.0, 488.0, 487.0, 485.0, 491.0, 482.0, 488.0, 491.0, 501.0, 523.0, 535.0, 546.0, 560.0, 574.0, 580.0, 591.0, 614.0, 628.0, 650.0, 658.0, 674.0, 684.0, 694.0, 705.0, 718.0, 727.0, 736.0, 746.0, 757.0, 790.0, 790.0, 800.0, 810.0, 823.0, 823.0, 830.0, 825.0, 794.0, 827.0, 826.0, 841.0, 847.0, 878.0, 890.0, }; // Logarithms of the previous table, used to calculate mixtures. const double MeanExcEnergy_logs[MeanExcEnergy_NELEMENTS] = { 34.5388, 2.95491, 3.7329, 3.68888, 4.15418, 4.33073, 4.35671, 4.40672, 4.55388, 4.74493, 4.91998, 5.00395, 5.04986, 5.11199, 5.15329, 5.15329, 5.19296, 5.15906, 5.23644, 5.24702, 5.25227, 5.37528, 5.45104, 5.50126, 5.54908, 5.6058, 5.65599, 5.69373, 5.73979, 5.77455, 5.79909, 5.81114, 5.85793, 5.84932, 5.8522, 5.83773, 5.86363, 5.8944, 5.90263, 5.93754, 5.97381, 6.03309, 6.04973, 6.05912, 6.08904, 6.10702, 6.15273, 6.15273, 6.1506, 6.19032, 6.19032, 6.18826, 6.18415, 6.19644, 6.17794, 6.19032, 6.19644, 6.21661, 6.25958, 6.28227, 6.30262, 6.32794, 6.35263, 6.36303, 6.38182, 6.41999, 6.44254, 6.47697, 6.4892, 6.51323, 6.52796, 6.54247, 6.5582, 6.57647, 6.58893, 6.60123, 6.61473, 6.62936, 6.67203, 6.67203, 6.68461, 6.69703, 6.71296, 6.71296, 6.72143, 6.71538, 6.67708, 6.7178, 6.71659, 6.73459, 6.7417, 6.77765, 6.79122, }; double MeanExcEnergy_get(int Z, bool logs = false) { assert(Z >= 0 && Z < MeanExcEnergy_NELEMENTS); if (logs) return MeanExcEnergy_logs[Z]; else return MeanExcEnergy_vals[Z]; } double MeanExcEnergy_get(TGeoMaterial* mat) { if (mat->IsMixture()) { // The mean excitation energy is calculated as the geometric mean // of the mEEs of the components, weighted for abundance. double logMEE = 0.; double denom = 0.; TGeoMixture* mix = (TGeoMixture*)mat; for (int i = 0; i < mix->GetNelements(); ++i) { int index = int(mix->GetZmixt()[i]); double weight = mix->GetWmixt()[i] * mix->GetZmixt()[i] / mix->GetAmixt()[i]; logMEE += weight * MeanExcEnergy_get(index, true); denom += weight; } logMEE /= denom; return exp(logMEE); } // not a mixture int index = int(mat->GetZ()); return MeanExcEnergy_get(index, false); } } /* End of namespace genfit */