diff --git a/src/include/gridfire/solver/strategies/CVODE_solver_strategy.h b/src/include/gridfire/solver/strategies/CVODE_solver_strategy.h index 6a05c48b..ec73777c 100644 --- a/src/include/gridfire/solver/strategies/CVODE_solver_strategy.h +++ b/src/include/gridfire/solver/strategies/CVODE_solver_strategy.h @@ -137,5 +137,7 @@ namespace gridfire::solver { int m_num_steps = 0; bool m_stdout_logging_enabled = true; + + N_Vector m_constraints = nullptr; }; } \ No newline at end of file diff --git a/src/lib/engine/views/engine_multiscale.cpp b/src/lib/engine/views/engine_multiscale.cpp index 0c5e5113..634aefe1 100644 --- a/src/lib/engine/views/engine_multiscale.cpp +++ b/src/lib/engine/views/engine_multiscale.cpp @@ -244,6 +244,9 @@ namespace gridfire { // If j is algebraic, we can return 0.0 since the Jacobian entry for algebraic species is always zero. return 0.0; } + if (std::ranges::contains(m_algebraic_species_indices, i_full)) { + return 0.0; + } // Otherwise we need to query the full jacobian return m_baseEngine.getJacobianMatrixEntry(i_full, j_full); } diff --git a/src/lib/solver/strategies/CVODE_solver_strategy.cpp b/src/lib/solver/strategies/CVODE_solver_strategy.cpp index df990fbb..f8afb5d9 100644 --- a/src/lib/solver/strategies/CVODE_solver_strategy.cpp +++ b/src/lib/solver/strategies/CVODE_solver_strategy.cpp @@ -160,6 +160,18 @@ namespace gridfire::solver { << " | NonlinIters: " << std::setw(2) << nliters << " | ConvFails: " << std::setw(2) << nlcfails << std::endl; + if (n_steps % 300 == 0) { + std::cout << "Manually triggering engine update at step " << n_steps << "..." << std::endl; + exceptions::StaleEngineTrigger::state staleState { + T9, + netIn.density, + std::vector(y_data, y_data + numSpecies), + current_time, + static_cast(n_steps), + current_energy + }; + throw exceptions::StaleEngineTrigger(staleState); + } // if (n_steps % 50 == 0) { // std::cout << "Logging step diagnostics at step " << n_steps << "..." << std::endl; @@ -390,6 +402,26 @@ namespace gridfire::solver { check_cvode_flag(CVodeInit(m_cvode_mem, cvode_rhs_wrapper, current_time, m_Y), "CVodeInit"); check_cvode_flag(CVodeSStolerances(m_cvode_mem, relTol, absTol), "CVodeSStolerances"); + // Constraints + // We constrain the solution vector using CVODE's built in constraint flags as outlines on page 53 of the CVODE manual + // https://computing.llnl.gov/sites/default/files/cv_guide-5.7.0.pdf + // For completeness and redundancy against future dead links the flags have been copied here + // 0.0: No constraint on the corresponding component of y. + // 1.0: The corresponding component of y is constrained to be >= 0. + // -1.0: The corresponding component of y is constrained to be <= 0. + // 2.0: The corresponding component of y is constrained to be > 0. + // -2.0: The corresponding component of y is constrained to be < 0 + // Here we use 1.0 for all species to ensure they remain non-negative. + + m_constraints = N_VClone(m_Y); + if (m_constraints == nullptr) { + LOG_ERROR(m_logger, "Failed to create constraints vector for CVODE"); + throw std::runtime_error("Failed to create constraints vector for CVODE"); + } + N_VConst(1.0, m_constraints); // Set all constraints to >= 0 (note this is where the flag values are set) + + check_cvode_flag(CVodeSetConstraints(m_cvode_mem, m_constraints), "CVodeSetConstraints"); + check_cvode_flag(CVodeSetMaxStep(m_cvode_mem, 1.0e20), "CVodeSetMaxStep"); m_J = SUNDenseMatrix(static_cast(N), static_cast(N), m_sun_ctx); @@ -406,11 +438,13 @@ namespace gridfire::solver { if (m_J) SUNMatDestroy(m_J); if (m_Y) N_VDestroy(m_Y); if (m_YErr) N_VDestroy(m_YErr); + if (m_constraints) N_VDestroy(m_constraints); m_LS = nullptr; m_J = nullptr; m_Y = nullptr; m_YErr = nullptr; + m_constraints = nullptr; if (memFree) { if (m_cvode_mem) CVodeFree(&m_cvode_mem); diff --git a/tests/graphnet_sandbox/main.cpp b/tests/graphnet_sandbox/main.cpp index d641fae2..761332b8 100644 --- a/tests/graphnet_sandbox/main.cpp +++ b/tests/graphnet_sandbox/main.cpp @@ -122,7 +122,7 @@ int main(int argc, char* argv[]){ netIn.temperature = 1.5e7; netIn.density = 1.6e2; netIn.energy = 0; - netIn.tMax = 1e2; + netIn.tMax = 3e13; // netIn.tMax = 1e-14; netIn.dt0 = 1e-12;