Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-01-07 10:01:42

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file celeritas/optical/gen/CherenkovDndxCalculator.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <cmath>
0010 
0011 #include "corecel/Assert.hh"
0012 #include "corecel/Macros.hh"
0013 #include "corecel/Types.hh"
0014 #include "corecel/grid/VectorUtils.hh"
0015 #include "celeritas/Quantities.hh"
0016 #include "celeritas/grid/NonuniformGridCalculator.hh"
0017 
0018 #include "CherenkovData.hh"
0019 #include "../MaterialView.hh"
0020 
0021 namespace celeritas
0022 {
0023 //---------------------------------------------------------------------------//
0024 /*!
0025  * Calculate the mean number of Cherenkov photons produced per unit length.
0026  *
0027  * The average number of photons produced is given by
0028  * \f[
0029    \dif N = \frac{\alpha z^2}{\hbar c}\sin^2\theta \dif\epsilon \dif x =
0030    \frac{\alpha z^2}{\hbar c}\left(1 - \frac{1}{n^2\beta^2}\right) \dif\epsilon
0031    \dif x,
0032  * \f]
0033  * where \f$ n \f$ is the refractive index of the material, \f$ \epsilon \f$
0034  * is the photon energy, and \f$ \theta \f$ is the angle of the emitted photons
0035  * with respect to the incident particle direction, given by \f$ \cos\theta = 1
0036  * / (\beta n) \f$. Note that in a dispersive medium, the index of refraction
0037  * is an inreasing function of photon energy. The mean number of photons per
0038  * unit length is given by
0039  * \f[
0040    \difd{N}{x} = \frac{\alpha z^2}{\hbar c}
0041    \int_{\epsilon_\text{min}}^{\epsilon_\text{max}} \left(1 -
0042    \frac{1}{n^2\beta^2} \right) \dif\epsilon
0043    = \frac{\alpha z^2}{\hbar c}
0044    \left[\epsilon_\text{max} - \epsilon_\text{min} - \frac{1}{\beta^2}
0045    \int_{\epsilon_\text{min}}^{\epsilon_\text{max}}
0046    \frac{1}{n^2(\epsilon)}\dif\epsilon \right].
0047  * \f]
0048  */
0049 class CherenkovDndxCalculator
0050 {
0051   public:
0052     // Construct from optical materials and Cherenkov angle integrals
0053     inline CELER_FUNCTION
0054     CherenkovDndxCalculator(optical::MaterialView const& material,
0055                             NativeCRef<CherenkovData> const& shared,
0056                             units::ElementaryCharge charge);
0057 
0058     // Calculate the mean number of Cherenkov photons produced per unit length
0059     inline CELER_FUNCTION real_type operator()(units::LightSpeed beta);
0060 
0061   private:
0062     // Calculate refractive index [MeV -> unitless]
0063     NonuniformGridCalculator calc_refractive_index_;
0064 
0065     // Calculate the Cherenkov angle integral [MeV -> unitless]
0066     NonuniformGridCalculator calc_integral_;
0067 
0068     // Square of particle charge
0069     real_type zsq_;
0070 };
0071 
0072 //---------------------------------------------------------------------------//
0073 // INLINE DEFINITIONS
0074 //---------------------------------------------------------------------------//
0075 /*!
0076  * Construct from optical materials and Cherenkov angle integrals.
0077  */
0078 CELER_FUNCTION
0079 CherenkovDndxCalculator::CherenkovDndxCalculator(
0080     optical::MaterialView const& material,
0081     NativeCRef<CherenkovData> const& shared,
0082     units::ElementaryCharge charge)
0083     : calc_refractive_index_(material.make_refractive_index_calculator())
0084     , calc_integral_{shared.angle_integral[material.material_id()],
0085                      shared.reals}
0086     , zsq_(ipow<2>(charge.value()))
0087 {
0088     CELER_EXPECT(charge != zero_quantity());
0089 }
0090 
0091 //---------------------------------------------------------------------------//
0092 /*!
0093  * Calculate the mean number of Cherenkov photons produced per unit length.
0094  *
0095  * \todo define a "generic grid extents" class for finding the lower/upper x/y
0096  * coordinates on grid data. In the future we could cache these if the memory
0097  * lookups result in too much indirection.
0098  */
0099 CELER_FUNCTION real_type
0100 CherenkovDndxCalculator::operator()(units::LightSpeed beta)
0101 {
0102     CELER_EXPECT(beta.value() > 0 && beta.value() <= 1);
0103 
0104     real_type inv_beta = 1 / beta.value();
0105     real_type energy_max = calc_refractive_index_.grid().back();
0106     if (inv_beta > calc_refractive_index_(energy_max))
0107     {
0108         // Incident particle energy is below the threshold for Cherenkov
0109         // emission (i.e., beta < 1 / n_max)
0110         return 0;
0111     }
0112 
0113     // Calculate \f$ \int_{\epsilon_\text{min}}^{\epsilon_\text{max}}
0114     // \dif\epsilon \left(1 - \frac{1}{n^2\beta^2}\right) \f$
0115     real_type energy;
0116     if (inv_beta < calc_refractive_index_[0])
0117     {
0118         energy = energy_max - calc_refractive_index_.grid().front()
0119                  - calc_integral_(energy_max) * ipow<2>(inv_beta);
0120     }
0121     else
0122     {
0123         // Find the energy where the refractive index is equal to 1 / beta.
0124         // Both energy and refractive index are monotonically increasing, so
0125         // the grid and values can be swapped and the energy can be calculated
0126         // from a given index of refraction
0127         real_type energy_min = calc_refractive_index_.make_inverse()(inv_beta);
0128         energy = energy_max - energy_min
0129                  - (calc_integral_(energy_max) - calc_integral_(energy_min))
0130                        * ipow<2>(inv_beta);
0131     }
0132 
0133     // Calculate number of photons. This may be negative if the incident
0134     // particle energy is very close to (just above) the Cherenkov production
0135     // threshold
0136     return clamp_to_nonneg(zsq_
0137                            * (constants::alpha_fine_structure
0138                               / (constants::hbar_planck * constants::c_light))
0139                            * native_value_from(units::MevEnergy(energy)));
0140 }
0141 
0142 //---------------------------------------------------------------------------//
0143 }  // namespace celeritas