diff --git a/src/include/gridfire/solver/strategies/triggers/engine_partitioning_trigger.h b/src/include/gridfire/solver/strategies/triggers/engine_partitioning_trigger.h index 3b242609..ec358375 100644 --- a/src/include/gridfire/solver/strategies/triggers/engine_partitioning_trigger.h +++ b/src/include/gridfire/solver/strategies/triggers/engine_partitioning_trigger.h @@ -331,8 +331,7 @@ namespace gridfire::trigger::solver::CVODE { * * @param simulationTimeInterval Interval used by SimulationTimeTrigger (> 0). * @param offDiagonalThreshold Off-diagonal Jacobian magnitude threshold (>= 0). - * @param timestepGrowthThreshold Threshold for timestep deviation (>= 0, and <= 1 when relative). - * @param timestepGrowthRelative Whether deviation is measured relatively. + * @param relativeTimestepCollapseThreshold Threshold for timestep deviation (>= 0, and <= 1 when relative). * @param timestepGrowthWindowSize Window size for timestep averaging (>= 1 recommended). * @return A unique_ptr to a composed Trigger implementing the policy above. * @@ -341,8 +340,7 @@ namespace gridfire::trigger::solver::CVODE { std::unique_ptr> makeEnginePartitioningTrigger( const double simulationTimeInterval, const double offDiagonalThreshold, - const double timestepGrowthThreshold, - const bool timestepGrowthRelative, + const double relativeTimestepCollapseThreshold, const size_t timestepGrowthWindowSize ); } diff --git a/src/lib/solver/strategies/CVODE_solver_strategy.cpp b/src/lib/solver/strategies/CVODE_solver_strategy.cpp index d5a0cfc1..ff8fe9b5 100644 --- a/src/lib/solver/strategies/CVODE_solver_strategy.cpp +++ b/src/lib/solver/strategies/CVODE_solver_strategy.cpp @@ -150,7 +150,7 @@ namespace gridfire::solver { ) { LOG_TRACE_L1(m_logger, "Starting solver evaluation with T9: {} and rho: {}", netIn.temperature/1e9, netIn.density); LOG_TRACE_L1(m_logger, "Building engine update trigger...."); - auto trigger = trigger::solver::CVODE::makeEnginePartitioningTrigger(1e12, 1e10, 1, true, 10); + auto trigger = trigger::solver::CVODE::makeEnginePartitioningTrigger(1e12, 1e10, 0.01, 10); LOG_TRACE_L1(m_logger, "Engine update trigger built!"); diff --git a/src/lib/solver/strategies/triggers/engine_partitioning_trigger.cpp b/src/lib/solver/strategies/triggers/engine_partitioning_trigger.cpp index b97dab77..d1427b4a 100644 --- a/src/lib/solver/strategies/triggers/engine_partitioning_trigger.cpp +++ b/src/lib/solver/strategies/triggers/engine_partitioning_trigger.cpp @@ -184,7 +184,7 @@ namespace gridfire::trigger::solver::CVODE { } bool TimestepCollapseTrigger::check(const gridfire::solver::CVODESolverStrategy::TimestepContext &ctx) const { - if (m_timestep_window.empty()) { + if (m_timestep_window.size() < m_windowSize) { m_misses++; return false; } @@ -193,11 +193,16 @@ namespace gridfire::trigger::solver::CVODE { averageTimestep += dt; } averageTimestep /= static_cast(m_timestep_window.size()); - if (m_relative && (std::abs(ctx.dt - averageTimestep) / averageTimestep) >= m_threshold) { + if (ctx.dt > averageTimestep) { + m_misses++; + return false; // Only trigger on timestep collapse (i.e., decrease in dt) + } + const double diff = std::abs(ctx.dt - averageTimestep); + if (m_relative && 1-(diff / averageTimestep) <= m_threshold) { m_hits++; LOG_TRACE_L2(m_logger, "TimestepCollapseTrigger triggered at t = {} due to relative growth: dt = {}, average dt = {}, threshold = {}", ctx.t, ctx.dt, averageTimestep, m_threshold); return true; - } else if (!m_relative && std::abs(ctx.dt - averageTimestep) >= m_threshold) { + } else if (!m_relative && diff >= m_threshold) { m_hits++; LOG_TRACE_L2(m_logger, "TimestepCollapseTrigger triggered at t = {} due to absolute growth: dt = {}, average dt = {}, threshold = {}", ctx.t, ctx.dt, averageTimestep, m_threshold); return true; @@ -207,13 +212,13 @@ namespace gridfire::trigger::solver::CVODE { } void TimestepCollapseTrigger::update(const gridfire::solver::CVODESolverStrategy::TimestepContext &ctx) { - push_to_fixed_deque(m_timestep_window, ctx.dt, m_windowSize); m_updates++; } void TimestepCollapseTrigger::step( const gridfire::solver::CVODESolverStrategy::TimestepContext &ctx ) { + push_to_fixed_deque(m_timestep_window, ctx.dt, m_windowSize); // --- TimestepCollapseTrigger::step does nothing and is intentionally left blank --- // } @@ -373,8 +378,7 @@ namespace gridfire::trigger::solver::CVODE { std::unique_ptr> makeEnginePartitioningTrigger( const double simulationTimeInterval, const double offDiagonalThreshold, - const double timestepGrowthThreshold, - const bool timestepGrowthRelative, + const double relativeTimestepCollapseThreshold, const size_t timestepGrowthWindowSize ) { using ctx_t = gridfire::solver::CVODESolverStrategy::TimestepContext; @@ -389,14 +393,12 @@ namespace gridfire::trigger::solver::CVODE { // TODO: This logic likely needs to be revisited; however, for now it is easy enough to change and test and it works reasonably well auto simulationTimeTrigger = std::make_unique>(std::make_unique(simulationTimeInterval), 1000); auto offDiagTrigger = std::make_unique(offDiagonalThreshold); - auto timestepGrowthTrigger = std::make_unique>(std::make_unique(timestepGrowthThreshold, timestepGrowthRelative, timestepGrowthWindowSize), 10); + auto timestepGrowthTrigger = std::make_unique>(std::make_unique(relativeTimestepCollapseThreshold, true, timestepGrowthWindowSize), 10); auto convergenceFailureTrigger = std::make_unique(5, 1.0f, 10); - // Combine the triggers using logical OR - auto orTriggerA = std::make_unique>(std::move(simulationTimeTrigger), std::move(offDiagTrigger)); - auto orTriggerB = std::make_unique>(std::move(orTriggerA), std::move(timestepGrowthTrigger)); - // auto orTriggerC = std::make_unique>(std::move(orTriggerB), std::move(convergenceFailureTrigger)); - return convergenceFailureTrigger; + auto convergenceOrTimestepTrigger = std::make_unique>(std::move(timestepGrowthTrigger), std::move(convergenceFailureTrigger)); + + return convergenceOrTimestepTrigger; } } \ No newline at end of file