newton.hpp serif/solver/nonlinear/observers.hpp serif/solver/nonlinear/steps.hpp src/compile_time_checks/serif/backend_independent.cpp src/compile_time_checks/serif/solver/public_contracts.cpp src/include/serif/solver/equilibrium.hpp serif serif::solver serif::solver::detail #pragmaonce #include"serif/solver/nonlinear/observers.hpp" #include"serif/solver/nonlinear/steps.hpp" namespaceserif::solver{ namespacedetail{ template<typenameProblem,typenameState,typenameOptions> conceptNewtonStrategyFor=requires(Problem&problem,constState&state,Options&options, consttypenamedecltype(problem.prepare(state))::value_type&prepared,typenameProblem::Vector&vector){ {options.strategies.solve(problem,state,prepared,vector,vector,options)}->std::same_as<linear::Report>; }; template<typenameProblem,typenameState,typenameOptions,typenameObserver> [[nodiscard]]autorun_newton(Problem&problem,Stateinitial_state,Optionsoptions,Observerobserver, std::optional<NewtonProgress>restart){ usingVector=typenameProblem::Vector; usingPrepared=typenamedecltype(problem.prepare(initial_state))::value_type; usingResult=SolveResult<State, typename Problem::System, typename Problem::Model>; validate_start(options,restart,initial_state.values().size()); Resultresult(problem.model_owner()); SolveDiagnosticsdiagnostics=restart?restart->diagnostics:SolveDiagnostics{}; SolveObservationobservation(observer,options.strategies,diagnostics); autoinitial=evaluate_start(problem,initial_state,options,restart,diagnostics); if(!initial){ returnobservation.finish(result,initial.error().status,initial.error().message); } MetricEvaluationaccepted_metric=initial->metric; result.accept(std::move(initial_state),std::move(initial->system)); constintsize=static_cast<int>(result.state().values().size()); Vectorcorrection(size),physical_direction(size); Vectorrhs(static_cast<int>(result.system()->residual().size())); std::ranges::fill(correction,0.0); doublenext_step=options.line_search.initial_step; if(restart){ std::ranges::copy(restart->correction,correction.begin()); next_step=restart->next_step; } save_progress(result,options,diagnostics,accepted_metric,std::span(correction),next_step); observation.notify(restart?EventKind::resumed:EventKind::initial,result.state(),result.system(), diagnostics.attempted_iterations,0,0.0,accepted_metric); //Checkterminalstatesbeforepreparinganinverse:arootmayhaveasingularJacobian. std::optional<Prepared>prepared; while(true){ if(accepted_metric.residual_norm<=*diagnostics.convergence_threshold){ returnobservation.finish(result,SolveStatus::converged,"Thestarsatisfiestheequilibriumtolerance.",accepted_metric); } if(observation.stop_requested()){ returnobservation.finish(result,SolveStatus::stopped,"Newtonstoppedatanacceptedboundaryattheobserver'srequest.",accepted_metric); } if(diagnostics.attempted_iterations>=options.method.maximum_iterations){ returnobservation.finish(result,SolveStatus::maximum_iterations,"Newtonreacheditsiterationbudget;theresultretainsthelastacceptedstar.",accepted_metric); } if(!prepared){ autopreparation=problem.prepare(result.state()); if(constautofailure=preparation_rejection(problem,preparation)){ returnobservation.finish(result,SolveStatus::preparation_failure,*failure,accepted_metric); } prepared=std::move(*preparation); } constintiteration=diagnostics.attempted_iterations++; observation.notify(EventKind::before_iteration,result.state(),result.system(),iteration,0,0.0,accepted_metric); constautodirection=compute_direction(problem,result,*prepared,options,diagnostics, rhs,correction,std::span(physical_direction)); if(!direction){ returnobservation.finish(result,direction.error().status,direction.error().message,accepted_metric); } autotrial=find_acceptable_step(problem,result,accepted_metric,correction,std::span(physical_direction), *direction,next_step,options,diagnostics,observation); if(!trial){ returnobservation.finish(result,trial.error().status,trial.error().message,accepted_metric); } //Nothingbecomesaccepteduntilthecandidateanditsnonterminalinversearebothusable. observation.notify(EventKind::before_accept,trial->state,trial->system,iteration,trial->trial,trial->step,trial->metric); result.accept(std::move(trial->state),std::move(trial->system)); prepared=std::move(trial->preparation); accepted_metric=trial->metric; ++diagnostics.accepted_iterations; diagnostics.final_residual_norm=accepted_metric.residual_norm; diagnostics.last_accepted_step=trial->step; for(double&value:correction){ value*=1.0-trial->step; } if(!finite_correction(std::span(correction),size)){ std::ranges::fill(correction,0.0); } next_step=std::min(options.line_search.initial_step,trial->step/options.line_search.contraction); save_progress(result,options,diagnostics,accepted_metric,std::span(correction),next_step); observation.notify(EventKind::accepted,result.state(),result.system(),iteration,trial->trial,trial->step,accepted_metric); } } } template<typenameProblem,typenameState,typenameOptions=SolverOptions<>,typenameObserver=NoObserver> requiresdetail::NewtonStrategyFor<Problem, State, Options> [[nodiscard]]autosolve_newton(Problem&problem,Stateinitial_state,Optionsoptions={},Observerobserver={}){ returndetail::run_newton(problem,std::move(initial_state),std::move(options),std::move(observer),std::nullopt); } template<typenameProblem,typenameState,typenameOptions=SolverOptions<>,typenameObserver=NoObserver> requiresdetail::NewtonStrategyFor<Problem, State, Options> [[nodiscard]]autoresume_newton(Problem&problem,NewtonCheckpoint<State>checkpoint,Optionsoptions={},Observerobserver={}){ returndetail::run_newton(problem,std::move(checkpoint.state),std::move(options),std::move(observer),std::move(checkpoint.progress)); } }