|
|
@ -1,5 +1,6 @@ |
|
|
|
#pragma once |
|
|
|
#pragma once |
|
|
|
#include "MString.h" |
|
|
|
#include "MString.h" |
|
|
|
|
|
|
|
#include "actiondep.h" |
|
|
|
#include "traits.h" |
|
|
|
#include "traits.h" |
|
|
|
#include <algorithm> |
|
|
|
#include <algorithm> |
|
|
|
#include <netcdf.h> |
|
|
|
#include <netcdf.h> |
|
|
@ -23,26 +24,31 @@ class NCFileWBase |
|
|
|
{ |
|
|
|
{ |
|
|
|
static constexpr nc_type nc = NC_UBYTE; |
|
|
|
static constexpr nc_type nc = NC_UBYTE; |
|
|
|
static int put_var(int nc, int vid, const michlib::uint1* data) { return nc_put_var_ubyte(nc, vid, data); } |
|
|
|
static int put_var(int nc, int vid, const michlib::uint1* data) { return nc_put_var_ubyte(nc, vid, data); } |
|
|
|
|
|
|
|
static int put_vara(int nc, int vid, const size_t* startp, const size_t* countp, const michlib::uint1* data) { return nc_put_vara_ubyte(nc, vid, startp, countp, data); } |
|
|
|
}; |
|
|
|
}; |
|
|
|
template<class Dummy> struct NCTypeD<michlib::int2, Dummy> |
|
|
|
template<class Dummy> struct NCTypeD<michlib::int2, Dummy> |
|
|
|
{ |
|
|
|
{ |
|
|
|
static constexpr nc_type nc = NC_SHORT; |
|
|
|
static constexpr nc_type nc = NC_SHORT; |
|
|
|
static int put_var(int nc, int vid, const michlib::int2* data) { return nc_put_var_short(nc, vid, data); } |
|
|
|
static int put_var(int nc, int vid, const michlib::int2* data) { return nc_put_var_short(nc, vid, data); } |
|
|
|
|
|
|
|
static int put_vara(int nc, int vid, const size_t* startp, const size_t* countp, const michlib::int2* data) { return nc_put_vara_short(nc, vid, startp, countp, data); } |
|
|
|
}; |
|
|
|
}; |
|
|
|
template<class Dummy> struct NCTypeD<michlib::uint2, Dummy> |
|
|
|
template<class Dummy> struct NCTypeD<michlib::uint2, Dummy> |
|
|
|
{ |
|
|
|
{ |
|
|
|
static constexpr nc_type nc = NC_USHORT; |
|
|
|
static constexpr nc_type nc = NC_USHORT; |
|
|
|
static int put_var(int nc, int vid, const michlib::uint2* data) { return nc_put_var_ushort(nc, vid, data); } |
|
|
|
static int put_var(int nc, int vid, const michlib::uint2* data) { return nc_put_var_ushort(nc, vid, data); } |
|
|
|
|
|
|
|
static int put_vara(int nc, int vid, const size_t* startp, const size_t* countp, const michlib::uint2* data) { return nc_put_vara_ushort(nc, vid, startp, countp, data); } |
|
|
|
}; |
|
|
|
}; |
|
|
|
template<class Dummy> struct NCTypeD<michlib::int4, Dummy> |
|
|
|
template<class Dummy> struct NCTypeD<michlib::int4, Dummy> |
|
|
|
{ |
|
|
|
{ |
|
|
|
static constexpr nc_type nc = NC_INT; |
|
|
|
static constexpr nc_type nc = NC_INT; |
|
|
|
static int put_var(int nc, int vid, const michlib::int4* data) { return nc_put_var_int(nc, vid, data); } |
|
|
|
static int put_var(int nc, int vid, const michlib::int4* data) { return nc_put_var_int(nc, vid, data); } |
|
|
|
|
|
|
|
static int put_vara(int nc, int vid, const size_t* startp, const size_t* countp, const michlib::int4* data) { return nc_put_vara_int(nc, vid, startp, countp, data); } |
|
|
|
}; |
|
|
|
}; |
|
|
|
template<class Dummy> struct NCTypeD<michlib::uint4, Dummy> |
|
|
|
template<class Dummy> struct NCTypeD<michlib::uint4, Dummy> |
|
|
|
{ |
|
|
|
{ |
|
|
|
static constexpr nc_type nc = NC_UINT; |
|
|
|
static constexpr nc_type nc = NC_UINT; |
|
|
|
static int put_var(int nc, int vid, const michlib::uint4* data) { return nc_put_var_uint(nc, vid, data); } |
|
|
|
static int put_var(int nc, int vid, const michlib::uint4* data) { return nc_put_var_uint(nc, vid, data); } |
|
|
|
|
|
|
|
static int put_vara(int nc, int vid, const size_t* startp, const size_t* countp, const michlib::uint4* data) { return nc_put_vara_uint(nc, vid, startp, countp, data); } |
|
|
|
}; |
|
|
|
}; |
|
|
|
template<class Dummy> struct NCTypeD<michlib::int8, Dummy> |
|
|
|
template<class Dummy> struct NCTypeD<michlib::int8, Dummy> |
|
|
|
{ |
|
|
|
{ |
|
|
@ -56,11 +62,13 @@ class NCFileWBase |
|
|
|
{ |
|
|
|
{ |
|
|
|
static constexpr nc_type nc = NC_FLOAT; |
|
|
|
static constexpr nc_type nc = NC_FLOAT; |
|
|
|
static int put_var(int nc, int vid, const float* data) { return nc_put_var_float(nc, vid, data); } |
|
|
|
static int put_var(int nc, int vid, const float* data) { return nc_put_var_float(nc, vid, data); } |
|
|
|
|
|
|
|
static int put_vara(int nc, int vid, const size_t* startp, const size_t* countp, const float* data) { return nc_put_vara_float(nc, vid, startp, countp, data); } |
|
|
|
}; |
|
|
|
}; |
|
|
|
template<class Dummy> struct NCTypeD<double, Dummy> |
|
|
|
template<class Dummy> struct NCTypeD<double, Dummy> |
|
|
|
{ |
|
|
|
{ |
|
|
|
static constexpr nc_type nc = NC_DOUBLE; |
|
|
|
static constexpr nc_type nc = NC_DOUBLE; |
|
|
|
static int put_var(int nc, int vid, const double* data) { return nc_put_var_double(nc, vid, data); } |
|
|
|
static int put_var(int nc, int vid, const double* data) { return nc_put_var_double(nc, vid, data); } |
|
|
|
|
|
|
|
static int put_vara(int nc, int vid, const size_t* startp, const size_t* countp, const double* data) { return nc_put_vara_double(nc, vid, startp, countp, data); } |
|
|
|
}; |
|
|
|
}; |
|
|
|
template<class Dummy> struct NCTypeD<MString, Dummy> |
|
|
|
template<class Dummy> struct NCTypeD<MString, Dummy> |
|
|
|
{ |
|
|
|
{ |
|
|
@ -84,7 +92,7 @@ class NCFileWBase |
|
|
|
public: |
|
|
|
public: |
|
|
|
constexpr Error(): err(NC_NOERR) {} |
|
|
|
constexpr Error(): err(NC_NOERR) {} |
|
|
|
constexpr Error(int n_err): err(n_err) {} |
|
|
|
constexpr Error(int n_err): err(n_err) {} |
|
|
|
explicit operator bool() const { return err == NC_NOERR; } |
|
|
|
explicit operator bool() const { return err == NC_NOERR; } |
|
|
|
const char* ErrMessage() const { return nc_strerror(err); } |
|
|
|
const char* ErrMessage() const { return nc_strerror(err); } |
|
|
|
int Err() const { return err; } |
|
|
|
int Err() const { return err; } |
|
|
|
bool IsErr() const { return err != NC_NOERR; } |
|
|
|
bool IsErr() const { return err != NC_NOERR; } |
|
|
@ -100,7 +108,7 @@ class NCFileWBase |
|
|
|
const char* ErrMessage() const { return err.ErrMessage(); } |
|
|
|
const char* ErrMessage() const { return err.ErrMessage(); } |
|
|
|
|
|
|
|
|
|
|
|
explicit operator bool() const { return Ok(); } |
|
|
|
explicit operator bool() const { return Ok(); } |
|
|
|
bool Ok() const { return opened && !err.IsErr(); } |
|
|
|
bool Ok() const { return opened && !err.IsErr(); } |
|
|
|
operator int() const { return ncid; } |
|
|
|
operator int() const { return ncid; } |
|
|
|
|
|
|
|
|
|
|
|
void Close() |
|
|
|
void Close() |
|
|
@ -124,11 +132,91 @@ class NCFileWBase |
|
|
|
err.Reset(nc_def_dim(ncid, name.Buf(), len, &dimid)); |
|
|
|
err.Reset(nc_def_dim(ncid, name.Buf(), len, &dimid)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MString AddAtts(const michlib_internal::ParameterListEx& pars) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
for(const auto& p: pars.GetParameterList()) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
MString ret; |
|
|
|
|
|
|
|
if(p.first.Prefix() != "") continue; // Only parameters with empty prefix considered for now
|
|
|
|
|
|
|
|
switch(p.second.valtype) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
case michlib_internal::Parameter::UINT1: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.u1); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::UINT2: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.u2); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::UINT4: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.u4); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::UINT8: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.u8); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::INT1: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.i1); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::INT2: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.i2); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::INT4: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.i4); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::INT8: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.i8); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::FLOAT: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.r4); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::DOUBLE: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.r8); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::LDOUBLE: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), static_cast<double>(p.second.value.r10)); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::BOOL: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.value.b ? 1 : 0); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::STRING: |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ret = AddAtt(p.first.Name(), p.second.svalue); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
case michlib_internal::Parameter::INVALID: break; // Silently skip
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if(ret.Exist()) return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return ""; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<class T> |
|
|
|
template<class T> |
|
|
|
requires(Type2NCType<T> != NC_NAT) |
|
|
|
requires(Type2NCType<T> != NC_NAT) |
|
|
|
void AddAtt(const MString& name, const T& val) |
|
|
|
MString AddAtt(const MString& name, const T& val) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(err.IsErr()) return; |
|
|
|
if(err.IsErr()) return "Can't write attribute " + name + " due to previous errors"; |
|
|
|
static constexpr auto nct = Type2NCType<T>; |
|
|
|
static constexpr auto nct = Type2NCType<T>; |
|
|
|
static constexpr bool ischar = std::is_same_v<T, char*>; |
|
|
|
static constexpr bool ischar = std::is_same_v<T, char*>; |
|
|
|
|
|
|
|
|
|
|
@ -138,19 +226,21 @@ class NCFileWBase |
|
|
|
err.Reset(nc_put_att_text(ncid, NC_GLOBAL, name.Buf(), strlen(val) + 1, val)); |
|
|
|
err.Reset(nc_put_att_text(ncid, NC_GLOBAL, name.Buf(), strlen(val) + 1, val)); |
|
|
|
else |
|
|
|
else |
|
|
|
err.Reset(nc_put_att_text(ncid, NC_GLOBAL, name.Buf(), val.Len() + 1, val.Buf())); |
|
|
|
err.Reset(nc_put_att_text(ncid, NC_GLOBAL, name.Buf(), val.Len() + 1, val.Buf())); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return err.IsErr() ? "Can't write attribute " + name + ": " + ErrMessage() : ""; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<class T> |
|
|
|
template<class T> |
|
|
|
requires(Type2NCType<T> != NC_NAT) |
|
|
|
requires(Type2NCType<T> != NC_NAT) |
|
|
|
void AddAtt(const MString& vname, const MString& name, const T& val) |
|
|
|
MString AddAtt(const MString& vname, const MString& name, const T& val) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(err.IsErr()) return; |
|
|
|
if(err.IsErr()) return "Can't write attribute " + name + " to the variable " + vname + " due to previous errors"; |
|
|
|
static constexpr auto nct = Type2NCType<T>; |
|
|
|
static constexpr auto nct = Type2NCType<T>; |
|
|
|
static constexpr bool ischar = std::is_same_v<T, char*>; |
|
|
|
static constexpr bool ischar = std::is_same_v<T, char*>; |
|
|
|
int varid; |
|
|
|
int varid; |
|
|
|
|
|
|
|
|
|
|
|
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid)); |
|
|
|
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid)); |
|
|
|
if(err.IsErr()) return; |
|
|
|
if(err.IsErr()) return "Can't find variable " + vname + ": " + ErrMessage(); |
|
|
|
|
|
|
|
|
|
|
|
if constexpr(nct != NC_CHAR) |
|
|
|
if constexpr(nct != NC_CHAR) |
|
|
|
err.Reset(nc_put_att(ncid, varid, name.Buf(), nct, 1, &val)); |
|
|
|
err.Reset(nc_put_att(ncid, varid, name.Buf(), nct, 1, &val)); |
|
|
@ -158,16 +248,19 @@ class NCFileWBase |
|
|
|
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), strlen(val) + 1, val)); |
|
|
|
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), strlen(val) + 1, val)); |
|
|
|
else |
|
|
|
else |
|
|
|
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), val.Len() + 1, val.Buf())); |
|
|
|
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), val.Len() + 1, val.Buf())); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return err.IsErr() ? "Can't write attribute " + name + " to the variable " + vname + ": " + ErrMessage() : ""; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void AddAtt(const MString& vname, const MString& name, const char* val) |
|
|
|
MString AddAtt(const MString& vname, const MString& name, const char* val) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(err.IsErr()) return; |
|
|
|
if(err.IsErr()) return "Can't write attribute " + name + " to the variable " + vname + " due to previous errors"; |
|
|
|
int varid; |
|
|
|
int varid; |
|
|
|
|
|
|
|
|
|
|
|
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid)); |
|
|
|
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid)); |
|
|
|
if(err.IsErr()) return; |
|
|
|
if(err.IsErr()) return "Can't find variable " + vname + ": " + ErrMessage(); |
|
|
|
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), strlen(val) + 1, val)); |
|
|
|
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), strlen(val) + 1, val)); |
|
|
|
|
|
|
|
return err.IsErr() ? "Can't write attribute " + name + " to the variable " + vname + ": " + ErrMessage() : ""; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<class... T> void AddVar(const MString& vname, nc_type type, const T&... dnames) { AddVar(vname, type, std::vector<MString>({dnames...})); } |
|
|
|
template<class... T> void AddVar(const MString& vname, nc_type type, const T&... dnames) { AddVar(vname, type, std::vector<MString>({dnames...})); } |
|
|
@ -202,6 +295,40 @@ class NCFileWBase |
|
|
|
err.Reset(NCTypeD<T, void>::put_var(ncid, varid, data)); |
|
|
|
err.Reset(NCTypeD<T, void>::put_var(ncid, varid, data)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class T> |
|
|
|
|
|
|
|
requires requires(int nc, int vid, const size_t* start, const size_t* count, const T* d) { |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
NCTypeD<T, void>::put_vara(nc, vid, start, count, d) |
|
|
|
|
|
|
|
} -> std::same_as<int>; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void WriteVar(const MString& vname, size_t ind, const T* data) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if(err.IsErr()) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int varid; |
|
|
|
|
|
|
|
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid)); |
|
|
|
|
|
|
|
if(err.IsErr()) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ndim; |
|
|
|
|
|
|
|
err.Reset(nc_inq_var(ncid, varid, nullptr, nullptr, &ndim, nullptr, nullptr)); |
|
|
|
|
|
|
|
if(err.IsErr()) return; |
|
|
|
|
|
|
|
std::vector<int> dimids(ndim); |
|
|
|
|
|
|
|
err.Reset(nc_inq_var(ncid, varid, nullptr, nullptr, nullptr, dimids.data(), nullptr)); |
|
|
|
|
|
|
|
if(err.IsErr()) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<size_t> start(ndim), count(ndim); |
|
|
|
|
|
|
|
start[0] = ind; |
|
|
|
|
|
|
|
count[0] = 1; |
|
|
|
|
|
|
|
for(size_t i = 1; i < dimids.size(); i++) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
start[i] = 0; |
|
|
|
|
|
|
|
err.Reset(nc_inq_dim(ncid, dimids[i], nullptr, &count[i])); |
|
|
|
|
|
|
|
if(err.IsErr()) return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err.Reset(NCTypeD<T, void>::put_vara(ncid, varid, start.data(), count.data(), data)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
// Members
|
|
|
|
// Members
|
|
|
|
int ncid; |
|
|
|
int ncid; |
|
|
@ -240,6 +367,7 @@ class NCFileW: public NCFileWBase |
|
|
|
|
|
|
|
|
|
|
|
Type type = UNKNOWN; |
|
|
|
Type type = UNKNOWN; |
|
|
|
int compress; |
|
|
|
int compress; |
|
|
|
|
|
|
|
bool tdep = false; |
|
|
|
|
|
|
|
|
|
|
|
template<class D> static constexpr Type DetType() |
|
|
|
template<class D> static constexpr Type DetType() |
|
|
|
{ |
|
|
|
{ |
|
|
@ -257,18 +385,18 @@ class NCFileW: public NCFileWBase |
|
|
|
static constexpr bool IsGeoType(Type t) { return t == GPSET || t == GGRID || t == GRGRID; } |
|
|
|
static constexpr bool IsGeoType(Type t) { return t == GPSET || t == GGRID || t == GRGRID; } |
|
|
|
static constexpr bool Is1DType(Type t) { return t == PSET || t == GPSET; } |
|
|
|
static constexpr bool Is1DType(Type t) { return t == PSET || t == GPSET; } |
|
|
|
|
|
|
|
|
|
|
|
MString CreateFile(Type stype, const MString& name, const MString& history, int compression, size_t nx, size_t ny); |
|
|
|
MString CreateFile(Type stype, const MString& name, int compression, size_t nx, size_t ny); |
|
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
public: |
|
|
|
static constexpr auto Fill() { return fill; } |
|
|
|
static constexpr auto Fill() { return fill; } |
|
|
|
|
|
|
|
|
|
|
|
template<class D> MString Create(const D& data, const MString& name, const MString& history, int compression) |
|
|
|
template<class D> MString Create(const D& data, const MString& name, int compression) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if(type != UNKNOWN) return "File already created"; |
|
|
|
if(type != UNKNOWN) return "File already created"; |
|
|
|
if constexpr(Is1DType<D>()) |
|
|
|
if constexpr(Is1DType<D>()) |
|
|
|
return CreateFile(DetType<D>(), name, history, compression, data.N(), 0); |
|
|
|
return CreateFile(DetType<D>(), name, compression, data.N(), 0); |
|
|
|
else |
|
|
|
else |
|
|
|
return CreateFile(DetType<D>(), name, history, compression, data.Nx(), data.Ny()); |
|
|
|
return CreateFile(DetType<D>(), name, compression, data.Nx(), data.Ny()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Close() |
|
|
|
void Close() |
|
|
@ -277,9 +405,12 @@ class NCFileW: public NCFileWBase |
|
|
|
type = UNKNOWN; |
|
|
|
type = UNKNOWN; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MString AddTimeData(const TimeData& tdata, bool tisindex); |
|
|
|
MString AddVariable(const MString& name, const MString& stname, const MString& lname, const MString& units, const MString& comment); |
|
|
|
MString AddVariable(const MString& name, const MString& stname, const MString& lname, const MString& units, const MString& comment); |
|
|
|
|
|
|
|
|
|
|
|
template<class D, class Op> MString WriteVariable(const D& data, const MString& name, Op op) |
|
|
|
template<class D, class Op> |
|
|
|
|
|
|
|
requires(std::is_invocable_v<Op, size_t> || std::is_invocable_v<Op, size_t, size_t>) |
|
|
|
|
|
|
|
MString WriteVariable(const D& data, const MString& name, Op op, size_t tind) |
|
|
|
{ |
|
|
|
{ |
|
|
|
static constexpr auto dtype = DetType<D>(); |
|
|
|
static constexpr auto dtype = DetType<D>(); |
|
|
|
if(type == UNKNOWN) return "File not open"; |
|
|
|
if(type == UNKNOWN) return "File not open"; |
|
|
@ -293,7 +424,10 @@ class NCFileW: public NCFileWBase |
|
|
|
const size_t c = data.N(); |
|
|
|
const size_t c = data.N(); |
|
|
|
float buf[c]; |
|
|
|
float buf[c]; |
|
|
|
for(size_t ix = 0; ix < c; ix++) buf[ix] = data.IsFill(ix) ? fill : op(ix); |
|
|
|
for(size_t ix = 0; ix < c; ix++) buf[ix] = data.IsFill(ix) ? fill : op(ix); |
|
|
|
WriteVar(name, buf); |
|
|
|
if(tdep) |
|
|
|
|
|
|
|
WriteVar(name, tind, buf); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
WriteVar(name, buf); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
else |
|
|
|
{ |
|
|
|
{ |
|
|
@ -301,7 +435,10 @@ class NCFileW: public NCFileWBase |
|
|
|
float buf[c[0] * c[1]]; |
|
|
|
float buf[c[0] * c[1]]; |
|
|
|
for(size_t iy = 0; iy < c[0]; iy++) |
|
|
|
for(size_t iy = 0; iy < c[0]; iy++) |
|
|
|
for(size_t ix = 0; ix < c[1]; ix++) buf[iy * c[1] + ix] = data.IsFill(ix, iy) ? fill : op(ix, iy); |
|
|
|
for(size_t ix = 0; ix < c[1]; ix++) buf[iy * c[1] + ix] = data.IsFill(ix, iy) ? fill : op(ix, iy); |
|
|
|
WriteVar(name, buf); |
|
|
|
if(tdep) |
|
|
|
|
|
|
|
WriteVar(name, tind, buf); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
WriteVar(name, buf); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(!*this) return "Can't write variable " + name + ": " + ErrMessage(); |
|
|
|
if(!*this) return "Can't write variable " + name + ": " + ErrMessage(); |
|
|
@ -309,13 +446,23 @@ class NCFileW: public NCFileWBase |
|
|
|
return ""; |
|
|
|
return ""; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<class D> MString WriteVariable(const D& data, const MString& name) |
|
|
|
template<class D> MString WriteVariable(const D& data, const MString& name, size_t tind) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if constexpr(Is1DType(DetType<D>())) |
|
|
|
if constexpr(Is1DType(DetType<D>())) |
|
|
|
return WriteVariable(data, name, [&data = std::as_const(data)](size_t i) { return data(i); }); |
|
|
|
return WriteVariable( |
|
|
|
|
|
|
|
data, name, [&data = std::as_const(data)](size_t i) { return data(i); }, tind); |
|
|
|
else |
|
|
|
else |
|
|
|
return WriteVariable(data, name, [&data = std::as_const(data)](size_t i, size_t j) { return data(i, j); }); |
|
|
|
return WriteVariable( |
|
|
|
|
|
|
|
data, name, [&data = std::as_const(data)](size_t i, size_t j) { return data(i, j); }, tind); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class D, class Op> |
|
|
|
|
|
|
|
requires(std::is_invocable_v<Op, size_t> || std::is_invocable_v<Op, size_t, size_t>) |
|
|
|
|
|
|
|
MString WriteVariable(const D& data, const MString& name, Op op) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return WriteVariable(data, name, op, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template<class D> MString WriteVariable(const D& data, const MString& name) { return WriteVariable(data, name, 0); } |
|
|
|
|
|
|
|
|
|
|
|
template<class D> MString WriteGrid(const D& data) |
|
|
|
template<class D> MString WriteGrid(const D& data) |
|
|
|
{ |
|
|
|
{ |
|
|
|