Compare commits

...

10 Commits

  1. 13
      actions/actioninfo.h
  2. 5
      actions/actiontsc.h
  3. 11
      doc.txt
  4. 52
      include/Adapter.h
  5. 21
      include/CF.h
  6. 7
      include/zarr.h
  7. 7
      sources/COPERNICUS.cpp
  8. 91
      src/Adapter.cpp
  9. 375
      src/CF.cpp
  10. 22
      src/ncfilew.cpp
  11. 4
      src/zarr.cpp

13
actions/actioninfo.h

@ -24,6 +24,11 @@ MString ActionInfo_DoAction(const CLArgs& args, D& data)
ad = std::move(ret.Value());
}
{ // Modules
auto ret = CF::TEOS10Module(args, pars, ad);
if(!ret) return "Error adding TEOS-10 derived variables";
}
const MString titCol = F(C::BWHITE);
const MString timeCol = F(C::YELLOW);
const MString v2dCol = F(C::BGREEN);
@ -32,6 +37,7 @@ MString ActionInfo_DoAction(const CLArgs& args, D& data)
const MString usedCol = F(C::BMAGENTA);
const MString depthCol = F(C::YELLOW);
const MString horCol = F(C::YELLOW);
const MString comCol = F(C::BYELLOW);
// Header
message(titCol, ad.Title(), C());
@ -64,9 +70,10 @@ MString ActionInfo_DoAction(const CLArgs& args, D& data)
message("");
// Metainfo
message(ad.Is2D(name) ? v2dCol : v3dCol, name, C(), info.lname.Exist() ? (" - " + info.lname) : "",
info.targetunit.Exist() ? (", measured in " + unitCol + info.targetunit + C()) : "");
if(info.stname.Exist()) message(" Standard name: " + info.stname);
message(ad.Is2D(name) ? v2dCol : v3dCol, name, C(), info->lname.Exist() ? (" - " + info->lname) : "",
info->targetunit.Exist() ? (", measured in " + unitCol + info->targetunit + C()) : "");
if(info->comment.Exist()) message(comCol," ", info->comment, C());
if(info->stname.Exist()) message(" Standard name: " + info->stname);
// Vertical grid description
if(!ad.Is2D(name))

5
actions/actiontsc.h

@ -29,6 +29,11 @@ MString ActionTSC_DoAction(const CLArgs& args, D& ds)
ad = std::move(ret.Value());
}
{ // Modules
auto ret = CF::TEOS10Module(args, pars, ad);
if(!ret) return "Error adding TEOS-10 derived variables";
}
MString name = args.contains("out") ? args.at("out") : "out.nc";
int compress = args.contains("compress") ? args.at("compress").ToInt() : 3;
bool obfuscate = args.contains("obfuscate");

11
doc.txt

@ -74,12 +74,13 @@ COPERNICUS - источник для зеркалирования данных
filter - регулярное выражение, определяющее имена файлов для зеркалирования. По умолчанию - ".*". Только для действия mirror.
Следующие параметры влияют на выбор подмножества данных и работают для действий tsc и info.
lonb, lone, latb, late - регион, для которого берутся данные. В случае отсутствия используются минимумы/максимумы из данных.
layer, layers, depth, depths - выбор горизонта/горизонтов. Если отсутствуют все эти параметры, используется слой с нулевым номером (приповерхностный). Если присутствуют два или более параметра, то использует параметр с большим приоритетом. layer > depth > layers > depths.
layer - номер горизонта, ноль соответствует поверхности,
layers - номер горизонта или диапазон горизонтов через двоеточие или слово ALL (all) для выбора всех горизонтов,
depth - глубина, выбирается горизонт, ближайший к этой глубине,
depths - глубина или диапазон глубин, разделённых двоеточием, горизонты выбираются так же, как и для параметра depth.
layer, layers, depth, depths - выбор горизонта/горизонтов. Если отсутствуют все эти параметры, используется слой с нулевым номером (приповерхностный). Если присутствуют два или более параметра, то использует параметр с большим приоритетом (layers > layer > depths > depth).
layer, layers - номер горизонта (ноль соответствует поверхности) или диапазон горизонтов через двоеточие или слово ALL (all) для выбора всех горизонтов.
depth, depths - глубина или диапазон глубин, разделённых двоеточием, или слово ALL (all). Горизонты выбираются ближайшие к заданным глубинам.
time, timeb, timee, timefilt - параметры, управляющие выбором моментов времени. Использовать можно либо time, либо тройку timeb, timee, timefilt.
time - фиксированое время, регулярное выражение или одно из значений BEGIN, BEG, FIRST (соответствуют минимальному времени, для которого доступны данные) или END, LAST (соответствуют максимальному времени, для которого доступны данные). В случае фиксированого времени, выбирается ближайшее доступное время. Если time регулярное выражение, то это синоним timefilt.
timeb, timee, timefilt - выбираются времена в интервале timeb : timee, удовлетворяющие регулярному выражению timefilt. Если timefilt отсутствует, используются все времена в интервале. По умолчанию timeb=BEG, timee=END.
var, vars - синонимы, var имеет больший приоритет. Список переменных, разделённых запятыми. Базовый список можно посмотреть в выводе действия info.
Технические параметры.
chunkcachetimeout - время устаревания чанка в кэше в секундах. По умолчанию - 3600.
geochunked - если этот флаг присутствует, будут использоваться geochunked версия данных, а не timechunked.

52
include/Adapter.h

@ -24,28 +24,40 @@ class Adapter
};
// Информация о переменной
struct VInfo
struct VInfoBase
{
MString name; // Внутреннее имя в файле
MString unit, stname, lname, comment; // Единица измерения в файле, стандартное имя, человеческое имя, комментарий
MString targetunit; // Единица измерения прочитанных данных
std::shared_ptr<struct ReadInfo> rinfo; // Информация о блоке чтения
real scale; // Масштаб и
real offset; // смещение величины в файле
real fillval; // _FillVal
MString stname, lname, comment; // Стандартное имя, человеческое имя, комментарий
MString targetunit; // Единица измерения прочитанных данных
std::shared_ptr<struct ReadInfo> rinfo; // Информация о блоке чтения
real fillval; // _FillVal
virtual ~VInfoBase() = default;
};
using VInfo = std::unique_ptr<VInfoBase>;
// Информация о переменной в файле
struct VInfoNC: public VInfoBase
{
MString name; // Внутреннее имя в файле
MString unit; // Единица измерения в файле
real scale; // Масштаб и
real offset; // смещение величины в файле
virtual ~VInfoNC() override = default;
};
// Полная информация о переменной
struct VarInfo
{
struct VInfo info; // Информация о переменной в файле
VInfo info; // Информация о переменной для функций чтения и записи
std::shared_ptr<Projection> proj; // Горизонтальная структура прочитанных данных
std::shared_ptr<Vertical> vert; // Вертикальная структура прочитанных данных
// Функции чтения двумерного и трёхмерного блоков
std::function<RetVal<std::shared_ptr<Data2D>>(const Adapter&, const void*, std::shared_ptr<Projection>, size_t)> Read2D; // = Def2DReader;
std::function<RetVal<std::shared_ptr<Data3D>>(const Adapter&, const void*, std::shared_ptr<Projection>, std::shared_ptr<Vertical>, size_t)> Read3D; // = Def3DReader;
std::function<RetVal<std::shared_ptr<Data2D>>(Adapter&, const struct VInfoBase*, std::shared_ptr<Projection>, size_t)> Read2D; // = Def2DReader;
std::function<RetVal<std::shared_ptr<Data3D>>(Adapter&, const struct VInfoBase*, std::shared_ptr<Projection>, std::shared_ptr<Vertical>, size_t)> Read3D; // = Def3DReader;
};
// Запись в таблице файлов
@ -86,14 +98,19 @@ class Adapter
void SetTitle(const MString& t) { title = t; }
void Add2DVariable(const MString& name, struct VInfo&& vinfo, std::shared_ptr<Projection> proj, decltype(VarInfo().Read2D) func = Def2DReader)
bool Add2DVariable(const MString& name, std::unique_ptr<VInfoBase>&& vinfo, std::shared_ptr<Projection> proj, decltype(VarInfo().Read2D) func = Def2DReader)
{
if(vars.contains(name)) return false;
vars[name] = {.info = std::move(vinfo), .proj = proj, .Read2D = func, .Read3D = {}};
return true;
}
void Add3DVariable(const MString& name, struct VInfo&& vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, decltype(VarInfo().Read3D) func = Def3DReader)
bool Add3DVariable(const MString& name, std::unique_ptr<VInfoBase>&& vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert,
decltype(VarInfo().Read3D) func = Def3DReader)
{
if(vars.contains(name)) return false;
vars[name] = {.info = std::move(vinfo), .proj = proj, .vert = vert, .Read2D = {}, .Read3D = func};
return true;
}
void CleanVariables(const std::set<MString>& keep)
@ -107,6 +124,9 @@ class Adapter
const auto& Title() const { return title; }
const auto& Var(const MString& name) const { return vars.at(name); }
// Для вызова внутри внешних функций чтения
size_t CurrentTime() const { return curtime; }
std::vector<MDateTime> IndexedTimes() const
{
std::vector<MDateTime> out(tindexes.size());
@ -121,9 +141,9 @@ class Adapter
private:
// Функция чтения двумерных данных по умолчанию
static RetVal<std::shared_ptr<Data2D>> Def2DReader(const Adapter& ad, const void* vinfo, std::shared_ptr<Projection> proj, size_t it);
static RetVal<std::shared_ptr<Data2D>> Def2DReader(const Adapter& ad, const struct VInfoBase* vinfo, std::shared_ptr<Projection> proj, size_t it);
// Функция чтения трёхмерных данных по умолчанию
static RetVal<std::shared_ptr<Data3D>> Def3DReader(const Adapter& ad, const void* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, size_t it);
static RetVal<std::shared_ptr<Data3D>> Def3DReader(const Adapter& ad, const struct VInfoBase* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, size_t it);
// Создание индексов tindexes сообразно параметрам командной строки
Error FilterTimes(const CLArgs& args, michlib_internal::ParameterListEx& pars);
@ -134,7 +154,7 @@ class Adapter
std::map<MString, VarInfo> vars; // Переменные, которые можно читать
ZarrMethod method; // Метод доступа к данным файла
std::vector<TimeRow> timetable; // Таблица файлов, каждый файл содержит даннные для соответствующего временного интервала
size_t curtime; // Номер текущей записи в таблице
size_t curtime; // Текущее время, для которого работает кэш
size_t curit; // Смещение текущего времени в текущем файле
std::vector<MDateTime> times; // Моменты времени, для которых доступны данные
std::vector<size_t> tindexes; // Индексы в times, для которых запрашиваются данные

21
include/CF.h

@ -11,6 +11,23 @@ class CF
uint tdims = 0, zdims = 0, ydims = 0, xdims = 0;
};
struct VInfoTEOS10: public Adapter::VInfoBase
{
enum Operation
{
TEMP2PTEMP,
PTEMP2TEMP,
TEMP2PDENS,
PTEMP2PDENS,
TEMP2SSPEED,
PTEMP2SSPEED
};
MString tempvar, salvar;
Operation op;
virtual ~VInfoTEOS10() override = default;
};
// Get time variable name
static MString GetTVarName(const NCZarr& nc);
@ -76,5 +93,7 @@ class CF
return "";
}
//static RetVal<std::shared_ptr<Data2D>> PTemp3DReader(const Adapter& ad, const void* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, size_t it);
static RetVal<std::shared_ptr<Data3D>> TEOS103DReader(Adapter& ad, const Adapter::VInfoBase* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, size_t it);
static Error TEOS10Module(const CLArgs& args, michlib_internal::ParameterListEx& pars, Adapter& ad);
};

7
include/zarr.h

@ -36,7 +36,7 @@ class ZarrTypes: public NcZarrTypes
[](size_t N, const size_t* st, const size_t* cn, const size_t* cs)
{
Vec out(N);
for(size_t i = 0; i < N; i++) out[i] = (st[i] + cn[i]) / cs[i] - st[i] / cs[i] + 1;
for(size_t i = 0; i < N; i++) out[i] = (st[i] + cn[i] - 1) / cs[i] - st[i] / cs[i] + 1;
return out;
}(N, start, count, csize)),
inchunkind(Vec(csize, csize + N)),
@ -96,6 +96,8 @@ class ZarrFunctions: public ZarrTypes
MString url;
MString proxyurl;
static size_t chunkcachetimeout;
std::vector<std::vector<size_t>> chunks;
// Find variable names in metadata
@ -173,6 +175,9 @@ class ZarrFunctions: public ZarrTypes
public:
Error Open(const MString& product, const MString& dataset, bool time = true);
static size_t ChunkCacheTimeout() { return chunkcachetimeout; }
static void SetChunkCacheTimeout(size_t newtimeout) { chunkcachetimeout = newtimeout; }
};
using Zarr = NcZarrRead<ZarrFunctions>;

7
sources/COPERNICUS.cpp

@ -242,6 +242,9 @@ RetVal<Adapter> COPERNICUSData::GetAdapter(const CLArgs& args, michlib_internal:
bool debug = args.contains("debug");
if(args.contains("chunkcachetimeout")) ZarrFunctions::SetChunkCacheTimeout(args.at("chunkcachetimeout").ToInteger<size_t>());
if(debug) pars.SetParameter("chunkcachetimeout", ZarrFunctions::ChunkCacheTimeout());
Adapter out(Adapter::ZarrMethod::MZARR);
GPL.UsePrefix("NEMO");
@ -250,6 +253,7 @@ RetVal<Adapter> COPERNICUSData::GetAdapter(const CLArgs& args, michlib_internal:
MString product;
std::vector<MString> dset;
MString dataset;
bool timechunked = args.contains("geochunked") ? false : true;
{
if(args.contains("product")) // Get product and dataset from command line
{
@ -307,7 +311,7 @@ RetVal<Adapter> COPERNICUSData::GetAdapter(const CLArgs& args, michlib_internal:
// Open data
std::unique_ptr<NCZarr> pnc(new NCZarr);
{
auto ret = pnc->OpenMultiZarr(product, dset);
auto ret = pnc->OpenMultiZarr(product, dset, timechunked);
if(!ret) return ret.Add(pref, "Can't open dataset " + dataset);
}
@ -325,6 +329,7 @@ RetVal<Adapter> COPERNICUSData::GetAdapter(const CLArgs& args, michlib_internal:
// Filename for adapter
MString fname = product + ":" + dset[0];
for(size_t i = 1; i < dset.size(); i++) fname += "," + dset[i];
if(!timechunked) fname += ":false";
auto tvar = CF::GetTVarName(*pnc);
if(!tvar.Exist()) return {pref, "Can't find time variable in the dataset " + dataset};

91
src/Adapter.cpp

@ -84,11 +84,12 @@ Error Adapter::FilterTimes(const CLArgs& args, michlib_internal::ParameterListEx
return {};
}
RetVal<std::shared_ptr<Data2D>> Adapter::Def2DReader(const Adapter& ad, const void* vinfo, std::shared_ptr<Projection> proj, size_t it)
RetVal<std::shared_ptr<Data2D>> Adapter::Def2DReader(const Adapter& ad, const struct Adapter::VInfoBase* vinfo, std::shared_ptr<Projection> proj, size_t it)
{
static const MString pref = "Adapter::Def2DReader";
auto v = michlib::pointer_cast<const struct VInfo*>(vinfo);
auto v = dynamic_cast<const struct VInfoNC*>(vinfo);
if(v == nullptr) return {pref, "Incorrect argument type"};
const struct ReadInfo* ri = v->rinfo.get();
@ -125,15 +126,15 @@ RetVal<std::shared_ptr<Data2D>> Adapter::Def2DReader(const Adapter& ad, const vo
{
size_t nx = ad.nc->DimSize(v->name, ri->xdname);
{
xreq = ri->xdname + ":" + ri->xb + ":" + (nx - ri->xb + 1);
xreq = ri->xdname + ":" + ri->xb + ":" + (nx - ri->xb);
auto ret = needsconvert ? ad.nc->Read(v->name, data, cnvtrans, req()) : ad.nc->Read(v->name, data, trans, req());
if(!ret) return ret.Add(pref, "Can't read variable " + v->name);
}
{
size_t shift = nx - ri->xb + 1;
size_t shift = nx - ri->xb;
auto shifteddata = [pdata = out.get(), shift](size_t ix, size_t iy) -> real& { return (*pdata)(ix + shift, iy); };
xreq = ri->xdname + ":0:" + (ri->xe - 1);
xreq = ri->xdname + ":0:" + (ri->xe + 1);
auto ret = needsconvert ? ad.nc->Read(v->name, shifteddata, cnvtrans, req()) : ad.nc->Read(v->name, shifteddata, trans, req());
if(!ret) return ret.Add(pref, "Can't read variable " + v->name);
@ -142,11 +143,13 @@ RetVal<std::shared_ptr<Data2D>> Adapter::Def2DReader(const Adapter& ad, const vo
return out;
}
RetVal<std::shared_ptr<Data3D>> Adapter::Def3DReader(const Adapter& ad, const void* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, size_t it)
RetVal<std::shared_ptr<Data3D>> Adapter::Def3DReader(const Adapter& ad, const struct Adapter::VInfoBase* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert,
size_t it)
{
static const MString pref = "Adapter::Def3DReader";
auto v = michlib::pointer_cast<const struct VInfo*>(vinfo);
auto v = dynamic_cast<const struct VInfoNC*>(vinfo);
if(v == nullptr) return {pref, "Incorrect argument type"};
const struct ReadInfo* ri = v->rinfo.get();
@ -187,16 +190,16 @@ RetVal<std::shared_ptr<Data3D>> Adapter::Def3DReader(const Adapter& ad, const vo
{
size_t nx = ad.nc->DimSize(v->name, ri->xdname);
{
xreq = ri->xdname + ":" + ri->xb + ":" + (nx - ri->xb + 1);
xreq = ri->xdname + ":" + ri->xb + ":" + (nx - ri->xb);
auto ret = needsconvert ? ad.nc->Read(v->name, data, cnvtrans, req()) : ad.nc->Read(v->name, data, trans, req());
if(!ret) return ret.Add(pref, "Can't read variable " + v->name);
}
{
size_t shift = nx - ri->xb + 1;
size_t shift = nx - ri->xb;
auto shifteddata = [pdata = out.get(), shift, invertz](size_t ix, size_t iy, size_t iz) -> real& { return (*pdata)(ix + shift, iy, invertz ? (pdata->Nz() - iz - 1) : iz); };
auto shifteddata2D = [pdata = out.get(), shift](size_t ix, size_t iy) -> real& { return (*pdata)(ix + shift, iy, 0); };
xreq = ri->xdname + ":0:" + (ri->xe - 1);
xreq = ri->xdname + ":0:" + (ri->xe + 1);
auto ret = needsconvert ? (onez ? ad.nc->Read(v->name, shifteddata2D, cnvtrans, req()) : ad.nc->Read(v->name, shifteddata, cnvtrans, req()))
: (onez ? ad.nc->Read(v->name, shifteddata2D, trans, req()) : ad.nc->Read(v->name, shifteddata, trans, req()));
@ -269,39 +272,43 @@ Error Adapter::ReadCheck(const MString& var, size_t it)
}
{
const auto& v = vars[var];
const auto* ri = v.info.rinfo.get();
const auto& name = v.info.name;
const auto& v = vars[var];
const auto* ri = v.info->rinfo.get();
const auto* pvinfo = dynamic_cast<const struct VInfoNC*>(v.info.get());
const bool isdirect = pvinfo != nullptr; // Variable is directly reading from file, so check indexes and dimensions
const bool layered = ri->zdname.Exist() && nc->HasDim(name, ri->zdname);
if(layered)
if(isdirect)
{
//if(ri->ze < ri->zb) return {pref, "Internal error: ze < zb for variable " + var + "(" + name + ")" + " (" + ri->ze + " < " + ri->zb + ")"};
const size_t nz = nc->DimSize(name, ri->zdname);
if(ri->zb > nz - 1) return {pref, "Internal error: zb > nz - 1 for variable " + var + "(" + name + ")" + " (" + ri->zb + " > " + nz + " - 1)"};
if(ri->ze > nz - 1) return {pref, "Internal error: ze > nz - 1 for variable " + var + "(" + name + ")" + " (" + ri->ze + " > " + nz + " - 1)"};
if(v.vert && (ri->zb < ri->ze ? ri->ze - ri->zb : ri->zb - ri->ze) + 1 != v.vert->Nz())
return {pref, "Internal error: number of requested layers does'nt correspond parameters of vertical column for variable " + var + "(" + name + ")" + " (zb = " + ri->zb +
", ze = " + ri->ze + ", Nz = " + v.vert->Nz()};
const auto& name = pvinfo->name;
const bool layered = ri->zdname.Exist() && nc->HasDim(name, ri->zdname);
if(layered)
{
//if(ri->ze < ri->zb) return {pref, "Internal error: ze < zb for variable " + var + "(" + name + ")" + " (" + ri->ze + " < " + ri->zb + ")"};
const size_t nz = nc->DimSize(name, ri->zdname);
if(ri->zb > nz - 1) return {pref, "Internal error: zb > nz - 1 for variable " + var + "(" + name + ")" + " (" + ri->zb + " > " + nz + " - 1)"};
if(ri->ze > nz - 1) return {pref, "Internal error: ze > nz - 1 for variable " + var + "(" + name + ")" + " (" + ri->ze + " > " + nz + " - 1)"};
if(v.vert && (ri->zb < ri->ze ? ri->ze - ri->zb : ri->zb - ri->ze) + 1 != v.vert->Nz())
return {pref, "Internal error: number of requested layers does'nt correspond parameters of vertical column for variable " + var + "(" + name + ")" + " (zb = " + ri->zb +
", ze = " + ri->ze + ", Nz = " + v.vert->Nz()};
}
if(ri->ye < ri->yb) return {pref, "Internal error: ye < yb for variable " + var + "(" + name + ")" + " (" + ri->ye + " < " + ri->yb + ")"};
const size_t nx = nc->DimSize(name, ri->xdname);
const size_t ny = nc->DimSize(name, ri->ydname);
if(ri->ye > ny - 1) return {pref, "Internal error: ye > ny - 1 for variable " + var + "(" + name + ")" + " (" + ri->ye + " > " + ny + " - 1)"};
if(ri->ye - ri->yb + 1 != v.proj->Ny())
return {pref, "Internal error: number of requested y-planes does'nt correspond parameters of projection for variable " + var + "(" + name + ")" + " (yb = " + ri->yb +
", ye = " + ri->ye + ", Ny = " + v.proj->Ny()};
if(ri->xe > nx - 1) return {pref, "Internal error: xe > nx - 1 for variable " + var + "(" + name + ")" + " (" + ri->xe + " > " + nx + " - 1)"};
if(ri->xb > nx - 1) return {pref, "Internal error: xb > nx - 1 for variable " + var + "(" + name + ")" + " (" + ri->xb + " > " + nx + " - 1)"};
const size_t rnx = (ri->xb <= ri->xe) ? (ri->xe - ri->xb + 1) : (nx + ri->xe - ri->xb + 1);
if(rnx != v.proj->Nx())
return {pref, "Internal error: number of requested x-planes does'nt correspond parameters of projection for variable " + var + "(" + name + ")" + " (xb = " + ri->xb +
", xe = " + ri->xe + ", Nx = " + v.proj->Nx()};
}
if(ri->ye < ri->yb) return {pref, "Internal error: ye < yb for variable " + var + "(" + name + ")" + " (" + ri->ye + " < " + ri->yb + ")"};
const size_t nx = nc->DimSize(name, ri->xdname);
const size_t ny = nc->DimSize(name, ri->ydname);
if(ri->ye > ny - 1) return {pref, "Internal error: ye > ny - 1 for variable " + var + "(" + name + ")" + " (" + ri->ye + " > " + ny + " - 1)"};
if(ri->ye - ri->yb + 1 != v.proj->Ny())
return {pref, "Internal error: number of requested y-planes does'nt correspond parameters of projection for variable " + var + "(" + name + ")" + " (yb = " + ri->yb +
", ye = " + ri->ye + ", Ny = " + v.proj->Ny()};
if(ri->xe > nx - 1) return {pref, "Internal error: xe > nx - 1 for variable " + var + "(" + name + ")" + " (" + ri->xe + " > " + nx + " - 1)"};
if(ri->xb > nx - 1) return {pref, "Internal error: xb > nx - 1 for variable " + var + "(" + name + ")" + " (" + ri->xb + " > " + nx + " - 1)"};
const size_t rnx = (ri->xb <= ri->xe) ? (ri->xe - ri->xb + 1) : (nx + ri->xe - ri->xb + 1);
if(rnx != v.proj->Nx())
return {pref, "Internal error: number of requested x-planes does'nt correspond parameters of projection for variable " + var + "(" + name + ")" + " (xb = " + ri->xb +
", xe = " + ri->xe + ", Nx = " + v.proj->Nx()};
}
return {};
@ -328,7 +335,7 @@ RetVal<std::shared_ptr<Data2D>> Adapter::Read2D(const MString& var, size_t it)
if(!v.Read2D) return {pref, "No read function for the variable " + var};
auto ret = v.Read2D(*this, &v.info, v.proj, curit);
auto ret = v.Read2D(*this, v.info.get(), v.proj, curit);
if(!ret) return ret.Add(pref, "Can't read variable " + var);
(*cache2D)[var] = ret.Value();
return (*cache2D)[var];
@ -356,7 +363,7 @@ RetVal<std::shared_ptr<Data3D>> Adapter::Read3D(const MString& var, size_t it)
if(!v.vert) return {pref, "Variable " + var + " is 2D in the this dataset"};
if(!v.Read3D) return {pref, "No read function for the variable " + var};
auto ret = v.Read3D(*this, &v.info, v.proj, v.vert, curit);
auto ret = v.Read3D(*this, v.info.get(), v.proj, v.vert, curit);
if(!ret) return ret.Add(pref, "Can't read variable " + var);
(*cache3D)[var] = ret.Value();
return (*cache3D)[var];

375
src/CF.cpp

@ -1,5 +1,6 @@
#define MICHLIB_NOSOURCE
#include "CF.h"
#include "gsw.h"
using michlib::DetGeoDomain;
@ -285,48 +286,21 @@ Error CF::FillAdapterFromCF(const CLArgs& args, michlib_internal::ParameterListE
rinfoplane->zb = rinfoplane->ze = rinfo->zb = rinfo->ze = depths.size() - 1;
}
if(args.contains("layer") || args.contains("depth"))
{
size_t layer = 0;
if(args.contains("layer"))
layer = args.at("layer").ToInteger<size_t>();
else
{
auto d = args.at("depth").ToReal();
if(d < depths.front()) d = depths.front();
if(d > depths.back()) d = depths.back();
for(size_t i = 0; i < depths.size() - 1; i++)
if(d >= depths[i] && d <= depths[i + 1])
{
layer = (d - depths[i] <= depths[i + 1] - d) ? i : (i + 1);
break;
}
if(debug) pars.AddParameter("Requested depth", d);
}
if(layer > depths.size() - 1) return {pref, "Layer must be lesser then " + MString(depths.size())};
rinfoplane->zb = rinfoplane->ze = rinfo->zb = rinfo->ze = depthinv ? depths.size() - layer - 1 : layer;
vert.reset(new Vertical(Vertical::Create<Vertical::Type::FIXED>(depths[layer])));
pars.AddParameter("layer", layer);
pars.AddParameter("depth", depths[layer]);
if(debug) pars.AddParameter("zb", rinfo->zb);
}
else if(args.contains("layers") || args.contains("depths"))
if(args.contains("layer") || args.contains("depth") || args.contains("layers") || args.contains("depths"))
{
size_t layer1 = 0, layer2 = 0;
if(args.contains("layers"))
if(args.contains("layers") || args.contains("layer"))
{
if(args.at("layers") == "ALL" || args.at("layers") == "all")
MString layerarg = args.contains("layers") ? args.at("layers") : args.at("layer");
if(layerarg == "ALL" || layerarg == "all")
{
layer1 = 0;
layer2 = depths.size() - 1;
}
else
{
auto layerstr = args.at("layers").Split(":");
auto layerstr = layerarg.Split(":");
if(layerstr.size() > 2 || layerstr.size() == 0) return {pref, "Layers must have format layer1:layer2"};
if(layerstr.size() == 1)
@ -340,11 +314,18 @@ Error CF::FillAdapterFromCF(const CLArgs& args, michlib_internal::ParameterListE
}
else
{
real d1 = 0.0, d2 = 0.0;
auto depthstr = args.at("depths").Split(":");
real d1 = 0.0, d2 = 0.0;
MString deptharg = args.contains("depths") ? args.at("depths") : args.at("depth");
auto depthstr = deptharg.Split(":");
if(depthstr.size() > 2 || depthstr.size() == 0) return {pref, "Depths must have format depth1:depth2"};
if(depthstr.size() == 1)
d1 = d2 = depthstr[0].ToReal();
if(depthstr[0] == "ALL" || depthstr[0] == "all")
{
d1 = depths.front();
d2 = depths.back();
}
else
d1 = d2 = depthstr[0].ToReal();
else
{
d1 = depthstr[0].ToReal();
@ -369,8 +350,13 @@ Error CF::FillAdapterFromCF(const CLArgs& args, michlib_internal::ParameterListE
}
if(debug)
{
pars.AddParameter("Requested depth1", d1);
pars.AddParameter("Requested depth2", d2);
if(d1 == d2)
pars.AddParameter("Requested depth", d1);
else
{
pars.AddParameter("Requested depth1", d1);
pars.AddParameter("Requested depth2", d2);
}
}
}
@ -381,10 +367,18 @@ Error CF::FillAdapterFromCF(const CLArgs& args, michlib_internal::ParameterListE
rinfo->zb = depthinv ? depths.size() - layer1 - 1 : layer1;
rinfo->ze = depthinv ? depths.size() - layer2 - 1 : layer2;
pars.AddParameter("layer1", layer1);
pars.AddParameter("depth1", depths[layer1]);
pars.AddParameter("layer2", layer2);
pars.AddParameter("depth2", depths[layer2]);
if(layer1 == layer2)
{
pars.AddParameter("layer", layer1);
pars.AddParameter("depth", depths[layer1]);
}
else
{
pars.AddParameter("layer1", layer1);
pars.AddParameter("depth1", depths[layer1]);
pars.AddParameter("layer2", layer2);
pars.AddParameter("depth2", depths[layer2]);
}
if(debug)
{
@ -393,6 +387,9 @@ Error CF::FillAdapterFromCF(const CLArgs& args, michlib_internal::ParameterListE
}
// Create vertical projection
if(layer1 == layer2)
vert.reset(new Vertical(Vertical::Create<Vertical::Type::FIXED>(depths[layer1])));
else
{
decltype(depths) rdepths(depths.begin() + layer1, depths.begin() + layer2 + 1);
vert.reset(new Vertical(Vertical::Create<Vertical::Type::HORIZONTS>(rdepths)));
@ -409,32 +406,28 @@ Error CF::FillAdapterFromCF(const CLArgs& args, michlib_internal::ParameterListE
}
if(debug) pars.AddParameter("depthinv", depthinv);
//michlib::message("depth1=", depths[depthinv ? depths.size() - 1 - rinfo->zb : rinfo->zb], ", zb=", rinfo->zb);
//michlib::message("depth2=", depths[depthinv ? depths.size() - 1 - rinfo->ze : rinfo->ze], ", ze=", rinfo->ze);
//michlib::message(depthinv ? "Depths inverted" : "Depths not inverted");
// Read variables information
for(const auto& v: pnc->VarNames())
{
Adapter::VInfo vinfo;
auto dnames = pnc->DimNames(v);
auto vinfo = new Adapter::VInfoNC();
auto dnames = pnc->DimNames(v);
if(dnames.size() != 3 && dnames.size() != 4) continue;
if(dnames.size() == 3 && (dnames[0] != axisinfo.tdimname || dnames[1] != axisinfo.ydimname || dnames[2] != axisinfo.xdimname)) continue;
if(dnames.size() == 4 && (dnames[0] != axisinfo.tdimname || dnames[1] != axisinfo.zdimname || dnames[2] != axisinfo.ydimname || dnames[3] != axisinfo.xdimname)) continue;
vinfo.name = v;
vinfo.unit = "1";
vinfo->name = v;
vinfo->unit = "1";
if(dnames.size() == 4)
vinfo.rinfo = rinfo;
vinfo->rinfo = rinfo;
else
vinfo.rinfo = rinfoplane;
if(pnc->HasAtt(v, "units")) vinfo.unit = pnc->AttString(v, "units");
if(pnc->HasAtt(v, "standard_name")) vinfo.stname = pnc->AttString(v, "standard_name");
if(pnc->HasAtt(v, "long_name")) vinfo.lname = pnc->AttString(v, "long_name");
vinfo.offset = pnc->HasAtt(v, "add_offset") ? pnc->AttReal(v, "add_offset") : 0.0;
vinfo.scale = pnc->HasAtt(v, "scale_factor") ? pnc->AttReal(v, "scale_factor") : 1.0;
vinfo.fillval = std::visit(
vinfo->rinfo = rinfoplane;
if(pnc->HasAtt(v, "units")) vinfo->unit = pnc->AttString(v, "units");
if(pnc->HasAtt(v, "standard_name")) vinfo->stname = pnc->AttString(v, "standard_name");
if(pnc->HasAtt(v, "long_name")) vinfo->lname = pnc->AttString(v, "long_name");
vinfo->offset = pnc->HasAtt(v, "add_offset") ? pnc->AttReal(v, "add_offset") : 0.0;
vinfo->scale = pnc->HasAtt(v, "scale_factor") ? pnc->AttReal(v, "scale_factor") : 1.0;
vinfo->fillval = std::visit(
[](auto r) -> real
{
if constexpr(std::is_convertible_v<decltype(r), real>)
@ -444,26 +437,268 @@ Error CF::FillAdapterFromCF(const CLArgs& args, michlib_internal::ParameterListE
},
pnc->VarFill(v));
vinfo.targetunit = vinfo.unit;
if(vinfo.stname.SubStr(vinfo.stname.Len() - 7, 8) == "velocity") vinfo.targetunit = "cm/s";
vinfo->targetunit = vinfo->unit;
if(vinfo->stname.SubStr(vinfo->stname.Len() - 7, 8) == "velocity") vinfo->targetunit = "cm/s";
MString name = StName2Name(vinfo.stname).Exist() ? StName2Name(vinfo.stname) : v;
if(dnames.size() == 3) { ad.Add2DVariable(name, std::move(vinfo), proj); }
else { ad.Add3DVariable(name, std::move(vinfo), proj, vert); }
MString name = StName2Name(vinfo->stname).Exist() ? StName2Name(vinfo->stname) : v;
const bool addsuc = dnames.size() == 3 ? ad.Add2DVariable(name, Adapter::VInfo(vinfo), proj) : ad.Add3DVariable(name, Adapter::VInfo(vinfo), proj, vert);
if(!addsuc) return {pref, "Variable with name " + name + " already exist"};
}
return Error();
}
/*
RetVal<std::shared_ptr<Data2D>> CF::PTemp3DReader(const Adapter& ad, const void* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, size_t it)
RetVal<std::shared_ptr<Data3D>> CF::TEOS103DReader(Adapter& ad, const Adapter::VInfoBase* vinfo, std::shared_ptr<Projection> proj, std::shared_ptr<Vertical> vert, size_t it)
{
static const MString pref = "CF::PTemp3DReader";
auto v = michlib::pointer_cast<const struct Adapter::VInfo*>(vinfo);
static const MString pref = "CF::TempSalDer3DReader";
const struct Adapter::ReadInfo* ri = v->rinfo.get();
const auto* v = dynamic_cast<const struct VInfoTEOS10*>(vinfo);
if(v == nullptr) return {pref, "Incorrect argument type"};
std::shared_ptr<Data3D> out(new Data3D(proj, vert, {.unit = v->targetunit, .stname = v->stname, .lname = v->lname, .comment = v->comment}));
std::shared_ptr<Data3D> temp, sal;
{
auto rettemp = ad.Read3D(v->tempvar, ad.CurrentTime());
if(!rettemp) return {pref, "Can't read temperature variable " + v->tempvar};
temp = rettemp.Value();
}
{
auto retsal = ad.Read3D(v->salvar, ad.CurrentTime());
if(!retsal) return {pref, "Can't read salinity variable " + v->salvar};
sal = retsal.Value();
}
if(temp->Nz() != sal->Nz()) return {pref, MString("For temperature variable Nz=") + temp->Nz() + ", for salinity variable Nz=" + sal->Nz()};
if(temp->Ny() != sal->Ny()) return {pref, MString("For temperature variable Ny=") + temp->Ny() + ", for salinity variable Ny=" + sal->Ny()};
if(temp->Nx() != sal->Nx()) return {pref, MString("For temperature variable Nx=") + temp->Nx() + ", for salinity variable Nx=" + sal->Nx()};
if(temp->Nz() != out->Nz()) return {pref, MString("For temperature variable Nz=") + temp->Nz() + ", for output variable Nz=" + out->Nz()};
if(temp->Ny() != out->Ny()) return {pref, MString("For temperature variable Ny=") + temp->Ny() + ", for output variable Ny=" + out->Ny()};
if(temp->Nx() != out->Nx()) return {pref, MString("For temperature variable Nx=") + temp->Nx() + ", for output variable Nx=" + out->Nx()};
switch(v->op)
{
case(VInfoTEOS10::TEMP2PTEMP):
{
for(size_t iz = 0; iz < out->Nz(); iz++)
for(size_t iy = 0; iy < out->Ny(); iy++)
for(size_t ix = 0; ix < out->Nx(); ix++)
(*out)(ix, iy, iz) = (temp->IsFill(ix, iy, iz) || sal->IsFill(ix, iy, iz))
? out->Fillval()
: Temp2PTemp((*temp)(ix, iy, iz), (*sal)(ix, iy, iz), out->Depth(ix, iy, iz), out->Lon(ix, iy), out->Lat(ix, iy));
break;
}
case(VInfoTEOS10::PTEMP2TEMP):
{
for(size_t iz = 0; iz < out->Nz(); iz++)
for(size_t iy = 0; iy < out->Ny(); iy++)
for(size_t ix = 0; ix < out->Nx(); ix++)
(*out)(ix, iy, iz) = (temp->IsFill(ix, iy, iz) || sal->IsFill(ix, iy, iz))
? out->Fillval()
: PTemp2Temp((*temp)(ix, iy, iz), (*sal)(ix, iy, iz), out->Depth(ix, iy, iz), out->Lon(ix, iy), out->Lat(ix, iy));
break;
}
case(VInfoTEOS10::TEMP2PDENS):
{
for(size_t iz = 0; iz < out->Nz(); iz++)
for(size_t iy = 0; iy < out->Ny(); iy++)
for(size_t ix = 0; ix < out->Nx(); ix++)
(*out)(ix, iy, iz) = (temp->IsFill(ix, iy, iz) || sal->IsFill(ix, iy, iz))
? out->Fillval()
: Temp2PDens((*temp)(ix, iy, iz), (*sal)(ix, iy, iz), out->Depth(ix, iy, iz), out->Lon(ix, iy), out->Lat(ix, iy));
break;
}
case(VInfoTEOS10::PTEMP2PDENS):
{
for(size_t iz = 0; iz < out->Nz(); iz++)
for(size_t iy = 0; iy < out->Ny(); iy++)
for(size_t ix = 0; ix < out->Nx(); ix++)
(*out)(ix, iy, iz) = (temp->IsFill(ix, iy, iz) || sal->IsFill(ix, iy, iz))
? out->Fillval()
: PTemp2PDens((*temp)(ix, iy, iz), (*sal)(ix, iy, iz), out->Depth(ix, iy, iz), out->Lon(ix, iy), out->Lat(ix, iy));
break;
}
case(VInfoTEOS10::TEMP2SSPEED):
{
for(size_t iz = 0; iz < out->Nz(); iz++)
for(size_t iy = 0; iy < out->Ny(); iy++)
for(size_t ix = 0; ix < out->Nx(); ix++)
(*out)(ix, iy, iz) = (temp->IsFill(ix, iy, iz) || sal->IsFill(ix, iy, iz))
? out->Fillval()
: Temp2SSpeed((*temp)(ix, iy, iz), (*sal)(ix, iy, iz), out->Depth(ix, iy, iz), out->Lon(ix, iy), out->Lat(ix, iy));
break;
}
case(VInfoTEOS10::PTEMP2SSPEED):
{
for(size_t iz = 0; iz < out->Nz(); iz++)
for(size_t iy = 0; iy < out->Ny(); iy++)
for(size_t ix = 0; ix < out->Nx(); ix++)
(*out)(ix, iy, iz) = (temp->IsFill(ix, iy, iz) || sal->IsFill(ix, iy, iz))
? out->Fillval()
: PTemp2SSpeed((*temp)(ix, iy, iz), (*sal)(ix, iy, iz), out->Depth(ix, iy, iz), out->Lon(ix, iy), out->Lat(ix, iy));
break;
}
}
return out;
}
Error CF::TEOS10Module(const CLArgs& args, michlib_internal::ParameterListEx& pars, Adapter& ad)
{
static const MString pref = "TempSalDerModule";
MString sal, temp, ptemp;
for(const auto& v: ad.Vars())
{
if(!ad.Is3D(v.first)) continue;
const auto& info = v.second.info;
if(!sal.Exist() && info->stname == "sea_water_salinity") sal = v.first;
if(!temp.Exist() && info->stname == "sea_water_temperature") temp = v.first;
if(!ptemp.Exist() && info->stname == "sea_water_potential_temperature") ptemp = v.first;
}
// From potential temperature and salinity
if(sal.Exist() && ptemp.Exist())
{
const auto& tvar = ad.Vars().at(ptemp);
const auto& svar = ad.Vars().at(sal);
const auto& tproj = tvar.proj;
const auto& sproj = svar.proj;
const auto& tvert = tvar.vert;
const auto& svert = svar.vert;
const auto& tfill = tvar.info->fillval;
const auto& rinfo = tvar.info->rinfo;
if(sproj != tproj) return Error(pref, "Salinity variable " + sal + " and potential temperature variable " + ptemp + " have different horizontal grids");
if(svert != tvert) return Error(pref, "Salinity variable " + sal + " and potential temperature variable " + ptemp + " have different vertical grids");
{ // Temperature
auto vinfo = new VInfoTEOS10();
vinfo->tempvar = ptemp;
vinfo->salvar = sal;
vinfo->op = VInfoTEOS10::PTEMP2TEMP;
vinfo->stname = "sea_water_temperature";
vinfo->lname = "Temperature";
vinfo->comment = "Module TEOS-10: Temperature calculated from potential temperature (" + ptemp + ") and salinity (" + sal + ")";
vinfo->targetunit = "degrees_C";
vinfo->rinfo = rinfo;
vinfo->fillval = tfill;
const bool addsuc = ad.Add3DVariable("temp", Adapter::VInfo(vinfo), tproj, tvert, TEOS103DReader);
if(!addsuc) return {pref, "Variable with name temp already exist"};
}
{ // Potential density
auto vinfo = new VInfoTEOS10();
vinfo->tempvar = ptemp;
vinfo->salvar = sal;
vinfo->op = VInfoTEOS10::PTEMP2PDENS;
vinfo->stname = "sea_water_sigma_theta";
vinfo->lname = "Potential density minus 1000 kg m-3";
vinfo->comment = "Module TEOS-10: Potential density calculated from potential temperature (" + ptemp + ") and salinity (" + sal + ")";
vinfo->targetunit = "kg m-3";
vinfo->rinfo = rinfo;
vinfo->fillval = NAN;
const bool addsuc = ad.Add3DVariable("pdens", Adapter::VInfo(vinfo), tproj, tvert, TEOS103DReader);
if(!addsuc) return {pref, "Variable with name pdens already exist"};
}
{ // Sound speed
auto vinfo = new VInfoTEOS10();
vinfo->tempvar = ptemp;
vinfo->salvar = sal;
vinfo->op = VInfoTEOS10::PTEMP2SSPEED;
vinfo->stname = "speed_of_sound_in_sea_water";
vinfo->lname = "Sound speed";
vinfo->comment = "Module TEOS-10: Sound speed calculated from potential temperature (" + ptemp + ") and salinity (" + sal + ")";
vinfo->targetunit = "m s-1";
vinfo->rinfo = rinfo;
vinfo->fillval = NAN;
const bool addsuc = ad.Add3DVariable("sspeed", Adapter::VInfo(vinfo), tproj, tvert, TEOS103DReader);
if(!addsuc) return {pref, "Variable with name sspeed already exist"};
}
}
// From temperature and salinity
if(sal.Exist() && temp.Exist())
{
const auto& tvar = ad.Vars().at(temp);
const auto& svar = ad.Vars().at(sal);
const auto& tproj = tvar.proj;
const auto& sproj = svar.proj;
const auto& tvert = tvar.vert;
const auto& svert = svar.vert;
const auto& tfill = tvar.info->fillval;
const auto& rinfo = tvar.info->rinfo;
if(sproj != tproj) return Error(pref, "Salinity variable " + sal + " and temperature variable " + temp + " have different horizontal grids");
if(svert != tvert) return Error(pref, "Salinity variable " + sal + " and temperature variable " + temp + " have different vertical grids");
{ // Potential temperature
auto vinfo = new VInfoTEOS10();
vinfo->tempvar = temp;
vinfo->salvar = sal;
vinfo->op = VInfoTEOS10::TEMP2PTEMP;
vinfo->stname = "sea_water_potential_temperature";
vinfo->lname = "Potential temperature";
vinfo->comment = "Module TEOS-10: Potential temperature calculated from temperature (" + temp + ") and salinity (" + sal + ")";
vinfo->targetunit = "degrees_C";
vinfo->rinfo = rinfo;
vinfo->fillval = tfill;
const bool addsuc = ad.Add3DVariable("ptemp", Adapter::VInfo(vinfo), tproj, tvert, TEOS103DReader);
if(!addsuc) return {pref, "Variable with name ptemp already exist"};
}
{ // Potential density
auto vinfo = new VInfoTEOS10();
vinfo->tempvar = temp;
vinfo->salvar = sal;
vinfo->op = VInfoTEOS10::TEMP2PDENS;
vinfo->stname = "sea_water_sigma_theta";
vinfo->lname = "Potential density minus 1000 kg m-3";
vinfo->comment = "Module TEOS-10: Potential density calculated from temperature (" + temp + ") and salinity (" + sal + ")";
vinfo->targetunit = "kg m-3";
vinfo->rinfo = rinfo;
vinfo->fillval = NAN;
const bool addsuc = ad.Add3DVariable("pdens", Adapter::VInfo(vinfo), tproj, tvert, TEOS103DReader);
if(!addsuc) return {pref, "Variable with name pdens already exist"};
}
{ // Sound speed
auto vinfo = new VInfoTEOS10();
vinfo->tempvar = temp;
vinfo->salvar = sal;
vinfo->op = VInfoTEOS10::TEMP2SSPEED;
vinfo->stname = "speed_of_sound_in_sea_water";
vinfo->lname = "Sound speed";
vinfo->comment = "Module TEOS-10: Sound speed calculated from temperature (" + temp + ") and salinity (" + sal + ")";
vinfo->targetunit = "m s-1";
vinfo->rinfo = rinfo;
vinfo->fillval = NAN;
const bool addsuc = ad.Add3DVariable("sspeed", Adapter::VInfo(vinfo), tproj, tvert, TEOS103DReader);
if(!addsuc) return {pref, "Variable with name sspeed already exist"};
}
}
return {};
}
*/

22
src/ncfilew.cpp

@ -214,17 +214,17 @@ michlib::Error NCFileW::Create(const MString& name, const Adapter& ad, const mic
bool is2D = v.second.Read2D ? true : false;
bool is3D = v.second.Read3D ? true : false;
const auto& vname = v.first; // Variable name
const auto& proj = *v.second.proj; // Horizontal projection
const auto& vert = *v.second.vert; // Vertical projection
const auto& units = v.second.info.targetunit; // Unit
const auto& stname = v.second.info.stname; // Standard name
const auto& lname = v.second.info.lname; // Long name
const auto& comment = v.second.info.comment; // Comment
const auto& xdname = v.second.info.rinfo->xdname; // X-dimension name
const auto& ydname = v.second.info.rinfo->ydname; // Y-dimension name
const auto& zdname = v.second.info.rinfo->zdname; // Z-dimension name
const auto& fillval = v.second.info.fillval; // _FillValue
const auto& vname = v.first; // Variable name
const auto& proj = *v.second.proj; // Horizontal projection
const auto& vert = *v.second.vert; // Vertical projection
const auto& units = v.second.info->targetunit; // Unit
const auto& stname = v.second.info->stname; // Standard name
const auto& lname = v.second.info->lname; // Long name
const auto& comment = v.second.info->comment; // Comment
const auto& xdname = v.second.info->rinfo->xdname; // X-dimension name
const auto& ydname = v.second.info->rinfo->ydname; // Y-dimension name
const auto& zdname = v.second.info->rinfo->zdname; // Z-dimension name
const auto& fillval = v.second.info->fillval; // _FillValue
if((is2D && is3D) || (!is2D && !is3D)) return {pref, "Can't determine type of variable " + vname};

4
src/zarr.cpp

@ -3,6 +3,8 @@
#include "copcat.h"
#include <blosc.h>
size_t ZarrFunctions::chunkcachetimeout = 3600;
std::vector<MString> ZarrFunctions::ReadVarNames(const Json::Value& meta)
{
std::vector<MString> out;
@ -179,7 +181,7 @@ Error ZarrFunctions::GetChunk(const MString& var, const std::vector<size_t>& chu
//curl_easy_getinfo(chandle, CURLINFO_RESPONSE_CODE, &respcode);
curl_easy_getinfo(myhandle, CURLINFO_RESPONSE_CODE, &respcode);
if(respcode == 403) out = ""; // Failed chunk download mean that this chunk contains only fill
cache->Put(str, out, 3600);
cache->Put(str, out, chunkcachetimeout);
content = std::move(out);
}

Loading…
Cancel
Save