Michael Uleysky
1 year ago
2 changed files with 304 additions and 0 deletions
@ -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); |
||||||
|
|
||||||
|
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,103 @@ |
|||||||
|
#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) |
||||||
|
{ |
||||||
|
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"; |
||||||
|
|
||||||
|
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