Newer
Older
/**
* (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
*
* See file AUTHORS for a list of contributors.
*
* This software is distributed under the terms of the GNU General Public
* Licence version 3 (GPL Version 3). See file LICENSE for a full version of
* the license.
*/
#include <corsika/cascade/Cascade.h>
#include <corsika/process/ProcessSequence.h>
#include <corsika/process/stack_inspector/StackInspector.h>
#include <corsika/process/tracking_line/TrackingLine.h>
#include <corsika/setup/SetupStack.h>
#include <corsika/setup/SetupTrajectory.h>
#include <corsika/environment/Environment.h>
#include <corsika/environment/HomogeneousMedium.h>
#include <corsika/environment/NuclearComposition.h>
#include <corsika/random/RNGManager.h>
#include <corsika/geometry/Sphere.h>
#include <corsika/process/sibyll/ParticleConversion.h>
#include <corsika/process/sibyll/ProcessDecay.h>
#include <corsika/units/PhysicalUnits.h>
Felix Riehn
committed
using namespace corsika;
using namespace corsika::process;
using namespace corsika::units;
using namespace corsika::particles;
using namespace corsika::random;
Felix Riehn
committed
using namespace corsika::setup;
using namespace corsika::geometry;
using namespace corsika::environment;
using namespace corsika::units::si;
static EnergyType fEnergy = 0. * 1_GeV;
// FOR NOW: global static variables for ParticleCut process
// this is just wrong...
class ProcessEMCut : public corsika::process::BaseProcess<ProcessEMCut> {
public:
ProcessEMCut() {}
template <typename Particle>
const EnergyType Ecm = sqrt(2. * p.GetEnergy() * 0.93827_GeV);
if (p.GetEnergy() < 50_GeV || Ecm < 10_GeV)
switch (pCode) {
case Code::Electron:
is_em = true;
break;
case Code::Gamma:
is_em = true;
break;
default:
break;
void defineEmParticles() const {
// create bool array identifying em particles
switch (pCode) {
case Code::NuE:
is_inv = true;
break;
case Code::NuEBar:
is_inv = true;
break;
case Code::NuMu:
is_inv = true;
break;
case Code::NuMuBar:
is_inv = true;
break;
case Code::MuPlus:
is_inv = true;
break;
case Code::MuMinus:
is_inv = true;
break;
default:
break;
}
return is_inv;
}
template <typename Particle>
double MinStepLength(Particle& p, setup::Trajectory&) const {
cout << "ProcessCut: MinStep: next cut: " << 0. << endl;
return 0.;
double next_step = std::numeric_limits<double>::infinity();
cout << "ProcessCut: MinStep: next cut: " << next_step << endl;
return next_step;
}
}
template <typename Particle, typename Stack>
EProcessReturn DoContinuous(Particle&, setup::Trajectory&, Stack&) const {
// cout << "ProcessCut: DoContinous: " << p.GetPID() << endl;
// cout << " is em: " << isEmParticle( p.GetPID() ) << endl;
// cout << " is inv: " << isInvisible( p.GetPID() ) << endl;
// const Code pid = p.GetPID();
// if( isEmParticle( pid ) ){
// cout << "removing em. particle..." << endl;
// fEmEnergy += p.GetEnergy();
// fEmCount += 1;
// p.Delete();
// return EProcessReturn::eParticleAbsorbed;
// }
// if ( isInvisible( pid ) ){
// cout << "removing inv. particle..." << endl;
// fInvEnergy += p.GetEnergy();
// fInvCount += 1;
// p.Delete();
// return EProcessReturn::eParticleAbsorbed;
// }
}
template <typename Particle, typename Stack>
cout << "ProcessCut: DoDiscrete: " << p.GetPID() << endl;
const Code pid = p.GetPID();
cout << "removing em. particle..." << endl;
fEmEnergy += p.GetEnergy();
cout << "removing inv. particle..." << endl;
fInvEnergy += p.GetEnergy();
cout << "removing low en. particle..." << endl;
fEnergy += p.GetEnergy();
void Init() {
fEmEnergy = 0. * 1_GeV;
fEmCount = 0;
fInvCount = 0;
fEnergy = 0. * 1_GeV;
// defineEmParticles();
cout << " ******************************" << endl
<< " ParticleCut: " << endl
<< " energy in em. component (GeV): " << fEmEnergy / 1_GeV << endl
<< " no. of em. particles injected: " << fEmCount << endl
<< " energy in inv. component (GeV): " << fInvEnergy / 1_GeV << endl
<< " no. of inv. particles injected: " << fInvCount << endl
<< " ******************************" << endl;
class ProcessSplit : public corsika::process::InteractionProcess<ProcessSplit> {
public:
ProcessSplit() {}
void setTrackedParticlesStable() const {
/*
Sibyll is hadronic generator
only hadrons decay
*/
corsika::process::sibyll::setHadronsUnstable();
// make tracked particles stable
std::cout << "ProcessSplit: setting tracked hadrons stable.." << std::endl;
setup::Stack ds;
ds.NewParticle().SetPID(Code::PiPlus);
ds.NewParticle().SetPID(Code::PiMinus);
ds.NewParticle().SetPID(Code::KPlus);
ds.NewParticle().SetPID(Code::KMinus);
ds.NewParticle().SetPID(Code::K0Long);
ds.NewParticle().SetPID(Code::K0Short);
for (auto& p : ds) {
int s_id = process::sibyll::ConvertToSibyllRaw(p.GetPID());
// set particle stable by setting table value negative
s_csydec_.idb[s_id - 1] = (-1) * abs(s_csydec_.idb[s_id - 1]);
p.Delete();
}
}
double GetInteractionLength(Particle& p, Track&) const {
Felix Riehn
committed
// coordinate system, get global frame of reference
CoordinateSystem& rootCS = RootCoordinateSystem::GetInstance().GetRootCS();
Felix Riehn
committed
const Code corsikaBeamId = p.GetPID();
// beam particles for sibyll : 1, 2, 3 for p, pi, k
Felix Riehn
committed
// read from cross section code table
int kBeam = process::sibyll::GetSibyllXSCode(corsikaBeamId);
bool kInteraction = process::sibyll::CanInteract(corsikaBeamId);
the target should be defined by the Environment,
and the boosts can be defined..
*/
// FOR NOW: assume target is oxygen
Felix Riehn
committed
int kTarget = 16;
EnergyType Etot = p.GetEnergy() + kTarget * corsika::particles::Proton::GetMass();
super_stupid::MomentumVector Ptot(
rootCS, {0.0_newton_second, 0.0_newton_second, 0.0_newton_second});
// FOR NOW: assume target is at rest
super_stupid::MomentumVector pTarget(
rootCS, {0.0_newton_second, 0.0_newton_second, 0.0_newton_second});
Ptot += p.GetMomentum();
Ptot += pTarget;
// calculate cm. energy
EnergyType sqs = sqrt(Etot * Etot - Ptot.squaredNorm() * si::constants::cSquared);
double Ecm = sqs / 1_GeV;
std::cout << "ProcessSplit: "
<< "MinStep: input en: " << p.GetEnergy() / 1_GeV << endl
<< " beam can interact:" << kBeam << endl
<< " beam XS code:" << kBeam << endl
<< " beam pid:" << p.GetPID() << endl
<< " target mass number:" << kTarget << std::endl;
Felix Riehn
committed
if (kInteraction) {
double prodCrossSection, dummy, dum1, dum2, dum3, dum4;
Felix Riehn
committed
double dumdif[3];
if (kTarget == 1)
sib_sigma_hp_(kBeam, Ecm, dum1, dum2, prodCrossSection, dumdif, dum3, dum4);
Felix Riehn
committed
else
sib_sigma_hnuc_(kBeam, kTarget, Ecm, prodCrossSection, dummy);
std::cout << "ProcessSplit: "
<< "MinStep: sibyll return: " << prodCrossSection << std::endl;
Felix Riehn
committed
CrossSectionType sig = prodCrossSection * 1_mbarn;
std::cout << "ProcessSplit: "
<< "MinStep: CrossSection (mb): " << sig / 1_mbarn << std::endl;
Felix Riehn
committed
const MassType nucleon_mass = 0.93827_GeV / corsika::units::si::constants::cSquared;
std::cout << "ProcessSplit: "
<< "nucleon mass " << nucleon_mass << std::endl;
Felix Riehn
committed
// calculate interaction length in medium
int_length = kTarget * (nucleon_mass / 1_g) / (sig / 1_cmeter / 1_cmeter);
Felix Riehn
committed
// pick random step lenth
std::cout << "ProcessSplit: "
<< "interaction length (g/cm2): " << int_length << std::endl;
} else
int_length = std::numeric_limits<double>::infinity();
/*
what are the units of the output? slant depth or 3space length?
// int a = 0;
// const double next_step = -int_length * log(s_rndm_(a));
// std::cout << "ProcessSplit: "
// << "next step (g/cm2): " << next_step << std::endl;
template <typename Particle, typename Track, typename Stack>
EProcessReturn DoContinuous(Particle&, Track&, Stack&) const {
return EProcessReturn::eOk;
}
template <typename Particle, typename Stack>
void DoInteraction(Particle& p, Stack& s) const {
cout << "ProcessSibyll: "
<< "DoInteraction: " << p.GetPID() << " interaction? "
<< process::sibyll::CanInteract(p.GetPID()) << endl;
if (process::sibyll::CanInteract(p.GetPID())) {
Felix Riehn
committed
cout << "defining coordinates" << endl;
// coordinate system, get global frame of reference
CoordinateSystem& rootCS = RootCoordinateSystem::GetInstance().GetRootCS();
QuantityVector<length_d> const coordinates{0_m, 0_m, 0_m};
Point pOrig(rootCS, coordinates);
/*
the target should be defined by the Environment,
ideally as full particle object so that the four momenta
and the boosts can be defined..
here we need: GetTargetMassNumber() or GetTargetPID()??
GetTargetMomentum() (zero in EAS)
Felix Riehn
committed
*/
// FOR NOW: set target to proton
Felix Riehn
committed
cout << "defining target momentum.." << endl;
// FOR NOW: target is always at rest
const EnergyType Etarget = 0. * 1_GeV + corsika::particles::Proton::GetMass();
const auto pTarget = super_stupid::MomentumVector(
rootCS, 0. * 1_GeV / si::constants::c, 0. * 1_GeV / si::constants::c,
0. * 1_GeV / si::constants::c);
cout << "target momentum (GeV/c): "
<< pTarget.GetComponents() / 1_GeV * si::constants::c << endl;
cout << "beam momentum (GeV/c): "
<< p.GetMomentum().GetComponents() / 1_GeV * si::constants::c << endl;
stack is in GeV in lab. frame
convert to GeV in cm. frame
(assuming proton at rest as target AND
assuming no pT, i.e. shower frame-z is aligned with hadron-int-frame-z)
Felix Riehn
committed
// total energy: E_beam + E_target
// in lab. frame: E_beam + m_target*c**2
EnergyType E = p.GetEnergy();
EnergyType Etot = E + Etarget;
Felix Riehn
committed
// total momentum
super_stupid::MomentumVector Ptot = p.GetMomentum(); // + pTarget;
// invariant mass, i.e. cm. energy
EnergyType Ecm = sqrt(Etot * Etot -
Ptot.squaredNorm() *
si::constants::cSquared); // sqrt( 2. * E * 0.93827_GeV );
/*
get transformation between Stack-frame and SibStack-frame
for EAS Stack-frame is lab. frame, could be different for CRMC-mode
the transformation should be derived from the input momenta
*/
const double gamma = Etot / Ecm;
const auto gambet = Ptot / (Ecm / si::constants::c);
std::cout << "ProcessSplit: "
<< " DoDiscrete: gamma:" << gamma << endl;
std::cout << "ProcessSplit: "
<< " DoDiscrete: gambet:" << gambet.GetComponents() << endl;
int kBeam = process::sibyll::ConvertToSibyllRaw(p.GetPID());
std::cout << "ProcessSplit: "
<< " DoInteraction: E(GeV):" << E / 1_GeV << " Ecm(GeV): " << Ecm / 1_GeV
<< std::endl;
if (E < 8.5_GeV || Ecm < 10_GeV) {
std::cout << "ProcessSplit: "
<< " DoInteraction: dropping particle.." << std::endl;
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
// Sibyll does not know about units..
double sqs = Ecm / 1_GeV;
// running sibyll, filling stack
sibyll_(kBeam, kTarget, sqs);
// running decays
setTrackedParticlesStable();
decsib_();
// print final state
int print_unit = 6;
sib_list_(print_unit);
// delete current particle
p.Delete();
// add particles from sibyll to stack
// link to sibyll stack
SibStack ss;
// SibStack does not know about momentum yet so we need counter to access momentum
// array in Sibyll
int i = -1;
super_stupid::MomentumVector Ptot_final(
rootCS, {0.0_newton_second, 0.0_newton_second, 0.0_newton_second});
for (auto& psib : ss) {
++i;
// skip particles that have decayed in Sibyll
if (abs(s_plist_.llist[i]) > 100) continue;
// transform energy to lab. frame, primitve
// compute beta_vec * p_vec
// arbitrary Lorentz transformation based on sibyll routines
const auto gammaBetaComponents = gambet.GetComponents();
const auto pSibyllComponents = psib.GetMomentum().GetComponents();
EnergyType en_lab = 0. * 1_GeV;
MomentumType p_lab_components[3];
en_lab = psib.GetEnergy() * gamma;
EnergyType pnorm = 0. * 1_GeV;
for (int j = 0; j < 3; ++j)
pnorm += (pSibyllComponents[j] * gammaBetaComponents[j] * si::constants::c) /
(gamma + 1.);
pnorm += psib.GetEnergy();
for (int j = 0; j < 3; ++j) {
p_lab_components[j] = pSibyllComponents[j] - (-1) * pnorm *
gammaBetaComponents[j] /
si::constants::c;
en_lab -=
(-1) * pSibyllComponents[j] * gammaBetaComponents[j] * si::constants::c;
}
// add to corsika stack
auto pnew = s.NewParticle();
pnew.SetEnergy(en_lab);
pnew.SetPID(process::sibyll::ConvertFromSibyll(psib.GetPID()));
corsika::geometry::QuantityVector<momentum_d> p_lab_c{
p_lab_components[0], p_lab_components[1], p_lab_components[2]};
pnew.SetMomentum(super_stupid::MomentumVector(rootCS, p_lab_c));
Ptot_final += pnew.GetMomentum();
}
// cout << "tot. momentum final (GeV/c): " << Ptot_final.GetComponents() / 1_GeV *
// si::constants::c << endl;
corsika::random::RNGManager& rmng = corsika::random::RNGManager::GetInstance();
rmng.RegisterRandomStream("s_rndm");
// test random number generator
std::cout << "ProcessSplit: "
<< " test sequence of random numbers." << std::endl;
for (int i = 0; i < 8; ++i) std::cout << i << " " << s_rndm_(a) << std::endl;
// initialize Sibyll
setTrackedParticlesStable();
int GetCount() { return fCount; }
double s_rndm_(int&) {
static corsika::random::RNG& rmng =
corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
;
return rmng() / (double)rmng.max();
corsika::environment::Environment env; // dummy environment
Maximilian Reininghaus
committed
auto& universe = *(env.GetUniverse());
Maximilian Reininghaus
committed
auto theMedium = corsika::environment::Environment::CreateNode<Sphere>(
Point{env.GetCoordinateSystem(), 0_m, 0_m, 0_m},
1_km * std::numeric_limits<double>::infinity());
using MyHomogeneousModel =
corsika::environment::HomogeneousMedium<corsika::environment::IMediumModel>;
theMedium->SetModelProperties<MyHomogeneousModel>(
1_g / (1_m * 1_m * 1_m),
corsika::environment::NuclearComposition(
std::vector<corsika::particles::Code>{corsika::particles::Code::Proton},
std::vector<float>{1.}));
Maximilian Reininghaus
committed
universe.AddChild(std::move(theMedium));
Felix Riehn
committed
CoordinateSystem& rootCS = RootCoordinateSystem::GetInstance().GetRootCS();
tracking_line::TrackingLine<setup::Stack> tracking(env);
stack_inspector::StackInspector<setup::Stack> p0(true);
Felix Riehn
committed
corsika::process::sibyll::ProcessDecay p2;
corsika::cascade::Cascade EAS(tracking, sequence, stack);
stack.Clear();
auto particle = stack.NewParticle();
EnergyType E0 = 100_GeV;
MomentumType P0 = sqrt(E0 * E0 - 0.93827_GeV * 0.93827_GeV) / si::constants::c;
auto plab = super_stupid::MomentumVector(rootCS, 0. * 1_GeV / si::constants::c,
0. * 1_GeV / si::constants::c, P0);
Felix Riehn
committed
particle.SetMomentum(plab);
particle.SetTime(0_ns);
Point p(rootCS, 0_m, 0_m, 0_m);
particle.SetPosition(p);
cout << "Result: E0=" << E0 / 1_GeV
<< "GeV, particles below energy threshold =" << p1.GetCount() << endl;
cout << "total energy below threshold (GeV): " << p1.GetEnergy() / 1_GeV << std::endl;
p3.ShowResults();
cout << "total energy (GeV): "
<< (p3.GetCutEnergy() + p3.GetInvEnergy() + p3.GetEmEnergy()) / 1_GeV << endl;