-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/eckit stats #154
base: develop
Are you sure you want to change the base?
Feature/eckit stats #154
Changes from 146 commits
9c060b9
5e48e9a
a712a43
b3859fe
8ccc4f4
54013f0
d211233
a5e88ae
b05421e
0b0419a
87bdf92
da2082f
8ae993a
cd2dc63
89682b0
d2da270
4a6f766
944e3a1
e288ba4
0d32d28
11e2602
dddc690
049d8df
2912c80
3071049
f7f768d
fba383a
6d30695
9155637
efa9a1d
321df0f
f5a28b4
846d46a
8b6471a
e291716
baa12ef
cad3759
57a8e61
18d0a67
adcdbc9
a79e134
94a51a8
552d327
335f2de
a751be6
6ac0bc6
65276cd
ae7cef7
6c3025b
7ca9c60
111295f
b37f134
f4733e9
bb6d1f0
cacaf2a
4628a15
d48f9c2
242da50
218db60
b833bca
0d0abd9
849a809
a0c8e4e
8587eaa
93faf46
489b7ee
9714ba9
eb8a1d0
b3eb405
29d1d60
3548e14
60cc03d
7c19c86
b3cfc54
1ed3c70
9f09ed7
9972ef2
7122e0c
2a3ebd7
f9299c9
c5991c1
7f8e7c2
4b8ec7a
21354e2
639c4e9
12013df
d28bb28
b1bf144
010ae33
1c54b37
2648331
ead4cc1
6b4e029
c6c533c
88a3e0e
07d191d
6406304
6b4497b
40e976e
72ac58b
1f31c85
0b2af7b
e36fc54
cb95334
ba4ca94
f4a5860
42e548e
2793384
52a2178
3648df1
6a2709f
1bfc6b1
6d18c1c
3d13f43
fb0e714
aa48457
3eb67bb
b9cfa49
8af674d
2f403ee
ffa12e2
1d76c31
152d463
fe0a36d
2aadb50
4973808
e7e9adb
53cce12
fc6a3db
1da915f
17ff1c1
7625c38
cf15b3e
368e32b
279ffb2
a569ab7
6f34418
044d6c3
50377f5
27c96c6
9bb79e8
a5e007a
98f5f81
98e4ccf
8557010
1ecd639
e7c22fa
055bc20
74e8b31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
list( APPEND eckit_stats_srcs | ||
Comparator.cc | ||
Comparator.h | ||
Distribution.cc | ||
Distribution.h | ||
Field.cc | ||
Field.h | ||
FieldStatistics.cc | ||
FieldStatistics.h | ||
Method.cc | ||
Method.h | ||
Statistics.cc | ||
Statistics.h | ||
comparator/ComparatorT.cc | ||
comparator/ComparatorT.h | ||
comparator/MissingValues.cc | ||
comparator/MissingValues.h | ||
comparator/Spectral.cc | ||
comparator/Spectral.h | ||
detail/AngleT.cc | ||
detail/AngleT.h | ||
detail/CentralMomentsT.cc | ||
detail/CentralMomentsT.h | ||
detail/Counter.cc | ||
detail/Counter.h | ||
detail/CounterBinary.cc | ||
detail/CounterBinary.h | ||
detail/ModeT.cc | ||
detail/ModeT.h | ||
detail/PNormsT.h | ||
detail/ScalarT.h | ||
distribution/DistributionT.cc | ||
distribution/DistributionT.h | ||
field/CentralMomentStats.cc | ||
field/CentralMomentStats.h | ||
field/CounterStats.cc | ||
field/CounterStats.h | ||
field/ModeStats.cc | ||
field/ModeStats.h | ||
method/MethodT.cc | ||
method/MethodT.h | ||
statistics/SimplePackingEntropy.cc | ||
statistics/SimplePackingEntropy.h | ||
statistics/Spectral.cc | ||
statistics/Spectral.h | ||
statistics/StatisticsT.cc | ||
statistics/StatisticsT.h | ||
util/mutex.h | ||
) | ||
|
||
ecbuild_add_library( | ||
TARGET eckit_stats | ||
TYPE SHARED | ||
INSTALL_HEADERS LISTED | ||
HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/stats | ||
SOURCES ${eckit_stats_srcs} | ||
PUBLIC_LIBS eckit ) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* (C) Copyright 1996- ECMWF. | ||
* | ||
* This software is licensed under the terms of the Apache Licence Version 2.0 | ||
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* In applying this licence, ECMWF does not waive the privileges and immunities | ||
* granted to it by virtue of its status as an intergovernmental organisation nor | ||
* does it submit to any jurisdiction. | ||
*/ | ||
|
||
|
||
#include "eckit/stats/Comparator.h" | ||
|
||
#include <map> | ||
#include <ostream> | ||
|
||
#include "eckit/exception/Exceptions.h" | ||
#include "eckit/log/Log.h" | ||
#include "eckit/stats/util/Mutex.h" | ||
|
||
|
||
namespace eckit::stats { | ||
|
||
|
||
static util::recursive_mutex* local_mutex = nullptr; | ||
static std::map<std::string, ComparatorFactory*>* m = nullptr; | ||
static util::once_flag once; | ||
static void init() { | ||
local_mutex = new util::recursive_mutex(); | ||
m = new std::map<std::string, ComparatorFactory*>(); | ||
} | ||
|
||
|
||
Comparator::Comparator(const Parametrisation& param1, const Parametrisation& param2) : | ||
parametrisation1_(param1), parametrisation2_(param2) {} | ||
|
||
|
||
Comparator::~Comparator() = default; | ||
|
||
|
||
ComparatorFactory::ComparatorFactory(const std::string& name) : name_(name) { | ||
util::call_once(once, init); | ||
util::lock_guard<util::recursive_mutex> lock(*local_mutex); | ||
|
||
if (m->find(name) != m->end()) { | ||
throw SeriousBug("ComparatorFactory: duplicate '" + name + "'"); | ||
} | ||
|
||
ASSERT(m->find(name) == m->end()); | ||
(*m)[name] = this; | ||
} | ||
|
||
|
||
ComparatorFactory::~ComparatorFactory() { | ||
util::lock_guard<util::recursive_mutex> lock(*local_mutex); | ||
|
||
m->erase(name_); | ||
} | ||
|
||
|
||
void ComparatorFactory::list(std::ostream& out) { | ||
util::call_once(once, init); | ||
util::lock_guard<util::recursive_mutex> lock(*local_mutex); | ||
|
||
const char* sep = ""; | ||
for (auto& j : *m) { | ||
out << sep << j.first; | ||
sep = ", "; | ||
} | ||
out << std::endl; | ||
} | ||
|
||
|
||
Comparator* ComparatorFactory::build(const std::string& name, const Parametrisation& param1, | ||
const Parametrisation& param2) { | ||
util::call_once(once, init); | ||
util::lock_guard<util::recursive_mutex> lock(*local_mutex); | ||
|
||
Log::debug() << "ComparatorFactory: looking for '" << name << "'" << std::endl; | ||
|
||
auto j = m->find(name); | ||
if (j == m->end()) { | ||
list(Log::error() << "ComparatorFactory: unknown '" << name << "', choices are: "); | ||
throw SeriousBug("ComparatorFactory: unknown '" + name + "'"); | ||
} | ||
|
||
return j->second->make(param1, param2); | ||
} | ||
|
||
|
||
} // namespace eckit::stats |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* (C) Copyright 1996- ECMWF. | ||
* | ||
* This software is licensed under the terms of the Apache Licence Version 2.0 | ||
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* In applying this licence, ECMWF does not waive the privileges and immunities | ||
* granted to it by virtue of its status as an intergovernmental organisation nor | ||
* does it submit to any jurisdiction. | ||
*/ | ||
|
||
|
||
#pragma once | ||
|
||
#include <iosfwd> | ||
#include <string> | ||
|
||
|
||
namespace eckit { | ||
class Parametrisation; | ||
namespace stats { | ||
class Field; | ||
} | ||
} // namespace eckit | ||
|
||
|
||
namespace eckit::stats { | ||
|
||
|
||
class Comparator { | ||
public: | ||
// -- Constructors | ||
|
||
Comparator(const Parametrisation&, const Parametrisation&); | ||
Comparator(const Comparator&) = delete; | ||
|
||
// -- Destructor | ||
|
||
virtual ~Comparator(); | ||
|
||
// -- Operators | ||
|
||
void operator=(const Comparator&) = delete; | ||
|
||
// -- Methods | ||
|
||
virtual std::string execute(const Field&, const Field&) = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. std::string is a very non-obvious return type for a Comparator. Unless it is doing something weird. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed this sholuld change -- it is a list of reasons why a comparison failed, and if empty is it a successful comparison. I should bring in more (a lot more) semantics here. Good catch! |
||
|
||
protected: | ||
// -- Members | ||
|
||
const Parametrisation& parametrisation1_; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels a touch dangerous. For general use, can we be confident that the supplied Parametrisation will outlive the Comparator instance? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, I'm not happy about this. Currently the Comparator is a class supporting comparing two statistics (say mean of two fields), but its use is quite specific to pgen-compare fields1 fields2 (which is in fact mir-compare). I probably should take the Comparator hierarchy out? I don't see that MultIO would use this. |
||
const Parametrisation& parametrisation2_; | ||
|
||
// -- Methods | ||
|
||
virtual void print(std::ostream&) const = 0; | ||
|
||
private: | ||
// -- Friends | ||
|
||
friend std::ostream& operator<<(std::ostream& out, const Comparator& r) { | ||
r.print(out); | ||
return out; | ||
} | ||
}; | ||
|
||
|
||
class ComparatorFactory { | ||
std::string name_; | ||
virtual Comparator* make(const Parametrisation&, const Parametrisation&) = 0; | ||
|
||
ComparatorFactory(const ComparatorFactory&) = delete; | ||
ComparatorFactory& operator=(const ComparatorFactory&) = delete; | ||
|
||
protected: | ||
ComparatorFactory(const std::string&); | ||
virtual ~ComparatorFactory(); | ||
|
||
public: | ||
static void list(std::ostream&); | ||
static Comparator* build(const std::string&, const Parametrisation&, const Parametrisation&); | ||
}; | ||
|
||
|
||
template <class T> | ||
class ComparatorBuilder : public ComparatorFactory { | ||
Comparator* make(const Parametrisation& param1, const Parametrisation& param2) override { | ||
return new T(param1, param2); | ||
} | ||
|
||
public: | ||
ComparatorBuilder(const std::string& name) : ComparatorFactory(name) {} | ||
}; | ||
|
||
|
||
} // namespace eckit::stats |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* (C) Copyright 1996- ECMWF. | ||
* | ||
* This software is licensed under the terms of the Apache Licence Version 2.0 | ||
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* In applying this licence, ECMWF does not waive the privileges and immunities | ||
* granted to it by virtue of its status as an intergovernmental organisation nor | ||
* does it submit to any jurisdiction. | ||
*/ | ||
|
||
|
||
#include "eckit/stats/Distribution.h" | ||
|
||
#include <map> | ||
#include <sstream> | ||
|
||
#include "eckit/config/YAMLConfiguration.h" | ||
#include "eckit/exception/Exceptions.h" | ||
#include "eckit/log/Log.h" | ||
#include "eckit/stats/util/Mutex.h" | ||
|
||
|
||
namespace eckit::stats { | ||
|
||
|
||
static util::once_flag once; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment RE instance() method rather than static global variables. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed -- maybe factories refactoring come first though. |
||
static util::recursive_mutex* local_mutex = nullptr; | ||
static std::map<std::string, DistributionFactory*>* m = nullptr; | ||
static void init() { | ||
local_mutex = new util::recursive_mutex(); | ||
m = new std::map<std::string, DistributionFactory*>(); | ||
} | ||
|
||
|
||
Distribution::Distribution() = default; | ||
|
||
|
||
Distribution::~Distribution() = default; | ||
|
||
|
||
DistributionFactory::DistributionFactory(const std::string& name) : name_(name) { | ||
util::call_once(once, init); | ||
util::lock_guard<util::recursive_mutex> lock(*local_mutex); | ||
|
||
if (m->find(name) != m->end()) { | ||
std::ostringstream oss; | ||
oss << "DistributionFactory: duplicate '" << name << "'"; | ||
throw SeriousBug(oss.str()); | ||
} | ||
|
||
(*m)[name] = this; | ||
} | ||
|
||
|
||
DistributionFactory::~DistributionFactory() { | ||
util::lock_guard<util::recursive_mutex> lock(*local_mutex); | ||
|
||
m->erase(name_); | ||
} | ||
|
||
|
||
Distribution* DistributionFactory::build(const std::string& name) { | ||
util::call_once(once, init); | ||
util::lock_guard<util::recursive_mutex> lock(*local_mutex); | ||
|
||
// parse <name>[{<yaml-arguments>}] (arguments are optional) | ||
auto braces = name.find('{'); | ||
ASSERT(braces == std::string::npos || name.back() == '}'); | ||
|
||
auto key = name.substr(0, braces); | ||
auto yaml = name.substr(braces); | ||
|
||
Log::debug() << "DistributionFactory: looking for '" << key << "'" << std::endl; | ||
|
||
if (auto j = m->find(key); j != m->end()) { | ||
return j->second->make(YAMLConfiguration{yaml}); | ||
} | ||
|
||
list(Log::error() << "DistributionFactory: unknown '" << key << "', choices are: "); | ||
Log::warning() << std::endl; | ||
} | ||
|
||
|
||
void DistributionFactory::list(std::ostream& out) { | ||
util::call_once(once, init); | ||
util::lock_guard<util::recursive_mutex> lock(*local_mutex); | ||
|
||
const char* sep = ""; | ||
for (const auto& j : *m) { | ||
out << sep << j.first; | ||
sep = ", "; | ||
} | ||
} | ||
|
||
|
||
} // namespace eckit::stats |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to be a recursive_mutex?
Can we not use the idiom, used elsewhere, with a static instance() method on the Factory type, and the mutex/map being local members. It's a bit cleaner than using posix once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a wrapper around the eckit types that have been superceded by stl; There's a define above that controls this, and I've put it in one place only so it's easy to change.
I called it recursive mutex because that's what the stl calls it, and what the eckit::Mutex really is. But this can of course change, at the moment this is only for controlling access to the factories. On that note, the factories could move to a eckit-based implementation -- which I recently changed to behave correctly for concurrent access, but the change is non-trivial. I think this is what should likely happen first? In any case, happy to update