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");
448 for (
unsigned iname = 0; iname <
theHadronNA.size(); ++iname) {
449 for (
unsigned iene = 0; iene <
theHadronEN.size(); ++iene) {
459 throw cms::Exception(
"FastSimulation/MaterialEffects") <<
"Tree with name " << treeName <<
" not found ";
463 <<
"Branch with name nuEvent not found in " <<
theFileNames[iname][iene];
471 unsigned NInteractions =
theNUEvents[iname][iene]->nInteractions();
482 theHadronCM[iname][iene] = (Reference + Proton).M();
501 for (
auto& vEvents : theNUEvents) {
502 for (
auto evtPtr : vEvents) {
510 myOutputFile.close();
515 std::vector<std::unique_ptr<fastsim::Particle> >& secondaries,
525 double radLengths = layer.getThickness(particle.
position(), particle.
momentum());
527 radLengths *= layer.getNuclearInteractionThicknessFactor();
531 if (radLengths < 1E-10) {
536 if (!currentValuesWereSet) {
537 currentValuesWereSet =
true;
538 for (
unsigned iname = 0; iname < theHadronNA.size(); ++iname) {
539 for (
unsigned iene = 0; iene < theHadronEN.size(); ++iene) {
540 theCurrentEntry[iname][iene] = (unsigned)(theNumberOfEntries[iname][iene] * random.
flatShoot());
542 theTrees[iname][iene]->GetEntry(theCurrentEntry[iname][iene]);
543 unsigned NInteractions = theNUEvents[iname][iene]->nInteractions();
544 theNumberOfInteractions[iname][iene] = NInteractions;
546 theCurrentInteraction[iname][iene] = (unsigned)(theNumberOfInteractions[iname][iene] * random.
flatShoot());
557 if (pHadron < theHadronEnergy) {
562 std::map<int, int>::const_iterator thePit = theIDMap.find(
pdgId);
564 int thePid = (thePit != theIDMap.end() ? thePit->second :
pdgId);
567 unsigned fPid =
abs(thePid);
568 if (fPid != 211 && fPid != 130 && fPid != 321 && fPid != 2112 && fPid != 2212) {
573 unsigned thePidIndex =
index(thePid);
575 double theInelasticLength = radLengths * theLengthRatio[thePidIndex];
580 double theElasticLength = (0.8753 * ee + 0.15) * theInelasticLength;
583 double theTotalInteractionLength = theInelasticLength + theElasticLength;
589 if (aNuclInteraction > theTotalInteractionLength) {
595 if (elastic < theElasticLength / theTotalInteractionLength) {
606 ROOT::Math::AxisAngle rotation1(orthogonal(particle.
momentum().Vect()),
theta);
607 ROOT::Math::AxisAngle rotation2(particle.
momentum().Vect(), phi);
613 secondaries.emplace_back(
619 if (particle.
charge() != 0) {
620 secondaries.back()->setMotherDeltaR(particle.
momentum());
621 secondaries.back()->setMotherPdgId(
pdgId);
622 secondaries.back()->setMotherSimTrackIndex(particle.
simTrackIndex());
626 particle.
momentum().SetXYZT(0., 0., 0., 0.);
629 particle.
momentum().SetXYZT(rotated.X(), rotated.Y(), rotated.Z(), particle.
momentum().E());
634 const std::vector<double>& aHadronCM = theHadronCM[thePidIndex];
635 const std::vector<double>& aRatios = theRatiosMap[thePidIndex];
642 double pMin = theHadronPMin[thePidIndex];
647 double ecm = (Proton + Hadron).M();
653 double ecm1 = (Proton + Hadron0).M();
655 double ecm2 = aHadronCM[0];
657 double ratio2 = aRatios[0];
658 if (ecm > aHadronCM[0] && ecm < aHadronCM[aHadronCM.size() - 1]) {
659 for (
unsigned ene = 1; ene < aHadronCM.size() && ecm > aHadronCM[ene - 1]; ++ene) {
660 if (ecm < aHadronCM[ene]) {
663 ecm1 = aHadronCM[ene1];
664 ecm2 = aHadronCM[ene2];
665 ratio1 = aRatios[ene1];
666 ratio2 = aRatios[ene2];
669 }
else if (ecm > aHadronCM[aHadronCM.size() - 1]) {
670 ene1 = aHadronCM.size() - 1;
671 ene2 = aHadronCM.size() - 2;
672 ecm1 = aHadronCM[ene1];
673 ecm2 = aHadronCM[ene2];
674 ratio1 = aRatios[ene2];
675 ratio2 = aRatios[ene2];
679 double slope = (std::log10(ecm) - std::log10(ecm1)) / (std::log10(ecm2) - std::log10(ecm1));
680 double inelastic = ratio1 + (ratio2 - ratio1) *
slope;
681 double inelastic4 = pHadron < 4. ? aRatios[ien4] : 1.;
684 if (elastic > 1. - (inelastic * theInelasticLength) / theTotalInteractionLength) {
686 std::vector<unsigned>& aCurrentInteraction = theCurrentInteraction[thePidIndex];
687 std::vector<unsigned>& aNumberOfInteractions = theNumberOfInteractions[thePidIndex];
688 std::vector<NUEvent*>& aNUEvents = theNUEvents[thePidIndex];
694 if (random.
flatShoot() <
slope || aNumberOfInteractions[ene1] == 0) {
702 theBoost /= theBoost.e();
706 if (aCurrentInteraction[ene] == aNumberOfInteractions[ene]) {
707 std::vector<unsigned>& aCurrentEntry = theCurrentEntry[thePidIndex];
708 std::vector<unsigned>& aNumberOfEntries = theNumberOfEntries[thePidIndex];
709 std::vector<TTree*>& aTrees = theTrees[thePidIndex];
710 ++aCurrentEntry[ene];
712 aCurrentInteraction[ene] = 0;
713 if (aCurrentEntry[ene] == aNumberOfEntries[ene]) {
714 aCurrentEntry[ene] = 0;
717 unsigned myEntry = aCurrentEntry[ene];
718 aTrees[ene]->GetEntry(myEntry);
719 aNumberOfInteractions[ene] = aNUEvents[ene]->nInteractions();
725 unsigned firstTrack = anInteraction.
first;
726 unsigned lastTrack = anInteraction.
last;
729 XYZVector theAxis = theBoost.Vect().Unit();
731 ROOT::Math::AxisAngle axisRotation(theAxis, theAngle);
732 ROOT::Math::Boost axisBoost(theBoost.x(), theBoost.y(), theBoost.z());
737 double orthAngle = acos(theBoost.Vect().Unit().Z());
738 ROOT::Math::AxisAngle orthRotation(orthAxis, orthAngle);
741 for (
unsigned iTrack = firstTrack; iTrack <= lastTrack; ++iTrack) {
747 aParticle.
pz * aParticle.
pz + aParticle.
mass * aParticle.
mass / (ecm * ecm));
752 XYZVector rotated = orthRotation(daugtherMomentum.Vect());
754 rotated = axisRotation(rotated);
757 daugtherMomentum.SetXYZT(rotated.X(), rotated.Y(), rotated.Z(), daugtherMomentum.E());
760 daugtherMomentum = axisBoost(daugtherMomentum);
769 if (particle.
charge() != 0) {
770 secondaries.back()->setMotherDeltaR(particle.
momentum());
771 secondaries.back()->setMotherPdgId(
pdgId);
772 secondaries.back()->setMotherSimTrackIndex(particle.
simTrackIndex());
777 particle.
momentum().SetXYZT(0., 0., 0., 0.);
785 ++aCurrentInteraction[ene];
788 }
else if (pHadron < 4. && elastic > 1. - (inelastic4 * theInelasticLength) / theTotalInteractionLength) {
790 particle.
momentum().SetXYZT(0., 0., 0., 0.);
800 if (myOutputBuffer / 1000 * 1000 == myOutputBuffer) {
801 myOutputFile.close();
802 myOutputFile.open(
"NuclearInteractionOutputFile.txt");
805 unsigned size1 = theCurrentEntry.size() * theCurrentEntry.begin()->size();
806 std::vector<unsigned> theCurrentEntries;
807 theCurrentEntries.resize(size1);
808 size1 *=
sizeof(unsigned);
810 unsigned size2 = theCurrentInteraction.size() * theCurrentInteraction.begin()->size();
811 std::vector<unsigned> theCurrentInteractions;
812 theCurrentInteractions.resize(size2);
813 size2 *=
sizeof(unsigned);
816 std::vector<std::vector<unsigned> >::const_iterator aCurrentEntry = theCurrentEntry.begin();
817 std::vector<std::vector<unsigned> >::const_iterator lastCurrentEntry = theCurrentEntry.end();
818 unsigned allEntries = 0;
819 for (; aCurrentEntry != lastCurrentEntry; ++aCurrentEntry) {
820 unsigned size = aCurrentEntry->size();
821 for (
unsigned iene = 0; iene < size; ++iene)
822 theCurrentEntries[allEntries++] = (*aCurrentEntry)[iene];
826 std::vector<std::vector<unsigned> >::const_iterator aCurrentInteraction = theCurrentInteraction.begin();
827 std::vector<std::vector<unsigned> >::const_iterator lastCurrentInteraction = theCurrentInteraction.end();
828 unsigned allInteractions = 0;
829 for (; aCurrentInteraction != lastCurrentInteraction; ++aCurrentInteraction) {
830 unsigned size = aCurrentInteraction->size();
831 for (
unsigned iene = 0; iene < size; ++iene)
832 theCurrentInteractions[allInteractions++] = (*aCurrentInteraction)[iene];
835 myOutputFile.write((
const char*)(&theCurrentEntries.front()), size1);
836 myOutputFile.write((
const char*)(&theCurrentInteractions.front()), size2);
837 myOutputFile.flush();
841 std::ifstream myInputFile;
844 unsigned size1 = theCurrentEntry.size() * theCurrentEntry.begin()->size();
845 std::vector<unsigned> theCurrentEntries;
846 theCurrentEntries.resize(size1);
847 size1 *=
sizeof(unsigned);
849 unsigned size2 = theCurrentInteraction.size() * theCurrentInteraction.begin()->size();
850 std::vector<unsigned> theCurrentInteractions;
851 theCurrentInteractions.resize(size2);
852 size2 *=
sizeof(unsigned);
858 if (myInputFile.is_open()) {
866 myInputFile.seekg(
size - size1 - size2);
867 myInputFile.read((
char*)(&theCurrentEntries.front()), size1);
868 myInputFile.read((
char*)(&theCurrentInteractions.front()), size2);
872 std::vector<std::vector<unsigned> >::iterator aCurrentEntry = theCurrentEntry.begin();
873 std::vector<std::vector<unsigned> >::iterator lastCurrentEntry = theCurrentEntry.end();
874 unsigned allEntries = 0;
875 for (; aCurrentEntry != lastCurrentEntry; ++aCurrentEntry) {
876 unsigned size = aCurrentEntry->size();
877 for (
unsigned iene = 0; iene <
size; ++iene)
878 (*aCurrentEntry)[iene] = theCurrentEntries[allEntries++];
882 std::vector<std::vector<unsigned> >::iterator aCurrentInteraction = theCurrentInteraction.begin();
883 std::vector<std::vector<unsigned> >::iterator lastCurrentInteraction = theCurrentInteraction.end();
884 unsigned allInteractions = 0;
885 for (; aCurrentInteraction != lastCurrentInteraction; ++aCurrentInteraction) {
886 unsigned size = aCurrentInteraction->size();
887 for (
unsigned iene = 0; iene <
size; ++iene)
888 (*aCurrentInteraction)[iene] = theCurrentInteractions[allInteractions++];
899 unsigned myIndex = 0;
900 while (thePid != theHadronID[myIndex])
906 double x = fabs(aVector.X());
907 double y = fabs(aVector.Y());
908 double z = fabs(aVector.Z());
911 return x <
z ?
XYZVector(0., aVector.Z(), -aVector.Y()) :
XYZVector(aVector.Y(), -aVector.X(), 0.);
913 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.
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.
static std::string to_string(const XMLCh *ch)
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.