Skip to content

Commit

Permalink
add MultiFieldCreatorArray - a generic MultiField constructor from da…
Browse files Browse the repository at this point in the history
…tatype, shape, variable_names
  • Loading branch information
sbrdar committed Sep 11, 2024
1 parent f55c748 commit 5d30f10
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 62 deletions.
2 changes: 2 additions & 0 deletions src/atlas/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ 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
Expand Down
1 change: 1 addition & 0 deletions src/atlas/array/ArrayStrides.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class ArrayStrides : public std::vector<idx_t> {
ArrayStrides() {}
ArrayStrides(std::initializer_list<idx_t> list): Base(list) {}
ArrayStrides(Base&& base): Base(std::forward<Base>(base)) {}
ArrayStrides(const std::vector<idx_t>& list): Base(list.begin(), list.end()) {}
};

namespace detail {
Expand Down
19 changes: 18 additions & 1 deletion src/atlas/field/MultiField.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
* 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/MultiField.h"
#include "atlas/field/MultiFieldCreator.h"
#include "atlas/field/detail/MultiFieldImpl.h"
#include "atlas/runtime/Exception.h"

Expand All @@ -24,6 +26,21 @@ 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); }
Expand Down
2 changes: 1 addition & 1 deletion src/atlas/field/MultiField.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class MultiField : public util::ObjectHandle<MultiFieldImpl> {
using Handle::Handle;

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

//-- Accessors
Expand Down
21 changes: 2 additions & 19 deletions src/atlas/field/MultiFieldCreator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@

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

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

#include "atlas/field/MultiField.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"
Expand All @@ -36,6 +35,7 @@ void force_link() {
static struct Link {
Link() {
MultiFieldCreatorBuilder<MultiFieldCreatorIFS>();
MultiFieldCreatorBuilder<MultiFieldCreatorArray>();
}
} link;
}
Expand All @@ -54,22 +54,5 @@ MultiFieldCreator* MultiFieldCreatorFactory::build(const std::string& builder, c
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));
}

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

} // namespace field
} // namespace atlas
2 changes: 1 addition & 1 deletion src/atlas/field/MultiFieldCreator.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class MultiFieldCreator : public util::Object {
virtual ~MultiFieldCreator();

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

Expand Down
109 changes: 109 additions & 0 deletions src/atlas/field/MultiFieldCreatorArray.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* (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 Slavko Brdar
/// @author Willem Deconinck
/// @date September 2024

#include <cmath>
#include <sstream>

#include "atlas/array/ArrayDataStore.h"
#include "atlas/array/DataType.h"
#include "atlas/array/Range.h"
#include "atlas/field/MultiFieldCreatorArray.h"
#include "atlas/field/detail/MultiFieldImpl.h"
#include "atlas/grid/Grid.h"
#include "atlas/runtime/Exception.h"
#include "atlas/runtime/Log.h"

namespace atlas {
namespace field {

MultiFieldCreatorArray::MultiFieldCreatorArray() {}

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

MultiFieldCreatorArray::~MultiFieldCreatorArray() = default;

MultiFieldImpl* MultiFieldCreatorArray::create(const eckit::Configuration&) const {
ATLAS_NOTIMPLEMENTED;
return nullptr;
}

MultiFieldImpl* MultiFieldCreatorArray::create(const array::DataType datatype, const std::vector<int>& shape, const std::vector<std::string>& var_names) const {
const int dim = shape.size();
const int nvar = var_names.size();
ATLAS_ASSERT(nvar > 0 && dim > 2, "MultiField must have at least one field name.");

int varidx = -1;
for (int i = 0; i < dim; i++) {
if (shape[i] == -1) {
varidx = i;
break;
}
}

array::ArrayShape multiarray_shape = shape;
multiarray_shape[varidx] = nvar;

MultiFieldImpl* multifield = new MultiFieldImpl{array::ArraySpec{datatype, multiarray_shape}};
auto& multiarray = multifield->array();

std::vector<int> field_shape_vec(multiarray_shape.size() - 1);
std::vector<int> field_strides_vec(multiarray_shape.size() - 1);
for (int ivar = 0, i = 0; ivar < nvar; ivar++) {
if(ivar != varidx) {
field_shape_vec[i] = multiarray.shape()[ivar];
field_strides_vec[i] = multiarray.strides()[ivar];
++i;
}
}
array::ArrayShape field_shape(field_shape_vec);
array::ArrayStrides field_strides(field_strides_vec);
array::ArraySpec field_array_spec = array::ArraySpec(field_shape, field_strides);

for (size_t ifield = 0; ifield < nvar; ++ifield) {
idx_t start_index = multiarray.strides()[varidx] * ifield;

Field field;
if (datatype.kind() == array::DataType::KIND_REAL64) {
double* slice_begin = multiarray.data<double>() + start_index;
field = Field(var_names[ifield], slice_begin, field_array_spec);
}
else if (datatype.kind() == array::DataType::KIND_REAL32) {
float* slice_begin = multiarray.data<float>() + start_index;
field = Field(var_names[ifield], slice_begin, field_array_spec);
}
else if (datatype.kind() == array::DataType::KIND_INT32) {
int* slice_begin = multiarray.data<int>() + start_index;
field = Field(var_names[ifield], slice_begin, field_array_spec);
}
else if (datatype.kind() == array::DataType::KIND_INT64) {
long* slice_begin = multiarray.data<long>() + start_index;
field = Field(var_names[ifield], slice_begin, field_array_spec);
}
else {
ATLAS_NOTIMPLEMENTED;
}
multifield->add(field);
}
Log::debug() << "Creating multifield of " << datatype.str() << " type" << std::endl;
return multifield;
}

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

namespace {
static MultiFieldCreatorBuilder<MultiFieldCreatorArray> __MultiFieldCreatorArray("MultiFieldCreatorArray");
}

} // namespace field
} // namespace atlas
58 changes: 58 additions & 0 deletions src/atlas/field/MultiFieldCreatorArray.h
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.
*/

/// @author Slavko Brdar
/// @date September 2024

#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 datatype, shape, variable names as arguments
* \details
* shape argument contains -1 at the position which gets filled with variable names
* Example use:
* \code{.cpp}
* MultiFieldImpl* multifield = MultiField::create(
* datatype,
* shape,
* var_names
* );
* \endcode
*/
class MultiFieldCreatorArray : public MultiFieldCreator {
public:
MultiFieldCreatorArray();
MultiFieldCreatorArray(const eckit::Configuration& config);
~MultiFieldCreatorArray() override;
MultiFieldImpl* create(const eckit::Configuration& config = util::Config()) const override;
MultiFieldImpl* create(const array::DataType datatype, const std::vector<int>& shape,
const std::vector<std::string>& var_names) const override;
};

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

} // namespace field
} // namespace atlas
26 changes: 5 additions & 21 deletions src/atlas/field/MultiFieldCreatorIFS.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,13 @@ MultiFieldCreatorIFS::MultiFieldCreatorIFS(const eckit::Configuration& config) {

MultiFieldCreatorIFS::~MultiFieldCreatorIFS() = default;

MultiFieldImpl* MultiFieldCreatorIFS::create(const std::string& datatype_str, const std::vector<int>& shape,
MultiFieldImpl* MultiFieldCreatorIFS::create(const array::DataType datatype, const std::vector<int>& shape,
const std::vector<std::string>& var_names) const {
const auto datatype = array::DataType(datatype_str);

if (datatype.kind() == array::DataType::KIND_REAL64) {
return create<double>(shape, var_names);
}
else if (datatype.kind() == array::DataType::KIND_REAL32) {
return create<float>(shape, var_names);
}
ATLAS_NOTIMPLEMENTED;
return nullptr;
}

/*
template<typename T>
MultiFieldImpl* MultiFieldCreatorIFS::create(const std::vector<int> shape, const std::vector<std::string> var_names) const {
const int dim = shape.size();
Expand Down Expand Up @@ -84,6 +79,7 @@ MultiFieldImpl* MultiFieldCreatorIFS::create(const std::vector<int> shape, const
config.set("fields", fconfigs);
return create(config);
}
*/

MultiFieldImpl* MultiFieldCreatorIFS::create(const eckit::Configuration& config) const {
long nproma;
Expand Down Expand Up @@ -129,8 +125,6 @@ MultiFieldImpl* MultiFieldCreatorIFS::create(const eckit::Configuration& config)
( (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();

Expand All @@ -140,10 +134,7 @@ MultiFieldImpl* MultiFieldCreatorIFS::create(const eckit::Configuration& config)
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)) :
Expand Down Expand Up @@ -203,13 +194,6 @@ MultiFieldImpl* MultiFieldCreatorIFS::create(const eckit::Configuration& config)
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));
Expand Down
7 changes: 1 addition & 6 deletions src/atlas/field/MultiFieldCreatorIFS.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,8 @@ class MultiFieldCreatorIFS : public MultiFieldCreator {
MultiFieldCreatorIFS(const eckit::Configuration& config);
~MultiFieldCreatorIFS() override;
MultiFieldImpl* create(const eckit::Configuration& config = util::Config()) const override;
MultiFieldImpl* create(const std::string& datatype_str, const std::vector<int>& shape,
MultiFieldImpl* create(const array::DataType datatype, const std::vector<int>& shape,
const std::vector<std::string>& var_names) const override;

private:
template<typename T>
MultiFieldImpl* create(const std::vector<int> shape, const std::vector<std::string> var_names) const;

};

// ------------------------------------------------------------------
Expand Down
4 changes: 0 additions & 4 deletions src/atlas/field/detail/MultiFieldInterface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ namespace field {
extern "C" {
MultiFieldImpl* atlas__MultiField__create(eckit::Configuration* config) {
ATLAS_ASSERT(config != nullptr);
// Register in factory
// TODO: move __multiFieldCreatorIFS out of test_multifield_ifs.cc
//MultiFieldCreatorBuilder<MultiFieldCreatorIFS> __MultiFieldCreatorIFS("MultiFieldCreatorIFS");

auto multifield = new MultiField(*config);
ATLAS_ASSERT(multifield);
return multifield->get();
Expand Down
Loading

0 comments on commit 5d30f10

Please sign in to comment.