35#include "gtest/gtest.h"
40 double integrateSpectrumCompositeSimpson(
41 double incomingPhotonEnergyERFGeV,
double minEnergy,
double maxEnergy,
int panels) {
42 const double h = (maxEnergy - minEnergy) / panels;
44 incomingPhotonEnergyERFGeV, minEnergy)
46 incomingPhotonEnergyERFGeV, maxEnergy);
48 for (
int i = 1; i < panels; ++i) {
49 const double energy = minEnergy + i * h;
50 const double weight = (i % 2 == 0) ? 2.0 : 4.0;
53 incomingPhotonEnergyERFGeV, energy);
60TEST(TestLinearCompton, ThomsonLimitRecoveredAtLowEnergy) {
61 const double incomingPhotonEnergyERFGeV = 1.0e-9;
65 EXPECT_NEAR(sigmaKN / sigmaThomson, 1.0, 1.0e-5);
68TEST(TestLinearCompton, EnergySupportMatchesComptonEndpoints) {
69 const double incomingPhotonEnergyERFGeV = 2.5e-4;
70 const double minEnergy =
72 const double maxEnergy =
75 EXPECT_DOUBLE_EQ(maxEnergy, incomingPhotonEnergyERFGeV);
82 EXPECT_LT(minEnergy, maxEnergy);
85TEST(TestLinearCompton, DifferentialSpectrumIntegratesToTotalCrossSection) {
86 const double incomingPhotonEnergyERFGeV = 2.0e-4;
87 const double minEnergy =
89 const double maxEnergy =
91 const double integral = integrateSpectrumCompositeSimpson(
92 incomingPhotonEnergyERFGeV, minEnergy, maxEnergy, 20000);
95 EXPECT_NEAR(integral, sigmaKN, sigmaKN * 2.0e-6);
98TEST(TestLinearCompton, NinetyDegreeLabForwardBenchmarkMatchesExactFormula) {
99 const double electronTotalEnergyGeV = 1.0;
100 const double wavelength_m = 1.03e-6;
101 const double laserPhotonEnergyGeV =
105 beamDirection(2) = 1.0;
107 laserDirection(0) = 1.0;
109 const double electronMomentumGeV = std::sqrt(
111 const double expectedInvariantX =
113 const double stableEnergyMinusMomentum =
115 const double expectedForwardPhotonEnergyGeV =
116 laserPhotonEnergyGeV * electronTotalEnergyGeV
117 / (stableEnergyMinusMomentum + laserPhotonEnergyGeV);
121 electronTotalEnergyGeV, laserPhotonEnergyGeV, beamDirection, laserDirection),
122 expectedInvariantX, expectedInvariantX * 1.0e-12);
125 electronTotalEnergyGeV, laserPhotonEnergyGeV, beamDirection, laserDirection),
126 expectedForwardPhotonEnergyGeV, expectedForwardPhotonEnergyGeV * 1.0e-12);
129TEST(TestLinearCompton, ExplicitLabPhotonEnergyMatchesForwardHelper) {
130 const double electronTotalEnergyGeV = 1.0;
131 const double wavelength_m = 1.03e-6;
132 const double laserPhotonEnergyGeV =
136 beamDirection(2) = 1.0;
138 laserDirection(0) = 1.0;
140 const double scatteringCosine =
142 electronTotalEnergyGeV, beamDirection, laserDirection);
146 electronTotalEnergyGeV, laserPhotonEnergyGeV, beamDirection, laserDirection,
147 scatteringCosine, 0.0),
149 electronTotalEnergyGeV, laserPhotonEnergyGeV, beamDirection, laserDirection),
153TEST(TestLinearCompton, SampledEventsRespectKinematicBounds) {
157 const double electronTotalEnergyGeV = 1.0;
158 const double wavelength_m = 1.03e-6;
159 const double laserPhotonEnergyGeV =
163 beamDirection(2) = 1.0;
165 laserDirection(0) = 1.0;
168 electronTotalEnergyGeV, laserPhotonEnergyGeV, beamDirection, laserDirection);
173 kernel.incomingPhotonEnergyERFGeV);
175 kernel.incomingPhotonEnergyERFGeV);
176 const double directionNorm =
177 std::sqrt(
dot(event.scatteredPhotonDirectionLab, event.scatteredPhotonDirectionLab));
179 EXPECT_GE(event.scatteringCosineERF, -1.0);
180 EXPECT_LE(event.scatteringCosineERF, 1.0);
181 EXPECT_GE(event.azimuthERF, 0.0);
183 EXPECT_GE(event.scatteredPhotonEnergyERFGeV, minERF);
184 EXPECT_LE(event.scatteredPhotonEnergyERFGeV, maxERF);
185 EXPECT_GT(event.scatteredPhotonEnergyLabGeV, 0.0);
186 EXPECT_NEAR(directionNorm, 1.0, 1.0e-12);
191TEST(TestLinearCompton, FixedSeedProducesDeterministicSampleSequence) {
195 const double electronTotalEnergyGeV = 1.0;
196 const double wavelength_m = 1.03e-6;
197 const double laserPhotonEnergyGeV =
201 beamDirection(2) = 1.0;
203 laserDirection(0) = 1.0;
206 electronTotalEnergyGeV, laserPhotonEnergyGeV, beamDirection, laserDirection);
210 for (
int i = 0; i < 8; ++i) {
213 EXPECT_DOUBLE_EQ(event1.scatteringCosineERF, event2.scatteringCosineERF);
214 EXPECT_DOUBLE_EQ(event1.azimuthERF, event2.azimuthERF);
215 EXPECT_DOUBLE_EQ(event1.scatteredPhotonEnergyERFGeV, event2.scatteredPhotonEnergyERFGeV);
216 EXPECT_DOUBLE_EQ(event1.scatteredPhotonEnergyLabGeV, event2.scatteredPhotonEnergyLabGeV);
217 for (
int axis = 0; axis < 3; ++axis) {
219 event1.scatteredPhotonDirectionLab(axis),
220 event2.scatteredPhotonDirectionLab(axis));
ippl::Vector< T, Dim > Vector_t
TEST(TestLinearCompton, ThomsonLimitRecoveredAtLowEnergy)
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
int seed
The current random seed.
double differentialCrossSectionOmegaERF(double incomingPhotonEnergyERFGeV, double scatteredPhotonEnergyERFGeV)
Unpolarized Klein-Nishina differential cross section in the scattered-photon energy.
double restFrameScatteringCosineForLabForwardPhoton(double electronTotalEnergyGeV, const Vector_t< double, 3 > &beamDirection, const Vector_t< double, 3 > &laserDirection)
Rest-frame scattering cosine corresponding to a lab-forward photon.
SamplingKernel makeSamplingKernel(double electronTotalEnergyGeV, double laserPhotonEnergyGeV, const Vector_t< double, 3 > &beamDirection, const Vector_t< double, 3 > &laserDirection)
Build a cached sampling kernel for repeated event generation.
double labForwardPhotonEnergyGeV(double electronTotalEnergyGeV, double laserPhotonEnergyGeV, const Vector_t< double, 3 > &beamDirection, const Vector_t< double, 3 > &laserDirection)
Forward scattered photon energy in the laboratory frame.
double totalCrossSection(double incomingPhotonEnergyERFGeV)
Total unpolarized Klein-Nishina cross section.
std::mt19937_64 makeHostRandomEngine(std::uint64_t streamIndex)
Create a deterministic host-side random engine for Monte Carlo validation.
SampledEvent sampleEvent(const SamplingKernel &kernel, std::mt19937_64 &engine)
Sample one unpolarized linear-Compton event on the host.
double invariantX(double incomingPhotonEnergyERFGeV)
Compute CAIN's linear-Compton invariant .
double labPhotonEnergyGeV(double electronTotalEnergyGeV, double laserPhotonEnergyGeV, const Vector_t< double, 3 > &beamDirection, const Vector_t< double, 3 > &laserDirection, double scatteringCosineERF, double azimuthERF)
Laboratory-frame photon energy from electron-rest-frame scattering angles.
double thomsonCrossSection()
Thomson limit cross section.
double scatteredPhotonEnergyMaxERFGeV(double incomingPhotonEnergyERFGeV)
Maximum scattered photon energy in the electron rest frame.
double scatteredPhotonEnergyERFGeV(double incomingPhotonEnergyERFGeV, double scatteringCosineERF)
Compute the scattered photon energy in the electron rest frame.
double photonEnergyFromWavelengthGeV(double wavelength_m)
Convert a laser wavelength to a single-photon energy.
double scatteredPhotonEnergyMinERFGeV(double incomingPhotonEnergyERFGeV)
Minimum scattered photon energy in the electron rest frame.
constexpr double two_pi
The value of.
constexpr double m_e
The electron rest mass in GeV.