Skip to content

Commit

Permalink
Improve and clean up MultiField
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrdar authored and wdeconinck committed Oct 7, 2024
1 parent 39ee651 commit 83cd8cd
Show file tree
Hide file tree
Showing 17 changed files with 1,412 additions and 410 deletions.
8 changes: 8 additions & 0 deletions src/atlas/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -476,12 +476,20 @@ field/MissingValue.cc
field/MissingValue.h
field/MultiField.cc
field/MultiField.h
field/MultiFieldCreator.cc
field/MultiFieldCreator.h
field/MultiFieldCreatorIFS.cc
field/MultiFieldCreatorIFS.h
field/MultiFieldCreatorArray.cc
field/MultiFieldCreatorArray.h
field/State.cc
field/State.h
field/detail/FieldImpl.cc
field/detail/FieldImpl.h
field/detail/FieldInterface.cc
field/detail/FieldInterface.h
field/detail/MultiFieldImpl.cc
field/detail/MultiFieldImpl.h
field/detail/MultiFieldInterface.cc
field/detail/MultiFieldInterface.h
field/detail/MissingValue.cc
Expand Down
95 changes: 35 additions & 60 deletions src/atlas/field/MultiField.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,75 +8,24 @@
* nor does it submit to any jurisdiction.
*/

#include "MultiField.h"
#include "atlas/field/MultiField.h"

#include <iomanip>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <mutex>

#include "atlas/field/Field.h"
#include "atlas/grid/Grid.h"
#include "atlas/mesh/Mesh.h"
#include "atlas/field/MultiFieldCreator.h"
#include "atlas/field/detail/MultiFieldImpl.h"
#include "atlas/runtime/Exception.h"
#include "atlas/runtime/Log.h"

namespace atlas {
namespace field {

namespace {
void force_link() {
static struct Link {
Link() {
;
// For static linking add here something like
// MultiFieldCreatorBuilder<T>();
}
} link;
}
} // namespace

//-----------------------------------------------------------------------------

class MultiFieldArrayRegistry : public field::FieldObserver {
private:
MultiFieldArrayRegistry() {}

public:
static MultiFieldArrayRegistry& instance() {
static MultiFieldArrayRegistry inst;
return inst;
}
void onFieldDestruction(FieldImpl& field) override {
std::lock_guard<std::mutex> guard(lock_);
map_.erase(&field);
}

~MultiFieldArrayRegistry() override = default;

void add(Field& field, std::shared_ptr<array::Array> array) {
std::lock_guard<std::mutex> guard(lock_);
map_.emplace(field.get(),array);
field->attachObserver(*this);
}

public:
std::mutex lock_;
std::map<FieldImpl*,std::shared_ptr<array::Array>> map_;

};

MultiFieldCreator::MultiFieldCreator(const eckit::Configuration&) {}

MultiFieldCreator::~MultiFieldCreator() = default;

MultiFieldCreator* MultiFieldCreatorFactory::build(const std::string& builder, const eckit::Configuration& config) {
force_link();
auto factory = get(builder);
return factory->make(config);
}

MultiField::MultiField(const eckit::Configuration& config) {
std::string type;
if (!config.get("type", type)) {
Expand All @@ -86,13 +35,39 @@ MultiField::MultiField(const eckit::Configuration& config) {
reset(creator->create(config));
}

void MultiFieldImpl::add(Field& field) {
ATLAS_ASSERT(not fieldset_.has(field.name()), "Field with name \"" + field.name() + "\" already exists!");
fieldset_.add(field);
MultiFieldArrayRegistry::instance().add(field,array_);

MultiField::MultiField(const array::DataType datatype, const std::vector<int>& shape,
const std::vector<std::string>& var_names) {
std::unique_ptr<MultiFieldCreator> creator(MultiFieldCreatorFactory::build("MultiFieldCreatorArray"));
reset(creator->create(datatype, shape, var_names));
}

const Field& MultiField::field(const std::string& name) const { return get()->field(name); }
Field& MultiField::field(const std::string& name) { return get()->field(name); }
bool MultiField::has(const std::string& name) const { return get()->has(name); }
std::vector<std::string> MultiField::field_names() const { return get()->field_names(); }

const Field& MultiField::field(const idx_t idx) const { return get()->field(idx); }
Field& MultiField::field(const idx_t idx) { return get()->field(idx); }
idx_t MultiField::size() const { return get()->size(); }

const Field& MultiField::operator[](const idx_t idx) const { return get()->field(idx); }
Field& MultiField::operator[](const idx_t idx) { return get()->field(idx); }

const Field& MultiField::operator[](const std::string& name) const { return get()->field(name); }
Field& MultiField::operator[](const std::string& name) { return get()->field(name); }

const util::Metadata& MultiField::metadata() const { return get()->metadata(); }
util::Metadata& MultiField::metadata() { return get()->metadata(); }

MultiField::operator const array::Array&() const { return get()->array(); }
MultiField::operator array::Array&() { return get()->array(); }

MultiField::operator const FieldSet&() const { return get()->fieldset_; }
MultiField::operator FieldSet&() { return get()->fieldset_; }

const array::Array& MultiField::array() const { return get()->array(); }
array::Array& MultiField::array() { return get()->array(); }

//-----------------------------------------------------------------------------

} // namespace field
Expand Down
167 changes: 53 additions & 114 deletions src/atlas/field/MultiField.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ namespace eckit {
class Parametrisation;
}

namespace atlas {
namespace field {
class MultiFieldImpl;
}
}

namespace atlas {
namespace field {

Expand All @@ -41,150 +47,83 @@ namespace field {
* Fields have to all be of same memory layout and data type
*/

class MultiFieldImpl : public util::Object {
public: // methods
//-- Constructors

MultiFieldImpl() { }

MultiFieldImpl(const array::ArraySpec& spec) {
array::ArraySpec s(spec);
array_.reset(array::Array::create(std::move(s)));
}

virtual ~MultiFieldImpl() {}


//-- Accessors

const Field& field(const std::string& name) const { return fieldset_.field(name); }
Field& field(const std::string& name) { return fieldset_.field(name); }
bool has(const std::string& name) const { return fieldset_.has(name); }
std::vector<std::string> field_names() const { return fieldset_.field_names(); }

const Field& field(const idx_t idx) const { return fieldset_[idx]; }
Field& field(const idx_t idx) { return fieldset_[idx]; }
idx_t size() const { return fieldset_.size(); }

const Field& operator[](const idx_t idx) const { return fieldset_[idx]; }
Field& operator[](const idx_t idx) { return fieldset_[idx]; }

const Field& operator[](const std::string& name) const { return fieldset_.field(name); }
Field& operator[](const std::string& name) { return fieldset_.field(name); }

const util::Metadata& metadata() const { return metadata_; }
util::Metadata& metadata() { return metadata_; }

// -- Modifiers

/// @brief Implicit conversion to Array
operator const array::Array&() const { return array(); }
operator array::Array&() { return array(); }

operator const FieldSet&() const { return fieldset_; }

operator FieldSet&() { return fieldset_; }

/// @brief Access contained Array
const array::Array& array() const {
ATLAS_ASSERT(array_);
return *array_;
}
array::Array& array() {
ATLAS_ASSERT(array_);
return *array_;
}

/// @brief Access contained FieldSet
const FieldSet& fieldset() const { return fieldset_; }
FieldSet& fieldset() { return fieldset_; }

void add(Field& field);

public: // temporary public for prototyping
FieldSet fieldset_;
std::shared_ptr<array::Array> array_;
util::Metadata metadata_;
};


class MultiField : public util::ObjectHandle<MultiFieldImpl> {
public: // methods
//-- Constructors
using Handle::Handle;

MultiField(const eckit::Configuration&);
MultiField(const array::DataType datatype, const std::vector<int>& shape,
const std::vector<std::string>& var_names);

//-- Accessors

const Field& field(const std::string& name) const { return get()->field(name); }
Field& field(const std::string& name) { return get()->field(name); }
bool has(const std::string& name) const { return get()->has(name); }
std::vector<std::string> field_names() const { return get()->field_names(); }
const Field& field(const std::string& name) const;
Field& field(const std::string& name);
bool has(const std::string& name) const;
std::vector<std::string> field_names() const;

const Field& field(const idx_t idx) const { return get()->field(idx); }
Field& field(const idx_t idx) { return get()->field(idx); }
idx_t size() const { return get()->size(); }
const Field& field(const idx_t idx) const;
Field& field(const idx_t idx);
idx_t size() const;

const Field& operator[](const idx_t idx) const { return get()->field(idx); }
Field& operator[](const idx_t idx) { return get()->field(idx); }
const Field& operator[](const idx_t idx) const;
Field& operator[](const idx_t idx);

const Field& operator[](const std::string& name) const { return get()->field(name); }
Field& operator[](const std::string& name) { return get()->field(name); }
const Field& operator[](const std::string& name) const;
Field& operator[](const std::string& name);

const util::Metadata& metadata() const { return get()->metadata(); }
util::Metadata& metadata() { return get()->metadata(); }
const util::Metadata& metadata() const;
util::Metadata& metadata();

// -- Modifiers

/// @brief Implicit conversion to Array
operator const array::Array&() const { return get()->array(); }
operator array::Array&() { return get()->array(); }
operator const array::Array&() const;
operator array::Array&();

operator const FieldSet&() const { return get()->fieldset_; }
operator FieldSet&() { return get()->fieldset_; }
operator const FieldSet&() const;
operator FieldSet&();

/// @brief Access contained Array
const array::Array& array() const { return get()->array(); }
array::Array& array() { return get()->array(); }
const array::Array& array() const;
array::Array& array();

private:
template<typename datatype>
void create(const std::vector<int> shape, const std::vector<std::string> var_names);
};

/**
* \brief MultiFieldArrayRegistry
*/

//------------------------------------------------------------------------------------------------------
class MultiFieldArrayRegistry : public field::FieldObserver {
private:
MultiFieldArrayRegistry() {}

class MultiFieldCreator : public util::Object {
public:
MultiFieldCreator(const eckit::Configuration& = util::Config());

virtual ~MultiFieldCreator();
static MultiFieldArrayRegistry& instance() {
static MultiFieldArrayRegistry inst;
return inst;
}
void onFieldDestruction(FieldImpl& field) override {
std::lock_guard<std::mutex> guard(lock_);
map_.erase(&field);
}

virtual MultiFieldImpl* create(const eckit::Configuration& = util::Config()) const = 0;
};
~MultiFieldArrayRegistry() override = default;

//------------------------------------------------------------------------------------------------------
void add(Field& field, std::shared_ptr<array::Array> array) {
std::lock_guard<std::mutex> guard(lock_);
map_.emplace(field.get(), array);
field->attachObserver(*this);
}

class MultiFieldCreatorFactory : public util::Factory<MultiFieldCreatorFactory> {
public:
static std::string className() { return "MultiFieldCreatorFactory"; }

/*!
* \brief build MultiFieldCreator with options specified in parametrisation
* \return MutliField creator
*/
static MultiFieldCreator* build(const std::string&, const eckit::Configuration& = util::NoConfig());
std::mutex lock_;
std::map<FieldImpl*,std::shared_ptr<array::Array>> map_;

using Factory::Factory;

private:
virtual MultiFieldCreator* make(const eckit::Configuration&) = 0;
};

template <class T>
class MultiFieldCreatorBuilder : public MultiFieldCreatorFactory {
virtual MultiFieldCreator* make(const eckit::Configuration& config) override { return new T(config); }

public:
using MultiFieldCreatorFactory::MultiFieldCreatorFactory;
};

// ------------------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit 83cd8cd

Please sign in to comment.