Skip to content

Commit

Permalink
Merge pull request #317 from tudo-astroparticlephysics/annihilation_d…
Browse files Browse the repository at this point in the history
…irect

Use closed form for AnnihilationHeitler parametrization
  • Loading branch information
Jean1995 authored Sep 23, 2022
2 parents b6c4a21 + 0e2b374 commit 0db0e20
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 190 deletions.
1 change: 0 additions & 1 deletion src/PROPOSAL/PROPOSAL/PROPOSAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
#include "PROPOSAL/secondaries/parametrization/Parametrization.h"
#include "PROPOSAL/secondaries/parametrization/annihilation/Annihilation.h"
#include "PROPOSAL/secondaries/parametrization/annihilation/HeitlerAnnihilation.h"
#include "PROPOSAL/secondaries/parametrization/annihilation/SingleDifferentialAnnihilation.h"
#include "PROPOSAL/secondaries/parametrization/bremsstrahlung/Bremsstrahlung.h"
#include "PROPOSAL/secondaries/parametrization/bremsstrahlung/BremsNoDeflection.h"
#include "PROPOSAL/secondaries/parametrization/bremsstrahlung/BremsEGS4Approximation.h"
Expand Down
38 changes: 25 additions & 13 deletions src/PROPOSAL/PROPOSAL/crosssection/parametrization/Annihilation.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,43 @@
#pragma once

#include "PROPOSAL/crosssection/parametrization/Parametrization.h"
#include "PROPOSAL/crosssection/parametrization/ParametrizationDirect.h"

namespace PROPOSAL {
namespace crosssection {
class Annihilation : public Parametrization<Component> {
class Annihilation : public ParametrizationDirect {
public:
Annihilation() = default;
~Annihilation() override = default;

double GetLowerEnergyLim(ParticleDef const&) const noexcept final;
// no continuous losses
double CalculatedEdx(double, const ParticleDef&, const Medium&, cut_ptr) override { return 0.; };
double CalculatedE2dx(double, const ParticleDef&, const Medium&, cut_ptr) override { return 0.; };

KinematicLimits GetKinematicLimits(
ParticleDef const&, Component const&, double) const final;
};
double CalculateCumulativeCrosssection(double, size_t, double, const ParticleDef&, const Medium&, cut_ptr) override {
throw std::logic_error("No cumulative crosssection defined for Annihilation.");
};

double CalculateStochasticLoss(size_t, double, double, const ParticleDef&, const Medium&, cut_ptr) override {
return 1.; // all energy is always lost, i.e. v=1
};

double GetLowerEnergyLim(const ParticleDef&, const Medium&, cut_ptr) const override;

template <> struct ParametrizationName<Annihilation> {
static constexpr auto value = "annihilation";
size_t GetHash(const ParticleDef&, const Medium& m, cut_ptr) const noexcept override;

InteractionType GetInteractionType() const noexcept override;
};

struct AnnihilationHeitler : public Annihilation {
AnnihilationHeitler() = default;
class AnnihilationHeitler : public Annihilation {
public:
AnnihilationHeitler();
std::unique_ptr<ParametrizationDirect> clone() const final;

std::unique_ptr<Parametrization<Component>> clone() const final;
double CalculatedNdx(double, const ParticleDef&, const Medium&, cut_ptr) override;
double CalculatedNdx(double, size_t, const ParticleDef&, const Medium&, cut_ptr) override;
std::vector<std::pair<size_t, double>> CalculatedNdx_PerTarget(
double, const ParticleDef&, const Medium&, cut_ptr) override;

double DifferentialCrossSection(
ParticleDef const&, Component const&, double, double) const final;
};

template <> struct ParametrizationName<AnnihilationHeitler> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
#pragma once

#include "PROPOSAL/secondaries/parametrization/annihilation/SingleDifferentialAnnihilation.h"
#include "PROPOSAL/crosssection/CrossSection.h"
#include "PROPOSAL/crosssection/parametrization/Annihilation.h"
#include "PROPOSAL/medium/Medium.h"
#include "PROPOSAL/particle/ParticleDef.h"
#include "PROPOSAL/secondaries/parametrization/annihilation/Annihilation.h"

namespace PROPOSAL {
namespace secondaries {
struct HeitlerAnnihilation
: public secondaries::SingleDifferentialAnnihilation,
public DefaultSecondaries<HeitlerAnnihilation> {
namespace secondaries {
class HeitlerAnnihilation : public secondaries::Annihilation,
public DefaultSecondaries<HeitlerAnnihilation> {

HeitlerAnnihilation(const ParticleDef& p_def, const Medium& medium)
: SingleDifferentialAnnihilation(crosssection::AnnihilationHeitler{}, p_def, medium, true)
{
}
};
} // namespace secondaries
double mass;
static double f_term(double a1, double a2, double v);
double f(double v, double a1, double a2, double v_min, double v_max, double rnd);

public:
static constexpr int n_rnd = 2;

HeitlerAnnihilation(const ParticleDef& p, const Medium& medium) : mass(p.mass) {}

double CalculateRho(double, double, const Component&) final;
std::tuple<Cartesian3D, Cartesian3D> CalculateDirections(
const Vector3D&, double, double, double) final;
std::tuple<double, double> CalculateEnergy(double, double) final;

size_t RequiredRandomNumbers() const noexcept override { return n_rnd; }
std::vector<ParticleState> CalculateSecondaries(
StochasticLoss, const Component&, std::vector<double>&) override;
};
} // namespace secondaries
} // namespace PROPOSAL

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@

#include <cassert>
#include <cmath>
#include <memory>
#include <type_traits>
Expand All @@ -8,58 +7,64 @@
#include "PROPOSAL/crosssection/parametrization/Annihilation.h"
#include "PROPOSAL/medium/Components.h"
#include "PROPOSAL/particle/Particle.h"
#include "PROPOSAL/crosssection/CrossSection.h"
#include "PROPOSAL/medium/Medium.h"

using std::make_tuple;
using namespace PROPOSAL;

double crosssection::Annihilation::GetLowerEnergyLim(
ParticleDef const& p_def) const noexcept
{
return p_def.mass * 2.f;
InteractionType crosssection::Annihilation::GetInteractionType() const noexcept {
return InteractionType::Annihilation;
}

crosssection::KinematicLimits crosssection::Annihilation::GetKinematicLimits(
ParticleDef const& p_def, Component const&, double energy) const
{
// Limits according to simple 2->2 body interactions
auto kin_lim = crosssection::KinematicLimits();

auto gamma = energy / p_def.mass;

if (gamma <= 1) {
kin_lim.v_min = 0;
kin_lim.v_max = 0;
} else {
auto aux = std::sqrt((gamma - 1.) / (gamma + 1.));
kin_lim.v_min = 0.5 * (1. - aux);
kin_lim.v_max = 0.5 * (1. + aux);
}
return kin_lim;
size_t crosssection::Annihilation::GetHash(const ParticleDef& p_def, const Medium &m, cut_ptr) const noexcept {
auto combined_hash = m.GetHash();
hash_combine(combined_hash, p_def.mass, hash);
return combined_hash;
}

std::unique_ptr<crosssection::Parametrization<Component>>
crosssection::AnnihilationHeitler::clone() const
{
using param_t = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>;
return std::make_unique<param_t>(*this);
}
double crosssection::Annihilation::GetLowerEnergyLim(const ParticleDef& p_def, const Medium&, cut_ptr) const {
return p_def.mass;
};

double crosssection::AnnihilationHeitler::DifferentialCrossSection(
ParticleDef const& p_def, Component const& comp, double energy,
double v) const
{
// W. Heitler. The Quantum Theory of Radiation, Clarendon Press, Oxford
// (1954) Adapted from Geant4 PhysicsReferenceManual
crosssection::AnnihilationHeitler::AnnihilationHeitler() {
hash_combine(hash, std::string(crosssection::ParametrizationName<AnnihilationHeitler>::value));
};

// v = energy of photon1 / total available energy
// with the total available energy being the sum of the total positron
// energy and the electron mass
double crosssection::AnnihilationHeitler::CalculatedNdx(double energy, size_t comp_hash, const ParticleDef& p_def,
const Medium& medium, cut_ptr cut) {
// integrated form of Heitler Annihilation, cf. Geant4 PhysicsReferenceManual
if (energy <= Annihilation::GetLowerEnergyLim(p_def, medium, cut))
return 0.;

auto comp = Component::GetComponentForHash(comp_hash);
auto gamma = energy / p_def.mass;
auto aux = 1. + (2. * gamma) / std::pow(gamma + 1., 2.) - v
- 1. / std::pow(gamma + 1., 2.) * 1. / v;
aux *= NA * comp.GetNucCharge() / comp.GetAtomicNum() * PI * RE * RE
/ (gamma - 1.) * 1. / v; // TODO: prefactors
auto weight = detail::weight_component(medium, comp);
auto aux = (gamma * gamma + 4 * gamma + 1) / (gamma * gamma - 1)
* std::log(gamma + std::sqrt(gamma * gamma - 1)) - (gamma + 3) / std::sqrt(gamma * gamma - 1);
aux *= NA * comp.GetNucCharge() / comp.GetAtomicNum() * PI * RE * RE / (gamma + 1.) / weight;

return aux;
}

double crosssection::AnnihilationHeitler::CalculatedNdx(double energy, const ParticleDef& p, const Medium& m, cut_ptr cut) {
double sum = 0.;
for (auto& rate : CalculatedNdx_PerTarget(energy, p, m, cut))
sum += rate.second;
return sum;
}

std::vector<std::pair<size_t, double>> crosssection::AnnihilationHeitler::CalculatedNdx_PerTarget(
double energy, const ParticleDef& p, const Medium& m, cut_ptr cut) {
std::vector<std::pair<size_t, double>> rates = {};
for (auto& comp : m.GetComponents()) {
double rate = CalculatedNdx(energy, comp.GetHash(), p, m, cut);
rates.push_back({comp.GetHash(), rate});
}
return rates;
}

std::unique_ptr<crosssection::ParametrizationDirect> crosssection::AnnihilationHeitler::clone() const {
using param_t = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>;
return std::make_unique<param_t>(*this);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "PROPOSAL/secondaries/parametrization/annihilation/HeitlerAnnihilation.h"
#include "PROPOSAL/math/MathMethods.h"

using namespace PROPOSAL;

double secondaries::HeitlerAnnihilation::f_term(double a1, double a2, double rho) {
return a1 * std::log(rho) + a2 / rho - rho;
}

double secondaries::HeitlerAnnihilation::f(double rho, double a1, double a2, double rho_min, double rho_max, double rnd) {
return f_term(a1, a2, rho) - f_term(a1, a2, rho_min) - rnd * (f_term(a1, a2, rho_max) - f_term(a1, a2, rho_min));
}

double secondaries::HeitlerAnnihilation::CalculateRho(double energy, double rnd, const Component&) {
// solve the following equation for \rho:
// \int_{\rho_{min}}^{\rho} \frac{d\sigma}{d\rho} = rnd * \int_{\rho_{min}}^{\rho_{max}} \frac{d\sigma}{d\rho}

double gamma = energy / mass;
double rho_min, rho_max;
if (gamma <= 1) {
rho_min = 0;
rho_max = 0;
} else {
auto aux = std::sqrt((gamma - 1.) / (gamma + 1.));
rho_min = 0.5 * (1. - aux);
rho_max = 0.5 * (1. + aux);
}

double a2 = 1 / std::pow(gamma + 1, 2.);
double a1 = 1 + 2 * gamma * a2;

auto function_to_solve = [&](double rho) { return f(rho, a1, a2, rho_min, rho_max, rnd); };
double precision = rho_min * energy * HALF_PRECISION;
return Bisection(function_to_solve, rho_min, rho_max, precision, 100).first;
}

std::tuple<Cartesian3D, Cartesian3D>
secondaries::HeitlerAnnihilation::CalculateDirections(
const Vector3D& primary_dir, double energy, double rho, double rnd)
{
// use two-body interaction kinematics to infer angles of secondary particles
auto com_energy = energy + ME; // center of mass energy
auto kin_energy = energy - ME; // kinetic energy
auto cosphi0 = (com_energy * (1. - rho) - ME)
/ ((1. - rho) * sqrt(com_energy * kin_energy));
auto cosphi1
= (com_energy * rho - ME) / (rho * sqrt(com_energy * kin_energy));
auto rnd_theta = rnd * 2. * PI;
auto dir_1 = Cartesian3D(primary_dir);
auto dir_2 = Cartesian3D(primary_dir);
dir_1.deflect(cosphi0, rnd_theta);
dir_2.deflect(cosphi1, fmod(rnd_theta + PI, 2. * PI));
return std::make_tuple(dir_1, dir_2);
}

std::tuple<double, double>
secondaries::HeitlerAnnihilation::CalculateEnergy(
double energy, double rho)
{
assert(rho >= 0);
assert(rho <= 1);
auto energy_1 = (energy + ME) * (1 - rho);
auto energy_2 = (energy + ME) * rho;
return std::make_tuple(energy_1, energy_2);
}

std::vector<ParticleState>
secondaries::HeitlerAnnihilation::CalculateSecondaries(
StochasticLoss loss, const Component& comp, std::vector<double> &rnd)
{
auto rho = CalculateRho(loss.parent_particle_energy, rnd[0], comp);
auto secondary_energies = CalculateEnergy(loss.parent_particle_energy, rho);
auto secondary_dir = CalculateDirections(
loss.direction, loss.parent_particle_energy, rho, rnd[1]);
auto sec = std::vector<ParticleState>();
sec.emplace_back(ParticleType::Gamma, loss.position, std::get<0>(secondary_dir),
std::get<0>(secondary_energies), loss.time, 0.);
sec.emplace_back(ParticleType::Gamma, loss.position, std::get<1>(secondary_dir),
std::get<1>(secondary_energies), loss.time, 0.);
return sec;
}
Loading

0 comments on commit 0db0e20

Please sign in to comment.