Skip to content

Commit

Permalink
restructure MultiField construction (with Willem)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrdar committed Sep 4, 2024
1 parent 33083ef commit 179e07d
Show file tree
Hide file tree
Showing 15 changed files with 760 additions and 405 deletions.
6 changes: 6 additions & 0 deletions src/atlas/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -470,12 +470,18 @@ 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/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
17 changes: 12 additions & 5 deletions src/atlas/field/FieldCreatorIFS.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,25 @@ FieldImpl* FieldCreatorIFS::createField(const eckit::Parametrisation& params) co
datatype = array::DataType(kind);
}

nblk = std::ceil(static_cast<double>(ngptot) / static_cast<double>(nproma));
nblk = std::ceil(static_cast<double>(ngptot + nproma - 1) / static_cast<double>(nproma));

array::ArrayShape s;
bool fortran(false);
params.get("fortran", fortran);
if (fortran) {
s = array::make_shape(nproma, nlev, nvar, nblk);
printf(" FieldCreatorIFS nlev, nvar: %zu, %zu", nlev, nvar);

if (nlev > 0 && nvar > 0) {
s = ( fortran ? array::make_shape(nproma, nlev, nvar, nblk) : array::make_shape(nblk, nvar, nlev, nproma) );
}
else if (nlev > 0) {
s = ( fortran ? array::make_shape(nproma, nlev, nblk) : array::make_shape(nblk, nlev, nproma) );
}
else if (nvar > 0) {
s = ( fortran ? array::make_shape(nproma, nvar, nblk) : array::make_shape(nblk, nvar, nproma) );
}
else {
s = array::make_shape(nblk, nvar, nlev, nproma);
s = ( fortran ? array::make_shape(nproma, nblk) : array::make_shape(nblk, nproma) );
}

std::string name;
params.get("name", name);
Log::debug() << "Creating IFS " << datatype.str() << " field: " << name << "[nblk=" << nblk << "][nvar=" << nvar
Expand Down
68 changes: 1 addition & 67 deletions src/atlas/field/MultiField.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* nor does it submit to any jurisdiction.
*/

#include "MultiField.h"
#include "MultiFieldCreator.h"

#include <iomanip>
#include <map>
Expand All @@ -25,74 +25,8 @@
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)) {
ATLAS_THROW_EXCEPTION("Could not find \"type\" in configuration");
}
std::unique_ptr<MultiFieldCreator> creator(MultiFieldCreatorFactory::build(type, 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_);

}

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

} // namespace field
Expand Down
118 changes: 23 additions & 95 deletions src/atlas/field/MultiField.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "atlas/array/Array.h"
#include "atlas/field/Field.h"
#include "atlas/field/FieldSet.h"
#include "atlas/field/detail/MultiFieldImpl.h"
#include "atlas/util/Config.h"
#include "atlas/util/Factory.h"
#include "atlas/util/Metadata.h"
Expand All @@ -41,73 +42,6 @@ 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, const eckit::Parametrisation& config = util::NoConfig()) {
array::ArraySpec s(spec);
array_.reset(array::Array::create(std::move(s), config));
}

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
Expand Down Expand Up @@ -149,42 +83,36 @@ class MultiField : public util::ObjectHandle<MultiFieldImpl> {
array::Array& array() { return get()->array(); }
};

/**
* \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());

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

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
68 changes: 68 additions & 0 deletions src/atlas/field/MultiFieldCreator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* (C) Copyright 2013 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.
*/

// file deepcode ignore CppMemoryLeak: static pointers for global registry are OK and will be cleaned up at end

#include "atlas/field/MultiFieldCreator.h"

#include <map>
#include <sstream>
#include <string>

#include "eckit/thread/AutoLock.h"
#include "eckit/thread/Mutex.h"

#include "atlas/field/MultiField.h"
#include "atlas/field/FieldCreatorArraySpec.h"
#include "atlas/field/MultiFieldCreatorIFS.h"
#include "atlas/grid/Grid.h"
#include "atlas/runtime/Exception.h"
#include "atlas/runtime/Log.h"


namespace atlas {
namespace field {


namespace {

void force_link() {
static struct Link {
Link() {
MultiFieldCreatorBuilder<MultiFieldCreatorIFS>();
}
} link;
}

} // namespace

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

MultiFieldCreator::MultiFieldCreator() = default;

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)) {
ATLAS_THROW_EXCEPTION("Could not find \"type\" in configuration");
}
std::unique_ptr<MultiFieldCreator> creator(MultiFieldCreatorFactory::build(type, config));
reset(creator->create(config));
}

} // namespace field
} // namespace atlas
Loading

0 comments on commit 179e07d

Please sign in to comment.