Browse Source

Support for time column in netcdf files generated by uv and tsc actions

lintest
Michael Uleysky 10 months ago
parent
commit
04f45ba459
  1. 53
      actions/actiontsc.h
  2. 44
      actions/actionuv.cpp
  3. 193
      actions/actionuv.h
  4. 29
      include/ncfilew.h
  5. 32
      src/ncfilew.cpp

53
actions/actiontsc.h

@ -41,6 +41,11 @@ template<class D> MString ActionTSC::DoAction(const CLArgs& args, D& ds)
} }
} }
bool average = args.contains("average");
int compress = 3;
if(args.contains("compress")) compress = args.at("compress").ToInt();
auto vlist = michlib::Split_on_words(varstring, " ,", false); auto vlist = michlib::Split_on_words(varstring, " ,", false);
std::vector<MString> vnames{std::make_move_iterator(std::begin(vlist)), std::make_move_iterator(std::end(vlist))}; std::vector<MString> vnames{std::make_move_iterator(std::begin(vlist)), std::make_move_iterator(std::end(vlist))};
{ {
@ -73,9 +78,21 @@ template<class D> MString ActionTSC::DoAction(const CLArgs& args, D& ds)
} }
auto p = sourcepars.get(); auto p = sourcepars.get();
auto data = Read(ds, vnames, p, tindexes); TimeData tdata(ds, tindexes);
if(data.size() != vnames.size()) return "Can't read data";
MString name = args.contains("out") ? args.at("out") : "out.bin";
MString outfmt = args.contains("format") ? args.at("format") : (GetExt(name) == "nc" ? "nc" : "bin");
if(outfmt == "bin" && !average && tindexes.size() > 1) return "Multiple time moments does'nt supported by the bin format";
bool headwrited = false;
NCFileW ncfw;
for(size_t it = 0; it < tindexes.size(); it++)
{
auto data = average ? Read(ds, vnames, p, tindexes) : Read(ds, vnames, p, tindexes[it]);
if(data.size() != vnames.size()) return "Can't read data";
if(!headwrited)
for(size_t i = 0; i < vnames.size(); i++) for(size_t i = 0; i < vnames.size(); i++)
{ {
if(!data[i].Unit().Exist()) michlib::errmessage("Unknown measurement unit for variable " + vnames[i] + "!"); if(!data[i].Unit().Exist()) michlib::errmessage("Unknown measurement unit for variable " + vnames[i] + "!");
@ -83,9 +100,6 @@ template<class D> MString ActionTSC::DoAction(const CLArgs& args, D& ds)
if(!data[i].LongName().Exist()) data[i].SetLongName(NCFuncs::Name2LongName(vnames[i])); if(!data[i].LongName().Exist()) data[i].SetLongName(NCFuncs::Name2LongName(vnames[i]));
} }
MString name = args.contains("out") ? args.at("out") : "out.bin";
MString outfmt = args.contains("format") ? args.at("format") : (GetExt(name) == "nc" ? "nc" : "bin");
if(outfmt == "bin") if(outfmt == "bin")
{ {
BFileW fw; BFileW fw;
@ -104,29 +118,28 @@ template<class D> MString ActionTSC::DoAction(const CLArgs& args, D& ds)
} }
fw.Finalize(); fw.Finalize();
fw.Close(); fw.Close();
return "";
} }
else if(outfmt == "nc" || outfmt == "netcdf")
if(outfmt == "nc" || outfmt == "netcdf")
{ {
int compress = 3;
NCFileW fw;
MString err; MString err;
if(args.contains("compress")) compress = args.at("compress").ToInt(); if(!err.Exist() && !headwrited) err = ncfw.Create(data[0], name, compress);
if(!err.Exist() && !headwrited) err = ncfw.AddTimeData(tdata, !average);
if(!err.Exist()) err = fw.Create(data[0], name, compress); if(!err.Exist() && !headwrited) err = ncfw.AddAtts(pars);
if(!err.Exist()) err = fw.AddAtts(pars);
for(size_t i = 0; i < data.size(); i++) 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() && !headwrited) err = ncfw.AddVariable(vnames[i], data[i].StandartName(), data[i].LongName(), data[i].Unit(), data[i].Comment());
if(!err.Exist()) err = fw.WriteGrid(data[0]); if(!err.Exist() && !headwrited) err = ncfw.WriteGrid(data[0]);
for(size_t i = 0; i < data.size(); i++) for(size_t i = 0; i < data.size(); i++)
if(!err.Exist()) err = fw.WriteVariable(data[i], vnames[i]); if(!err.Exist()) err = average ? ncfw.WriteVariable(data[i], vnames[i]) : ncfw.WriteVariable(data[i], vnames[i], it);
if(err.Exist()) return err; if(err.Exist()) return err;
fw.Close(); }
else
return "Unknown format: " + outfmt;
return ""; if(average) break;
headwrited = true;
} }
ncfw.Close();
return "Unknown format: " + outfmt; return "";
}; };

44
actions/actionuv.cpp

@ -20,9 +20,9 @@ void UVMethods::StPoints::WriteBinBile(const MString& name, const michlib_intern
stp.Close(); stp.Close();
} }
MString UVMethods::StPoints::WriteNcFile(const MString& name, const michlib_internal::ParameterListEx& pars, const MString& history, int comp) const MString UVMethods::StPoints::CreateNcFile(const MString& name, const michlib_internal::ParameterListEx& pars, const MString& history, int comp, const TimeData& tdata, bool timedep)
{ {
NCFileWBase nc; tdep = timedep;
const MString xname = lonlat ? "longitude" : "x"; const MString xname = lonlat ? "longitude" : "x";
const MString yname = lonlat ? "latitude" : "y"; const MString yname = lonlat ? "latitude" : "y";
@ -33,8 +33,24 @@ MString UVMethods::StPoints::WriteNcFile(const MString& name, const michlib_inte
nc.AddAtt("history", history); nc.AddAtt("history", history);
nc.AddAtts(pars); nc.AddAtts(pars);
nc.AddDim("i", N()); nc.AddDim("i", N());
nc.AddDim("time", tdata.steps.size());
nc.AddVar("time", decltype(nc)::Type2NCType<decltype(tdata.steps)::value_type>, "time");
nc.SetComp("time", comp);
nc.AddAtt("time", "standard_name", "time");
nc.AddAtt("time", "long_name", "time");
nc.AddAtt("time", "units", tdata.UnitName());
if(tdep)
{
nc.AddVar(xname, NC_FLOAT, "time", "i");
nc.AddVar(yname, NC_FLOAT, "time", "i");
}
else
{
nc.AddVar(xname, NC_FLOAT, "i"); nc.AddVar(xname, NC_FLOAT, "i");
nc.AddVar(yname, NC_FLOAT, "i"); nc.AddVar(yname, NC_FLOAT, "i");
}
nc.SetComp(xname, comp); nc.SetComp(xname, comp);
nc.SetComp(yname, comp); nc.SetComp(yname, comp);
@ -51,20 +67,38 @@ MString UVMethods::StPoints::WriteNcFile(const MString& name, const michlib_inte
nc.AddAtt(yname, "long_name", "y-coordinate"); nc.AddAtt(yname, "long_name", "y-coordinate");
} }
if(tdep)
nc.AddVar("type", NC_UBYTE, "time", "i");
else
nc.AddVar("type", NC_UBYTE, "i"); nc.AddVar("type", NC_UBYTE, "i");
nc.SetComp("type", comp); nc.SetComp("type", comp);
nc.AddAtt("type", "long_name", 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"); "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");
nc.WriteVar("time", tdata.steps.data());
if(!nc) return "Can't set grid in the netcdf file " + name + ": " + nc.ErrMessage(); if(!nc) return "Can't set grid in the netcdf file " + name + ": " + nc.ErrMessage();
return "";
}
nc.EndDef(); MString UVMethods::StPoints::WriteNcFile(size_t it)
{
const MString xname = lonlat ? "longitude" : "x";
const MString yname = lonlat ? "latitude" : "y";
if(tdep)
{
nc.WriteVar(xname, it, x.data());
nc.WriteVar(yname, it, y.data());
nc.WriteVar("type", it, t.data());
}
else
{
nc.WriteVar(xname, x.data()); nc.WriteVar(xname, x.data());
nc.WriteVar(yname, y.data()); nc.WriteVar(yname, y.data());
nc.WriteVar("type", t.data()); nc.WriteVar("type", t.data());
}
if(!nc) return "Can't write data to the netcdf file " + name + ": " + nc.ErrMessage(); if(!nc) return MString("Can't write data to the netcdf file: ") + nc.ErrMessage();
return ""; return "";
} }

193
actions/actionuv.h

@ -70,6 +70,8 @@ class UVMethods
std::vector<real> x, y; std::vector<real> x, y;
std::vector<michlib::uint1> t; std::vector<michlib::uint1> t;
bool lonlat; bool lonlat;
NCFileWBase nc;
bool tdep;
size_t N() const { return t.size(); } size_t N() const { return t.size(); }
@ -86,9 +88,19 @@ class UVMethods
} }
} }
void Reset()
{
x.clear();
y.clear();
t.clear();
}
void WriteBinBile(const MString& name, const michlib_internal::ParameterListEx& pars) const; void WriteBinBile(const MString& name, const michlib_internal::ParameterListEx& pars) const;
MString WriteNcFile(const MString& name, const michlib_internal::ParameterListEx& pars, const MString& history, int comp) const; MString CreateNcFile(const MString& name, const michlib_internal::ParameterListEx& pars, const MString& history, int comp, const TimeData& tdata, bool timedep);
MString WriteNcFile(size_t it);
void CloseNcFile() { nc.Close(); }
}; };
}; };
@ -112,6 +124,11 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
auto [tindexes, err] = GetTIndexes(ds, args, pars); auto [tindexes, err] = GetTIndexes(ds, args, pars);
if(err.Exist()) return err; if(err.Exist()) return err;
bool average = args.contains("average");
int compress = 3;
if(args.contains("compress")) compress = args.at("compress").ToInt();
std::unique_ptr<const BaseParameters> sourcepars; std::unique_ptr<const BaseParameters> sourcepars;
if constexpr(ParametersSupported<D>) if constexpr(ParametersSupported<D>)
{ {
@ -130,15 +147,40 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
} }
auto p = sourcepars.get(); auto p = sourcepars.get();
auto data = ReadUV(ds, p, tindexes, mode); TimeData tdata(ds, tindexes);
if(!data) return "Can't read data";
// Main file
MString name = args.contains("out") ? args.at("out") : ""; MString name = args.contains("out") ? args.at("out") : "";
MString outfmt = args.contains("outformat") ? args.at("outformat") : (GetExt(name) == "nc" ? "nc" : "bin"); MString outfmt = args.contains("outformat") ? args.at("outformat") : (GetExt(name) == "nc" ? "nc" : "bin");
MString namevel = args.contains("velout") ? args.at("velout") : "";
MString outfmtvel = args.contains("veloutformat") ? args.at("veloutformat") : (GetExt(name) == "nc" ? "nc" : "bin");
MString namestp = args.contains("stpout") ? args.at("stpout") : "";
MString outfmtstp = args.contains("stpoutformat") ? args.at("stpoutformat") : (GetExt(name) == "nc" ? "nc" : "bin");
size_t shiftx = args.contains("shiftx") ? args.at("shiftx").ToInteger<size_t>() : 0;
size_t shifty = args.contains("shifty") ? args.at("shifty").ToInteger<size_t>() : 0;
size_t skipx = args.contains("skipx") ? args.at("skipx").ToInteger<size_t>() : 1;
size_t skipy = args.contains("skipy") ? args.at("skipy").ToInteger<size_t>() : 1;
MString u = data.Unit().Exist() ? data.Unit() : "unknown", d = data.DUnit().Exist() ? data.DUnit() : "unknown"; if(!average && tindexes.size() > 1 && ((name.Exist() && outfmt == "bin") || (namevel.Exist() && outfmtvel == "bin") || (namestp.Exist() && outfmtstp == "bin")))
return "Multiple time moments does'nt supported by the bin format";
bool headwrited = false;
MString velunit, distunit;
NCFileW fw, fwfilt;
StPoints stp(true);
for(size_t it = 0; it < tindexes.size(); it++)
{
auto data = average ? ReadUV(ds, p, tindexes, mode) : ReadUV(ds, p, tindexes[it], mode);
if(!headwrited)
{
velunit = data.Unit().Exist() ? data.Unit() : "unknown";
distunit = data.DUnit().Exist() ? data.DUnit() : "unknown";
}
// Main file
if(name.Exist()) if(name.Exist())
{ {
if(outfmt == "bin") if(outfmt == "bin")
@ -147,13 +189,13 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
fw.Create(name, 9); fw.Create(name, 9);
fw.SetColumnName(1, "Longitude"); fw.SetColumnName(1, "Longitude");
fw.SetColumnName(2, "Latitude"); fw.SetColumnName(2, "Latitude");
fw.SetColumnName(3, "u, " + u); fw.SetColumnName(3, "u, " + velunit);
fw.SetColumnName(4, "v, " + u); fw.SetColumnName(4, "v, " + velunit);
fw.SetColumnName(5, "Div, (" + u + ")/" + d); fw.SetColumnName(5, "Div, (" + velunit + ")/" + distunit);
fw.SetColumnName(6, "Rot, (" + u + ")/" + d); fw.SetColumnName(6, "Rot, (" + velunit + ")/" + distunit);
fw.SetColumnName(7, "Okubo-Weiss parameter, (" + u + ")2/" + d + "2"); fw.SetColumnName(7, "Okubo-Weiss parameter, (" + velunit + ")2/" + distunit + "2");
fw.SetColumnName(8, "Kinetic energy, (" + u + ")2"); fw.SetColumnName(8, "Kinetic energy, (" + velunit + ")2");
fw.SetColumnName(9, "Eddy kinetic energy, (" + u + ")2"); fw.SetColumnName(9, "Eddy kinetic energy, (" + velunit + ")2");
fw.SetParameters(pars); fw.SetParameters(pars);
for(size_t i = 0; i < data.N(); i++) for(size_t i = 0; i < data.N(); i++)
@ -173,59 +215,59 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
} }
else if(outfmt == "nc" || outfmt == "netcdf") else if(outfmt == "nc" || outfmt == "netcdf")
{ {
int compress = 3;
NCFileW fw;
MString err; MString err;
if(args.contains("compress")) compress = args.at("compress").ToInt(); if(!err.Exist() && !headwrited) err = fw.Create(data, name, compress);
if(!err.Exist() && !headwrited) err = fw.AddTimeData(tdata, !average);
if(!err.Exist() && !headwrited) err = fw.AddAtts(pars);
if(!err.Exist() && !headwrited) err = fw.AddVariable("u", "", "Eastward velocity", velunit, "");
if(!err.Exist() && !headwrited) err = fw.AddVariable("v", "", "Northward velocity", velunit, "");
if(!err.Exist() && !headwrited) err = fw.AddVariable("div", "", "Velocity divergence", "(" + velunit + ")/" + distunit, "");
if(!err.Exist() && !headwrited) err = fw.AddVariable("rot", "", "Velocity rotor", "(" + velunit + ")/" + distunit, "");
if(!err.Exist() && !headwrited) err = fw.AddVariable("ow", "", "Okubo-Weiss parameter", "(" + velunit + ")2/" + distunit + "2", "");
if(!err.Exist() && !headwrited) err = fw.AddVariable("ke", "", "Squared velocity module, u^2+v^2", "(" + velunit + ")2", "");
if(!err.Exist() && !headwrited) err = fw.AddVariable("eke", "", "Squared velocity dispersion aka eddy kinetic energy, <u^2+v^2>-<u>^2-<v>^2", "(" + velunit + ")2", "");
if(!err.Exist() && !headwrited) err = fw.WriteGrid(data);
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, "");
if(!err.Exist()) err = fw.AddVariable("rot", "", "Velocity rotor", "(" + u + ")/" + d, "");
if(!err.Exist()) err = fw.AddVariable("ow", "", "Okubo-Weiss parameter", "(" + u + ")2/" + d + "2", "");
if(!err.Exist()) err = fw.AddVariable("ke", "", "Squared velocity module, u^2+v^2", "(" + u + ")2", "");
if(!err.Exist()) err = fw.AddVariable("eke", "", "Squared velocity dispersion aka eddy kinetic energy, <u^2+v^2>-<u>^2-<v>^2", "(" + u + ")2", "");
if(!err.Exist()) err = fw.WriteGrid(data);
if(!err.Exist()) err = fw.WriteVariable(data, "u", [&data = std::as_const(data)](size_t i, size_t j) { return data.U(i, j); });
if(!err.Exist()) err = fw.WriteVariable(data, "v", [&data = std::as_const(data)](size_t i, size_t j) { return data.V(i, j); });
if(!err.Exist()) err = fw.WriteVariable(data, "div", [&data = std::as_const(data)](size_t i, size_t j) { return data.Div(i, j); });
if(!err.Exist()) err = fw.WriteVariable(data, "rot", [&data = std::as_const(data)](size_t i, size_t j) { return data.Rot(i, j); });
if(!err.Exist()) err = fw.WriteVariable(data, "ow", [&data = std::as_const(data)](size_t i, size_t j) { return data.OW(i, j); });
if(!err.Exist()) err = fw.WriteVariable(data, "ke", [&data = std::as_const(data)](size_t i, size_t j) { return data.U2(i, j); });
if(!err.Exist()) if(!err.Exist())
err = fw.WriteVariable(data, "eke", [&data = std::as_const(data)](size_t i, size_t j) { return data.U2(i, j) - (data.U(i, j) * data.U(i, j) + data.V(i, j) * data.V(i, j)); }); err = fw.WriteVariable(
data, "u", [&data = std::as_const(data)](size_t i, size_t j) { return data.U(i, j); }, it);
if(!err.Exist())
err = fw.WriteVariable(
data, "v", [&data = std::as_const(data)](size_t i, size_t j) { return data.V(i, j); }, it);
if(!err.Exist())
err = fw.WriteVariable(
data, "div", [&data = std::as_const(data)](size_t i, size_t j) { return data.Div(i, j); }, it);
if(!err.Exist())
err = fw.WriteVariable(
data, "rot", [&data = std::as_const(data)](size_t i, size_t j) { return data.Rot(i, j); }, it);
if(!err.Exist())
err = fw.WriteVariable(
data, "ow", [&data = std::as_const(data)](size_t i, size_t j) { return data.OW(i, j); }, it);
if(!err.Exist())
err = fw.WriteVariable(
data, "ke", [&data = std::as_const(data)](size_t i, size_t j) { return data.U2(i, j); }, it);
if(!err.Exist())
err = fw.WriteVariable(
data, "eke", [&data = std::as_const(data)](size_t i, size_t j) { return data.U2(i, j) - (data.U(i, j) * data.U(i, j) + data.V(i, j) * data.V(i, j)); }, it);
if(err.Exist()) return err; if(err.Exist()) return err;
fw.Close();
} }
else else
return "Unknown format: " + outfmt; return "Unknown format: " + outfmt;
} }
// Filtered vectors file // Filtered file
name = args.contains("velout") ? args.at("velout") : ""; if(namevel.Exist())
outfmt = args.contains("veloutformat") ? args.at("veloutformat") : (GetExt(name) == "nc" ? "nc" : "bin");
if(name.Exist())
{ {
size_t shiftx = args.contains("shiftx") ? args.at("shiftx").ToInteger<size_t>() : 0;
size_t shifty = args.contains("shifty") ? args.at("shifty").ToInteger<size_t>() : 0;
size_t skipx = args.contains("skipx") ? args.at("skipx").ToInteger<size_t>() : 1;
size_t skipy = args.contains("skipy") ? args.at("skipy").ToInteger<size_t>() : 1;
Sparser<decltype(data)> sdata(data, shiftx, shifty, skipx, skipy); Sparser<decltype(data)> sdata(data, shiftx, shifty, skipx, skipy);
if(outfmt == "bin") if(outfmtvel == "bin")
{ {
BFileW vel; BFileW vel;
vel.Create(name, 4); vel.Create(name, 4);
vel.SetColumnName(1, "Longitude"); vel.SetColumnName(1, "Longitude");
vel.SetColumnName(2, "Latitude"); vel.SetColumnName(2, "Latitude");
vel.SetColumnName(3, "u, " + u); vel.SetColumnName(3, "u, " + velunit);
vel.SetColumnName(4, "v, " + u); vel.SetColumnName(4, "v, " + velunit);
vel.SetParameters(pars); vel.SetParameters(pars);
for(size_t ix = 0; ix < sdata.Nx(); ix++) for(size_t ix = 0; ix < sdata.Nx(); ix++)
@ -239,51 +281,54 @@ template<class D> MString ActionUV::DoAction(const CLArgs& args, D& ds)
vel.Finalize(); vel.Finalize();
vel.Close(); vel.Close();
} }
else if(outfmt == "nc" || outfmt == "netcdf") else if(outfmtvel == "nc" || outfmtvel == "netcdf")
{ {
int compress = 3;
NCFileW fw;
MString err; MString err;
if(args.contains("compress")) compress = args.at("compress").ToInt(); if(!err.Exist() && !headwrited) err = fwfilt.Create(sdata, name, compress);
if(!err.Exist() && !headwrited) err = fwfilt.AddTimeData(tdata, !average);
if(!err.Exist() && !headwrited) err = fwfilt.AddAtts(pars);
if(!err.Exist() && !headwrited) err = fwfilt.AddVariable("u", "", "Eastward velocity", velunit, "");
if(!err.Exist() && !headwrited) err = fwfilt.AddVariable("v", "", "Northward velocity", velunit, "");
if(!err.Exist() && !headwrited) err = fwfilt.WriteGrid(sdata);
if(!err.Exist()) err = fw.Create(sdata, name, compress); if(!err.Exist())
if(!err.Exist()) err = fw.AddAtts(pars); err = fwfilt.WriteVariable(
if(!err.Exist()) err = fw.AddVariable("u", "", "Eastward velocity", u, ""); sdata, "u", [&data = std::as_const(sdata)](size_t i, size_t j) { return data.U(i, j); }, it);
if(!err.Exist()) err = fw.AddVariable("v", "", "Northward velocity", u, ""); if(!err.Exist())
err = fwfilt.WriteVariable(
if(!err.Exist()) err = fw.WriteGrid(sdata); sdata, "v", [&data = std::as_const(sdata)](size_t i, size_t j) { return data.V(i, j); }, it);
if(!err.Exist()) err = fw.WriteVariable(sdata, "u", [&data = std::as_const(sdata)](size_t i, size_t j) { return data.U(i, j); });
if(!err.Exist()) err = fw.WriteVariable(sdata, "v", [&data = std::as_const(sdata)](size_t i, size_t j) { return data.V(i, j); });
if(err.Exist()) return err; if(err.Exist()) return err;
fw.Close();
} }
else else
return "Unknown format: " + outfmt; return "Unknown format: " + outfmtvel;
} }
// Stationary points // Stationary points
name = args.contains("stpout") ? args.at("stpout") : ""; if(namestp.Exist())
outfmt = args.contains("stpoutformat") ? args.at("stpoutformat") : (GetExt(name) == "nc" ? "nc" : "bin");
if(name.Exist())
{ {
StPoints p(true); stp.Reset();
for(size_t ix = 0; ix < data.Nx() - 1; ix++) for(size_t ix = 0; ix < data.Nx() - 1; ix++)
for(size_t iy = 0; iy < data.Ny() - 1; iy++) p.Add(data.StablePoints(ix, iy)); for(size_t iy = 0; iy < data.Ny() - 1; iy++) stp.Add(data.StablePoints(ix, iy));
if(outfmt == "bin") if(outfmtstp == "bin")
p.WriteBinBile(name, pars); stp.WriteBinBile(name, pars);
else if(outfmt == "nc" || outfmt == "netcdf") else if(outfmtstp == "nc" || outfmtstp == "netcdf")
{ {
int compress = args.contains("compress") ? args.at("compress").ToInt() : 3; MString err;
MString err = p.WriteNcFile(name, pars, args.at("_cmdline"), compress); if(!err.Exist() && !headwrited) err = stp.CreateNcFile(name, pars, args.at("_cmdline"), compress, tdata, !average);
if(!err.Exist()) err = stp.WriteNcFile(it);
if(err.Exist()) return err; if(err.Exist()) return err;
} }
else else
return "Unknown format: " + outfmt; return "Unknown format: " + outfmt;
} }
if(average) break;
headwrited = true;
}
fw.Close();
fwfilt.Close();
stp.CloseNcFile();
return ""; return "";
}; };

29
include/ncfilew.h

@ -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>
@ -366,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()
{ {
@ -403,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";
@ -419,6 +424,9 @@ 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);
if(tdep)
WriteVar(name, tind, buf);
else
WriteVar(name, buf); WriteVar(name, buf);
} }
else else
@ -427,6 +435,9 @@ 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);
if(tdep)
WriteVar(name, tind, buf);
else
WriteVar(name, buf); WriteVar(name, buf);
} }
@ -435,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)
{ {

32
src/ncfilew.cpp

@ -87,16 +87,48 @@ MString NCFileW::CreateFile(NCFileW::Type stype, const MString& name, int compre
return ""; return "";
} }
MString NCFileW::AddTimeData(const TimeData& tdata, bool tisindex)
{
tdep = tisindex;
AddDim("time", tdata.steps.size());
AddVar("time", Type2NCType<decltype(tdata.steps)::value_type>, "time");
SetComp("time", compress);
AddAtt("time", "standard_name", "time");
AddAtt("time", "long_name", "time");
AddAtt("time", "units", tdata.UnitName());
WriteVar("time", tdata.steps.data());
if(!*this) return MString("Can't add time data to the netcdf file: ") + ErrMessage();
return "";
}
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(Is1DType(type)) if(Is1DType(type))
{
if(tdep)
AddVar(name, NC_FLOAT, "time", "i");
else
AddVar(name, NC_FLOAT, "i"); AddVar(name, NC_FLOAT, "i");
}
else if(IsGeoType(type)) else if(IsGeoType(type))
{
if(tdep)
AddVar(name, NC_FLOAT, "time", "latitude", "longitude");
else
AddVar(name, NC_FLOAT, "latitude", "longitude"); AddVar(name, NC_FLOAT, "latitude", "longitude");
}
else
{
if(tdep)
AddVar(name, NC_FLOAT, "time", "y", "x");
else else
AddVar(name, NC_FLOAT, "y", "x"); AddVar(name, NC_FLOAT, "y", "x");
}
SetComp(name, compress); SetComp(name, compress);
if(stname.Exist()) AddAtt(name, "standard_name", stname); if(stname.Exist()) AddAtt(name, "standard_name", stname);

Loading…
Cancel
Save