Browse Source

Added support for writing attributes to netcdf files

lintest
Michael Uleysky 1 year ago
parent
commit
7a1690e6f0
  1. 4
      actions/actiontsc.h
  2. 6
      actions/actionuv.cpp
  3. 16
      actions/actionuv.h
  4. 113
      include/ncfilew.h
  5. 3
      src/ncfilew.cpp

4
actions/actiontsc.h

@ -20,6 +20,7 @@ template<class D> MString ActionTSC::DoAction(const CLArgs& args, D& ds)
michlib_internal::ParameterListEx pars;
pars.UsePrefix("");
pars.SetParameter("source", args.at("source"));
pars.SetParameter("history", args.at("_cmdline"));
auto [tindexes, err] = GetTIndexes(ds, args, pars);
if(err.Exist()) return err;
@ -114,7 +115,8 @@ template<class D> MString ActionTSC::DoAction(const CLArgs& args, D& ds)
if(args.contains("compress")) compress = args.at("compress").ToInt();
if(!err.Exist()) err = fw.Create(data[0], name, args.at("_cmdline"), compress);
if(!err.Exist()) err = fw.Create(data[0], name, compress);
if(!err.Exist()) err = fw.AddAtts(pars);
for(size_t i = 0; i < data.size(); i++)
if(!err.Exist()) err = fw.AddVariable(vnames[i], data[i].StandartName(), data[i].LongName(), data[i].Unit(), data[i].Comment());
if(!err.Exist()) err = fw.WriteGrid(data[0]);

6
actions/actionuv.cpp

@ -1,13 +1,14 @@
#define MICHLIB_NOSOURCE
#include "actionuv.h"
void UVMethods::StPoints::WriteBinBile(const MString& name) const
void UVMethods::StPoints::WriteBinBile(const MString& name, const michlib_internal::ParameterListEx& pars) const
{
BFileW stp;
stp.Create(name, 3);
stp.SetColumnName(1, lonlat ? "Longitude" : "x");
stp.SetColumnName(2, lonlat ? "Latitude" : "x");
stp.SetColumnName(3, "Stability (0 - saddle, 1 - st. anticicl. focus, 2 - st. knot, 3 - unst. anticicl. focus, 4 - unst. knot, 5 - st. cicl. focus, 6 - unst. cicl. focus)");
stp.SetParameters(pars);
for(size_t i = 0; i < N(); i++)
{
@ -19,7 +20,7 @@ void UVMethods::StPoints::WriteBinBile(const MString& name) const
stp.Close();
}
MString UVMethods::StPoints::WriteNcFile(const MString& name, const MString& history, int comp) const
MString UVMethods::StPoints::WriteNcFile(const MString& name, const michlib_internal::ParameterListEx& pars, const MString& history, int comp) const
{
NCFileWBase nc;
@ -30,6 +31,7 @@ MString UVMethods::StPoints::WriteNcFile(const MString& name, const MString& his
if(!nc) return "Can't create netcdf file " + name + ": " + nc.ErrMessage();
nc.AddAtt("history", history);
nc.AddAtts(pars);
nc.AddDim("i", N());
nc.AddVar(xname, NC_FLOAT, "i");
nc.AddVar(yname, NC_FLOAT, "i");

16
actions/actionuv.h

@ -86,9 +86,9 @@ class UVMethods
}
}
void WriteBinBile(const MString& name) const;
void WriteBinBile(const MString& name, const michlib_internal::ParameterListEx& pars) const;
MString WriteNcFile(const MString& name, const MString& history, int comp) const;
MString WriteNcFile(const MString& name, const michlib_internal::ParameterListEx& pars, const MString& history, int comp) const;
};
};
@ -105,6 +105,7 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
michlib_internal::ParameterListEx pars;
pars.UsePrefix("");
pars.SetParameter("source", args.at("source"));
pars.SetParameter("history", args.at("_cmdline"));
bool mode = args.contains("geostrophic");
@ -178,7 +179,8 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
if(args.contains("compress")) compress = args.at("compress").ToInt();
if(!err.Exist()) err = fw.Create(data, name, args.at("_cmdline"), compress);
if(!err.Exist()) err = fw.Create(data, name, compress);
if(!err.Exist()) err = fw.AddAtts(pars);
if(!err.Exist()) err = fw.AddVariable("u", "", "Eastward velocity", u, "");
if(!err.Exist()) err = fw.AddVariable("v", "", "Northward velocity", u, "");
if(!err.Exist()) err = fw.AddVariable("div", "", "Velocity divergence", "(" + u + ")/" + d, "");
@ -224,6 +226,7 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
vel.SetColumnName(2, "Latitude");
vel.SetColumnName(3, "u, " + u);
vel.SetColumnName(4, "v, " + u);
vel.SetParameters(pars);
for(size_t ix = 0; ix < sdata.Nx(); ix++)
for(size_t iy = 0; iy < sdata.Ny(); iy++)
@ -244,7 +247,8 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
if(args.contains("compress")) compress = args.at("compress").ToInt();
if(!err.Exist()) err = fw.Create(sdata, name, args.at("_cmdline"), compress);
if(!err.Exist()) err = fw.Create(sdata, name, compress);
if(!err.Exist()) err = fw.AddAtts(pars);
if(!err.Exist()) err = fw.AddVariable("u", "", "Eastward velocity", u, "");
if(!err.Exist()) err = fw.AddVariable("v", "", "Northward velocity", u, "");
@ -270,11 +274,11 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
for(size_t iy = 0; iy < data.Ny() - 1; iy++) p.Add(data.StablePoints(ix, iy));
if(outfmt == "bin")
p.WriteBinBile(name);
p.WriteBinBile(name, pars);
else if(outfmt == "nc" || outfmt == "netcdf")
{
int compress = args.contains("compress") ? args.at("compress").ToInt() : 3;
MString err = p.WriteNcFile(name, args.at("_cmdline"), compress);
MString err = p.WriteNcFile(name, pars, args.at("_cmdline"), compress);
if(err.Exist()) return err;
}
else

113
include/ncfilew.h

@ -84,7 +84,7 @@ class NCFileWBase
public:
constexpr Error(): err(NC_NOERR) {}
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); }
int Err() const { return err; }
bool IsErr() const { return err != NC_NOERR; }
@ -100,7 +100,7 @@ class NCFileWBase
const char* ErrMessage() const { return err.ErrMessage(); }
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; }
void Close()
@ -124,11 +124,91 @@ class NCFileWBase
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>
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 bool ischar = std::is_same_v<T, char*>;
@ -138,19 +218,21 @@ class NCFileWBase
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()));
return err.IsErr() ? "Can't write attribute " + name + ": " + ErrMessage() : "";
}
template<class T>
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 bool ischar = std::is_same_v<T, char*>;
int 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)
err.Reset(nc_put_att(ncid, varid, name.Buf(), nct, 1, &val));
@ -158,16 +240,19 @@ class NCFileWBase
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()));
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;
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));
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...})); }
@ -257,18 +342,18 @@ class NCFileW: public NCFileWBase
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, int compression, size_t nx, size_t ny);
public:
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 constexpr(Is1DType<D>())
return CreateFile(DetType<D>(), name, history, compression, data.N(), 0);
return CreateFile(DetType<D>(), name, compression, data.N(), 0);
else
return CreateFile(DetType<D>(), name, history, compression, data.Nx(), data.Ny());
return CreateFile(DetType<D>(), name, compression, data.Nx(), data.Ny());
}
void Close()

3
src/ncfilew.cpp

@ -1,7 +1,7 @@
#define MICHLIB_NOSOURCE
#include "ncfilew.h"
MString NCFileW::CreateFile(NCFileW::Type stype, const MString& name, const MString& history, int compression, size_t nx, size_t ny)
MString NCFileW::CreateFile(NCFileW::Type stype, const MString& name, int compression, size_t nx, size_t ny)
{
if(stype == UNKNOWN) return "Can't determine file type";
@ -12,7 +12,6 @@ MString NCFileW::CreateFile(NCFileW::Type stype, const MString& name, const MStr
Open(name);
if(!*this) return "Can't create netcdf file " + name + ": " + ErrMessage();
AddAtt("history", history);
AddAtt("node_offset", node_offset);
switch(stype)

Loading…
Cancel
Save