Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:31:27

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