Skip to content
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

Add MultiField to pack field allocations #229

Merged
merged 7 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/atlas/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -474,12 +474,24 @@ field/FieldSet.cc
field/FieldSet.h
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
field/detail/MissingValue.h
)
Expand Down
74 changes: 74 additions & 0 deletions src/atlas/field/MultiField.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* (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.
*/

#include "atlas/field/MultiField.h"

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

#include "atlas/field/MultiFieldCreator.h"
#include "atlas/field/detail/MultiFieldImpl.h"
#include "atlas/runtime/Exception.h"

namespace atlas {
namespace field {

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

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));
}

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
} // namespace atlas
132 changes: 132 additions & 0 deletions src/atlas/field/MultiField.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* (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.
*/

/// @author Willem Deconinck
/// @date June 2015

#pragma once

#include <map>
#include <vector>

#include "atlas/array/Array.h"
#include "atlas/field/Field.h"
#include "atlas/field/FieldSet.h"
#include "atlas/util/Config.h"
#include "atlas/util/Factory.h"
#include "atlas/util/Metadata.h"
#include "atlas/util/Object.h"
#include "atlas/util/ObjectHandle.h"

namespace eckit {
class Parametrisation;
}

namespace atlas {
namespace field {
class MultiFieldImpl;
}
}

namespace atlas {
namespace field {

/**
* \brief MultiField class that owns a collection of fields that are co-allocated
*
* Fields can only be described by parametrisation during the construction.
* Once setup, no additional fields can be added.
*
* Fields have to all be of same memory layout and data type
*/

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;
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;
Field& field(const idx_t idx);
idx_t size() const;

const Field& operator[](const idx_t idx) const;
Field& operator[](const idx_t idx);

const Field& operator[](const std::string& name) const;
Field& operator[](const std::string& name);

const util::Metadata& metadata() const;
util::Metadata& metadata();

// -- Modifiers

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

operator const FieldSet&() const;
operator FieldSet&();

/// @brief Access contained 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() {}

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_;

};

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

} // namespace field
} // namespace atlas
58 changes: 58 additions & 0 deletions src/atlas/field/MultiFieldCreator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* (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 "eckit/thread/AutoLock.h"
#include "eckit/thread/Mutex.h"

#include "atlas/field/MultiFieldCreatorIFS.h"
#include "atlas/field/MultiFieldCreatorArray.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>();
MultiFieldCreatorBuilder<MultiFieldCreatorArray>();
}
} 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);
}

} // namespace field
} // namespace atlas
89 changes: 89 additions & 0 deletions src/atlas/field/MultiFieldCreator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* (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.
*/

#ifndef atlas_field_MultiFieldCreator_h
#define atlas_field_MultiFieldCreator_h

#include <string>

#include "atlas/util/Object.h"

#include "atlas/field/MultiField.h"

namespace eckit {
class Configuration;
}

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

namespace atlas {
namespace field {

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

/*!
* \brief Base class for creating new multifields based on Configuration
*
* \details
* Example to create field[100][3] of default type double:
* \code{.cpp}
* FieldImpl* field = Field::create(
* Config
* ("creator","ArraySpec") // ArraySpec MultiFieldCreator
* ("shape",array::make_shape(100,3)) // Rank 2 field with indexing [100][3]
* );
* \endcode
*/
class MultiFieldCreator : public util::Object {
public:
MultiFieldCreator();
MultiFieldCreator(const eckit::Configuration& config);

virtual ~MultiFieldCreator();

virtual MultiFieldImpl* create(const eckit::Configuration& config = util::Config()) const = 0;
virtual MultiFieldImpl* create(const array::DataType datatype, const std::vector<int>& shape,
const std::vector<std::string>& var_names) const = 0;
};

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

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

/*!
* \brief build MultiFieldCreator with options specified in parametrisation
* \return mesh generator
*/
static MultiFieldCreator* build(const std::string&, const eckit::Configuration& = util::Config());

using Factory::Factory;

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

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

public:
using MultiFieldCreatorFactory::MultiFieldCreatorFactory;
};

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

} // namespace field
} // namespace atlas

#endif
Loading
Loading