Compare commits

..

5 Commits

  1. 143
      actions/actiongrad.cpp
  2. 19
      actions/actiongrad.h
  3. 87
      actions/actionuv.cpp
  4. 374
      include/ncfilew.h
  5. 2
      michlib
  6. 58
      sources/NEMO.h
  7. 20
      src/layereddata.cpp
  8. 145
      src/ncfilew.cpp
  9. 1
      src/ncfuncs.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, 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) const std::vector<GradMethods::DataType>& lons, const std::vector<GradMethods::DataType>& lats, int compress)
{ {
int ret;
const float node_offset = 0.0; const float node_offset = 0.0;
auto nx = lons.size(); auto nx = lons.size();
auto ny = lats.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()); const auto fill = static_cast<GradMethods::DataType>(std::numeric_limits<GradMethods::Matrix::MDataType>::max());
// Creating // Creating
ret = nc_create(name.Buf(), NC_CLOBBER | NC_NETCDF4, &newnc.ncid); Open(name);
if(ret != NC_NOERR) return "Can't create netcdf file: " + name; if(!*this) return "Can't create netcdf file " + name + ": " + ErrMessage();
newnc.active = true;
AddAtt("history", history);
// Global attributes AddAtt("node_offset", node_offset);
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"; AddDim("longitude", nx);
AddDim("latitude", ny);
ret = nc_put_att(newnc, NC_GLOBAL, "node_offset", NC_FLOAT, 1, &node_offset); AddVar("longitude", NC_FLOAT, "longitude");
if(ret != NC_NOERR) return "Can't write history attribute in the netcdf file"; AddVar("latitude", NC_FLOAT, "latitude");
SetComp("longitude", compress);
// Dimensions SetComp("latitude", compress);
ret = nc_def_dim(newnc, "longitude", nx, &dim.xdimid); AddAtt("longitude", "standard_name", "longitude");
if(ret != NC_NOERR) return "Can't create x-dimension in the netcdf file"; AddAtt("longitude", "long_name", "Longitude");
ret = nc_def_dim(newnc, "latitude", ny, &dim.ydimid); AddAtt("latitude", "standard_name", "latitude");
if(ret != NC_NOERR) return "Can't create y-dimension in the netcdf file"; AddAtt("latitude", "long_name", "Latitude");
// 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";
// Variables // Variables
for(size_t i = 0; i < vnames.size(); i++) for(size_t i = 0; i < vnames.size(); i++)
{ {
int vid; AddVar(vnames[i], NC_FLOAT, "latitude", "longitude");
ret = nc_def_var(newnc, vnames[i].Buf(), NC_FLOAT, 2, dim.dimid, &vid); SetComp(vnames[i], compress);
if(ret != NC_NOERR) return "Can't create " + vnames[i] + " variable in the netcdf file"; if(lnames[i].Exist()) AddAtt(vnames[i], "long_name", lnames[i]);
AddAtt(vnames[i], "_FillValue", fill);
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";
} }
// End definitions // End definitions
nc_enddef(newnc); EndDef();
// Writing lon, lat // 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(!*this) return "Can't set grid in the netcdf file " + name + ": " + ErrMessage();
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";
ncid = newnc;
newnc.active = false;
return ""; 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; WriteVar(name, data.Data().data());
int vid; if(!*this) return "Can't write variable " + name + ": " + ErrMessage();
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]);
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 ""; return "";
} }

19
actions/actiongrad.h

@ -45,25 +45,12 @@ class GradMethods::Matrix
const auto& Data() const { return data; } const auto& Data() const { return data; }
}; };
class GradMethods::NCFileW class GradMethods::NCFileW: public NCFileWBase
{ {
bool opened;
int ncid;
public: 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, 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); const std::vector<GradMethods::DataType>& lats, int compress);
MString WriteVar(const MString& name, const std::vector<GradMethods::Matrix::MDataType>& data); MString WriteVariable(const MString& name, const GradMethods::Matrix& data);
~NCFileW() { Close(); }
void Close()
{
if(opened) nc_close(ncid);
opened = false;
}
}; };
template<class T> template<class T>
@ -139,7 +126,7 @@ template<class D> MString ActionGRAD::DoAction(const CLArgs& args, D& ds)
{ {
const MString& name = ds.VarNames()[i]; const MString& name = ds.VarNames()[i];
data[i].Grad(); data[i].Grad();
fw.WriteVar(name, data[i].Data()); fw.WriteVariable(name, data[i]);
} }
return ""; 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 MString UVMethods::StPoints::WriteNcFile(const MString& name, const MString& history, int comp) const
{ {
int ret; NCFileWBase nc;
int ncid;
int dimid;
int xid, yid, tid;
MString text;
ret = nc_create(name.Buf(), NC_CLOBBER | NC_NETCDF4, &ncid); const MString xname = lonlat ? "longitude" : "x";
if(ret != NC_NOERR) return "Can't create netcdf file: " + name; const MString yname = lonlat ? "latitude" : "y";
ret = nc_put_att_text(ncid, NC_GLOBAL, "history", history.Len() + 1, history.Buf()); nc.Open(name);
if(ret != NC_NOERR) return "Can't write history attribute in the netcdf file"; if(!nc) return "Can't create netcdf file " + name + ": " + nc.ErrMessage();
ret = nc_def_dim(ncid, "i", N(), &dimid); nc.AddAtt("history", history);
if(ret != NC_NOERR) return "Can't create dimension in the netcdf file"; nc.AddDim("i", N());
nc.AddVar(xname, NC_FLOAT, "i");
ret = nc_def_var(ncid, lonlat ? "longitude" : "x", NC_FLOAT, 1, &dimid, &xid); nc.AddVar(yname, NC_FLOAT, "i");
if(ret != NC_NOERR) return "Can't create x variable in the netcdf file"; nc.SetComp(xname, comp);
ret = nc_def_var(ncid, lonlat ? "latitude" : "y", NC_FLOAT, 1, &dimid, &yid); nc.SetComp(yname, comp);
if(ret != NC_NOERR) return "Can't create y variable in the netcdf file";
if(lonlat) if(lonlat)
{ {
text = "longitude"; nc.AddAtt(xname, "standard_name", "longitude");
ret = nc_put_att_text(ncid, xid, "standard_name", text.Len() + 1, text.Buf()); nc.AddAtt(xname, "long_name", "Longitude");
if(ret != NC_NOERR) return "Can't write standard_name attribute of longitude variable in the netcdf file"; nc.AddAtt(yname, "standard_name", "latitude");
text = "latitude"; nc.AddAtt(yname, "long_name", "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"; else
{
text = "Longitude"; nc.AddAtt(xname, "long_name", "x-coordinate");
ret = nc_put_att_text(ncid, xid, "long_name", text.Len() + 1, text.Buf()); nc.AddAtt(yname, "long_name", "y-coordinate");
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";
} }
ret = nc_def_var_deflate(ncid, xid, 1, 1, comp); nc.AddVar("type", NC_UBYTE, "i");
if(ret != NC_NOERR) return "Can't set deflate parameters for x variable in the netcdf file"; nc.SetComp("type", comp);
ret = nc_def_var_deflate(ncid, yid, 1, 1, comp); nc.AddAtt("type", "long_name",
if(ret != NC_NOERR) return "Can't set deflate parameters for y variable in the netcdf file"; "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_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];
for(size_t ix = 0; ix < c; ix++) buf[ix] = x[ix]; if(!nc) return "Can't set grid in the netcdf file " + name + ": " + nc.ErrMessage();
ret = nc_put_vara_float(ncid, xid, &i, &c, buf);
if(ret != NC_NOERR) return "Can't write x variable in the netcdf file";
for(size_t ix = 0; ix < c; ix++) buf[ix] = y[ix]; nc.EndDef();
ret = nc_put_vara_float(ncid, yid, &i, &c, buf);
if(ret != NC_NOERR) return "Can't write y variable in the netcdf file";
ret = nc_put_vara_ubyte(ncid, tid, &i, &c, t.data()); nc.WriteVar(xname, x.data());
if(ret != NC_NOERR) return "Can't write type variable in the netcdf file"; nc.WriteVar(yname, y.data());
nc.WriteVar("type", t.data());
ret = nc_close(ncid); if(!nc) return "Can't write data to the netcdf file " + name + ": " + nc.ErrMessage();
if(ret != NC_NOERR) return "Can't close netcdf file";
return ""; return "";
} }

374
include/ncfilew.h

@ -8,56 +8,260 @@
using michlib::MString; using michlib::MString;
class NCFileW class NCFileWBase
{ {
enum Type template<class T, class Dummy> struct NCTypeD
{ {
UNKNOWN, static constexpr nc_type nc = NC_NAT;
G1V1, };
G1V2,
G2V2 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; static constexpr nc_type nc = NC_CHAR;
int id;
}; };
static constexpr auto fill = std::numeric_limits<float>::max(); template<class T> using NCType = NCTypeD<T, void>;
public:
template<class T> static constexpr nc_type Type2NCType = NCType<T>::nc;
// Error class
class Error
{
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) {
{
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; int ncid;
Type type = UNKNOWN; Error err = NC_NOERR;
union bool opened = false;
void AddVar(const MString& vname, nc_type type, std::vector<MString>&& dnames)
{ {
struct if(err.IsErr()) return;
std::vector<int> dimids(dnames.size());
int varid;
for(size_t i = 0; i < dnames.size(); i++)
{ {
int ydimid, xdimid; err.Reset(nc_inq_dimid(ncid, dnames[i].Buf(), &dimids[i]));
}; if(err.IsErr()) return;
int dimid[2]; }
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;
static constexpr auto fill = std::numeric_limits<float>::max();
Type type = UNKNOWN;
int compress; int compress;
std::vector<struct Var> vars;
template<class D> static constexpr Type DetType() template<class D> static constexpr Type DetType()
{ {
if constexpr(ReadIs2DGeoRectArray<D>) return G1V2; if constexpr(ReadIs2DGeoRectArray<D>) return GRGRID;
if constexpr(ReadIs2DGeoArray<D>) return G2V2; if constexpr(ReadIs2DGeoArray<D>) return GGRID;
if constexpr(ReadIs1DGeoArray<D>) return G1V1; 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; return UNKNOWN;
}; };
template<class D> static constexpr bool Is1DType() { return Is1DType(DetType<D>()); } 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); MString CreateFile(Type stype, const MString& name, const MString& history, int compression, size_t nx, size_t ny);
public: public:
static constexpr auto Fill() { return fill; } static constexpr auto Fill() { return fill; }
~NCFileW() { Close(); }
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, const MString& history, int compression)
{ {
if(type != UNKNOWN) return "File already created"; if(type != UNKNOWN) return "File already created";
@ -67,78 +271,53 @@ class NCFileW
return CreateFile(DetType<D>(), name, history, compression, data.Nx(), data.Ny()); 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() void Close()
{ {
if(type != UNKNOWN) nc_close(ncid); NCFileWBase::Close();
type = UNKNOWN; type = UNKNOWN;
} }
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, 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>(); static constexpr auto dtype = DetType<D>();
if(type == UNKNOWN) return "File not open"; if(type == UNKNOWN) return "File not open";
if(type != dtype) return "Incompatible data type"; if(type != dtype) return "Incompatible data type";
if(varid == 0) return "Incorrect variable";
if constexpr(dtype == UNKNOWN) return "Unknown data type"; if constexpr(dtype == UNKNOWN) return "Unknown data type";
size_t v = varid - 1;
EndDef(); EndDef();
int ret;
if constexpr(Is1DType(dtype)) if constexpr(Is1DType(dtype))
{ {
const size_t i = 0, 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);
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";
} }
else else
{ {
const size_t i[2] = {0, 0};
const size_t c[2] = {data.Ny(), data.Nx()}; const size_t c[2] = {data.Ny(), data.Nx()};
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);
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";
} }
if(!*this) return "Can't write variable " + name + ": " + ErrMessage();
return ""; 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, const MString& name)
template<class D> MString WriteVariable(const D& data, size_t varid) const
{ {
if constexpr(Is1DType(DetType<D>())) 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 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)
template<class D> MString WriteGrid(const D& data) const
{ {
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";
@ -146,10 +325,24 @@ class NCFileW
EndDef(); EndDef();
int ret; if constexpr(dtype == UNKNOWN)
if constexpr(dtype == G1V1) return "Unknown data type";
else if constexpr(dtype == PSET)
{
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 i = 0, c = data.N(); const size_t c = data.N();
float bufx[c]; float bufx[c];
float bufy[c]; float bufy[c];
for(size_t ix = 0; ix < c; ix++) for(size_t ix = 0; ix < c; ix++)
@ -157,28 +350,45 @@ class NCFileW
bufx[ix] = data.Lon(ix); bufx[ix] = data.Lon(ix);
bufy[ix] = data.Lat(ix); bufy[ix] = data.Lat(ix);
} }
ret = nc_put_vara_float(ncid, xid, &i, &c, bufx); WriteVar("longitude", bufx);
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file"; WriteVar("latitude", bufy);
ret = nc_put_vara_float(ncid, yid, &i, &c, bufy);
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file";
} }
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 bufx[cx];
float bufy[cy]; float bufy[cy];
for(size_t ix = 0; ix < cx; ix++) bufx[ix] = data.Ix2Lon(ix); 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); for(size_t iy = 0; iy < cy; iy++) bufy[iy] = data.Iy2Lat(iy);
WriteVar("longitude", bufx);
ret = nc_put_vara_float(ncid, xid, &i, &cx, bufx); WriteVar("latitude", bufy);
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file"; }
ret = nc_put_vara_float(ncid, yid, &i, &cy, bufy); else if constexpr(dtype == GRID)
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file"; {
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);
} }
else if constexpr(dtype == G2V2) 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()}; const size_t c[2] = {data.Ny(), data.Nx()};
float bufx[c[0] * c[1]]; float bufx[c[0] * c[1]];
float bufy[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); bufx[iy * c[1] + ix] = data.Lon(ix, iy);
bufy[iy * c[1] + ix] = data.Lat(ix, iy); bufy[iy * c[1] + ix] = data.Lat(ix, iy);
} }
ret = nc_put_vara_float(ncid, xid, i, c, bufx); WriteVar("longitude", bufx);
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file"; WriteVar("latitude", bufy);
ret = nc_put_vara_float(ncid, yid, i, c, bufy);
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file";
} }
else else
return "Unknown data type"; return "Unknown data type";
if(!*this) return MString("Can't write grid: ") + ErrMessage();
return ""; return "";
} }
}; };

2
michlib

@ -1 +1 @@
Subproject commit a2105413f8a10e8695c85706487d4db5d2f54a61 Subproject commit 6268edea843cae04337fe6493b611f3a4fe7cc9b

58
sources/NEMO.h

@ -8,7 +8,21 @@ class NEMOData: public LayeredData
TYPE_UNKNOWN, TYPE_UNKNOWN,
TYPE_DT, TYPE_DT,
TYPE_NRT, TYPE_NRT,
TYPE_NRT6 TYPE_NRT6,
TYPE_BALTICDT,
TYPE_BALTICNRT,
TYPE_BALTICNRT1,
TYPE_BLKSEADT,
TYPE_BLKSEANRT,
TYPE_MEDSEADT,
TYPE_MEDSEANRT,
TYPE_MEDSEANRT1,
TYPE_BISCDT,
TYPE_BISCNRT,
TYPE_ENWSDT,
TYPE_ENWSNRT,
TYPE_BRITNRT,
TYPE_BRITNRT1
}; };
Type type = TYPE_UNKNOWN; Type type = TYPE_UNKNOWN;
@ -25,6 +39,20 @@ class NEMOData: public LayeredData
case(TYPE_DT): return "NEMO Delayed time, daily mean (DT)"; case(TYPE_DT): return "NEMO Delayed time, daily mean (DT)";
case(TYPE_NRT): return "NEMO Near-real time, daily mean (NRT)"; case(TYPE_NRT): return "NEMO Near-real time, daily mean (NRT)";
case(TYPE_NRT6): return "NEMO Near-real time, 6h resolution (NRT6)"; case(TYPE_NRT6): return "NEMO Near-real time, 6h resolution (NRT6)";
case(TYPE_BALTICDT): return "NEMO Delayed time, Baltic region, daily mean (BALTICDT)";
case(TYPE_BALTICNRT): return "NEMO Near-real time, Baltic region, daily mean (BALTICNRT)";
case(TYPE_BALTICNRT1): return "NEMO Near-real time, Baltic region, 1h resolution (BALTICNRT1)";
case(TYPE_BLKSEADT): return "NEMO Delayed time, Black Sea region, daily mean (BLKSEADT)";
case(TYPE_BLKSEANRT): return "NEMO Near-real time time, Black Sea region, daily mean (BLKSEANRT)";
case(TYPE_MEDSEADT): return "NEMO Delayed time, Mediterranean Sea region, daily mean (MEDSEADT)";
case(TYPE_MEDSEANRT): return "NEMO Near-real time, Mediterranean Sea region, daily mean (MEDSEANRT)";
case(TYPE_MEDSEANRT1): return "NEMO Near-real time, Mediterranean Sea region, hourly mean (MEDSEANRT1)";
case(TYPE_BISCDT): return "NEMO Delayed time, Atlantic-Iberian Biscay Irish region, daily mean (BISCDT)";
case(TYPE_BISCNRT): return "NEMO Near-real time, Atlantic-Iberian Biscay Irish region, daily mean (BISCNRT)";
case(TYPE_ENWSDT): return "NEMO Delayed time, Atlantic - European North West Shelf region, daily mean (ENWSDT)";
case(TYPE_ENWSNRT): return "NEMO Near-real time, Atlantic - European North West Shelf region, daily mean (ENWSNRT)";
case(TYPE_BRITNRT): return "NEMO Near-real time, British Islands region, daily mean (BRITNRT)";
case(TYPE_BRITNRT1): return "NEMO Near-real time, British Islands region, 1h resolution (BRITNRT1)";
default: return "No title"; default: return "No title";
} }
} }
@ -41,6 +69,34 @@ class NEMOData: public LayeredData
type = TYPE_NRT; type = TYPE_NRT;
else if(dataset == "NRT6") else if(dataset == "NRT6")
type = TYPE_NRT6; type = TYPE_NRT6;
else if(dataset == "BALTICDT")
type = TYPE_BALTICDT;
else if(dataset == "BALTICNRT")
type = TYPE_BALTICNRT;
else if(dataset == "BALTICNRT1")
type = TYPE_BALTICNRT1;
else if(dataset == "BLKSEADT")
type = TYPE_BLKSEADT;
else if(dataset == "BLKSEANRT")
type = TYPE_BLKSEANRT;
else if(dataset == "MEDSEADT")
type = TYPE_MEDSEADT;
else if(dataset == "MEDSEANRT")
type = TYPE_MEDSEANRT;
else if(dataset == "MEDSEANRT1")
type = TYPE_MEDSEANRT1;
else if(dataset == "BISCDT")
type = TYPE_BISCDT;
else if(dataset == "BISCNRT")
type = TYPE_BISCNRT;
else if(dataset == "ENWSDT")
type = TYPE_ENWSDT;
else if(dataset == "ENWSNRT")
type = TYPE_ENWSNRT;
else if(dataset == "BRITNRT")
type = TYPE_BRITNRT;
else if(dataset == "BRITNRT1")
type = TYPE_BRITNRT1;
else else
return "Unknown dataset: " + dataset; return "Unknown dataset: " + dataset;

20
src/layereddata.cpp

@ -139,20 +139,30 @@ std::pair<const BaseParameters*, MString> LayeredData::Parameters(michlib_intern
real lon2 = ToGeoDomain(reg.lone, dom); real lon2 = ToGeoDomain(reg.lone, dom);
real lat1 = reg.latb; real lat1 = reg.latb;
real lat2 = reg.late; real lat2 = reg.late;
bool global = lone - lonb + 1.5 * lonstep > 360.0;
// Special case when the longitude lies in a small sector between the end and the start // Special case when the longitude lies in a small sector between the end and the start
if(global)
{
if(lon1 < lonb) lon1 = lone; if(lon1 < lonb) lon1 = lone;
if(lon2 > lone) lon2 = lonb; if(lon2 > lone) lon2 = lonb;
}
ppar->yb = static_cast<size_t>(Floor((lat1 - latb) / latstep)); else
ppar->ye = static_cast<size_t>(Ceil((lat2 - latb) / latstep)); {
if(ppar->ye > dname.ny - 1) ppar->ye = dname.ny - 1; if(lon1 < lonb) lon1 = lonb;
if(ppar->yb >= ppar->ye) return {nullptr, "Latb must be lesser then late"}; if(lon2 > lone) lon2 = lone;
}
ppar->xb = static_cast<size_t>(Floor((lon1 - lonb) / lonstep)); ppar->xb = static_cast<size_t>(Floor((lon1 - lonb) / lonstep));
ppar->xe = static_cast<size_t>(Ceil((lon2 - lonb) / lonstep)); ppar->xe = static_cast<size_t>(Ceil((lon2 - lonb) / lonstep));
if(ppar->xb == ppar->xe) return {nullptr, "Lonb must be not equal late"}; if(ppar->xb == ppar->xe) return {nullptr, "Lonb must be not equal late"};
if(!global && ppar->xb > ppar->xe) return {nullptr, "Lonb must be lesser then lone"};
ppar->yb = static_cast<size_t>(Floor((lat1 - latb) / latstep));
ppar->ye = static_cast<size_t>(Ceil((lat2 - latb) / latstep));
if(ppar->ye > dname.ny - 1) ppar->ye = dname.ny - 1;
if(ppar->yb >= ppar->ye) return {nullptr, "Latb must be lesser then late"};
if(depth < 0.0 || depth > depths.back()) if(depth < 0.0 || depth > depths.back())
ppar->layer = (depth < 0.0) ? 0 : (depths.size() - 1); ppar->layer = (depth < 0.0) ? 0 : (depths.size() - 1);

145
src/ncfilew.cpp

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

1
src/ncfuncs.cpp

@ -93,6 +93,7 @@ std::tuple<MDateTime, time_t, bool> NCFuncs::Refdate(const MString& refdate)
auto ci = words.begin(); auto ci = words.begin();
if(ci != words.end()) if(ci != words.end())
{ {
if(*ci == "seconds") step = 1;
if(*ci == "minutes") step = 60; if(*ci == "minutes") step = 60;
if(*ci == "hours") step = 3600; if(*ci == "hours") step = 3600;
if(*ci == "days") step = 3600 * 24; if(*ci == "days") step = 3600 * 24;

Loading…
Cancel
Save