CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch12/src/SimMuon/CSCDigitizer/src/CSCGasCollisions.cc

Go to the documentation of this file.
00001 // This implements the CSC gas ionization simulation.
00002 // It requires the GEANT3-generated tables in the input file 
00003 // (default) MuonData/EndcapData/collisions.dat
00004 
00005 // Outstanding problems to fix 15-Oct-2003
00006 // - ework must be re-tuned once eion or ework are removed before delta e range estimation.
00007 // - logic of long-range delta e's must be revisited.
00008 // - The code here needs to have diagnostic output removed, or reduced. PARTICULARLY filling of std::vectors!
00009 // - 'gap' is a misnomer, when simhit entry and exit don't coincide with gap edges
00010 //  so the CSCCrossGap might better be named as a simhit-related thing. 
00011 // 22-Jan-2004 Corrected position of trap for 'infinite' loop while
00012 //    generating steps. Output files (debugV-flagged only) require SC flag.
00013 //    Increase deCut from 10 keV to 100 keV to accomodate protons!
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 // stdlib math functions
00024 // for 'abs':
00025 #include <cstdlib>
00026 // for usual math functions:
00027 #include <cmath>
00028 
00029 // stdlib container trickery
00030 // for 'for_each':
00031 #include <algorithm>
00032 // for 'greater' and 'less':
00033 #include <functional>
00034 // for 'accumulate':
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   // I'd prefer to allow comments in the data file which means
00073   // complications of reading line-by-line and then item-by-item.
00074 
00075   // Is float OK? Or do I need double?
00076 
00077   // Do I need any sort of error trapping?
00078 
00079   // We use the default CMSSW data file path
00080   // We use the default file name 'collisions.dat'
00081    
00082   // This can be reset in .orcarc by SimpleConfigurable
00083   //    Muon:Endcap:CollisionsFile
00084 
00085   string path( getenv( "CMSSW_SEARCH_PATH" ) );
00086   // TODO make configurable
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( );                  // Clear eof read status
00109   fin.seekg( 0, ios::beg );      // Position at start of file
00110 
00111   // @@ We had better have the right sizes everywhere or all
00112   // hell will break loose. There's no trapping.
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;                     // Shortness of simhit 'length'
00156   //  const float max_gap_z = 1.5;                     // Gas gaps are 0.5 or 1.0 cm
00157 
00158   // Note that what I call the 'gap' may in fact be the 'length' of a PSimHit which
00159   // does not start and end on the gap edges. This confuses the nomenclature at least.
00160 
00161   double mom    = simHit.pabs();
00162   int iam       = simHit.particleType();           // PDG type
00163   delete theCrossGap;                              // before building new one
00164   assert(theParticleDataTable != 0);
00165   ParticleData const * particle = theParticleDataTable->particle( simHit.particleType() );
00166   double mass = 0.105658; // assume a muon
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   // Test the simhit 'length' (beware of angular effects)
00181   //  if ( gapSize <= epsilonL || gapSize > max_gap_z ) {
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; //@@ Just skip this PSimHit
00189   }
00190 
00191   // Interpolate the table for current gamma value
00192   // Extract collisions binned by energy loss values, for this gamma
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.; // total energy loss
00207   double sum_steps = 0.; // total distance across gap (along simhit direction)
00208   int n_steps      = 0;  // no. of steps/primary collisions
00209   int n_try        = 0;  // no. of tries to generate steps
00210   double step      = -1.; // Sentinel for start
00211 
00212   //LocalPoint chamberLocalPoint( simHit.entryPoint() );
00213   // translate to layer local coordinates
00214   //GlobalPoint globalPoint( layer->chamber()->toGlobal(chamberLocalPoint) );
00215   //LocalPoint layerLocalPoint( layer->toLocal(globalPoint) );
00216   LocalPoint layerLocalPoint( simHit.entryPoint() );
00217 
00218   //std::cout << "DEBUG " << chamberLocalPoint << " " << layerLocalPoint << std::endl;
00219   // step/primary collision loop
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     // Is the eloss too large? (then GEANT should have produced hits!)
00235     if ( eloss > deCut ) {
00236       LogTrace(me) << "eloss > " << deCut << " = " << eloss;
00237       continue; // to generate another collision/step
00238     }
00239 
00240     dedx      += eloss; // the energy lost from the ionizing particle
00241     sum_steps += step;  // the position of the ionizing particle
00242     ++n_steps;          // the number of primary collisions
00243     
00244     if (n_steps > MAX_STEPS ) { // Extra-careful trap for bizarreness
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     // Generate ionization. 
00254     // eion is the minimum energy at which ionization can occur in the gas
00255     if ( eloss > eion  ) {
00256       layerLocalPoint += step * theCrossGap->unitVector(); // local point where the collision occurs
00257       ionize( eloss, layerLocalPoint );
00258     }
00259     else {
00260       LogTrace(me) << "Energy available = " << eloss <<
00261         ", too low for ionization.";
00262     }
00263 
00264   } // step/collision loop
00265 
00266   //TODO port this
00267   //if ( debugV ) writeSummary( n_steps, sum_steps, dedx );
00268 
00269   // Return values in two container arguments
00270   positions = theCrossGap->ionClusters();
00271   electrons = theCrossGap->electrons();
00272   return;
00273 }
00274 
00275 double CSCGasCollisions::generateStep( double avCollisions ) const
00276 {
00277 // Generate a m.f.p.  (1/avCollisions = cm/collision)
00278   double step = (theRandExponential->fire())/avCollisions;
00279 
00280 // Without using CLHEP: approx random exponential by...
00281 //    double da = double(rand())/double(RAND_MAX);
00282 //    double step = -log(1.-da)/avCollisions;
00283 
00284     LogTrace(me)  << " step = " << step;
00285     // Next line only used to fill a container of 'step's for later diagnostic dumps
00286     //if ( debugV ) theCrossGap->addStep( step );
00287     return step;
00288 }
00289 
00290 float CSCGasCollisions::generateEnergyLoss( double avCollisions,
00291    double anmin, double anmax, const std::vector<float>& collisions ) const
00292 {
00293 // Generate a no. of collisions between collisions[0] and [N_ENERGY-1]
00294     float lnColl = log(theRandFlat->fire(anmin, anmax));
00295 
00296 // Without using CLHEP: approx random between anmin and anmax
00297 //    double ra = double(rand())/double(RAND_MAX)*avCollisions;
00298 //    cout << "ra = " << ra << std::endl;
00299 //    float lnColl = static_cast<float>( log( ra ) );
00300 
00301     // Find energy loss for that number
00302     float lnE    = lnEnergyLoss( lnColl, collisions );
00303     float eloss  = exp(lnE);
00304     // Compensate if gamma was actually below 1.1
00305     if ( theCrossGap->gamma() < 1.1 ) eloss = eloss * 0.173554/theCrossGap->beta2();
00306     LogTrace(me) << "eloss = " << eloss;
00307     // Next line only used to fill container of eloss's for later diagnostic dumps
00308     // if ( debugV ) theCrossGap->addEloss( eloss );
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   //@@ I consider NOT subtracting eion before calculating range to be a bug.
00321   //@@ But this changes tuning of the algorithm so leave it until after the big rush to 7_5_0
00322   //@@  energyAvailable -= eion; 
00323 
00324   // Sauli CERN 77-09: delta e range with E in MeV (Sauli references Kobetich & Katz 1968,
00325   // but I cannot find this expression in that set of papers.)
00326   // Take HALF that range. //@@ Why? Why not...
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       // short-range delta e
00332           // How many electrons can we make? Now use *average* energy for ionization (not *minimum*)
00333       int nelec = static_cast<int>(energyAvailable/ework);
00334       LogTrace(me) << "s-r delta energy in = " << energyAvailable;
00335       energyAvailable -= nelec*(energyAvailable/ework);
00336             // If still above eion (minimum, not average) add one more e
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       // long-range delta e
00348          LogTrace(me) << "l-r delta \n"
00349              << "no. of electrons in cluster now = " << theCrossGap->noOfElectrons();
00350          theCrossGap->addElectrons( 1 ); // Position is at startHere still
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(); // increment last element
00362               }
00363               else {
00364                 startHere += drange*theCrossGap->unitVector(); // update delta e start position
00365                 range = range2;                       // update range
00366                 new_range = true;                     // Test range again
00367                 LogTrace(me) << "reset range to range2 and iterate";
00368               }
00369               break; // out of inner while energyAvailable>eion
00370 
00371             } // inner while energyAvailable>eion
00372 
00373           } // while !new_range && energyAvailable>ework
00374 
00375           // energyAvailable now less than ework, but still may be over eion...add an e
00376           if ( energyAvailable > eion ) {
00377             energyAvailable -= ework; // yes, it may go negative
00378             theCrossGap->addElectronToBack(); // add one more e
00379           }
00380 
00381         } // if range
00382 
00383       } // outer while energyAvailable>eion
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     // Check for zero-e clusters
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    // Find collision[] bin in which lnCollisions falls
00480     std::vector<float>::const_iterator it = find(collisions.begin(),
00481       collisions.end(), lnCollisions );
00482 
00483     if ( it != collisions.end() ) {
00484       // found the value
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       // interpolate the value
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]; //@@ WHAT ELSE TO DO?
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     // use highest bin
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     // use bigger and its lower neighbour
00529     std::vector<float>::difference_type ihi = bigger - theGammaBins.begin();
00530     if ( ihi > 0 ) {
00531       double dlg2 = *bigger--; // and decrement after deref
00532       //LogTrace(me) << ": using gamma bins " 
00533       //                   << ihi-1 << " and " << ihi;
00534       double dlg1 = *bigger;   // now the preceding element
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       // bigger has no lower neighbour
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 }