00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "FWCore/Utilities/interface/Exception.h"
00016 #include "DataFormats/GeometryVector/interface/LocalVector.h"
00017 #include "SimMuon/CSCDigitizer/src/CSCGasCollisions.h"
00018 #include "Utilities/General/interface/FileInPath.h"
00019 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00020 #include <iostream>
00021 #include <fstream>
00022 #include <cassert>
00023
00024
00025
00026 #include <cstdlib>
00027
00028 #include <cmath>
00029
00030
00031
00032 #include <algorithm>
00033
00034 #include <functional>
00035
00036 #include <numeric>
00037 #include <iterator>
00038
00039 using namespace std;
00040
00041
00042
00043
00044
00045
00046
00047 CSCGasCollisions::CSCGasCollisions() : me("CSCGasCollisions"),
00048 gasDensity( 2.1416e-03 ),
00049 deCut( 1.e05 ), eion( 14.95 ), ework( 34.0 ), clusterExtent( 0.001 ),
00050 theGammaBins(N_GAMMA, 0.), theEnergyBins(N_ENERGY, 0.),
00051 theCollisionTable(N_ENTRIES, 0.), theCrossGap( 0 ),
00052 theParticleDataTable(0),
00053 theRandFlat(0),
00054 theRandExponential(0),
00055 saveGasCollisions ( false )
00056 {
00057
00058 edm::LogInfo(me) << "Constructing a " << me << ":";
00059 edm::LogInfo(me) << "gas density = " << gasDensity << " g/cm3";
00060 edm::LogInfo(me) << "max eloss per collision allowed = " << deCut/1000.
00061 << " keV (for higher elosses, hits should have been simulated.)";
00062 edm::LogInfo(me) << "ionization threshold = " << eion << " eV";
00063 edm::LogInfo(me) << "effective work function = " << ework << " eV";
00064 edm::LogInfo(me) << "cluster extent = " << clusterExtent*1.e04 << " micrometres";
00065 edm::LogInfo(me) << "Save gas collision info to files when using debugV? " << saveGasCollisions;
00066
00067 readCollisionTable();
00068 }
00069
00070 CSCGasCollisions::~CSCGasCollisions() {
00071 edm::LogInfo(me) << "Destructing a " << me;
00072 delete theCrossGap;
00073 delete theRandFlat;
00074 delete theRandExponential;
00075 }
00076
00077 void CSCGasCollisions::readCollisionTable() {
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 string path( getenv( "CMSSW_SEARCH_PATH" ) );
00093
00094 string colliFile = "SimMuon/CSCDigitizer/data/collisions.dat";
00095 FileInPath f1( path, colliFile );
00096 if (f1() == 0 ) {
00097 string errorMessage = "Input file " + colliFile + "not found";
00098 edm::LogError("CSCGasCollisions") << errorMessage << " in path " << path
00099 << "\nSet Muon:Endcap:CollisionsFile in .orcarc to the "
00100 " location of the file relative to ORCA_DATA_PATH." ;
00101 throw cms::Exception( " Endcap Muon gas collisions data file not found.");
00102 }
00103 else {
00104 edm::LogInfo(me) << ": reading " << f1.name();
00105 }
00106
00107 ifstream & fin = *f1();
00108
00109 if (fin == 0) {
00110 string errorMessage = "Cannot open input file " + path + colliFile;
00111 edm::LogError("CSCGasCollisions") << errorMessage;
00112 throw cms::Exception(errorMessage);
00113 }
00114
00115 fin.clear( );
00116 fin.seekg( 0, ios::beg );
00117
00118
00119
00120 LogTrace(me) << "Reading gamma bins";
00121 int j = 0;
00122 for(int i = 0; i<N_GAMMA; ++i) {
00123 fin >> theGammaBins[i];
00124 LogTrace(me) << ++j << " " << theGammaBins[i];
00125 }
00126
00127 j = 0;
00128 LogTrace(me) << "Reading energy bins \n";
00129 for(int i = 0; i<N_ENERGY; ++i) {
00130 fin >> theEnergyBins[i];
00131 LogTrace(me) << ++j << " " << theEnergyBins[i];
00132 }
00133
00134 j = 0;
00135 LogTrace(me) << "Reading collisions table \n";
00136
00137 for(int i = 0; i<N_ENTRIES; ++i) {
00138 fin >> theCollisionTable[i];
00139 LogTrace(me) << ++j << " " << theCollisionTable[i];
00140 }
00141
00142 fin.close();
00143 }
00144
00145
00146 void CSCGasCollisions::setParticleDataTable(const ParticleDataTable * pdt)
00147 {
00148 theParticleDataTable = pdt;
00149 }
00150
00151
00152 void CSCGasCollisions::setRandomEngine(CLHEP::HepRandomEngine & engine)
00153 {
00154 theRandFlat = new CLHEP::RandFlat(engine);
00155 theRandExponential = new CLHEP::RandExponential(engine);
00156 }
00157
00158
00159 void CSCGasCollisions::simulate( const PSimHit& simHit,
00160 std::vector<LocalPoint>& positions, std::vector<int>& electrons ) {
00161
00162 const float epsilonL = 0.01;
00163
00164
00165
00166
00167
00168 double mom = simHit.pabs();
00169 int iam = simHit.particleType();
00170 delete theCrossGap;
00171 assert(theParticleDataTable != 0);
00172 ParticleData const * particle = theParticleDataTable->particle( simHit.particleType() );
00173 double mass = 0.105658;
00174 if(particle == 0)
00175 {
00176 edm::LogError("CSCGasCollisions") << "Cannot find particle of type " << simHit.particleType()
00177 << " in the PDT";
00178 }
00179 else
00180 {
00181 mass = particle->mass();
00182 }
00183
00184 theCrossGap = new CSCCrossGap( mass, mom, simHit.exitPoint() - simHit.entryPoint() );
00185 float gapSize = theCrossGap->length();
00186
00187
00188
00189 if ( gapSize <= epsilonL ) {
00190 LogTrace(me) << ": WARNING! simhit entry and exit are very close: \n"
00191 << "\n entry = " << simHit.entryPoint()
00192 << "\n exit = " << simHit.exitPoint()
00193 << "\n particle type = " << iam << ", momentum = " << mom
00194 << ", gap length = " << gapSize;
00195 return;
00196 }
00197
00198
00199
00200 std::vector<float> collisions(N_ENERGY);
00201 double loggam = theCrossGap->logGamma();
00202 fillCollisionsForThisGamma( static_cast<float>(loggam), collisions );
00203
00204 double anmin = exp(collisions[N_ENERGY-1]);
00205 double anmax = exp(collisions[0]);
00206 double amu = anmax - anmin;
00207
00208 LogTrace(me) << "collisions extremes = " << collisions[N_ENERGY-1]
00209 << ", " << collisions[0] << "\n"
00210 << "anmin = " << anmin << ", anmax = " << anmax << "\n"
00211 << "amu = " << amu << "\n";
00212
00213 float dedx = 0.;
00214 double sum_steps = 0.;
00215 int n_steps = 0;
00216 int n_try = 0;
00217 double step = -1.;
00218
00219 LocalPoint layerLocalPoint( simHit.entryPoint() );
00220
00221
00222 while ( sum_steps < gapSize) {
00223 ++n_try;
00224 if ( n_try > MAX_STEPS ) {
00225 LogTrace(me) << ": n_try=" << n_try << " is too large. Skip simhit."
00226 << "\n particle type=" << iam << ", momentum= " << mom
00227 << "\n gapSize=" << gapSize << ", last step=" << step
00228 << ", sum_steps=" << sum_steps << ", n_steps=" << n_steps;
00229 break;
00230 }
00231 step = generateStep( amu );
00232 if ( sum_steps + step > gapSize ) break;
00233
00234 float eloss = generateEnergyLoss( amu, anmin, anmax, collisions );
00235
00236
00237 if ( eloss > deCut ) {
00238 LogTrace(me) << "eloss > " << deCut << " = " << eloss;
00239 continue;
00240 }
00241
00242 dedx += eloss;
00243 sum_steps += step;
00244 ++n_steps;
00245
00246 if (n_steps > MAX_STEPS ) {
00247 edm::LogInfo(me) << ": n_steps=" << n_steps << " is too large. Skip simhit.";
00248 edm::LogInfo(me) << "particle type=" << iam << ", momentum= " << mom;
00249 edm::LogInfo(me) << "gapSize=" << gapSize << ", last step=" << step
00250 << ", sum_steps=" << sum_steps;
00251 break;
00252 }
00253 LogTrace(me) << "sum_steps = " << sum_steps << ", dedx = " << dedx;
00254
00255
00256
00257 if ( eloss > eion ) {
00258 layerLocalPoint += step * theCrossGap->unitVector();
00259 ionize( eloss, layerLocalPoint );
00260 }
00261 else {
00262 LogTrace(me) << "Energy available = " << eloss <<
00263 ", too low for ionization.";
00264 }
00265
00266 }
00267
00268
00269
00270
00271
00272 positions = theCrossGap->ionClusters();
00273 electrons = theCrossGap->electrons();
00274 return;
00275 }
00276
00277 double CSCGasCollisions::generateStep( double avCollisions ) const
00278 {
00279
00280 double step = (theRandExponential->fire())/avCollisions;
00281
00282
00283
00284
00285
00286 LogTrace(me) << " step = " << step;
00287
00288
00289 return step;
00290 }
00291
00292 float CSCGasCollisions::generateEnergyLoss( double avCollisions,
00293 double anmin, double anmax, const std::vector<float>& collisions ) const
00294 {
00295
00296 float lnColl = log(theRandFlat->fire(anmin, anmax));
00297
00298
00299
00300
00301
00302
00303
00304 float lnE = lnEnergyLoss( lnColl, collisions );
00305 float eloss = exp(lnE);
00306
00307 if ( theCrossGap->gamma() < 1.1 ) eloss = eloss * 0.173554/theCrossGap->beta2();
00308 LogTrace(me) << "eloss = " << eloss;
00309
00310
00311 return eloss;
00312 }
00313
00314 void CSCGasCollisions::ionize( double energyAvailable, LocalPoint startHere ) const
00315 {
00316 while ( energyAvailable > eion ) {
00317 LogTrace(me) << " NEW CLUSTER " << theCrossGap->noOfClusters() + 1 <<
00318 " AT " << startHere;
00319 LocalPoint newCluster( startHere );
00320 theCrossGap->addCluster(newCluster);
00321
00322
00323
00324
00325
00326
00327
00328
00329 double range = 0.5 * (0.71/gasDensity)*pow( energyAvailable*1.E-6, 1.72);
00330 LogTrace(me) << " range = " << range;
00331 if ( range < clusterExtent ) {
00332
00333
00334
00335 int nelec = static_cast<int>(energyAvailable/ework);
00336 LogTrace(me) << "s-r delta energy in = " << energyAvailable;
00337
00338 energyAvailable -= nelec*ework;
00339
00340 if ( energyAvailable > eion ) {
00341 ++nelec;
00342 energyAvailable -= eion;
00343 }
00344 LogTrace(me) << "s-r delta energy out = " << energyAvailable << ", nelec = " << nelec;
00345 theCrossGap->addElectrons( nelec );
00346 break;
00347
00348 }
00349 else {
00350
00351 LogTrace(me) << "l-r delta \n"
00352 << "no. of electrons in cluster now = " << theCrossGap->noOfElectrons();
00353 theCrossGap->addElectrons( 1 );
00354
00355 bool new_range = false;
00356 while ( !new_range && (energyAvailable>ework) ) {
00357 energyAvailable -= ework;
00358 while ( energyAvailable > eion ) {
00359 double range2 = 0.5 * 0.71/gasDensity*pow( 1.E-6*energyAvailable, 1.72);
00360 double drange = range - range2;
00361 LogTrace(me) << " energy left = " << energyAvailable <<
00362 ", range2 = " << range2 << ", drange = " << drange;
00363 if ( drange < clusterExtent ) {
00364 theCrossGap->addElectronToBack();
00365 }
00366 else {
00367 startHere += drange*theCrossGap->unitVector();
00368 range = range2;
00369 new_range = true;
00370 LogTrace(me) << "reset range to range2 and iterate";
00371 }
00372 break;
00373
00374 }
00375
00376 }
00377
00378
00379 if ( energyAvailable > eion ) {
00380 energyAvailable -= ework;
00381 theCrossGap->addElectronToBack();
00382 }
00383
00384 }
00385
00386 }
00387 }
00388
00389 void CSCGasCollisions::writeSummary( int n_steps, double sum_steps, float dedx, float simHiteloss ) const
00390 {
00391 std::vector<LocalPoint> ion_clusters = theCrossGap->ionClusters();
00392 std::vector<int> electrons = theCrossGap->electrons();
00393 std::vector<float> elosses = theCrossGap->eLossPerStep();
00394 std::vector<double> steps = theCrossGap->stepLengths();
00395
00396 cout << "------------------" << std::endl;
00397 cout << "AFTER CROSSING GAP" << std::endl;
00398 cout << "No. of steps = " << n_steps << std::endl;
00399 cout << "Check: stored steps = " << theCrossGap->noOfSteps() << std::endl;
00400
00401 cout << "Lengths of steps: " << std::endl;
00402 std::copy( steps.begin(), steps.end(), std::ostream_iterator<float>(cout,"\n"));
00403 cout << std::endl;
00404
00405 if ( saveGasCollisions ) {
00406 ofstream of0("osteplen.dat",ios::app);
00407 std::copy( steps.begin(), steps.end(), std::ostream_iterator<float>(of0,"\n"));
00408 }
00409
00410 cout << "Total sum of steps = " << sum_steps << std::endl;
00411 if ( n_steps > 0 ) cout << "Average step length = " <<
00412 sum_steps/float(n_steps) << std::endl;
00413 cout << std::endl;
00414
00415 cout << "Energy loss per collision:" << std::endl;
00416 std::copy( elosses.begin(), elosses.end(), std::ostream_iterator<float>(cout,"\n"));
00417 cout << std::endl;
00418
00419 if ( saveGasCollisions ) {
00420 ofstream of1("olperc.dat",ios::app);
00421 std::copy( elosses.begin(), elosses.end(), std::ostream_iterator<float>(of1,"\n"));
00422 }
00423
00424 cout << "Total energy loss across gap = " << dedx << " eV = " <<
00425 dedx/1000. << " keV" << std::endl;
00426 int n_ic = count_if( elosses.begin(), elosses.end(),
00427 bind2nd(greater<float>(), eion) );
00428 cout << "No. of primary ionizing collisions across gap = " << n_ic << std::endl;
00429 if ( n_steps > 0 ) cout << "Average energy loss/collision = " <<
00430 dedx/float(n_steps) << " eV" << std::endl;
00431 cout << std::endl;
00432
00433 cout << "No. of ion clusters = " << ion_clusters.size() << std::endl;
00434 cout << "Positions of clusters:" << std::endl;
00435 std::copy( ion_clusters.begin(), ion_clusters.end(),
00436 std::ostream_iterator<LocalPoint>(cout,"\n"));
00437 cout << std::endl;
00438
00439 if ( saveGasCollisions ) {
00440 ofstream of2("oclpos.dat",ios::app);
00441 std::copy( ion_clusters.begin(), ion_clusters.end(),
00442 std::ostream_iterator<LocalPoint>(of2,"\n"));
00443 }
00444
00445 cout << "No. of electrons per cluster:" << std::endl;
00446 std::copy( electrons.begin(), electrons.end(), std::ostream_iterator<int>(cout,"\n"));
00447 cout << std::endl;
00448
00449 if ( saveGasCollisions ) {
00450 ofstream of3("oepercl.dat",ios::app);
00451 std::copy( electrons.begin(), electrons.end(), std::ostream_iterator<int>(of3,"\n"));
00452 }
00453
00454
00455 std::vector<int>::const_iterator bigger = find(electrons.begin(),
00456 electrons.end(), 0 );
00457 if ( bigger != electrons.end() ) {
00458 cout << "Error! There is a cluster with 0 electrons." << std::endl;
00459 }
00460 int n_e = accumulate(electrons.begin(), electrons.end(), 0 );
00461 if ( n_steps > 0 ) {
00462 cout << "# cm cm keV eV eV eV keV" << std::endl;
00463 cout << " " << n_steps << " " << sum_steps << " " << sum_steps/float(n_steps) << " " <<
00464 ion_clusters.size() << " " <<
00465 dedx/1000. << " " << n_ic << " " << dedx/float(n_steps) << " " << n_e << " " <<
00466 dedx/float(n_e) << " " << float(n_e)/float(ion_clusters.size()) << " " << simHiteloss*1.E6 << std::endl;
00467 }
00468 }
00469
00470 float CSCGasCollisions::lnEnergyLoss( float lnCollisions,
00471 const std::vector<float>& collisions ) const {
00472
00473 float lnE = -1.;
00474
00475
00476 std::vector<float>::const_iterator it = find(collisions.begin(),
00477 collisions.end(), lnCollisions );
00478
00479 if ( it != collisions.end() ) {
00480
00481 std::vector<float>::difference_type ihi = it - collisions.begin();
00482 LogTrace(me) << ": using one energy bin " << ihi << " = "
00483 << theEnergyBins[ihi]
00484 << " for lnCollisions = " << lnCollisions;
00485 lnE = theEnergyBins[ihi];
00486 }
00487 else {
00488
00489 std::vector<float>::const_iterator loside = find_if(collisions.begin(),
00490 collisions.end(), bind2nd(less<float>(), lnCollisions));
00491 std::vector<float>::difference_type ilo = loside - collisions.begin();
00492 if ( ilo > 0 ) {
00493 LogTrace(me) << ": using energy bin "
00494 << ilo-1 << " and " << ilo;
00495 lnE = theEnergyBins[ilo-1] + (lnCollisions-collisions[ilo-1])*
00496 (theEnergyBins[ilo]-theEnergyBins[ilo-1]) /
00497 (collisions[ilo]-collisions[ilo-1]);
00498 }
00499 else {
00500 LogTrace(me) << ": using one energy bin 0 = "
00501 << theEnergyBins[0]
00502 << " for lnCollisions = " << lnCollisions;
00503 lnE = theEnergyBins[0];
00504 }
00505 }
00506
00507 return lnE;
00508 }
00509
00510 void CSCGasCollisions::fillCollisionsForThisGamma( float logGamma,
00511 std::vector<float>& collisions ) const
00512 {
00513 std::vector<float>::const_iterator bigger = find_if(theGammaBins.begin(),
00514 theGammaBins.end(), bind2nd(greater<float>(), logGamma));
00515
00516 if ( bigger == theGammaBins.end() ) {
00517
00518 LogTrace(me) << ": using highest gamma bin"
00519 << " for logGamma = " << logGamma;
00520 for (int i=0; i<N_ENERGY; ++i)
00521 collisions[i] = theCollisionTable[i*N_GAMMA];
00522 }
00523 else {
00524
00525 std::vector<float>::difference_type ihi = bigger - theGammaBins.begin();
00526 if ( ihi > 0 ) {
00527 double dlg2 = *bigger--;
00528
00529
00530 double dlg1 = *bigger;
00531 double dlg = (logGamma-dlg1)/(dlg2-dlg1);
00532 double omdlg = 1. - dlg;
00533 for (int i=0; i<N_ENERGY; ++i)
00534 collisions[i] = theCollisionTable[i*N_GAMMA+ihi-1]*omdlg +
00535 theCollisionTable[i*N_GAMMA+ihi]*dlg;
00536 }
00537 else {
00538
00539 LogTrace(me) << ": using lowest gamma bin"
00540 << " for logGamma = " << logGamma;
00541
00542 for (int i=0; i<N_ENERGY; ++i)
00543 collisions[i] = theCollisionTable[i*N_GAMMA];
00544 }
00545 }
00546 }