14 #include "ioda/distribution/InefficientDistribution.h"
15 #include "ioda/ObsSpace.h"
23 template <
typename VariableType>
25 const std::string &group,
const std::string &variable,
26 const ioda::ObsSpace &obsdb,
const ioda::Distribution &obsDistribution) {
27 std::vector<VariableType> result(obsdb.nlocs());
28 obsdb.get_db(group, variable, result);
29 obsDistribution.allGatherv(result);
36 const std::vector<size_t> &validObsIds) {
37 std::vector<T> validObsCategories(validObsIds.size());
38 for (
size_t validObsIndex = 0; validObsIndex < validObsIds.size(); ++validObsIndex) {
39 validObsCategories[validObsIndex] = categories[validObsIds[validObsIndex]];
41 return validObsCategories;
44 template <
typename VariableType>
47 const std::vector<size_t> &validObsIds,
48 const ioda::ObsSpace &obsdb,
49 const ioda::Distribution &obsDistribution,
51 std::vector<VariableType> obsCategories(obsdb.nlocs());
52 obsdb.get_db(variable.
group(), variable.
variable(), obsCategories);
53 obsDistribution.allGatherv(obsCategories);
56 obsCategories, validObsIds);
58 splitter.
groupBy(validObsCategories);
65 boost::optional<Variable> categoryVariable)
66 : obsdb_(&obsdb), groupBy_(groupBy), categoryVariable_(categoryVariable)
75 eckit::LocalConfiguration emptyConfig;
78 oops::Log::trace() <<
"ObservationAccessor: no MPI communication necessary" << std::endl;
85 const ioda::ObsSpace &obsdb) {
90 const ioda::ObsSpace &obsdb) {
95 const ioda::ObsSpace &obsdb,
const Variable &variable) {
101 const ufo::Variables &filtervars,
bool validIfAnyFilterVariablePassedQC)
const {
103 std::vector<int> globalApply(apply.size());
104 std::vector<ioda::ObsDataRow<int>> filterVariableFlags;
106 for (
size_t ivar = 0; ivar < filtervars.
nvars(); ++ivar) {
108 auto it = std::find(flags.varnames().variables().begin(), flags.varnames().variables().end(),
110 filterVariableFlags.push_back(flags[*it]);
112 for (
size_t obsId = 0; obsId < apply.size(); ++obsId)
113 globalApply[obsId] = apply[obsId]
114 &&
isValid(filterVariableFlags, obsId, validIfAnyFilterVariablePassedQC);
117 std::vector<size_t> validObsIds;
118 for (
size_t obsId = 0; obsId < globalApply.size(); ++obsId)
119 if (globalApply[obsId])
120 validObsIds.push_back(obsId);
126 const std::vector<bool> &apply)
const {
128 std::vector<int> globalApply(apply.begin(), apply.end());
131 std::vector<size_t> validObsIds;
132 for (
size_t obsId = 0; obsId < globalApply.size(); ++obsId)
133 if (globalApply[obsId])
134 validObsIds.push_back(obsId);
140 const std::string &group,
const std::string &variable)
const {
145 const std::string &group,
const std::string &variable)
const {
150 const std::string &group,
const std::string &variable)
const {
155 const std::string &group,
const std::string &variable)
const {
160 const std::string &group,
const std::string &variable)
const {
165 std::vector<size_t> recordIds =
obsdb_->recnum();
171 return obsdb_->globalNumLocs();
175 bool validIfAnyFilterVariablePassedQC)
const {
177 if (validIfAnyFilterVariablePassedQC) {
178 obIsNotFlagged =
false;
179 for (
size_t irow = 0; irow < flags.size(); ++irow) {
181 obIsNotFlagged =
true;
186 obIsNotFlagged =
true;
187 for (
size_t irow = 0; irow < flags.size(); ++irow) {
189 obIsNotFlagged =
false;
194 return obIsNotFlagged;
198 const std::vector<size_t> &validObsIds,
bool opsCompatibilityMode)
const {
216 const std::vector<size_t> &obsCategories =
obsdb_->recnum();
218 obsCategories, validObsIds);
219 splitter.
groupBy(validObsCategories);
223 const std::vector<size_t> &validObsIds,
226 case ioda::ObsDtype::Integer:
231 case ioda::ObsDtype::String:
237 throw eckit::UserError(
239 " is neither an integer nor a string variable", Here());
244 const std::vector<bool> &isRejected, std::vector<std::vector<bool> > &flagged)
const {
245 const size_t localNumObs =
obsdb_->nlocs();
246 for (
const std::vector<bool> & variableFlagged : flagged)
247 ASSERT(variableFlagged.size() == localNumObs);
249 for (
size_t localObsId = 0; localObsId < localNumObs; ++localObsId) {
250 const size_t globalObsId =
252 if (isRejected[globalObsId]) {
253 for (std::vector<bool> & variableFlagged : flagged)
254 variableFlagged[localObsId] =
true;
260 std::vector<std::string> groupingVars =
obsdb_->obs_group_vars();
261 std::string groupingVar;
262 if (groupingVars.size() > 0) {
263 groupingVar = groupingVars[0];
This class provides access to observations that may be held on multiple MPI ranks.
RecursiveSplitter splitObservationsIntoIndependentGroups(const std::vector< size_t > &validObsIds, bool opsCompatibilityMode=false) const
std::vector< std::string > getStringVariableFromObsSpace(const std::string &group, const std::string &variable) const
std::vector< size_t > getValidObservationIds(const std::vector< bool > &apply, const ioda::ObsDataVector< int > &flags, const Variables &filtervars, bool validIfAnyFilterVariablePassedQC=true) const
Return the IDs of observation locations that should be treated as valid by a filter.
std::vector< int > getIntVariableFromObsSpace(const std::string &group, const std::string &variable) const
Return the values of the specified variable at successive observation locations.
static ObsAccessor toObservationsSplitIntoIndependentGroupsByRecordId(const ioda::ObsSpace &obsdb)
Create an accessor to the collection of observations held in obsdb, assuming that each record can be ...
void groupObservationsByCategoryVariable(const std::vector< size_t > &validObsIds, RecursiveSplitter &splitter) const
const ioda::ObsSpace * obsdb_
static ObsAccessor toAllObservations(const ioda::ObsSpace &obsdb)
Create an accessor to observations from the observation space obsdb, assuming that the whole set of o...
boost::optional< Variable > categoryVariable_
std::vector< size_t > getRecordIds() const
Return the vector of IDs of records successive observation locations belong to.
static ObsAccessor toObservationsSplitIntoIndependentGroupsByVariable(const ioda::ObsSpace &obsdb, const Variable &variable)
Create an accessor to the collection of observations held in obsdb, assuming that observations with d...
std::vector< float > getFloatVariableFromObsSpace(const std::string &group, const std::string &variable) const
ObsAccessor(const ObsAccessor &)=delete
void groupObservationsByRecordNumber(const std::vector< size_t > &validObsIds, RecursiveSplitter &splitter) const
bool wereRecordsGroupedByCategoryVariable() const
std::vector< util::DateTime > getDateTimeVariableFromObsSpace(const std::string &group, const std::string &variable) const
void flagRejectedObservations(const std::vector< bool > &isRejected, std::vector< std::vector< bool > > &flagged) const
Update flags of observations held on the current MPI rank.
bool isValid(const std::vector< ioda::ObsDataRow< int >> &flags, size_t ObsId, bool validIfAnyFilterVariablePassedQC) const
Return true if filtered variable(s) have passed QC, otherwise false.
std::shared_ptr< const ioda::Distribution > obsDistribution_
std::vector< double > getDoubleVariableFromObsSpace(const std::string &group, const std::string &variable) const
size_t totalNumObservations() const
Partitions an array into groups of elements equivalent according to certain criteria.
void groupBy(const std::vector< size_t > &categories)
Split existing equivalence classes according to a new criterion.
const std::string & variable() const
const std::string & group() const
size_t nvars() const
Return the number of constituent "primitive" (single-channel) variables.
Variable variable(const size_t) const
Return a given constituent "primitive" (single-channel) variable.
std::vector< VariableType > getVariableFromObsSpaceImpl(const std::string &group, const std::string &variable, const ioda::ObsSpace &obsdb, const ioda::Distribution &obsDistribution)
void groupObservationsByVariableImpl(const Variable &variable, const std::vector< size_t > &validObsIds, const ioda::ObsSpace &obsdb, const ioda::Distribution &obsDistribution, RecursiveSplitter &splitter)
std::vector< T > getValidObservationCategories(const std::vector< T > &categories, const std::vector< size_t > &validObsIds)
Return the vector of elements of categories with indices validObsIds.