observers.hpp chrono functional type_traits serif/solver/nonlinear/result.hpp src/include/serif/solver/nonlinear/newton.hpp serif::solver::SolveTiming serif::solver::TimedObserver serif::solver::detail::SolveObservation serif serif::solver serif::solver::detail #pragmaonce #include<chrono> #include<functional> #include<type_traits> #include"serif/solver/nonlinear/result.hpp" namespaceserif::solver{ structSolveTiming{ doubleseconds{0.0}; }; template<typenameObserver=NoObserver> classTimedObserver{ public: explicitTimedObserver(SolveTiming&timing,Observerobserver={}): m_timing(timing),m_observer(std::move(observer)){} voidstarted(){ m_start=std::chrono::steady_clock::now(); ifconstexpr(requires{m_observer.started();}){ m_observer.started(); } } voidfinished(SolveStatusstatus,constSolveDiagnostics&diagnostics){ ifconstexpr(requires{m_observer.finished(status,diagnostics);}){ m_observer.finished(status,diagnostics); } m_timing.seconds+=std::chrono::duration<double>(std::chrono::steady_clock::now()-m_start).count(); } decltype(auto)operator()(SolveEventevent,constauto&state,constauto&system){ returnstd::invoke(m_observer,std::move(event),state,system); } private: SolveTiming&m_timing; Observerm_observer; std::chrono::steady_clock::time_pointm_start; }; namespacedetail{ template<typenameObserver,typenameStrategies> classSolveObservation{ public: SolveObservation(Observer&observer,Strategies&strategies,SolveDiagnostics&diagnostics): m_observer(observer),m_strategies(strategies),m_diagnostics(diagnostics){ ifconstexpr(requires{observer.started();}){ observer.started(); } } voidnotify(EventKindkind,constauto&state,constauto&system,intiteration=0, inttrial=0,doublestep=0.0,std::optional<MetricEvaluation>metric={},std::stringmessage={}){ m_strategies.contribute_diagnostics(m_diagnostics); SolveEventevent{.kind=kind,.iteration=iteration,.trial=trial,.step=step, .metric=metric,.message=std::move(message),.diagnostics=m_diagnostics}; ifconstexpr(std::same_as<std::invoke_result_t<Observer&,SolveEvent,decltype(state),decltype(system)>,SolveControl>){ m_stop_requested|=std::invoke(m_observer,std::move(event),state,system)==SolveControl::stop; }else{ std::invoke(m_observer,std::move(event),state,system); } } [[nodiscard]]boolstop_requested()constnoexcept{ returnm_stop_requested; } [[nodiscard]]autofinish(auto&result,SolveStatusstatus,std::stringmessage,MetricEvaluationmetric={}){ m_strategies.contribute_diagnostics(m_diagnostics); result.finish(status,std::move(message),m_diagnostics); if(result.has_state()){ notify(EventKind::finished,result.state(),result.system(),m_diagnostics.attempted_iterations, 0,0.0,metric,result.message()); } ifconstexpr(requires{m_observer.finished(status,m_diagnostics);}){ m_observer.finished(status,m_diagnostics); } returnstd::move(result); } private: Observer&m_observer; Strategies&m_strategies; SolveDiagnostics&m_diagnostics; boolm_stop_requested{false}; }; } }