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.
*/
#ifndef _include_corsika_processes_TrackingLine_h_
#define _include_corsika_processes_TrackingLine_h_
#include <corsika/geometry/Sphere.h>
#include <corsika/units/PhysicalUnits.h>
#include <corsika/environment/Environment.h>
#include <corsika/setup/SetupStack.h>
#include <corsika/setup/SetupTrajectory.h>
Maximilian Reininghaus
committed
#include <algorithm>
Maximilian Reininghaus
committed
#include <optional>
Maximilian Reininghaus
committed
#include <utility>
using namespace corsika;
namespace corsika::process {
namespace tracking_line {
template <typename Stack>
Maximilian Reininghaus
committed
using Particle = typename Stack::ParticleType;
corsika::environment::Environment const& fEnvironment;
std::optional<std::pair<corsika::units::si::TimeType, corsika::units::si::TimeType>>
TimeOfIntersection(corsika::geometry::Line const& line,
using namespace corsika::units::si;
auto const& cs = fEnvironment.GetCoordinateSystem();
geometry::Point const origin(cs, 0_m, 0_m, 0_m);
auto const r0 = (line.GetR0() - origin);
auto const v0 = line.GetV0();
auto const c0 = (sphere.GetCenter() - origin);
auto const alpha = r0.dot(v0) - 2 * v0.dot(c0);
auto const beta = c0.squaredNorm() + r0.squaredNorm() + 2 * c0.dot(r0) -
sphere.GetRadius() * sphere.GetRadius();
auto const discriminant = alpha * alpha - 4 * beta * v0.squaredNorm();
//~ std::cout << "discriminant: " << discriminant << std::endl;
//~ std::cout << "alpha: " << alpha << std::endl;
//~ std::cout << "beta: " << beta << std::endl;
if (discriminant.magnitude() > 0) {
Maximilian Reininghaus
committed
(-alpha - sqrt(discriminant)) / (2 * v0.squaredNorm());
return std::make_pair((-alpha - sqrt(discriminant)) / (2 * v0.squaredNorm()),
(-alpha + sqrt(discriminant)) / (2 * v0.squaredNorm()));
} else {
return {};
}
}
TrackingLine(corsika::environment::Environment const& pEnv)
: fEnvironment(pEnv) {}
Maximilian Reininghaus
committed
auto GetTrack(Particle const& p) {
using namespace corsika::units::si;
geometry::Vector<SpeedType::dimension_type> const velocity =
p.GetMomentum() / p.GetEnergy() * corsika::units::si::constants::cSquared;
Maximilian Reininghaus
committed
auto const currentPosition = p.GetPosition();
// to do: include effect of magnetic field
Maximilian Reininghaus
committed
geometry::Line line(currentPosition, velocity);
auto const* currentVolumeNode =
fEnvironment.GetUniverse()->GetContainingNode(currentPosition);
auto const& children = currentVolumeNode->GetChildNodes();
auto const& excluded = currentVolumeNode->GetExcludedNodes();
std::vector<TimeType> intersectionTimes;
auto addIfIntersects = [&](auto& vtn) {
auto const& volume = vtn.GetVolume();
auto const& sphere = dynamic_cast<geometry::Sphere const&>(
volume); // for the moment we are a bit bold here and assume
// everything is a sphere, crashes with exception if not
if (auto opt = TimeOfIntersection(line, sphere); opt.has_value()) {
Maximilian Reininghaus
committed
auto const [t1, t2] = *opt;
if (t1.magnitude() >= 0)
Maximilian Reininghaus
committed
else if (t2.magnitude() >= 0)
Maximilian Reininghaus
committed
}
Maximilian Reininghaus
committed
};
for (auto const& child : children) { addIfIntersects(*child); }
for (auto const* child : excluded) { addIfIntersects(*child); }
addIfIntersects(*currentVolumeNode);
auto const minIter =
std::min_element(intersectionTimes.cbegin(), intersectionTimes.cend());
Maximilian Reininghaus
committed
if (minIter == intersectionTimes.cend()) {
min = 1_s; // todo: do sth. more reasonable as soon as tracking is able
// to handle the numerics properly
//~ throw std::runtime_error("no intersection with anything!");
} else {
min = *minIter;
Maximilian Reininghaus
committed
}
return geometry::Trajectory<corsika::geometry::Line>(line, min);
} // namespace corsika::process
#endif