-
Nikos Karastathis authoredNikos Karastathis authored
testRadio.cpp 25.18 KiB
/*
* (c) Copyright 2020 CORSIKA Project, corsika-project@lists.kit.edu
*
* 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 <catch2/catch.hpp>
#include <corsika/modules/radio/ZHS.hpp>
#include <corsika/modules/radio/CoREAS.hpp>
#include <corsika/modules/radio/antennas/TimeDomainAntenna.hpp>
#include <corsika/modules/radio/detectors/RadioDetector.hpp>
#include <corsika/modules/radio/propagators/StraightPropagator.hpp>
#include <corsika/modules/radio/propagators/SimplePropagator.hpp>
#include <corsika/modules/radio/propagators/SignalPath.hpp>
#include <corsika/modules/radio/propagators/RadioPropagator.hpp>
#include <vector>
#include <istream>
#include <fstream>
#include <iostream>
#include <corsika/media/Environment.hpp>
#include <corsika/media/FlatExponential.hpp>
#include <corsika/media/HomogeneousMedium.hpp>
#include <corsika/media/IMagneticFieldModel.hpp>
#include <corsika/media/LayeredSphericalAtmosphereBuilder.hpp>
#include <corsika/media/NuclearComposition.hpp>
#include <corsika/media/MediumPropertyModel.hpp>
#include <corsika/media/UniformMagneticField.hpp>
#include <corsika/media/SlidingPlanarExponential.hpp>
#include <corsika/media/IMediumModel.hpp>
#include <corsika/media/IRefractiveIndexModel.hpp>
#include <corsika/media/UniformRefractiveIndex.hpp>
#include <corsika/media/ExponentialRefractiveIndex.hpp>
#include <corsika/media/VolumeTreeNode.hpp>
#include <corsika/media/CORSIKA7Atmospheres.hpp>
#include <corsika/framework/geometry/CoordinateSystem.hpp>
#include <corsika/framework/geometry/Line.hpp>
#include <corsika/framework/geometry/Point.hpp>
#include <corsika/framework/geometry/RootCoordinateSystem.hpp>
#include <corsika/framework/geometry/Vector.hpp>
#include <corsika/setup/SetupStack.hpp>
#include <corsika/setup/SetupEnvironment.hpp>
#include <corsika/setup/SetupTrajectory.hpp>
#include <corsika/framework/core/PhysicalUnits.hpp>
#include <corsika/framework/core/PhysicalConstants.hpp>
#include <corsika/output/OutputManager.hpp>
using namespace corsika;
double constexpr absMargin = 1.0e-7;
template <typename TInterface>
using MyExtraEnv =
UniformRefractiveIndex<MediumPropertyModel<UniformMagneticField<TInterface>>>;
TEST_CASE("Radio", "[processes]") {
logging::set_level(logging::level::debug);
SECTION("CoREAS process") {
// This serves as a compiler test for any changes in the CoREAS algorithm
// Environment
using EnvironmentInterface =
IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>;
// using EnvType = setup::Environment;
using EnvType = Environment<EnvironmentInterface>;
EnvType envCoREAS;
CoordinateSystemPtr const& rootCSCoREAS = envCoREAS.getCoordinateSystem();
Point const center{rootCSCoREAS, 0_m, 0_m, 0_m};
// 1.000327,
create_5layer_atmosphere<EnvironmentInterface, MyExtraEnv>(
envCoREAS, AtmosphereId::LinsleyUSStd, center, 1.000327, Medium::AirDry1Atm,
MagneticFieldVector{rootCSCoREAS, 0_T, 50_uT, 0_T});
// now create antennas and detectors
// the antennas location
const auto point1{Point(envCoREAS.getCoordinateSystem(), 100_m, 2_m, 3_m)};
const auto point2{Point(envCoREAS.getCoordinateSystem(), 4_m, 80_m, 6_m)};
const auto point3{Point(envCoREAS.getCoordinateSystem(), 7_m, 8_m, 9_m)};
const auto point4{Point(envCoREAS.getCoordinateSystem(), 5_m, 5_m, 10_m)};
// create times for the antenna
const TimeType t1{0_s};
const TimeType t2{10_s};
const InverseTimeType t3{1e+3_Hz};
const TimeType t4{11_s};
// check that I can create an antenna at (1, 2, 3)
TimeDomainAntenna ant1("antenna_name", point1, t1, t2, t3, t1);
TimeDomainAntenna ant2("antenna_name2", point2, t1, t2, t3, t1);
// construct a radio detector instance to store our antennas
AntennaCollection<TimeDomainAntenna> detector;
// add the antennas to the detector
detector.addAntenna(ant1);
detector.addAntenna(ant2);
// create a particle
const Code particle{Code::Electron};
// const Code particle{Code::Proton};
const auto pmass{get_mass(particle)};
VelocityVector v0(rootCSCoREAS, {5e+2_m / second, 5e+2_m / second, 5e+2_m / second});
Vector B0(rootCSCoREAS, 5_T, 5_T, 5_T);
Line const line(point3, v0);
auto const k{1_m * ((1_m) / ((1_s * 1_s) * 1_V))};
auto const t = 1e-12_s;
LeapFrogTrajectory base(point4, v0, B0, k, t);
// std::cout << "Leap Frog Trajectory is: " << base << std::endl;
// create a new stack for each trial
setup::Stack stack;
// construct an energy
const HEPEnergyType E0{1_TeV};
// compute the necessary momentumn
const HEPMomentumType P0{sqrt(E0 * E0 - pmass * pmass)};
// and create the momentum vector
const auto plab{MomentumVector(rootCSCoREAS, {0_GeV, 0_GeV, P0})};
// and create the location of the particle in this coordinate system
const Point pos(rootCSCoREAS, 50_m, 10_m, 80_m);
// add the particle to the stack
auto const particle1{stack.addParticle(std::make_tuple(
particle, calculate_kinetic_energy(plab.getNorm(), get_mass(particle)),
plab.normalized(), pos, 0_ns))};
auto const charge_{get_charge(particle1.getPID())};
// create a radio process instance using CoREAS
RadioProcess<decltype(detector),
CoREAS<decltype(detector), decltype(StraightPropagator(envCoREAS))>,
decltype(StraightPropagator(envCoREAS))>
coreas(detector, envCoREAS);
// check doContinuous and simulate methods
coreas.doContinuous(particle1, base, true);
} // END: SECTION("CoREAS process")
SECTION("ZHS process") {
// This section serves as a compiler test for any changes in the ZHS algorithm
// Environment
using IModelInterface =
IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>;
using AtmModel = UniformRefractiveIndex<
MediumPropertyModel<UniformMagneticField<HomogeneousMedium<IModelInterface>>>>;
using EnvType = Environment<AtmModel>;
EnvType envZHS;
CoordinateSystemPtr const& rootCSZHS = envZHS.getCoordinateSystem();
// get the center point
Point const center{rootCSZHS, 0_m, 0_m, 0_m};
// a refractive index
const double ri_{1.000327};
// the constant density
const auto density{19.2_g / cube(1_cm)};
// the composition we use for the homogeneous medium
NuclearComposition const protonComposition({Code::Proton}, {1.});
// create magnetic field vector
Vector B1(rootCSZHS, 0_T, 0_T, 1_T);
auto Medium = EnvType::createNode<Sphere>(
center, 1_km * std::numeric_limits<double>::infinity());
auto const props = Medium->setModelProperties<AtmModel>(ri_, Medium::AirDry1Atm, B1,
density, protonComposition);
envZHS.getUniverse()->addChild(std::move(Medium));
// the antennas location
const auto point1{Point(envZHS.getCoordinateSystem(), 100_m, 2_m, 3_m)};
const auto point2{Point(envZHS.getCoordinateSystem(), 4_m, 80_m, 6_m)};
const auto point3{Point(envZHS.getCoordinateSystem(), 7_m, 8_m, 9_m)};
const auto point4{Point(envZHS.getCoordinateSystem(), 5_m, 5_m, 10_m)};
// create times for the antenna
const TimeType t1{0_s};
const TimeType t2{10_s};
const InverseTimeType t3{1e+3_Hz};
const TimeType t4{11_s};
// check that I can create an antenna at (1, 2, 3)
TimeDomainAntenna ant1("antenna_zhs", point1, t1, t2, t3, t1);
TimeDomainAntenna ant2("antenna_zhs2", point2, t1, t2, t3, t1);
// construct a radio detector instance to store our antennas
AntennaCollection<TimeDomainAntenna> detector;
// add the antennas to the detector
detector.addAntenna(ant1);
detector.addAntenna(ant2);
// create a particle
auto const particle{Code::Electron};
const auto pmass{get_mass(particle)};
VelocityVector v0(rootCSZHS, {5e+2_m / second, 5e+2_m / second, 5e+2_m / second});
Vector B0(rootCSZHS, 5_T, 5_T, 5_T);
Line const line(point3, v0);
auto const k{1_m * ((1_m) / ((1_s * 1_s) * 1_V))};
auto const t = 1e-12_s;
LeapFrogTrajectory base(point4, v0, B0, k, t);
// std::cout << "Leap Frog Trajectory is: " << base << std::endl;
// create a new stack for each trial
setup::Stack stack;
// construct an energy
const HEPEnergyType E0{1_TeV};
// compute the necessary momentum
const HEPMomentumType P0{sqrt(E0 * E0 - pmass * pmass)};
// and create the momentum vector
const auto plab{MomentumVector(rootCSZHS, {0_GeV, 0_GeV, P0})};
// and create the location of the particle in this coordinate system
const Point pos(rootCSZHS, 50_m, 10_m, 80_m);
// add the particle to the stack
auto const particle1{stack.addParticle(std::make_tuple(
particle, calculate_kinetic_energy(plab.getNorm(), get_mass(particle)),
plab.normalized(), pos, 0_ns))};
auto const charge_{get_charge(particle1.getPID())};
// create a radio process instance using ZHS
RadioProcess<
AntennaCollection<TimeDomainAntenna>,
ZHS<AntennaCollection<TimeDomainAntenna>, decltype(StraightPropagator(envZHS))>,
decltype(StraightPropagator(envZHS))>
zhs(detector, envZHS);
// check doContinuous and simulate methods
zhs.doContinuous(particle1, base, true);
} // END: SECTION("ZHS process")
SECTION("TimeDomainAntenna") {
// create an environment so we can get a coordinate system
using EnvType = Environment<IRefractiveIndexModel<IMediumModel>>;
EnvType env6;
using UniRIndex =
UniformRefractiveIndex<HomogeneousMedium<IRefractiveIndexModel<IMediumModel>>>;
// the antenna location
const auto point1{Point(env6.getCoordinateSystem(), 1_m, 2_m, 3_m)};
const auto point2{Point(env6.getCoordinateSystem(), 4_m, 5_m, 6_m)};
// get a coordinate system
const CoordinateSystemPtr rootCS6 = env6.getCoordinateSystem();
auto Medium6 = EnvType::createNode<Sphere>(
Point{rootCS6, 0_m, 0_m, 0_m}, 1_km * std::numeric_limits<double>::infinity());
auto const props6 = Medium6->setModelProperties<UniRIndex>(
1, 1_kg / (1_m * 1_m * 1_m), NuclearComposition({Code::Nitrogen}, {1.}));
env6.getUniverse()->addChild(std::move(Medium6));
// create times for the antenna
const TimeType t1{10_s};
const TimeType t2{10_s};
const InverseTimeType t3{1 / 1_s};
const TimeType t4{11_s};
// check that I can create an antenna at (1, 2, 3)
TimeDomainAntenna ant1("antenna_name", point1, t1, t2, t3, t1);
TimeDomainAntenna ant2("antenna_name2", point2, t4, t2, t3, t4);
// assert that the antenna name is correct
REQUIRE(ant1.getName() == "antenna_name");
REQUIRE(ant2.getName() == "antenna_name2");
// and check that the antenna is at the right location
REQUIRE((ant1.getLocation() - point1).getNorm() < 1e-12 * 1_m);
REQUIRE((ant2.getLocation() - point2).getNorm() < 1e-12 * 1_m);
// construct a radio detector instance to store our antennas
AntennaCollection<TimeDomainAntenna> detector;
// add this antenna to the process
detector.addAntenna(ant1);
detector.addAntenna(ant2);
CHECK(detector.size() == 2);
// get a unit vector
Vector<dimensionless_d> v1(rootCS6, {0, 0, 1});
Vector<ElectricFieldType::dimension_type> v11(rootCS6,
{10_V / 1_m, 10_V / 1_m, 10_V / 1_m});
Vector<dimensionless_d> v2(rootCS6, {0, 1, 0});
Vector<ElectricFieldType::dimension_type> v22(rootCS6,
{20_V / 1_m, 20_V / 1_m, 20_V / 1_m});
// use receive methods
ant1.receive(15_s, v1, v11);
ant2.receive(16_s, v2, v22);
// use getWaveform() methods
auto [tx, Ex] = ant1.getWaveformX();
CHECK(Ex[5] - 10 == 0);
CHECK(tx[5] - 5 * 1_s / 1_ns == Approx(0.0));
auto [ty, Ey] = ant1.getWaveformY();
CHECK(Ey[5] - 10 == 0);
auto [tz, Ez] = ant1.getWaveformZ();
CHECK(Ez[5] - 10 == 0);
CHECK(tx[5] - ty[5] == 0);
CHECK(ty[5] - tz[5] == 0);
auto [tx2, Ex2] = ant2.getWaveformX();
CHECK(Ex2[5] - 20 == 0);
auto [ty2, Ey2] = ant2.getWaveformY();
CHECK(Ey2[5] - 20 == 0);
auto [tz2, Ez2] = ant2.getWaveformZ();
CHECK(Ez2[5] - 20 == 0);
// the following creates a star-shaped pattern of antennas in the ground
AntennaCollection<TimeDomainAntenna> detector__;
const auto point11{Point(env6.getCoordinateSystem(), 1000_m, 20_m, 30_m)};
const TimeType t2222{1e-6_s};
const InverseTimeType t3333{1e+9_Hz};
for (auto radius_ = 100_m; radius_ <= 200_m; radius_ += 100_m) {
for (auto phi_ = 0; phi_ <= 315; phi_ += 45) {
auto phiRad_ = phi_ / 180. * M_PI;
auto const point_{Point(env6.getCoordinateSystem(), radius_ * cos(phiRad_),
radius_ * sin(phiRad_), 0_m)};
auto time__{(point11 - point_).getNorm() / constants::c};
const int rr_ = static_cast<int>(radius_ / 1_m);
std::string var_ = "antenna_R=" + std::to_string(rr_) +
"_m-Phi=" + std::to_string(phi_) + "degrees";
TimeDomainAntenna ant111(var_, point_, time__, t2222, t3333, time__);
detector__.addAntenna(ant111);
}
}
// this prints out the antenna names and locations
for (auto const antenna : detector__.getAntennas()) {
CORSIKA_LOG_DEBUG("Antenna name: {} ", antenna.getName());
CORSIKA_LOG_DEBUG("Antenna location: {} ", antenna.getLocation());
}
} // END: SECTION("TimeDomainAntenna")
SECTION("Simple Propagator w/ Uniform Refractive Index") {
// create a suitable environment
using IModelInterface =
IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>;
using AtmModel = UniformRefractiveIndex<
MediumPropertyModel<UniformMagneticField<HomogeneousMedium<IModelInterface>>>>;
using EnvType = Environment<AtmModel>;
EnvType env;
CoordinateSystemPtr const& rootCS = env.getCoordinateSystem();
// get the center point
Point const center{rootCS, 0_m, 0_m, 0_m};
// a refractive index for the vacuum
const double ri_{1};
// the constant density
const auto density{19.2_g / cube(1_cm)};
// the composition we use for the homogeneous medium
NuclearComposition const Composition({Code::Nitrogen}, {1.});
// create magnetic field vector
Vector B1(rootCS, 0_T, 0_T, 0.3809_T);
// create a Sphere for the medium
auto Medium = EnvType::createNode<Sphere>(
center, 1_km * std::numeric_limits<double>::infinity());
// set the environment properties
auto const props = Medium->setModelProperties<AtmModel>(ri_, Medium::AirDry1Atm, B1,
density, Composition);
// bind things together
env.getUniverse()->addChild(std::move(Medium));
// get some points
Point p0(rootCS, {0_m, 0_m, 0_m});
Point p10(rootCS, {0_m, 0_m, 10_m});
// get a unit vector
Vector<dimensionless_d> v1(rootCS, {0, 0, 1});
Vector<dimensionless_d> v2(rootCS, {0, 0, -1});
// get a geometrical path of points
Path P1({p0, p10});
// construct a Straight Propagator given the uniform refractive index environment
SimplePropagator SP(env);
// store the outcome of the Propagate method to paths_
auto const paths_ = SP.propagate(p0, p10, 1_m);
// perform checks to paths_ components
for (auto const& path : paths_) {
CHECK((path.propagation_time_ / 1_s) -
(((p10 - p0).getNorm() / constants::c) / 1_s) ==
Approx(0));
CHECK(path.average_refractive_index_ == Approx(1));
CHECK(path.refractive_index_source_ == Approx(1));
CHECK(path.refractive_index_destination_ == Approx(1));
CHECK(path.emit_.getComponents() == v1.getComponents());
CHECK(path.receive_.getComponents() == v2.getComponents());
CHECK(path.R_distance_ == 10_m);
CHECK(std::equal(P1.begin(), P1.end(), Path(path.points_).begin(),
[](Point a, Point b) { return (a - b).getNorm() / 1_m < 1e-5; }));
}
} // END: SECTION("Simple Propagator w/ Uniform Refractive Index")
// check that I can create working Straight Propagators in different environments
SECTION("Straight Propagator w/ Uniform Refractive Index") {
// create a suitable environment
using IModelInterface =
IRefractiveIndexModel<IMediumPropertyModel<IMagneticFieldModel<IMediumModel>>>;
using AtmModel = UniformRefractiveIndex<
MediumPropertyModel<UniformMagneticField<HomogeneousMedium<IModelInterface>>>>;
using EnvType = Environment<AtmModel>;
EnvType env;
CoordinateSystemPtr const& rootCS = env.getCoordinateSystem();
// get the center point
Point const center{rootCS, 0_m, 0_m, 0_m};
// a refractive index for the vacuum
const double ri_{1};
// the constant density
const auto density{19.2_g / cube(1_cm)};
// the composition we use for the homogeneous medium
NuclearComposition const Composition({Code::Nitrogen}, {1.});
// create magnetic field vector
Vector B1(rootCS, 0_T, 0_T, 0.3809_T);
// create a Sphere for the medium
auto Medium = EnvType::createNode<Sphere>(
center, 1_km * std::numeric_limits<double>::infinity());
// set the environment properties
auto const props = Medium->setModelProperties<AtmModel>(ri_, Medium::AirDry1Atm, B1,
density, Composition);
// bind things together
env.getUniverse()->addChild(std::move(Medium));
// get some points
Point p0(rootCS, {0_m, 0_m, 0_m});
Point p1(rootCS, {0_m, 0_m, 1_m});
Point p2(rootCS, {0_m, 0_m, 2_m});
Point p3(rootCS, {0_m, 0_m, 3_m});
Point p4(rootCS, {0_m, 0_m, 4_m});
Point p5(rootCS, {0_m, 0_m, 5_m});
Point p6(rootCS, {0_m, 0_m, 6_m});
Point p7(rootCS, {0_m, 0_m, 7_m});
Point p8(rootCS, {0_m, 0_m, 8_m});
Point p9(rootCS, {0_m, 0_m, 9_m});
Point p10(rootCS, {0_m, 0_m, 10_m});
Point p30(rootCS, {0_m, 0_m, 30000_m});
// get a unit vector
Vector<dimensionless_d> v1(rootCS, {0, 0, 1});
Vector<dimensionless_d> v2(rootCS, {0, 0, -1});
// get a geometrical path of points
Path P1({p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10});
// construct a Straight Propagator given the uniform refractive index environment
StraightPropagator SP(env);
// store the outcome of the Propagate method to paths_
auto const paths_ = SP.propagate(p0, p10, 1_m);
// perform checks to paths_ components
for (auto const& path : paths_) {
CHECK((path.propagation_time_ / 1_s) -
(((p10 - p0).getNorm() / constants::c) / 1_s) ==
Approx(0).margin(absMargin));
CHECK(path.average_refractive_index_ == Approx(1));
CHECK(path.refractive_index_source_ == Approx(1));
CHECK(path.refractive_index_destination_ == Approx(1));
CHECK(path.emit_.getComponents() == v1.getComponents());
CHECK(path.receive_.getComponents() == v2.getComponents());
CHECK(path.R_distance_ == 10_m);
CHECK(std::equal(P1.begin(), P1.end(), Path(path.points_).begin(),
[](Point a, Point b) { return (a - b).getNorm() / 1_m < 1e-5; }));
}
// get another path to different points
auto const paths2_{SP.propagate(p0, p30, 909_m)};
for (auto const& path : paths2_) {
CHECK((path.propagation_time_ / 1_s) -
(((p30 - p0).getNorm() / constants::c) / 1_s) ==
Approx(0).margin(absMargin));
CHECK(path.average_refractive_index_ == Approx(1));
CHECK(path.refractive_index_source_ == Approx(1));
CHECK(path.refractive_index_destination_ == Approx(1));
CHECK(path.R_distance_ == 30000_m);
}
// get a third path using a weird stepsize
auto const paths3_{SP.propagate(p0, p30, 731.89_m)};
for (auto const& path : paths3_) {
CHECK((path.propagation_time_ / 1_s) -
(((p30 - p0).getNorm() / constants::c) / 1_s) ==
Approx(0).margin(absMargin));
CHECK(path.average_refractive_index_ == Approx(1));
CHECK(path.refractive_index_source_ == Approx(1));
CHECK(path.refractive_index_destination_ == Approx(1));
CHECK(path.R_distance_ == 30000_m);
}
CHECK(paths_.size() == 1);
CHECK(paths2_.size() == 1);
CHECK(paths3_.size() == 1);
} // END: SECTION("Straight Propagator w/ Uniform Refractive Index")
SECTION("Straight Propagator w/ Exponential Refractive Index") {
// create an environment with exponential refractive index (n_0 = 1 & lambda = 0)
using ExpoRIndex = ExponentialRefractiveIndex<
HomogeneousMedium<IRefractiveIndexModel<IMediumModel>>>;
using EnvType = Environment<IRefractiveIndexModel<IMediumModel>>;
EnvType env1;
// get another coordinate system
const CoordinateSystemPtr rootCS1 = env1.getCoordinateSystem();
// the center of the earth
Point const center1_{rootCS1, 0_m, 0_m, 0_m};
LengthType const radius_{0_m};
auto Medium1 = EnvType::createNode<Sphere>(
Point{rootCS1, 0_m, 0_m, 0_m}, 1_km * std::numeric_limits<double>::infinity());
auto const props1 = Medium1->setModelProperties<ExpoRIndex>(
1, 0 / 1_m, center1_, radius_, 1_kg / (1_m * 1_m * 1_m),
NuclearComposition({Code::Nitrogen}, {1.}));
env1.getUniverse()->addChild(std::move(Medium1));
// get some points
Point pp0(rootCS1, {0_m, 0_m, 0_m});
Point pp1(rootCS1, {0_m, 0_m, 1_m});
Point pp2(rootCS1, {0_m, 0_m, 2_m});
Point pp3(rootCS1, {0_m, 0_m, 3_m});
Point pp4(rootCS1, {0_m, 0_m, 4_m});
Point pp5(rootCS1, {0_m, 0_m, 5_m});
Point pp6(rootCS1, {0_m, 0_m, 6_m});
Point pp7(rootCS1, {0_m, 0_m, 7_m});
Point pp8(rootCS1, {0_m, 0_m, 8_m});
Point pp9(rootCS1, {0_m, 0_m, 9_m});
Point pp10(rootCS1, {0_m, 0_m, 10_m});
// get a unit vector
Vector<dimensionless_d> vv1(rootCS1, {0, 0, 1});
Vector<dimensionless_d> vv2(rootCS1, {0, 0, -1});
// get a geometrical path of points
Path PP1({pp0, pp1, pp2, pp3, pp4, pp5, pp6, pp7, pp8, pp9, pp10});
// construct a Straight Propagator given the exponential refractive index environment
StraightPropagator SP1(env1);
// store the outcome of Propagate method to paths1_
auto const paths1_ = SP1.propagate(pp0, pp10, 1_m);
// perform checks to paths1_ components (this is just a sketch for now)
for (auto const& path : paths1_) {
CHECK((path.propagation_time_ / 1_s) -
(((pp10 - pp0).getNorm() / constants::c) / 1_s) ==
Approx(0).margin(absMargin));
CHECK(path.average_refractive_index_ == Approx(1));
CHECK(path.refractive_index_source_ == Approx(1));
CHECK(path.refractive_index_destination_ == Approx(1));
CHECK(path.emit_.getComponents() == vv1.getComponents());
CHECK(path.receive_.getComponents() == vv2.getComponents());
CHECK(path.R_distance_ == 10_m);
CHECK(std::equal(PP1.begin(), PP1.end(), Path(path.points_).begin(),
[](Point a, Point b) { return (a - b).getNorm() / 1_m < 1e-5; }));
}
CHECK(paths1_.size() == 1);
/*
* A second environment with another exponential refractive index
*/
// create an environment with exponential refractive index (n_0 = 2 & lambda = 2)
using ExpoRIndex = ExponentialRefractiveIndex<
HomogeneousMedium<IRefractiveIndexModel<IMediumModel>>>;
using EnvType = Environment<IRefractiveIndexModel<IMediumModel>>;
EnvType env2;
// get another coordinate system
const CoordinateSystemPtr rootCS2 = env2.getCoordinateSystem();
// the center of the earth
Point const center2_{rootCS2, 0_m, 0_m, 0_m};
auto Medium2 = EnvType::createNode<Sphere>(
Point{rootCS2, 0_m, 0_m, 0_m}, 1_km * std::numeric_limits<double>::infinity());
auto const props2 = Medium2->setModelProperties<ExpoRIndex>(
2, 2 / 1_m, center2_, radius_, 1_kg / (1_m * 1_m * 1_m),
NuclearComposition({Code::Nitrogen}, {1.}));
env2.getUniverse()->addChild(std::move(Medium2));
// get some points
Point ppp0(rootCS2, {0_m, 0_m, 0_m});
Point ppp10(rootCS2, {0_m, 0_m, 10_m});
// get a unit vector
Vector<dimensionless_d> vvv1(rootCS2, {0, 0, 1});
Vector<dimensionless_d> vvv2(rootCS2, {0, 0, -1});
// construct a Straight Propagator given the exponential refractive index environment
StraightPropagator SP2(env2);
// store the outcome of Propagate method to paths1_
auto const paths2_ = SP2.propagate(ppp0, ppp10, 1_m);
// perform checks to paths1_ components (this is just a sketch for now)
for (auto const& path : paths2_) {
CHECK((path.propagation_time_ / 1_s) -
((3.177511688_m / (3 * constants::c)) / 1_s) ==
Approx(0).margin(absMargin));
CHECK(path.average_refractive_index_ == Approx(0.210275935));
CHECK(path.refractive_index_source_ == Approx(2));
// CHECK(path.refractive_index_destination_ == Approx(0.0000000041));
CHECK(path.emit_.getComponents() == vvv1.getComponents());
CHECK(path.receive_.getComponents() == vvv2.getComponents());
CHECK(path.R_distance_ == 10_m);
}
CHECK(paths2_.size() == 1);
} // END: SECTION("Straight Propagator w/ Exponential Refractive Index")
} // END: TEST_CASE("Radio", "[processes]")