/* Create Ntuples with material properties along straight lines from the model * and from the surfaces. */ int main(int argc, char** argv) { if(argc < 2) { std::cout << " usage: ./material_ntuples ILDEx.xml " << std::endl ; return 1; } std::string inFile = argv[1] ; std::vector<int> thetasDeg ; // ={ 85 , 20 } --- C++11 thetasDeg.push_back( 90 ) ; thetasDeg.push_back( 85 ) ; thetasDeg.push_back( 60 ) ; thetasDeg.push_back( 45 ) ; thetasDeg.push_back( 30 ) ; thetasDeg.push_back( 20 ) ; thetasDeg.push_back( 15 ) ; thetasDeg.push_back( 10 ) ; thetasDeg.push_back( 7 ) ; std::vector<int> phisDeg ; //= { 42 } ; phisDeg.push_back( 0 ) ; phisDeg.push_back( 7 ) ; phisDeg.push_back( 12 ) ; phisDeg.push_back( 17 ) ; phisDeg.push_back( 25 ) ; phisDeg.push_back( 30 ) ; phisDeg.push_back( 42 ) ; phisDeg.push_back( 60 ) ; phisDeg.push_back( 71 ) ; phisDeg.push_back( 85 ) ; //---------------- std::string varNames = "theta:phi:epx:epy:epz:x0:lambda:eloss" ; TFile *ofile = new TFile( "material_ntuples.root", "RECREATE"); TNtuple* surfTuple = new TNtuple( "surfTuple" , "material properties from surfaces", varNames.c_str() ) ; TNtuple* matTuple = new TNtuple( "matTuple" , "material properties from detailed model", varNames.c_str() ) ; //---------------- for( unsigned i=0,N= thetasDeg.size() ; i<N ; ++i ){ for( unsigned j=0,M= phisDeg.size() ; j<M ; ++j ){ double theta = thetasDeg[i] / 180. * M_PI ; double phi = phisDeg[j] / 180. * M_PI ; aidaTT::Vector3D dirVec( 1. , phi , theta, aidaTT::Vector3D::spherical ) ; // create an (almost) straight track in that direction double omega = 1.e-9 ; double tanl = tan( 0.5*M_PI - theta ) ; double phi0 = phi ; double d0 = 0. ; double z0 = 0. ; aidaTT::Vector3D p0(0.,0.,0.) ; // start point aidaTT::Vector3D p1 ; // end point aidaTT::trackParameters tP( aidaTT::Vector5(omega, tanl, phi0 , d0 , z0 ), p0 ) ; std::cout << " --- theta, phi : " << thetasDeg[i] <<" , " << phisDeg[j] << std::endl ; const aidaTT::IGeometry& geom = aidaTT::IGeometry::instance( inFile ) ; const aidaTT::SurfaceVec& surfaces = geom.getSurfaces() ; // create a trajectory w/o fitter or propagation aidaTT::trajectory traj( tP, 0, 0, &geom ) ; aidaTT::IntersectionVec intersections = traj.getIntersectionsWithSurfaces( surfaces ) ; double X0_tot = 0. ; // ============================ loop over surface intersections ==================== for(unsigned ii=0,NN=intersections.size() ; ii<NN ; ++ii){ const aidaTT::ISurface* surf = intersections[ii].second ; double s = 0; aidaTT::Vector3D xx ; bool intersects = aidaTT::intersectWithSurface( surf , tP.parameters() , tP.referencePoint() , s, xx, 0 , true ) ; //----------------- get X0 -------------------------------------------- const dd4hep::rec::IMaterial& material_inn = surf->innerMaterial(); const dd4hep::rec::IMaterial& material_out = surf->outerMaterial(); const double r_i = surf->innerThickness(); const double r_o = surf->outerThickness(); const double X0_o = material_out.radiationLength(); const double X0_i = material_inn.radiationLength(); double r_tot = r_i + r_o ; //calculation of effective radiation length of the surface double X0_eff = ( r_i/X0_i + r_o/X0_o ) / r_tot ; //calculation of the path of the particle inside the material //compute path as projection of (straight) track to surface normal: const aidaTT::Vector3D& up = dirVec.unit() ; // need to get the normal at crossing point const aidaTT::Vector3D& n = surf->normal( xx ) ; double cosTrk = std::fabs( up * n ) ; double path = r_i + r_o ; path = path/cosTrk ; double X_X0 = path * X0_eff ; //-------------------------------------------------------------------- X0_tot += X_X0 ; //"theta:phi:epx:epy:epz:x0:lambda:eloss" surfTuple->Fill( float(thetasDeg[i]) , float(phisDeg[j]) , xx.x() , xx.y() , xx.z() , X0_tot , 0., 0. ) ; p1 = xx ; // save last crossing point } aidaTT::Vector3D end ; aidaTT::Vector3D direction = ( p1 -p0 ).unit() ; dd4hep::Detector& thedetector = dd4hep::Detector::getInstance(); const dd4hep::DetElement& world = thedetector.world() ; MaterialManager matMgr( world.volume() ) ; const MaterialVec& materials = matMgr.materialsBetween( p0, p1 ); double sum_x0 = 0; double sum_lambda = 0; double path_length = 0; for( unsigned k=0,K=materials.size();k<K;++k){ TGeoMaterial* mat = materials[k].first->GetMaterial(); double length = materials[k].second; double nx0 = length / mat->GetRadLen(); sum_x0 += nx0; double nLambda = length / mat->GetIntLen(); sum_lambda += nLambda; path_length += length; end = path_length * direction; // ::printf(fmt, i+1, mat->GetName(), mat->GetZ(), mat->GetA(), // mat->GetDensity(), mat->GetRadLen(), mat->GetIntLen(), // length, path_length, sum_x0, sum_lambda, end[0], end[1], end[2]); // //mat->Print(); //"theta:phi:epx:epy:epz:x0:lambda:eloss" matTuple->Fill( float(thetasDeg[i]) , float(phisDeg[j]) , end.x() , end.y() , end.z() , sum_x0 , sum_lambda, 0. ) ; } } // phi } //theta ofile->Write("surfTuple"); return 0; }
void MUONChamberMaterialBudget(const char* geoFilename = "geometry.root", Int_t segmentationLevel = 1) { /// Draw the local chamber thickness over x0 (x/x0) used in the computation of Multiple Coulomb Scattering effets. /// Compute <x> and <x/x0> in a limited area (displayed on the histograms) to avoid edge effets. /// The resolution can be changed by changing the sementation level: resolution = 1 cm / segmentationLevel. const char* chamberName[10] = {"SC01", "SC02", "SC03", "SC04", "SC05", "SC06", "SC07", "SC08", "SC09", "SC10"}; Double_t OneOverX0MeanCh[10] = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.}; Double_t totalLengthCh[10] = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.}; Double_t OneOverX0Mean = 0.; Double_t totalLength = 0.; // Import TGeo geometry if (!gGeoManager) { TGeoManager::Import(geoFilename); if (!gGeoManager) { cout<<"getting geometry from file geometry.root failed"<<endl; return; } } // z intervals where to find the stations Double_t zIn[5] = {-510., -600., -800., -1150., -1350.}; Double_t zOut[5] = {-600., -800., -1150., -1350., -1470.}; // transverse area where to compute locally x and x/x0 Double_t xIn0[5] = {0., 0., 0., 0., 0.}; Double_t yIn0[5] = {0., 0., 0., 0., 0.}; Int_t ixMax[5] = {90, 120, 165, 250, 260}; Int_t iyMax[5] = {90, 120, 180, 250, 270}; // transverse area where to compute <x> and <x/x0> for each chamber Double_t xIn0ForMean[5] = { 5., 5., 35., 40., 40.}; Double_t yIn0ForMean[5] = {20., 25., 0., 0., 0.}; Int_t ixMaxForMean[5] = { 50, 65, 85, 120, 160 }; Int_t iyMaxForMean[5] = { 60, 70, 110, 150, 150 }; // define output histograms gStyle->SetPalette(1); TFile *f = TFile::Open("MaterialBudget.root","RECREATE"); TH2F* hXOverX0[10]; TBox* bXOverX0[10]; for (Int_t i=0; i<10; i++) { Int_t st = i/2; hXOverX0[i] = new TH2F(Form("hXOverX0_%d",i+1), Form("x/x0 on ch %d (%%)",i+1), segmentationLevel*ixMax[st], xIn0[st], xIn0[st]+ixMax[st], segmentationLevel*iyMax[st], yIn0[st], yIn0[st]+iyMax[st]); hXOverX0[i]->SetOption("COLZ"); hXOverX0[i]->SetStats(kFALSE); bXOverX0[i] = new TBox(xIn0ForMean[st], yIn0ForMean[st], xIn0ForMean[st]+ixMaxForMean[st], yIn0ForMean[st]+iyMaxForMean[st]); bXOverX0[i]->SetLineStyle(2); bXOverX0[i]->SetLineWidth(2); bXOverX0[i]->SetFillStyle(0); hXOverX0[i]->GetListOfFunctions()->Add(bXOverX0[i]); } // loop over stations for (Int_t ist=0; ist<5; ist++) { Int_t nPoints = 0; // loop over position in non bending direction (by step of 1cm) for (Int_t ix=0; ix<segmentationLevel*ixMax[ist]; ix++) { Double_t xIn = xIn0[ist] + ((Double_t)ix+0.5) / ((Double_t)segmentationLevel); // loop over position in bending direction (by step of 1cm) for (Int_t iy=0; iy<segmentationLevel*iyMax[ist]; iy++) { Int_t permilDone = 1000 * (ix * segmentationLevel*iyMax[ist] + iy + 1) / (segmentationLevel*segmentationLevel*ixMax[ist]*iyMax[ist]); if (permilDone%10 == 0) cout<<"\rStation "<<ist+1<<": processing... "<<permilDone/10<<"%"<<flush; Double_t yIn = yIn0[ist] + ((Double_t)iy+0.5) / ((Double_t)segmentationLevel); // Initialize starting point and direction Double_t trackXYZIn[3] = {xIn, yIn, zIn[ist]}; Double_t trackXYZOut[3] = {1.000001*xIn, 1.000001*yIn, zOut[ist]}; Double_t pathLength = TMath::Sqrt((trackXYZOut[0] - trackXYZIn[0])*(trackXYZOut[0] - trackXYZIn[0])+ (trackXYZOut[1] - trackXYZIn[1])*(trackXYZOut[1] - trackXYZIn[1])+ (trackXYZOut[2] - trackXYZIn[2])*(trackXYZOut[2] - trackXYZIn[2])); Double_t b[3]; b[0] = (trackXYZOut[0] - trackXYZIn[0]) / pathLength; b[1] = (trackXYZOut[1] - trackXYZIn[1]) / pathLength; b[2] = (trackXYZOut[2] - trackXYZIn[2]) / pathLength; TGeoNode *currentnode = gGeoManager->InitTrack(trackXYZIn, b); if (!currentnode) break; Bool_t OK = kTRUE; Double_t x0 = 0.; // radiation-length (cm-1) Double_t localOneOverX0MeanCh[10] = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.}; Double_t localTotalLengthCh[10] = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.}; Double_t localPathLength = 0.; Double_t remainingPathLength = pathLength; do { // Get material properties TGeoMaterial *material = currentnode->GetVolume()->GetMedium()->GetMaterial(); TString currentNodePath(gGeoManager->GetPath()); x0 = material->GetRadLen(); // Get path length within this material gGeoManager->FindNextBoundary(remainingPathLength); localPathLength = gGeoManager->GetStep() + 1.e-6; // Check if boundary within remaining path length. // If so, make sure to cross the boundary to prepare the next step if (localPathLength >= remainingPathLength) localPathLength = remainingPathLength; else { currentnode = gGeoManager->Step(); if (!currentnode) { OK = kFALSE; break; } if (!gGeoManager->IsEntering()) { // make another small step to try to enter in new slice gGeoManager->SetStep(0.001); currentnode = gGeoManager->Step(); if (!gGeoManager->IsEntering() || !currentnode) { OK = kFALSE; break; } localPathLength += 0.001; } } remainingPathLength -= localPathLength; // check if entering a chamber of the current station or go to next step Int_t chId; if (currentNodePath.Contains(chamberName[2*ist])) chId = 2*ist; else if (currentNodePath.Contains(chamberName[2*ist+1])) chId = 2*ist+1; else continue; // add current material budget localOneOverX0MeanCh[chId] += localPathLength / x0; localTotalLengthCh[chId] += localPathLength; } while (remainingPathLength > TGeoShape::Tolerance()); // account for the local material characteristic if computed successfully if (OK) { // fill histograms in the full space hXOverX0[2*ist]->Fill(xIn,yIn,100.*localOneOverX0MeanCh[2*ist]); hXOverX0[2*ist+1]->Fill(xIn,yIn,100.*localOneOverX0MeanCh[2*ist+1]); // computation of <x> and <x/x0> in a limited chamber region if (xIn > xIn0ForMean[ist] && xIn < xIn0ForMean[ist]+1.*ixMaxForMean[ist] && yIn > yIn0ForMean[ist] && yIn < yIn0ForMean[ist]+1.*iyMaxForMean[ist]) { nPoints++; OneOverX0MeanCh[2*ist] += localOneOverX0MeanCh[2*ist]; OneOverX0MeanCh[2*ist+1] += localOneOverX0MeanCh[2*ist+1]; totalLengthCh[2*ist] += localTotalLengthCh[2*ist]; totalLengthCh[2*ist+1] += localTotalLengthCh[2*ist+1]; } } } } cout<<"\rStation "<<ist+1<<": processing... 100%"<<endl; // normalize <x> and <x/x0> to the number of data points for (Int_t i=2*ist; i<=2*ist+1; i++) { OneOverX0MeanCh[i] /= (Double_t) nPoints; totalLengthCh[i] /= (Double_t) nPoints; } } // print results cout<<endl<<endl; cout<<"chamber thickness (cm) x/x0 (%)"<<endl; cout<<"------------------------------------"<<endl; for (Int_t i=0; i<10; i++) { printf(" %2d %4.2f %4.2f\n",i+1,totalLengthCh[i],100.*OneOverX0MeanCh[i]); totalLength += totalLengthCh[i]; OneOverX0Mean += OneOverX0MeanCh[i]; } cout<<"------------------------------------"<<endl; printf(" tot %4.1f %4.1f\n",totalLength,100.*OneOverX0Mean); cout<<endl; // save histograms f->Write(); f->Close(); }