Compare commits
13 Commits
17b04d63de
...
18b1f939b3
Author | SHA1 | Date |
---|---|---|
Michael Uleysky | 18b1f939b3 | 9 months ago |
Michael Uleysky | 2e0f396497 | 9 months ago |
Michael Uleysky | 9f4d7094dd | 10 months ago |
Michael Uleysky | df85e7ca51 | 10 months ago |
Michael Uleysky | c85dc28858 | 10 months ago |
Michael Uleysky | 3b40409fb2 | 10 months ago |
Michael Uleysky | ed1282413f | 10 months ago |
Michael Uleysky | 1d9268b32d | 10 months ago |
Michael Uleysky | 3b1d5c3157 | 10 months ago |
Michael Uleysky | fd7d7f8a5f | 10 months ago |
Michael Uleysky | 8a1cf03804 | 10 months ago |
Michael Uleysky | e25f843e7e | 10 months ago |
Michael Uleysky | 20824cdaab | 10 months ago |
22 changed files with 1633 additions and 338 deletions
@ -0,0 +1,88 @@
|
||||
#define MICHLIB_NOSOURCE |
||||
#include "actionuv.h" |
||||
|
||||
void UVMethods::StPoints::WriteBinBile(const MString& name) 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)"); |
||||
|
||||
for(size_t i = 0; i < N(); i++) |
||||
{ |
||||
stp.Write(x[i]); |
||||
stp.Write(y[i]); |
||||
stp.Write(michlib::int_cast<size_t>(t[i])); |
||||
} |
||||
stp.Finalize(); |
||||
stp.Close(); |
||||
} |
||||
|
||||
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; |
||||
|
||||
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"; |
||||
|
||||
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"; |
||||
|
||||
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"; |
||||
} |
||||
|
||||
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]; |
||||
|
||||
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"; |
||||
|
||||
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"; |
||||
|
||||
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"; |
||||
|
||||
ret = nc_close(ncid); |
||||
if(ret != NC_NOERR) return "Can't close netcdf file"; |
||||
|
||||
return ""; |
||||
} |
@ -0,0 +1,201 @@
|
||||
#pragma once |
||||
#include "MString.h" |
||||
#include "traits.h" |
||||
#include <algorithm> |
||||
#include <netcdf.h> |
||||
#include <utility> |
||||
#include <vector> |
||||
|
||||
using michlib::MString; |
||||
|
||||
class NCFileW |
||||
{ |
||||
enum Type |
||||
{ |
||||
UNKNOWN, |
||||
G1V1, |
||||
G1V2, |
||||
G2V2 |
||||
}; |
||||
struct Var |
||||
{ |
||||
MString name; |
||||
int id; |
||||
}; |
||||
|
||||
static constexpr auto fill = std::numeric_limits<float>::max(); |
||||
|
||||
int ncid; |
||||
Type type = UNKNOWN; |
||||
union |
||||
{ |
||||
struct |
||||
{ |
||||
int xdimid, ydimid; |
||||
}; |
||||
int dimid[2]; |
||||
}; |
||||
int xid, yid; |
||||
int compress; |
||||
std::vector<struct Var> vars; |
||||
|
||||
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; |
||||
return UNKNOWN; |
||||
}; |
||||
|
||||
template<class D> static constexpr bool Is1DType() { return Is1DType(DetType<D>()); } |
||||
|
||||
static constexpr bool Is1DType(Type t) { return t == G1V1; } |
||||
|
||||
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"; |
||||
if constexpr(Is1DType<D>()) |
||||
return CreateFile(DetType<D>(), name, history, compression, data.N(), 0); |
||||
else |
||||
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); |
||||
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 |
||||
{ |
||||
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(); |
||||
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"; |
||||
} |
||||
else |
||||
{ |
||||
const size_t i[2] = {0, 0}; |
||||
const size_t c[2] = {data.Nx(), data.Ny()}; |
||||
float buf[c[0] * c[1]]; |
||||
|
||||
for(size_t ix = 0; ix < c[0]; ix++) |
||||
for(size_t iy = 0; iy < c[1]; iy++) buf[ix * c[1] + iy] = 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"; |
||||
} |
||||
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 |
||||
{ |
||||
if constexpr(Is1DType(DetType<D>())) |
||||
return WriteVariable(data, varid, [&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); }); |
||||
} |
||||
|
||||
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 |
||||
{ |
||||
static constexpr auto dtype = DetType<D>(); |
||||
if(type == UNKNOWN) return "File not open"; |
||||
if(type != dtype) return "Incompatible data type"; |
||||
|
||||
EndDef(); |
||||
|
||||
int ret; |
||||
if constexpr(dtype == G1V1) |
||||
{ |
||||
const size_t i = 0, c = data.N(); |
||||
float bufx[c]; |
||||
float bufy[c]; |
||||
for(size_t ix = 0; ix < c; ix++) |
||||
{ |
||||
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"; |
||||
} |
||||
else if constexpr(dtype == G1V2) |
||||
{ |
||||
const size_t i = 0, 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"; |
||||
} |
||||
else if constexpr(dtype == G2V2) |
||||
{ |
||||
const size_t i[2] = {0, 0}; |
||||
const size_t c[2] = {data.Nx(), data.Ny()}; |
||||
float bufx[c[0] * c[1]]; |
||||
float bufy[c[0] * c[1]]; |
||||
for(size_t ix = 0; ix < c[0]; ix++) |
||||
for(size_t iy = 0; iy < c[1]; iy++) |
||||
{ |
||||
bufx[ix * c[1] + iy] = data.Lon(ix, iy); |
||||
bufy[ix * c[1] + iy] = 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"; |
||||
} |
||||
else |
||||
return "Unknown data type"; |
||||
|
||||
return ""; |
||||
} |
||||
}; |
@ -0,0 +1,526 @@
|
||||
#define MICHLIB_NOSOURCE |
||||
#include "VYLET.h" |
||||
|
||||
MString VYLETData::Info() const |
||||
{ |
||||
if(!vylet) return ""; |
||||
MString out; |
||||
michlib::CompiledParser xy2lon, xy2lat; |
||||
real x, y; |
||||
michlib::ParserVars pv; |
||||
|
||||
pv["x"] = &x; |
||||
pv["y"] = &y; |
||||
|
||||
vylet->UsePrefix("Datafile_Info"); |
||||
MString xy2lonstr = vylet->ParameterSValue("xy2lon", "%y"); |
||||
MString xy2latstr = vylet->ParameterSValue("xy2lat", "%x"); |
||||
ArifmeticCompiler(xy2lonstr, xy2lon, &pv); |
||||
ArifmeticCompiler(xy2latstr, xy2lat, &pv); |
||||
|
||||
real lonb, latb, lone, late; |
||||
|
||||
vylet->UsePrefix(""); |
||||
x = vylet->ParameterRValue("x0", 0.0); |
||||
y = vylet->ParameterRValue("y0", 0.0); |
||||
xy2lon.Run(lonb); |
||||
xy2lat.Run(latb); |
||||
x = vylet->ParameterRValue("x1", 0.0); |
||||
y = vylet->ParameterRValue("y1", 0.0); |
||||
xy2lon.Run(lone); |
||||
xy2lat.Run(late); |
||||
|
||||
out += "Start time: " + start.ToString() + "\n"; |
||||
out += "End time: " + end.ToString() + " " + (invtime ? "(backward integration)" : "(forward integration)") + "\n"; |
||||
out += "Region: (" + MString(lonb) + " : " + lone + ") x (" + latb + " : " + late + ")\n"; |
||||
out += "Grid:" + MString(" ") + lons.size() + "x" + lats.size() + "\n"; |
||||
out += HasCoast() ? "Coast: checked\n" : "Coast: not checked\n"; |
||||
out += LengthFast() ? "Trajectory length: fast calculation\n" : "Trajectory length: exact calculation\n"; |
||||
|
||||
out += "Borders: "; |
||||
bool needcomma = false; |
||||
if(Left() >= 0.0) |
||||
{ |
||||
real lon; |
||||
if(needcomma) out += ", "; |
||||
out += "left="; |
||||
x = Left(); |
||||
xy2lon.Run(lon); |
||||
out += lon; |
||||
needcomma = true; |
||||
} |
||||
if(Right() <= maxx) |
||||
{ |
||||
real lon; |
||||
if(needcomma) out += ", "; |
||||
out += "right="; |
||||
x = Right(); |
||||
xy2lon.Run(lon); |
||||
out += lon; |
||||
needcomma = true; |
||||
} |
||||
if(Down() >= 0.0) |
||||
{ |
||||
real lat; |
||||
if(needcomma) out += ", "; |
||||
out += "bottom="; |
||||
y = Down(); |
||||
xy2lat.Run(lat); |
||||
out += lat; |
||||
needcomma = true; |
||||
} |
||||
if(Up() <= maxy) |
||||
{ |
||||
real lat; |
||||
if(needcomma) out += ", "; |
||||
out += "bottom="; |
||||
y = Up(); |
||||
xy2lat.Run(lat); |
||||
out += lat; |
||||
needcomma = true; |
||||
} |
||||
if(!needcomma) out += "no"; |
||||
out += "\n"; |
||||
|
||||
MString vars = "vylD"; |
||||
if(HasLyap()) vars += ", vylL"; |
||||
if(HasTime()) vars += ", vylT"; |
||||
vars += ", vylNx, vylNy, vylRx, vylRy, vylEx, vylEy, vylPhip, vylPhim, vylPhit"; |
||||
if(HasLyap()) vars += ", vyldS"; |
||||
vars += ", vylAngle, vylLen"; |
||||
if(HasTime()) vars += ", vylTmask"; |
||||
|
||||
out += "Supported variables: " + vars + "\n"; |
||||
|
||||
return out; |
||||
} |
||||
|
||||
MString VYLETData::Open(const CLArgs& args) |
||||
{ |
||||
if(!args.contains("dataset")) return "path to data not specified"; |
||||
MString dataset = args.at("dataset"); |
||||
decltype(vylet) nvylet; |
||||
|
||||
michlib::RegExpSimple havex("%x"), havey("%y"); |
||||
|
||||
nvylet.reset(new michlib::BFileR); |
||||
if(nvylet->Open(dataset) != ERR_NOERR) return "Can't open file " + dataset; |
||||
|
||||
nvylet->UsePrefix("ProgramInfo"); |
||||
if(nvylet->ParameterSValue("Task", "") != "AdvInt:Vylet") return "File " + dataset + " is not vylet file"; |
||||
|
||||
nvylet->UsePrefix(""); |
||||
if(nvylet->ParameterSValue("nettype", "") != "SQUARE") return "File " + dataset + " have unsupported net type"; |
||||
MString method = nvylet->ParameterSValue("Method", ""); |
||||
if(!(method == "Bicubic" || method == "BicubicL" || method == "BicubicI" || method == "BicubicIL")) return "File " + dataset + " have unsupported integration method"; |
||||
invtime = (method == "BicubicI" || method == "BicubicIL"); |
||||
|
||||
nvylet->UsePrefix("Datafile_Info"); |
||||
MString xy2lonstr = nvylet->ParameterSValue("xy2lon", "%y"); |
||||
MString xy2latstr = nvylet->ParameterSValue("xy2lat", "%x"); |
||||
if(havey.Match(xy2lonstr.Buf()) || havex.Match(xy2latstr.Buf())) return "File " + dataset + " have unsupported grid"; |
||||
auto res = ref.FromString(nvylet->ParameterSValue(invtime ? "EndDate" : "BeginDate", "")); |
||||
if(!res) return "Can't read reference time"; |
||||
|
||||
nvylet->UsePrefix(""); |
||||
start = R2Time(nvylet->ParameterRValue("tbeg", 0.0)); |
||||
end = R2Time(nvylet->ParameterRValue("tmax", 0.0)); |
||||
|
||||
nvylet->UsePrefix("Datafile"); |
||||
auto dx = nvylet->ParameterRValue("dx", 0.0); |
||||
auto dy = nvylet->ParameterRValue("dy", 0.0); |
||||
auto nx = nvylet->ParameterUValue("nx", 0); |
||||
auto ny = nvylet->ParameterUValue("ny", 0); |
||||
maxx = dx * (nx - 1); |
||||
maxy = dy * (ny - 1); |
||||
|
||||
michlib::CompiledParser xy2lon, xy2lat; |
||||
real x, y; |
||||
michlib::ParserVars pv; |
||||
|
||||
pv["x"] = &x; |
||||
pv["y"] = &y; |
||||
|
||||
ArifmeticCompiler(xy2lonstr, xy2lon, &pv); |
||||
ArifmeticCompiler(xy2latstr, xy2lat, &pv); |
||||
|
||||
nvylet->UsePrefix(""); |
||||
auto nlon = nvylet->ParameterUValue("Nx", 0) + 1; |
||||
auto nlat = nvylet->ParameterUValue("Ny", 0) + 1; |
||||
lons.resize(nlon); |
||||
lats.resize(nlat); |
||||
|
||||
elon.resize(nlon * nlat); |
||||
elat.resize(nlon * nlat); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) |
||||
{ |
||||
x = (*nvylet)[2][iy * lons.size() + ix]; |
||||
y = (*nvylet)[3][iy * lons.size() + ix]; |
||||
xy2lon.Run(elon[iy * lons.size() + ix]); |
||||
xy2lat.Run(elat[iy * lons.size() + ix]); |
||||
} |
||||
|
||||
for(size_t ix = 0; ix < nlon; ix++) |
||||
{ |
||||
x = (*nvylet)[0][ix]; |
||||
y = (*nvylet)[1][ix]; |
||||
xy2lon.Run(lons[ix]); |
||||
} |
||||
|
||||
for(size_t iy = 0; iy < nlat; iy++) |
||||
{ |
||||
x = (*nvylet)[0][iy * nlon]; |
||||
y = (*nvylet)[1][iy * nlon]; |
||||
xy2lat.Run(lats[iy]); |
||||
} |
||||
|
||||
vylet = std::move(nvylet); |
||||
return ""; |
||||
} |
||||
|
||||
bool VYLETData::Read(const MString& vname, std::map<MString, VYLETData::Data>& cache, size_t tind) const |
||||
{ |
||||
if(tind != 0) return false; |
||||
if(cache.contains(vname)) return true; |
||||
Data out; |
||||
|
||||
if(vname == "vylD") out = ReadD(); |
||||
if(vname == "vylL") out = ReadL(); |
||||
if(vname == "vylT") out = ReadT(); |
||||
if(vname == "vylNx") out = ReadNx(); |
||||
if(vname == "vylNy") out = ReadNy(); |
||||
if(vname == "vylRx") out = ReadRx(); |
||||
if(vname == "vylRy") out = ReadRy(); |
||||
if(vname == "vylEx") out = ReadEx(); |
||||
if(vname == "vylEy") out = ReadEy(); |
||||
if(vname == "vylPhip") out = ReadPhip(); |
||||
if(vname == "vylPhim") out = ReadPhim(); |
||||
if(vname == "vylPhit") out = ReadPhit(); |
||||
if(vname == "vyldS") out = ReaddS(); |
||||
if(vname == "vylAngle") out = ReadAngle(); |
||||
if(vname == "vylLen") out = ReadLen(); |
||||
if(vname == "vylTmask") out = ReadTmask(); |
||||
|
||||
if(!out) return false; |
||||
cache[vname] = std::move(out); |
||||
return true; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadD() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
const real xl = Left(); |
||||
const real xr = Right(); |
||||
const real yd = Down(); |
||||
const real yu = Up(); |
||||
|
||||
real x, y; |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) |
||||
{ |
||||
out(ix, iy) = 0.0; |
||||
x = (*vylet)[2][iy * lons.size() + ix]; |
||||
y = (*vylet)[3][iy * lons.size() + ix]; |
||||
if(yd > 0.0 && y < yd) out(ix, iy) = -1.0; |
||||
if(xl > 0.0 && x < xl) out(ix, iy) = -2.0; |
||||
if(yu < maxy && y > yu) out(ix, iy) = -3.0; |
||||
if(xr < maxx && x > xr) out(ix, iy) = -4.0; |
||||
if(out(ix, iy) >= 0.0) |
||||
out(ix, iy) = 6371.0 * michlib::GCD(M_PI * lons[ix] / 180.0, M_PI * lats[iy] / 180.0, M_PI * elon[iy * lons.size() + ix] / 180.0, M_PI * elat[iy * lons.size() + ix] / 180.0); |
||||
} |
||||
|
||||
out.SetUnit("km"); |
||||
out.SetLongName("Distance between start and end points"); |
||||
out.SetComment("Special values: -1.0 - trajectory leave region via south border, -2.0 - trajectory leave region via west border, -3.0 - trajectory leave region via north border, " |
||||
"-4.0 - trajectory leave region via east border"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadL() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto lcol = Name2ColNum("Log(G.sigma1)"); |
||||
auto tcol = Name2ColNum("time"); |
||||
if(lcol == 0 || tcol == 0) return Data(); |
||||
|
||||
MDateTime time; |
||||
real lambda, days; |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) |
||||
{ |
||||
time = R2Time((*vylet)[tcol - 1][iy * lons.size() + ix]); |
||||
lambda = (*vylet)[lcol - 1][iy * lons.size() + ix]; |
||||
days = static_cast<real>(time - start) / MDateTime::secondsperday; |
||||
out(ix, iy) = lambda / days; |
||||
} |
||||
|
||||
out.SetUnit("days-1"); |
||||
out.SetLongName("Lyapunov exponent"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadT() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto tcol = Name2ColNum("time"); |
||||
if(tcol == 0) return Data(); |
||||
|
||||
const real xl = Left(); |
||||
const real xr = Right(); |
||||
const real yd = Down(); |
||||
const real yu = Up(); |
||||
|
||||
vylet->UsePrefix(""); |
||||
const real acc = vylet->ParameterRValue("accuracy", 1.0); |
||||
const real tstep = 2.0 * M_PI * 1000.0 / acc; |
||||
|
||||
const real maxdays = static_cast<real>(end - start) / MDateTime::secondsperday; |
||||
|
||||
MDateTime time; |
||||
real days; |
||||
real x, y; |
||||
bool inside, maxtime; |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) |
||||
{ |
||||
x = (*vylet)[2][iy * lons.size() + ix]; |
||||
y = (*vylet)[3][iy * lons.size() + ix]; |
||||
time = R2Time((*vylet)[tcol - 1][iy * lons.size() + ix]); |
||||
days = static_cast<real>(time - start) / MDateTime::secondsperday; |
||||
if(days <= tstep * 1.5) days = 0.0; |
||||
inside = x > xl && x < xr && y > yd && y < yu; |
||||
maxtime = days >= maxdays - tstep * 0.5; |
||||
if(maxtime) days = maxdays; |
||||
if(inside && !maxtime) days = -days; |
||||
out(ix, iy) = days; |
||||
} |
||||
|
||||
out.SetUnit("days"); |
||||
out.SetLongName("Time to reach border or coast"); |
||||
out.SetComment("Special values: 0.0 - initial point on the land, " + MString(maxdays) + " - trajectory don't reach border, negative values - trajectory beached on the coast"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadNx() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto ncol = Name2ColNum("nx=0"); |
||||
if(ncol == 0) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = (*vylet)[ncol - 1][iy * lons.size() + ix]; |
||||
|
||||
out.SetLongName("Number of moments u=0"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadNy() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto ncol = Name2ColNum("ny=0"); |
||||
if(ncol == 0) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = (*vylet)[ncol - 1][iy * lons.size() + ix]; |
||||
|
||||
out.SetLongName("Number of moments v=0"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadRx() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = elon[iy * lons.size() + ix] - lons[ix]; |
||||
|
||||
out.SetLongName("Displacement in zonal direction"); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadRy() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = elat[iy * lons.size() + ix] - lats[iy]; |
||||
|
||||
out.SetLongName("Displacement in meridional direction"); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadEx() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = elon[iy * lons.size() + ix]; |
||||
|
||||
out.SetLongName("Final longitude"); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadEy() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = elat[iy * lons.size() + ix]; |
||||
|
||||
out.SetLongName("Final latitude"); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadPhip() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto ncol = Name2ColNum("nphip"); |
||||
if(ncol == 0) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = (*vylet)[ncol - 1][iy * lons.size() + ix]; |
||||
|
||||
out.SetLongName("Number of counterclockwise rotations"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadPhim() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto ncol = Name2ColNum("nphim"); |
||||
if(ncol == 0) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = (*vylet)[ncol - 1][iy * lons.size() + ix]; |
||||
|
||||
out.SetLongName("Number of clockwise rotations"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadPhit() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto pcol = Name2ColNum("nphip"); |
||||
auto mcol = Name2ColNum("nphim"); |
||||
if(pcol == 0 || mcol == 0) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = (*vylet)[pcol - 1][iy * lons.size() + ix] - (*vylet)[mcol - 1][iy * lons.size() + ix]; |
||||
|
||||
out.SetLongName("Difference between the number of rotations counterclockwise and clockwise"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReaddS() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto l1col = Name2ColNum("Log(G.sigma1)"); |
||||
auto l2col = Name2ColNum("Log(G.sigma2)"); |
||||
if(l1col == 0 || l2col == 0) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = (*vylet)[l1col - 1][iy * lons.size() + ix] + (*vylet)[l2col - 1][iy * lons.size() + ix]; |
||||
|
||||
out.SetLongName("Logarithm of area change multiplier"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadAngle() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto ncol = Name2ColNum("angle"); |
||||
if(ncol == 0) return Data(); |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = (*vylet)[ncol - 1][iy * lons.size() + ix] / (2.0 * M_PI); |
||||
|
||||
out.SetLongName("Total rotation angle normalized to 2π"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadLen() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto ncol = Name2ColNum("length"); |
||||
if(ncol == 0) return Data(); |
||||
bool sisangle = !LengthFast(); |
||||
real mul = sisangle ? (6371.0 * M_PI / (60.0 * 180.0)) : 1.0; |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) out(ix, iy) = mul * (*vylet)[ncol - 1][iy * lons.size() + ix]; |
||||
|
||||
if(sisangle) |
||||
{ |
||||
out.SetUnit("km"); |
||||
out.SetLongName("Trajectory length"); |
||||
} |
||||
out.SetLongName("Trajectory length (in abstract units)"); |
||||
return out; |
||||
} |
||||
|
||||
VYLETData::Data VYLETData::ReadTmask() const |
||||
{ |
||||
Data out(lons, lats); |
||||
if(!vylet) return Data(); |
||||
|
||||
auto tcol = Name2ColNum("time"); |
||||
if(tcol == 0) return Data(); |
||||
|
||||
vylet->UsePrefix(""); |
||||
const real acc = vylet->ParameterRValue("accuracy", 1.0); |
||||
const real tstep = 2.0 * M_PI * 1000.0 / acc; |
||||
|
||||
const real maxdays = static_cast<real>(end - start) / MDateTime::secondsperday; |
||||
|
||||
MDateTime time; |
||||
real days; |
||||
bool maxtime; |
||||
|
||||
for(size_t iy = 0; iy < lats.size(); iy++) |
||||
for(size_t ix = 0; ix < lons.size(); ix++) |
||||
{ |
||||
time = R2Time((*vylet)[tcol - 1][iy * lons.size() + ix]); |
||||
days = static_cast<real>(time - start) / MDateTime::secondsperday; |
||||
maxtime = days >= maxdays - tstep * 0.5; |
||||
out(ix, iy) = maxtime ? 1.0 : NAN; |
||||
} |
||||
|
||||
out.SetLongName("Flag"); |
||||
out.SetComment("Values: 1.0 - the trajectory did not reach either the coast or the borders, NaN - overwise"); |
||||
return out; |
||||
} |
@ -0,0 +1,145 @@
|
||||
#pragma once |
||||
#include "BFileR.h" |
||||
#include "ParseArgs.h" |
||||
#include "mdatetime.h" |
||||
#include "mregex.h" |
||||
#include "simple2ddata.h" |
||||
#include <memory> |
||||
#include <set> |
||||
|
||||
using michlib::M_PI; |
||||
using michlib::MDateTime; |
||||
using michlib::real; |
||||
using michlib::Round; |
||||
|
||||
class VYLETData |
||||
{ |
||||
std::unique_ptr<michlib::BFileR> vylet; |
||||
MDateTime start, end, ref; |
||||
bool invtime; |
||||
real maxx, maxy; |
||||
std::vector<real> lons, lats; |
||||
std::vector<real> elon, elat; |
||||
|
||||
MDateTime R2Time(real r) const |
||||
{ |
||||
auto sec = static_cast<time_t>(Round(r * MDateTime::secondsperday)); |
||||
return ref + (invtime ? -sec : sec); |
||||
}; |
||||
|
||||
public: |
||||
using Data = Rect2DData; |
||||
|
||||
private: |
||||
auto Name2ColNum(const MString& name) const |
||||
{ |
||||
auto nc = vylet->Columns(); |
||||
decltype(nc) i; |
||||
for(i = 1; i <= nc; i++) |
||||
if(vylet->ColumnName(i) == name) return i; |
||||
i = 0; |
||||
return i; |
||||
} |
||||
|
||||
Data ReadD() const; |
||||
Data ReadL() const; |
||||
Data ReadT() const; |
||||
Data ReadNx() const; |
||||
Data ReadNy() const; |
||||
Data ReadRx() const; |
||||
Data ReadRy() const; |
||||
Data ReadEx() const; |
||||
Data ReadEy() const; |
||||
Data ReadPhip() const; |
||||
Data ReadPhim() const; |
||||
Data ReadPhit() const; |
||||
Data ReaddS() const; |
||||
Data ReadAngle() const; |
||||
Data ReadLen() const; |
||||
Data ReadTmask() const; |
||||
|
||||
public: |
||||
static constexpr const char* name = "VYLET"; |
||||
|
||||
static constexpr const char* disabledactions = "genintfile uv"; |
||||
|
||||
MString DefaultVars() const |
||||
{ |
||||
MString vars = "vylD,vylRx,vylRy,vylEx,vylEy,vylAngle,vylLen"; |
||||
if(HasLyap()) vars += ",vylL"; |
||||
if(HasTime()) vars += ",vylT"; |
||||
return vars; |
||||
} |
||||
|
||||
bool CheckVar(const MString& vname) const |
||||
{ |
||||
std::set<MString> vars{"vylD", "vylNx", "vylNy", "vylRx", "vylRy", "vylEx", "vylEy", "vylPhip", "vylPhim", "vylPhit", "vylAngle", "vylLen"}; |
||||
if(HasLyap()) vars.insert("vylL"); |
||||
if(HasLyap()) vars.insert("vyldS"); |
||||
if(HasTime()) vars.insert("vylT"); |
||||
if(HasTime()) vars.insert("vylTmask"); |
||||
return vars.contains(vname); |
||||
} |
||||
|
||||
bool Read(const MString& vname, std::map<MString, Data>& cache, size_t tind) const; |
||||
|
||||
size_t NTimes() const { return vylet ? 1 : 0; } |
||||
|
||||
MDateTime Time(size_t i) const |
||||
{ |
||||
if(i == 0 && vylet) return start; |
||||
return MDateTime(); |
||||
} |
||||
|
||||
bool HasLyap() const |
||||
{ |
||||
if(!vylet) return false; |
||||
vylet->UsePrefix(""); |
||||
MString method = vylet->ParameterSValue("Method", ""); |
||||
return method == "BicubicL" || method == "BicubicIL"; |
||||
} |
||||
|
||||
bool HasCoast() const |
||||
{ |
||||
if(!vylet) return false; |
||||
vylet->UsePrefix(""); |
||||
return vylet->ParameterBValue("checkcoast", true); |
||||
} |
||||
|
||||
real Left() const |
||||
{ |
||||
vylet->UsePrefix(""); |
||||
return vylet->ParameterRValue("xl", -1.0); |
||||
} |
||||
|
||||
real Right() const |
||||
{ |
||||
vylet->UsePrefix(""); |
||||
return vylet->ParameterRValue("xr", maxx + 1.0); |
||||
} |
||||
|
||||
real Down() const |
||||
{ |
||||
vylet->UsePrefix(""); |
||||
return vylet->ParameterRValue("yd", -1.0); |
||||
} |
||||
|
||||
real Up() const |
||||
{ |
||||
vylet->UsePrefix(""); |
||||
return vylet->ParameterRValue("yu", maxy + 1.0); |
||||
} |
||||
|
||||
bool HasBorders() const { return Left() >= 0.0 || Right() <= maxx || Down() >= 0.0 || Up() <= maxy; } |
||||
|
||||
bool HasTime() const { return HasCoast() || HasBorders(); } |
||||
|
||||
bool LengthFast() const |
||||
{ |
||||
vylet->UsePrefix(""); |
||||
return !vylet->ParameterBValue("sisangle", false); |
||||
} |
||||
|
||||
MString Info() const; |
||||
MString Open(const CLArgs& args); |
||||
}; |
@ -0,0 +1,105 @@
|
||||
#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) |
||||
{ |
||||
if(stype == UNKNOWN) return "Can't determine file type"; |
||||
|
||||
compress = compression; |
||||
|
||||
int ret; |
||||
MString text; |
||||
|
||||
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"; |
||||
|
||||
switch(stype) |
||||
{ |
||||
case(G1V1): |
||||
{ |
||||
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"; |
||||
break; |
||||
} |
||||
case(G1V2): |
||||
{ |
||||
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"; |
||||
break; |
||||
} |
||||
case(G2V2): |
||||
{ |
||||
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"; |
||||
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"; |
||||
|
||||
type = stype; |
||||
return ""; |
||||
} |
||||
|
||||
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); |
||||
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"; |
||||
|
||||
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"; |
||||
|
||||
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"; |
||||
|
||||
vars.push_back(v); |
||||
return ""; |
||||
} |
Loading…
Reference in new issue