00001
00002 #include "FWCore/Utilities/interface/Exception.h"
00003 #include "FWCore/ParameterSet/interface/FileInPath.h"
00004
00005 #include "FastSimulation/MaterialEffects/interface/NuclearInteractionSimulator.h"
00006 #include "FastSimulation/Utilities/interface/RandomEngine.h"
00007
00008 #include "FastSimDataFormats/NuclearInteractions/interface/NUEvent.h"
00009
00010
00011
00012
00013 #include <iostream>
00014 #include <sys/stat.h>
00015 #include <cmath>
00016 #include "TFile.h"
00017 #include "TTree.h"
00018 #include "TROOT.h"
00019
00020 NuclearInteractionSimulator::NuclearInteractionSimulator(
00021 std::vector<double>& pionEnergies,
00022 std::vector<int>& pionTypes,
00023 std::vector<std::string>& pionNames,
00024 std::vector<double>& pionMasses,
00025 std::vector<double>& pionPMin,
00026 double pionEnergy,
00027 std::vector<double>& lengthRatio,
00028 std::vector< std::vector<double> >& ratios,
00029 std::map<int,int >& idMap,
00030 std::string inputFile,
00031 unsigned int distAlgo,
00032 double distCut,
00033 const RandomEngine* engine)
00034 :
00035 MaterialEffectsSimulator(engine),
00036 thePionEN(pionEnergies),
00037 thePionID(pionTypes),
00038 thePionNA(pionNames),
00039 thePionMA(pionMasses),
00040 thePionPMin(pionPMin),
00041 thePionEnergy(pionEnergy),
00042 theLengthRatio(lengthRatio),
00043 theRatios(ratios),
00044 theIDMap(idMap),
00045 theDistAlgo(distAlgo),
00046 theDistCut(distCut)
00047
00048 {
00049
00050 gROOT->cd();
00051
00052 std::string fullPath;
00053
00054
00055
00056 std::vector<TFile*> aVFile(thePionEN.size(),static_cast<TFile*>(0));
00057 std::vector<TTree*> aVTree(thePionEN.size(),static_cast<TTree*>(0));
00058 std::vector<TBranch*> aVBranch(thePionEN.size(),static_cast<TBranch*>(0));
00059 std::vector<NUEvent*> aVNUEvents(thePionEN.size(),static_cast<NUEvent*>(0));
00060 std::vector<unsigned> aVCurrentEntry(thePionEN.size(),static_cast<unsigned>(0));
00061 std::vector<unsigned> aVCurrentInteraction(thePionEN.size(),static_cast<unsigned>(0));
00062 std::vector<unsigned> aVNumberOfEntries(thePionEN.size(),static_cast<unsigned>(0));
00063 std::vector<unsigned> aVNumberOfInteractions(thePionEN.size(),static_cast<unsigned>(0));
00064 std::vector<std::string> aVFileName(thePionEN.size(),static_cast<std::string>(""));
00065 std::vector<double> aVPionCM(thePionEN.size(),static_cast<double>(0));
00066 theFiles.resize(thePionNA.size());
00067 theTrees.resize(thePionNA.size());
00068 theBranches.resize(thePionNA.size());
00069 theNUEvents.resize(thePionNA.size());
00070 theCurrentEntry.resize(thePionNA.size());
00071 theCurrentInteraction.resize(thePionNA.size());
00072 theNumberOfEntries.resize(thePionNA.size());
00073 theNumberOfInteractions.resize(thePionNA.size());
00074 theFileNames.resize(thePionNA.size());
00075 thePionCM.resize(thePionNA.size());
00076 for ( unsigned iname=0; iname<thePionNA.size(); ++iname ) {
00077 theFiles[iname] = aVFile;
00078 theTrees[iname] = aVTree;
00079 theBranches[iname] = aVBranch;
00080 theNUEvents[iname] = aVNUEvents;
00081 theCurrentEntry[iname] = aVCurrentEntry;
00082 theCurrentInteraction[iname] = aVCurrentInteraction;
00083 theNumberOfEntries[iname] = aVNumberOfEntries;
00084 theNumberOfInteractions[iname] = aVNumberOfInteractions;
00085 theFileNames[iname] = aVFileName;
00086 thePionCM[iname] = aVPionCM;
00087 }
00088
00089
00090 bool input = this->read(inputFile);
00091 if ( input )
00092 std::cout << "***WARNING*** You are reading nuclear-interaction information from the file "
00093 << inputFile << " created in an earlier run."
00094 << std::endl;
00095
00096
00097 myOutputFile.open ("NuclearInteractionOutputFile.txt");
00098 myOutputBuffer = 0;
00099
00100
00101
00102
00103 unsigned fileNb = 0;
00104 for ( unsigned iname=0; iname<thePionNA.size(); ++iname ) {
00105 for ( unsigned iene=0; iene<thePionEN.size(); ++iene ) {
00106
00107 std::ostringstream filename;
00108 double theEne = thePionEN[iene];
00109 filename << "NuclearInteractionsVal_" << thePionNA[iname] << "_E"<< theEne << ".root";
00110 theFileNames[iname][iene] = filename.str();
00111
00112
00113 edm::FileInPath myDataFile("FastSimulation/MaterialEffects/data/"+theFileNames[iname][iene]);
00114 fullPath = myDataFile.fullPath();
00115
00116 theFiles[iname][iene] = TFile::Open(fullPath.c_str());
00117 if ( !theFiles[iname][iene] ) throw cms::Exception("FastSimulation/MaterialEffects")
00118 << "File " << theFileNames[iname][iene] << " " << fullPath << " not found ";
00119 ++fileNb;
00120
00121 theTrees[iname][iene] = (TTree*) theFiles[iname][iene]->Get("NuclearInteractions");
00122 if ( !theTrees[iname][iene] ) throw cms::Exception("FastSimulation/MaterialEffects")
00123 << "Tree with name NuclearInteractions not found in " << theFileNames[iname][iene];
00124
00125 theBranches[iname][iene] = theTrees[iname][iene]->GetBranch("nuEvent");
00126
00127 if ( !theBranches[iname][iene] ) throw cms::Exception("FastSimulation/MaterialEffects")
00128 << "Branch with name nuEvent not found in " << theFileNames[iname][iene];
00129
00130 theNUEvents[iname][iene] = new NUEvent();
00131
00132 theBranches[iname][iene]->SetAddress(&theNUEvents[iname][iene]);
00133
00134 theNumberOfEntries[iname][iene] = theTrees[iname][iene]->GetEntries();
00135
00136
00137 if ( !input )
00138 theCurrentEntry[iname][iene] = (unsigned) (theNumberOfEntries[iname][iene] * random->flatShoot());
00139
00140 theTrees[iname][iene]->GetEntry(theCurrentEntry[iname][iene]);
00141 unsigned NInteractions = theNUEvents[iname][iene]->nInteractions();
00142 theNumberOfInteractions[iname][iene] = NInteractions;
00143
00144 if ( !input )
00145 theCurrentInteraction[iname][iene] = (unsigned) (theNumberOfInteractions[iname][iene] * random->flatShoot());
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 XYZTLorentzVector Proton(0.,0.,0.,0.986);
00158 XYZTLorentzVector
00159 Reference(0.,
00160 0.,
00161 std::sqrt(thePionEN[iene]*thePionEN[iene]
00162 -thePionMA[iname]*thePionMA[iname]),
00163 thePionEN[iene]);
00164 thePionCM[iname][iene] = (Reference+Proton).M();
00165
00166 }
00167
00168 }
00169
00170
00171 ien4 = 0;
00172 while ( thePionEN[ien4] < 4.0 ) ++ien4;
00173
00174
00175 gROOT->cd();
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 }
00192
00193 NuclearInteractionSimulator::~NuclearInteractionSimulator() {
00194
00195
00196
00197
00198 for ( unsigned ifile=0; ifile<theFiles.size(); ++ifile ) {
00199 for ( unsigned iene=0; iene<theFiles[ifile].size(); ++iene ) {
00200
00201 theFiles[ifile][iene]->Close();
00202 }
00203 }
00204
00205
00206 myOutputFile.close();
00207
00208
00209 gROOT->cd();
00210
00211
00212
00213 }
00214
00215 void NuclearInteractionSimulator::compute(ParticlePropagator& Particle)
00216 {
00217
00218
00219
00220 double pHadron = std::sqrt(Particle.Vect().Mag2());
00221
00222
00223
00224 if ( pHadron > thePionEnergy ) {
00225
00226
00227 std::map<int,int>::const_iterator thePit = theIDMap.find(Particle.pid());
00228
00229 int thePid = thePit != theIDMap.end() ? thePit->second : Particle.pid();
00230
00231
00232 unsigned fPid = abs(thePid);
00233 if ( fPid != 211 && fPid != 130 && fPid != 321 && fPid != 2112 && fPid != 2212 ) {
00234 return;
00235
00236
00237 }
00238
00239
00240 unsigned thePidIndex = index(thePid);
00241 double theInelasticLength = radLengths * theLengthRatio[thePidIndex];
00242
00243
00244
00245 double ee = pHadron > 0.6 ?
00246 exp(-std::sqrt((pHadron-0.6)/1.122)) : exp(std::sqrt((0.6-pHadron)/1.122));
00247 double theElasticLength = ( 0.8753 * ee + 0.15 )
00248
00249
00250 * theInelasticLength;
00251
00252
00253 double theTotalInteractionLength = theInelasticLength + theElasticLength;
00254
00255
00256 double aNuclInteraction = -std::log(random->flatShoot());
00257 if ( aNuclInteraction < theTotalInteractionLength ) {
00258
00259
00260 double elastic = random->flatShoot();
00261 if ( elastic < theElasticLength/theTotalInteractionLength ) {
00262
00263
00264
00265
00266 double theta0 = std::sqrt(3.)/ std::pow(theA(),1./3.) * Particle.mass()/pHadron;
00267
00268
00269 double theta = theta0 * std::sqrt(-2.*std::log(random->flatShoot()));
00270 double phi = 2. * 3.14159265358979323 * random->flatShoot();
00271
00272
00273 RawParticle::Rotation rotation1(orthogonal(Particle.Vect()),theta);
00274 RawParticle::Rotation rotation2(Particle.Vect(),phi);
00275 Particle.rotate(rotation1);
00276 Particle.rotate(rotation2);
00277
00278
00279 double distance = std::sin(theta);
00280
00281
00282 if ( distance > theDistCut ) {
00283 _theUpdatedState.resize(1);
00284 _theUpdatedState[0].SetXYZT(Particle.Px(), Particle.Py(),
00285 Particle.Pz(), Particle.E());
00286 _theUpdatedState[0].setID(Particle.pid());
00287 }
00288
00289
00290
00291
00292 }
00293
00294
00295 else {
00296
00297
00298 const std::vector<double>& aPionCM = thePionCM[thePidIndex];
00299 const std::vector<double>& aRatios = theRatios[thePidIndex];
00300
00301
00302 XYZTLorentzVector Proton(0.,0.,0.,0.939);
00303
00304 const XYZTLorentzVector& Hadron = (const XYZTLorentzVector&)Particle;
00305
00306 double pMin = thePionPMin[thePidIndex];
00307
00308 XYZTLorentzVector Hadron0(0.,0.,pMin,std::sqrt(pMin*pMin+Particle.M2()));
00309
00310
00311 double ecm = (Proton+Hadron).M();
00312
00313
00314
00315
00316 unsigned ene1=0;
00317 unsigned ene2=0;
00318
00319
00320 double ecm1= (Proton+Hadron0).M();
00321
00322
00323
00324 double ecm2=aPionCM[0];
00325 double ratio1=0.;
00326 double ratio2=aRatios[0];
00327 if ( ecm > aPionCM[0] && ecm < aPionCM [ aPionCM.size()-1 ] ) {
00328 for ( unsigned ene=1;
00329 ene < aPionCM.size() && ecm > aPionCM[ene-1];
00330 ++ene ) {
00331 if ( ecm<aPionCM[ene] ) {
00332 ene2 = ene;
00333 ene1 = ene2-1;
00334 ecm1 = aPionCM[ene1];
00335 ecm2 = aPionCM[ene2];
00336 ratio1 = aRatios[ene1];
00337 ratio2 = aRatios[ene2];
00338 }
00339 }
00340 } else if ( ecm > aPionCM[ aPionCM.size()-1 ] ) {
00341 ene1 = aPionCM.size()-1;
00342 ene2 = aPionCM.size()-2;
00343 ecm1 = aPionCM[ene1];
00344 ecm2 = aPionCM[ene2];
00345 ratio1 = aRatios[ene2];
00346 ratio2 = aRatios[ene2];
00347 }
00348
00349
00350
00351 double slope = (std::log10(ecm )-std::log10(ecm1))
00352 / (std::log10(ecm2)-std::log10(ecm1));
00353 double inelastic = ratio1 + (ratio2-ratio1) * slope;
00354 double inelastic4 = pHadron < 4. ? aRatios[ien4] : 1.;
00355
00356
00357
00358
00359
00360
00361 if ( elastic > 1.- (inelastic*theInelasticLength)
00362 /theTotalInteractionLength ) {
00363
00364
00365 std::vector<unsigned>& aCurrentInteraction = theCurrentInteraction[thePidIndex];
00366 std::vector<unsigned>& aNumberOfInteractions = theNumberOfInteractions[thePidIndex];
00367 std::vector<NUEvent*>& aNUEvents = theNUEvents[thePidIndex];
00368
00369
00370
00371
00372
00373
00374
00375 unsigned ene;
00376 if ( random->flatShoot() < slope || aNumberOfInteractions[ene1] == 0 )
00377 ene = ene2;
00378 else
00379 ene = ene1;
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 XYZTLorentzVector theBoost = Proton + Hadron;
00391 theBoost /= theBoost.e();
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 if ( aCurrentInteraction[ene] == aNumberOfInteractions[ene] ) {
00403
00404 std::vector<unsigned>& aCurrentEntry = theCurrentEntry[thePidIndex];
00405 std::vector<unsigned>& aNumberOfEntries = theNumberOfEntries[thePidIndex];
00406 std::vector<TTree*>& aTrees = theTrees[thePidIndex];
00407 ++aCurrentEntry[ene];
00408
00409
00410 aCurrentInteraction[ene] = 0;
00411 if ( aCurrentEntry[ene] == aNumberOfEntries[ene] ) {
00412 aCurrentEntry[ene] = 0;
00413
00414 }
00415 unsigned myEntry = aCurrentEntry[ene];
00416
00417
00418 aTrees[ene]->GetEntry(myEntry);
00419
00420 aNumberOfInteractions[ene] = aNUEvents[ene]->nInteractions();
00421
00422 }
00423
00424
00425 NUEvent::NUInteraction anInteraction
00426 = aNUEvents[ene]->theNUInteractions()[aCurrentInteraction[ene]];
00427
00428 unsigned firstTrack = anInteraction.first;
00429 unsigned lastTrack = anInteraction.last;
00430
00431
00432 _theUpdatedState.resize(lastTrack-firstTrack+1);
00433
00434 double distMin = 1E99;
00435
00436
00437 XYZVector theAxis = theBoost.Vect().Unit();
00438 double theAngle = random->flatShoot() * 2. * 3.14159265358979323;
00439 RawParticle::Rotation axisRotation(theAxis,theAngle);
00440 RawParticle::Boost axisBoost(theBoost.x(),theBoost.y(),theBoost.z());
00441
00442
00443 XYZVector zAxis(0.,0.,1.);
00444 XYZVector orthAxis = (zAxis.Cross(theBoost.Vect())).Unit();
00445 double orthAngle = acos(theBoost.Vect().Unit().Z());
00446 RawParticle::Rotation orthRotation(orthAxis,orthAngle);
00447
00448
00449
00450
00451
00452 for ( unsigned iTrack=firstTrack; iTrack<=lastTrack; ++iTrack ) {
00453
00454 unsigned idaugh = iTrack - firstTrack;
00455 NUEvent::NUParticle aParticle = aNUEvents[ene]->theNUParticles()[iTrack];
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 double energy = std::sqrt( aParticle.px*aParticle.px
00467 + aParticle.py*aParticle.py
00468 + aParticle.pz*aParticle.pz
00469 + aParticle.mass*aParticle.mass/(ecm*ecm) );
00470
00471 RawParticle& aDaughter = _theUpdatedState[idaugh];
00472 aDaughter.SetXYZT(aParticle.px*ecm,aParticle.py*ecm,
00473 aParticle.pz*ecm,energy*ecm);
00474 aDaughter.setID(aParticle.id);
00475
00476
00477 aDaughter.rotate(orthRotation);
00478
00479
00480 aDaughter.rotate(axisRotation);
00481
00482
00483 aDaughter.boost(axisBoost);
00484
00485
00486 double distance = distanceToPrimary(Particle,aDaughter);
00487
00488 if ( distance < distMin && distance < theDistCut ) {
00489 distMin = distance;
00490 theClosestChargedDaughterId = idaugh;
00491 }
00492
00493
00494
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508 ++aCurrentInteraction[ene];
00509
00510
00511 } else if ( pHadron < 4. &&
00512 elastic > 1.- (inelastic4*theInelasticLength)
00513 /theTotalInteractionLength ) {
00514
00515 _theUpdatedState.resize(1);
00516 _theUpdatedState[0].SetXYZT(0.,0.,0.,0.);
00517 _theUpdatedState[0].setID(22);
00518 }
00519
00520 }
00521
00522 }
00523
00524 }
00525
00526 }
00527
00528 double
00529 NuclearInteractionSimulator::distanceToPrimary(const RawParticle& Particle,
00530 const RawParticle& aDaughter) const {
00531
00532 double distance = 2E99;
00533
00534
00535 if ( fabs(Particle.charge()) > 1E-12 ) {
00536
00537
00538 double chargeDiff = fabs(aDaughter.charge()-Particle.charge());
00539 if ( fabs(chargeDiff) < 1E-12 ) {
00540
00541
00542 switch ( theDistAlgo ) {
00543
00544 case 1:
00545
00546 distance = (aDaughter.Vect().Unit().Cross(Particle.Vect().Unit())).R();
00547 break;
00548
00549 case 2:
00550
00551 distance = (aDaughter.Vect().Cross(Particle.Vect())).R()
00552 /aDaughter.Vect().Mag2();
00553 break;
00554
00555 default:
00556
00557 distance = 2E99;
00558 break;
00559
00560 }
00561
00562 }
00563
00564 }
00565
00566 return distance;
00567
00568 }
00569
00570 void
00571 NuclearInteractionSimulator::save() {
00572
00573
00574 ++myOutputBuffer;
00575
00576
00577 if ( myOutputBuffer/1000*1000 == myOutputBuffer ) {
00578 myOutputFile.close();
00579 myOutputFile.open ("NuclearInteractionOutputFile.txt");
00580
00581 }
00582
00583 unsigned size1 =
00584 theCurrentEntry.size()*
00585 theCurrentEntry.begin()->size();
00586 std::vector<unsigned> theCurrentEntries;
00587 theCurrentEntries.resize(size1);
00588 size1*=sizeof(unsigned);
00589
00590 unsigned size2 =
00591 theCurrentInteraction.size()*
00592 theCurrentInteraction.begin()->size();
00593 std::vector<unsigned> theCurrentInteractions;
00594 theCurrentInteractions.resize(size2);
00595 size2 *= sizeof(unsigned);
00596
00597
00598 std::vector< std::vector<unsigned> >::const_iterator aCurrentEntry = theCurrentEntry.begin();
00599 std::vector< std::vector<unsigned> >::const_iterator lastCurrentEntry = theCurrentEntry.end();
00600 unsigned allEntries=0;
00601 for ( ; aCurrentEntry!=lastCurrentEntry; ++aCurrentEntry ) {
00602 unsigned size = aCurrentEntry->size();
00603 for ( unsigned iene=0; iene<size; ++iene )
00604 theCurrentEntries[allEntries++] = (*aCurrentEntry)[iene];
00605 }
00606
00607
00608 std::vector< std::vector<unsigned> >::const_iterator aCurrentInteraction = theCurrentInteraction.begin();
00609 std::vector< std::vector<unsigned> >::const_iterator lastCurrentInteraction = theCurrentInteraction.end();
00610 unsigned allInteractions=0;
00611 for ( ; aCurrentInteraction!=lastCurrentInteraction; ++aCurrentInteraction ) {
00612 unsigned size = aCurrentInteraction->size();
00613 for ( unsigned iene=0; iene<size; ++iene )
00614 theCurrentInteractions[allInteractions++] = (*aCurrentInteraction)[iene];
00615 }
00616
00617 myOutputFile.write((const char*)(&theCurrentEntries.front()), size1);
00618 myOutputFile.write((const char*)(&theCurrentInteractions.front()), size2);
00619 myOutputFile.flush();
00620
00621 }
00622
00623 bool
00624 NuclearInteractionSimulator::read(std::string inputFile) {
00625
00626 ifstream myInputFile;
00627 struct stat results;
00628
00629 unsigned size1 =
00630 theCurrentEntry.size()*
00631 theCurrentEntry.begin()->size();
00632 std::vector<unsigned> theCurrentEntries;
00633 theCurrentEntries.resize(size1);
00634 size1*=sizeof(unsigned);
00635
00636 unsigned size2 =
00637 theCurrentInteraction.size()*
00638 theCurrentInteraction.begin()->size();
00639 std::vector<unsigned> theCurrentInteractions;
00640 theCurrentInteractions.resize(size2);
00641 size2 *= sizeof(unsigned);
00642
00643 unsigned size = 0;
00644
00645
00646
00647 myInputFile.open (inputFile.c_str());
00648 if ( myInputFile.is_open() ) {
00649
00650
00651 if ( stat(inputFile.c_str(), &results) == 0 ) size = results.st_size;
00652 else return false;
00653
00654
00655 myInputFile.seekg(size-size1-size2);
00656 myInputFile.read((char*)(&theCurrentEntries.front()),size1);
00657 myInputFile.read((char*)(&theCurrentInteractions.front()),size2);
00658 myInputFile.close();
00659
00660
00661 std::vector< std::vector<unsigned> >::iterator aCurrentEntry = theCurrentEntry.begin();
00662 std::vector< std::vector<unsigned> >::iterator lastCurrentEntry = theCurrentEntry.end();
00663 unsigned allEntries=0;
00664 for ( ; aCurrentEntry!=lastCurrentEntry; ++aCurrentEntry ) {
00665 unsigned size = aCurrentEntry->size();
00666 for ( unsigned iene=0; iene<size; ++iene )
00667 (*aCurrentEntry)[iene] = theCurrentEntries[allEntries++];
00668 }
00669
00670
00671 std::vector< std::vector<unsigned> >::iterator aCurrentInteraction = theCurrentInteraction.begin();
00672 std::vector< std::vector<unsigned> >::iterator lastCurrentInteraction = theCurrentInteraction.end();
00673 unsigned allInteractions=0;
00674 for ( ; aCurrentInteraction!=lastCurrentInteraction; ++aCurrentInteraction ) {
00675 unsigned size = aCurrentInteraction->size();
00676 for ( unsigned iene=0; iene<size; ++iene )
00677 (*aCurrentInteraction)[iene] = theCurrentInteractions[allInteractions++];
00678 }
00679
00680 return true;
00681 }
00682
00683 return false;
00684
00685 }
00686
00687 unsigned
00688 NuclearInteractionSimulator::index(int thePid) {
00689
00690 unsigned myIndex=0;
00691 while ( thePid != thePionID[myIndex] ) ++myIndex;
00692
00693 return myIndex;
00694
00695 }