From 8906f259278606909d01c512d76c381d4b061873 Mon Sep 17 00:00:00 2001 From: Michael Uleysky Date: Wed, 22 Mar 2023 13:35:43 +1000 Subject: [PATCH] Redone abstractions --- include/NEMO.h | 305 +++++++++++++++++++++++------------------ include/ParseArgs.h | 7 + include/basedata.h | 24 +++- include/odm.h | 180 ++++++++++++++++-------- include/simple2ddata.h | 13 +- include/tindexes.h | 63 --------- include/vartype.h | 118 ---------------- src/ParseArgs.cpp | 5 +- src/actioninfo.cpp | 45 ++---- src/actiontsc.cpp | 165 +++++++++------------- src/basedata.cpp | 3 + src/odm.cpp | 23 +++- 12 files changed, 437 insertions(+), 514 deletions(-) create mode 100644 include/ParseArgs.h delete mode 100644 include/tindexes.h delete mode 100644 include/vartype.h create mode 100644 src/basedata.cpp diff --git a/include/NEMO.h b/include/NEMO.h index 504096b..e1c87b1 100644 --- a/include/NEMO.h +++ b/include/NEMO.h @@ -1,16 +1,19 @@ #pragma once #include "DataAdapters/ncfilealt.h" +#include "ParseArgs.h" #include "mdatetime.h" #include "simple2ddata.h" #include "specfunc.h" -#include "vartype.h" +#include #include #include #include #include using michlib::Ceil; +using michlib::errmessage; using michlib::Floor; +using michlib::GPL; using michlib::int2; using michlib::MDateTime; using michlib::NCFileA; @@ -26,11 +29,19 @@ class NEMOData TYPE_NRT6 }; + struct Parameters: public BaseParameters + { + size_t xb, yb, xe, ye, layer; + MString varname; + virtual ~Parameters() override = default; + }; + std::vector nc; - size_t xb, yb, xe, ye, layer; std::vector depths; std::vector times; - size_t nx; + size_t nx, ny; + real lonb, latb, lone, late; + real lonstep, latstep; Type type = TYPE_UNKNOWN; class EnvVar @@ -73,7 +84,7 @@ class NEMOData using Data = Simple2DData; private: - template Data ReadVarRaw(const NCFileA& f, const MString& name, size_t i, bool nodepth) const + template Data ReadVarRaw(const NCFileA& f, const MString& name, size_t i, bool nodepth, const Parameters* p) const { real unitmul = 1.0; DataType fill; @@ -92,12 +103,12 @@ class NEMOData auto unit = f.A(name, "units"); if(unit && unit.Get() == "m s-1") unitmul = 100.0; - Data data((xb < xe) ? (xe - xb + 1) : (nx + xe - xb + 1), ye - yb + 1, Lonb(), Latb(), 1.0 / 12.0, 1.0 / 12.0); + Data data((p->xb < p->xe) ? (p->xe - p->xb + 1) : (nx + p->xe - p->xb + 1), p->ye - p->yb + 1, Lon(p->xb), Lat(p->yb), lonstep, latstep); - if(xb < xe) + if(p->xb < p->xe) { - auto var = nodepth ? f.V(name, {"longitude", xb, xe - xb + 1}, {"latitude", yb, ye - yb + 1}, {"time", i, 1}) - : f.V(name, {"longitude", xb, xe - xb + 1}, {"latitude", yb, ye - yb + 1}, {"time", i, 1}, {"depth", layer, 1}); + auto var = nodepth ? f.V(name, {"longitude", p->xb, p->xe - p->xb + 1}, {"latitude", p->yb, p->ye - p->yb + 1}, {"time", i, 1}) + : f.V(name, {"longitude", p->xb, p->xe - p->xb + 1}, {"latitude", p->yb, p->ye - p->yb + 1}, {"time", i, 1}, {"depth", p->layer, 1}); if(!var) return Data(); if(var.DimLen(0) != data.Nx() || var.DimLen(1) != data.Ny()) return Data(); @@ -110,10 +121,10 @@ class NEMOData } else { - auto var1 = nodepth ? f.V(name, {"longitude", xb}, {"latitude", yb, ye - yb + 1}, {"time", i, 1}) - : f.V(name, {"longitude", xb}, {"latitude", yb, ye - yb + 1}, {"time", i, 1}, {"depth", layer, 1}); - auto var2 = nodepth ? f.V(name, {"longitude", 0, xe + 1}, {"latitude", yb, ye - yb + 1}, {"time", i, 1}) - : f.V(name, {"longitude", 0, xe + 1}, {"latitude", yb, ye - yb + 1}, {"time", i, 1}, {"depth", layer, 1}); + auto var1 = nodepth ? f.V(name, {"longitude", p->xb}, {"latitude", p->yb, p->ye - p->yb + 1}, {"time", i, 1}) + : f.V(name, {"longitude", p->xb}, {"latitude", p->yb, p->ye - p->yb + 1}, {"time", i, 1}, {"depth", p->layer, 1}); + auto var2 = nodepth ? f.V(name, {"longitude", 0, p->xe + 1}, {"latitude", p->yb, p->ye - p->yb + 1}, {"time", i, 1}) + : f.V(name, {"longitude", 0, p->xe + 1}, {"latitude", p->yb, p->ye - p->yb + 1}, {"time", i, 1}, {"depth", p->layer, 1}); if(!(var1 && var2)) return Data(); if((var1.DimLen(0) + var2.DimLen(0)) != data.Nx() || var1.DimLen(1) != data.Ny() || var2.DimLen(1) != data.Ny()) return Data(); for(size_t ix = 0; ix < var1.DimLen(0); ix++) @@ -132,12 +143,24 @@ class NEMOData return data; } + static MString VName2IName(const MString& vname) + { + if(vname == "temp") return "thetao"; + if(vname == "sal") return "so"; + if(vname == "mld") return "mlotst"; + if(vname == "ssh") return "zos"; + if(vname == "w") return "wo"; + return ""; + } + public: - Data ReadVar(const MString& name, size_t i) const + Data Read(const BaseParameters* ip, size_t i) const { if(!isOk()) return Data(); bool nodepth = false; + auto p = dynamic_cast(ip); + MString name = VName2IName(p->varname); for(const auto& f: nc) { auto head = f.Header(); @@ -145,88 +168,84 @@ class NEMOData if(v.Name() == name) { if(v.Dimensions().size() == 3) nodepth = true; - if(v.Type().Id() == NC_SHORT) return ReadVarRaw(f, name, i, nodepth); - if(v.Type().Id() == NC_FLOAT) return ReadVarRaw(f, name, i, nodepth); + if(v.Type().Id() == NC_SHORT) return ReadVarRaw(f, name, i, nodepth, p); + if(v.Type().Id() == NC_FLOAT) return ReadVarRaw(f, name, i, nodepth, p); } } return Data(); } - Data ReadVar(const MString& name, const std::vector& tindex) const + bool HasVar(const MString vname) const { - Averager out; - if(tindex.size() == 0 || !isOk()) return out; + MString name = VName2IName(vname); + if(name == "") return false; - for(size_t i = 0; i < tindex.size(); i++) + for(const auto& f: nc) { - Data dat = ReadVar(name, tindex[i]); - if(!dat) return Data(); - out.Add(dat); + auto head = f.Header(); + for(const auto& v: head.Variables()) + if(v.Name() == name) return true; } - out.Div(); - return out; + return false; } public: NEMOData() = default; // TODO: RetVal - bool Open(const MString& stype, const MString& cred, const MString& proxyurl = "") + MString Open(const CLArgs& args) { + MString oldprefix = GPL.UsePrefix("AVISO"); + MString dataset = args.contains("dataset") ? args.at("dataset") : "DT"; + MString cred = GPL.ParameterSValue("COPERNICUS_USER", ""); + MString proxyurl = GPL.ParameterSValue("COPERNICUS_PROXY", ""); + + GPL.UsePrefix(oldprefix); + nc.clear(); if(proxyurl.Exist()) proxy.Activate("all_proxy", proxyurl); - if(stype == "DT") + + std::vector urls; + if(dataset == "DT") { - NCFileA newnc; - newnc.Reset("https://" + cred + "@my.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy_my_0.083_P1D-m"); - if(!newnc) return false; - nc.push_back(std::move(newnc)); + urls = {"https://" + cred + "@my.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy_my_0.083_P1D-m"}; type = TYPE_DT; } - if(stype == "NRT") + else if(dataset == "NRT") { - std::vector urls{"https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-cur_anfc_0.083deg_P1D-m", - "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-thetao_anfc_0.083deg_P1D-m", - "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-so_anfc_0.083deg_P1D-m", - "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy_anfc_0.083deg_P1D-m", - "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-wcur_anfc_0.083deg_P1D-m"}; - for(const auto& url: urls) - { - NCFileA newnc; - newnc.Reset(url); - if(!newnc) - { - nc.clear(); - return false; - } - nc.push_back(std::move(newnc)); - } + urls = {"https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-cur_anfc_0.083deg_P1D-m", + "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-thetao_anfc_0.083deg_P1D-m", + "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-so_anfc_0.083deg_P1D-m", + "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy_anfc_0.083deg_P1D-m", + "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-wcur_anfc_0.083deg_P1D-m"}; type = TYPE_NRT; } - if(stype == "NRT6") + else if(dataset == "NRT6") { - std::vector urls{"https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-cur_anfc_0.083deg_PT6H-i", - "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-thetao_anfc_0.083deg_PT6H-i", - "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-so_anfc_0.083deg_PT6H-i"}; - for(const auto& url: urls) + urls = {"https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-cur_anfc_0.083deg_PT6H-i", + "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-thetao_anfc_0.083deg_PT6H-i", + "https://" + cred + "@nrt.cmems-du.eu/thredds/dodsC/cmems_mod_glo_phy-so_anfc_0.083deg_PT6H-i"}; + type = TYPE_NRT6; + } + else + return "Unknown dataset: " + dataset; + + nc.resize(urls.size()); + for(size_t i = 0; i < urls.size(); i++) + { + nc[i].Reset(urls[i]); + if(!nc[i]) { - NCFileA newnc; - newnc.Reset(url); - if(!newnc) - { - nc.clear(); - return false; - } - nc.push_back(std::move(newnc)); + nc.clear(); + return "Can't connect to database"; } - type = TYPE_NRT6; } auto rdepths = nc[0].V("depth"); if(!rdepths) { nc.clear(); - return false; + return "Can't read depths"; } depths.resize(rdepths.DimLen(0)); for(size_t i = 0; i < depths.size(); i++) depths[i] = rdepths(i); @@ -236,21 +255,46 @@ class NEMOData if(!(timeD || timeF)) { nc.clear(); - return false; + return "Can't read times"; } MDateTime refdate("1950-01-01"); timeD ? times.resize(timeD.DimLen(0)) : times.resize(timeF.DimLen(0)); for(size_t i = 0; i < times.size(); i++) times[i] = refdate + static_cast(timeD ? timeD(i) : timeF(i)) * 3600; - return true; + auto nlon = nc[0].D("longitude"); + auto nlat = nc[0].D("latitude"); + if(!(nlon && nlat)) + { + nc.clear(); + return "Can't get number of longitudes/latitudes"; + } + nx = nlon; + ny = nlat; + + auto lons = nc[0].V("longitude"); + auto lats = nc[0].V("latitude"); + if(!(lons && lats)) + { + nc.clear(); + return "Can't get longitudes/latitudes"; + } + lonb = lons(0); + latb = lats(0); + lone = lons(nx - 1); + late = lats(ny - 1); + lonstep = (lone - lonb) / (nx - 1); + latstep = (late - latb) / (ny - 1); + + return ""; } MString Info() const { + if(!isOk()) return ""; MString d; for(size_t i = 0; i < NDepths(); i++) d += MString(" ") + "(" + i + " " + Depth(i) + ")"; - std::set vars; + std::set vars; for(const auto& f: nc) { auto head = f.Header(); @@ -268,7 +312,7 @@ class NEMOData bool first = true; for(const auto& v: vars) { - svars += (first ? "" : ", ") + v.ShortName(); + svars += (first ? "" : ", ") + v; first = false; } } @@ -280,70 +324,81 @@ class NEMOData " End date: " + Time(NTimes()-1).ToString() + "\n" + " Time step: " + Timestep() + " seconds\n" + " Time moments: " + NTimes() + "\n" + + " Region: (" + lonb + " : " + lone + ") x (" + latb + " : " + late + ")\n" + + " Grid: " + nx + "x" + ny + " (" + lonstep + " x " + latstep + ")\n" + " Depths:" + d + "\n" + " Supported variables: " + svars; // clang-format on } - MString Dump() const + std::pair Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const { - // clang-format off - return - "Current settings:\n" + MString() + - " Longitudes: from " + Lonb() + " (" + xb + ") to "+ Lone() + " (" + xe + ")\n" + - " Latitudes: from " + Latb() + " (" + yb + ") to "+ Late() + " (" + ye + ")\n" + - " Depth: layer " + layer + ", depth " + Depth() + " m\n"; - // clang-format on - } + std::unique_ptr ppar{new struct Parameters}; - bool SetRegion(real lonbin, real lonein, real latb, real late, real depth) - { - if(!isOk()) return false; - real lonb = ToGeoDomainNeg(lonbin), lone = ToGeoDomainNeg(lonein); + if(!args.contains("var")) return {nullptr, "Variable not specified"}; + ppar->varname = args.at("var"); + if(!HasVar(ppar->varname)) return {nullptr, "Variable " + ppar->varname + " not exists in this dataset"}; + if(args.contains("layer")) ppar->layer = args.at("layer").ToInteger(); + if(!args.contains("depth") && ppar->layer >= NDepths()) return {nullptr, MString("Layer ") + ppar->layer + " is too deep!"}; + real depth = args.contains("depth") ? args.at("depth").ToReal() : Depth(ppar->layer); - size_t xb_, xe_, yb_, ye_, layer_ = 0; + if(!(args.contains("lonb") && args.contains("lone") && args.contains("latb") && args.contains("late"))) return {nullptr, "Region not specified (lonb, lone, latb, late)"}; - yb_ = static_cast(Floor((latb + 80.0) * 12.0)); - ye_ = static_cast(Ceil((late + 80.0) * 12.0)); - if(ye_ > 2040) ye_ = 2040; - if(yb_ >= ye_) return false; + { + real lon1 = ToGeoDomainNeg(args.at("lonb").ToReal()); + real lon2 = ToGeoDomainNeg(args.at("lone").ToReal()); + real lat1 = ToGeoDomainNeg(args.at("latb").ToReal()); + real lat2 = ToGeoDomainNeg(args.at("late").ToReal()); - xb_ = static_cast(Floor((lonb + 180.0) * 12.0)); - xe_ = static_cast(Ceil((lone + 180.0) * 12.0)); - if(xb_ == xe_) return false; + ppar->yb = static_cast(Floor((lat1 - latb) / latstep)); + ppar->ye = static_cast(Ceil((lat2 - latb) / latstep)); + if(ppar->ye > 2040) ppar->ye = 2040; + if(ppar->yb >= ppar->ye) return {nullptr, "Latb must be lesser then late"}; - if(depth < 0.0 || depth > depths.back()) - layer_ = (depth < 0.0) ? 0 : (depths.size() - 1); - else - for(size_t i = 0; i < depths.size() - 1; i++) - { - if(depth >= depths[i] && depth <= depths[i + 1]) + ppar->xb = static_cast(Floor((lon1 - lonb) / lonstep)); + ppar->xe = static_cast(Ceil((lon2 - lonb) / lonstep)); + + if(ppar->xb == ppar->xe) return {nullptr, "Lonb must be not equal late"}; + + if(depth < 0.0 || depth > depths.back()) + ppar->layer = (depth < 0.0) ? 0 : (depths.size() - 1); + else + for(size_t i = 0; i < depths.size() - 1; i++) { - layer_ = (depth - depths[i] <= depths[i + 1] - depth) ? i : (i + 1); - break; + if(depth >= depths[i] && depth <= depths[i + 1]) + { + ppar->layer = (depth - depths[i] <= depths[i + 1] - depth) ? i : (i + 1); + break; + } } - } - xb = xb_; - xe = xe_; - yb = yb_; - ye = ye_; - layer = layer_; - return true; + } + + pars.SetParameter("variable", ppar->varname); + pars.SetParameter("depth", Depth(ppar->layer)); + pars.SetParameter("layer", ppar->layer); + pars.SetParameter("dataset", Title()); + pars.SetParameter("lonb", Lon(ppar->xb)); + pars.SetParameter("latb", Lat(ppar->yb)); + pars.SetParameter("lone", Lon(ppar->xe)); + pars.SetParameter("late", Lat(ppar->ye)); + + return {ppar.release(), ""}; + } + + MString Dump(const struct Parameters* ppar) const + { + // clang-format off + return + "Current settings:\n" + MString() + + " Longitudes: from " + Lon(ppar->xb) + " (" + ppar->xb + ") to "+ Lon(ppar->xe) + " (" + ppar->xe + ")\n" + + " Latitudes: from " + Lat(ppar->yb) + " (" + ppar->yb + ") to "+ Lat(ppar->ye) + " (" + ppar->ye + ")\n" + + " Depth: layer " + ppar->layer + ", depth " + Depth(ppar->layer) + " m\n"; + // clang-format on } - real Lonb() const { return isOk() ? (-180.0 + xb / 12.0) : -1000.0; } - real Lone() const { return isOk() ? (-180.0 + xe / 12.0) : -1000.0; } - real Latb() const { return isOk() ? (-80.0 + yb / 12.0) : -1000.0; } - real Late() const { return isOk() ? (-80.0 + ye / 12.0) : -1000.0; } - size_t Xb() const { return isOk() ? xb : 0; } - size_t Xe() const { return isOk() ? xe : 0; } - size_t Yb() const { return isOk() ? yb : 0; } - size_t Ye() const { return isOk() ? ye : 0; } - size_t Nx() const { return isOk() ? ((xb < xe) ? (xe - xb + 1) : (nx + xe - xb + 1)) : 0; } - size_t Ny() const { return isOk() ? (ye - yb + 1) : 0; } + real Lon(size_t ix) const { return isOk() ? (-180.0 + ix / 12.0) : -1000.0; } + real Lat(size_t iy) const { return isOk() ? (-80.0 + iy / 12.0) : -1000.0; } real Depth(size_t l) const { return isOk() ? depths[l] : -1000.0; } - real Depth() const { return Depth(layer); } - size_t Layer() const { return layer; } time_t Timestep() const { return isOk() ? (times[1] - times[0]) : 0; } MDateTime Time(size_t i) const { @@ -351,16 +406,12 @@ class NEMOData return times[i]; } - bool isOk() const { return nc.size() > 0; } + bool isOk() const { return nc.size() > 0; } explicit operator bool() const { return nc.size() > 0; } size_t NDepths() const { return depths.size(); } size_t NTimes() const { return times.size(); } - template Data Read(size_t it) const = delete; - - template Data Read(const std::vector& tindex) const = delete; - MString Title() const { switch(type) @@ -374,19 +425,3 @@ class NEMOData static real Fillval() { return Data::Fillval(); } }; - -template<> inline NEMOData::Data NEMOData::Read(size_t it) const { return ReadVar("uo", it); } -template<> inline NEMOData::Data NEMOData::Read(size_t it) const { return ReadVar("vo", it); } -template<> inline NEMOData::Data NEMOData::Read(size_t it) const { return ReadVar("thetao", it); } -template<> inline NEMOData::Data NEMOData::Read(size_t it) const { return ReadVar("so", it); } -template<> inline NEMOData::Data NEMOData::Read(size_t it) const { return ReadVar("mlotst", it); } -template<> inline NEMOData::Data NEMOData::Read(size_t it) const { return ReadVar("zos", it); } -template<> inline NEMOData::Data NEMOData::Read(size_t it) const { return ReadVar("wo", it); } - -template<> inline NEMOData::Data NEMOData::Read(const std::vector& tindex) const { return ReadVar("uo", tindex); } -template<> inline NEMOData::Data NEMOData::Read(const std::vector& tindex) const { return ReadVar("vo", tindex); } -template<> inline NEMOData::Data NEMOData::Read(const std::vector& tindex) const { return ReadVar("thetao", tindex); } -template<> inline NEMOData::Data NEMOData::Read(const std::vector& tindex) const { return ReadVar("so", tindex); } -template<> inline NEMOData::Data NEMOData::Read(const std::vector& tindex) const { return ReadVar("mlotst", tindex); } -template<> inline NEMOData::Data NEMOData::Read(const std::vector& tindex) const { return ReadVar("zos", tindex); } -template<> inline NEMOData::Data NEMOData::Read(const std::vector& tindex) const { return ReadVar("wo", tindex); } diff --git a/include/ParseArgs.h b/include/ParseArgs.h new file mode 100644 index 0000000..254bdd0 --- /dev/null +++ b/include/ParseArgs.h @@ -0,0 +1,7 @@ +#pragma once +#include "GPL.h" + +using michlib::MString; +using CLArgs = std::map; + +CLArgs ParseArgs(int argc, char** argv); diff --git a/include/basedata.h b/include/basedata.h index 88fb9cf..3db88a2 100644 --- a/include/basedata.h +++ b/include/basedata.h @@ -1,25 +1,45 @@ #pragma once #include "comdefs.h" +#include using michlib::real; +class BaseParameters +{ + public: + virtual ~BaseParameters(); +}; + class BaseData { protected: static constexpr real fillval = 1.0e10; std::vector data; + std::vector lons, lats; - BaseData() = default; + BaseData(size_t n): data(n), lons(n), lats(n) {} - BaseData(size_t n): data(n) {} + template BaseData(size_t n, Lon genlon, Lat genlat): data(n), lons(n), lats(n) + { + for(size_t i = 0; i < n; i++) + { + lons[i] = genlon(i); + lats[i] = genlat(i); + } + }; public: + BaseData() = default; + const real& V(size_t i) const { return data[i]; } real& V(size_t i) { return data[i]; } const real& operator()(size_t i) const { return data[i]; } real& operator()(size_t i) { return data[i]; } + real Lon(size_t i) const { return lons[i]; } + real Lat(size_t i) const { return lats[i]; } + size_t N() const { return data.size(); } static real Fillval() { return fillval; } diff --git a/include/odm.h b/include/odm.h index b047654..79e7b98 100644 --- a/include/odm.h +++ b/include/odm.h @@ -1,29 +1,121 @@ #pragma once #include "BFileW.h" -#include "GPL.h" #include "NEMO.h" -#include "tindexes.h" +#include +#include using michlib::BFileW; using michlib::errmessage; using michlib::GPL; using michlib::message; -using michlib::SList; using DataVariants = std::variant; -using CLArgs = std::map; + +template +concept InfoSupported = requires(T t) { + { + t.template Info() + } -> std::convertible_to; +}; + +template +concept ParametersSupported = requires(T t, michlib_internal::ParameterListEx& pars, const CLArgs& args) { + { + t.template Parameters(pars, args).first + } -> std::convertible_to; +}; + +template +concept ReadPSupported = requires(T t, const BaseParameters* ip, size_t i) { + { + t.template Read(ip, i)(0) + } -> std::convertible_to; +}; +template +concept ReadSupported = requires(T t, size_t i) { + { + t.template Read(i)(0) + } -> std::convertible_to; +}; + +template +concept ActionTscSupported = requires(T t, michlib_internal::ParameterListEx& pars, const CLArgs& args, const BaseParameters* ip, size_t i) { + { + t.template Parameters(pars, args).first + } -> std::convertible_to; + { + t.template Read(ip, i)(0) + } -> std::convertible_to; +}; class Data: public DataVariants { - template static bool WriteData(BFileW& fw, const D& data) + public: + using TIndex = std::vector; + + private: + TIndex GetTIndexes(const MDateTime& b, const MDateTime& e) const { - for(size_t i = 0; i < data.N(); i++) + TIndex out; + auto nt = NTimes(); + const MDateTime& beg = (b < e) ? b : e; + const MDateTime& end = (b > e) ? b : e; + + if(beg > Time(nt - 1) || end < Time(0)) return out; + + size_t ib = 0, ie = nt - 1; + for(size_t i = 0; i < nt; i++) + if(Time(i) >= beg) + { + ib = i; + break; + } + + for(size_t i = nt; i != 0; i--) + if(Time(i - 1) <= end) + { + ie = i - 1; + break; + } + + out.resize(ie - ib + 1); + for(size_t i = 0; i < ie - ib + 1; i++) out[i] = i + ib; + return out; + } + + TIndex GetTIndexes(const MString& regex) + { + { + MDateTime time; + if(time.FromString(regex)) return TIndex(1, GetTIndex(time)); // Time, not regex + if(regex == "BEGIN" || regex == "BEG" || regex == "FIRST") return TIndex(1, 0); // First time + if(regex == "END" || regex == "LAST") return TIndex(1, NTimes() - 1); // Last time + } + + TIndex out; + + std::unique_ptr regbuf(new regex_t); + if(0 != regcomp(regbuf.get(), regex.Buf(), REG_EXTENDED | REG_NOSUB)) return out; + + for(size_t i = 0; i < NTimes(); i++) { - fw.Write(data.Lon(i)); - fw.Write(data.Lat(i)); - fw.Write(data(i) == data.Fillval() ? NAN : data(i)); + MString date = Time(i).ToString(); + if(0 != regexec(regbuf.get(), date.Buf(), 0, 0, 0)) continue; + out.push_back(i); } - return true; + + return out; + } + + size_t GetTIndex(const MDateTime& t) + { + size_t nt = NTimes(); + + if(t <= Time(0)) return 0; + if(t >= Time(nt - 1)) return nt - 1; + for(size_t i = 0; i < nt - 1; i++) + if(t >= Time(i) && t <= Time(i + 1)) return (t - Time(i) <= Time(i + 1) - t) ? i : (i + 1); + return 0; } public: @@ -31,59 +123,31 @@ class Data: public DataVariants Data(DataVariants&& d): DataVariants(std::move(d)) {} - auto Time(size_t it) const + MDateTime Time(size_t it) const { - return std::visit( - [it = it](const auto& arg) -> auto{ return arg.Time(it); }, *this); + return std::visit([it = it](const auto& arg) -> auto { return arg.Time(it); }, *this); } - auto NTimes() const + size_t NTimes() const { - return std::visit( - [](const auto& arg) -> auto{ return arg.NTimes(); }, *this); - } - auto Info() const - { - return std::visit( - [](const auto& arg) -> auto{ return arg.Info(); }, *this); + return std::visit([](const auto& arg) -> auto { return arg.NTimes(); }, *this); } - bool Write(BFileW& fw, VarType vt, const std::vector& tindexes) const + MString Init(const CLArgs& args) { - return std::visit( - [&fw = fw, vt = vt, &ti = tindexes](const auto& d) -> bool - { - using T = std::decay_t; - - return std::visit( - [&fw = fw, &ti = ti, &d = d](auto v) -> bool - { - constexpr auto cvt = decltype(v)::vt; - if constexpr(isDataSupported) - return WriteData(fw, d.template Read(ti)); - else - return false; - }, - vt); - }, - *this); + MString src = args.contains("source") ? args.at("source") : ""; + if(!src.Exist()) return "No source specified"; + if(src == "NEMO") + { + NEMOData data; + auto res = data.Open(args); + if(res.Exist()) return "Can't open source " + src + ":\n" + res; + *this = Data(std::move(data)); + } + else + return "Unknown source: " + src; + return ""; } -}; - -CLArgs ParseArgs(int argc, char** argv); -int actioninfo(const CLArgs& args); -int actiontsc(const CLArgs& args); - -inline NEMOData NEMOOpen(const CLArgs& args) -{ - NEMOData ndata; - - MString oldprefix = GPL.UsePrefix("AVISO"); - MString dataset = args.contains("dataset") ? args.at("dataset") : "DT"; - MString cred = GPL.ParameterSValue("COPERNICUS_USER", ""); - MString proxy = GPL.ParameterSValue("COPERNICUS_PROXY", ""); - - GPL.UsePrefix(oldprefix); - ndata.Open(dataset, cred, proxy); - return ndata; -} + MString ActionInfo(const CLArgs& args); + MString ActionTsc(const CLArgs& args); +}; diff --git a/include/simple2ddata.h b/include/simple2ddata.h index 2c17c82..32471bd 100644 --- a/include/simple2ddata.h +++ b/include/simple2ddata.h @@ -10,7 +10,18 @@ class Simple2DData: public BaseData public: Simple2DData() = default; - Simple2DData(size_t nx_, size_t ny_, real x0_, real y0_, real xs_, real ys_): BaseData(nx_ * ny_), x0(x0_), y0(y0_), nx(nx_), ny(ny_), xstep(xs_), ystep(ys_) {} + Simple2DData(size_t nx_, size_t ny_, real x0_, real y0_, real xs_, real ys_): + BaseData( + nx_ * ny_, [x0 = x0_, nx = nx_, xstep = xs_](size_t i) -> real { return x0 + (i % nx) * xstep; }, + [y0 = y0_, nx = nx_, ystep = ys_](size_t i) -> real { return y0 + (i / nx) * ystep; }), + x0(x0_), + y0(y0_), + nx(nx_), + ny(ny_), + xstep(xs_), + ystep(ys_) + { + } const real& V(size_t i) const { return BaseData::V(i); } real& V(size_t i) { return BaseData::V(i); } diff --git a/include/tindexes.h b/include/tindexes.h deleted file mode 100644 index 594f378..0000000 --- a/include/tindexes.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once -#include "mdatetime.h" -#include -#include - -using michlib::MDateTime; - -template std::vector GetTIndexes(const T& adapter, const MDateTime& b, const MDateTime& e) -{ - std::vector out; - auto nt = adapter.NTimes(); - const MDateTime& beg = (b < e) ? b : e; - const MDateTime& end = (b > e) ? b : e; - - if(beg > adapter.Time(nt - 1) || end < adapter.Time(0)) return out; - - size_t ib = 0, ie = nt - 1; - for(size_t i = 0; i < nt; i++) - if(adapter.Time(i) >= beg) - { - ib = i; - break; - } - - for(size_t i = nt; i != 0; i--) - if(adapter.Time(i - 1) <= end) - { - ie = i - 1; - break; - } - - out.resize(ie - ib + 1); - for(size_t i = 0; i < ie - ib + 1; i++) out[i] = i + ib; - return out; -} - -template std::vector GetTIndexes(const T& adapter, const MString& regex) -{ - std::vector out; - - std::unique_ptr regbuf(new regex_t); - if(0 != regcomp(regbuf.get(), regex.Buf(), REG_EXTENDED | REG_NOSUB)) return out; - - for(size_t i = 0; i < adapter.NTimes(); i++) - { - MString date = adapter.Time(i).ToString(); - if(0 != regexec(regbuf.get(), date.Buf(), 0, 0, 0)) continue; - out.push_back(i); - } - - return out; -} - -template size_t GetTIndex(const T& adapter, const MDateTime& t) -{ - size_t nt = adapter.NTimes(); - - if(t <= adapter.Time(0)) return 0; - if(t >= adapter.Time(nt - 1)) return nt - 1; - for(size_t i = 0; i < nt - 1; i++) - if(t >= adapter.Time(i) && t <= adapter.Time(i + 1)) return (t - adapter.Time(i) <= adapter.Time(i + 1) - t) ? i : (i + 1); - return 0; -} diff --git a/include/vartype.h b/include/vartype.h deleted file mode 100644 index 3634819..0000000 --- a/include/vartype.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once -#include "MString.h" -#include - -using michlib::MString; - -namespace vartype -{ -enum class Vartype -{ - NONE, - U, - V, - TEMP, - SAL, - CHL, - MLD, - SSH, - W -}; - -template struct VartypeCarrier -{ - static const Vartype vt = vt_; -}; - -using VartypeUnion = - std::variant, VartypeCarrier, VartypeCarrier, VartypeCarrier, VartypeCarrier, - VartypeCarrier, VartypeCarrier, VartypeCarrier, VartypeCarrier>; - -template -concept HasVar = requires(T t) { - { - t.template Read(0)(0, 0) - } -> std::convertible_to; - { - t.template Read(std::vector())(0, 0) - } -> std::convertible_to; - }; -} // namespace vartype - -template static constexpr bool isDataSupported = vartype::HasVar; - -class VarType: public vartype::VartypeUnion -{ - auto VT() const - { - return std::visit( - [](auto v) -> auto{ return decltype(v)::vt; }, *this); - } - - public: - template VarType(vartype::VartypeCarrier&& vc): vartype::VartypeUnion(std::move(vc)) {} - - VarType(MString str) - { - str.ToLower(); - if(str == "u") *this = vartype::VartypeCarrier(); - if(str == "v") *this = vartype::VartypeCarrier(); - if(str == "t" || str == "temp" || str == "temperature") *this = vartype::VartypeCarrier(); - if(str == "s" || str == "sal" || str == "salinity") *this = vartype::VartypeCarrier(); - if(str == "c" || str == "chl" || str == "chlorophyll") *this = vartype::VartypeCarrier(); - if(str == "mld") *this = vartype::VartypeCarrier(); - if(str == "ssh") *this = vartype::VartypeCarrier(); - if(str == "w") *this = vartype::VartypeCarrier(); - } - - MString Name() const - { - switch(VT()) - { - case(vartype::Vartype::NONE): return "none"; - case(vartype::Vartype::U): return "U"; - case(vartype::Vartype::V): return "V"; - case(vartype::Vartype::TEMP): return "Temperature"; - case(vartype::Vartype::SAL): return "Salinity"; - case(vartype::Vartype::CHL): return "Chlorophyll"; - case(vartype::Vartype::MLD): return "Mixed layer depth"; - case(vartype::Vartype::SSH): return "Sea surface height"; - case(vartype::Vartype::W): return "W"; - } - return "none"; - } - - MString ShortName() const - { - switch(VT()) - { - case(vartype::Vartype::NONE): return "none"; - case(vartype::Vartype::U): return "u"; - case(vartype::Vartype::V): return "v"; - case(vartype::Vartype::TEMP): return "temp"; - case(vartype::Vartype::SAL): return "sal"; - case(vartype::Vartype::CHL): return "chl"; - case(vartype::Vartype::MLD): return "mld"; - case(vartype::Vartype::SSH): return "ssh"; - case(vartype::Vartype::W): return "w"; - } - return "none"; - } - - bool Ok() const { return VT() != vartype::Vartype::NONE; } - explicit operator bool() const { return Ok(); } - bool operator==(const VarType& vt) const { return VT() == vt.VT(); } - auto operator<=>(const VarType& vt) const { return VT() <=> vt.VT(); } - template bool isSupported() const - { - return std::visit( - [](const auto v) -> bool - { - if constexpr(isDataSupported) - return true; - else - return false; - }, - *this); - } -}; diff --git a/src/ParseArgs.cpp b/src/ParseArgs.cpp index d682223..517fc86 100644 --- a/src/ParseArgs.cpp +++ b/src/ParseArgs.cpp @@ -1,6 +1,7 @@ #define MICHLIB_NOSOURCE -#include "GPL.h" -#include "odm.h" +#include "ParseArgs.h" + +using michlib::SList; CLArgs ParseArgs(int argc, char** argv) { diff --git a/src/actioninfo.cpp b/src/actioninfo.cpp index f121fde..496318c 100644 --- a/src/actioninfo.cpp +++ b/src/actioninfo.cpp @@ -1,36 +1,19 @@ #define MICHLIB_NOSOURCE -#include "GPL.h" #include "odm.h" -int actioninfo(const CLArgs& args) +MString Data::ActionInfo(const CLArgs& args) { - if(!args.contains("source")) - { - errmessage("No source specified!"); - return 1; - } - - Data data; - - if(args.at("source") == "NEMO") - { - NEMOData ndata = NEMOOpen(args); - - if(!ndata) - { - errmessage("Can't open NEMO dataset"); - return 1; - } - - data = DataVariants(std::move(ndata)); - } - else - { - errmessage("Unknown source " + args.at("source")); - return 1; - } - - message(data.Info()); - - return 0; + MString info = std::visit( + [](const auto& arg) -> auto + { + using T = std::decay_t; + if constexpr(InfoSupported) + return arg.Info(); + else + return MString(); + }, + *this); + if(!info.Exist()) return "Unsupported combination of action and source"; + message(info); + return ""; } diff --git a/src/actiontsc.cpp b/src/actiontsc.cpp index 40bd79e..f4b408a 100644 --- a/src/actiontsc.cpp +++ b/src/actiontsc.cpp @@ -2,132 +2,97 @@ #include "GPL.h" #include "odm.h" -int actiontsc(const CLArgs& args) +MString Data::ActionTsc(const CLArgs& args) { - if(!args.contains("source")) - { - errmessage("No source specified!"); - return 1; - } - - VarType vtype(args.at("var")); - if(!vtype) - { - errmessage("Incorrect or no variable specified"); - return 1; - } + if(args.contains("time") && (args.contains("timeb") || args.contains("timee"))) return "Time must be set via time parameter or timeb and timee parameter but not via both"; + if(!(args.contains("time") || (args.contains("timeb") && args.contains("timee")))) return "Time must be set via time parameter or timeb and timee parameter"; michlib_internal::ParameterListEx pars; pars.UsePrefix(""); pars.SetParameter("source", args.at("source")); - pars.SetParameter("variable", vtype.Name()); + TIndex tindexes; - Data data; - - if(args.at("source") == "NEMO") + if(args.contains("time")) { - if(!vtype.isSupported()) - { - errmessage("Variable " + args.at("var") + " is unsupported by NEMO"); - return 1; - } - - NEMOData ndata = NEMOOpen(args); - if(!ndata) - { - errmessage("Can't open NEMO dataset"); - return 1; - } - - size_t layer = 0; - if(args.contains("layer")) layer = args.at("layer").ToInteger(); - if(!args.contains("depth") && layer >= ndata.NDepths()) - { - errmessage(MString("Layer ") + layer + " is too deep!"); - return 1; - } - real depth = args.contains("depth") ? args.at("depth").ToReal() : ndata.Depth(layer); - - if(!(args.contains("lonb") && args.contains("lone") && args.contains("latb") && args.contains("late"))) - { - errmessage("Region not specified (lonb, lone, latb, late)"); - return 1; - } - if(!ndata.SetRegion(args.at("lonb").ToReal(), args.at("lone").ToReal(), args.at("latb").ToReal(), args.at("late").ToReal(), depth)) - { - errmessage("Can't set region"); - return 1; - } - - pars.SetParameter("depth", depth); - pars.SetParameter("layer", ndata.Layer()); - pars.SetParameter("dataset", ndata.Title()); - pars.SetParameter("lonb", args.at("lonb").ToReal()); - pars.SetParameter("latb", args.at("latb").ToReal()); - pars.SetParameter("lone", args.at("lone").ToReal()); - pars.SetParameter("late", args.at("late").ToReal()); - - data = DataVariants(std::move(ndata)); + tindexes = GetTIndexes(args.at("time")); // Regular expression or single date + if(tindexes.size() == 0) return "There are no times matching the regular expression"; + if(tindexes.size() == 1) + pars.SetParameter("time", Time(tindexes[0]).ToString()); + else + pars.SetParameter("timeregex", args.at("time")); } else { - errmessage("Unknown source " + args.at("source")); - return 1; + MDateTime tb(args.at("timeb")), te(args.at("timee")); + tindexes = GetTIndexes(tb, te); + if(tindexes.size() == 0) return "There are no times between " + tb.ToString() + " and " + te.ToString(); + pars.SetParameter("timeb", tb.ToString()); + pars.SetParameter("timee", te.ToString()); } - if(args.contains("time") && (args.contains("timeb") || args.contains("timee"))) + std::unique_ptr sourcepars; { - errmessage("Time must be set via time parameter or timeb and timee parameter but not via both"); - return 1; + std::pair ppar = std::visit( + [&pars = pars, &args = args](const auto& arg) -> std::pair + { + using T = std::decay_t; + if constexpr(ParametersSupported) + return arg.Parameters(pars, args); + else + return {nullptr, ""}; + }, + *this); + if(ppar.second.Exist()) return ppar.second; + sourcepars.reset(ppar.first); } - if(!(args.contains("time") || (args.contains("timeb") && args.contains("timee")))) + auto p = sourcepars.get(); + size_t ind; + auto read = [p = p, &ind = ind](const auto& arg) -> BaseData + { + using T = std::decay_t; + if constexpr(ParametersSupported && ReadPSupported) + return arg.Read(p, ind); + else if constexpr(!ParametersSupported && ReadSupported) + return arg.Read(ind); + else + return BaseData(); + }; + + BaseData data; + if(tindexes.size() == 1) + data = std::visit(read, *this); + else { - errmessage("Time must be set via time parameter or timeb and timee parameter"); - return 1; + Averager out; + bool ok = true; + for(size_t i = 0; i < tindexes.size(); i++) + { + if(!ok) break; + ind = tindexes[i]; + auto dat = std::visit(read, *this); + if(dat) + out.Add(dat); + else + ok = false; + } + if(ok) data = out.Div(); } + if(!data) return "Can't read data"; BFileW fw; MString name = args.contains("out") ? args.at("out") : ""; if(!name.Exist()) name = "out.bin"; fw.Create(name, 3); - /* - if(!fw.Create(name,3)) - { - errmessage("Can't create file "+name); - return 1; - } - */ fw.SetParameters(pars); - fw.UsePrefix(""); - - if(args.contains("time")) + for(size_t i = 0; i < data.N(); i++) { - MDateTime time; - if(time.FromString(args.at("time"))) // One date - { - auto it = GetTIndex(data, time); - fw.SetParameter("time", data.Time(it).ToString()); - data.Write(fw, vtype, std::vector(1, it)); - } - else // Regular expression - { - fw.SetParameter("timeregex", args.at("time")); - data.Write(fw, vtype, GetTIndexes(data, args.at("time"))); - } + fw.Write(data.Lon(i)); + fw.Write(data.Lat(i)); + fw.Write(data(i) == data.Fillval() ? NAN : data(i)); } - else // Bdate, edate - { - MDateTime tb(args.at("timeb")), te(args.at("timee")); - fw.SetParameter("timeb", tb.ToString()); - fw.SetParameter("timee", te.ToString()); - data.Write(fw, vtype, GetTIndexes(data, tb, te)); - } - - fw.Finalize(); - fw.Close(); - return 0; + return ""; } diff --git a/src/basedata.cpp b/src/basedata.cpp new file mode 100644 index 0000000..43a5ddc --- /dev/null +++ b/src/basedata.cpp @@ -0,0 +1,3 @@ +#include "basedata.h" + +BaseParameters::~BaseParameters() {} diff --git a/src/odm.cpp b/src/odm.cpp index cba317f..bd92c7c 100644 --- a/src/odm.cpp +++ b/src/odm.cpp @@ -33,16 +33,31 @@ int main(int argc, char** argv) MString action = args.contains("action") ? args["action"] : "tsc"; - int ret = 1; + Data data; + { + auto ret = data.Init(args); + if(ret.Exist()) + { + errmessage(ret); + return 1; + } + } + + MString ret; if(action == "info") - ret = actioninfo(args); + ret = data.ActionInfo(args); else if(action == "tsc") - ret = actiontsc(args); + ret = data.ActionTsc(args); else { errmessage("Unknown action " + action); return 1; } + if(ret.Exist()) + { + errmessage(ret); + return 1; + } - return ret; + return 0; }