IAP GITLAB

Skip to content
Snippets Groups Projects
Commit 60bed2bf authored by Marvin Gottowik's avatar Marvin Gottowik
Browse files

rename all antennas to observers

parent 66463ae7
No related branches found
No related tags found
1 merge request!645rename all antennas to observers
Showing
with 371 additions and 266 deletions
......@@ -69,9 +69,9 @@
#include <corsika/modules/radio/CoREAS.hpp>
#include <corsika/modules/radio/RadioProcess.hpp>
#include <corsika/modules/radio/ZHS.hpp>
#include <corsika/modules/radio/antennas/Antenna.hpp>
#include <corsika/modules/radio/antennas/TimeDomainAntenna.hpp>
#include <corsika/modules/radio/detectors/AntennaCollection.hpp>
#include <corsika/modules/radio/observers/Observer.hpp>
#include <corsika/modules/radio/observers/TimeDomainObserver.hpp>
#include <corsika/modules/radio/detectors/ObserverCollection.hpp>
#include <corsika/modules/radio/propagators/TabulatedFlatAtmospherePropagator.hpp>
#include <corsika/setup/SetupStack.hpp>
......@@ -271,7 +271,7 @@ int main(int argc, char** argv) {
bool multithin = false;
app.add_flag("--multithin", multithin, "keep thinned particles (with weight=0)")
->group("Thinning");
app.add_option("--ring", "concentric ring of star shape pattern of antennas")
app.add_option("--ring", "concentric ring of star shape pattern of observers")
->default_val(0)
->check(CLI::Range(0, 20))
->group("Radio");
......@@ -527,14 +527,14 @@ int main(int argc, char** argv) {
auto const radius_{ring_number * 25_m};
const int rr_ = static_cast<int>(radius_ / 1_m);
// Radio antennas and relevant information
// the antenna time variables
// Radio observers and relevant information
// the observer time variables
const TimeType duration_{4e-7_s};
const InverseTimeType sampleRate_{1e+9_Hz};
// the antenna collection for CoREAS and ZHS
AntennaCollection<TimeDomainAntenna> detectorCoREAS;
AntennaCollection<TimeDomainAntenna> detectorZHS;
// the observer collection for CoREAS and ZHS
ObserverCollection<TimeDomainObserver> detectorCoREAS;
ObserverCollection<TimeDomainObserver> detectorZHS;
auto const showerCoreX_{showerCore.getCoordinates().getX()};
auto const showerCoreY_{showerCore.getCoordinates().getY()};
......@@ -544,34 +544,34 @@ int main(int argc, char** argv) {
auto const triggerpoint_{Point(rootCS, injectionPosX_, injectionPosY_, injectionPosZ_)};
if (ring_number != 0) {
// setup CoREAS antennas - use the for loop for star shape pattern
// setup CoREAS observers - use the for loop for star shape pattern
for (auto phi_1 = 0; phi_1 <= 315; phi_1 += 45) {
auto phiRad_1 = phi_1 / 180. * M_PI;
auto const point_1{Point(rootCS, showerCoreX_ + radius_ * cos(phiRad_1),
showerCoreY_ + radius_ * sin(phiRad_1),
constants::EarthRadius::Mean)};
std::cout << "Antenna point CoREAS: " << point_1 << std::endl;
std::cout << "Observer point CoREAS: " << point_1 << std::endl;
auto triggertime_1{(triggerpoint_ - point_1).getNorm() / constants::c};
std::string name_1 = "CoREAS_R=" + std::to_string(rr_) +
"_m--Phi=" + std::to_string(phi_1) + "degrees";
TimeDomainAntenna antenna_1(name_1, point_1, rootCS, triggertime_1, duration_,
sampleRate_, triggertime_1);
detectorCoREAS.addAntenna(antenna_1);
TimeDomainObserver observer_1(name_1, point_1, rootCS, triggertime_1, duration_,
sampleRate_, triggertime_1);
detectorCoREAS.addObserver(observer_1);
}
// setup ZHS antennas - use the for loop for star shape pattern
// setup ZHS observers - use the for loop for star shape pattern
for (auto phi_ = 0; phi_ <= 315; phi_ += 45) {
auto phiRad_ = phi_ / 180. * M_PI;
auto const point_{Point(rootCS, showerCoreX_ + radius_ * cos(phiRad_),
showerCoreY_ + radius_ * sin(phiRad_),
constants::EarthRadius::Mean)};
std::cout << "Antenna point ZHS: " << point_ << std::endl;
std::cout << "Observer point ZHS: " << point_ << std::endl;
auto triggertime_{(triggerpoint_ - point_).getNorm() / constants::c};
std::string name_ =
"ZHS_R=" + std::to_string(rr_) + "_m--Phi=" + std::to_string(phi_) + "degrees";
TimeDomainAntenna antenna_(name_, point_, rootCS, triggertime_, duration_,
sampleRate_, triggertime_);
detectorZHS.addAntenna(antenna_);
TimeDomainObserver observer_2(name_, point_, rootCS, triggertime_, duration_,
sampleRate_, triggertime_);
detectorZHS.addObserver(observer_2);
}
}
LengthType const step = 1_m;
......
......@@ -54,16 +54,16 @@ namespace corsika {
// set threshold for application of ZHS-like approximation.
const double approxThreshold_{1.0e-3};
// loop over each antenna in the antenna collection (detector)
for (auto& antenna : antennas_.getAntennas()) {
// loop over each observer in the observer collection (detector)
for (auto& observer : observers_.getObservers()) {
// get the SignalPathCollection (path1) from the start "endpoint" to the antenna.
// get the SignalPathCollection (path1) from the start "endpoint" to the observer.
auto paths1{this->propagator_.propagate(step.getParticlePre(), startPoint_,
antenna.getLocation())};
observer.getLocation())};
// get the SignalPathCollection (path2) from the end "endpoint" to the antenna.
// get the SignalPathCollection (path2) from the end "endpoint" to the observer.
auto paths2{this->propagator_.propagate(step.getParticlePre(), endPoint_,
antenna.getLocation())};
observer.getLocation())};
// LCOV_EXCL_START
// This should never happen unless someone implements a bad propagator
......@@ -140,14 +140,14 @@ namespace corsika {
// calculate receive time for endpoint
auto endPointReceiveTime_{endTime_ + paths2[i].propagation_time_};
// get unit vector for startpoint at antenna location
// get unit vector for startpoint at observer location
auto ReceiveVectorStart_{paths1[i].receive_};
// get unit vector for endpoint at antenna location
// get unit vector for endpoint at observer location
auto ReceiveVectorEnd_{paths2[i].receive_};
// perform ZHS-like calculation close to Cherenkov angle and for refractive
// index at antenna location greater than 1
// index at observer location greater than 1
if ((paths1[i].refractive_index_destination_ > 1) &&
((std::fabs(preDoppler_) < approxThreshold_) ||
(std::fabs(postDoppler_) < approxThreshold_))) {
......@@ -165,9 +165,9 @@ namespace corsika {
TimeType const midTime_{(startTime_ + endTime_) * 0.5};
// get the SignalPathCollection (path3) from the middle "endpoint" to the
// antenna.
// observer.
auto paths3{this->propagator_.propagate(step.getParticlePre(), midPoint_,
antenna.getLocation())};
observer.getLocation())};
// now loop over the paths for endpoint that we got above
for (auto const& path : paths3) {
......@@ -202,8 +202,8 @@ namespace corsika {
// CoREAS calculation -> get ElectricFieldVector for "midPoint"
ElectricFieldVector EVmid_ = (path.emit_.cross(path.emit_.cross(beta_))) /
midDoppler_ / path.R_distance_ * constants_ *
antenna.getSampleRate();
midDoppler_ / path.R_distance_ * constants_ *
observer.getSampleRate();
ElectricFieldVector EV1_{EVmid_};
ElectricFieldVector EV2_{EVmid_ * (-1.0)};
......@@ -222,7 +222,7 @@ namespace corsika {
endPointReceiveTime_ = midPointReceiveTime_ - 0.5 * deltaT_;
}
TimeType const gridResolution_{1 / antenna.getSampleRate()};
TimeType const gridResolution_{1 / observer.getSampleRate()};
deltaT_ = endPointReceiveTime_ - startPointReceiveTime_;
// redistribute contributions over time scale defined by the observation
......@@ -304,8 +304,8 @@ namespace corsika {
// TODO: Be very careful with this. Maybe the EVs should be fed after the
// for loop of paths3
antenna.receive(startPointReceiveTime_, ReceiveVectorStart_, EV1_);
antenna.receive(endPointReceiveTime_, ReceiveVectorEnd_, EV2_);
observer.receive(startPointReceiveTime_, ReceiveVectorStart_, EV1_);
observer.receive(endPointReceiveTime_, ReceiveVectorEnd_, EV2_);
} // End of looping over paths3
} // end of ZHS-like approximation
......@@ -314,16 +314,16 @@ namespace corsika {
// calculate electric field vector for startpoint
ElectricFieldVector EV1_ =
(paths1[i].emit_.cross(paths1[i].emit_.cross(beta_))) / preDoppler_ /
paths1[i].R_distance_ * constants_ * antenna.getSampleRate();
paths1[i].R_distance_ * constants_ * observer.getSampleRate();
// calculate electric field vector for endpoint
ElectricFieldVector EV2_ =
(paths2[i].emit_.cross(paths2[i].emit_.cross(beta_))) / postDoppler_ /
paths2[i].R_distance_ * constants_ * (-1.0) * antenna.getSampleRate();
paths2[i].R_distance_ * constants_ * (-1.0) * observer.getSampleRate();
if ((preDoppler_ < 1.e-9) || (postDoppler_ < 1.e-9)) {
TimeType const gridResolution_{1 / antenna.getSampleRate()};
TimeType const gridResolution_{1 / observer.getSampleRate()};
TimeType deltaT_{endPointReceiveTime_ - startPointReceiveTime_};
if (abs(deltaT_) < (gridResolution_)) {
......@@ -372,15 +372,15 @@ namespace corsika {
} // End of if for startbin == endbin
} // End of if deltaT < gridresolution
} // End of if that checks small doppler factors
antenna.receive(startPointReceiveTime_, ReceiveVectorStart_, EV1_);
antenna.receive(endPointReceiveTime_, ReceiveVectorEnd_, EV2_);
observer.receive(startPointReceiveTime_, ReceiveVectorStart_, EV1_);
observer.receive(endPointReceiveTime_, ReceiveVectorEnd_, EV2_);
} // End of else that does not perform ZHS-like approximation
} // End of loop over both paths to get signal info
} // End of looping over antennas
} // End of looping over observer
return ProcessReturn::Ok;
}
} // End of simulate method
} // namespace corsika
\ No newline at end of file
} // namespace corsika
......@@ -11,32 +11,32 @@
namespace corsika {
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
inline TRadioImpl&
RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>::implementation() {
RadioProcess<TObserverCollection, TRadioImpl, TPropagator>::implementation() {
return static_cast<TRadioImpl&>(*this);
}
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
inline TRadioImpl const&
RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>::implementation() const {
RadioProcess<TObserverCollection, TRadioImpl, TPropagator>::implementation() const {
return static_cast<TRadioImpl const&>(*this);
}
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
inline RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>::RadioProcess(
TAntennaCollection& antennas, TPropagator& propagator)
: antennas_(antennas)
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
inline RadioProcess<TObserverCollection, TRadioImpl, TPropagator>::RadioProcess(
TObserverCollection& observers, TPropagator& propagator)
: observers_(observers)
, propagator_(propagator) {}
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
template <typename Particle>
inline ProcessReturn RadioProcess<TAntennaCollection, TRadioImpl,
inline ProcessReturn RadioProcess<TObserverCollection, TRadioImpl,
TPropagator>::doContinuous(const Step<Particle>& step,
const bool) {
// return immediately if radio process does not have any antennas
if (antennas_.size() == 0) return ProcessReturn::Ok;
// return immediately if radio process does not have any observers
if (observers_.size() == 0) return ProcessReturn::Ok;
// we want the following particles:
// Code::Electron & Code::Positron
......@@ -57,21 +57,21 @@ namespace corsika {
//}
}
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
template <typename Particle, typename Track>
inline LengthType
RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>::getMaxStepLength(
RadioProcess<TObserverCollection, TRadioImpl, TPropagator>::getMaxStepLength(
[[maybe_unused]] const Particle& vParticle,
[[maybe_unused]] const Track& vTrack) const {
return meter * std::numeric_limits<double>::infinity();
}
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
inline void RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>::startOfLibrary(
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
inline void RadioProcess<TObserverCollection, TRadioImpl, TPropagator>::startOfLibrary(
const boost::filesystem::path& directory) {
// setup the streamer
output_.initStreamer((directory / ("antennas.parquet")).string());
output_.initStreamer((directory / ("observers.parquet")).string());
// LCOV_EXCL_START
// build the schema
output_.addField("Time", parquet::Repetition::REQUIRED, parquet::Type::DOUBLE,
......@@ -90,34 +90,34 @@ namespace corsika {
output_.buildStreamer();
}
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
inline void RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>::endOfShower(
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
inline void RadioProcess<TObserverCollection, TRadioImpl, TPropagator>::endOfShower(
const unsigned int) {
// loop over every antenna and instruct them to
// flush data to disk, and then reset the antenna
// loop over every observer and instruct them to
// flush data to disk, and then reset the observer
// before the next event
for (auto& antenna : antennas_.getAntennas()) {
for (auto& observer : observers_.getObservers()) {
auto const sampleRate = antenna.getSampleRate() * 1_s;
auto const sampleRate = observer.getSampleRate() * 1_s;
auto const radioImplementation =
static_cast<std::string>(this->implementation().algorithm);
// get the axis labels for this antenna and write the first row.
axistype axis = antenna.implementation().getAxis();
// get the axis labels for this observer and write the first row.
axistype axis = observer.implementation().getAxis();
// get the copy of the waveform data for this event
std::vector<double> const& dataX = antenna.implementation().getWaveformX();
std::vector<double> const& dataY = antenna.implementation().getWaveformY();
std::vector<double> const& dataZ = antenna.implementation().getWaveformZ();
std::vector<double> const& dataX = observer.implementation().getWaveformX();
std::vector<double> const& dataY = observer.implementation().getWaveformY();
std::vector<double> const& dataZ = observer.implementation().getWaveformZ();
// check for the axis name
std::string label = "Unknown";
if (antenna.getDomainLabel() == "Time") {
if (observer.getDomainLabel() == "Time") {
label = "Time";
}
// LCOV_EXCL_START
else if (antenna.getDomainLabel() == "Frequency") {
else if (observer.getDomainLabel() == "Frequency") {
label = "Frequency";
}
// LCOV_EXCL_STOP
......@@ -141,7 +141,7 @@ namespace corsika {
}
}
antenna.reset();
observer.reset();
}
output_.closeStreamer();
......@@ -149,8 +149,8 @@ namespace corsika {
showerId_++;
}
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
inline YAML::Node RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>::getConfig()
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
inline YAML::Node RadioProcess<TObserverCollection, TRadioImpl, TPropagator>::getConfig()
const {
// top-level YAML node
......@@ -164,18 +164,18 @@ namespace corsika {
config["units"]["electric field"] = "V/m";
config["units"]["distance"] = "m";
for (auto& antenna : antennas_.getAntennas()) {
// get the name/location of this antenna
auto name = antenna.getName();
auto location = antenna.getLocation().getCoordinates();
for (auto& observer : observers_.getObservers()) {
// get the name/location of this observer
auto name = observer.getName();
auto location = observer.getLocation().getCoordinates();
// get the antennas config
config["antennas"][name] = antenna.getConfig();
// get the observers config
config["observers"][name] = observer.getConfig();
// write the location of this antenna
config["antennas"][name]["location"].push_back(location.getX() / 1_m);
config["antennas"][name]["location"].push_back(location.getY() / 1_m);
config["antennas"][name]["location"].push_back(location.getZ() / 1_m);
// write the location of this observer
config["observers"][name]["location"].push_back(location.getX() / 1_m);
config["observers"][name]["location"].push_back(location.getY() / 1_m);
config["observers"][name]["location"].push_back(location.getZ() / 1_m);
}
return config;
......
......@@ -45,15 +45,15 @@ namespace corsika {
auto const constants{charge * emConstant_ * thinningWeight};
// we loop over each antenna in the collection
for (auto& antenna : antennas_.getAntennas()) {
// we loop over each observer in the collection
for (auto& observer : observers_.getObservers()) {
auto midPaths{this->propagator_.propagate(step.getParticlePre(), midPoint,
antenna.getLocation())};
observer.getLocation())};
// Loop over midPaths, first check Fraunhoffer limit
for (size_t i{0}; i < midPaths.size(); i++) {
double const uTimesK{beta.dot(midPaths[i].emit_) / betaModule};
double const sinTheta2{1. - uTimesK * uTimesK};
LengthType const lambda{constants::c / antenna.getSampleRate()};
LengthType const lambda{constants::c / observer.getSampleRate()};
double const fraunhLimit{sinTheta2 * trackLength * trackLength /
midPaths[i].R_distance_ / lambda * 2 * M_PI};
// Checks if we are in fraunhoffer domain
......@@ -72,7 +72,7 @@ namespace corsika {
auto const newHalfVector{(point1 - point2) / 2.};
auto const newMidPoint{point2 + newHalfVector};
auto const newMidPaths{this->propagator_.propagate(
step.getParticlePre(), newMidPoint, antenna.getLocation())};
step.getParticlePre(), newMidPoint, observer.getLocation())};
// A function for calculating the field should be made since it is repeated
// later
for (size_t k{0}; k < newMidPaths.size(); k++) {
......@@ -98,10 +98,10 @@ namespace corsika {
} // end if statement for time structure
double const startBin{std::floor(
(detectionTime1 - antenna.getStartTime()) * antenna.getSampleRate() +
(detectionTime1 - observer.getStartTime()) * observer.getSampleRate() +
0.5)};
double const endBin{std::floor((detectionTime2 - antenna.getStartTime()) *
antenna.getSampleRate() +
double const endBin{std::floor((detectionTime2 - observer.getStartTime()) *
observer.getSampleRate() +
0.5)};
auto const betaPerp{
......@@ -112,42 +112,42 @@ namespace corsika {
// track contained in bin
// if not in Cerenkov angle then
if (std::fabs(denominator) > 1.e-15) {
double const f{std::fabs((detectionTime2 * antenna.getSampleRate() -
detectionTime1 * antenna.getSampleRate()))};
double const f{std::fabs((detectionTime2 * observer.getSampleRate() -
detectionTime1 * observer.getSampleRate()))};
VectorPotential const Vp = betaPerp * sign * constants * f /
denominator / newMidPaths[k].R_distance_;
antenna.receive(detectionTime2, betaPerp, Vp);
observer.receive(detectionTime2, betaPerp, Vp);
} else { // If emission in Cerenkov angle => approximation
double const f{time2 * antenna.getSampleRate() -
time1 * antenna.getSampleRate()};
double const f{time2 * observer.getSampleRate() -
time1 * observer.getSampleRate()};
VectorPotential const Vp =
betaPerp * sign * constants * f / newMidPaths[k].R_distance_;
antenna.receive(detectionTime2, betaPerp, Vp);
observer.receive(detectionTime2, betaPerp, Vp);
} // end if Cerenkov angle approx
} else {
/*Track is contained in more than one bin*/
int const numberOfBins{static_cast<int>(endBin - startBin)};
// first contribution/ plus 1 bin minus 0.5 from new antenna ruonding
// first contribution/ plus 1 bin minus 0.5 from new observer ruonding
double f{std::fabs(startBin + 0.5 -
(detectionTime1 - antenna.getStartTime()) *
antenna.getSampleRate())};
(detectionTime1 - observer.getStartTime()) *
observer.getSampleRate())};
VectorPotential Vp = betaPerp * sign * constants * f / denominator /
newMidPaths[k].R_distance_;
antenna.receive(detectionTime1, betaPerp, Vp);
observer.receive(detectionTime1, betaPerp, Vp);
// intermidiate contributions
for (int it{1}; it < numberOfBins; ++it) {
Vp = betaPerp * constants / denominator / newMidPaths[k].R_distance_;
antenna.receive(detectionTime1 +
static_cast<double>(it) / antenna.getSampleRate(),
observer.receive(detectionTime1 +
static_cast<double>(it) / observer.getSampleRate(),
betaPerp, Vp);
} // end loop over bins in which potential vector is not zero
// final contribution// f +0.5 from new antenna rounding
f = std::fabs((detectionTime2 - antenna.getStartTime()) *
antenna.getSampleRate() +
// final contribution// f +0.5 from new observer rounding
f = std::fabs((detectionTime2 - observer.getStartTime()) *
observer.getSampleRate() +
0.5 - endBin);
Vp = betaPerp * sign * constants * f / denominator /
newMidPaths[k].R_distance_;
antenna.receive(detectionTime2, betaPerp, Vp);
observer.receive(detectionTime2, betaPerp, Vp);
} // end if statement for track in multiple bins
} // end of loop over newMidPaths
......@@ -178,11 +178,11 @@ namespace corsika {
sign = -1.;
} // end if statement for time structure
double const startBin{std::floor((detectionTime1 - antenna.getStartTime()) *
antenna.getSampleRate() +
double const startBin{std::floor((detectionTime1 - observer.getStartTime()) *
observer.getSampleRate() +
0.5)};
double const endBin{std::floor((detectionTime2 - antenna.getStartTime()) *
antenna.getSampleRate() +
double const endBin{std::floor((detectionTime2 - observer.getStartTime()) *
observer.getSampleRate() +
0.5)};
auto const betaPerp{midPaths[i].emit_.cross(beta.cross(midPaths[i].emit_))};
......@@ -193,18 +193,18 @@ namespace corsika {
// track contained in bin
// if not in Cerenkov angle then
if (std::fabs(denominator) > 1.e-15) {
double const f{std::fabs((detectionTime2 * antenna.getSampleRate() -
detectionTime1 * antenna.getSampleRate()))};
double const f{std::fabs((detectionTime2 * observer.getSampleRate() -
detectionTime1 * observer.getSampleRate()))};
VectorPotential const Vp = betaPerp * sign * constants * f / denominator /
midPaths[i].R_distance_;
antenna.receive(detectionTime2, betaPerp, Vp);
observer.receive(detectionTime2, betaPerp, Vp);
} else { // If emission in Cerenkov angle => approximation
double const f{endTime * antenna.getSampleRate() -
startTime * antenna.getSampleRate()};
double const f{endTime * observer.getSampleRate() -
startTime * observer.getSampleRate()};
VectorPotential const Vp =
betaPerp * sign * constants * f / midPaths[i].R_distance_;
antenna.receive(detectionTime2, betaPerp, Vp);
observer.receive(detectionTime2, betaPerp, Vp);
} // end if Cerenkov angle approx
} else {
/*Track is contained in more than one bin*/
......@@ -212,34 +212,34 @@ namespace corsika {
// TODO: should we check for Cerenkov angle?
// first contribution
double f{std::fabs(startBin + 0.5 -
(detectionTime1 - antenna.getStartTime()) *
antenna.getSampleRate())};
(detectionTime1 - observer.getStartTime()) *
observer.getSampleRate())};
VectorPotential Vp =
betaPerp * sign * constants * f / denominator / midPaths[i].R_distance_;
antenna.receive(detectionTime1, betaPerp, Vp);
observer.receive(detectionTime1, betaPerp, Vp);
// intermediate contributions
for (int it{1}; it < numberOfBins; ++it) {
Vp = betaPerp * sign * constants / denominator / midPaths[i].R_distance_;
antenna.receive(
detectionTime1 + static_cast<double>(it) / antenna.getSampleRate(),
observer.receive(
detectionTime1 + static_cast<double>(it) / observer.getSampleRate(),
betaPerp, Vp);
} // end loop over bins in which potential vector is not zero
// final contribution
f = std::fabs((detectionTime2 - antenna.getStartTime()) *
antenna.getSampleRate() +
f = std::fabs((detectionTime2 - observer.getStartTime()) *
observer.getSampleRate() +
0.5 - endBin);
Vp =
betaPerp * sign * constants * f / denominator / midPaths[i].R_distance_;
antenna.receive(detectionTime2, betaPerp, Vp);
observer.receive(detectionTime2, betaPerp, Vp);
} // end if statement for track in multiple bins
} // finish if statement of track in fraunhoffer or not
} // end loop over mid paths
} // END: loop over antennas
} // END: loop over observers
return ProcessReturn::Ok;
}
} // end simulate
} // namespace corsika
\ No newline at end of file
} // namespace corsika
/*
* (c) Copyright 2022 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.
*/
#pragma once
#include <corsika/modules/radio/detectors/AntennaCollection.hpp>
namespace corsika {
template <typename TAntennaImpl>
inline void AntennaCollection<TAntennaImpl>::addAntenna(TAntennaImpl const& antenna) {
antennas_.push_back(antenna);
}
template <typename TAntennaImpl>
inline TAntennaImpl& AntennaCollection<TAntennaImpl>::at(std::size_t const i) {
return antennas_.at(i);
}
template <typename TAntennaImpl>
inline TAntennaImpl const& AntennaCollection<TAntennaImpl>::at(
std::size_t const i) const {
return antennas_.at(i);
}
template <typename TAntennaImpl>
inline int AntennaCollection<TAntennaImpl>::size() const {
return antennas_.size();
}
template <typename TAntennaImpl>
inline std::vector<TAntennaImpl>& AntennaCollection<TAntennaImpl>::getAntennas() {
return antennas_;
}
template <typename TAntennaImpl>
inline void AntennaCollection<TAntennaImpl>::reset() {
std::for_each(antennas_.begin(), antennas_.end(), std::mem_fn(&TAntennaImpl::reset));
}
} // namespace corsika
/*
* (c) Copyright 2022 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.
*/
#pragma once
#include <corsika/modules/radio/detectors/ObserverCollection.hpp>
namespace corsika {
template <typename TObserverImpl>
inline void ObserverCollection<TObserverImpl>::addObserver(TObserverImpl const& observer) {
observers_.push_back(observer);
}
template <typename TObserverImpl>
inline TObserverImpl& ObserverCollection<TObserverImpl>::at(std::size_t const i) {
return observers_.at(i);
}
template <typename TObserverImpl>
inline TObserverImpl const& ObserverCollection<TObserverImpl>::at(
std::size_t const i) const {
return observers_.at(i);
}
template <typename TObserverImpl>
inline int ObserverCollection<TObserverImpl>::size() const {
return observers_.size();
}
template <typename TObserverImpl>
inline std::vector<TObserverImpl>& ObserverCollection<TObserverImpl>::getObservers() {
return observers_;
}
template <typename TObserverImpl>
inline void ObserverCollection<TObserverImpl>::reset() {
std::for_each(observers_.begin(), observers_.end(), std::mem_fn(&TObserverImpl::reset));
}
} // namespace corsika
......@@ -7,30 +7,30 @@
*/
#pragma once
#include <corsika/modules/radio/antennas/Antenna.hpp>
#include <corsika/modules/radio/observers/Observer.hpp>
namespace corsika {
template <typename TAntennaImpl>
inline Antenna<TAntennaImpl>::Antenna(std::string const& name, Point const& location,
CoordinateSystemPtr const& coordinateSystem)
template <typename TObserverImpl>
inline Observer<TObserverImpl>::Observer(std::string const& name, Point const& location,
CoordinateSystemPtr const& coordinateSystem)
: name_(name)
, location_(location)
, coordinateSystem_(coordinateSystem) {}
template <typename TAntennaImpl>
inline Point const& Antenna<TAntennaImpl>::getLocation() const {
template <typename TObserverImpl>
inline Point const& Observer<TObserverImpl>::getLocation() const {
return location_;
}
template <typename TAntennaImpl>
inline std::string const& Antenna<TAntennaImpl>::getName() const {
template <typename TObserverImpl>
inline std::string const& Observer<TObserverImpl>::getName() const {
return name_;
}
template <typename TAntennaImpl>
inline TAntennaImpl& Antenna<TAntennaImpl>::implementation() {
return static_cast<TAntennaImpl&>(*this);
template <typename TObserverImpl>
inline TObserverImpl& Observer<TObserverImpl>::implementation() {
return static_cast<TObserverImpl&>(*this);
}
} // namespace corsika
......@@ -7,18 +7,18 @@
*/
#pragma once
#include <corsika/modules/radio/antennas/TimeDomainAntenna.hpp>
#include <corsika/modules/radio/observers/TimeDomainObserver.hpp>
namespace corsika {
inline TimeDomainAntenna::TimeDomainAntenna(std::string const& name,
inline TimeDomainObserver::TimeDomainObserver(std::string const& name,
Point const& location,
CoordinateSystemPtr coordinateSystem,
TimeType const& start_time,
TimeType const& duration,
InverseTimeType const& sample_rate,
TimeType const ground_hit_time)
: Antenna(name, location, coordinateSystem)
: Observer(name, location, coordinateSystem)
, start_time_(start_time)
, duration_(std::abs(duration / 1_s) * 1_s)
, sample_rate_(std::abs(sample_rate / 1_Hz) * 1_Hz)
......@@ -30,21 +30,21 @@ namespace corsika {
, time_axis_(createTimeAxis()) {
if (0_s == duration_) {
CORSIKA_LOG_WARN(
"Antenna: \"{}\" has a duration of zero. Nothing will be injected into it",
"Observer: \"{}\" has a duration of zero. Nothing will be injected into it",
name);
} else if (duration_ != duration) {
CORSIKA_LOG_WARN(
"Antenna: \"{}\" was given a negative duration. Set to absolute value.", name);
"Observer: \"{}\" was given a negative duration. Set to absolute value.", name);
}
if (sample_rate_ != sample_rate) {
CORSIKA_LOG_WARN(
"Antenna: \"{}\" was given a negative sampling rate. Set to absolute value.",
"Observer: \"{}\" was given a negative sampling rate. Set to absolute value.",
name);
}
}
inline void TimeDomainAntenna::receive(
inline void TimeDomainObserver::receive(
const TimeType time, [[maybe_unused]] const Vector<dimensionless_d>& receive_vector,
const ElectricFieldVector& efield) {
......@@ -66,7 +66,7 @@ namespace corsika {
}
}
inline void TimeDomainAntenna::receive(
inline void TimeDomainObserver::receive(
const TimeType time, [[maybe_unused]] const Vector<dimensionless_d>& receive_vector,
const VectorPotential& vectorP) {
......@@ -91,15 +91,15 @@ namespace corsika {
}
}
inline auto const& TimeDomainAntenna::getWaveformX() const { return waveformEX_; }
inline auto const& TimeDomainObserver::getWaveformX() const { return waveformEX_; }
inline auto const& TimeDomainAntenna::getWaveformY() const { return waveformEY_; }
inline auto const& TimeDomainObserver::getWaveformY() const { return waveformEY_; }
inline auto const& TimeDomainAntenna::getWaveformZ() const { return waveformEZ_; }
inline auto const& TimeDomainObserver::getWaveformZ() const { return waveformEZ_; }
inline std::string const TimeDomainAntenna::getDomainLabel() { return "Time"; }
inline std::string const TimeDomainObserver::getDomainLabel() { return "Time"; }
inline std::vector<long double> TimeDomainAntenna::createTimeAxis() const {
inline std::vector<long double> TimeDomainObserver::createTimeAxis() const {
// create a 1-D xtensor to store time values so we can print them later.
std::vector<long double> times(num_bins_, 0);
......@@ -117,26 +117,26 @@ namespace corsika {
return times;
}
inline auto const TimeDomainAntenna::getAxis() const { return time_axis_; }
inline auto const TimeDomainObserver::getAxis() const { return time_axis_; }
inline InverseTimeType const& TimeDomainAntenna::getSampleRate() const {
inline InverseTimeType const& TimeDomainObserver::getSampleRate() const {
return sample_rate_;
}
inline TimeType const& TimeDomainAntenna::getStartTime() const { return start_time_; }
inline TimeType const& TimeDomainObserver::getStartTime() const { return start_time_; }
inline void TimeDomainAntenna::reset() {
inline void TimeDomainObserver::reset() {
std::fill(waveformEX_.begin(), waveformEX_.end(), 0);
std::fill(waveformEY_.begin(), waveformEY_.end(), 0);
std::fill(waveformEZ_.begin(), waveformEZ_.end(), 0);
}
inline YAML::Node TimeDomainAntenna::getConfig() const {
inline YAML::Node TimeDomainObserver::getConfig() const {
// top-level config
YAML::Node config;
config["type"] = "TimeDomainAntenna";
config["type"] = "TimeDomainObserver";
config["start time"] = start_time_ / 1_ns;
config["duration"] = duration_ / 1_ns;
config["number of bins"] = duration_ * sample_rate_;
......
......@@ -31,7 +31,7 @@ namespace corsika {
*
*/
// these are used for the direction of emission and reception of signal at the antenna
// these are used for the direction of emission and reception of signal at the observer
auto const emit_{(destination - source).normalized()};
auto const receive_{-emit_};
......
......@@ -31,7 +31,7 @@ namespace corsika {
* so they are both called direction
*/
// these are used for the direction of emission and reception of signal at the antenna
// these are used for the direction of emission and reception of signal at the observer
auto const emit{(destination - source).normalized()};
auto const receive{-emit};
......
......@@ -86,7 +86,7 @@ namespace corsika {
*
*/
// these are used for the direction of emission and reception of signal at the antenna
// these are used for the direction of emission and reception of signal at the observer
auto const emit_{(destination - source).normalized()};
auto const receive_{-emit_};
......
......@@ -49,10 +49,10 @@ namespace corsika {
using Base =
RadioProcess<TRadioDetector, CoREAS<TRadioDetector, TPropagator>, TPropagator>;
using Base::antennas_;
using Base::observers_;
}; // end of class CoREAS
} // namespace corsika
#include <corsika/detail/modules/radio/CoREAS.inl>
\ No newline at end of file
#include <corsika/detail/modules/radio/CoREAS.inl>
......@@ -20,12 +20,12 @@ namespace corsika {
* The base interface for radio emission processes.
*
* TRadioImpl is the concrete implementation of the radio algorithm.
* TAntennaCollection is the detector instance that stores antennas
* TObserverCollection is the detector instance that stores observers
* and is responsible for managing the output writing.
*/
template <typename TAntennaCollection, typename TRadioImpl, typename TPropagator>
template <typename TObserverCollection, typename TRadioImpl, typename TPropagator>
class RadioProcess : public ContinuousProcess<
RadioProcess<TAntennaCollection, TRadioImpl, TPropagator>>,
RadioProcess<TObserverCollection, TRadioImpl, TPropagator>>,
public BaseOutput {
/*
......@@ -44,17 +44,17 @@ namespace corsika {
TRadioImpl const& implementation() const;
protected:
TAntennaCollection& antennas_; ///< The radio antennas we store into.
TPropagator propagator_; ///< The propagator implementation.
unsigned int showerId_{0}; ///< The current event ID.
ParquetStreamer output_; //!< The parquet streamer for this process.
TObserverCollection& observers_; ///< The radio observers we store into.
TPropagator propagator_; ///< The propagator implementation.
unsigned int showerId_{0}; ///< The current event ID.
ParquetStreamer output_; //!< The parquet streamer for this process.
public:
using axistype = std::vector<long double>;
/**
* Construct a new RadioProcess.
*/
RadioProcess(TAntennaCollection& antennas, TPropagator& propagator);
RadioProcess(TObserverCollection& observers, TPropagator& propagator);
/**
* Perform the continuous process (radio emission).
......@@ -106,4 +106,4 @@ namespace corsika {
} // namespace corsika
#include <corsika/detail/modules/radio/RadioProcess.inl>
\ No newline at end of file
#include <corsika/detail/modules/radio/RadioProcess.inl>
......@@ -52,10 +52,10 @@ namespace corsika {
private:
using Base =
RadioProcess<TRadioDetector, ZHS<TRadioDetector, TPropagator>, TPropagator>;
using Base::antennas_;
using Base::observers_;
}; // END: class ZHS
} // namespace corsika
#include <corsika/detail/modules/radio/ZHS.inl>
\ No newline at end of file
#include <corsika/detail/modules/radio/ZHS.inl>
......@@ -11,59 +11,59 @@ namespace corsika {
/**
* The base interface for radio detectors.
* At the moment it is a collection of antennas with the same implementation.
* At the moment it is a collection of observers with the same implementation.
*/
template <typename TAntennaImpl>
class AntennaCollection {
template <typename TObserverImpl>
class ObserverCollection {
/**
* The collection of antennas used in this simulation.
* The collection of observers used in this simulation.
*/
std::vector<TAntennaImpl> antennas_;
std::vector<TObserverImpl> observers_;
public:
/**
* Add an antenna to this radio process.
* Add an observer to this radio process.
*
* @param antenna The antenna to add
* @param observer The observer to add
*/
void addAntenna(TAntennaImpl const& antenna);
void addObserver(TObserverImpl const& observer);
/**
* Get the specific antenna at that place in the collection
* Get the specific observer at that place in the collection
*
* @param index in the collection
*/
TAntennaImpl& at(std::size_t const i);
TObserverImpl& at(std::size_t const i);
TAntennaImpl const& at(std::size_t const i) const;
TObserverImpl const& at(std::size_t const i) const;
/**
* Get the number of antennas in the collection
* Get the number of observerss in the collection
*/
int size() const;
/**
* Get a *non*-const reference to the collection of antennas.
* Get a *non*-const reference to the collection of observers.
*
* @returns An iterable mutable reference to the antennas.
* @returns An iterable mutable reference to the observers.
*/
std::vector<TAntennaImpl>& getAntennas();
std::vector<TObserverImpl>& getObservers();
/**
* Get a const reference to the collection of antennas.
* Get a const reference to the collection of observers.
*
* @returns An iterable mutable reference to the antennas.
* @returns An iterable mutable reference to the observers.
*/
std::vector<TAntennaImpl> const& getAntennas() const;
std::vector<TObserverImpl> const& getObservers() const;
/**
* Reset all the antenna waveforms.
* Reset all the observer waveforms.
*/
void reset();
}; // END: class RadioDetector
} // namespace corsika
#include <corsika/detail/modules/radio/detectors/AntennaCollection.inl>
#include <corsika/detail/modules/radio/detectors/ObserverCollection.inl>
......@@ -15,57 +15,57 @@
namespace corsika {
/**
* A common abstract interface for radio antennas.
* A common abstract interface for radio oberservers.
*
* All concrete antenna implementations should be of
* type Antenna<T> where T is a concrete antenna implementation.
* All concrete observer implementations should be of
* type Observer<T> where T is a concrete observer implementation.
*
*/
template <typename TAntennaImpl>
class Antenna {
template <typename TObserverImpl>
class Observer {
protected:
std::string const name_; ///< The name/identifier of this antenna.
Point const location_; ///< The location of this antenna.
CoordinateSystemPtr const coordinateSystem_; ///< The coordinate system of the antenna
std::string const name_; ///< The name/identifier of this observer.
Point const location_; ///< The location of this observer.
CoordinateSystemPtr const coordinateSystem_; ///< The coordinate system of the observer
public:
using axistype = std::vector<long double>;
/**
* \brief Construct a base antenna instance.
* \brief Construct a base observer instance.
*
* @param name A name for this antenna.
* @param location The location of this antenna.
* @param name A name for this observer.
* @param location The location of this observer.
*
*/
Antenna(std::string const& name, Point const& location,
CoordinateSystemPtr const& coordinateSystem);
Observer(std::string const& name, Point const& location,
CoordinateSystemPtr const& coordinateSystem);
/**
* Receive a signal at this antenna.
* Receive a signal at this observer.
*
* This is a general implementation call that must be specialized
* for the particular antenna implementation and usage.
* for the particular observer implementation and usage.
*
*/
template <typename... TVArgs>
void receive(TVArgs&&... args);
/**
* Get the location of this antenna.
* Get the location of this observer.
*/
Point const& getLocation() const;
/**
* Get the name of this name antenna.
* Get the name of this name observer.
*
* This is used in producing the output data file.
*/
std::string const& getName() const;
/**
* Reset the antenna before starting a new simulation.
* Reset the observer before starting a new simulation.
*/
void reset();
......@@ -80,7 +80,7 @@ namespace corsika {
/**
* Return a reference to the underlying waveform data for X polarization.
*
* This is used when writing the antenna information to disk
* This is used when writing the observer information to disk
* and will be converted to a 32-bit float before writing.
*/
std::vector<double> const& getWaveformX() const;
......@@ -88,7 +88,7 @@ namespace corsika {
/**
* Return a reference to the underlying waveform data for Y polarization.
*
* This is used when writing the antenna information to disk
* This is used when writing the observer information to disk
* and will be converted to a 32-bit float before writing.
*/
std::vector<double> const& getWaveformY() const;
......@@ -96,7 +96,7 @@ namespace corsika {
/**
* Return a reference to the underlying waveform data for Z polarization.
*
* This is used when writing the antenna information to disk
* This is used when writing the observer information to disk
* and will be converted to a 32-bit float before writing.
*/
std::vector<double> const& getWaveformZ() const;
......@@ -104,10 +104,10 @@ namespace corsika {
/**
* Get a reference to the underlying radio implementation.
*/
TAntennaImpl& implementation();
TObserverImpl& implementation();
}; // END: class Antenna final
}; // END: class Observer final
} // namespace corsika
#include <corsika/detail/modules/radio/antennas/Antenna.inl>
#include <corsika/detail/modules/radio/observers/Observer.inl>
......@@ -7,22 +7,22 @@
*/
#pragma once
#include <corsika/modules/radio/antennas/Antenna.hpp>
#include <corsika/modules/radio/observers/Observer.hpp>
#include <yaml-cpp/yaml.h>
#include <vector>
namespace corsika {
/**
* An implementation of a time-domain antenna that has a customized
* An implementation of a time-domain observer that has a customized
* start time, sampling rate, and waveform duration.
*
*/
class TimeDomainAntenna : public Antenna<TimeDomainAntenna> {
class TimeDomainObserver : public Observer<TimeDomainObserver> {
TimeType const start_time_; ///< The start time of this waveform.
TimeType const duration_; ///< The duration of this waveform.
InverseTimeType const sample_rate_; ///< The sampling rate of this antenna.
InverseTimeType const sample_rate_; ///< The sampling rate of this observer.
TimeType const ground_hit_time_; ///< The time the primary particle hits the ground.
uint64_t const num_bins_; ///< The number of bins used.
std::vector<double> waveformEX_; ///< EX polarization.
......@@ -32,16 +32,16 @@ namespace corsika {
time_axis_; ///< The time axis corresponding to the electric field.
public:
// import the methods from the antenna
using Antenna<TimeDomainAntenna>::getName;
using Antenna<TimeDomainAntenna>::getLocation;
// import the methods from the observer
using Observer<TimeDomainObserver>::getName;
using Observer<TimeDomainObserver>::getLocation;
/**
* Construct a new TimeDomainAntenna.
* Construct a new TimeDomainObserver.
*
* @param name The name of this antenna.
* @param location The location of this antenna.
* @param coordinateSystem The coordinate system of this antenna.
* @param name The name of this observer.
* @param location The location of this observer.
* @param coordinateSystem The coordinate system of this observer.
* @param start_time The starting time of this waveform.
* @param duration The duration of this waveform.
* @param sample_rate The sample rate of this waveform.
......@@ -49,15 +49,15 @@ namespace corsika {
* straight vertical line.
*
*/
TimeDomainAntenna(std::string const& name, Point const& location,
CoordinateSystemPtr coordinateSystem, TimeType const& start_time,
TimeType const& duration, InverseTimeType const& sample_rate,
TimeType const ground_hit_time);
TimeDomainObserver(std::string const& name, Point const& location,
CoordinateSystemPtr coordinateSystem, TimeType const& start_time,
TimeType const& duration, InverseTimeType const& sample_rate,
TimeType const ground_hit_time);
/**
* Receive an electric field at this antenna.
* Receive an electric field at this observer.
*
* This assumes that the antenna will receive
* This assumes that the observer will receive
* an *instantaneous* electric field modeled as a delta function (or timebin).
*
* @param time The (global) time at which this signal is received.
......@@ -65,7 +65,7 @@ namespace corsika {
* @param field The incident electric field vector.
*
*/
// TODO: rethink this method a bit. If the endpoint is at the end of the antenna
// TODO: rethink this method a bit. If the endpoint is at the end of the observer
// resolution then you get the startpoint signal but you lose the endpoint signal!
void receive(TimeType const time, Vector<dimensionless_d> const& receive_vector,
ElectricFieldVector const& efield);
......@@ -96,7 +96,7 @@ namespace corsika {
/**
* Return a label that indicates that this is a time
* domain antenna
* domain observer
*
* This returns the string "Time".
*/
......@@ -117,27 +117,27 @@ namespace corsika {
auto const getAxis() const;
/**
* Returns the sampling rate of the time domain antenna.
* Returns the sampling rate of the time domain observer.
*/
InverseTimeType const& getSampleRate() const;
/**
* Returns the start time of detection for the time domain antenna.
* Returns the start time of detection for the time domain observer.
*/
TimeType const& getStartTime() const;
/**
* Reset the antenna before starting a new simulation.
* Reset the observer before starting a new simulation.
*/
void reset();
/**
* Return a YAML configuration for this antenna.
* Return a YAML configuration for this observer.
*/
YAML::Node getConfig() const;
}; // END: class TimeDomainAntenna
}; // END: class TimeDomainObserver
} // namespace corsika
#include <corsika/detail/modules/radio/antennas/TimeDomainAntenna.inl>
#include <corsika/detail/modules/radio/observers/TimeDomainObserver.inl>
......@@ -19,7 +19,7 @@ namespace corsika {
/**
* This class implements a dummy propagator that uses
* the straight-line (vector) between the particle
* location and the antenna as the trajectory.
* location and the observer as the trajectory.
* It is intended mainly for fast testing as it only
* works with 2 points in a uniform refractive index
* atmospheric profile.
......@@ -42,7 +42,7 @@ namespace corsika {
/**
* Return the collection of paths from `source` to `destination`.
* Hence, the signal propagated from the
* emission point to the antenna location.
* emission point to the observer location.
*
*/
template <typename Particle>
......@@ -63,4 +63,4 @@ namespace corsika {
} // namespace corsika
#include <corsika/detail/modules/radio/propagators/DummyTestPropagator.inl>
\ No newline at end of file
#include <corsika/detail/modules/radio/propagators/DummyTestPropagator.inl>
......@@ -19,7 +19,7 @@ namespace corsika {
/**
* This class implements a basic propagator that uses
* the straight-line (vector) between the particle
* location and the antenna as the trajectory.
* location and the observer as the trajectory.
* To calculate the time delay of the signal, a basic
* numerical integration scheme based on Simpson's rule
* takes place. This propagator is slow and not
......@@ -46,7 +46,7 @@ namespace corsika {
/**
* Return the collection of paths from `start` to `end`.
* or from 'source' which is the emission point to 'destination'
* which is the location of the antenna
* which is the location of the observer
*/
template <typename Particle>
SignalPathCollection propagate(Particle const& particle, Point const& source,
......@@ -66,4 +66,4 @@ namespace corsika {
} // namespace corsika
#include <corsika/detail/modules/radio/propagators/NumericalIntegratingPropagator.inl>
\ No newline at end of file
#include <corsika/detail/modules/radio/propagators/NumericalIntegratingPropagator.inl>
......@@ -16,7 +16,7 @@ namespace corsika {
/**
* Radio propagators are used to calculate the propagation
* paths from particles to antennas. Any class that wants
* paths from particles to observers. Any class that wants
* to be used as a RadioPropagator must implement the
* following methods:
*
......@@ -44,4 +44,4 @@ namespace corsika {
} // namespace corsika
#include <corsika/detail/modules/radio/propagators/RadioPropagator.inl>
\ No newline at end of file
#include <corsika/detail/modules/radio/propagators/RadioPropagator.inl>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment