diff --git a/Environment/CMakeLists.txt b/Environment/CMakeLists.txt index e01188125c647e1f802edf844ce69b7014e70a49..d5e69be6dd383bd5c1ce126331a59c66bbdb3be6 100644 --- a/Environment/CMakeLists.txt +++ b/Environment/CMakeLists.txt @@ -21,6 +21,8 @@ set ( SlidingPlanarExponential.h LayeredSphericalAtmosphereBuilder.h ShowerAxis.h + IMagneticFieldModel.h + UniformMagneticField.h ) set ( diff --git a/Environment/IMagneticFieldModel.h b/Environment/IMagneticFieldModel.h new file mode 100644 index 0000000000000000000000000000000000000000..5941f3ba473c6f4d5bc9a864dd31256ac1355e18 --- /dev/null +++ b/Environment/IMagneticFieldModel.h @@ -0,0 +1,47 @@ +/* + * (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. + */ +#pragma once + +#include <corsika/geometry/Point.h> +#include <corsika/units/PhysicalUnits.h> + +namespace corsika::environment { + + /** + * An interface for magnetic field models. + * + * This is the base interface for magnetic field model mixins. + * + */ + template <typename Model> + class IMagneticFieldModel : public Model { + + // a type-alias for a magnetic field vector + using MagneticFieldVector = + corsika::geometry::QuantityVector<corsika::units::si::magnetic_flux_density_d>; + + public: + /** + * Evaluate the magnetic field at a given location. + * + * @param point The location to evaluate the field at. + * @returns The magnetic field vector at that point. + */ + virtual auto GetMagneticField(corsika::geometry::Point const&) const + -> MagneticFieldVector = 0; + + /** + * A virtual default destructor. + */ + virtual ~IMagneticFieldModel() = default; + + }; // END: class MagneticField + +} // namespace corsika::environment diff --git a/Environment/UniformMagneticField.h b/Environment/UniformMagneticField.h new file mode 100644 index 0000000000000000000000000000000000000000..4e3ee298ad9cd0d53a0edca1386905eb8e6e6677 --- /dev/null +++ b/Environment/UniformMagneticField.h @@ -0,0 +1,67 @@ +/* + * (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. + */ +#pragma once + +#include <corsika/environment/IMagneticFieldModel.h> + +namespace corsika::environment { + + /** + * A uniform (constant) magnetic field. + * + * This class returns the same magnetic field vector + * for all evaluated locations. + * + */ + template <typename T> + class UniformMagneticField : public T { + + // a type-alias for a magnetic field vector + using MagneticFieldVector = + corsika::geometry::QuantityVector<corsika::units::si::magnetic_flux_density_d>; + + MagneticFieldVector B_; ///< The constant magnetic field we use. + + public: + /** + * Construct a UniformMagneticField. + * + * This is initialized with a fixed magnetic field + * and returns this magnetic field at all locations. + * + * @param field The fixed magnetic field to return. + */ + template <typename... Args> + UniformMagneticField(MagneticFieldVector const& B, Args&&... args) + : T(std::forward<Args>(args)...) + , B_(B) {} + + /** + * Evaluate the magnetic field at a given location. + * + * @param point The location to evaluate the field at. + * @returns The magnetic field vector. + */ + MagneticFieldVector GetMagneticField( + corsika::geometry::Point const&) const final override { + return B_; + } + + /** + * Set the magnetic field returned by this instance. + * + * @param point The location to evaluate the field at. + * @returns The magnetic field vector. + */ + auto SetMagneticField(MagneticFieldVector const& Bfield) -> void { B_ = Bfield; } + + }; // END: class MagneticField + +} // namespace corsika::environment diff --git a/Environment/testEnvironment.cc b/Environment/testEnvironment.cc index 574907e5914ec7e97628023483f4dd7572dde836..d2434aac25429dd69cd4e096e36c8f19f1814595 100644 --- a/Environment/testEnvironment.cc +++ b/Environment/testEnvironment.cc @@ -11,12 +11,14 @@ #include <corsika/environment/DensityFunction.h> #include <corsika/environment/FlatExponential.h> #include <corsika/environment/HomogeneousMedium.h> +#include <corsika/environment/IMagneticFieldModel.h> #include <corsika/environment/IMediumModel.h> #include <corsika/environment/InhomogeneousMedium.h> #include <corsika/environment/LayeredSphericalAtmosphereBuilder.h> #include <corsika/environment/LinearApproximationIntegrator.h> #include <corsika/environment/NuclearComposition.h> #include <corsika/environment/SlidingPlanarExponential.h> +#include <corsika/environment/UniformMagneticField.h> #include <corsika/environment/VolumeTreeNode.h> #include <corsika/geometry/Line.h> #include <corsika/geometry/RootCoordinateSystem.h> @@ -229,3 +231,47 @@ TEST_CASE("LayeredSphericalAtmosphereBuilder") { univ->GetContainingNode(Point(gCS, 0_m, 0_m, R + 24_km))->GetVolume()) .GetRadius() == R + 30_km); } + +TEST_CASE("UniformMagneticField w/ Homogeneous Medium") { + + // setup our interface types + using IModelInterface = IMagneticFieldModel<IMediumModel>; + using AtmModel = UniformMagneticField<HomogeneousMedium<IModelInterface>>; + + // the composition we use for the homogenous medium + NuclearComposition const protonComposition(std::vector<Code>{Code::Proton}, + std::vector<float>{1.f}); + + // create a magnetic field vector + QuantityVector B0(0_T, 0_T, 0_T); + + // create our atmospheric model + AtmModel const medium(B0, 19.2_g / cube(1_cm), protonComposition); +} + +TEST_CASE("UniformMagneticField w/ FlatExponential") { + + // setup our interface types + using IModelInterface = IMagneticFieldModel<IMediumModel>; + using AtmModel = UniformMagneticField<FlatExponential<IModelInterface>>; + + // the composition we use for the homogenous medium + NuclearComposition const protonComposition(std::vector<Code>{Code::Proton}, + std::vector<float>{1.f}); + + // define our quantity vector + Vector const axis(gCS, QuantityVector<dimensionless_d>(0, 0, 1)); + + // the parameters of our exponential model + LengthType const lambda = 3_m; + auto const rho0 = 1_g / units::si::detail::static_pow<3>(1_cm); + + // create a magnetic field vector + QuantityVector B0(23_T, 57_T, -4_T); + + // create our atmospheric model + AtmModel const medium(B0, gOrigin, axis, rho0, lambda, protonComposition); + + // check that the returned magnetic field is correct + REQUIRE(B0 == medium.GetMagneticField(Point(gCS, -10_m, 4_m, 35_km))); +}