15 #include <type_traits> 17 #include "invlib/algebra.h" 18 #include "invlib/algebra/precision_matrix.h" 19 #include "invlib/algebra/solvers.h" 20 #include "invlib/interfaces/arts_wrapper.h" 21 #include "invlib/map.h" 22 #include "invlib/optimization.h" 23 #include "invlib/profiling/timer.h" 32 using Vector = invlib::Vector<ArtsVector>;
34 using Matrix = invlib::Matrix<ArtsMatrix>;
39 using Identity = invlib::MatrixIdentity<Matrix>;
46 using invlib::Formulation;
56 template <
typename ForwardModel>
62 Formulation::STANDARD,
73 template <
typename ForwardModel>
74 using OEM_NFORM = invlib::MAP<ForwardModel,
89 template <
typename ForwardModel>
90 using OEM_MFORM = invlib::MAP<ForwardModel,
111 template <
typename TransformationMatrixType,
112 typename SolverType = invlib::Standard>
115 template <
typename... Params>
119 : SolverType(params...),
apply_(apply),
trans_(trans) {}
131 template <
typename MatrixType,
typename VectorType>
133 typename VectorType::ResultType {
134 typename VectorType::ResultType
w;
136 typename VectorType::ResultType vv =
trans_ * v;
141 VectorType u = v - A *
w;
169 using GN = invlib::GaussNewton<Numeric, Std>;
171 using GN_CG = invlib::GaussNewton<Numeric, CG>;
173 using LM = invlib::LevenbergMarquardt<Numeric, CovarianceMatrix, Std>;
175 using LM_CG = invlib::LevenbergMarquardt<Numeric, CovarianceMatrix, CG>;
187 template <
typename T>
195 template <
typename RealType,
typename DampingMatrix,
typename Solver>
197 invlib::LevenbergMarquardt<RealType, DampingMatrix, Solver>> {
199 static constexpr
auto name =
"Levenberg-Marquardt";
203 std::string out =
"Gamma Factor";
209 const invlib::LevenbergMarquardt<RealType, DampingMatrix, Solver> &g,
210 Vector &gamma_history_,
212 std::string lambda = std::to_string(g.get_lambda());
213 std::string out(15 - std::min<size_t>(lambda.size(), 15),
' ');
215 gamma_history_[i] = g.get_lambda();
221 template <
typename RealType,
typename Solver>
224 static constexpr
auto name =
"Gauss-Newton";
227 static std::string
header() {
return ""; }
229 static std::string
log(
const invlib::GaussNewton<RealType, Solver> &,
243 template <invlib::LogType type>
253 ArtsLog(
unsigned int v, ::Vector &g,
bool l =
false)
254 : verbosity_(v), gamma_history_(g), linear_(l), finalized_(false) {}
258 if ((verbosity_ >= 1) && (!finalized_)) {
260 std::cout <<
"Error during OEM computation." << std::endl;
261 std::cout << std::endl;
262 std::cout << invlib::center(
"----") << std::endl;
263 std::cout << std::endl;
272 template <
typename... Params>
273 void init(Params &... params) {
274 if (verbosity_ >= 1) {
275 std::tuple<Params &...> tuple(params...);
277 auto &y = std::get<4>(tuple);
278 scaling_factor_ = 1.0 /
static_cast<Numeric>(y.nelem());
279 std::cout << std::endl;
280 std::cout << invlib::center(
"MAP Computation") << std::endl;
283 int formulation =
static_cast<int>(std::get<6>(tuple));
284 switch (formulation) {
286 std::cout <<
"Formulation: Standard" << std::endl;
289 std::cout <<
"Formulation: N-Form" << std::endl;
293 std::cout <<
"Formulation: M-Form" << std::endl;
298 using OptimizationType =
typename std::decay<
299 typename std::tuple_element<5, decltype(tuple)>::type>::type;
300 std::cout <<
"Method: " 301 << invlib::OptimizerLog<OptimizationType>::name;
302 std::cout << std::endl;
304 std::cout << std::endl;
305 std::cout << std::setw(5) <<
"Step" << std::setw(15) <<
"Total Cost";
306 std::cout << std::setw(15) <<
"x-Cost" << std::setw(15) <<
"y-Cost";
307 std::cout << std::setw(15) <<
"Conv. Crit.";
308 std::cout << std::setw(15) << OptimizerLog<OptimizationType>::header();
318 template <
typename... Params>
319 void step(
const Params &... params) {
320 if (verbosity_ >= 1) {
321 std::tuple<
const Params &...> tuple(params...);
322 using OptimizationType =
typename std::decay<
323 typename std::tuple_element<5, decltype(tuple)>::type>::type;
325 auto step_number = std::get<0>(tuple);
326 std::cout << std::setw(5) << step_number;
327 if (step_number == 0) {
328 start_cost_ = std::get<1>(tuple);
330 std::cout << std::setw(15) << scaling_factor_ * std::get<1>(tuple);
331 std::cout << std::setw(15) << scaling_factor_ * std::get<2>(tuple);
332 std::cout << std::setw(15) << scaling_factor_ * std::get<3>(tuple);
334 if (std::isnan(std::get<4>(tuple))) {
335 std::cout << std::setw(15) <<
" ";
337 std::cout << std::setw(15) << std::get<4>(tuple);
339 std::cout << OptimizerLog<OptimizationType>::log(
340 std::get<5>(tuple), gamma_history_, std::get<0>(tuple));
341 std::cout << std::endl;
350 template <
typename... Params>
352 if (verbosity_ >= 1) {
355 std::tuple<
const Params &...> tuple(params...);
356 std::cout << std::endl;
358 std::cout <<
"Total number of steps: ";
359 std::cout << std::get<1>(tuple) << std::endl;
360 std::cout <<
"Final scaled cost function value: ";
361 std::cout << std::get<2>(tuple) * scaling_factor_ << std::endl;
363 bool converged = std::get<0>(tuple);
365 std::cout <<
"OEM computation converged." << std::endl;
366 }
else if (linear_) {
367 std::cout <<
"Linear OEM computation finished." << std::endl;
369 std::cout <<
"OEM computation DID NOT converge!" << std::endl;
377 template <
typename... Params>
378 void time(
const Params &... params) {
379 if (verbosity_ >= 1) {
380 std::tuple<
const Params &...> tuple(params...);
381 std::cout << std::endl;
382 std::cout <<
"Elapsed Time for Retrieval: ";
383 std::cout << std::get<0>(tuple) << std::endl;
384 std::cout <<
"Time in inversion_iterate Agenda (No Jacobian): ";
385 std::cout << std::get<1>(tuple) << std::endl;
386 std::cout <<
"Time in inversion_iterate Agenda (With Jacobian): ";
387 std::cout << std::get<2>(tuple) << std::endl;
389 std::cout << std::endl;
390 std::cout << invlib::center(
"----") << std::endl;
391 std::cout << std::endl;
405 bool linear_ =
false;
407 bool finalized_ =
false;
424 template <
typename E>
426 const std::exception *re;
427 std::vector<std::string> errors{};
429 re =
dynamic_cast<const std::exception *
>(&e);
435 s =
"Run-time error in oem computation: ";
443 std::rethrow_if_nested(e);
444 }
catch (
const std::exception &ne) {
446 errors.insert(errors.end(), sv.begin(), sv.end());
465 const unsigned int m = 0;
467 const unsigned int n = 0;
484 unsigned int measurement_space_dimension,
485 unsigned int state_space_dimension,
486 ::Matrix &arts_jacobian,
488 const Agenda *inversion_iterate_agenda)
489 : m(measurement_space_dimension),
490 n(state_space_dimension),
491 inversion_iterate_agenda_(inversion_iterate_agenda),
492 iteration_counter_(0),
493 jacobian_(arts_jacobian),
494 reuse_jacobian_((arts_jacobian.nrows() != 0) &&
495 (arts_jacobian.ncols() != 0) && (arts_y.
nelem() != 0)),
522 if (!reuse_jacobian_) {
524 *ws_, yi_, jacobian_, xi, 1, 0, *inversion_iterate_agenda_);
526 iteration_counter_ += 1;
528 reuse_jacobian_ =
false;
544 if (!reuse_jacobian_) {
552 *inversion_iterate_agenda_);
554 reuse_jacobian_ =
false;
589 if (iq < -1)
throw runtime_error(
"Argument *iq* must be >= -1.");
592 os <<
"Argument *iq* is too high.\n" 593 <<
"You have selected index: " << iq <<
"\n" 594 <<
"but the number of quantities is only: " << nq <<
"\n" 595 <<
"(Note that zero-based indexing is used)\n";
596 throw runtime_error(os.
str());
599 Index ifirst = 0, ilast = nq - 1;
605 if (!std::isinf(limit_low)) {
606 for (
Index i = ifirst;
i <= ilast;
i++) {
610 if (x(
i, p,
r, c) < limit_low) x(
i, p,
r, c) = limit_low;
617 if (!std::isinf(limit_high)) {
618 for (
Index i = ifirst;
i <= ilast;
i++) {
622 if (x(
i, p,
r, c) > limit_high) x(
i, p,
r, c) = limit_high;
670 const Agenda& inversion_iterate_agenda,
678 const Index& max_iter,
680 const Vector& lm_ga_settings,
681 const Index& clear_matrices,
682 const Index& display_progress) {
689 "The length of *x* must be either the same as *xa* or 0.");
691 throw runtime_error(
"*covmat_sx* must be a square matrix.");
692 if (covmat_sx.
ncols() != n)
693 throw runtime_error(
"Inconsistency in size between *x* and *covmat_sx*.");
696 "The length of *yf* must be either the same as *y* or 0.");
698 throw runtime_error(
"*covmat_se* must be a square matrix.");
699 if (covmat_se.
ncols() != m)
700 throw runtime_error(
"Inconsistency in size between *y* and *covmat_se*.");
701 if ((jacobian.
nrows() != m) && (!jacobian.
empty()))
703 "The number of rows of the jacobian must be either the number of elements in *y* or 0.");
704 if ((jacobian.
ncols() != n) && (!jacobian.
empty()))
706 "The number of cols of the jacobian must be either the number of elements in *xa* or 0.");
711 if (jacobian_indices.
nelem() != nq)
713 "Different number of elements in *jacobian_quantities* " 714 "and *jacobian_indices*.");
715 if (nq && jacobian_indices[nq - 1][1] + 1 != n)
717 "Size of *covmat_sx* do not agree with Jacobian " 718 "information (*jacobian_indices*).");
721 if (!(method ==
"li" || method ==
"gn" || method ==
"li_m" ||
722 method ==
"gn_m" || method ==
"ml" || method ==
"lm" ||
723 method ==
"li_cg" || method ==
"gn_cg" || method ==
"li_cg_m" ||
724 method ==
"gn_cg_m" || method ==
"lm_cg" || method ==
"ml_cg")) {
726 "Valid options for *method* are \"nl\", \"gn\" and " 727 "\"ml\" or \"lm\".");
730 if (!(x_norm.
nelem() == 0 || x_norm.
nelem() == n)) {
732 "The vector *x_norm* must have length 0 or match " 736 if (x_norm.
nelem() > 0 &&
min(x_norm) <= 0) {
737 throw runtime_error(
"All values in *x_norm* must be > 0.");
741 throw runtime_error(
"The argument *max_iter* must be > 0.");
745 throw runtime_error(
"The argument *stop_dx* must be > 0.");
748 if ((method ==
"ml") || (method ==
"lm") || (method ==
"lm_cg") ||
749 (method ==
"ml_cg")) {
750 if (lm_ga_settings.
nelem() != 6) {
752 "When using \"ml\", *lm_ga_setings* must be a " 753 "vector of length 6.");
755 if (
min(lm_ga_settings) < 0) {
757 "The vector *lm_ga_setings* can not contain any " 762 if (clear_matrices < 0 || clear_matrices > 1)
763 throw runtime_error(
"Valid options for *clear_matrices* are 0 and 1.");
764 if (display_progress < 0 || display_progress > 1)
765 throw runtime_error(
"Valid options for *display_progress* are 0 and 1.");
768 if (x.
nelem() == 0) {
771 ws, yf, jacobian, xa, 1, 0, inversion_iterate_agenda);
773 if ((yf.
nelem() == 0) || (jacobian.
empty())) {
775 ws, yf, jacobian, x, 1, 0, inversion_iterate_agenda);
779 #endif // _ARTS_OEM_H_ void separator(ostream &stream, Index length)
INDEX Index
The type to use for all integer numbers and indices.
const bool apply_
Whether or not to apply the transformation.
unsigned int iteration_counter_
Workspace * ws_
Pointer to current ARTS workspace.
Index nelem() const
Number of elements.
invlib::Matrix< ArtsCovarianceMatrixWrapper > CovarianceMatrix
invlib wrapper type for ARTS the ARTS covariance class.
bool empty() const
Returns true if variable size is zero.
invlib::MAP< ForwardModel, Matrix, CovarianceMatrix, CovarianceMatrix, Vector, Formulation::MFORM > OEM_MFORM
OEM m form.
void inversion_iterate_agendaExecute(Workspace &ws, Vector &yf, Matrix &jacobian, const Vector &x, const Index jacobian_do, const Index inversion_iteration_counter, const Agenda &input_agenda)
const TransformationMatrixType & trans_
The transformation matrix.
Eigen::Matrix< Numeric, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MatrixType
void step(const Params &... params)
Print step to command line.
Index npages() const
Returns the number of pages.
Log customization for different optimization methods.
bool reuse_jacobian_
Flag whether to reuse Jacobian from previous calculation.
invlib::Vector< ArtsVector > Vector
invlib wrapper type for ARTS vectors.
auto solve(const MatrixType &A, const VectorType &v) -> typename VectorType::ResultType
Solve linear system.
cmplx FADDEEVA() w(cmplx z, double relerr)
Vector yi_
Cached simulation result.
Index nrows() const
Returns the number of rows.
Index nelem() const
Returns the number of elements.
static std::string header()
Name to append to header line.
std::vector< std::string > handle_nested_exception(const E &e, int level=0)
Handle exception encountered within invlib.
void jac_ranges_indices(ArrayOfArrayOfIndex &jis, bool &any_affine, const ArrayOfRetrievalQuantity &jqs, const bool &before_affine)
Determines the index range inside x and the Jacobian for each retrieval quantity. ...
Index ncols() const
Returns the number of columns.
void time(const Params &... params)
Print timing information to command line.
invlib::GaussNewton< Numeric, CG > GN_CG
Gauss-Newton (GN) optimization using normed CG solver.
ArtsLog(unsigned int v, ::Vector &g, bool l=false)
Create log.
MatrixReference Jacobian(const Vector &xi, Vector &yi)
Evaluate forward model and compute Jacobian.
_CS_string_type str() const
ArtsVector get_measurement_vector()
Return most recently simulated measurement vector.
Interface to ARTS inversion_iterate_agenda.
const Agenda * inversion_iterate_agenda_
Pointer to the inversion_iterate_agenda of the workspace.
invlib::LevenbergMarquardt< Numeric, CovarianceMatrix, Std > LM
Levenberg-Marquardt (LM) optimization using normed ARTS QR solver.
Vector evaluate(const Vector &xi)
Evaluate the ARTS forward model.
invlib::GaussNewton< Numeric, Std > GN
OEM Gauss-Newton optimization using normed ARTS QR solver.
NUMERIC Numeric
The type to use for all floating point numbers.
invlib::MAP< ForwardModel, Matrix, CovarianceMatrix, CovarianceMatrix, Vector, Formulation::NFORM > OEM_NFORM
OEM n form.
invlib::LevenbergMarquardt< Numeric, CovarianceMatrix, CG > LM_CG
Levenberg-Marquardt (LM) optimization using normed CG solver.
This can be used to make arrays out of anything.
MatrixReference jacobian_
Reference to the jacobian WSV.
void Tensor4Clip(Tensor4 &x, const Index &iq, const Numeric &limit_low, const Numeric &limit_high)
Clip Tensor4.
AgendaWrapper(Workspace *ws, unsigned int measurement_space_dimension, unsigned int state_space_dimension, ::Matrix &arts_jacobian, ::Vector &arts_y, const Agenda *inversion_iterate_agenda)
Create inversion_iterate_agendaExecute wrapper.
void init(Params &... params)
Initialize log output.
invlib::MAP< ForwardModel, Matrix, CovarianceMatrix, CovarianceMatrix, Vector, Formulation::STANDARD, invlib::Rodgers531 > OEM_STANDARD
OEM standard form.
NormalizingSolver(const TransformationMatrixType &trans, bool apply, Params... params)
Index nelem(const Lines &l)
Number of lines.
static std::string log(const invlib::GaussNewton< RealType, Solver > &, Vector &, size_t)
void finalize(const Params &... params)
Finalize log output.
Index nbooks() const
Returns the number of books.
void OEM_checks(Workspace &ws, Vector &x, Vector &yf, Matrix &jacobian, const Agenda &inversion_iterate_agenda, const Vector &xa, const CovarianceMatrix &covmat_sx, const Vector &y, const CovarianceMatrix &covmat_se, const ArrayOfRetrievalQuantity &jacobian_quantities, const String &method, const Vector &x_norm, const Index &max_iter, const Numeric &stop_dx, const Vector &lm_ga_settings, const Index &clear_matrices, const Index &display_progress)
Error checking for OEM method.
static std::string log(const invlib::LevenbergMarquardt< RealType, DampingMatrix, Solver > &g, Vector &gamma_history_, size_t i)
Returns the string to append to the log of a single step.
invlib::MatrixIdentity< Matrix > Identity
static std::string header()
Name to append to header line.
Index ncols() const
Returns the number of columns.
int verbosity_
Verbosity level of logger.
void solve(VectorView w, const CovarianceMatrix &A, ConstVectorView v)
invlib::Matrix< ArtsMatrix > Matrix
invlib wrapper type for ARTS matrices.
invlib::Matrix< ArtsMatrixReference<::Matrix > > MatrixReference
invlib wrapper type for ARTS matrices to be passed by reference.
Index nrows() const
Returns the number of rows.
Vector gamma_history_
Reference to ARTS vector holding the LM gamma history.
~ArtsLog()
Finalizes log output if necessary.