fix(LogicalReaclibReaction): Properly class reverse reactions

Previously there was a bug where some reverse reactions were being
classed as forward reactions. This results in a failure of many
timesteps due to the reverse reactions very high molar flows
This commit is contained in:
2025-11-24 14:57:14 -05:00
parent ce8717b248
commit b335bf7100
5 changed files with 239 additions and 88 deletions

View File

@@ -643,15 +643,6 @@ namespace gridfire::engine {
std::set<fourdst::atomic::Species> seed_species; ///< Dynamic species in this group.
double mean_timescale; ///< Mean timescale of the group.
// DEBUG METHODS.
// THESE SHOULD NOT BE USED IN PRODUCTION CODE.
[[deprecated("Use for debug only")]] void removeSpecies(const fourdst::atomic::Species& species);
[[deprecated("Use for debug only")]] void addSpeciesToAlgebraic(const fourdst::atomic::Species& species);
[[deprecated("Use for debug only")]] void addSpeciesToSeed(const fourdst::atomic::Species& species);
/**
* @brief Less-than operator for QSEGroup, used for sorting.
* @param other The other QSEGroup to compare to.
@@ -739,6 +730,8 @@ namespace gridfire::engine {
const std::unordered_map<fourdst::atomic::Species, size_t>& qse_solve_species_index_map;
const std::vector<fourdst::atomic::Species>& qse_solve_species;
const QSESolver& instance;
std::vector<double> row_scaling_factors;
const double initial_group_mass;
};
private:
@@ -943,6 +936,9 @@ namespace gridfire::engine {
* @brief Builds a connectivity graph from a species pool.
*
* @param species_pool A vector of species indices representing a species pool.
* @param comp
* @param T9
* @param rho
* @return An unordered map representing the adjacency list of the connectivity graph.
*
* @par Purpose
@@ -955,7 +951,8 @@ namespace gridfire::engine {
* that reaction that are also in the pool.
*/
std::unordered_map<fourdst::atomic::Species, std::vector<fourdst::atomic::Species>> buildConnectivityGraph(
const std::vector<fourdst::atomic::Species>& species_pool
const std::vector<fourdst::atomic::Species>& species_pool, const fourdst::composition::Composition &comp, double T9, double
rho
) const;
/**
@@ -989,6 +986,9 @@ namespace gridfire::engine {
*
* @param timescale_pools A vector of vectors of species indices, where each inner vector
* represents a timescale pool.
* @param comp
* @param T9
* @param rho
* @return A vector of vectors of species indices, where each inner vector represents a
* single connected component.
*
@@ -1002,7 +1002,8 @@ namespace gridfire::engine {
* The resulting components from all pools are collected and returned.
*/
std::vector<std::vector<fourdst::atomic::Species>> analyzeTimescalePoolConnectivity(
const std::vector<std::vector<fourdst::atomic::Species>> &timescale_pools
const std::vector<std::vector<fourdst::atomic::Species>> &timescale_pools, const fourdst::composition::Composition &
comp, double T9, double rho
) const;
std::vector<QSEGroup> pruneValidatedGroups(
@@ -1012,6 +1013,11 @@ namespace gridfire::engine {
double T9,
double rho
) const;
static std::vector<QSEGroup> merge_coupled_groups(
const std::vector<QSEGroup> &groups,
const std::vector<reaction::ReactionSet> &groupReactions
);
};
}

View File

@@ -46,20 +46,28 @@ namespace gridfire::utils {
};
static inline std::unordered_map<int, std::string> kinsol_ret_code_map {
{0, "KIN_SUCCESS: The solver succeeded."},
{1, "KIN_STEP_LT_STPTOL: The solver step size became less than the stopping tolerance."},
{2, "KIN_RES_REPTD_ERR: The residual function repeatedly failed recoverably."},
{-1, "KIN_MEM_NULL: The KINSOL memory structure is NULL."},
{-2, "KIN_ILL_INPUT: An illegal input was detected."},
{1, "KIN_INITIAL_GUESS_OKAY: The guess, u=u0, satisfied the system F(u) = 0 within the tolerances specified"},
{2, "KIN_STEP_LT_STPTOL: KINSOL stopped based on scaled step length. This means that the current iterate may be an approximate solution of the given nonlinear system, but it is also quite possible that the algorithm is “stalled” (making insufficient progress) near an invalid solution, or that the scalar, scsteptol, is too large."},
{99, "KIN_WARNING: KINSOL succeeded but in an unusual way"},
{-1, "KIN_MEM_NULL: The KINSOL memory pointer is NULL."},
{-2, "KIN_ILL_INPUT: An illegal value was specified for an input argument."},
{-3, "KIN_NO_MALLOC: The KINSOL memory structure has not been allocated."},
{-4, "KIN_MEM_FAIL: Memory allocation failed."},
{-5, "KIN_LINIT_FAIL: The linear solver's initialization function failed."},
{-6, "KIN_LSETUP_FAIL: The linear solver's setup function failed."},
{-7, "KIN_LSOLVE_FAIL: The linear solver's solve function failed."},
{-8, "KIN_RESFUNC_FAIL: The residual function failed in an unrecoverable manner."},
{-9, "KIN_CONSTR_FAIL: The inequality constraint was violated and the solver was unable to recover."},
{-10, "KIN_NLS_INIT_FAIL: The nonlinear solver's initialization function failed."},
{-11, "KIN_NLS_SETUP_FAIL: The nonlinear solver's setup function failed."},
{-12, "KIN_NLS_FAIL: The nonlinear solver's solve function failed."}
{-4, "KIN_MEM_FAIL: A memory allocation failed."},
{-5, "KIN_LINESEARCH_NONCONV: The line search algorithm was unable to find an iterate sufficiently distinct from the current iterate."},
{-6, "KIN_MAXITER_REACHED: The maximum number of iterations was reached before convergence."},
{-7, "KIN_MXNEWT_5X_EXCEEDED: Five consecutive steps have been taken that satisfy a scaled step length test."},
{-8, "KIN_LINESEARCH_BCFAIL: The line search algorithm was unable to satisfy the beta-condition for nbcf fails iterations."},
{-9, "KIN_LINSOLV_NO_RECOVERY: The linear solver's solve function failed recoverably, but the Jacobian data is already current."},
{-10, "KIN_LINIT_FAIL: The linear solver's init routine failed."},
{-11, "KIN_LSETUP_FAIL: The linear solver's setup function failed in an unrecoverable manner."},
{-12, "KIN_LSOLVE_FAIL: The linear solver's solve function failed in an unrecoverable manner."},
{-13, "KIN_SYSFUNC_FAIL: The system function failed in an unrecoverable manner."},
{-14, "KIN_FIRST_SYSFUNC_ERR: The system function failed at the first call."},
{-15, "KIN_REPTD_SYSFUNC_ERR: Unable to correct repeated recoverable system function errors."},
{-16, "KIN_VECTOROP_ERR: A vector operation failed."},
{-17, "KIN_CONTEXT_ERR: A context error occurred."},
{-18, "KIN_DAMPING_FN_ERR: The damping function failed."},
{-19, "KIN_DEPTH_FN_ERR: The depth function failed."}
};
inline const std::unordered_map<int, std::string>& sundials_retcode_map(const SUNDIALS_RET_CODE_TYPES type) {
@@ -96,4 +104,27 @@ namespace gridfire::utils {
return vec;
}
inline void check_sundials_flag(const int flag, const std::string& func_name, const SUNDIALS_RET_CODE_TYPES type) {
if (flag < 0) {
const auto& ret_code_map = sundials_retcode_map(type);
if (!ret_code_map.contains(flag)) {
switch (type) {
case (SUNDIALS_RET_CODE_TYPES::CVODE):
throw exceptions::CVODESolverFailureError("CVODE error in " + func_name + ": Unknown error code: " + std::to_string(flag));
case (SUNDIALS_RET_CODE_TYPES::KINSOL):
throw exceptions::KINSolSolverFailureError("KINSol error in " + func_name + ": Unknown error code: " + std::to_string(flag));
default:
throw exceptions::CVODESolverFailureError("SUNDIALS error in " + func_name + ": Unknown error code: " + std::to_string(flag));
}
}
switch (type) {
case (SUNDIALS_RET_CODE_TYPES::CVODE):
throw exceptions::CVODESolverFailureError("CVODE error in " + func_name + ": " + ret_code_map.at(flag));
case (SUNDIALS_RET_CODE_TYPES::KINSOL):
throw exceptions::KINSolSolverFailureError("KINSol error in " + func_name + ": " + ret_code_map.at(flag));
default:
throw exceptions::CVODESolverFailureError("SUNDIALS error in " + func_name + ": " + ret_code_map.at(flag));
}
}
}
}