14 #include <Math/AxisAngle.h> 15 #include "Math/Boost.h" 75 std::vector<std::unique_ptr<fastsim::Particle> >& secondaries,
80 unsigned index(
int thePid);
128 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 9.0, 12.0, 15.0, 20.0, 30.0, 50.0, 100.0, 200.0, 300.0, 500.0, 700.0, 1000.0};
133 const std::vector<int>
theHadronID = {211, -211, 130, 321, -321, 2212, -2212, 2112, -2112};
136 "piplus",
"piminus",
"K0L",
"Kplus",
"Kminus",
"p",
"pbar",
"n",
"nbar"};
139 0.13957, 0.13957, 0.497648, 0.493677, 0.493677, 0.93827, 0.93827, 0.939565, 0.939565};
141 const std::vector<double>
theHadronPMin = {0.7, 0.0, 1.0, 1.0, 0.0, 1.1, 0.0, 1.1, 0.0};
330 const std::vector<int>
protonsID = {2212, 3222, -101, -102, -103, -104};
332 const std::vector<int>
neutronsID = {2112, 3122, 3112, 3312, 3322, 3334, -3334};
334 const std::vector<int>
K0LsID = {130, 310};
382 for (
const auto&
id :
K0LsID)
400 TFile* aVFile =
nullptr;
402 std::vector<TBranch*> aVBranch(
theHadronEN.size());
403 std::vector<NUEvent*> aVNUEvents(
theHadronEN.size());
404 std::vector<unsigned> aVCurrentEntry(
theHadronEN.size());
405 std::vector<unsigned> aVCurrentInteraction(
theHadronEN.size());
406 std::vector<unsigned> aVNumberOfEntries(
theHadronEN.size());
407 std::vector<unsigned> aVNumberOfInteractions(
theHadronEN.size());
408 std::vector<std::string> aVFileName(
theHadronEN.size());
409 std::vector<double> aVHadronCM(
theHadronEN.size());
420 for (
unsigned iname = 0; iname <
theHadronNA.size(); ++iname) {
435 std::cout <<
"***WARNING*** You are reading nuclear-interaction information from the file " <<
inputFile 436 <<
" created in an earlier run." << std::endl;
443 edm::FileInPath myDataFile(
"FastSimulation/MaterialEffects/data/NuclearInteractions.root");
449 for (
unsigned iname = 0; iname <
theHadronNA.size(); ++iname) {
450 for (
unsigned iene = 0; iene <
theHadronEN.size(); ++iene) {
461 throw cms::Exception(
"FastSimulation/MaterialEffects") <<
"Tree with name " << treeName <<
" not found ";
465 <<
"Branch with name nuEvent not found in " <<
theFileNames[iname][iene];
473 unsigned NInteractions =
theNUEvents[iname][iene]->nInteractions();
484 theHadronCM[iname][iene] = (Reference + Proton).M();
503 for (
auto& vEvents : theNUEvents) {
504 for (
auto evtPtr : vEvents) {
512 myOutputFile.close();
517 std::vector<std::unique_ptr<fastsim::Particle> >& secondaries,
527 double radLengths = layer.getThickness(particle.
position(), particle.
momentum());
529 radLengths *= layer.getNuclearInteractionThicknessFactor();
533 if (radLengths < 1E-10) {
538 if (!currentValuesWereSet) {
539 currentValuesWereSet =
true;
540 for (
unsigned iname = 0; iname < theHadronNA.size(); ++iname) {
541 for (
unsigned iene = 0; iene < theHadronEN.size(); ++iene) {
542 theCurrentEntry[iname][iene] = (unsigned)(theNumberOfEntries[iname][iene] * random.
flatShoot());
544 theTrees[iname][iene]->GetEntry(theCurrentEntry[iname][iene]);
545 unsigned NInteractions = theNUEvents[iname][iene]->nInteractions();
546 theNumberOfInteractions[iname][iene] = NInteractions;
548 theCurrentInteraction[iname][iene] = (unsigned)(theNumberOfInteractions[iname][iene] * random.
flatShoot());
559 if (pHadron < theHadronEnergy) {
564 std::map<int, int>::const_iterator thePit = theIDMap.find(
pdgId);
566 int thePid = (thePit != theIDMap.end() ? thePit->second :
pdgId);
569 unsigned fPid =
abs(thePid);
570 if (fPid != 211 && fPid != 130 && fPid != 321 && fPid != 2112 && fPid != 2212) {
575 unsigned thePidIndex =
index(thePid);
577 double theInelasticLength = radLengths * theLengthRatio[thePidIndex];
582 double theElasticLength = (0.8753 * ee + 0.15) * theInelasticLength;
585 double theTotalInteractionLength = theInelasticLength + theElasticLength;
591 if (aNuclInteraction > theTotalInteractionLength) {
597 if (elastic < theElasticLength / theTotalInteractionLength) {
608 ROOT::Math::AxisAngle rotation1(orthogonal(particle.
momentum().Vect()),
theta);
609 ROOT::Math::AxisAngle rotation2(particle.
momentum().Vect(), phi);
615 secondaries.emplace_back(
621 if (particle.
charge() != 0) {
622 secondaries.back()->setMotherDeltaR(particle.
momentum());
623 secondaries.back()->setMotherPdgId(
pdgId);
624 secondaries.back()->setMotherSimTrackIndex(particle.
simTrackIndex());
628 particle.
momentum().SetXYZT(0., 0., 0., 0.);
631 particle.
momentum().SetXYZT(rotated.X(), rotated.Y(), rotated.Z(), particle.
momentum().E());
636 const std::vector<double>& aHadronCM = theHadronCM[thePidIndex];
637 const std::vector<double>& aRatios = theRatiosMap[thePidIndex];
644 double pMin = theHadronPMin[thePidIndex];
649 double ecm = (Proton + Hadron).M();
655 double ecm1 = (Proton + Hadron0).M();
657 double ecm2 = aHadronCM[0];
659 double ratio2 = aRatios[0];
660 if (ecm > aHadronCM[0] && ecm < aHadronCM[aHadronCM.size() - 1]) {
661 for (
unsigned ene = 1; ene < aHadronCM.size() && ecm > aHadronCM[ene - 1]; ++ene) {
662 if (ecm < aHadronCM[ene]) {
665 ecm1 = aHadronCM[ene1];
666 ecm2 = aHadronCM[ene2];
667 ratio1 = aRatios[ene1];
668 ratio2 = aRatios[ene2];
671 }
else if (ecm > aHadronCM[aHadronCM.size() - 1]) {
672 ene1 = aHadronCM.size() - 1;
673 ene2 = aHadronCM.size() - 2;
674 ecm1 = aHadronCM[ene1];
675 ecm2 = aHadronCM[ene2];
676 ratio1 = aRatios[ene2];
677 ratio2 = aRatios[ene2];
681 double slope = (std::log10(ecm) - std::log10(ecm1)) / (std::log10(ecm2) - std::log10(ecm1));
682 double inelastic = ratio1 + (ratio2 - ratio1) *
slope;
683 double inelastic4 = pHadron < 4. ? aRatios[ien4] : 1.;
686 if (elastic > 1. - (inelastic * theInelasticLength) / theTotalInteractionLength) {
688 std::vector<unsigned>& aCurrentInteraction = theCurrentInteraction[thePidIndex];
689 std::vector<unsigned>& aNumberOfInteractions = theNumberOfInteractions[thePidIndex];
690 std::vector<NUEvent*>& aNUEvents = theNUEvents[thePidIndex];
696 if (random.
flatShoot() <
slope || aNumberOfInteractions[ene1] == 0) {
704 theBoost /= theBoost.e();
708 if (aCurrentInteraction[ene] == aNumberOfInteractions[ene]) {
709 std::vector<unsigned>& aCurrentEntry = theCurrentEntry[thePidIndex];
710 std::vector<unsigned>& aNumberOfEntries = theNumberOfEntries[thePidIndex];
711 std::vector<TTree*>& aTrees = theTrees[thePidIndex];
712 ++aCurrentEntry[ene];
714 aCurrentInteraction[ene] = 0;
715 if (aCurrentEntry[ene] == aNumberOfEntries[ene]) {
716 aCurrentEntry[ene] = 0;
719 unsigned myEntry = aCurrentEntry[ene];
720 aTrees[ene]->GetEntry(myEntry);
721 aNumberOfInteractions[ene] = aNUEvents[ene]->nInteractions();
727 unsigned firstTrack = anInteraction.
first;
728 unsigned lastTrack = anInteraction.
last;
731 XYZVector theAxis = theBoost.Vect().Unit();
733 ROOT::Math::AxisAngle axisRotation(theAxis, theAngle);
734 ROOT::Math::Boost axisBoost(theBoost.x(), theBoost.y(), theBoost.z());
739 double orthAngle = acos(theBoost.Vect().Unit().Z());
740 ROOT::Math::AxisAngle orthRotation(orthAxis, orthAngle);
743 for (
unsigned iTrack = firstTrack; iTrack <= lastTrack; ++iTrack) {
749 aParticle.
pz * aParticle.
pz + aParticle.
mass * aParticle.
mass / (ecm * ecm));
754 XYZVector rotated = orthRotation(daugtherMomentum.Vect());
756 rotated = axisRotation(rotated);
759 daugtherMomentum.SetXYZT(rotated.X(), rotated.Y(), rotated.Z(), daugtherMomentum.E());
762 daugtherMomentum = axisBoost(daugtherMomentum);
771 if (particle.
charge() != 0) {
772 secondaries.back()->setMotherDeltaR(particle.
momentum());
773 secondaries.back()->setMotherPdgId(
pdgId);
774 secondaries.back()->setMotherSimTrackIndex(particle.
simTrackIndex());
779 particle.
momentum().SetXYZT(0., 0., 0., 0.);
787 ++aCurrentInteraction[ene];
790 }
else if (pHadron < 4. && elastic > 1. - (inelastic4 * theInelasticLength) / theTotalInteractionLength) {
792 particle.
momentum().SetXYZT(0., 0., 0., 0.);
802 if (myOutputBuffer / 1000 * 1000 == myOutputBuffer) {
803 myOutputFile.close();
804 myOutputFile.open(
"NuclearInteractionOutputFile.txt");
807 unsigned size1 = theCurrentEntry.size() * theCurrentEntry.begin()->size();
808 std::vector<unsigned> theCurrentEntries;
809 theCurrentEntries.resize(size1);
810 size1 *=
sizeof(unsigned);
812 unsigned size2 = theCurrentInteraction.size() * theCurrentInteraction.begin()->size();
813 std::vector<unsigned> theCurrentInteractions;
814 theCurrentInteractions.resize(size2);
815 size2 *=
sizeof(unsigned);
818 std::vector<std::vector<unsigned> >::const_iterator aCurrentEntry = theCurrentEntry.begin();
819 std::vector<std::vector<unsigned> >::const_iterator lastCurrentEntry = theCurrentEntry.end();
820 unsigned allEntries = 0;
821 for (; aCurrentEntry != lastCurrentEntry; ++aCurrentEntry) {
822 unsigned size = aCurrentEntry->size();
823 for (
unsigned iene = 0; iene <
size; ++iene)
824 theCurrentEntries[allEntries++] = (*aCurrentEntry)[iene];
828 std::vector<std::vector<unsigned> >::const_iterator aCurrentInteraction = theCurrentInteraction.begin();
829 std::vector<std::vector<unsigned> >::const_iterator lastCurrentInteraction = theCurrentInteraction.end();
830 unsigned allInteractions = 0;
831 for (; aCurrentInteraction != lastCurrentInteraction; ++aCurrentInteraction) {
832 unsigned size = aCurrentInteraction->size();
833 for (
unsigned iene = 0; iene <
size; ++iene)
834 theCurrentInteractions[allInteractions++] = (*aCurrentInteraction)[iene];
837 myOutputFile.write((
const char*)(&theCurrentEntries.front()), size1);
838 myOutputFile.write((
const char*)(&theCurrentInteractions.front()), size2);
839 myOutputFile.flush();
843 std::ifstream myInputFile;
846 unsigned size1 = theCurrentEntry.size() * theCurrentEntry.begin()->size();
847 std::vector<unsigned> theCurrentEntries;
848 theCurrentEntries.resize(size1);
849 size1 *=
sizeof(unsigned);
851 unsigned size2 = theCurrentInteraction.size() * theCurrentInteraction.begin()->size();
852 std::vector<unsigned> theCurrentInteractions;
853 theCurrentInteractions.resize(size2);
854 size2 *=
sizeof(unsigned);
860 if (myInputFile.is_open()) {
868 myInputFile.seekg(
size - size1 - size2);
869 myInputFile.read((
char*)(&theCurrentEntries.front()), size1);
870 myInputFile.read((
char*)(&theCurrentInteractions.front()), size2);
874 std::vector<std::vector<unsigned> >::iterator aCurrentEntry = theCurrentEntry.begin();
875 std::vector<std::vector<unsigned> >::iterator lastCurrentEntry = theCurrentEntry.end();
876 unsigned allEntries = 0;
877 for (; aCurrentEntry != lastCurrentEntry; ++aCurrentEntry) {
878 unsigned size = aCurrentEntry->size();
879 for (
unsigned iene = 0; iene <
size; ++iene)
880 (*aCurrentEntry)[iene] = theCurrentEntries[allEntries++];
884 std::vector<std::vector<unsigned> >::iterator aCurrentInteraction = theCurrentInteraction.begin();
885 std::vector<std::vector<unsigned> >::iterator lastCurrentInteraction = theCurrentInteraction.end();
886 unsigned allInteractions = 0;
887 for (; aCurrentInteraction != lastCurrentInteraction; ++aCurrentInteraction) {
888 unsigned size = aCurrentInteraction->size();
889 for (
unsigned iene = 0; iene <
size; ++iene)
890 (*aCurrentInteraction)[iene] = theCurrentInteractions[allInteractions++];
901 unsigned myIndex = 0;
902 while (thePid != theHadronID[myIndex])
908 double x = fabs(aVector.X());
909 double y = fabs(aVector.Y());
910 double z = fabs(aVector.Z());
913 return x <
z ?
XYZVector(0., aVector.Z(), -aVector.Y()) :
XYZVector(aVector.Y(), -aVector.X(), 0.);
915 return y <
z ?
XYZVector(-aVector.Z(), 0., aVector.X()) :
XYZVector(aVector.Y(), -aVector.X(), 0.);
const std::vector< int > antineutronsID
PdgID of anti-neutrons.
const std::vector< int > PiplussesID
PdgID of pt+.
std::vector< std::vector< unsigned > > theCurrentInteraction
Necessary to read the FullSim interactions.
Implementation of a generic detector layer (base class for forward/barrel layers).
double theDistCut
Cut on deltaR for the FastSim Tracking (ClosestChargedDaughter algorithm)
const std::vector< int > KminussesID
PdgID of K-.
std::string fullPath() const
static const double slope[3]
Sin< T >::type sin(const T &t)
std::vector< std::vector< unsigned > > theNumberOfEntries
Necessary to read the FullSim interactions.
bool currentValuesWereSet
Read data from file that was created in a previous run.
std::string to_string(const V &value)
const math::XYZTLorentzVector & position() const
Return position of the particle.
const std::vector< int > KplussesID
PdgID of K+.
std::vector< std::vector< std::string > > theFileNames
Necessary to read the FullSim interactions.
TFile * theFile
Necessary to read the FullSim interactions.
static std::vector< std::vector< double > > theRatiosMap
The evolution of the interaction lengths with energy.
std::vector< std::vector< double > > theHadronCM
Necessary to read the FullSim interactions.
std::vector< std::vector< NUEvent * > > theNUEvents
Necessary to read the FullSim interactions.
Implementation of nuclear interactions of hadrons in the tracker layers (based on fully simulated int...
const std::vector< int > protonsID
PdgID of protons.
const std::vector< double > theLengthRatio
Inelastic interaction length at p(Hadron) = 5 GeV/c (relativ to radionLength of material) ...
XYZTLorentzVectorD XYZTLorentzVector
Lorentz vector with cylindrical internal representation using pseudorapidity.
Base class for any interaction model between a particle and a tracker layer.
const std::vector< double > theRatios
Filled into 'theRatiosMap' (evolution of the interaction lengths with energy)
void interact(fastsim::Particle &particle, const SimplifiedGeometry &layer, std::vector< std::unique_ptr< fastsim::Particle > > &secondaries, const RandomEngineAndDistribution &random) override
Perform the interaction.
const std::vector< int > K0LsID
PdgID of K0.
const std::vector< int > antiprotonsID
PdgID of anti-protons.
static std::map< int, int > theIDMap
Build the ID map (i.e., what is to be considered as a proton, etc...)
~NuclearInteraction() override
Default destructor.
unsigned index(int thePid)
Return a hashed index for a given particle ID.
#define CMS_THREAD_GUARD(_var_)
Abs< T >::type abs(const T &t)
int simTrackIndex() const
Return index of the SimTrack.
std::ofstream myOutputFile
Output file to save interactions.
math::XYZTLorentzVector XYZTLorentzVector
const std::vector< int > neutronsID
PdgID of neutrons.
void save()
Save the nuclear interactions to a file, so you can reproduce the events (e.g. in case of a crash)...
double theHadronEnergy
Minimum energy for nuclear interaction.
int pdgId() const
Return pdgId of the particle.
math::XYZVector XYZVector
NuclearInteraction(const std::string &name, const edm::ParameterSet &cfg)
Constructor.
XYZVector orthogonal(const XYZVector &aVector) const
Return an orthogonal vector.
XYZVectorD XYZVector
spatial vector with cartesian internal representation
bool read(std::string inputFile)
Read the nuclear interactions from a file, so you can reproduce the events (e.g. in case of a crash)...
const std::vector< double > theHadronPMin
Smallest momentum for inelastic interactions.
const math::XYZTLorentzVector & momentum() const
Return momentum of the particle.
unsigned ien4
Find the index for which EN = 4.
double charge() const
Return charge of the particle.
const std::vector< double > theHadronMA
Masses of the hadrons.
std::vector< std::vector< TBranch * > > theBranches
Necessary to read the FullSim interactions.
const std::vector< int > PiminussesID
PdgID of pi-.
const std::vector< double > theHadronEN
Filled into 'theRatiosMap' (evolution of the interaction lengths with energy)
std::vector< std::vector< unsigned > > theNumberOfInteractions
Necessary to read the FullSim interactions.
static std::once_flag initializeOnce
const std::vector< int > theHadronID
ID of the hadrons.
#define DEFINE_EDM_PLUGIN(factory, type, name)
std::string inputFile
Directory/Name of input file in case you want to read interactions from file.
double flatShoot(double xmin=0.0, double xmax=1.0) const
Definition of a generic FastSim Particle which can be propagated through the detector (formerly Parti...
std::vector< std::vector< TTree * > > theTrees
Necessary to read the FullSim interactions.
math::XYZVector XYZVector
const std::vector< std::string > theHadronNA
Names of the hadrons.
Geom::Theta< T > theta() const
Power< A, B >::type pow(const A &a, const B &b)
math::XYZTLorentzVector XYZTLorentzVector
std::vector< std::vector< unsigned > > theCurrentEntry
Necessary to read the FullSim interactions.
unsigned myOutputBuffer
Needed to save interactions to file.