From 179e07dee6ca93afb8a796e5ef6d41add7b75d96 Mon Sep 17 00:00:00 2001 From: Slavko Brdar Date: Wed, 4 Sep 2024 17:59:15 +0200 Subject: [PATCH] restructure MultiField construction (with Willem) --- src/atlas/CMakeLists.txt | 6 + src/atlas/field/FieldCreatorIFS.cc | 17 +- src/atlas/field/MultiField.cc | 68 +----- src/atlas/field/MultiField.h | 118 ++------- src/atlas/field/MultiFieldCreator.cc | 68 ++++++ src/atlas/field/MultiFieldCreator.h | 87 +++++++ src/atlas/field/MultiFieldCreatorIFS.cc | 230 ++++++++++++++++++ src/atlas/field/MultiFieldCreatorIFS.h | 61 +++++ src/atlas/field/detail/FieldInterface.cc | 5 + src/atlas/field/detail/MultiFieldImpl.cc | 32 +++ src/atlas/field/detail/MultiFieldImpl.h | 96 ++++++++ src/atlas/field/detail/MultiFieldInterface.cc | 102 +------- .../field/atlas_MultiField_module.fypp | 63 +++++ src/tests/field/fctest_multifield_ifs.F90 | 97 ++++++-- src/tests/field/test_multifield_ifs.cc | 115 +-------- 15 files changed, 760 insertions(+), 405 deletions(-) create mode 100644 src/atlas/field/MultiFieldCreator.cc create mode 100644 src/atlas/field/MultiFieldCreator.h create mode 100644 src/atlas/field/MultiFieldCreatorIFS.cc create mode 100644 src/atlas/field/MultiFieldCreatorIFS.h create mode 100644 src/atlas/field/detail/MultiFieldImpl.cc create mode 100644 src/atlas/field/detail/MultiFieldImpl.h diff --git a/src/atlas/CMakeLists.txt b/src/atlas/CMakeLists.txt index 5c14da9db..47acd59de 100644 --- a/src/atlas/CMakeLists.txt +++ b/src/atlas/CMakeLists.txt @@ -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 diff --git a/src/atlas/field/FieldCreatorIFS.cc b/src/atlas/field/FieldCreatorIFS.cc index a15261c0c..d7279dc6d 100644 --- a/src/atlas/field/FieldCreatorIFS.cc +++ b/src/atlas/field/FieldCreatorIFS.cc @@ -55,18 +55,25 @@ FieldImpl* FieldCreatorIFS::createField(const eckit::Parametrisation& params) co datatype = array::DataType(kind); } - nblk = std::ceil(static_cast(ngptot) / static_cast(nproma)); + nblk = std::ceil(static_cast(ngptot + nproma - 1) / static_cast(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 diff --git a/src/atlas/field/MultiField.cc b/src/atlas/field/MultiField.cc index f7a3ba88d..9628de2a4 100644 --- a/src/atlas/field/MultiField.cc +++ b/src/atlas/field/MultiField.cc @@ -8,7 +8,7 @@ * nor does it submit to any jurisdiction. */ -#include "MultiField.h" +#include "MultiFieldCreator.h" #include #include @@ -25,74 +25,8 @@ namespace atlas { namespace field { -namespace { -void force_link() { - static struct Link { - Link() { - ; - // For static linking add here something like - // MultiFieldCreatorBuilder(); - } - } 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 guard(lock_); - map_.erase(&field); - } - - ~MultiFieldArrayRegistry() override = default; - - void add(Field& field, std::shared_ptr array) { - std::lock_guard guard(lock_); - map_.emplace(field.get(),array); - field->attachObserver(*this); - } - -public: - std::mutex lock_; - std::map> 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 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 diff --git a/src/atlas/field/MultiField.h b/src/atlas/field/MultiField.h index 52438a595..6228a4ca0 100644 --- a/src/atlas/field/MultiField.h +++ b/src/atlas/field/MultiField.h @@ -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" @@ -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 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_; - util::Metadata metadata_; -}; - - class MultiField : public util::ObjectHandle { public: // methods //-- Constructors @@ -149,42 +83,36 @@ class MultiField : public util::ObjectHandle { 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 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) { + std::lock_guard guard(lock_); + map_.emplace(field.get(), array); + field->attachObserver(*this); + } -class MultiFieldCreatorFactory : public util::Factory { 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> map_; -private: - virtual MultiFieldCreator* make(const eckit::Configuration&) = 0; -}; - -template -class MultiFieldCreatorBuilder : public MultiFieldCreatorFactory { - virtual MultiFieldCreator* make(const eckit::Configuration& config) override { return new T(config); } - -public: - using MultiFieldCreatorFactory::MultiFieldCreatorFactory; }; // ------------------------------------------------------------------------------------ diff --git a/src/atlas/field/MultiFieldCreator.cc b/src/atlas/field/MultiFieldCreator.cc new file mode 100644 index 000000000..06a368b0e --- /dev/null +++ b/src/atlas/field/MultiFieldCreator.cc @@ -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 +#include +#include + +#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(); + } + } 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 creator(MultiFieldCreatorFactory::build(type, config)); + reset(creator->create(config)); +} + +} // namespace field +} // namespace atlas diff --git a/src/atlas/field/MultiFieldCreator.h b/src/atlas/field/MultiFieldCreator.h new file mode 100644 index 000000000..0984d1bbd --- /dev/null +++ b/src/atlas/field/MultiFieldCreator.h @@ -0,0 +1,87 @@ +/* + * (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 + +#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; +}; + +//------------------------------------------------------------------------------------------------------ + +class MultiFieldCreatorFactory : public util::Factory { +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 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 diff --git a/src/atlas/field/MultiFieldCreatorIFS.cc b/src/atlas/field/MultiFieldCreatorIFS.cc new file mode 100644 index 000000000..cd76658a8 --- /dev/null +++ b/src/atlas/field/MultiFieldCreatorIFS.cc @@ -0,0 +1,230 @@ +/* + * (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, Slavko Brdar +/// @date June 2024 + +#include "atlas/field/MultiFieldCreatorIFS.h" + +#include +#include + +#include "eckit/config/Parametrisation.h" + +#include "atlas/array/ArrayDataStore.h" +#include "atlas/array/DataType.h" +#include "atlas/field/detail/FieldImpl.h" +#include "atlas/grid/Grid.h" +#include "atlas/runtime/Exception.h" +#include "atlas/runtime/Log.h" + +namespace atlas { +namespace field { + +MultiFieldImpl* MultiFieldCreatorIFS::create(const eckit::Configuration& config) const { + long nproma; + config.get("nproma", nproma); + long nlev; + config.get("nlev", nlev); + long nblk = 0; + if (config.has("nblk")) { + config.get("nblk", nblk); + } + else if (config.has("ngptot")) { + long ngptot; + config.get("ngptot", ngptot); + nblk = std::ceil(static_cast(ngptot) / static_cast(nproma)); + } + else { + ATLAS_THROW_EXCEPTION("Configuration not found: ngptot or nblk"); + } + array::DataType datatype = array::DataType::create(); + std::string datatype_str; + if (config.get("datatype", datatype_str)) { + datatype = array::DataType(datatype_str); + } + else { + array::DataType::kind_t kind(array::DataType::kind()); + config.get("kind", kind); + if (!array::DataType::kind_valid(kind)) { + std::stringstream msg; + msg << "Could not create field. kind parameter unrecognized"; + throw_Exception(msg.str()); + } + datatype = array::DataType(kind); + } + + auto fields = config.getSubConfigurations("fields"); + long nfld = 0; + for (const auto& field_params : fields) { + long nvar = 1; + field_params.get("nvar", nvar); + nfld += nvar; + } + array::ArrayShape multiarray_shape = ( (nlev > 0 and nfld > 0) ? array::make_shape(nblk, nfld, nlev, nproma) : + ( (nlev > 0) ? array::make_shape(nblk, nlev, nproma) : ( (nfld > 0) ? array::make_shape(nblk, nfld, nproma) : + array::make_shape(nblk, nproma) ) ) ); + + std::cout << "nfld: " << nfld << std::endl; + + MultiFieldImpl* multifield = new MultiFieldImpl{array::ArraySpec{datatype, multiarray_shape}, config}; + auto& multiarray = multifield->array(); + + size_t multiarray_field_idx = 0; + for (size_t i = 0; i < fields.size(); ++i) { + std::string name; + fields[i].get("name", name); + Field field; + size_t field_vars = 1; + std::cout << i << ". nvar: " << name << std::endl; + + if (fields[i].get("nvar", field_vars)) { + std::cout << i << ". nvar: " << field_vars << std::endl; + array::ArrayShape field_shape = + ( (nlev > 0 and field_vars > 0) ? + array::make_shape(multiarray.shape(0), field_vars, multiarray.shape(2), multiarray.shape(3)) : + ( nlev > 0 ? + array::make_shape(multiarray.shape(0), multiarray.shape(1), multiarray.shape(2)) : + ( field_vars > 0 ? + array::make_shape(multiarray.shape(0), field_vars, multiarray.shape(2)) : + array::make_shape(multiarray.shape(0), multiarray.shape(1)) ) ) ); + array::ArrayShape multiarray_shape = + ( (nlev > 0 and field_vars > 0) ? array::make_shape(nblk, field_vars, nlev, nproma) : + ( (nlev > 0) ? array::make_shape(nblk, nlev, nproma) : ( (field_vars > 0) ? + array::make_shape(nblk, field_vars, nproma) : array::make_shape(nblk, nproma) ) ) ); + auto field_strides = multiarray.strides(); + auto field_array_spec = array::ArraySpec(field_shape, field_strides); + + constexpr auto all = array::Range::all(); + const auto range = array::Range(multiarray_field_idx, multiarray_field_idx + field_vars); + if (datatype.kind() == array::DataType::KIND_REAL64) { + if (nlev > 0 and field_vars > 0) { + auto slice = array::make_view(multiarray).slice(all, range, all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else if (nlev > 0) { + auto slice = array::make_view(multiarray).slice(all, all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else if (field_vars > 0) { + auto slice = array::make_view(multiarray).slice(all, range, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else { + auto slice = array::make_view(multiarray).slice(all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + } + else if (datatype.kind() == array::DataType::KIND_REAL32) { + if (nlev > 0 and field_vars > 0) { + auto slice = array::make_view(multiarray).slice(all, range, all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else if (nlev > 0) { + auto slice = array::make_view(multiarray).slice(all, all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else if (field_vars > 0) { + auto slice = array::make_view(multiarray).slice(all, range, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else { + auto slice = array::make_view(multiarray).slice(all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + } + else { + ATLAS_NOTIMPLEMENTED; + } + field.set_variables(field_vars); + } + else { + std::cout << "multiarray.shape: " << multiarray.shape(0) << ", " << multiarray.shape(1) << ", " << multiarray.shape(2); + if (multiarray.shape().size() > 3) std::cout << ", " << multiarray.shape(3); + std::cout << std::endl; + std::cout << "multiarray.stride: " << multiarray.stride(0) << ", " << multiarray.stride(1) << ", " << multiarray.stride(2); + if (multiarray.strides().size() > 3) std::cout << ", " << multiarray.stride(3); + std::cout << std::endl; + std::cout << "multiarray.index: " << multiarray_field_idx << std::endl; + array::ArraySpec field_array_spec; + if (nlev > 0) { + auto field_shape = array::make_shape(multiarray.shape(0), multiarray.shape(2), multiarray.shape(3)); + auto field_strides = array::make_strides(multiarray.stride(0), multiarray.stride(2), multiarray.stride(3)); + field_array_spec = array::ArraySpec(field_shape, field_strides); + } + else if (field_vars > 0) { + auto field_shape = array::make_shape(multiarray.shape(0), multiarray.shape(2)); + auto field_strides = array::make_strides(multiarray.stride(0), multiarray.stride(2)); + field_array_spec = array::ArraySpec(field_shape, field_strides); + } + + constexpr auto all = array::Range::all(); + if (datatype.kind() == array::DataType::KIND_REAL64) { + if (nlev > 0 and field_vars > 0) { + auto slice = array::make_view(multiarray).slice(all, multiarray_field_idx, all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else if (nlev > 0) { + auto slice = array::make_view(multiarray).slice(all, all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else if (field_vars > 0) { + auto slice = array::make_view(multiarray).slice(all, multiarray_field_idx, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else { + auto slice = array::make_view(multiarray).slice(all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + } + else if (datatype.kind() == array::DataType::KIND_REAL32) { + if (nlev > 0 and field_vars > 0) { + auto slice = array::make_view(multiarray).slice(all, multiarray_field_idx, all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else if (nlev > 0) { + auto slice = array::make_view(multiarray).slice(all, all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else if (field_vars > 0) { + auto slice = array::make_view(multiarray).slice(all, multiarray_field_idx, all); + field = Field(name, slice.data(), field_array_spec, config); + } + else { + auto slice = array::make_view(multiarray).slice(all, all); + field = Field(name, slice.data(), field_array_spec, config); + } + } + else { + ATLAS_NOTIMPLEMENTED; + } + } + field.set_levels(nlev); + //field.set_blocks(nblk); + + multifield->add(field); + + multiarray_field_idx += field_vars; + } + std::string name; + config.get("name", name); + Log::debug() << "Creating IFS " << datatype.str() << " multifield: " << name << "[nblk=" << nblk << "][nvar=" << nfld + << "][nlev=" << nlev << "][nproma=" << nproma << "]\n"; + return multifield; +} + +// ------------------------------------------------------------------ + +namespace { +static MultiFieldCreatorBuilder __MultiFieldCreatorIFS("MultiFieldCreatorIFS"); +} + +} // namespace field +} // namespace atlas diff --git a/src/atlas/field/MultiFieldCreatorIFS.h b/src/atlas/field/MultiFieldCreatorIFS.h new file mode 100644 index 000000000..367f7ff0e --- /dev/null +++ b/src/atlas/field/MultiFieldCreatorIFS.h @@ -0,0 +1,61 @@ +/* + * (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 "atlas/field/MultiFieldCreator.h" + +namespace eckit { +class Configuration; +} +namespace atlas { +namespace field { +class MultiFieldImpl; +} +} // namespace atlas + +namespace atlas { +namespace field { + +// ------------------------------------------------------------------ + +/*! + * \brief MultiField creator using IFS parametrisation + * \details + * Ideally this class should belong to IFS. + * The only reference to IFS in Atlas::MultiField should be here. + * Example use: + * \code{.cpp} + * MultiFieldImpl* multifield = MultiField::create( + * Config + * ("creator","MultiFieldIFS") // MultiFieldIFS FieldCreator + * ("ngptot",ngptot) // Total number of grid points + * ("nproma",nproma) // Grouping of grid points for vectorlength + * ("nlev",nlev) // Number of levels + * ("nvar",nvar) // Number of variables + * ("kind",8) // Real kind in bytes + * ); + * \endcode + */ +class MultiFieldCreatorIFS : public MultiFieldCreator { +public: + MultiFieldCreatorIFS() {} + MultiFieldCreatorIFS(const eckit::Configuration& config) {} + ~MultiFieldCreatorIFS() override = default; + MultiFieldImpl* create(const eckit::Configuration& config = util::Config()) const override; +}; + +// ------------------------------------------------------------------ + +} // namespace field +} // namespace atlas diff --git a/src/atlas/field/detail/FieldInterface.cc b/src/atlas/field/detail/FieldInterface.cc index 2319f9974..8dea1b132 100644 --- a/src/atlas/field/detail/FieldInterface.cc +++ b/src/atlas/field/detail/FieldInterface.cc @@ -36,6 +36,9 @@ void atlas__Field__data_specf(FieldImpl* This, Value*& data, int& rank, int*& sh shapef = const_cast(This->shapef().data()); stridesf = const_cast(This->stridesf().data()); rank = This->shapef().size(); + printf("atlas__Field__data_specf :: rank: %i\n", rank); + printf("atlas__Field__data_specf :: shape: %i, %i, %i\n", shapef[0], shapef[1], shapef[2]); + if (rank > 3) printf(", %i", shapef[3]); } template @@ -195,10 +198,12 @@ void atlas__Field__data_long_specf(FieldImpl* This, long*& data, int& rank, int* void atlas__Field__data_float_specf(FieldImpl* This, float*& data, int& rank, int*& shapef, int*& stridesf) { atlas__Field__data_specf(This, data, rank, shapef, stridesf); + std::cout << "atlas__Field__data_float_specf :: rank = " << rank << std::endl; } void atlas__Field__data_double_specf(FieldImpl* This, double*& data, int& rank, int*& shapef, int*& stridesf) { atlas__Field__data_specf(This, data, rank, shapef, stridesf); + std::cout << "atlas__Field__data_double_specf :: rank = " << rank << std::endl; } void atlas__Field__device_data_int_specf(FieldImpl* This, int*& data, int& rank, int*& shapef, int*& stridesf) { diff --git a/src/atlas/field/detail/MultiFieldImpl.cc b/src/atlas/field/detail/MultiFieldImpl.cc new file mode 100644 index 000000000..c3a6abb73 --- /dev/null +++ b/src/atlas/field/detail/MultiFieldImpl.cc @@ -0,0 +1,32 @@ +/* + * (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/MultiField.h" +#include "atlas/field/MultiFieldCreator.h" + +#include +#include +#include + +#include "atlas/field/detail/MultiFieldImpl.h" + +namespace atlas { +namespace field { + +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_); +} + +} +} diff --git a/src/atlas/field/detail/MultiFieldImpl.h b/src/atlas/field/detail/MultiFieldImpl.h new file mode 100644 index 000000000..ec8284355 --- /dev/null +++ b/src/atlas/field/detail/MultiFieldImpl.h @@ -0,0 +1,96 @@ +/* + * (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 +#include + +#include "atlas/array/Array.h" +#include "atlas/field/Field.h" +#include "atlas/field/FieldSet.h" +#include "atlas/util/Config.h" +#include "atlas/util/Metadata.h" +#include "atlas/util/Object.h" + +namespace atlas { +namespace field { + +class MultiFieldImpl : public util::Object { +public: // methods + //-- Constructors + + MultiFieldImpl() { } + + MultiFieldImpl(const array::ArraySpec& spec, const eckit::Configuration& 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 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_; + util::Metadata metadata_; +}; + +} // namespace field +} // namespace atlas diff --git a/src/atlas/field/detail/MultiFieldInterface.cc b/src/atlas/field/detail/MultiFieldInterface.cc index 27a01c06a..7f8e05781 100644 --- a/src/atlas/field/detail/MultiFieldInterface.cc +++ b/src/atlas/field/detail/MultiFieldInterface.cc @@ -27,107 +27,9 @@ MultiFieldImpl* atlas__MultiField__create(eckit::Configuration* config) { // TODO: move __multiFieldCreatorIFS out of test_multifield_ifs.cc //MultiFieldCreatorBuilder __MultiFieldCreatorIFS("MultiFieldCreatorIFS"); - //MultiField* multifield = new MultiField(*config); - //return multifield->get(); - - // TODO - // repeat here the code for __multiFieldCreatorIFS out of test_multifield_ifs.cc - long nproma = config->getLong("nproma"); - long nlev = config->getLong("nlev"); - long nblk = 0; - if (config->has("nblk")) { - nblk = config->getLong("nblk"); - } - else if (config->has("ngptot")) { - long ngptot = config->getLong("ngptot"); - nblk = std::ceil(static_cast(ngptot) / static_cast(nproma)); - } - else { - ATLAS_THROW_EXCEPTION("Configuration not found: ngptot or nblk"); - } - array::DataType datatype = array::DataType::create(); - std::string datatype_str; - if (config->get("datatype", datatype_str)) { - datatype = array::DataType(datatype_str); - } - else { - array::DataType::kind_t kind(array::DataType::kind()); - config->get("kind", kind); - if (!array::DataType::kind_valid(kind)) { - std::stringstream msg; - msg << "Could not create field. kind parameter unrecognized"; - throw_Exception(msg.str()); - } - datatype = array::DataType(kind); - } - - auto fields = config->getSubConfigurations("fields"); - long nfld = 0; - for (const auto& field_config : fields) { - long nvar = 1; - field_config.get("nvar", nvar); - nfld += nvar; - } - auto multiarray_shape = array::make_shape(nblk, nfld, nlev, nproma); - - MultiFieldImpl* multifield = new MultiFieldImpl{array::ArraySpec{datatype, multiarray_shape}, *config}; - auto& multiarray = multifield->array(); - - size_t multiarray_field_idx = 0; - for (size_t i = 0; i < fields.size(); ++i) { - std::string name; - fields[i].get("name", name); - Field field; - size_t field_vars = 1; - - if (fields[i].get("nvar", field_vars)) { - auto field_shape = - array::make_shape(multiarray.shape(0), field_vars, multiarray.shape(2), multiarray.shape(3)); - auto field_strides = multiarray.strides(); - auto field_array_spec = array::ArraySpec(field_shape, field_strides); - - constexpr auto all = array::Range::all(); - const auto range = array::Range(multiarray_field_idx, multiarray_field_idx + field_vars); - if (datatype.kind() == array::DataType::KIND_REAL64) { - auto slice = array::make_view(multiarray).slice(all, range, all, all); - field = Field(name, slice.data(), field_array_spec, *config); - } - else if (datatype.kind() == array::DataType::KIND_REAL32) { - auto slice = array::make_view(multiarray).slice(all, range, all, all); - field = Field(name, slice.data(), field_array_spec, *config); - } - else { - ATLAS_NOTIMPLEMENTED; - } - field.set_variables(field_vars); - } - else { - auto field_shape = array::make_shape(multiarray.shape(0), multiarray.shape(2), multiarray.shape(3)); - auto field_strides = array::make_strides(multiarray.stride(0), multiarray.stride(2), multiarray.stride(3)); - auto field_array_spec = array::ArraySpec(field_shape, field_strides); - - constexpr auto all = array::Range::all(); - if (datatype.kind() == array::DataType::KIND_REAL64) { - auto slice = array::make_view(multiarray).slice(all, multiarray_field_idx, all, all); - field = Field(name, slice.data(), field_array_spec, *config); - } - else if (datatype.kind() == array::DataType::KIND_REAL32) { - auto slice = array::make_view(multiarray).slice(all, multiarray_field_idx, all, all); - field = Field(name, slice.data(), field_array_spec, *config); - } - else { - ATLAS_NOTIMPLEMENTED; - } - } - field.set_levels(nlev); - // field.set_blocks(nblk); - - multifield->add(field); - - multiarray_field_idx += field_vars; - } + auto multifield = new MultiField(*config); ATLAS_ASSERT(multifield); - return multifield; + return multifield->get(); } void atlas__MultiField__delete(MultiFieldImpl* This) { diff --git a/src/atlas_f/field/atlas_MultiField_module.fypp b/src/atlas_f/field/atlas_MultiField_module.fypp index 9c0e406b9..2bb78e77a 100644 --- a/src/atlas_f/field/atlas_MultiField_module.fypp +++ b/src/atlas_f/field/atlas_MultiField_module.fypp @@ -77,6 +77,8 @@ END TYPE interface atlas_MultiField module procedure atlas_MultiField__cptr module procedure atlas_MultiField__create + module procedure atlas_MultiField__create_names + !#:for dtype in integer_dtypes ! module procedure atlas_MultiField__create_name_kind_shape_${dtype}$ ! module procedure atlas_MultiField__create_kind_shape_${dtype}$ @@ -119,6 +121,67 @@ end function !------------------------------------------------------------------------------- +function atlas_MultiField__create_names(kind, shape, field_names, opt_config) result(field) + use atlas_multifield_c_binding + type(atlas_MultiField) :: field + character(*), intent(in) :: kind + integer, intent(in) :: shape(:) + character(*), intent(in) :: field_names(:) + type(atlas_Config), intent(in), optional :: opt_config + type(atlas_Config) :: config + type(atlas_Config), allocatable :: field_configs(:) + integer :: rank, i, ivar, nvar, nblk, nproma, field_idx, nlev + + if (size(field_names) == 0 .or. size(shape) < 3) then + print *, "atlas_MultiField__create_names: must have at least one field name, and the size of shape", & + & " is minimum 3, e.g. [nproma,-1,nblk]" + stop -1 + end if + + if (present(opt_config)) then + config = opt_config + else + config = atlas_Config() + end if + + rank = size(shape) + do i = 1, rank + if (shape(i) == -1) then + field_idx = i + exit + end if + end do + + nlev = 0 + if (field_idx > 2) then + nlev = shape(field_idx - 1) + end if + + nblk = shape(rank) + nproma = shape(1) + nvar = size(field_names) + call config%set("type", "MultiFieldCreatorIFS"); + call config%set("datatype", kind); + call config%set("nproma", nproma); + call config%set("nblk", nblk); + call config%set("nlev", nlev); + call config%set("ngptot", nblk * nproma); + +print *, "field_idx: ", field_idx +print *, " rank, nlev, nblk, nvar, nproma: ", rank, nlev, nblk, nvar, nproma + + allocate(field_configs(nvar)) + do ivar = 1, nvar + field_configs(ivar) = atlas_Config() + call field_configs(ivar)%set("name", trim(field_names(ivar))) + end do + call config%set("fields", field_configs) + field = atlas_MultiField__cptr( atlas__MultiField__create(config%CPTR_PGIBUG_B) ) + call field%return() +end function + +!------------------------------------------------------------------------------- + function MultiField__size(this) result(size) use atlas_multifield_c_binding class(atlas_MultiField), intent(in) :: this diff --git a/src/tests/field/fctest_multifield_ifs.F90 b/src/tests/field/fctest_multifield_ifs.F90 index 8cbef1e26..46d6c5bb1 100644 --- a/src/tests/field/fctest_multifield_ifs.F90 +++ b/src/tests/field/fctest_multifield_ifs.F90 @@ -42,7 +42,8 @@ module fcta_MultiField_fixture TEST( test_multifield ) implicit none - type(atlas_MultiField) :: multifield + type(atlas_MultiField) :: mfield(2) ! mfield(1): created through config + ! mfield(2): created directly in atlas_MultiField constructor type(atlas_FieldSet) :: fieldset_1, fieldset_2 type(atlas_Field) :: field type(atlas_config) :: config @@ -51,16 +52,18 @@ module fcta_MultiField_fixture real(c_double), pointer :: fdata_real64_2d(:,:) real(c_double), pointer :: fdata_real64(:,:,:) - integer, parameter :: nvar = 5; integer, parameter :: nproma = 16; - integer, parameter :: nlev = 100; + integer, parameter :: nlev = 0; integer, parameter :: ngptot = 2000; - type(atlas_Config), dimension(5) :: field_configs - character(len=12), parameter, dimension(nvar) :: var_names = (/ & + integer, parameter :: nblk = (ngptot + nproma - 1) / nproma + type(atlas_Config), allocatable :: field_configs(:) + integer :: i + character(len=12), parameter, dimension(5) :: var_names = (/ & "temperature ", "pressure ", "density ", "clv ", "wind_u " & /) integer :: ivar + return config = atlas_Config() call config%set("type", "MultiFieldCreatorIFS"); @@ -68,34 +71,80 @@ module fcta_MultiField_fixture call config%set("nproma", nproma); call config%set("nlev", nlev); call config%set("datatype", "real64"); - do ivar = 1, 5 + allocate(field_configs(size(var_names))) + do ivar = 1, size(var_names) field_configs(ivar) = atlas_Config() call field_configs(ivar)%set("name", trim(var_names(ivar))) end do - call field_configs(4)%set("nvar", 5) ! clv has five subvariables + !call field_configs(4)%set("nvar", 4) ! clv has four subvariables call config%set("fields", field_configs) + mfield(1) = atlas_MultiField(config) + + !mfield(2) = atlas_MultiField('real64', [nproma, nlev, -1, nblk], var_names) + + do i = 1, 1 + FCTEST_CHECK_EQUAL(mfield(i)%size(), 5) + + fieldset_1 = mfield(i)%fieldset() + FCTEST_CHECK_EQUAL(fieldset_1%size(), 5) + + fieldset_2 = atlas_FieldSet() + call fieldset_2%add(mfield(i)%fieldset()) + field = fieldset_2%field("density") + call field%data(fdata_real64) + fdata_real64(1,1,1) = 2. + call field%rename("dens") + + ! check data access directly though multifield + call mfield(i)%data("dens", fdata_real64) + fdata_real64(1,1,1) = 3. + + field = fieldset_1%field("dens") + call field%data(fdata_real64) + FCTEST_CHECK_EQUAL(fdata_real64(1,1,1), 3._c_double) + end do + +END_TEST + + +TEST( test_multifield_direct_constructor ) + implicit none + + type(atlas_MultiField) :: mfield(2) + type(atlas_FieldSet) :: fset + type(atlas_Field) :: field + type(atlas_config) :: config + real(c_float), pointer :: fdata_f2d(:,:), fdata_f3d(:,:,:) + real(c_double), pointer :: fdata_d3d(:,:,:) + + integer, parameter :: nproma = 16; + integer, parameter :: nlev = 100; + integer, parameter :: ngptot = 2000; + integer, parameter :: nblk = (ngptot + nproma - 1) / nproma + integer :: i + character(len=12), parameter, dimension(5) :: var_names = (/ & + "temperature ", "pressure ", "density ", "clv ", "wind_u " & + /) + integer :: ivar + + config = atlas_Config() - multifield = atlas_MultiField(config) - FCTEST_CHECK_EQUAL(multifield%size(), 5) + ! surface vars + mfield(1) = atlas_MultiField('real32', [nproma, -1, nblk], var_names, config) - fieldset_1 = multifield%fieldset() - FCTEST_CHECK_EQUAL(fieldset_1%size(), 5) + ! 3d vars + mfield(2) = atlas_MultiField('real64', [nproma, nlev, -1, nblk], var_names, config) - fieldset_2 = atlas_FieldSet() - call fieldset_2%add(multifield%fieldset()) - field = fieldset_2%field("density") - call field%data(fdata_real64) - fdata_real64(1,1,1) = 2. - call field%rename("dens") + FCTEST_CHECK_EQUAL(mfield(1)%size(), 5) - ! check data access directly though multifield - !call multifield%data("density", fdata_real64) - call multifield%data("dens", fdata_real64) - fdata_real64(1,1,1) = 3. + call mfield(1)%data("density", fdata_f2d) + fdata_f2d(1,1) = 3. + call mfield(2)%data("density", fdata_d3d) + fdata_d3d(1,1,1) = 4. - field = fieldset_1%field("dens") - call field%data(fdata_real64) - FCTEST_CHECK_EQUAL(fdata_real64(1,1,1), 3._c_double) + fset = atlas_FieldSet() + call fset%add(mfield(1)%fieldset()) + call fset%add(mfield(2)%fieldset()) END_TEST diff --git a/src/tests/field/test_multifield_ifs.cc b/src/tests/field/test_multifield_ifs.cc index 3186eec53..a93ffe826 100644 --- a/src/tests/field/test_multifield_ifs.cc +++ b/src/tests/field/test_multifield_ifs.cc @@ -18,6 +18,7 @@ #include "atlas/array/MakeView.h" #include "atlas/field/Field.h" #include "atlas/field/MultiField.h" +#include "atlas/field/MultiFieldCreatorIFS.h" #include "atlas/grid/Grid.h" #include "atlas/runtime/Exception.h" #include "atlas/runtime/Log.h" @@ -30,120 +31,6 @@ using namespace atlas::field; namespace atlas { namespace test { -// ------------------------------------------------------------------- -// Example IFS MultiField creato - -// --- Declaration (in .h file) -class MultiFieldCreatorIFS : public MultiFieldCreator { -public: - MultiFieldCreatorIFS(const eckit::Configuration& config = util::Config()): MultiFieldCreator(config) {} - ~MultiFieldCreatorIFS() override = default; - MultiFieldImpl* create(const eckit::Configuration& = util::Config()) const override; -}; - -// --- Implementation (in .cc file) -MultiFieldImpl* MultiFieldCreatorIFS::create(const eckit::Configuration& config) const { - long ngptot = config.getLong("ngptot"); - long nproma = config.getLong("nproma"); - long nlev = config.getLong("nlev"); - long nblk = 0; - - - array::DataType datatype = array::DataType::create(); - std::string datatype_str; - if (config.get("datatype", datatype_str)) { - datatype = array::DataType(datatype_str); - } - else { - array::DataType::kind_t kind(array::DataType::kind()); - config.get("kind", kind); - if (!array::DataType::kind_valid(kind)) { - std::stringstream msg; - msg << "Could not create field. kind parameter unrecognized"; - throw_Exception(msg.str()); - } - datatype = array::DataType(kind); - } - - nblk = std::ceil(static_cast(ngptot) / static_cast(nproma)); - - auto fields = config.getSubConfigurations("fields"); - long nfld = 0; - for (const auto& field_config : fields) { - long nvar = 1; - field_config.get("nvar", nvar); - nfld += nvar; - } - - auto multiarray_shape = array::make_shape(nblk, nfld, nlev, nproma); - - MultiFieldImpl* multifield = new MultiFieldImpl{array::ArraySpec{datatype, multiarray_shape}}; - - auto& multiarray = multifield->array(); - - size_t multiarray_field_idx = 0; - for (size_t i = 0; i < fields.size(); ++i) { - std::string name; - fields[i].get("name", name); - Field field; - size_t field_vars = 1; - - if (fields[i].get("nvar", field_vars)) { - auto field_shape = - array::make_shape(multiarray.shape(0), field_vars, multiarray.shape(2), multiarray.shape(3)); - auto field_strides = multiarray.strides(); - auto field_array_spec = array::ArraySpec(field_shape, field_strides); - - constexpr auto all = array::Range::all(); - const auto range = array::Range(multiarray_field_idx, multiarray_field_idx + field_vars); - if (datatype.kind() == array::DataType::KIND_REAL64) { - auto slice = array::make_view(multiarray).slice(all, range, all, all); - field = Field(name, slice.data(), field_array_spec); - } - else if (datatype.kind() == array::DataType::KIND_REAL32) { - auto slice = array::make_view(multiarray).slice(all, range, all, all); - field = Field(name, slice.data(), field_array_spec); - } - else { - ATLAS_NOTIMPLEMENTED; - } - field.set_variables(field_vars); - } - else { - auto field_shape = array::make_shape(multiarray.shape(0), multiarray.shape(2), multiarray.shape(3)); - auto field_strides = array::make_strides(multiarray.stride(0), multiarray.stride(2), multiarray.stride(3)); - auto field_array_spec = array::ArraySpec(field_shape, field_strides); - - constexpr auto all = array::Range::all(); - if (datatype.kind() == array::DataType::KIND_REAL64) { - auto slice = array::make_view(multiarray).slice(all, multiarray_field_idx, all, all); - field = Field(name, slice.data(), field_array_spec); - } - else if (datatype.kind() == array::DataType::KIND_REAL32) { - auto slice = array::make_view(multiarray).slice(all, multiarray_field_idx, all, all); - field = Field(name, slice.data(), field_array_spec); - } - else { - ATLAS_NOTIMPLEMENTED; - } - } - field.set_levels(nlev); - - multifield->add(field); - - multiarray_field_idx += field_vars; - } - return multifield; -} - -// Register in factory -MultiFieldCreatorBuilder __MultiFieldCreatorIFS("MultiFieldCreatorIFS"); - -// =================================================================== -// BEGIN TESTS -// =================================================================== - - CASE("multifield_generator") { EXPECT(MultiFieldCreatorFactory::has("MultiFieldCreatorIFS")); std::unique_ptr MultiFieldCreator(MultiFieldCreatorFactory::build("MultiFieldCreatorIFS"));