![]() |
|
|||
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
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |