/* Copyright 2008-2009, 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
//#define DEBUG
namespace genfit {
double MeanExcEnergy_get(int Z);
double MeanExcEnergy_get(TGeoMaterial*);
TGeoMaterialInterface::TGeoMaterialInterface() : whichNavig_(0) {
gGeoManager->AddNavigator();
}
void
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
const Double_t * pt = gGeoManager->GetCurrentPoint();
if (posX == pt[0] &&
posY == pt[1] &&
posZ == pt[2]) {
// position does not change
gGeoManager->SetCurrentDirection(dirX, dirY, dirZ);
#ifdef DEBUG
std::cout << "just init dir (default navigator)! \n";
#endif
}
else {
whichNavig_ = (whichNavig_ + 1) % 2;
gGeoManager->SetCurrentNavigator(whichNavig_);
pt = gGeoManager->GetCurrentPoint();
if (posX == pt[0] &&
posY == pt[1] &&
posZ == pt[2]) {
// position does not change
gGeoManager->SetCurrentDirection(dirX, dirY, dirZ);
#ifdef DEBUG
std::cout << "just init dir (second navigator)! \n";
#endif
}
else {
gGeoManager->InitTrack(posX, posY, posZ,
dirX, dirY, dirZ);
}
}
#ifdef DEBUG
std::cout << "\n";
#endif
}
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
double s(0), safety(0), slDist(0);
M1x3 SA;
M1x7 state7;
memcpy(state7, stateOrig, sizeof(stateOrig));
int stepSign(1);
if (sMax < 0) stepSign = -1;
unsigned int maxIt(300), it(0);
while (true) {
if (++it > maxIt){
Exception exc("TGeoMaterialInterface::findNextBoundary ==> maximum number of iterations exceeded",__LINE__,__FILE__);
exc.setFatal();
throw exc;
}
safety = gGeoManager->Safety(); // unsigned; distance to closest boundary
#ifdef DEBUG
std::cout << " TGeoMaterialInterface::findNextBoundary: Iteration " << it << ". Safety = " << safety << ". slDist = " << slDist << ". Step so far = " << s << "\n";
std::cout << " Material before step: " << gGeoManager->GetCurrentVolume()->GetMedium()->GetName() << "\n";
#endif
if (fabs(s + stepSign*safety) > fabs(sMax)) { // next boundary is further away than sMax
#ifdef DEBUG
std::cout << " next boundary is further away than sMax \n";
#endif
return s + stepSign*safety;
}
gGeoManager->FindNextBoundary();
slDist = gGeoManager->GetStep(); // unsigned; straight line distance to next boundary along step direction
if (slDist < delta) { // very near the boundary
#ifdef DEBUG
std::cout << " very near the boundary -> return s + stepSign*slDist; = " << s + stepSign*slDist << "\n";
#endif
return s + stepSign*slDist;
}
else {
#ifdef DEBUG
std::cout << " make RKutta step \n";
#endif
// check if we would cross a boundary when making slDist step
double tryStep = 0.9 * stepSign*slDist;
bool safe = false;
if (fabs(tryStep) < fabs(safety))
safe = true;
if (!safe) {
memcpy(state7, stateOrig, sizeof(state7)); // propagate complete way from original start
rep->RKPropagate(state7, NULL, SA, s+tryStep, varField);
// init for checking
initTrack(stateOrig[0], stateOrig[1], stateOrig[2],
state7[0]-stateOrig[0], state7[1]-stateOrig[1], state7[2]-stateOrig[2]);
}
// check: gGeoManager->GetStep() gives us the max sl step size from stateOrig to state7
if (!safe && gGeoManager->GetStep() > fabs(tryStep)) {
s += tryStep;
// init for next iteration
initTrack(state7[0], state7[1], state7[2], stepSign*state7[3], stepSign*state7[4], stepSign*state7[5]);
#ifdef DEBUG
std::cout << " tried and its safe to make a step of " << stepSign*tryStep << "\n";
#endif
}
else { // step along safety
s += stepSign*safety;
memcpy(state7, stateOrig, sizeof(state7)); // propagate complete way from original start
rep->RKPropagate(state7, NULL, SA, s, varField);
// init for next iteration
initTrack(state7[0], state7[1], state7[2], stepSign*state7[3], stepSign*state7[4], stepSign*state7[5]);
#ifdef DEBUG
std::cout << " step along safety " << stepSign*safety << "\n";
#endif
}
}
#ifdef DEBUG
std::cout << " Material after step: " << gGeoManager->GetCurrentVolume()->GetMedium()->GetName() << "\n";
#endif
}
}
double
TGeoMaterialInterface::findNextBoundaryAndStepStraight(double sMax) {
gGeoManager->FindNextBoundaryAndStep(sMax);
return gGeoManager->GetStep();
}
/*
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[] = {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};
double
MeanExcEnergy_get(int Z) {
assert(Z >= 0 && Z < MeanExcEnergy_NELEMENTS);
return MeanExcEnergy_vals[Z];
}
double
MeanExcEnergy_get(TGeoMaterial* mat) {
if (mat->IsMixture()) {
double logMEE = 0.;
double denom = 0.;
TGeoMixture* mix = (TGeoMixture*)mat;
for (int i = 0; i < mix->GetNelements(); ++i) {
int index = int(floor((mix->GetZmixt())[i]));
logMEE += 1. / (mix->GetAmixt())[i] * (mix->GetWmixt())[i] * (mix->GetZmixt())[i] * log(MeanExcEnergy_get(index));
denom += (mix->GetWmixt())[i] * (mix->GetZmixt())[i] * 1. / (mix->GetAmixt())[i];
}
logMEE /= denom;
return exp(logMEE);
} else { // not a mixture
int index = int(floor(mat->GetZ()));
return MeanExcEnergy_get(index);
}
}
} /* End of namespace genfit */