GridFire 0.0.1a
General Purpose Nuclear Network
Loading...
Searching...
No Matches
partition_rauscher_thielemann.cpp
Go to the documentation of this file.
4
5#include "fourdst/logging/logging.h"
6#include "quill/LogMacros.h"
7
8#include <stdexcept>
9#include <algorithm>
10#include <vector>
11#include <array>
12#include <iostream>
13
14namespace gridfire::partition {
15 static constexpr std::array<double, 24> RT_TEMPERATURE_GRID_T9 = {
16 0.01, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.5,
17 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0
18 };
19
22 m_partitionData.reserve(numRecords);
23 const auto* records = reinterpret_cast<const record::RauscherThielemannPartitionDataRecord*>(rauscher_thielemann_partition_data);
24 for (size_t i = 0; i < numRecords; ++i) {
25 const auto&[z, a, ground_state_spin, normalized_g_values] = records[i];
26 IsotopeData data;
27 data.ground_state_spin = ground_state_spin;
28 std::ranges::copy(normalized_g_values, data.normalized_g_values.begin());
29 const int key = make_key(z, a);
30 LOG_TRACE_L3_LIMIT_EVERY_N(
31 100,
33 "(EVERY 100) Adding Rauscher-Thielemann partition data for Z={} A={} (key={})",
34 z,
35 a,
36 key
37 );
38
39 m_partitionData[key] = std::move(data);
40 }
41 }
42
44 const int z,
45 const int a,
46 const double T9
47 ) const {
48 LOG_TRACE_L2(m_logger, "Evaluating Rauscher-Thielemann partition function for Z={} A={} T9={}", z, a, T9);
49
50 const auto [bound, data, upperIndex, lowerIndex] = find(z, a, T9);
51
52 switch (bound) {
53 case FRONT: {
54 LOG_TRACE_L2(m_logger, "Using FRONT bound for Z={} A={} T9={}", z, a, T9);
55 return data.normalized_g_values.front() * (2.0 * data.ground_state_spin + 1.0);
56 }
57 case BACK: {
58 LOG_TRACE_L2(m_logger, "Using BACK bound for Z={} A={} T9={}", z, a, T9);
59 return data.normalized_g_values.back() * (2.0 * data.ground_state_spin + 1.0);
60 }
61 case MIDDLE: {
62 LOG_TRACE_L2(m_logger, "Using MIDDLE bound for Z={} A={} T9={}", z, a, T9);
63 }
64 }
65
66 const auto [T9_high, G_norm_high, T9_low, G_norm_low] = get_interpolation_points(
67 upperIndex,
68 lowerIndex,
69 data.normalized_g_values
70 );
71
72 const double frac = (T9 - T9_low) / (T9_high - T9_low);
73 const double interpolated_g_norm = G_norm_low + frac * (G_norm_high - G_norm_low);
74
75 return interpolated_g_norm * (2.0 * data.ground_state_spin + 1.0);
76 }
77
79 const int z,
80 const int a,
81 const double T9
82 ) const {
83 LOG_TRACE_L2(m_logger, "Evaluating derivative of Rauscher-Thielemann partition function for Z={} A={} T9={}", z, a, T9);
84 const auto [bound, data, upperIndex, lowerIndex] = find(z, a, T9);
85 if (bound == FRONT || bound == BACK) {
86 LOG_TRACE_L2(m_logger, "Derivative is zero for Z={} A={} T9={} (bound: {})", z, a, T9, bound == FRONT ? "FRONT" : "BACK");
87 return 0.0; // Derivative is zero at the boundaries
88 }
89 const auto [T9_high, G_norm_high, T9_low, G_norm_low] = get_interpolation_points(
90 upperIndex,
91 lowerIndex,
92 data.normalized_g_values
93 );
94 const double slope_g_norm = (G_norm_high - G_norm_low) / (T9_high - T9_low);
95 return slope_g_norm * (2.0 * data.ground_state_spin + 1.0);
96 }
97
99 const int z,
100 const int a
101 ) const {
102 return m_partitionData.contains(make_key(z, a));
103 }
104
106 const size_t upper_index,
107 const size_t lower_index,
108 const std::array<double, 24>& normalized_g_values
109 ) {
110 const double T_high = RT_TEMPERATURE_GRID_T9[upper_index];
111 const double G_norm_high = normalized_g_values[upper_index];
112 const double T_low = RT_TEMPERATURE_GRID_T9[lower_index];
113 const double G_norm_low = normalized_g_values[lower_index];
114 return {T_high, G_norm_high, T_low, G_norm_low};
115 }
116
118 const int z,
119 const int a,
120 const double T9
121 ) const {
122 const auto key = make_key(z, a);
123 const auto it = m_partitionData.find(key);
124
125 if (it == m_partitionData.end()) {
126 LOG_ERROR(m_logger, "Rauscher-Thielemann partition function data for Z={} A={} not found.", z, a);
127 throw std::out_of_range("Partition function data not found for Z=" + std::to_string(z) + " A=" + std::to_string(a));
128 }
129
130 const IsotopeData& data = it->second;
131 const auto upper_it = std::ranges::lower_bound(RT_TEMPERATURE_GRID_T9, T9);
132 Bounds bound;
133 if (upper_it == RT_TEMPERATURE_GRID_T9.begin()) {
134 bound = FRONT; // T9 is below the first grid point
135 } else if (upper_it == RT_TEMPERATURE_GRID_T9.end()) {
136 bound = BACK; // T9 is above the last grid point
137 } else {
138 bound = MIDDLE; // T9 is within the grid
139 }
140 const size_t upper_index = std::distance(RT_TEMPERATURE_GRID_T9.begin(), upper_it);
141 const size_t lower_index = upper_index - 1;
142 return {bound, data, upper_index, lower_index};
143 }
144
146 const int z,
147 const int a
148 ) {
149 return z * 1000 + a; // Simple key generation for Z and A
150 }
151}
IdentifiedIsotope find(int z, int a, double T9) const
Identify isotope entry and grid indices for given T9.
static InterpolationPoints get_interpolation_points(const size_t upper_index, const size_t lower_index, const std::array< double, 24 > &normalized_g_values)
Get interpolation points from normalized G array.
std::unordered_map< int, IsotopeData > m_partitionData
Map of isotope key to data.
bool supports(int z, int a) const override
Check if partition data exists for given isotope.
double evaluateDerivative(int z, int a, double T9) const override
Evaluate temperature derivative of partition function.
static constexpr int make_key(int z, int a)
Generate integer key for isotope (z,a).
RauscherThielemannPartitionFunction()
Construct and populate partition data.
double evaluate(int z, int a, double T9) const override
Evaluate partition function for isotope at temperature.
static constexpr std::array< double, 24 > RT_TEMPERATURE_GRID_T9
const size_t rauscher_thielemann_partition_data_len
const unsigned char rauscher_thielemann_partition_data[]
std::array< double, 24 > normalized_g_values
Normalized G values on RT grid.
Packed binary record of Rauscher-Thielemann partition function data for an isotope.