Browse Source

Added an interface class for writing netcdf files

master
Michael Uleysky 8 months ago
parent
commit
cccd67aab4
  1. 143
      actions/actiongrad.cpp
  2. 19
      actions/actiongrad.h
  3. 87
      actions/actionuv.cpp
  4. 378
      include/ncfilew.h
  5. 145
      src/ncfilew.cpp

143
actions/actiongrad.cpp

@ -4,146 +4,57 @@
MString GradMethods::NCFileW::Create(const MString& name, const MString& history, const std::vector<MString>& vnames, const std::vector<MString>& lnames,
const std::vector<GradMethods::DataType>& lons, const std::vector<GradMethods::DataType>& lats, int compress)
{
int ret;
const float node_offset = 0.0;
auto nx = lons.size();
auto ny = lats.size();
int xid, yid;
MString text;
struct
{
union
{
struct
{
int ydimid, xdimid;
};
int dimid[2];
};
} dim;
struct Keeper
{
bool active;
int ncid;
~Keeper()
{
if(active) nc_close(ncid);
}
operator int() { return ncid; }
} newnc;
const auto fill = static_cast<GradMethods::DataType>(std::numeric_limits<GradMethods::Matrix::MDataType>::max());
// Creating
ret = nc_create(name.Buf(), NC_CLOBBER | NC_NETCDF4, &newnc.ncid);
if(ret != NC_NOERR) return "Can't create netcdf file: " + name;
newnc.active = true;
// Global attributes
ret = nc_put_att_text(newnc, NC_GLOBAL, "history", history.Len() + 1, history.Buf());
if(ret != NC_NOERR) return "Can't write history attribute in the netcdf file";
ret = nc_put_att(newnc, NC_GLOBAL, "node_offset", NC_FLOAT, 1, &node_offset);
if(ret != NC_NOERR) return "Can't write history attribute in the netcdf file";
// Dimensions
ret = nc_def_dim(newnc, "longitude", nx, &dim.xdimid);
if(ret != NC_NOERR) return "Can't create x-dimension in the netcdf file";
ret = nc_def_dim(newnc, "latitude", ny, &dim.ydimid);
if(ret != NC_NOERR) return "Can't create y-dimension in the netcdf file";
// lon, lat variables
ret = nc_def_var(newnc, "longitude", NC_FLOAT, 1, &dim.xdimid, &xid);
if(ret != NC_NOERR) return "Can't create longitude variable in the netcdf file";
ret = nc_def_var(newnc, "latitude", NC_FLOAT, 1, &dim.ydimid, &yid);
if(ret != NC_NOERR) return "Can't create latitude variable in the netcdf file";
ret = nc_def_var_deflate(newnc, xid, 1, 1, compress);
if(ret != NC_NOERR) return "Can't set deflate parameters for longitude variable in the netcdf file";
ret = nc_def_var_deflate(newnc, yid, 1, 1, compress);
if(ret != NC_NOERR) return "Can't set deflate parameters for latitude variable in the netcdf file";
text = "longitude";
ret = nc_put_att_text(newnc, xid, "standard_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write standard_name attribute of longitude variable in the netcdf file";
text = "latitude";
ret = nc_put_att_text(newnc, yid, "standard_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write standard_name attribute of latitude variable in the netcdf file";
text = "Longitude";
ret = nc_put_att_text(newnc, xid, "long_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of longitude variable in the netcdf file";
text = "Latitude";
ret = nc_put_att_text(newnc, yid, "long_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of latitude variable in the netcdf file";
Open(name);
if(!*this) return "Can't create netcdf file " + name + ": " + ErrMessage();
AddAtt("history", history);
AddAtt("node_offset", node_offset);
AddDim("longitude", nx);
AddDim("latitude", ny);
AddVar("longitude", NC_FLOAT, "longitude");
AddVar("latitude", NC_FLOAT, "latitude");
SetComp("longitude", compress);
SetComp("latitude", compress);
AddAtt("longitude", "standard_name", "longitude");
AddAtt("longitude", "long_name", "Longitude");
AddAtt("latitude", "standard_name", "latitude");
AddAtt("latitude", "long_name", "Latitude");
// Variables
for(size_t i = 0; i < vnames.size(); i++)
{
int vid;
ret = nc_def_var(newnc, vnames[i].Buf(), NC_FLOAT, 2, dim.dimid, &vid);
if(ret != NC_NOERR) return "Can't create " + vnames[i] + " variable in the netcdf file";
ret = nc_def_var_deflate(newnc, vid, 1, 1, compress);
if(ret != NC_NOERR) return "Can't set deflate parameters for " + vnames[i] + " variable in the netcdf file";
if(lnames[i].Exist()) ret = nc_put_att_text(newnc, vid, "long_name", lnames[i].Len() + 1, lnames[i].Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of " + vnames[i] + " variable in the netcdf file";
ret = nc_put_att_float(newnc, vid, "_FillValue", NC_FLOAT, 1, &fill);
if(ret != NC_NOERR) return "Can't write _FillValue attribute of " + vnames[i] + " variable in the netcdf file";
AddVar(vnames[i], NC_FLOAT, "latitude", "longitude");
SetComp(vnames[i], compress);
if(lnames[i].Exist()) AddAtt(vnames[i], "long_name", lnames[i]);
AddAtt(vnames[i], "_FillValue", fill);
}
// End definitions
nc_enddef(newnc);
EndDef();
// Writing lon, lat
const size_t i = 0;
WriteVar("longitude", lons.data());
WriteVar("latitude", lats.data());
ret = nc_put_vara_float(newnc, xid, &i, &nx, lons.data());
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file";
ret = nc_put_vara_float(newnc, yid, &i, &ny, lats.data());
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file";
if(!*this) return "Can't set grid in the netcdf file " + name + ": " + ErrMessage();
ncid = newnc;
newnc.active = false;
return "";
}
MString GradMethods::NCFileW::WriteVar(const MString& name, const std::vector<GradMethods::Matrix::MDataType>& data)
MString GradMethods::NCFileW::WriteVariable(const MString& name, const GradMethods::Matrix& data)
{
int ret;
int vid;
int xid, yid;
size_t nx, ny;
ret = nc_inq_varid(ncid, name.Buf(), &vid);
if(ret != NC_NOERR) return "Can't find variable " + name + " in the netcdf file";
ret = nc_inq_dimid(ncid, "longitude", &xid);
if(ret != NC_NOERR) return "Can't find longitude dimension in the netcdf file";
ret = nc_inq_dimid(ncid, "latitude", &yid);
if(ret != NC_NOERR) return "Can't find latitude dimension in the netcdf file";
ret = nc_inq_dimlen(ncid, xid, &nx);
if(ret != NC_NOERR) return "Can't find longitude size in the netcdf file";
ret = nc_inq_dimlen(ncid, yid, &ny);
if(ret != NC_NOERR) return "Can't find latitude size in the netcdf file";
const size_t i[2] = {0, 0};
const size_t c[2] = {ny, nx};
GradMethods::DataType buf[nx * ny];
for(size_t i = 0; i < nx * ny; i++) buf[i] = static_cast<GradMethods::DataType>(data[i]);
WriteVar(name, data.Data().data());
if(!*this) return "Can't write variable " + name + ": " + ErrMessage();
ret = nc_put_vara_float(ncid, vid, i, c, buf);
if(ret != NC_NOERR) return "Can't write " + name + " variable in the netcdf file";
return "";
}

19
actions/actiongrad.h

@ -45,25 +45,12 @@ class GradMethods::Matrix
const auto& Data() const { return data; }
};
class GradMethods::NCFileW
class GradMethods::NCFileW: public NCFileWBase
{
bool opened;
int ncid;
public:
NCFileW(): opened(false) {}
MString Create(const MString& name, const MString& history, const std::vector<MString>& vnames, const std::vector<MString>& lnames, const std::vector<GradMethods::DataType>& lons,
const std::vector<GradMethods::DataType>& lats, int compress);
MString WriteVar(const MString& name, const std::vector<GradMethods::Matrix::MDataType>& data);
~NCFileW() { Close(); }
void Close()
{
if(opened) nc_close(ncid);
opened = false;
}
MString WriteVariable(const MString& name, const GradMethods::Matrix& data);
};
template<class T>
@ -139,7 +126,7 @@ template<class D> MString ActionGRAD::DoAction(const CLArgs& args, D& ds)
{
const MString& name = ds.VarNames()[i];
data[i].Grad();
fw.WriteVar(name, data[i].Data());
fw.WriteVariable(name, data[i]);
}
return "";

87
actions/actionuv.cpp

@ -21,75 +21,48 @@ void UVMethods::StPoints::WriteBinBile(const MString& name) const
MString UVMethods::StPoints::WriteNcFile(const MString& name, const MString& history, int comp) const
{
int ret;
int ncid;
int dimid;
int xid, yid, tid;
MString text;
NCFileWBase nc;
ret = nc_create(name.Buf(), NC_CLOBBER | NC_NETCDF4, &ncid);
if(ret != NC_NOERR) return "Can't create netcdf file: " + name;
const MString xname = lonlat ? "longitude" : "x";
const MString yname = lonlat ? "latitude" : "y";
ret = nc_put_att_text(ncid, NC_GLOBAL, "history", history.Len() + 1, history.Buf());
if(ret != NC_NOERR) return "Can't write history attribute in the netcdf file";
nc.Open(name);
if(!nc) return "Can't create netcdf file " + name + ": " + nc.ErrMessage();
ret = nc_def_dim(ncid, "i", N(), &dimid);
if(ret != NC_NOERR) return "Can't create dimension in the netcdf file";
ret = nc_def_var(ncid, lonlat ? "longitude" : "x", NC_FLOAT, 1, &dimid, &xid);
if(ret != NC_NOERR) return "Can't create x variable in the netcdf file";
ret = nc_def_var(ncid, lonlat ? "latitude" : "y", NC_FLOAT, 1, &dimid, &yid);
if(ret != NC_NOERR) return "Can't create y variable in the netcdf file";
nc.AddAtt("history", history);
nc.AddDim("i", N());
nc.AddVar(xname, NC_FLOAT, "i");
nc.AddVar(yname, NC_FLOAT, "i");
nc.SetComp(xname, comp);
nc.SetComp(yname, comp);
if(lonlat)
{
text = "longitude";
ret = nc_put_att_text(ncid, xid, "standard_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write standard_name attribute of longitude variable in the netcdf file";
text = "latitude";
ret = nc_put_att_text(ncid, yid, "standard_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write standard_name attribute of latitude variable in the netcdf file";
text = "Longitude";
ret = nc_put_att_text(ncid, xid, "long_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of longitude variable in the netcdf file";
text = "Latitude";
ret = nc_put_att_text(ncid, yid, "long_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of latitude variable in the netcdf file";
nc.AddAtt(xname, "standard_name", "longitude");
nc.AddAtt(xname, "long_name", "Longitude");
nc.AddAtt(yname, "standard_name", "latitude");
nc.AddAtt(yname, "long_name", "Latitude");
}
else
{
nc.AddAtt(xname, "long_name", "x-coordinate");
nc.AddAtt(yname, "long_name", "y-coordinate");
}
ret = nc_def_var_deflate(ncid, xid, 1, 1, comp);
if(ret != NC_NOERR) return "Can't set deflate parameters for x variable in the netcdf file";
ret = nc_def_var_deflate(ncid, yid, 1, 1, comp);
if(ret != NC_NOERR) return "Can't set deflate parameters for y variable in the netcdf file";
ret = nc_def_var(ncid, "type", NC_UBYTE, 1, &dimid, &tid);
if(ret != NC_NOERR) return "Can't create type variable in the netcdf file";
ret = nc_def_var_deflate(ncid, tid, 1, 1, comp);
if(ret != NC_NOERR) return "Can't set deflate parameters for type variable in the netcdf file";
text = "Stationary point type, 0 - saddle, 1 - st. anticicl. focus, 2 - st. knot, 3 - unst. anticicl. focus, 4 - unst. knot, 5 - st. cicl. focus, 6 - unst. cicl. focus";
ret = nc_put_att_text(ncid, tid, "long_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of type variable in the netcdf file";
ret = nc_enddef(ncid);
if(ret != NC_NOERR) return "Can't finish definition of the netcdf file";
const size_t i = 0, c = N();
float buf[c];
nc.AddVar("type", NC_UBYTE, "i");
nc.SetComp("type", comp);
nc.AddAtt("type", "long_name",
"Stationary point type, 0 - saddle, 1 - st. anticicl. focus, 2 - st. knot, 3 - unst. anticicl. focus, 4 - unst. knot, 5 - st. cicl. focus, 6 - unst. cicl. focus");
for(size_t ix = 0; ix < c; ix++) buf[ix] = x[ix];
ret = nc_put_vara_float(ncid, xid, &i, &c, buf);
if(ret != NC_NOERR) return "Can't write x variable in the netcdf file";
if(!nc) return "Can't set grid in the netcdf file " + name + ": " + nc.ErrMessage();
for(size_t ix = 0; ix < c; ix++) buf[ix] = y[ix];
ret = nc_put_vara_float(ncid, yid, &i, &c, buf);
if(ret != NC_NOERR) return "Can't write y variable in the netcdf file";
nc.EndDef();
ret = nc_put_vara_ubyte(ncid, tid, &i, &c, t.data());
if(ret != NC_NOERR) return "Can't write type variable in the netcdf file";
nc.WriteVar(xname, x.data());
nc.WriteVar(yname, y.data());
nc.WriteVar("type", t.data());
ret = nc_close(ncid);
if(ret != NC_NOERR) return "Can't close netcdf file";
if(!nc) return "Can't write data to the netcdf file " + name + ": " + nc.ErrMessage();
return "";
}

378
include/ncfilew.h

@ -8,56 +8,260 @@
using michlib::MString;
class NCFileW
class NCFileWBase
{
enum Type
template<class T, class Dummy> struct NCTypeD
{
UNKNOWN,
G1V1,
G1V2,
G2V2
static constexpr nc_type nc = NC_NAT;
};
template<class Dummy> struct NCTypeD<michlib::int1, Dummy>
{
static constexpr nc_type nc = NC_BYTE;
};
template<class Dummy> struct NCTypeD<michlib::uint1, Dummy>
{
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); }
};
template<class Dummy> struct NCTypeD<michlib::int2, Dummy>
{
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); }
};
template<class Dummy> struct NCTypeD<michlib::uint2, Dummy>
{
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); }
};
template<class Dummy> struct NCTypeD<michlib::int4, Dummy>
{
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); }
};
template<class Dummy> struct NCTypeD<michlib::uint4, Dummy>
{
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); }
};
template<class Dummy> struct NCTypeD<michlib::int8, Dummy>
{
static constexpr nc_type nc = NC_INT64;
};
template<class Dummy> struct NCTypeD<michlib::uint8, Dummy>
{
static constexpr nc_type nc = NC_UINT64;
};
template<class Dummy> struct NCTypeD<float, Dummy>
{
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); }
};
template<class Dummy> struct NCTypeD<double, Dummy>
{
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); }
};
template<class Dummy> struct NCTypeD<MString, Dummy>
{
static constexpr nc_type nc = NC_CHAR;
};
struct Var
template<class Dummy> struct NCTypeD<char*, Dummy>
{
MString name;
int id;
static constexpr nc_type nc = NC_CHAR;
};
static constexpr auto fill = std::numeric_limits<float>::max();
template<class T> using NCType = NCTypeD<T, void>;
int ncid;
Type type = UNKNOWN;
union
public:
template<class T> static constexpr nc_type Type2NCType = NCType<T>::nc;
// Error class
class Error
{
struct
int err;
public:
constexpr Error(): err(NC_NOERR) {}
constexpr Error(int n_err): err(n_err) {}
explicit operator bool() const { return err == NC_NOERR; }
const char* ErrMessage() const { return nc_strerror(err); }
int Err() const { return err; }
bool IsErr() const { return err != NC_NOERR; }
void Reset() { err = NC_NOERR; }
void Reset(int n_err) { err = n_err; }
void Reset(const Error& e) { err = e.err; }
};
~NCFileWBase() { Close(); }
int Id() const { return ncid; }
int Err() const { return err.Err(); }
const char* ErrMessage() const { return err.ErrMessage(); }
explicit operator bool() const { return Ok(); }
bool Ok() const { return opened && !err.IsErr(); }
operator int() const { return ncid; }
void Close()
{
if(opened) nc_close(ncid);
err.Reset();
opened = false;
}
void Open(const MString& path)
{
if(opened) return;
err.Reset(nc_create(path.Buf(), NC_CLOBBER | NC_NETCDF4, &ncid));
opened = !err.IsErr();
}
void AddDim(const MString& name, size_t len)
{
if(err.IsErr()) return;
static int dimid;
err.Reset(nc_def_dim(ncid, name.Buf(), len, &dimid));
}
template<class T>
requires(Type2NCType<T> != NC_NAT)
void AddAtt(const MString& name, const T& val)
{
if(err.IsErr()) return;
static constexpr auto nct = Type2NCType<T>;
static constexpr bool ischar = std::is_same_v<T, char*>;
if constexpr(nct != NC_CHAR)
err.Reset(nc_put_att(ncid, NC_GLOBAL, name.Buf(), nct, 1, &val));
else if constexpr(ischar)
err.Reset(nc_put_att_text(ncid, NC_GLOBAL, name.Buf(), strlen(val) + 1, val));
else
err.Reset(nc_put_att_text(ncid, NC_GLOBAL, name.Buf(), val.Len() + 1, val.Buf()));
}
template<class T>
requires(Type2NCType<T> != NC_NAT)
void AddAtt(const MString& vname, const MString& name, const T& val)
{
if(err.IsErr()) return;
static constexpr auto nct = Type2NCType<T>;
static constexpr bool ischar = std::is_same_v<T, char*>;
int varid;
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid));
if(err.IsErr()) return;
if constexpr(nct != NC_CHAR)
err.Reset(nc_put_att(ncid, varid, name.Buf(), nct, 1, &val));
else if constexpr(ischar)
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), strlen(val) + 1, val));
else
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), val.Len() + 1, val.Buf()));
}
void AddAtt(const MString& vname, const MString& name, const char* val)
{
if(err.IsErr()) return;
int varid;
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid));
if(err.IsErr()) return;
err.Reset(nc_put_att_text(ncid, varid, name.Buf(), strlen(val) + 1, val));
}
template<class... T> void AddVar(const MString& vname, nc_type type, const T&... dnames) { AddVar(vname, type, std::vector<MString>({dnames...})); }
void EndDef() const { nc_enddef(ncid); }
void SetComp(const MString& vname, int comp)
{
if(err.IsErr()) return;
int varid;
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid));
if(err.IsErr()) return;
err.Reset(nc_def_var_deflate(ncid, varid, 1, 1, comp));
}
template<class T>
requires requires(int nc, int vid, const T* d) {
{
int ydimid, xdimid;
};
int dimid[2];
NCTypeD<T, void>::put_var(nc, vid, d)
} -> std::same_as<int>;
}
void WriteVar(const MString& vname, const T* data)
{
if(err.IsErr()) return;
int varid;
err.Reset(nc_inq_varid(ncid, vname.Buf(), &varid));
if(err.IsErr()) return;
err.Reset(NCTypeD<T, void>::put_var(ncid, varid, data));
}
private:
// Members
int ncid;
Error err = NC_NOERR;
bool opened = false;
void AddVar(const MString& vname, nc_type type, std::vector<MString>&& dnames)
{
if(err.IsErr()) return;
std::vector<int> dimids(dnames.size());
int varid;
for(size_t i = 0; i < dnames.size(); i++)
{
err.Reset(nc_inq_dimid(ncid, dnames[i].Buf(), &dimids[i]));
if(err.IsErr()) return;
}
err.Reset(nc_def_var(ncid, vname.Buf(), type, dimids.size(), dimids.data(), &varid));
}
};
class NCFileW: public NCFileWBase
{
enum Type
{
UNKNOWN,
PSET,
GPSET,
GRID,
GGRID,
RGRID,
GRGRID
};
int xid, yid;
int compress;
std::vector<struct Var> vars;
static constexpr auto fill = std::numeric_limits<float>::max();
Type type = UNKNOWN;
int compress;
template<class D> static constexpr Type DetType()
{
if constexpr(ReadIs2DGeoRectArray<D>) return G1V2;
if constexpr(ReadIs2DGeoArray<D>) return G2V2;
if constexpr(ReadIs1DGeoArray<D>) return G1V1;
if constexpr(ReadIs2DGeoRectArray<D>) return GRGRID;
if constexpr(ReadIs2DGeoArray<D>) return GGRID;
if constexpr(ReadIs1DGeoArray<D>) return GPSET;
if constexpr(ReadIs2DXYRectArray<D>) return RGRID;
if constexpr(ReadIs2DXYArray<D>) return GRID;
if constexpr(ReadIs1DArray<D>) return PSET;
return UNKNOWN;
};
template<class D> static constexpr bool Is1DType() { return Is1DType(DetType<D>()); }
static constexpr bool Is1DType(Type t) { return t == G1V1; }
static constexpr bool IsGeoType(Type t) { return t == GPSET || t == GGRID || t == GRGRID; }
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);
public:
static constexpr auto Fill() { return fill; }
~NCFileW() { Close(); }
template<class D> MString Create(const D& data, const MString& name, const MString& history, int compression)
{
if(type != UNKNOWN) return "File already created";
@ -67,78 +271,53 @@ class NCFileW
return CreateFile(DetType<D>(), name, history, compression, data.Nx(), data.Ny());
}
size_t VarId(const MString& name) const
{
for(size_t i = 0; i < vars.size(); i++)
if(vars[i].name == name) return i + 1;
return 0;
}
bool HaveVar(const MString& name) const { return VarId(name) != 0; }
void EndDef() const
{
if(type != UNKNOWN) nc_enddef(ncid);
}
void Close()
{
if(type != UNKNOWN) nc_close(ncid);
NCFileWBase::Close();
type = UNKNOWN;
}
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, size_t varid, Op op) const
template<class D, class Op> MString WriteVariable(const D& data, const MString& name, Op op)
{
static constexpr auto dtype = DetType<D>();
if(type == UNKNOWN) return "File not open";
if(type != dtype) return "Incompatible data type";
if(varid == 0) return "Incorrect variable";
if constexpr(dtype == UNKNOWN) return "Unknown data type";
size_t v = varid - 1;
EndDef();
int ret;
if constexpr(Is1DType(dtype))
{
const size_t i = 0, c = data.N();
const size_t c = data.N();
float buf[c];
for(size_t ix = 0; ix < c; ix++) buf[ix] = data.IsFill(ix) ? fill : op(ix);
ret = nc_put_vara_float(ncid, vars[v].id, &i, &c, buf);
if(ret != NC_NOERR) return "Can't write " + vars[v].name + " variable in the netcdf file";
WriteVar(name, buf);
}
else
{
const size_t i[2] = {0, 0};
const size_t c[2] = {data.Ny(), data.Nx()};
float buf[c[0] * c[1]];
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);
ret = nc_put_vara_float(ncid, vars[v].id, i, c, buf);
if(ret != NC_NOERR) return "Can't write " + vars[v].name + " variable in the netcdf file";
WriteVar(name, buf);
}
if(!*this) return "Can't write variable " + name + ": " + ErrMessage();
return "";
}
template<class D, class Op> MString WriteVariable(const D& data, const MString& name, Op op) const { return WriteVariable(data, VarId(name), op); }
template<class D> MString WriteVariable(const D& data, size_t varid) const
template<class D> MString WriteVariable(const D& data, const MString& name)
{
if constexpr(Is1DType(DetType<D>()))
return WriteVariable(data, varid, [&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); });
else
return WriteVariable(data, varid, [&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); });
}
template<class D> MString WriteVariable(const D& data, const MString& name) const { return WriteVariable(data, VarId(name)); }
template<class D> MString WriteGrid(const D& data) const
template<class D> MString WriteGrid(const D& data)
{
static constexpr auto dtype = DetType<D>();
if(type == UNKNOWN) return "File not open";
@ -146,10 +325,24 @@ class NCFileW
EndDef();
int ret;
if constexpr(dtype == G1V1)
if constexpr(dtype == UNKNOWN)
return "Unknown data type";
else if constexpr(dtype == PSET)
{
const size_t i = 0, c = data.N();
const size_t c = data.N();
float bufx[c];
float bufy[c];
for(size_t ix = 0; ix < c; ix++)
{
bufx[ix] = data.X(ix);
bufy[ix] = data.Y(ix);
}
WriteVar("x", bufx);
WriteVar("y", bufy);
}
else if constexpr(dtype == GPSET)
{
const size_t c = data.N();
float bufx[c];
float bufy[c];
for(size_t ix = 0; ix < c; ix++)
@ -157,28 +350,45 @@ class NCFileW
bufx[ix] = data.Lon(ix);
bufy[ix] = data.Lat(ix);
}
ret = nc_put_vara_float(ncid, xid, &i, &c, bufx);
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file";
ret = nc_put_vara_float(ncid, yid, &i, &c, bufy);
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file";
WriteVar("longitude", bufx);
WriteVar("latitude", bufy);
}
else if constexpr(dtype == G1V2)
else if constexpr(dtype == RGRID)
{
const size_t i = 0, cx = data.Nx(), cy = data.Ny();
const size_t cx = data.Nx(), cy = data.Ny();
float bufx[cx];
float bufy[cy];
for(size_t ix = 0; ix < cx; ix++) bufx[ix] = data.Ix2X(ix);
for(size_t iy = 0; iy < cy; iy++) bufy[iy] = data.Iy2Y(iy);
WriteVar("x", bufx);
WriteVar("y", bufy);
}
else if constexpr(dtype == GRGRID)
{
const size_t cx = data.Nx(), cy = data.Ny();
float bufx[cx];
float bufy[cy];
for(size_t ix = 0; ix < cx; ix++) bufx[ix] = data.Ix2Lon(ix);
for(size_t iy = 0; iy < cy; iy++) bufy[iy] = data.Iy2Lat(iy);
ret = nc_put_vara_float(ncid, xid, &i, &cx, bufx);
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file";
ret = nc_put_vara_float(ncid, yid, &i, &cy, bufy);
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file";
WriteVar("longitude", bufx);
WriteVar("latitude", bufy);
}
else if constexpr(dtype == G2V2)
else if constexpr(dtype == GRID)
{
const size_t c[2] = {data.Ny(), data.Nx()};
float bufx[c[0] * c[1]];
float bufy[c[0] * c[1]];
for(size_t iy = 0; iy < c[0]; iy++)
for(size_t ix = 0; ix < c[1]; ix++)
{
bufx[iy * c[1] + ix] = data.X(ix, iy);
bufy[iy * c[1] + ix] = data.Y(ix, iy);
}
WriteVar("x", bufx);
WriteVar("y", bufy);
}
else if constexpr(dtype == GGRID)
{
const size_t i[2] = {0, 0};
const size_t c[2] = {data.Ny(), data.Nx()};
float bufx[c[0] * c[1]];
float bufy[c[0] * c[1]];
@ -188,14 +398,14 @@ class NCFileW
bufx[iy * c[1] + ix] = data.Lon(ix, iy);
bufy[iy * c[1] + ix] = data.Lat(ix, iy);
}
ret = nc_put_vara_float(ncid, xid, i, c, bufx);
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file";
ret = nc_put_vara_float(ncid, yid, i, c, bufy);
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file";
WriteVar("longitude", bufx);
WriteVar("latitude", bufy);
}
else
return "Unknown data type";
if(!*this) return MString("Can't write grid: ") + ErrMessage();
return "";
}
};

145
src/ncfilew.cpp

@ -7,77 +7,82 @@ MString NCFileW::CreateFile(NCFileW::Type stype, const MString& name, const MStr
compress = compression;
int ret;
MString text;
const float node_offset = 0.0;
ret = nc_create(name.Buf(), NC_CLOBBER | NC_NETCDF4, &ncid);
if(ret != NC_NOERR) return "Can't create netcdf file: " + name;
ret = nc_put_att_text(ncid, NC_GLOBAL, "history", history.Len() + 1, history.Buf());
if(ret != NC_NOERR) return "Can't write history attribute in the netcdf file";
Open(name);
if(!*this) return "Can't create netcdf file " + name + ": " + ErrMessage();
ret = nc_put_att(ncid, NC_GLOBAL, "node_offset", NC_FLOAT, 1, &node_offset);
if(ret != NC_NOERR) return "Can't write node_offset attribute in the netcdf file";
AddAtt("history", history);
AddAtt("node_offset", node_offset);
switch(stype)
{
case(G1V1):
case(PSET):
{
AddDim("i", nx);
AddVar("x", NC_FLOAT, "i");
AddVar("y", NC_FLOAT, "i");
break;
}
case(GPSET):
{
AddDim("i", nx);
AddVar("longitude", NC_FLOAT, "i");
AddVar("latitude", NC_FLOAT, "i");
break;
}
case(RGRID):
{
AddDim("x", nx);
AddDim("y", ny);
AddVar("x", NC_FLOAT, "x");
AddVar("y", NC_FLOAT, "y");
break;
}
case(GRGRID):
{
ret = nc_def_dim(ncid, "i", nx, &xdimid);
if(ret != NC_NOERR) return "Can't create dimension in the netcdf file";
ret = nc_def_var(ncid, "longitude", NC_FLOAT, 1, &xdimid, &xid);
if(ret != NC_NOERR) return "Can't create longitude variable in the netcdf file";
ret = nc_def_var(ncid, "latitude", NC_FLOAT, 1, &xdimid, &yid);
if(ret != NC_NOERR) return "Can't create latitude variable in the netcdf file";
AddDim("longitude", nx);
AddDim("latitude", ny);
AddVar("longitude", NC_FLOAT, "longitude");
AddVar("latitude", NC_FLOAT, "latitude");
break;
}
case(G1V2):
case(GRID):
{
ret = nc_def_dim(ncid, "longitude", nx, &xdimid);
if(ret != NC_NOERR) return "Can't create x-dimension in the netcdf file";
ret = nc_def_dim(ncid, "latitude", ny, &ydimid);
if(ret != NC_NOERR) return "Can't create y-dimension in the netcdf file";
ret = nc_def_var(ncid, "longitude", NC_FLOAT, 1, &xdimid, &xid);
if(ret != NC_NOERR) return "Can't create longitude variable in the netcdf file";
ret = nc_def_var(ncid, "latitude", NC_FLOAT, 1, &ydimid, &yid);
if(ret != NC_NOERR) return "Can't create latitude variable in the netcdf file";
AddDim("x", nx);
AddDim("y", ny);
AddVar("x", NC_FLOAT, "y", "x");
AddVar("y", NC_FLOAT, "y", "x");
break;
}
case(G2V2):
case(GGRID):
{
ret = nc_def_dim(ncid, "longitude", nx, &xdimid);
if(ret != NC_NOERR) return "Can't create x-dimension in the netcdf file";
ret = nc_def_dim(ncid, "latitude", ny, &ydimid);
if(ret != NC_NOERR) return "Can't create y-dimension in the netcdf file";
ret = nc_def_var(ncid, "longitude", NC_FLOAT, 2, dimid, &xid);
if(ret != NC_NOERR) return "Can't create longitude variable in the netcdf file";
ret = nc_def_var(ncid, "latitude", NC_FLOAT, 2, dimid, &yid);
if(ret != NC_NOERR) return "Can't create latitude variable in the netcdf file";
AddDim("longitude", nx);
AddDim("latitude", ny);
AddVar("longitude", NC_FLOAT, "latitude", "longitude");
AddVar("latitude", NC_FLOAT, "latitude", "longitude");
break;
}
case(UNKNOWN): return "Can't determine file type";
}
ret = nc_def_var_deflate(ncid, xid, 1, 1, compress);
if(ret != NC_NOERR) return "Can't set deflate parameters for longitude variable in the netcdf file";
ret = nc_def_var_deflate(ncid, yid, 1, 1, compress);
if(ret != NC_NOERR) return "Can't set deflate parameters for latitude variable in the netcdf file";
text = "longitude";
ret = nc_put_att_text(ncid, xid, "standard_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write standard_name attribute of longitude variable in the netcdf file";
text = "latitude";
ret = nc_put_att_text(ncid, yid, "standard_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write standard_name attribute of latitude variable in the netcdf file";
text = "Longitude";
ret = nc_put_att_text(ncid, xid, "long_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of longitude variable in the netcdf file";
text = "Latitude";
ret = nc_put_att_text(ncid, yid, "long_name", text.Len() + 1, text.Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of latitude variable in the netcdf file";
if(IsGeoType(stype))
{
SetComp("longitude", compress);
SetComp("latitude", compress);
AddAtt("longitude", "standard_name", "longitude");
AddAtt("longitude", "long_name", "Longitude");
AddAtt("latitude", "standard_name", "latitude");
AddAtt("latitude", "long_name", "Latitude");
}
else
{
SetComp("x", compress);
SetComp("y", compress);
AddAtt("x", "long_name", "x-coordinate");
AddAtt("y", "long_name", "y-coordinate");
}
if(!*this) return "Can't set grid in the netcdf file " + name + ": " + ErrMessage();
type = stype;
return "";
@ -86,32 +91,22 @@ MString NCFileW::CreateFile(NCFileW::Type stype, const MString& name, const MStr
MString NCFileW::AddVariable(const MString& name, const MString& stname, const MString& lname, const MString& units, const MString& comment)
{
if(type == UNKNOWN) return "File not opened";
if(HaveVar(name)) return "Variable " + name + " already defined";
struct Var v(name, 0);
int ret;
if(type == G1V1)
ret = nc_def_var(ncid, v.name.Buf(), NC_FLOAT, 1, &xdimid, &v.id);
if(Is1DType(type))
AddVar(name, NC_FLOAT, "i");
else if(IsGeoType(type))
AddVar(name, NC_FLOAT, "latitude", "longitude");
else
ret = nc_def_var(ncid, v.name.Buf(), NC_FLOAT, 2, dimid, &v.id);
if(ret != NC_NOERR) return "Can't create " + v.name + " variable in the netcdf file";
ret = nc_def_var_deflate(ncid, v.id, 1, 1, compress);
if(ret != NC_NOERR) return "Can't set deflate parameters for " + v.name + " variable in the netcdf file";
AddVar(name, NC_FLOAT, "y", "x");
if(stname.Exist()) ret = nc_put_att_text(ncid, v.id, "standard_name", stname.Len() + 1, stname.Buf());
if(ret != NC_NOERR) return "Can't write standard_name attribute of " + v.name + " variable in the netcdf file";
if(lname.Exist()) ret = nc_put_att_text(ncid, v.id, "long_name", lname.Len() + 1, lname.Buf());
if(ret != NC_NOERR) return "Can't write long_name attribute of " + v.name + " variable in the netcdf file";
if(units.Exist()) ret = nc_put_att_text(ncid, v.id, "units", units.Len() + 1, units.Buf());
if(ret != NC_NOERR) return "Can't write units attribute of " + v.name + " variable in the netcdf file";
if(comment.Exist()) ret = nc_put_att_text(ncid, v.id, "comment", comment.Len() + 1, comment.Buf());
if(ret != NC_NOERR) return "Can't write comment attribute of " + v.name + " variable in the netcdf file";
SetComp(name, compress);
if(stname.Exist()) AddAtt(name, "standard_name", stname);
if(lname.Exist()) AddAtt(name, "long_name", lname);
if(units.Exist()) AddAtt(name, "units", units);
if(comment.Exist()) AddAtt(name, "comment", comment);
AddAtt(name, "_FillValue", fill);
ret = nc_put_att_float(ncid, v.id, "_FillValue", NC_FLOAT, 1, &fill);
if(ret != NC_NOERR) return "Can't write _FillValue attribute of " + v.name + " variable in the netcdf file";
if(!*this) return "Can't add variable " + name + ": " + ErrMessage();
vars.push_back(v);
return "";
}

Loading…
Cancel
Save