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