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