summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudius "keldu" Holeksa <mail@keldu.de>2023-11-08 16:20:32 +0100
committerClaudius "keldu" Holeksa <mail@keldu.de>2023-11-08 16:20:32 +0100
commit3353cad0b365bc870306ccaa21f701859e68a92f (patch)
tree04f737ad844d10ef550d04a6f8140b69fc7032a4
parentfeae80e5e4236654ea5a843197e05d9211869750 (diff)
codec-netcdf: Multidimensional arrays implemented
-rw-r--r--c++/codec-netcdf/netcdf.h6
-rw-r--r--c++/codec-netcdf/netcdf.tmpl.h123
-rw-r--r--tests/.nix/derivation.nix2
-rw-r--r--tests/SConstruct8
-rw-r--r--tests/codec-netcdf.cpp43
-rw-r--r--tests/data/array.ncbin0 -> 156 bytes
-rw-r--r--tests/data/primitive.ncbin0 -> 112 bytes
7 files changed, 159 insertions, 23 deletions
diff --git a/c++/codec-netcdf/netcdf.h b/c++/codec-netcdf/netcdf.h
index d579b7f..c99217e 100644
--- a/c++/codec-netcdf/netcdf.h
+++ b/c++/codec-netcdf/netcdf.h
@@ -2,7 +2,7 @@
#include <forstio/core/string_literal.h>
#include <forstio/core/error.h>
-#include <forstio/codec/codec.h>
+#include <forstio/codec/data.h>
#include <netcdf.h>
@@ -66,7 +66,7 @@ public:
*/
template<typename FromEncoding>
error_or<void> encode() {
- return void_t{};
+ return make_error<err::not_implemented>();
}
/**
@@ -78,7 +78,7 @@ public:
int rc{};
rc = nc_open(from_decode.get_path().c_str(), NC_NOWRITE, &ncid);
- if(rc){
+ if(rc != NC_NOERR){
// Don't know how to get the error, so fail critically.
return make_error<err::critical>();
}
diff --git a/c++/codec-netcdf/netcdf.tmpl.h b/c++/codec-netcdf/netcdf.tmpl.h
index 921c84e..f3b36b8 100644
--- a/c++/codec-netcdf/netcdf.tmpl.h
+++ b/c++/codec-netcdf/netcdf.tmpl.h
@@ -3,6 +3,41 @@
namespace saw {
namespace impl {
template<typename Schema>
+struct netcdf_primitive_id {
+ static_assert(always_false<Schema>, "Not a primitive id");
+};
+
+template<>
+struct netcdf_primitive_id<schema::Int32> {
+ static constexpr nc_type value = NC_INT;
+};
+
+template<>
+struct netcdf_primitive_id<schema::UInt32> {
+ static constexpr nc_type value = NC_UINT;
+};
+
+template<>
+struct netcdf_primitive_id<schema::Int64> {
+ static constexpr nc_type value = NC_INT64;
+};
+
+template<>
+struct netcdf_primitive_id<schema::UInt64> {
+ static constexpr nc_type value = NC_UINT64;
+};
+
+template<>
+struct netcdf_primitive_id<schema::Float32> {
+ static constexpr nc_type value = NC_FLOAT;
+};
+
+template<>
+struct netcdf_primitive_id<schema::Float64> {
+ static constexpr nc_type value = NC_DOUBLE;
+};
+
+template<typename Schema>
struct netcdf_is_group {
static constexpr bool value = false;
};
@@ -12,12 +47,13 @@ struct netcdf_is_group<schema::Struct<schema::Member<T,Lits>...>> {
static constexpr bool value = true;
};
-template<typename Schema, typename RootSchema, typename ToEncode>
+template<typename Schema, typename ToEncode>
struct netcdf_decode;
-template<typename RootSchema, typename ToDecode>
-struct netcdf_decode<schema::Int32, RootSchema, ToDecode> {
- using Schema = schema::Int32;
+template<typename T, size_t N, typename ToDecode>
+struct netcdf_decode<schema::Primitive<T,N>, ToDecode> {
+ using Schema = schema::Primitive<T,N>;
+
static error_or<void> decode(data<Schema, ToDecode>& to, int from, int nc_varid){
int rc{};
@@ -29,15 +65,15 @@ struct netcdf_decode<schema::Int32, RootSchema, ToDecode> {
if(rc != NC_NOERR){
return make_error<err::critical>();
}
- if(nc_vartype != NC_INT){
+ if(nc_vartype != netcdf_primitive_id<schema::Primitive<T,N>>::value){
return make_error<err::critical>();
}
if(nc_dimnum != 0){
return make_error<err::critical>();
}
- int32_t val{};
- rc = nc_get_var_int(from, nc_varid, &val);
+ typename native_data_type<schema::Primitive<T,N>>::type val{};
+ rc = nc_get_var(from, nc_varid, &val);
if(rc != NC_NOERR){
return make_error<err::critical>();
}
@@ -48,8 +84,71 @@ struct netcdf_decode<schema::Int32, RootSchema, ToDecode> {
}
};
-template<typename... T, string_literal... Lits, typename RootSchema, typename ToDecode>
-struct netcdf_decode<schema::Struct<schema::Member<T,Lits>...>, RootSchema, ToDecode> {
+template<typename T, size_t Dim, typename ToDecode>
+struct netcdf_decode<schema::Array<T,Dim>, ToDecode> {
+ using Schema = schema::Array<T,Dim>;
+
+ template<std::size_t Level>
+ static error_or<void> decode_level(data<Schema, ToDecode>& to, int from, int nc_varid, std::array<std::size_t, Dim>& index, const std::array<size_t,Dim>& count){
+ if constexpr ( Level == Dim ){
+ int rc{};
+ typename native_data_type<T>::type val;
+ rc = nc_get_vara(from, nc_varid, index.data(), count.data(), &val);
+ if(rc != NC_NOERR){
+ return make_error<err::critical>();
+ }
+ to.at(index).set(val);
+ }else{
+ const std::size_t dim_size = to.get_dim_size(Level);
+ for(index[Level] = 0; index[Level] < dim_size; ++index[Level]){
+ auto eov = decode_level<Level+1>(to, from, nc_varid, index, count);
+ if(eov.is_error()){
+ return eov;
+ }
+ }
+ }
+
+ return void_t{};
+ }
+
+ static error_or<void> decode(data<Schema, ToDecode>& to, int from, int nc_varid){
+ int rc{};
+
+ nc_type nc_vartype{};
+
+ int nc_dimnum{};
+ std::array<int, NC_MAX_VAR_DIMS> nc_dimids;
+
+ rc = nc_inq_var(from, nc_varid, nullptr, &nc_vartype, &nc_dimnum, &nc_dimids[0], nullptr);
+ if(rc != NC_NOERR){
+ return make_error<err::critical>();
+ }
+ if(nc_vartype != netcdf_primitive_id<T>::value){
+ return make_error<err::critical>();
+ }
+ if(nc_dimnum != Dim){
+ return make_error<err::critical>();
+ }
+
+ std::array<std::size_t, Dim> dims;
+ std::array<size_t, Dim> count;
+ for(std::size_t i = 0; i < Dim; ++i){
+ rc = nc_inq_dim(from, nc_dimids[i], nullptr, &dims[i]);
+ if(rc != NC_NOERR){
+ return make_error<err::critical>();
+ }
+ count[i] = 1;
+ }
+
+ to = {dims};
+ std::array<std::size_t, Dim> index;
+
+ return decode_level<0>(to, from, nc_varid, index, count);
+ }
+};
+
+template<typename... T, string_literal... Lits, typename ToDecode>
+struct netcdf_decode<schema::Struct<schema::Member<T,Lits>...>, ToDecode> {
using Schema = schema::Struct<schema::Member<T,Lits>...>;
template<std::size_t i>
@@ -67,7 +166,7 @@ struct netcdf_decode<schema::Struct<schema::Member<T,Lits>...>, RootSchema, ToDe
if(rc != NC_NOERR) {
return make_error<err::critical>();
}
- auto eov = netcdf_decode<Type, RootSchema, ToDecode>::decode(to.template get<Literal>(), nc_group_id);
+ auto eov = netcdf_decode<Type, ToDecode>::decode(to.template get<Literal>(), nc_group_id);
if(eov.is_error()){
return eov;
}
@@ -78,12 +177,12 @@ struct netcdf_decode<schema::Struct<schema::Member<T,Lits>...>, RootSchema, ToDe
if(rc != NC_NOERR) {
return make_error<err::critical>();
}
- auto eov = netcdf_decode<Type, RootSchema, ToDecode>::decode(to.template get<Literal>(), from, nc_varid);
+ auto eov = netcdf_decode<Type, ToDecode>::decode(to.template get<Literal>(), from, nc_varid);
}
}
if constexpr ((i+1) < sizeof...(T)){
- auto eov = decode_member<i+1>(from, to, ncid);
+ auto eov = decode_member<i+1>(to, from);
if(eov.is_error()){
return eov;
}
diff --git a/tests/.nix/derivation.nix b/tests/.nix/derivation.nix
index e096e70..ea40920 100644
--- a/tests/.nix/derivation.nix
+++ b/tests/.nix/derivation.nix
@@ -4,6 +4,7 @@
, clang-tools
, version
, forstio
+, netcdf
}:
stdenv.mkDerivation {
@@ -24,6 +25,7 @@ stdenv.mkDerivation {
forstio.io
forstio.test
forstio.window
+ netcdf
];
doCheck = true;
diff --git a/tests/SConstruct b/tests/SConstruct
index 4434d20..88477f7 100644
--- a/tests/SConstruct
+++ b/tests/SConstruct
@@ -46,7 +46,13 @@ env_vars.Add('prefix',
env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=[],
CPPDEFINES=['SAW_UNIX'],
CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'],
- LIBS=['forstio-core', 'forstio-async', 'forstio-test'])
+ LIBS=[
+ 'forstio-core',
+ 'forstio-async',
+ 'forstio-test',
+ 'netcdf'
+ ]
+);
env.__class__.add_source_files = add_kel_source_files
env.Tool('compilation_db');
env.cdb = env.CompilationDatabase('compile_commands.json');
diff --git a/tests/codec-netcdf.cpp b/tests/codec-netcdf.cpp
index df0037b..72fc5ea 100644
--- a/tests/codec-netcdf.cpp
+++ b/tests/codec-netcdf.cpp
@@ -5,21 +5,50 @@ namespace {
namespace schema {
using namespace saw::schema;
using TestStruct = Struct<
- Member<Int32, "rh">
+ Member<Int32, "data">,
+ Member<Float64, "other">
+>;
+
+using TestArrayStruct = Struct<
+ Member<Array<Int32,2>, "data">
>;
}
-SAW_TEST("NetCDF read"){
+SAW_TEST("NetCDF Struct Primitive read"){
using namespace saw;
- data<TestStruct, encode::Netcdf> net{"./data/simple.nc"};
+ data<schema::TestStruct, encode::Netcdf> netcdf{"./data/primitive.nc"};
- data<TestStruct, encode::KelSimple> kel;
+ data<schema::TestStruct, encode::Native> native;
- codec<TestStruct, encode::Netcdf> codec;
+ codec<schema::TestStruct, encode::Netcdf> codec;
- auto eov = codec.decode(net, kel);
+ auto eov = codec.decode(netcdf, native);
SAW_EXPECT(eov.is_value(), "Decoding failed");
- SAW_EXPECT(kel.get<"rh">.get() == 5, "Value incorrect");
+ SAW_EXPECT(native.get<"data">().get() == 5, "Int Value incorrect");
+ SAW_EXPECT(native.get<"other">().get() == 32.0, "Double Value incorrect");
+}
+
+SAW_TEST("NetCDF Struct Array read"){
+ using namespace saw;
+
+ data<schema::TestArrayStruct, encode::Netcdf> netcdf{"./data/array.nc"};
+
+ data<schema::TestArrayStruct, encode::Native> native;
+
+ codec<schema::TestArrayStruct, encode::Netcdf> codec;
+
+ auto eov = codec.decode(netcdf, native);
+ SAW_EXPECT(eov.is_value(), "Decoding failed");
+ auto& arr = native.get<"data">();
+ SAW_EXPECT(arr.get_dim_size(0) == 5, "Incorrect dimension 0");
+ SAW_EXPECT(arr.get_dim_size(1) == 3, "Incorrect dimension 1");
+
+ for(std::size_t i = 0; i < 5; ++i){
+ for(std::size_t j = 0; j < 3; ++j){
+ int64_t exp_val = i * 3 + j;
+ SAW_EXPECT(arr.at(i,j).get() == exp_val, "Incorrect value");
+ }
+ }
}
}
diff --git a/tests/data/array.nc b/tests/data/array.nc
new file mode 100644
index 0000000..2155846
--- /dev/null
+++ b/tests/data/array.nc
Binary files differ
diff --git a/tests/data/primitive.nc b/tests/data/primitive.nc
new file mode 100644
index 0000000..ab49e3b
--- /dev/null
+++ b/tests/data/primitive.nc
Binary files differ