Michael Uleysky
8 months ago
2 changed files with 318 additions and 0 deletions
@ -0,0 +1,87 @@ |
|||||||
|
#pragma once |
||||||
|
#include "nczarrcommon.h" |
||||||
|
#include <netcdf.h> |
||||||
|
#include <variant> |
||||||
|
|
||||||
|
class NCSimpleTypes: public NcZarrTypes |
||||||
|
{ |
||||||
|
protected: |
||||||
|
template<class VType> class ReadedData |
||||||
|
{ |
||||||
|
using Vec = std::vector<size_t>; |
||||||
|
|
||||||
|
private: |
||||||
|
std::unique_ptr<VType[]> data; |
||||||
|
|
||||||
|
public: |
||||||
|
ReadedData() = default; |
||||||
|
|
||||||
|
ReadedData(std::unique_ptr<VType[]>&& d): data(std::move(d)) {} |
||||||
|
|
||||||
|
VType operator()(size_t lini) const { return data[lini]; } |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
class NCSimpleFunctions: public NCSimpleTypes |
||||||
|
{ |
||||||
|
int ncid; |
||||||
|
|
||||||
|
RetVal<std::vector<Attribute>> ReadAtts(int vid) const; |
||||||
|
|
||||||
|
protected: |
||||||
|
NCSimpleFunctions(): ncid(0) {} |
||||||
|
|
||||||
|
template<class VType> RetVal<ReadedData<VType>> Read(const MString& var, const size_t* start, const size_t* count) const |
||||||
|
{ |
||||||
|
static const MString pref = "NCSimpleFunctions::Read"; |
||||||
|
|
||||||
|
size_t ind = FindInd(var, vars); |
||||||
|
const size_t N = vars[ind].NDim(); |
||||||
|
|
||||||
|
std::unique_ptr<VType[]> cdata; |
||||||
|
|
||||||
|
size_t dsize = 1; |
||||||
|
for(size_t i = 0; i < N; i++) dsize *= count[i]; |
||||||
|
cdata.reset(new VType[dsize]); |
||||||
|
|
||||||
|
int vid; |
||||||
|
int res = nc_inq_varid(ncid, var.Buf(), &vid); |
||||||
|
if(res != NC_NOERR) return Error(pref, MString("nc_inq_varid error: ") + nc_strerror(res)); |
||||||
|
|
||||||
|
if constexpr(std::is_same_v<VType, float>) |
||||||
|
res = nc_get_vara_float(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, double>) |
||||||
|
res = nc_get_vara_double(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, int>) |
||||||
|
res = nc_get_vara_int(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, long>) |
||||||
|
res = nc_get_vara_long(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, long long>) |
||||||
|
res = nc_get_vara_longlong(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, short>) |
||||||
|
res = nc_get_vara_short(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, signed char>) |
||||||
|
res = nc_get_vara_schar(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, unsigned int>) |
||||||
|
res = nc_get_vara_uint(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, unsigned long long>) |
||||||
|
res = nc_get_vara_ulonglong(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, unsigned short>) |
||||||
|
res = nc_get_vara_ushort(ncid, vid, start, count, cdata.get()); |
||||||
|
else if constexpr(std::is_same_v<VType, unsigned char>) |
||||||
|
res = nc_get_vara_ubyte(ncid, vid, start, count, cdata.get()); |
||||||
|
else |
||||||
|
return Error(pref, "Unsupported variable type"); |
||||||
|
|
||||||
|
if(res != NC_NOERR) return Error(pref, MString("nc_get_vara error: ") + nc_strerror(res)); |
||||||
|
|
||||||
|
return ReadedData<VType>(std::move(cdata)); |
||||||
|
} |
||||||
|
|
||||||
|
public: |
||||||
|
~NCSimpleFunctions() { nc_close(ncid); } |
||||||
|
|
||||||
|
Error Open(const MString& filename); |
||||||
|
}; |
||||||
|
|
||||||
|
using NCSimple = NcZarrRead<NCSimpleFunctions>; |
@ -0,0 +1,231 @@ |
|||||||
|
#define MICHLIB_NOSOURCE |
||||||
|
#include "ncsimple.h" |
||||||
|
|
||||||
|
RetVal<std::vector<NCSimpleFunctions::Attribute>> NCSimpleFunctions::ReadAtts(int vid) const |
||||||
|
{ |
||||||
|
static const MString pref = "NCSimple::ReadAtts"; |
||||||
|
|
||||||
|
int natt; |
||||||
|
int ret; |
||||||
|
if(vid == NC_GLOBAL) |
||||||
|
ret = nc_inq_natts(ncid, &natt); |
||||||
|
else |
||||||
|
ret = nc_inq_var(ncid, vid, nullptr, nullptr, nullptr, nullptr, &natt); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't inquire number of attributes: ") + nc_strerror(ret)); |
||||||
|
|
||||||
|
std::vector<Attribute> out; |
||||||
|
char name[NC_MAX_NAME + 1]; |
||||||
|
|
||||||
|
for(int aid = 0; aid < natt; aid++) |
||||||
|
{ |
||||||
|
nc_type type; |
||||||
|
size_t len; |
||||||
|
|
||||||
|
ret = nc_inq_attname(ncid, vid, aid, name); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't inquire attribute name: ") + nc_strerror(ret)); |
||||||
|
ret = nc_inq_atttype(ncid, vid, name, &type); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't inquire attribute type: ") + nc_strerror(ret)); |
||||||
|
ret = nc_inq_attlen(ncid, vid, name, &len); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't inquire attribute length: ") + nc_strerror(ret)); |
||||||
|
|
||||||
|
if(type == NC_DOUBLE || type == NC_FLOAT) |
||||||
|
{ |
||||||
|
if(len == 1) |
||||||
|
{ |
||||||
|
double d; |
||||||
|
ret = nc_get_att_double(ncid, vid, name, &d); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't read attribute ") + name + ": " + nc_strerror(ret)); |
||||||
|
out.emplace_back(MString(name), d); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
std::vector<double> dd(len); |
||||||
|
ret = nc_get_att_double(ncid, vid, name, dd.data()); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't read attribute ") + name + ": " + nc_strerror(ret)); |
||||||
|
for(size_t i = 0; i < dd.size(); i++) out.emplace_back(MString(name) + "[" + i + "]", dd[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
else if(type == NC_BYTE || type == NC_SHORT || type == NC_INT || type == NC_INT64) |
||||||
|
{ |
||||||
|
if(len == 1) |
||||||
|
{ |
||||||
|
long long i; |
||||||
|
ret = nc_get_att_longlong(ncid, vid, name, &i); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't read attribute ") + name + ": " + nc_strerror(ret)); |
||||||
|
out.emplace_back(MString(name), int_cast<int8>(i)); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
std::vector<long long> ii(len); |
||||||
|
ret = nc_get_att_longlong(ncid, vid, name, ii.data()); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't read attribute ") + name + ": " + nc_strerror(ret)); |
||||||
|
for(size_t i = 0; i < ii.size(); i++) out.emplace_back(MString(name) + "[" + i + "]", int_cast<int8>(ii[i])); |
||||||
|
} |
||||||
|
} |
||||||
|
else if(type == NC_UBYTE || type == NC_USHORT || type == NC_UINT || type == NC_UINT64) |
||||||
|
{ |
||||||
|
if(len == 1) |
||||||
|
{ |
||||||
|
unsigned long long u; |
||||||
|
ret = nc_get_att_ulonglong(ncid, vid, name, &u); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't read attribute ") + name + ": " + nc_strerror(ret)); |
||||||
|
out.emplace_back(MString(name), int_cast<uint8>(u)); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
std::vector<unsigned long long> uu(len); |
||||||
|
ret = nc_get_att_ulonglong(ncid, vid, name, uu.data()); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't read attribute ") + name + ": " + nc_strerror(ret)); |
||||||
|
for(size_t i = 0; i < uu.size(); i++) out.emplace_back(MString(name) + "[" + i + "]", int_cast<uint8>(uu[i])); |
||||||
|
} |
||||||
|
} |
||||||
|
else if(type == NC_CHAR) |
||||||
|
{ |
||||||
|
std::vector<char> ss(len + 1, 0); |
||||||
|
ret = nc_get_att_text(ncid, vid, name, ss.data()); |
||||||
|
if(ret != NC_NOERR) return Error(pref, MString("Can't read attribute ") + name + ": " + nc_strerror(ret)); |
||||||
|
out.emplace_back(MString(name), MString(ss.data())); |
||||||
|
} |
||||||
|
else |
||||||
|
return Error(pref, MString("Unsupported type of attribute ") + name); |
||||||
|
|
||||||
|
// Ignore all other types
|
||||||
|
} |
||||||
|
|
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
Error NCSimpleFunctions::Open(const MString& filename) |
||||||
|
{ |
||||||
|
static const MString pref = "NCSimple::Open"; |
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
gats.clear(); |
||||||
|
dims.clear(); |
||||||
|
vars.clear(); |
||||||
|
|
||||||
|
nc_close(ncid); |
||||||
|
|
||||||
|
std::vector<Attribute> newgats; |
||||||
|
std::vector<Dimension> newdims; |
||||||
|
std::vector<Variable> newvars; |
||||||
|
|
||||||
|
char name[NC_MAX_NAME + 1]; |
||||||
|
|
||||||
|
// Open
|
||||||
|
{ |
||||||
|
auto ret = nc_open(filename.Buf(), 0, &ncid); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't open file " + filename + ": " + nc_strerror(ret)); |
||||||
|
} |
||||||
|
|
||||||
|
// Dimensions
|
||||||
|
{ |
||||||
|
int ndim; |
||||||
|
auto ret = nc_inq_dimids(ncid, &ndim, nullptr, 1); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't inquire number of dimensions in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
std::vector<int> dimids(ndim); |
||||||
|
ret = nc_inq_dimids(ncid, nullptr, dimids.data(), 1); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't inquire dimension ids in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
|
||||||
|
size_t len; |
||||||
|
for(const auto id: dimids) |
||||||
|
{ |
||||||
|
ret = nc_inq_dim(ncid, id, name, &len); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't inquire dimension name and size in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
newdims.emplace_back(name, len); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Global attributes
|
||||||
|
{ |
||||||
|
auto ret = ReadAtts(NC_GLOBAL); |
||||||
|
if(!ret) return ret.Add(pref, "Can't read global attributes in file " + filename); |
||||||
|
newgats = std::move(ret.Value()); |
||||||
|
} |
||||||
|
|
||||||
|
// Variables
|
||||||
|
{ |
||||||
|
int nvar; |
||||||
|
auto ret = nc_inq_varids(ncid, &nvar, nullptr); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't inquire number of variables in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
std::vector<int> varids(nvar); |
||||||
|
ret = nc_inq_varids(ncid, nullptr, varids.data()); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't inquire variables ids in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
|
||||||
|
for(const auto vid: varids) |
||||||
|
{ |
||||||
|
nc_type nctype; |
||||||
|
int ndim; |
||||||
|
|
||||||
|
auto ret = nc_inq_var(ncid, vid, name, &nctype, &ndim, nullptr, nullptr); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't inquire variable info in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
|
||||||
|
VarType vt = VarType::UNDEF; |
||||||
|
|
||||||
|
if(nctype == NC_FLOAT) vt = VarType::FLOAT; |
||||||
|
if(nctype == NC_DOUBLE) vt = VarType::DOUBLE; |
||||||
|
if(nctype == NC_BYTE) vt = VarType::INT1; |
||||||
|
if(nctype == NC_SHORT) vt = VarType::INT2; |
||||||
|
if(nctype == NC_INT) vt = VarType::INT4; |
||||||
|
if(nctype == NC_INT64) vt = VarType::INT8; |
||||||
|
if(nctype == NC_UBYTE) vt = VarType::UINT1; |
||||||
|
|
||||||
|
if(vt == VarType::UNDEF) return Error(pref, "Unsupported type of variable " + MString(name) + " in file " + filename); |
||||||
|
|
||||||
|
std::vector<int> dimids(ndim); |
||||||
|
ret = nc_inq_vardimid(ncid, vid, dimids.data()); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't inquire variable dimensions in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
|
||||||
|
std::vector<size_t> dims; |
||||||
|
char dname[NC_MAX_NAME + 1]; |
||||||
|
for(const auto did: dimids) |
||||||
|
{ |
||||||
|
auto ret = nc_inq_dimname(ncid, did, dname); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't inquire dimension name in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
size_t ind = newdims.size(); |
||||||
|
for(size_t i = 0; i < newdims.size() && ind == newdims.size(); i++) |
||||||
|
if(dname == newdims[i].Name()) ind = i; |
||||||
|
if(ind == newdims.size()) return Error(pref, "Can't find dimension " + MString(dname) + " of variable " + name + " in file " + filename); |
||||||
|
dims.push_back(ind); |
||||||
|
} |
||||||
|
|
||||||
|
auto atts = ReadAtts(vid); |
||||||
|
const char fname[] = "_FillValue"; |
||||||
|
if(!atts) return Error(pref, "Can't get attributes of variable " + MString(name) + " in file " + filename); |
||||||
|
std::vector<Attribute> vatts = std::move(atts.Value()); |
||||||
|
|
||||||
|
Variable::FillType fill; |
||||||
|
if(FindInd(fname, vatts) != vatts.size()) |
||||||
|
{ |
||||||
|
if(nctype == NC_FLOAT || nctype == NC_DOUBLE) |
||||||
|
{ |
||||||
|
double d; |
||||||
|
auto ret = nc_get_att_double(ncid, vid, fname, &d); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't get fill value for the variable " + MString(name) + " in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
fill = d; |
||||||
|
} |
||||||
|
if(nctype == NC_BYTE || nctype == NC_SHORT || nctype == NC_INT || nctype == NC_INT64) |
||||||
|
{ |
||||||
|
long long l; |
||||||
|
auto ret = nc_get_att_longlong(ncid, vid, fname, &l); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't get fill value for the variable " + MString(name) + " in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
fill = int_cast<int8>(l); |
||||||
|
} |
||||||
|
if(nctype == NC_UBYTE || nctype == NC_USHORT || nctype == NC_UINT || nctype == NC_UINT64) |
||||||
|
{ |
||||||
|
unsigned long long u; |
||||||
|
auto ret = nc_get_att_ulonglong(ncid, vid, fname, &u); |
||||||
|
if(ret != NC_NOERR) return Error(pref, "Can't get fill value for the variable " + MString(name) + " in file " + filename + ": " + nc_strerror(ret)); |
||||||
|
fill = int_cast<uint8>(u); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
newvars.emplace_back(name, vt, std::move(dims), std::move(vatts), fill); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
gats = std::move(newgats); |
||||||
|
dims = std::move(newdims); |
||||||
|
vars = std::move(newvars); |
||||||
|
return Error(); |
||||||
|
} |
Loading…
Reference in new issue