File indexing completed on 2025-08-05 08:19:07
0001
0002
0003
0004
0005 #include "../src/nucleon.h"
0006
0007 #include <cmath>
0008
0009 #include "catch.hpp"
0010 #include "util.h"
0011
0012 #include "../src/nucleus.h"
0013 #include "../src/random.h"
0014
0015 using namespace trento;
0016
0017 TEST_CASE( "nucleon" ) {
0018 auto fluct = 1. + .5*random::canonical<>();
0019 auto xsec = 4. + 3.*random::canonical<>();
0020 auto width = .5 + .2*random::canonical<>();
0021 auto wsq = width*width;
0022
0023 auto var_map = make_var_map({
0024 {"fluctuation", fluct},
0025 {"cross-section", xsec},
0026 {"nucleon-width", width},
0027 });
0028
0029 NucleonProfile profile{var_map};
0030 profile.fluctuate();
0031
0032
0033 auto R = profile.radius();
0034 CHECK( R == Approx(5*width) );
0035
0036
0037
0038 auto tzero = profile.thickness(0.);
0039 CHECK( profile.thickness(wsq) == Approx(tzero*std::exp(-.5)) );
0040
0041
0042 auto dsq = std::pow(R*random::canonical<>(), 2);
0043 CHECK( profile.thickness(dsq) == Approx(tzero*std::exp(-.5*dsq/wsq)).epsilon(1e-5).margin(1e-5) );
0044
0045
0046 dsq = std::pow(R*(1+random::canonical<>()), 2);
0047 CHECK( profile.thickness(dsq) == 0. );
0048
0049
0050
0051 auto total = 0.;
0052 auto n = 1e6;
0053 for (auto i = 0; i < static_cast<int>(n); ++i) {
0054 profile.fluctuate();
0055 total += profile.thickness(0.) * (2*M_PI*wsq);
0056 }
0057
0058 auto mean = total/n;
0059 CHECK( mean == Approx(1.).epsilon(.003) );
0060
0061
0062
0063
0064 Proton A{}, B{};
0065 A.sample_nucleons(0.);
0066 B.sample_nucleons(0.);
0067 auto& nA = *A.begin();
0068 auto& nB = *B.begin();
0069 CHECK( nA.x() == 0. );
0070 CHECK( nA.y() == 0. );
0071 CHECK( nA.z() == 0. );
0072 CHECK( !nA.is_participant() );
0073
0074
0075 while (!profile.participate(nA, nB)) {}
0076 CHECK( nA.is_participant() );
0077 CHECK( nB.is_participant() );
0078
0079
0080 A.sample_nucleons(0.);
0081 CHECK( !nA.is_participant() );
0082
0083
0084
0085 auto bmax = profile.max_impact();
0086 CHECK( bmax == Approx(6*width) );
0087
0088 auto nev = 1e6;
0089 auto count = 0;
0090 for (auto i = 0; i < static_cast<int>(nev); ++i) {
0091 auto b = bmax * std::sqrt(random::canonical<>());
0092 A.sample_nucleons(.5*b);
0093 B.sample_nucleons(-.5*b);
0094 if (profile.participate(nA, nB))
0095 ++count;
0096 }
0097
0098 auto xsec_mc = M_PI*bmax*bmax * static_cast<double>(count)/nev;
0099
0100
0101 CHECK( xsec_mc == Approx(xsec).epsilon(.02) );
0102
0103
0104 auto b = bmax + random::canonical<>();
0105 A.sample_nucleons(.5*b);
0106 B.sample_nucleons(-.5*b);
0107 CHECK( !profile.participate(nA, nB) );
0108
0109
0110 auto no_fluct_var_map = make_var_map({
0111 {"fluctuation", 1e12},
0112 {"cross-section", xsec},
0113 {"nucleon-width", width},
0114 });
0115
0116 NucleonProfile no_fluct_profile{no_fluct_var_map};
0117 no_fluct_profile.fluctuate();
0118 CHECK( no_fluct_profile.thickness(0) == Approx(1/(2*M_PI*wsq)) );
0119
0120 CHECK_THROWS_AS([]() {
0121
0122 auto bad_var_map = make_var_map({
0123 {"fluctuation", 1.},
0124 {"cross-section", 5.},
0125 {"nucleon-width", .1},
0126 });
0127 NucleonProfile bad_profile{bad_var_map};
0128 }(),
0129 std::domain_error);
0130 }