diff options
author | Claudius "keldu" Holeksa <mail@keldu.de> | 2023-11-08 16:20:32 +0100 |
---|---|---|
committer | Claudius "keldu" Holeksa <mail@keldu.de> | 2023-11-08 16:20:32 +0100 |
commit | 3353cad0b365bc870306ccaa21f701859e68a92f (patch) | |
tree | 04f737ad844d10ef550d04a6f8140b69fc7032a4 | |
parent | feae80e5e4236654ea5a843197e05d9211869750 (diff) |
codec-netcdf: Multidimensional arrays implemented
-rw-r--r-- | c++/codec-netcdf/netcdf.h | 6 | ||||
-rw-r--r-- | c++/codec-netcdf/netcdf.tmpl.h | 123 | ||||
-rw-r--r-- | tests/.nix/derivation.nix | 2 | ||||
-rw-r--r-- | tests/SConstruct | 8 | ||||
-rw-r--r-- | tests/codec-netcdf.cpp | 43 | ||||
-rw-r--r-- | tests/data/array.nc | bin | 0 -> 156 bytes | |||
-rw-r--r-- | tests/data/primitive.nc | bin | 0 -> 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 Binary files differnew file mode 100644 index 0000000..2155846 --- /dev/null +++ b/tests/data/array.nc diff --git a/tests/data/primitive.nc b/tests/data/primitive.nc Binary files differnew file mode 100644 index 0000000..ab49e3b --- /dev/null +++ b/tests/data/primitive.nc |