feat(dynamic-engine): added derivitves for energy generation rate. dε/dT and dε/dρ have been added to NetOut and computed with auto diff
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "gridfire/engine/engine_abstract.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace gridfire::diagnostics {
|
||||
void report_limiting_species(
|
||||
const DynamicEngine& engine,
|
||||
const std::vector<double>& Y_full,
|
||||
const std::vector<double>& E_full,
|
||||
const std::vector<double>& dydt_full,
|
||||
double relTol,
|
||||
double absTol,
|
||||
size_t top_n = 10
|
||||
);
|
||||
|
||||
void inspect_species_balance(
|
||||
const DynamicEngine& engine,
|
||||
const std::string& species_name,
|
||||
const std::vector<double>& Y_full,
|
||||
double T9,
|
||||
double rho
|
||||
);
|
||||
|
||||
void inspect_jacobian_stiffness(
|
||||
const DynamicEngine& engine,
|
||||
const std::vector<double>& Y_full,
|
||||
double T9,
|
||||
double rho
|
||||
);
|
||||
|
||||
}
|
||||
@@ -64,6 +64,16 @@ namespace gridfire {
|
||||
|
||||
using SparsityPattern = std::vector<std::pair<size_t, size_t>>;
|
||||
|
||||
struct EnergyDerivatives {
|
||||
double dEps_dT = 0.0; ///< Partial derivative of energy generation rate with respect to temperature.
|
||||
double dEps_dRho = 0.0;///< Partial derivative of energy generation rate with respect to density.
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const EnergyDerivatives& ed) {
|
||||
os << "<dε/dT: " << ed.dEps_dT << ", dε/dρ: " << ed.dEps_dRho << ">";
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Abstract base class for a reaction network engine.
|
||||
*
|
||||
@@ -210,6 +220,23 @@ namespace gridfire {
|
||||
double rho
|
||||
) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Calculate the derivatives of the energy generation rate with respect to T and rho.
|
||||
*
|
||||
* @param Y Vector of current abundances.
|
||||
* @param T9 Temperature in units of 10^9 K.
|
||||
* @param rho Density in g/cm^3.
|
||||
* @return EnergyDerivatives containing dEps/dT and dEps/dRho.
|
||||
*
|
||||
* This method computes the partial derivatives of the specific nuclear energy
|
||||
* generation rate with respect to temperature and density for the current state.
|
||||
*/
|
||||
[[nodiscard]] virtual EnergyDerivatives calculateEpsDerivatives(
|
||||
const std::vector<double>& Y,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the set of logical reactions in the network.
|
||||
*
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace gridfire {
|
||||
static constexpr double MIN_JACOBIAN_THRESHOLD = 1e-24;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @class GraphEngine
|
||||
* @brief A reaction network engine that uses a graph-based representation.
|
||||
@@ -143,6 +144,12 @@ namespace gridfire {
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
||||
const std::vector<double>& Y,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Generates the Jacobian matrix for the current state.
|
||||
*
|
||||
@@ -581,6 +588,7 @@ namespace gridfire {
|
||||
|
||||
mutable boost::numeric::ublas::compressed_matrix<double> m_jacobianMatrix; ///< Jacobian matrix (species x species).
|
||||
mutable CppAD::ADFun<double> m_rhsADFun; ///< CppAD function for the right-hand side of the ODE.
|
||||
mutable CppAD::ADFun<double> m_epsADFun; ///< CppAD function for the energy generation rate.
|
||||
mutable CppAD::sparse_jac_work m_jac_work; ///< Work object for sparse Jacobian calculations.
|
||||
CppAD::sparse_rc<std::vector<size_t>> m_full_jacobian_sparsity_pattern; ///< Full sparsity pattern for the Jacobian matrix.
|
||||
|
||||
@@ -652,6 +660,8 @@ namespace gridfire {
|
||||
*/
|
||||
void recordADTape() const;
|
||||
|
||||
void recordEpsADTape() const;
|
||||
|
||||
void collectAtomicReverseRateAtomicBases();
|
||||
|
||||
void precomputeNetwork();
|
||||
|
||||
@@ -107,6 +107,12 @@ namespace gridfire {
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
||||
const std::vector<double> &Y_culled,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Generates the Jacobian matrix for the active species.
|
||||
*
|
||||
|
||||
@@ -42,6 +42,13 @@ namespace gridfire{
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
||||
const std::vector<double> &Y,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Generates the Jacobian matrix for the active species.
|
||||
*
|
||||
|
||||
@@ -236,6 +236,12 @@ namespace gridfire {
|
||||
double rho
|
||||
) const override;
|
||||
|
||||
[[nodiscard]] EnergyDerivatives calculateEpsDerivatives(
|
||||
const std::vector<double> &Y,
|
||||
const double T9,
|
||||
const double rho
|
||||
) const override;
|
||||
|
||||
/**
|
||||
* @brief Generates the Jacobian matrix for the current state.
|
||||
*
|
||||
@@ -754,6 +760,10 @@ namespace gridfire {
|
||||
* @return True if the sets of species indices are not identical.
|
||||
*/
|
||||
bool operator!=(const QSEGroup& other) const;
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
std::string toString(DynamicEngine &engine) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1056,9 +1066,11 @@ namespace gridfire {
|
||||
* flux exceeds a configurable threshold, the group is considered valid and is added
|
||||
* to the returned vector.
|
||||
*/
|
||||
std::vector<QSEGroup> validateGroupsWithFluxAnalysis(
|
||||
std::pair<std::vector<MultiscalePartitioningEngineView::QSEGroup>, std::vector<MultiscalePartitioningEngineView
|
||||
::
|
||||
QSEGroup>> validateGroupsWithFluxAnalysis(
|
||||
const std::vector<QSEGroup> &candidate_groups,
|
||||
const std::vector<double>& Y,
|
||||
const std::vector<double> &Y,
|
||||
double T9,
|
||||
double rho
|
||||
) const;
|
||||
|
||||
@@ -57,16 +57,18 @@ namespace gridfire {
|
||||
double energy; ///< Energy in ergs
|
||||
double culling = 0.0; ///< Culling threshold for reactions (default is 0.0, meaning no culling)
|
||||
|
||||
std::vector<double> MolarAbundance() const;
|
||||
[[nodiscard]] std::vector<double> MolarAbundance() const;
|
||||
};
|
||||
|
||||
struct NetOut {
|
||||
fourdst::composition::Composition composition; ///< Composition of the network after evaluation
|
||||
int num_steps; ///< Number of steps taken in the evaluation
|
||||
double energy; ///< Energy in ergs after evaluation
|
||||
double dEps_dT; ///< Partial derivative of energy generation rate with respect to temperature
|
||||
double dEps_dRho; ///< Partial derivative of energy generation rate with respect to density
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const NetOut& netOut) {
|
||||
os << "NetOut(composition=" << netOut.composition << ", num_steps=" << netOut.num_steps << ", energy=" << netOut.energy << ")";
|
||||
os << "NetOut(composition=" << netOut.composition << ", num_steps=" << netOut.num_steps << ", ε=" << netOut.energy << ", dε/dT=" << netOut.dEps_dT << ", dε/dρ=" << netOut.dEps_dRho << ")";
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <memory>
|
||||
|
||||
namespace gridfire::partition {
|
||||
|
||||
/**
|
||||
* @class PartitionFunction
|
||||
* @brief Abstract interface for evaluating nuclear partition functions.
|
||||
|
||||
@@ -98,16 +98,18 @@ namespace gridfire::solver {
|
||||
DynamicEngine* engine;
|
||||
double T9;
|
||||
double rho;
|
||||
double energy;
|
||||
const std::vector<fourdst::atomic::Species>* networkSpecies;
|
||||
std::unique_ptr<exceptions::StaleEngineTrigger> captured_exception = nullptr;
|
||||
};
|
||||
|
||||
private:
|
||||
Config& m_config = Config::getInstance();
|
||||
quill::Logger* m_logger = LogManager::getInstance().getLogger("log");
|
||||
static int cvode_rhs_wrapper(sunrealtype t, N_Vector y, N_Vector ydot, void *user_data);
|
||||
static int cvode_jac_wrapper(sunrealtype t, N_Vector y, N_Vector ydot, SUNMatrix J, void *user_data, N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
|
||||
|
||||
int calculate_rhs(sunrealtype t, N_Vector y, N_Vector ydot, const CVODEUserData* data) const;
|
||||
void calculate_rhs(sunrealtype t, N_Vector y, N_Vector ydot, const CVODEUserData* data) const;
|
||||
|
||||
void initialize_cvode_integration_resources(
|
||||
uint64_t N,
|
||||
@@ -120,10 +122,13 @@ namespace gridfire::solver {
|
||||
);
|
||||
|
||||
void cleanup_cvode_resources(bool memFree);
|
||||
|
||||
void log_step_diagnostics(const CVODEUserData& user_data) const;
|
||||
private:
|
||||
SUNContext m_sun_ctx = nullptr;
|
||||
void* m_cvode_mem = nullptr;
|
||||
N_Vector m_Y = nullptr;
|
||||
N_Vector m_YErr = nullptr;
|
||||
SUNMatrix m_J = nullptr;
|
||||
SUNLinearSolver m_LS = nullptr;
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace gridfire::utils {
|
||||
/**
|
||||
@@ -62,4 +68,6 @@ namespace gridfire::utils {
|
||||
const double T9,
|
||||
const double rho
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
121
src/include/gridfire/utils/table_format.h
Normal file
121
src/include/gridfire/utils/table_format.h
Normal file
@@ -0,0 +1,121 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace gridfire::utils {
|
||||
class ColumnBase {
|
||||
public:
|
||||
virtual ~ColumnBase() = default;
|
||||
// Gets the string representation of the data at a given row
|
||||
virtual std::string getCellData(size_t rowIndex) const = 0;
|
||||
// Gets the header text for the column
|
||||
virtual std::string getHeader() const = 0;
|
||||
// Gets the number of data rows in the column
|
||||
virtual size_t getRowCount() const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Column final : public ColumnBase {
|
||||
public:
|
||||
Column(const std::string& header, const std::vector<T>& data)
|
||||
: m_header(header), m_data(data) {}
|
||||
|
||||
std::string getCellData(size_t rowIndex) const override {
|
||||
std::stringstream ss;
|
||||
if (rowIndex < m_data.size()) {
|
||||
ss << m_data[rowIndex];
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string getHeader() const override {
|
||||
return m_header;
|
||||
}
|
||||
|
||||
size_t getRowCount() const override {
|
||||
return m_data.size();
|
||||
}
|
||||
private:
|
||||
std::string m_header;
|
||||
std::vector<T> m_data;
|
||||
|
||||
};
|
||||
|
||||
inline std::string format_table(const std::string& tableName, const std::vector<std::unique_ptr<ColumnBase>>& columns) {
|
||||
// --- 1. Handle Empty Table ---
|
||||
if (columns.empty()) {
|
||||
return tableName + "\n(Table has no columns)\n";
|
||||
}
|
||||
|
||||
// --- 2. Determine dimensions and calculate column widths ---
|
||||
size_t num_cols = columns.size();
|
||||
size_t num_rows = 0;
|
||||
for(const auto& col : columns) {
|
||||
num_rows = std::max(num_rows, col->getRowCount());
|
||||
}
|
||||
|
||||
std::vector<size_t> col_widths(num_cols);
|
||||
for (size_t j = 0; j < num_cols; ++j) {
|
||||
col_widths[j] = columns[j]->getHeader().length();
|
||||
for (size_t i = 0; i < num_rows; ++i) {
|
||||
col_widths[j] = std::max(col_widths[j], columns[j]->getCellData(i).length());
|
||||
}
|
||||
}
|
||||
|
||||
// --- 3. Build the table string using stringstream ---
|
||||
std::stringstream table_ss;
|
||||
|
||||
// --- Table Title ---
|
||||
size_t total_width = std::accumulate(col_widths.begin(), col_widths.end(), 0) + (num_cols * 3) + 1;
|
||||
size_t title_padding = (total_width > tableName.length()) ? (total_width - tableName.length()) / 2 : 0;
|
||||
table_ss << std::string(title_padding, ' ') << tableName << "\n";
|
||||
|
||||
// --- Helper to draw horizontal border ---
|
||||
auto draw_border = [&]() {
|
||||
table_ss << "+";
|
||||
for (size_t width : col_widths) {
|
||||
table_ss << std::string(width + 2, '-'); // +2 for padding
|
||||
table_ss << "+";
|
||||
}
|
||||
table_ss << "\n";
|
||||
};
|
||||
|
||||
// --- Draw Top Border ---
|
||||
draw_border();
|
||||
|
||||
// --- Draw Header Row ---
|
||||
table_ss << "|";
|
||||
for (size_t j = 0; j < num_cols; ++j) {
|
||||
table_ss << " " << std::left << std::setw(col_widths[j]) << columns[j]->getHeader() << " |";
|
||||
}
|
||||
table_ss << "\n";
|
||||
|
||||
// --- Draw Separator ---
|
||||
draw_border();
|
||||
|
||||
// --- Draw Data Rows ---
|
||||
for (size_t i = 0; i < num_rows; ++i) {
|
||||
table_ss << "|";
|
||||
for (size_t j = 0; j < num_cols; ++j) {
|
||||
table_ss << " " << std::left << std::setw(col_widths[j]) << columns[j]->getCellData(i) << " |";
|
||||
}
|
||||
table_ss << "\n";
|
||||
}
|
||||
|
||||
// --- Draw Bottom Border ---
|
||||
draw_border();
|
||||
|
||||
return table_ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user