Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:19:07

0001 // TRENTO: Reduced Thickness Event-by-event Nuclear Topology
0002 // Copyright 2015 Jonah E. Bernhard, J. Scott Moreland
0003 // MIT License
0004 
0005 #include "../src/event.h"
0006 
0007 #include "catch.hpp"
0008 #include "util.h"
0009 
0010 #include "../src/nucleus.h"
0011 #include "../src/random.h"
0012 
0013 using namespace trento;
0014 
0015 TEST_CASE( "event" ) {
0016   // Check Event class results against equivalent (but slower) methods.
0017 
0018   // Repeat for p == 0, p < 0, p > 0.
0019   auto pplus = .5 + .49*random::canonical<>();
0020   auto pminus = -.5 + .49*random::canonical<>();
0021   for (auto p : {0., pplus, pminus }) {
0022     // Random physical params.
0023     auto norm = 1. + .5*random::canonical<>();
0024     auto xsec = 4. + 3.*random::canonical<>();
0025     auto nucleon_width = .5 + .2*random::canonical<>();
0026 
0027     // Effectively disable fluctuations to deterministically compute thickness.
0028     auto fluct = 1e12;
0029 
0030     // Coarse-ish grid.
0031     auto grid_max = 9.;
0032     auto grid_step = 0.3;
0033     auto grid_nsteps = 60;
0034 
0035     auto var_map = make_var_map({
0036         {"normalization", norm},
0037         {"reduced-thickness", p},
0038         {"grid-max", grid_max},
0039         {"grid-step", grid_step},
0040         {"fluctuation",   fluct},
0041         {"cross-section", xsec},
0042         {"nucleon-width", nucleon_width},
0043     });
0044 
0045     Event event{var_map};
0046     NucleonProfile profile{var_map};
0047 
0048     CHECK( event.reduced_thickness_grid().num_dimensions() == 2 );
0049     CHECK( static_cast<int>(event.reduced_thickness_grid().shape()[0]) == grid_nsteps );
0050     CHECK( static_cast<int>(event.reduced_thickness_grid().shape()[1]) == grid_nsteps );
0051 
0052     auto nucleusA = Nucleus::create("Pb");
0053     auto nucleusB = Nucleus::create("Pb");
0054 
0055     // Sample impact param, nucleons, and participants.
0056     auto b = 4.*std::sqrt(random::canonical<>());
0057     nucleusA->sample_nucleons(+.5*b);
0058     nucleusB->sample_nucleons(-.5*b);
0059 
0060     for (auto&& A : *nucleusA)
0061       for (auto&& B : *nucleusB)
0062         profile.participate(A, B);
0063 
0064     // Run a normal Event.
0065     event.compute(*nucleusA, *nucleusB, profile);
0066 
0067     // Verify npart.
0068     auto count_part = [](const Nucleus& nucleus) {
0069       auto npart = 0;
0070       for (const auto& n : nucleus)
0071         if (n.is_participant())
0072           ++npart;
0073       return npart;
0074     };
0075     auto npart = count_part(*nucleusA) + count_part(*nucleusB);
0076     CHECK( npart == event.npart() );
0077 
0078     // Compute TR grid the slow way -- switch the order of grid and nucleon loops.
0079     boost::multi_array<double, 2> TR{boost::extents[grid_nsteps][grid_nsteps]};
0080 
0081     auto thickness = [&profile](const Nucleus& nucleus, double x, double y) {
0082       auto t = 0.;
0083       for (const auto& n : nucleus) {
0084         if (n.is_participant()) {
0085           auto dx = n.x() - x;
0086           auto dy = n.y() - y;
0087           t += profile.thickness(dx*dx + dy*dy);
0088         }
0089       }
0090       return t;
0091     };
0092 
0093     auto gen_mean = [p](double a, double b) {
0094       if (std::abs(p) < 1e-12)
0095         return std::sqrt(a*b);
0096       else if (p < 0. && (a < 1e-12 || b < 1e-12))
0097         return 0.;
0098       else
0099         return std::pow(.5*(std::pow(a, p) + std::pow(b, p)), 1./p);
0100     };
0101 
0102     for (auto iy = 0; iy < grid_nsteps; ++iy) {
0103       for (auto ix = 0; ix < grid_nsteps; ++ix) {
0104         auto x = (ix + .5) * 2 * grid_max/grid_nsteps - grid_max;
0105         auto y = (iy + .5) * 2 * grid_max/grid_nsteps - grid_max;
0106         auto TA = thickness(*nucleusA, x, y);
0107         auto TB = thickness(*nucleusB, x, y);
0108         TR[iy][ix] = norm * gen_mean(TA, TB);
0109       }
0110     }
0111 
0112     // Verify multiplicity.
0113     auto mult = std::pow(2*grid_max/grid_nsteps, 2) *
0114       std::accumulate(TR.origin(), TR.origin() + TR.num_elements(), 0.);
0115     CHECK( mult == Approx(event.multiplicity()) );
0116 
0117     // Verify each grid element.
0118     auto all_correct = true;
0119     for (const auto* t1 = TR.origin(),
0120          * t2 = event.reduced_thickness_grid().origin();
0121          t1 != TR.origin() + TR.num_elements();
0122          ++t1, ++t2) {
0123       if (*t1 != Approx(*t2).epsilon(1e-5)) {
0124         all_correct = false;
0125         WARN( "TR mismatch: " << *t1 << " != " << *t2 );
0126         break;
0127       }
0128     }
0129     CHECK( all_correct );
0130 
0131     // Verify eccentricity.
0132     auto sum = 0., xcm = 0., ycm = 0.;
0133     for (auto iy = 0; iy < grid_nsteps; ++iy) {
0134       for (auto ix = 0; ix < grid_nsteps; ++ix) {
0135         auto& t = TR[iy][ix];
0136         sum += t;
0137         xcm += t*ix;
0138         ycm += t*iy;
0139       }
0140     }
0141     xcm /= sum;
0142     ycm /= sum;
0143 
0144     for (auto n = 2; n <= 5; ++n) {
0145       auto real = 0., imag = 0., weight = 0.;
0146       for (auto iy = 0; iy < grid_nsteps; ++iy) {
0147         for (auto ix = 0; ix < grid_nsteps; ++ix) {
0148           auto x = ix - xcm;
0149           auto y = iy - ycm;
0150           auto w = TR[iy][ix] * std::pow(x*x + y*y, .5*n);
0151           // compute exp(i*n*phi) the naive way
0152           auto phi = std::atan2(y, x);
0153           real += w*std::cos(n*phi);
0154           imag += w*std::sin(n*phi);
0155           weight += w;
0156         }
0157       }
0158       auto ecc = std::sqrt(real*real + imag*imag) / weight;
0159       CHECK( ecc == Approx(event.eccentricity().at(n)).epsilon(1e-6).margin(1e-6) );
0160     }
0161   }
0162 
0163   // test grid size when step size does not evenly divide width
0164   auto var_map = make_var_map({
0165       {"normalization", 1.},
0166       {"reduced-thickness", 0.},
0167       {"grid-max", 10.},
0168       {"grid-step", 0.3}
0169   });
0170 
0171   Event event{var_map};
0172 
0173   CHECK( event.reduced_thickness_grid().num_dimensions() == 2 );
0174   CHECK( event.reduced_thickness_grid().shape()[0] == 67 );
0175   CHECK( event.reduced_thickness_grid().shape()[1] == 67 );
0176 }