Program Listing for File PhotCommons.hpp

↰ Return to documentation for file (src/phot/PhotCommons.hpp)

#ifndef PHOTCOMMONS_HPP
#define PHOTCOMMONS_HPP

#include "../utils/Constants.hpp"
#include <cmath>
#include <cstdint>
#include <filesystem>
#include <numbers>
#include <string>

namespace phot
{
    enum class PhotSystem : std::uint8_t // NOLINT(readability-identifier-naming) -- capitalized to match Flambda/Fnu/ST/AB/Vega's own fixed photometric-system naming below, rather than the project's usual camelBack enum-constant convention
    {
        Flambda,  // NOLINT(readability-identifier-naming) -- see PhotSystem
        Fnu,      // NOLINT(readability-identifier-naming) -- see PhotSystem
        ST,       // NOLINT(readability-identifier-naming) -- see PhotSystem
        AB,       // NOLINT(readability-identifier-naming) -- see PhotSystem
        Vega      // NOLINT(readability-identifier-naming) -- see PhotSystem
    };

    inline constexpr double flux0AB = 3631.0;
    inline constexpr double flux0ST = 3.631e-9;
    inline constexpr double fourPiTenPcSq =
        4.0 * std::numbers::pi_v<double> * (10.0 * utils::pc) * (10.0 * utils::pc);

    inline static const std::string defaultVegaSpec = // NOLINT(bugprone-throwing-static-initialization,cert-err58-cpp) -- built from fixed string literals, so the (theoretically throwing) path conversion can never actually throw here
        (std::filesystem::path("data") / std::filesystem::path("spectra")
        / std::filesystem::path("vega.h5"));
    template <PhotSystem From, PhotSystem To>
    constexpr auto PhotConvert(double photIn, double wl) -> double; // NOLINT(readability-identifier-naming) -- capitalized to match this file's other fixed photometric naming (PhotSystem above), rather than the project's usual camelBack function convention

    template <PhotSystem From, PhotSystem To>
    auto PhotConvert(double photIn, double wl, double fluxVega) -> double; // NOLINT(readability-identifier-naming) -- see the two-argument overload above

    template <>
    constexpr auto PhotConvert<PhotSystem::Flambda, PhotSystem::Fnu>(const double photIn, const double wl) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        return photIn * wl * wl * utils::Angstrom / utils::c;
    }

    template <>
    constexpr auto PhotConvert<PhotSystem::Fnu, PhotSystem::Flambda>(const double photIn, const double wl) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        return photIn * utils::c / (wl * wl * utils::Angstrom);
    }

    template <>
    inline auto PhotConvert<PhotSystem::Fnu, PhotSystem::AB>(const double photIn, double /*wl*/) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        const double fluxIn = (photIn / fourPiTenPcSq) / utils::Jy;
        return -2.5 * std::log10(fluxIn / flux0AB);
    }

    template <>
    inline auto PhotConvert<PhotSystem::AB, PhotSystem::Fnu>(const double photIn, double /*wl*/) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        const double fluxIn = flux0AB * std::pow(10.0, photIn / -2.5);
        return (fluxIn * utils::Jy) * fourPiTenPcSq;
    }

    template <>
    inline auto PhotConvert<PhotSystem::Flambda, PhotSystem::ST>(const double photIn, double /*wl*/) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        const double fluxIn = photIn / fourPiTenPcSq;
        return -2.5 * std::log10(fluxIn / flux0ST);
    }

    template <>
    inline auto PhotConvert<PhotSystem::ST, PhotSystem::Flambda>(const double photIn, double /*wl*/) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        const double fluxIn = flux0ST * std::pow(10.0, photIn / -2.5);
        return fluxIn * fourPiTenPcSq;
    }

    // The remaining (from, to) combinations -- every one not directly
    // defined above, excluding any involving Vega (handled separately
    // as a special case rather than through this template -- see the
    // primary template's own comment) -- are each composed from the
    // six direct conversions above, chained through Flambda and/or Fnu
    // (the two physical-flux systems every magnitude system's own
    // conversion above already goes through). wl is genuinely used by
    // each of these, unlike PhotConvert<Fnu, AB>/<Flambda, ST> and
    // their inverses: it's threaded through to whichever of those
    // Flambda <-> Fnu steps the chain actually needs. None of these
    // are marked constexpr either, since each calls at least one of
    // the log10/pow-based conversions above that aren't -- see
    // PhotConvert<Fnu, AB>'s own comment for why. Each is marked
    // inline for the same ODR reason those non-constexpr conversions
    // are.

    template <>
    inline auto PhotConvert<PhotSystem::Flambda, PhotSystem::AB>(const double photIn, const double wl) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        return PhotConvert<PhotSystem::Fnu, PhotSystem::AB>(
            PhotConvert<PhotSystem::Flambda, PhotSystem::Fnu>(photIn, wl), wl);
    }

    template <>
    inline auto PhotConvert<PhotSystem::AB, PhotSystem::Flambda>(const double photIn, const double wl) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        return PhotConvert<PhotSystem::Fnu, PhotSystem::Flambda>(
            PhotConvert<PhotSystem::AB, PhotSystem::Fnu>(photIn, wl), wl);
    }

    template <>
    inline auto PhotConvert<PhotSystem::Fnu, PhotSystem::ST>(const double photIn, const double wl) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::ST>(
            PhotConvert<PhotSystem::Fnu, PhotSystem::Flambda>(photIn, wl), wl);
    }

    template <>
    inline auto PhotConvert<PhotSystem::ST, PhotSystem::Fnu>(const double photIn, const double wl) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::Fnu>(
            PhotConvert<PhotSystem::ST, PhotSystem::Flambda>(photIn, wl), wl);
    }

    template <>
    inline auto PhotConvert<PhotSystem::ST, PhotSystem::AB>(const double photIn, const double wl) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        return PhotConvert<PhotSystem::Fnu, PhotSystem::AB>(
            PhotConvert<PhotSystem::Flambda, PhotSystem::Fnu>(
                PhotConvert<PhotSystem::ST, PhotSystem::Flambda>(photIn, wl), wl), wl);
    }

    template <>
    inline auto PhotConvert<PhotSystem::AB, PhotSystem::ST>(const double photIn, const double wl) -> double // NOLINT(readability-identifier-naming) -- see the primary template above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::ST>(
            PhotConvert<PhotSystem::Fnu, PhotSystem::Flambda>(
                PhotConvert<PhotSystem::AB, PhotSystem::Fnu>(photIn, wl), wl), wl);
    }

    // ---- Vega magnitude conversions (three-argument overload) ----
    //
    // Flambda <-> Vega are direct: identical in form to Flambda <->
    // ST, but with flux0ST (a fixed constant) replaced by fluxVega (a
    // per-filter value) as the zero point -- so Vega itself (photIn
    // == fluxVega) evaluates to magnitude 0 by construction, exactly
    // as the Vega system is defined to work. Unlike photIn, fluxVega
    // is always a genuine flux (from the real, already-at-Earth Vega
    // reference spectrum -- see Filter::fluxVega()), never a specific
    // luminosity, so it needs no fourPiTenPcSq scaling of its own; only
    // photIn (when it's on the Flambda side) does, exactly as for
    // PhotConvert<Flambda, ST>/<ST, Flambda>. Every other (From, To)
    // pair involving Vega is built by chaining through Flambda: To
    // Vega, first convert From -> Flambda (via the two-argument
    // overload), then Flambda -> Vega; from Vega, first convert
    // Vega -> Flambda, then Flambda -> To (via the two-argument
    // overload again). None of these are constexpr, for the same
    // reason as their AB/ST counterparts above.

    template <>
    inline auto PhotConvert<PhotSystem::Flambda, PhotSystem::Vega>(const double photIn, double /*wl*/, const double fluxVega) -> double // NOLINT(readability-identifier-naming) -- see the two-argument overload above
    {
        const double fluxIn = photIn / fourPiTenPcSq;
        return -2.5 * std::log10(fluxIn / fluxVega);
    }

    template <>
    inline auto PhotConvert<PhotSystem::Vega, PhotSystem::Flambda>(const double photIn, double /*wl*/, const double fluxVega) -> double // NOLINT(readability-identifier-naming) -- see the two-argument overload above
    {
        const double fluxIn = fluxVega * std::pow(10.0, photIn / -2.5);
        return fluxIn * fourPiTenPcSq;
    }

    template <>
    inline auto PhotConvert<PhotSystem::Fnu, PhotSystem::Vega>(const double photIn, const double wl, const double fluxVega) -> double // NOLINT(readability-identifier-naming) -- see the two-argument overload above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::Vega>(
            PhotConvert<PhotSystem::Fnu, PhotSystem::Flambda>(photIn, wl), wl, fluxVega);
    }

    template <>
    inline auto PhotConvert<PhotSystem::Vega, PhotSystem::Fnu>(const double photIn, const double wl, const double fluxVega) -> double // NOLINT(readability-identifier-naming) -- see the two-argument overload above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::Fnu>(
            PhotConvert<PhotSystem::Vega, PhotSystem::Flambda>(photIn, wl, fluxVega), wl);
    }

    template <>
    inline auto PhotConvert<PhotSystem::ST, PhotSystem::Vega>(const double photIn, const double wl, const double fluxVega) -> double // NOLINT(readability-identifier-naming) -- see the two-argument overload above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::Vega>(
            PhotConvert<PhotSystem::ST, PhotSystem::Flambda>(photIn, wl), wl, fluxVega);
    }

    template <>
    inline auto PhotConvert<PhotSystem::Vega, PhotSystem::ST>(const double photIn, const double wl, const double fluxVega) -> double // NOLINT(readability-identifier-naming) -- see the two-argument overload above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::ST>(
            PhotConvert<PhotSystem::Vega, PhotSystem::Flambda>(photIn, wl, fluxVega), wl);
    }

    template <>
    inline auto PhotConvert<PhotSystem::AB, PhotSystem::Vega>(const double photIn, const double wl, const double fluxVega) -> double // NOLINT(readability-identifier-naming) -- see the two-argument overload above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::Vega>(
            PhotConvert<PhotSystem::AB, PhotSystem::Flambda>(photIn, wl), wl, fluxVega);
    }

    template <>
    inline auto PhotConvert<PhotSystem::Vega, PhotSystem::AB>(const double photIn, const double wl, const double fluxVega) -> double // NOLINT(readability-identifier-naming) -- see the two-argument overload above
    {
        return PhotConvert<PhotSystem::Flambda, PhotSystem::AB>(
            PhotConvert<PhotSystem::Vega, PhotSystem::Flambda>(photIn, wl, fluxVega), wl);
    }

} // namespace phot

#endif // PHOTCOMMONS_HPP