350 typedef Tracker<AMPTracker> Base;
351 typedef typename TrackerTraits<AMPTracker>::EventEmitterType EmitterType;
353 enum UpsampleRefinementOption
355 upsample_refine_off = 0,
356 upsample_refine_on = 1
365 Set<PrecConf>(AMPConfigFrom(sys));
374 Set<PrecConf>(AMP_config);
378 const unsigned GetCurrentPrecision()
const
380 return current_precision_;
391 preserve_precision_ = should_preseve_precision;
398 Vec<mpfr_complex> CurrentPoint()
const override
400 if (this->CurrentPrecision()==DoublePrecision())
402 const auto& curr_vector = std::get<Vec<dbl>>(this->
current_space_);
403 Vec<mpfr_complex> returnme(NumVariables());
404 for (
unsigned ii = 0; ii < NumVariables(); ++ii)
406 returnme(ii) = mpfr_complex(curr_vector(ii));
427 SuccessCode TrackerLoopInitialization(mpfr_complex
const& start_time,
428 mpfr_complex
const& end_time,
429 Vec<mpfr_complex>
const& start_point)
const override
431 #ifndef BERTINI_DISABLE_ASSERTS
433 (!preserve_precision_
436 &&
"when tracking a path, either preservation of precision must be turned off (so precision can be higher at the end of tracking), or the initial precision must be high enough to support the resulting points to the desired tolerance"
440 NotifyObservers(Initializing<AMPTracker,mpfr_complex>(*
this,start_time, end_time, start_point));
442 initial_precision_ =
Precision(start_point(0));
443 DefaultPrecision(initial_precision_);
450 endtime_highest_precision_ = end_time;
451 endtime_highest_precision_.precision(initial_precision_);
454 endtime_.precision(initial_precision_);
459 mpfr_float segment_length = abs(start_time-end_time)/Get<Stepping>().min_num_steps;
460 SetStepSize(min(NumTraits<mpfr_float>::FromRational(Get<Stepping>().initial_step_size, current_precision_),segment_length));
464 if (initial_precision_==DoublePrecision())
465 MultipleToDouble(start_point);
467 MultipleToMultiple(initial_precision_, start_point);
476 auto initial_refinement_code = InitialRefinement();
478 #ifndef BERTINI_DISABLE_ASSERTS
479 if (initial_precision_==DoublePrecision()){
480 PrecisionSanityCheck<dbl>();
483 PrecisionSanityCheck<mpfr_complex>();
487 return initial_refinement_code;
494 void ResetCounters()
const override
496 Tracker::ResetCountersBase();
497 num_precision_decreases_ = 0;
499 num_successful_steps_since_precision_decrease_ = 0;
509 SuccessCode InitialRefinement()
const
511 SuccessCode initial_refinement_code = RefineStoredPoint();
512 if (initial_refinement_code!=SuccessCode::Success)
515 if (current_precision_ > Get<PrecConf>().maximum_precision)
518 return SuccessCode::SingularStartPoint;
521 if (current_precision_==DoublePrecision())
526 while (initial_refinement_code!=SuccessCode::Success);
528 return SuccessCode::Success;
539 SuccessCode PreIterationCheck()
const override
542 return SuccessCode::MaxNumStepsTaken;
544 return SuccessCode::MinStepSizeReached;
545 if (current_precision_ > Get<PrecConf>().maximum_precision)
546 return SuccessCode::MaxPrecisionReached;
548 return SuccessCode::Success;
557 void PostTrackCleanup()
const override
559 if (preserve_precision_)
571 void CopyFinalSolution(Vec<mpfr_complex> & solution_at_endtime)
const override
575 if (current_precision_==DoublePrecision())
578 solution_at_endtime.resize(num_vars);
579 for (
unsigned ii=0; ii<num_vars; ii++)
580 solution_at_endtime(ii) = mpfr_complex(std::get<Vec<dbl> >(
current_space_)(ii));
585 solution_at_endtime.resize(num_vars);
586 for (
unsigned ii=0; ii<num_vars; ii++)
588 solution_at_endtime(ii) = std::get<Vec<mpfr_complex> >(
current_space_)(ii);
589 solution_at_endtime(ii).precision(current_precision_);
604 SuccessCode TrackerIteration()
const override
606 if (current_precision_==DoublePrecision())
607 return TrackerIteration<dbl>();
609 return TrackerIteration<mpfr_complex>();
620 template <
typename ComplexType>
621 SuccessCode TrackerIteration() const
624 using RealType =
typename Eigen::NumTraits<ComplexType>::Real;
626 #ifndef BERTINI_DISABLE_ASSERTS
627 assert(PrecisionSanityCheck<ComplexType>() &&
"precision sanity check failed. some internal variable is not in correct precision");
632 Vec<ComplexType>& predicted_space = std::get<Vec<ComplexType> >(
temporary_space_);
633 Vec<ComplexType>& current_space = std::get<Vec<ComplexType> >(
current_space_);
635 ComplexType delta_t = ComplexType(
delta_t_);
637 #ifndef BERTINI_DISABLE_ASSERTS
638 PrecisionSanityCheck<ComplexType>();
641 SuccessCode predictor_code = Predict<ComplexType, RealType>(predicted_space, current_space, current_time, delta_t);
642 if (predictor_code==SuccessCode::MatrixSolveFailureFirstPartOfPrediction)
644 NotifyObservers(FirstStepPredictorMatrixSolveFailure<EmitterType>(*
this));
645 InitialMatrixSolveError();
646 return predictor_code;
648 else if (predictor_code==SuccessCode::MatrixSolveFailure)
651 NewtonConvergenceError();
652 return predictor_code;
654 else if (predictor_code==SuccessCode::HigherPrecisionNecessary)
656 NotifyObservers(PredictorHigherPrecisionNecessary<EmitterType>(*
this));
657 AMPCriterionError<ComplexType>();
658 return predictor_code;
662 NotifyObservers(SuccessfulPredict<AMPTracker, ComplexType>(*
this, predicted_space));
664 Vec<ComplexType>& tentative_next_space = std::get<Vec<ComplexType> >(
tentative_space_);
666 ComplexType tentative_next_time = current_time + delta_t;
668 SuccessCode corrector_code = Correct<ComplexType, RealType>(tentative_next_space,
670 tentative_next_time);
672 #ifndef BERTINI_DISABLE_ASSERTS
673 assert(PrecisionSanityCheck<ComplexType>() &&
"precision sanity check failed. some internal variable is not in correct precision");
676 if (corrector_code==SuccessCode::MatrixSolveFailure || corrector_code==SuccessCode::FailedToConverge)
679 NewtonConvergenceError();
680 return corrector_code;
682 else if (corrector_code == SuccessCode::HigherPrecisionNecessary)
684 NotifyObservers(CorrectorHigherPrecisionNecessary<EmitterType>(*
this));
685 AMPCriterionError<ComplexType>();
686 return corrector_code;
688 else if (corrector_code == SuccessCode::GoingToInfinity)
691 return corrector_code;
694 NotifyObservers(SuccessfulCorrect<AMPTracker, ComplexType>(*
this, tentative_next_space));
697 current_space = tentative_next_space;
698 return AdjustAMPStepSuccess<ComplexType>();
705 SuccessCode CheckGoingToInfinity()
const override
707 if (current_precision_ == DoublePrecision())
708 return Base::CheckGoingToInfinity<dbl>();
710 return Base::CheckGoingToInfinity<mpfr_complex>();
720 template <UpsampleRefinementOption refine_if_necessary = upsample_refine_off>
721 SuccessCode UpdatePrecisionAndStepsize()
const
743 template <
typename ComplexType>
744 SuccessCode AdjustAMPStepSuccess()
const
747 mpfr_float min_stepsize =
current_stepsize_ * NumTraits<mpfr_float>::FromRational(Get<Stepping>().step_size_fail_factor, current_precision_);
748 mpfr_float max_stepsize = min(
current_stepsize_ * NumTraits<mpfr_float>::FromRational(Get<Stepping>().step_size_success_factor, current_precision_), NumTraits<mpfr_float>::FromRational(Get<Stepping>().max_step_size, current_precision_));
751 unsigned min_precision = MinRequiredPrecision_BCTol<ComplexType>();
752 unsigned max_precision =
max(min_precision,current_precision_);
758 if ( (num_successful_steps_since_precision_decrease_ < Get<PrecConf>().consecutive_successful_steps_before_precision_decrease)
760 (num_precision_decreases_ >= Get<PrecConf>().max_num_precision_decreases))
761 min_precision =
max(min_precision, current_precision_);
765 min_precision, min_stepsize,
766 max_precision, max_stepsize,
767 DigitsB<ComplexType>(),
768 Get<NewtonConfig>().max_num_newton_iterations,
772 if ( (next_stepsize_ >
current_stepsize_) || (next_precision_ < current_precision_) )
778 if (next_precision_ < current_precision_)
780 ++num_precision_decreases_;
781 num_successful_steps_since_precision_decrease_ = 0;
784 ++num_successful_steps_since_precision_decrease_;
786 return UpdatePrecisionAndStepsize();
791 void InitialMatrixSolveError()
const
795 if (current_precision_==DoublePrecision())
796 next_precision_ = LowestMultiplePrecision();
800 UpdatePrecisionAndStepsize();
814 void NewtonConvergenceError()
const
816 next_precision_ = current_precision_;
818 next_stepsize_ = mpfr_float(Get<Stepping>().step_size_fail_factor, CurrentPrecision())*
current_stepsize_;
821 if (next_precision_==DoublePrecision())
822 next_precision_=LowestMultiplePrecision();
824 next_precision_+=PrecisionIncrement();
827 UpdatePrecisionAndStepsize();
845 template<
typename ComplexType>
846 void AMPCriterionError()
const
848 using RealT =
typename Eigen::NumTraits<ComplexType>::Real;
850 unsigned min_next_precision;
851 if (current_precision_==DoublePrecision())
852 min_next_precision = LowestMultiplePrecision();
858 mpfr_float max_stepsize =
current_stepsize_ * NumTraits<mpfr_float>::FromRational(Get<Stepping>().step_size_fail_factor,current_precision_);
860 if (min_stepsize > max_stepsize)
863 next_precision_ = min_next_precision;
865 next_stepsize_ =
max(
current_stepsize_ * (1+NumTraits<mpfr_float>::FromRational(Get<Stepping>().step_size_fail_factor,current_precision_))/2, min_stepsize);
869 unsigned digits_B = DigitsB<ComplexType>();
871 unsigned min_precision =
max(min_next_precision,
873 DigitsC<ComplexType>(),
878 unsigned a = ceil(digits_B - (
predictor_order_+1)* -log10(max_stepsize)/Get<NewtonConfig>().max_num_newton_iterations).convert_to<
unsigned>();
880 unsigned max_precision =
max(min_precision, a);
883 min_precision, min_stepsize,
884 Get<PrecConf>().maximum_precision, max_stepsize,
886 Get<NewtonConfig>().max_num_newton_iterations,
890 UpdatePrecisionAndStepsize();
900 template<
typename ComplexType>
901 NumErrorT B_RHS()
const
905 Get<NewtonConfig>().max_num_newton_iterations,
908 Get<PrecConf>()), NumErrorT(0));
929 template<
typename ComplexType>
930 unsigned DigitsB()
const
932 return unsigned(B_RHS<ComplexType>());
942 template<
typename ComplexType>
943 NumErrorT C_RHS()
const
948 Get<PrecConf>()), NumErrorT(0));
966 template<
typename ComplexType>
967 unsigned DigitsC()
const
969 return unsigned(C_RHS<ComplexType>());
996 template <
typename ComplexType>
997 unsigned MinRequiredPrecision_BCTol()
const
999 return max(DigitsB<ComplexType>(),
1000 DigitsC<ComplexType>(),
1020 void OnStepSuccess()
const override
1029 void OnStepFail()
const override
1032 num_successful_steps_since_precision_decrease_ = 0;
1039 void OnInfiniteTruncation()
const override
1070 template<
typename ComplexType,
typename RealType>
1071 SuccessCode Predict(Vec<ComplexType> & predicted_space,
1072 const Vec<ComplexType>& current_space,
1073 ComplexType
const& current_time, ComplexType
const& delta_t)
const
1079 static_assert(std::is_same< typename Eigen::NumTraits<RealType>::Real,
1080 typename Eigen::NumTraits<ComplexType>::Real>::value,
1081 "underlying complex type and the type for comparisons must match");
1084 if (predictor_->HasErrorEstimate())
1085 return predictor_->Predict(predicted_space,
1091 current_space, current_time,
1095 Get<Stepping>().frequency_of_CN_estimation,
1099 return predictor_->Predict(predicted_space,
1104 current_space, current_time,
1108 Get<Stepping>().frequency_of_CN_estimation,
1129 template<
typename ComplexType,
typename RealType>
1130 SuccessCode Correct(Vec<ComplexType> & corrected_space,
1131 Vec<ComplexType>
const& current_space,
1132 ComplexType
const& current_time)
const
1134 static_assert(std::is_same< typename Eigen::NumTraits<RealType>::Real,
1135 typename Eigen::NumTraits<ComplexType>::Real>::value,
1136 "underlying complex type and the type for comparisons must match");
1141 return corrector_->Correct(corrected_space,
1150 Get<NewtonConfig>().min_num_newton_iterations,
1151 Get<NewtonConfig>().max_num_newton_iterations,
1164 SuccessCode RefineStoredPoint()
const
1167 if (current_precision_==DoublePrecision())
1170 if (code == SuccessCode::Success)
1176 if (code == SuccessCode::Success)
1198 template <
typename ComplexType>
1199 SuccessCode RefineImpl(Vec<ComplexType> & new_space,
1200 Vec<ComplexType>
const& start_point, ComplexType
const& current_time)
const
1202 using RealType =
typename Eigen::NumTraits<ComplexType>::Real;
1204 static_assert(std::is_same< typename Eigen::NumTraits<RealType>::Real,
1205 typename Eigen::NumTraits<ComplexType>::Real>::value,
1206 "underlying complex type and the type for comparisons must match");
1208 auto target_precision =
Precision(current_time);
1209 assert(
Precision(start_point)==target_precision);
1216 return corrector_->Correct(new_space,
1225 Get<NewtonConfig>().min_num_newton_iterations,
1226 Get<NewtonConfig>().max_num_newton_iterations,
1250 template <
typename ComplexType>
1251 SuccessCode RefineImpl(Vec<ComplexType> & new_space,
1252 Vec<ComplexType>
const& start_point, ComplexType
const& current_time,
1253 NumErrorT
const& tolerance,
unsigned max_iterations)
const
1255 auto target_precision =
Precision(current_time);
1256 assert(
Precision(start_point)==target_precision);
1260 return corrector_->Correct(new_space,
1302 template <UpsampleRefinementOption refine_if_necessary = upsample_refine_off>
1305 if (new_precision==current_precision_)
1306 return SuccessCode::Success;
1308 NotifyObservers(PrecisionChanged<EmitterType>(*
this,current_precision_,new_precision));
1311 bool upsampling_needed = new_precision > current_precision_;
1315 if (new_precision==DoublePrecision() && current_precision_>DoublePrecision())
1320 else if(new_precision > DoublePrecision() && current_precision_ == DoublePrecision())
1323 DoubleToMultiple(new_precision);
1324 #ifndef BERTINI_DISABLE_ASSERTS
1325 assert(PrecisionSanityCheck<mpfr_complex>() &&
"precision sanity check failed. some internal variable is not in correct precision");
1330 MultipleToMultiple(new_precision);
1331 #ifndef BERTINI_DISABLE_ASSERTS
1332 assert(PrecisionSanityCheck<mpfr_complex>() &&
"precision sanity check failed. some internal variable is not in correct precision");
1336 if (refine_if_necessary && upsampling_needed)
1337 return RefineStoredPoint();
1339 return SuccessCode::Success;
1355 void DoubleToDouble(Vec<dbl>
const& source_point)
const
1357 #ifndef BERTINI_DISABLE_ASSERTS
1358 assert(source_point.size() ==
GetSystem().NumVariables() &&
"source point for converting to multiple precision is not the same size as the number of variables in the system being solved.");
1361 current_precision_ = DoublePrecision();
1362 DefaultPrecision(DoublePrecision());
1374 void DoubleToDouble()
const
1388 void MultipleToDouble(Vec<mpfr_complex>
const& source_point)
const
1390 #ifndef BERTINI_DISABLE_ASSERTS
1391 assert(source_point.size() ==
GetSystem().NumVariables() &&
"source point for converting to multiple precision is not the same size as the number of variables in the system being solved.");
1394 AdjustCurrentPrecision(DoublePrecision());
1399 if (std::get<Vec<dbl> >(
current_space_).size()!=source_point.size())
1402 for (
unsigned ii=0; ii<source_point.size(); ii++)
1405 endtime_.precision(DoublePrecision());
1413 void MultipleToDouble()
const
1430 void DoubleToMultiple(
unsigned new_precision, Vec<dbl>
const& source_point)
const
1432 #ifndef BERTINI_DISABLE_ASSERTS
1433 assert(source_point.size() ==
GetSystem().NumVariables() &&
"source point for converting to multiple precision is not the same size as the number of variables in the system being solved.");
1434 assert(new_precision > DoublePrecision() &&
"must convert to precision higher than DoublePrecision when converting to multiple precision");
1437 AdjustCurrentPrecision(new_precision);
1438 CopyToCurrentSpace(source_point);
1439 AdjustInternalsPrecision(new_precision);
1440 AdjustTemporariesPrecision(new_precision);
1442 #ifndef BERTINI_DISABLE_ASSERTS
1443 PrecisionSanityCheck<mpfr_complex>();
1456 void DoubleToMultiple(
unsigned new_precision)
const
1458 DoubleToMultiple( new_precision, std::get<Vec<dbl> >(
current_space_));
1474 void MultipleToMultiple(
unsigned new_precision, Vec<mpfr_complex>
const& source_point)
const
1476 #ifndef BERTINI_DISABLE_ASSERTS
1477 assert(source_point.size() ==
GetSystem().NumVariables() &&
"source point for converting to multiple precision is not the same size as the number of variables in the system being solved.");
1478 assert(new_precision > DoublePrecision() &&
"must convert to precision higher than DoublePrecision when converting to multiple precision");
1481 AdjustCurrentPrecision(new_precision);
1482 CopyToCurrentSpace(source_point);
1483 AdjustInternalsPrecision(new_precision);
1484 AdjustTemporariesPrecision(new_precision);
1486 #ifndef BERTINI_DISABLE_ASSERTS
1487 PrecisionSanityCheck<mpfr_complex>();
1499 void MultipleToMultiple(
unsigned new_precision)
const
1501 MultipleToMultiple( new_precision, std::get<Vec<mpfr_complex> >(
current_space_));
1508 void AdjustCurrentPrecision(
unsigned new_precision)
const
1510 previous_precision_ = current_precision_;
1511 current_precision_ = new_precision;
1512 DefaultPrecision(new_precision);
1516 void CopyToCurrentSpace(Vec<dbl>
const& source_point)
const
1519 if (space.size()!=source_point.size())
1520 space.resize(source_point.size());
1521 for (
unsigned ii=0; ii<source_point.size(); ii++)
1522 space(ii) = mpfr_complex(source_point(ii));
1525 void CopyToCurrentSpace(Vec<mpfr_complex>
const& source_point)
const
1528 if (space.size()!=source_point.size())
1529 space.resize(source_point.size());
1530 space = source_point;
1533 void AdjustInternalsPrecision(
unsigned new_precision)
const
1536 predictor_->ChangePrecision(new_precision);
1537 corrector_->ChangePrecision(new_precision);
1539 endtime_ = endtime_highest_precision_;
1556 void AdjustTemporariesPrecision(
unsigned new_precision)
const
1576 template<
typename ComplexType>
1577 bool PrecisionSanityCheck()
const
1580 if constexpr (std::is_same<ComplexType, dbl>::value){
1584 if constexpr (std::is_same<ComplexType, mpfr_complex>::value){
1585 assert(DefaultPrecision()==current_precision_ &&
"current precision differs from the default precision");
1586 assert(
GetSystem().precision() == current_precision_ &&
"tracked system is out of precision");
1588 assert(std::get<Vec<mpfr_complex> >(
current_space_)(0).precision() == current_precision_ &&
"current space out of precision");
1589 assert(std::get<Vec<mpfr_complex> >(
tentative_space_)(0).precision() == current_precision_ &&
"tentative space out of precision");
1590 assert(std::get<Vec<mpfr_complex> >(
temporary_space_)(0).precision() == current_precision_ &&
"temporary space out of precision");
1592 assert(
Precision(
delta_t_) == current_precision_ &&
"delta_t_ out of precision");
1593 assert(
Precision(
endtime_) == current_precision_ &&
"endtime_ out of precision");
1595 assert(current_precision_ <= MaxPrecisionAllowed() &&
"current_precision_ exceeds max precision");
1596 assert(predictor_->precision() == current_precision_ &&
"predictor_ out of precision");
1620 bool preserve_precision_ =
false;
1622 mutable unsigned previous_precision_;
1623 mutable unsigned current_precision_;
1624 mutable unsigned next_precision_;
1625 mutable unsigned num_precision_decreases_;
1626 mutable unsigned initial_precision_;
1627 mutable unsigned num_successful_steps_since_precision_decrease_;
1629 mutable mpfr_complex endtime_highest_precision_;
1633 unsigned CurrentPrecision()
const override
1635 return current_precision_;