Skip to content

Commit 9de8f1e

Browse files
committed
MIR-665 Interpolation from matrix file
1 parent 903a7fb commit 9de8f1e

File tree

4 files changed

+106
-329
lines changed

4 files changed

+106
-329
lines changed

src/mir/method/Matrix.cc

Lines changed: 22 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,9 @@
1414

1515
#include "eckit/log/JSON.h"
1616
#include "eckit/utils/MD5.h"
17-
#include "eckit/utils/StringTools.h"
1817

19-
#include "mir/action/context/Context.h"
20-
#include "mir/caching/InMemoryCacheUsage.h"
21-
#include "mir/caching/matrix/MatrixLoader.h"
22-
#include "mir/config/LibMir.h"
23-
#include "mir/data/MIRField.h"
24-
#include "mir/data/Space.h"
25-
#include "mir/method/MethodWeighted.h"
26-
#include "mir/method/nonlinear/NonLinear.h"
27-
#include "mir/method/solver/Multiply.h"
28-
#include "mir/method/solver/Statistics.h"
2918
#include "mir/param/MIRParametrisation.h"
30-
#include "mir/repres/Representation.h"
31-
#include "mir/stats/Field.h"
3219
#include "mir/util/Exceptions.h"
33-
#include "mir/util/Log.h"
34-
#include "mir/util/MIRStatistics.h"
35-
#include "mir/util/Trace.h"
3620

3721

3822
namespace mir::method {
@@ -41,225 +25,64 @@ namespace mir::method {
4125
static const MethodBuilder<Matrix> __builder("matrix");
4226

4327

44-
Matrix::Matrix(const param::MIRParametrisation& param) : Method(param) {
28+
Matrix::Matrix(const param::MIRParametrisation& param) : MethodWeighted(param) {
4529
std::string matrix;
4630
if (!parametrisation_.get("interpolation-matrix", matrix)) {
4731
throw exception::UserError("Matrix: option interpolation-matrix missing");
4832
}
4933

5034
matrix_ = matrix;
5135
if (!matrix_.exists()) {
52-
throw exception::UserError("Matrix: matrix path does not exist '" + matrix + "'");
36+
throw exception::UserError("Matrix: path does not exist '" + matrix + "'");
5337
}
5438

55-
std::string nonLinear = "missing-if-heaviest-missing";
56-
parametrisation_.get("non-linear", nonLinear);
57-
for (auto& n : eckit::StringTools::split("/", nonLinear)) {
58-
nonLinear_.emplace_back(nonlinear::NonLinearFactory::build(n, parametrisation_));
59-
ASSERT(nonLinear_.back());
60-
}
61-
62-
if (std::string stats = "maximum"; parametrisation_.get("interpolation-statistics", stats)) {
63-
solver_ =
64-
std::make_unique<solver::Statistics>(parametrisation_, stats::FieldFactory::build(stats, parametrisation_));
65-
}
66-
else {
67-
solver_ = std::make_unique<solver::Multiply>(parametrisation_);
68-
}
69-
ASSERT(solver_);
70-
71-
matrix_loader_ = LibMir::cacheLoader(LibMir::cache_loader::MATRIX);
72-
parametrisation_.get("matrix-loader", matrix_loader_);
73-
74-
parametrisation_.get("vector-space", vector_space_);
39+
matrix_path_ = matrix_.realName().asString();
7540
}
7641

7742

7843
void Matrix::json(eckit::JSON& j) const {
7944
j.startObject();
80-
81-
j << "type" << "matrix";
82-
j << "matrix" << matrix_;
83-
j << "solver" << *solver_;
84-
j << "nonLinear";
85-
j.startList();
86-
for (const auto& n : nonLinear_) {
87-
j << *n;
88-
}
89-
j.endList();
90-
45+
j << "interpolation-matrix=" << matrix_;
46+
MethodWeighted::json(j);
9147
j.endObject();
9248
}
9349

9450

95-
void Matrix::execute(context::Context& ctx, const repres::Representation& in, const repres::Representation& out) const {
96-
trace::Timer timer("Matrix::execute");
97-
98-
auto& log = Log::debug();
99-
log << "Matrix::execute (input: " << in << ", output: " << out << ", matrix: " << matrix_ << ")" << std::endl;
100-
101-
if (!matrix_.exists()) {
102-
throw exception::UserError("Matrix: file not found: '" + matrix_.realName() + "'");
103-
}
104-
105-
106-
// get matrix from in-memory cache, or insert an empty entry
107-
auto& cache = MethodWeighted::matrix_cache();
108-
109-
auto key = matrix_.realName().asString();
110-
auto& W = cache[key];
111-
112-
if (W.empty()) {
113-
log << "Load matrix from file " << matrix_loader_ << std::endl;
114-
WeightMatrix M(caching::matrix::MatrixLoaderFactory::build(matrix_loader_, matrix_));
115-
W.swap(M);
116-
117-
// update memory footprint
118-
auto shared = W.inSharedMemory();
119-
caching::InMemoryCacheUsage usage(shared ? 0 : W.footprint(), shared ? W.footprint() : 0);
120-
cache.footprint(key, usage);
121-
122-
log << "Matrix footprint " << W.owner() << " " << usage << " W -> " << W.owner() << std::endl;
123-
}
124-
else {
125-
log << "Using matrix from InMemoryCache" << std::endl;
126-
}
127-
128-
log << "Matrix: " << W << std::endl;
129-
ASSERT_NONEMPTY_INTERPOLATION("Matrix", !W.empty());
130-
131-
132-
// ensure unique missingValue on no input missing values
133-
auto& field = ctx.field();
134-
const bool hasMissing = field.hasMissing();
135-
if (!hasMissing) {
136-
field.missingValue(std::numeric_limits<double>::lowest());
137-
}
138-
139-
const double missingValue = field.missingValue();
140-
141-
142-
// check if matrix copy is required: run-time modifiable matrix is not cacheable
143-
const bool matrixCopy = std::any_of(nonLinear_.begin(), nonLinear_.end(),
144-
[&field](const std::unique_ptr<const nonlinear::NonLinear>& n) {
145-
return n->modifiesMatrix(field.hasMissing());
146-
});
147-
148-
149-
// check if forcing of missing values is required
150-
std::vector<size_t> forceMissing; // reserving size unnecessary (not the general case)
151-
{
152-
auto begin = W.begin(0);
153-
auto end(begin);
154-
for (size_t r = 0; r < W.rows(); r++) {
155-
if (begin == (end = W.end(r))) {
156-
forceMissing.push_back(r);
157-
}
158-
begin = end;
159-
}
160-
}
161-
162-
163-
// solve
164-
165-
auto npts_inp = in.numberOfPoints();
166-
auto npts_out = out.numberOfPoints();
167-
168-
const auto& sp = data::SpaceChooser::lookup(vector_space_);
169-
170-
for (size_t i = 0; i < field.dimensions(); i++) {
171-
MIRValuesVector result(npts_out); // field.update() takes ownership with std::swap()
172-
173-
WeightMatrix::Matrix A;
174-
WeightMatrix::Matrix B;
175-
MethodWeighted::set_operand_matrices_from_vectors(B, A, result, field.values(i), missingValue, sp);
176-
ASSERT(A.rows() == npts_inp);
177-
ASSERT(B.rows() == npts_out);
178-
179-
180-
// modify matrix (as a copy) if there are non-linear treatments
181-
if (matrixCopy) {
182-
auto timing(ctx.statistics().matrixTimer());
183-
WeightMatrix M(W); // modifiable matrix copy
184-
185-
for (const auto& n : nonLinear_) {
186-
n->treatment(A, M, B, field.values(i), missingValue);
187-
}
188-
189-
solver_->solve(A, M, B, missingValue);
190-
}
191-
else {
192-
auto timing(ctx.statistics().matrixTimer());
193-
solver_->solve(A, W, B, missingValue);
194-
}
51+
const char* Matrix::name() const {
52+
return "matrix";
53+
}
19554

19655

197-
// update field values with interpolation result
198-
MethodWeighted::set_vector_from_operand_matrix(B, result, missingValue, sp);
56+
MethodWeighted::CacheKeys Matrix::getDiskAndMemoryCacheKeys(const repres::Representation& in,
57+
const repres::Representation& out,
58+
const lsm::LandSeaMasks&) const {
59+
return {matrix_path_, matrix_path_};
60+
}
19961

200-
for (auto& r : forceMissing) {
201-
result[r] = missingValue;
202-
}
20362

204-
field.update(result, i, hasMissing || !forceMissing.empty());
205-
}
63+
void Matrix::assemble(util::MIRStatistics&, WeightMatrix&, const repres::Representation& in,
64+
const repres::Representation& out) const {
65+
NOTIMP;
20666
}
20767

20868

20969
void Matrix::hash(eckit::MD5& h) const {
210-
h << matrix_.asString();
211-
212-
for (const auto& n : nonLinear_) {
213-
n->hash(h);
214-
}
215-
216-
solver_->hash(h);
217-
218-
if (auto v = version(); v != 0) {
219-
h.add(v);
220-
}
70+
h << matrix_path_;
71+
MethodWeighted::hash(h);
22172
}
22273

22374

22475
bool Matrix::sameAs(const Method& other) const {
225-
auto sameNonLinearities = [](const auto& a, const auto& b) {
226-
if (a.size() != b.size()) {
227-
return false;
228-
}
229-
for (size_t i = 0; i < a.size(); ++i) {
230-
if (!a[i]->sameAs(*b[i])) {
231-
return false;
232-
}
233-
}
234-
return true;
235-
};
236-
23776
const auto* o = dynamic_cast<const Matrix*>(&other);
238-
return (o != nullptr) && matrix_.sameAs(o->matrix_) && sameNonLinearities(nonLinear_, o->nonLinear_) &&
239-
solver_->sameAs(*o->solver_);
77+
return (o != nullptr) && matrix_path_ == o->matrix_path_ && MethodWeighted::sameAs(other);
24078
}
24179

24280

24381
void Matrix::print(std::ostream& out) const {
24482
out << "Matrix["
245-
<< "InterpolationMatrix=" << matrix_ << ",Solver=" << (*solver_) << ",nonLinear[";
246-
const auto* sep = "";
247-
for (const auto& n : nonLinear_) {
248-
out << sep << (*n);
249-
sep = ",";
250-
}
251-
out << "]"
252-
<< "]";
253-
}
254-
255-
256-
void Matrix::setCropping(const util::BoundingBox&) {
257-
NOTIMP;
258-
}
259-
260-
261-
const util::BoundingBox& Matrix::getCropping() const {
262-
NOTIMP;
83+
<< "InterpolationMatrix=" << matrix_ << ",";
84+
MethodWeighted::print(out);
85+
out << "]";
26386
}
26487

26588

src/mir/method/Matrix.h

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,15 @@
1212

1313
#pragma once
1414

15-
#include <memory>
16-
#include <vector>
17-
1815
#include "eckit/filesystem/PathName.h"
19-
#include "mir/method/Method.h"
20-
21-
22-
namespace eckit {
23-
class JSON;
24-
}
2516

26-
namespace mir::method {
27-
namespace nonlinear {
28-
class NonLinear;
29-
}
30-
namespace solver {
31-
class Solver;
32-
}
33-
} // namespace mir::method
17+
#include "mir/method/MethodWeighted.h"
3418

3519

3620
namespace mir::method {
3721

3822

39-
class Matrix final : public Method {
23+
class Matrix final : public MethodWeighted {
4024
public:
4125
// -- Constructors
4226

@@ -46,33 +30,26 @@ class Matrix final : public Method {
4630
// -- Members
4731

4832
eckit::PathName matrix_;
49-
std::unique_ptr<const solver::Solver> solver_;
50-
std::vector<std::unique_ptr<const nonlinear::NonLinear>> nonLinear_;
33+
std::string matrix_path_;
5134

52-
std::string matrix_loader_;
53-
std::string vector_space_;
54-
55-
// -- Methods
35+
// -- Overridden methods
5636

57-
void json(eckit::JSON&) const;
58-
void solve(context::Context&, const repres::Representation& in, const repres::Representation& out) const;
37+
// From MethodWeighted
38+
void json(eckit::JSON&) const override;
39+
const char* name() const override;
5940

60-
// -- Overridden methods
41+
void assemble(util::MIRStatistics&, WeightMatrix&, const repres::Representation& in,
42+
const repres::Representation& out) const override;
6143

62-
// From Method
63-
void execute(context::Context&, const repres::Representation& in, const repres::Representation& out) const override;
44+
CacheKeys getDiskAndMemoryCacheKeys(const repres::Representation& in, const repres::Representation& out,
45+
const lsm::LandSeaMasks&) const override;
6446

6547
int version() const override { return 0; }
6648

6749
void hash(eckit::MD5&) const override;
6850
bool sameAs(const Method&) const override;
6951
void print(std::ostream&) const override;
7052

71-
bool canCrop() const override { return false; }
72-
bool hasCropping() const override { return false; }
73-
void setCropping(const util::BoundingBox&) override;
74-
const util::BoundingBox& getCropping() const override;
75-
7653
// -- Friends
7754

7855
friend eckit::JSON& operator<<(eckit::JSON& s, const Matrix& o) {

0 commit comments

Comments
 (0)