Go to the documentation of this file.
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>
89 template <
typename 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,
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>
259 std::cout << invlib::separator() << std::endl << std::endl;
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) {
275 std::tuple<Params &...> tuple(params...);
277 auto &
y = std::get<4>(tuple);
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.";
309 std::cout << std::endl << invlib::separator() << std::endl;
318 template <
typename... Params>
319 void step(
const Params &... params) {
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) {
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(
341 std::cout << std::endl;
350 template <
typename... Params>
353 std::cout << invlib::separator() << std::endl;
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: ";
363 bool converged = std::get<0>(tuple);
365 std::cout <<
"OEM computation converged." << std::endl;
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) {
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;
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,
489 :
m(measurement_space_dimension),
490 n(state_space_dimension),
495 (arts_jacobian.
ncols() != 0) && (arts_y.
nelem() != 0)),
587 const Index nq =
x.nbooks();
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++) {
607 for (
Index p = 0; p <
x.npages(); p++) {
608 for (
Index r = 0; r <
x.nrows(); r++) {
609 for (
Index c = 0; c <
x.ncols(); c++) {
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++) {
619 for (
Index p = 0; p <
x.npages(); p++) {
620 for (
Index r = 0; r <
x.nrows(); r++) {
621 for (
Index c = 0; c <
x.ncols(); c++) {
622 if (
x(i, p, r, c) > limit_high)
x(i, p, r, c) = limit_high;
678 const Index& max_iter,
680 const Vector& lm_ga_settings,
681 const Index& clear_matrices,
682 const Index& display_progress) {
685 const Index m =
y.nelem();
687 if ((
x.nelem() != n) && (
x.nelem() != 0))
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.");
693 throw runtime_error(
"Inconsistency in size between *x* and *covmat_sx*.");
694 if ((
yf.nelem() != m) && (
yf.nelem() != 0))
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.");
700 throw runtime_error(
"Inconsistency in size between *y* and *covmat_se*.");
703 "The number of rows of the jacobian must be either the number of elements in *y* or 0.");
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) {
773 if ((
yf.nelem() == 0) || (
jacobian.empty())) {
779 #endif // _ARTS_OEM_H_
Numeric scaling_factor_
Scaling factor for the cost.
ArtsVector get_measurement_vector()
Return most recently simulated measurement vector.
const TransformationMatrixType & trans_
The transformation matrix.
AgendaWrapper(AgendaWrapper &&)=delete
bool reuse_jacobian_
Flag whether to reuse Jacobian from previous calculation.
ArrayOfRetrievalQuantity jacobian_quantities(Workspace &ws) noexcept
Complex w(Complex z) noexcept
The Faddeeva function.
void step(const Params &... params)
Print step to command line.
Vector gamma_history_
Reference to ARTS vector holding the LM gamma history.
void finalize(const Params &... params)
Finalize log output.
Interface to ARTS inversion_iterate_agenda.
invlib::Matrix< ArtsMatrix > Matrix
invlib wrapper type for ARTS matrices.
Workspace * ws_
Pointer to current ARTS workspace.
auto solve(const MatrixType &A, const VectorType &v) -> typename VectorType::ResultType
Solve linear system.
Vector xa(Workspace &ws) noexcept
Vector y(Workspace &ws) noexcept
invlib::MAP< ForwardModel, Matrix, CovarianceMatrix, CovarianceMatrix, Vector, Formulation::NFORM > OEM_NFORM
OEM n form.
ArtsLog(unsigned int v, ::Vector &g, bool l=false)
Create log.
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.
invlib::Matrix< ArtsCovarianceMatrixWrapper > CovarianceMatrix
invlib wrapper type for ARTS the ARTS covariance class.
Agenda inversion_iterate_agenda(Workspace &ws) noexcept
unsigned int iteration_counter_
This can be used to make arrays out of anything.
invlib::GaussNewton< Numeric, Std > GN
OEM Gauss-Newton optimization using normed ARTS QR solver.
Index nelem(const Lines &l)
Number of lines.
bool linear_
Flag indicating whether forward model is linear.
invlib::GaussNewton< Numeric, CG > GN_CG
Gauss-Newton (GN) optimization using normed CG solver.
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)
static std::string log(const invlib::GaussNewton< RealType, Solver > &, Vector &, size_t)
MatrixReference Jacobian(const Vector &xi, Vector &yi)
Evaluate forward model and compute Jacobian.
void init(Params &... params)
Initialize log output.
Vector yi_
Cached simulation result.
invlib::MAP< ForwardModel, Matrix, CovarianceMatrix, CovarianceMatrix, Vector, Formulation::MFORM > OEM_MFORM
OEM m form.
Index nelem() const
Returns the number of elements.
AgendaWrapper(const AgendaWrapper &)=delete
NUMERIC Numeric
The type to use for all floating point numbers.
std::vector< std::string > handle_nested_exception(const E &e, int level=0)
Handle exception encountered within invlib.
Vector yf(Workspace &ws) noexcept
CovarianceMatrix covmat_sx(Workspace &ws) noexcept
CovarianceMatrix covmat_se(Workspace &ws) noexcept
Eigen::Matrix< Numeric, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MatrixType
static std::string header()
Name to append to header line.
const unsigned int m
Dimension of the measurement space.
void Tensor4Clip(Tensor4 &x, const Index &iq, const Numeric &limit_low, const Numeric &limit_high)
Clip Tensor4.
invlib::MatrixIdentity< Matrix > Identity
Index nrows(Workspace &ws) noexcept
MatrixReference jacobian_
Reference to the jacobian WSV.
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.
invlib::Vector< ArtsVector > Vector
invlib wrapper type for ARTS vectors.
const Agenda * inversion_iterate_agenda_
Pointer to the inversion_iterate_agenda of the workspace.
static std::string header()
Name to append to header line.
Vector evaluate(const Vector &xi)
Evaluate the ARTS forward model.
bool finalized_
Flag indicating whether output has been finalized.
invlib::Matrix< ArtsMatrixReference<::Matrix > > MatrixReference
invlib wrapper type for ARTS matrices to be passed by reference.
Numeric start_cost_
Start cost (not computed by invlib)
invlib::MAP< ForwardModel, Matrix, CovarianceMatrix, CovarianceMatrix, Vector, Formulation::STANDARD, invlib::Rodgers531 > OEM_STANDARD
OEM standard form.
Log customization for different optimization methods.
invlib::LevenbergMarquardt< Numeric, CovarianceMatrix, CG > LM_CG
Levenberg-Marquardt (LM) optimization using normed CG solver.
AgendaWrapper & operator=(AgendaWrapper &&)=delete
const bool apply_
Whether or not to apply the transformation.
Matrix jacobian(Workspace &ws) noexcept
Vector x(Workspace &ws) noexcept
INDEX Index
The type to use for all integer numbers and indices.
Index ncols(Workspace &ws) noexcept
NormalizingSolver(const TransformationMatrixType &trans, bool apply, Params... params)
invlib::LevenbergMarquardt< Numeric, CovarianceMatrix, Std > LM
Levenberg-Marquardt (LM) optimization using normed ARTS QR solver.
AgendaWrapper & operator=(const AgendaWrapper &)=delete
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 nelem() const
Number of elements.
const unsigned int n
Dimension of the state space.
void time(const Params &... params)
Print timing information to command line.
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.
int verbosity_
Verbosity level of logger.
~ArtsLog()
Finalizes log output if necessary.
void solve(VectorView w, const CovarianceMatrix &A, ConstVectorView v)