diff --git a/actions/actiongenintfile.h b/actions/actiongenintfile.h index 5ccd9a1..7b04a21 100644 --- a/actions/actiongenintfile.h +++ b/actions/actiongenintfile.h @@ -11,6 +11,9 @@ ADD_ACTION(GenIntFile, genintfile, ReadIsGrid); template MString ActionGenIntFile::DoAction(const CLArgs& args, D& ds) { + auto [reg, regerr] = GetRegion(args); + if(regerr.Exist()) return regerr; + auto resop = ds.Open(args); if(resop.Exist()) return "Can't open source: " + resop; @@ -30,9 +33,18 @@ template MString ActionGenIntFile::DoAction(const CLArgs& args, D& ds) std::unique_ptr sourcepars; if constexpr(ParametersSupported) { - auto [p, err] = ds.Parameters(pars, args); - if(err.Exist()) return err; - sourcepars.reset(p); + if constexpr(ParametersRequiredRegion) + { + auto [p, err] = ds.Parameters(pars, args, reg); + if(err.Exist()) return err; + sourcepars.reset(p); + } + else + { + auto [p, err] = ds.Parameters(pars, args); + if(err.Exist()) return err; + sourcepars.reset(p); + } } auto p = sourcepars.get(); diff --git a/actions/actiontsc.h b/actions/actiontsc.h index 6e45c8b..1bf97f3 100644 --- a/actions/actiontsc.h +++ b/actions/actiontsc.h @@ -9,6 +9,9 @@ ADD_ACTION(TSC, tsc, ReadPSupported || ReadSupported); template MString ActionTSC::DoAction(const CLArgs& args, D& ds) { + auto [reg, regerr] = GetRegion(args); + if(regerr.Exist()) return regerr; + auto resop = ds.Open(args); if(resop.Exist()) return "Can't open source: " + resop; @@ -27,9 +30,18 @@ template MString ActionTSC::DoAction(const CLArgs& args, D& ds) std::unique_ptr sourcepars; if constexpr(ParametersSupported) { - auto [p, err] = ds.Parameters(pars, args); - if(err.Exist()) return err; - sourcepars.reset(p); + if constexpr(ParametersRequiredRegion) + { + auto [p, err] = ds.Parameters(pars, args, reg); + if(err.Exist()) return err; + sourcepars.reset(p); + } + else + { + auto [p, err] = ds.Parameters(pars, args); + if(err.Exist()) return err; + sourcepars.reset(p); + } } auto p = sourcepars.get(); diff --git a/actions/actionuv.h b/actions/actionuv.h index 883a6ff..da64ebf 100644 --- a/actions/actionuv.h +++ b/actions/actionuv.h @@ -9,6 +9,9 @@ ADD_ACTION(UV, uv, ReadPSupported || ReadSupported); template MString ActionUV::DoAction(const CLArgs& args, D& ds) { + auto [reg, regerr] = GetRegion(args); + if(regerr.Exist()) return regerr; + auto resop = ds.Open(args); if(resop.Exist()) return "Can't open source: " + resop; @@ -22,9 +25,18 @@ template MString ActionUV::DoAction(const CLArgs& args, D& ds) std::unique_ptr sourcepars; if constexpr(ParametersSupported) { - auto [p, err] = ds.Parameters(pars, args); - if(err.Exist()) return err; - sourcepars.reset(p); + if constexpr(ParametersRequiredRegion) + { + auto [p, err] = ds.Parameters(pars, args, reg); + if(err.Exist()) return err; + sourcepars.reset(p); + } + else + { + auto [p, err] = ds.Parameters(pars, args); + if(err.Exist()) return err; + sourcepars.reset(p); + } } auto p = sourcepars.get(); diff --git a/include/actiondep.h b/include/actiondep.h index 7caf65b..4f2a8cc 100644 --- a/include/actiondep.h +++ b/include/actiondep.h @@ -1,6 +1,12 @@ #pragma once #include "ParseArgs.h" +#include "basedata.h" +#include "mdatetime.h" +#include "mregex.h" #include "traits.h" +#include "uvdata.h" + +using michlib::MDateTime; #if defined GENACTIONLIST #define ADD_ACTION(actclass, actname, suptest) ADD ACTION CLASS: actclass @@ -14,3 +20,197 @@ template static MString DoAction(const CLArgs& args, Source& data); \ }; #endif + +template size_t GetTIndex(const D& data, const MDateTime& t) +{ + size_t nt = data.NTimes(); + + if(t <= data.Time(0)) return 0; + if(t >= data.Time(nt - 1)) return nt - 1; + for(size_t i = 0; i < nt - 1; i++) + if(t >= data.Time(i) && t <= data.Time(i + 1)) return (t - data.Time(i) <= data.Time(i + 1) - t) ? i : (i + 1); + return 0; +} + +template std::pair GetTIndexes(const D& data, const CLArgs& args, michlib_internal::ParameterListEx& pars) +{ + TIndex tindexes; + + if(args.contains("time") && (args.contains("timeb") || args.contains("timee"))) + return {tindexes, "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 {tindexes, "Time must be set via time parameter or timeb and timee parameter"}; + + if(args.contains("time")) + { + MString regex = args.at("time"); + MDateTime time; + + if(time.FromString(regex)) return {TIndex(1, GetTIndex(data, 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, data.NTimes() - 1), ""}; // Last time + + michlib::RegExpSimple reg(regex.Buf()); + if(reg.Compile() != 0) return {tindexes, "Bad regular expression: " + regex}; + + for(size_t i = 0; i < data.NTimes(); i++) + { + MString date = data.Time(i).ToString(); + if(reg.Match(date.Buf())) tindexes.push_back(i); + } + if(tindexes.size() == 0) return {tindexes, "There are no times matching the regular expression: " + regex}; + if(tindexes.size() == 1) + pars.SetParameter("time", data.Time(tindexes[0]).ToString()); + else + pars.SetParameter("timeregex", args.at("time")); + } + else + { + MString tb = args.at("timeb"); + MString te = args.at("timee"); + MDateTime b(tb), e(te); + + auto nt = data.NTimes(); + if(tb == "BEGIN" || tb == "BEG") b = data.Time(0); + if(te == "LAST" || te == "END") e = data.Time(nt - 1); + + const MDateTime& beg = (b < e) ? b : e; + const MDateTime& end = (b > e) ? b : e; + + if(beg > data.Time(nt - 1)) return {tindexes, "Begin time " + b.ToTString() + " is greater then end time in the dataset " + data.Time(nt - 1).ToTString()}; + if(end < data.Time(0)) return {tindexes, "End time " + e.ToTString() + " is lesser then begin time in the dataset " + data.Time(0).ToTString()}; + + size_t ib = 0, ie = nt - 1; + for(size_t i = 0; i < nt; i++) + if(data.Time(i) >= beg) + { + ib = i; + break; + } + + for(size_t i = nt; i != 0; i--) + if(data.Time(i - 1) <= end) + { + ie = i - 1; + break; + } + + tindexes.resize(ie - ib + 1); + for(size_t i = 0; i < ie - ib + 1; i++) tindexes[i] = i + ib; + + if(tindexes.size() == 0) return {tindexes, "There are no times between " + b.ToString() + " and " + e.ToString()}; + pars.SetParameter("timeb", b.ToString()); + pars.SetParameter("timee", e.ToString()); + } + + return {tindexes, ""}; +} + +template ReadType Read(const D& data, const MString& vname, const BaseParameters* p, const TIndex& tindex) +{ + using RT = ReadType; + size_t ind; + if(tindex.size() == 1) + { + ind = tindex[0]; + michlib::message("Time: " + data.Time(ind).ToTString()); + if constexpr(ReadPSupported) + return data.Read(vname, p, ind); + else if constexpr(ReadSupported) + return data.Read(vname, ind); + } + else + { + Averager out; + bool ok = true; + for(size_t i = 0; i < tindex.size(); i++) + { + if(!ok) break; + ind = tindex[i]; + michlib::message("Time: " + data.Time(ind).ToTString()); + RT dat; + if constexpr(ReadPSupported) + dat = data.Read(vname, p, ind); + else if constexpr(ReadSupported) + dat = data.Read(vname, ind); + if(dat) + out.Add(dat); + else + ok = false; + } + if(ok) return out.Div(); + } + return RT(); +} + +template UVData> ReadUV(const D& data, const BaseParameters* p, size_t ind) +{ + using RT = ReadType; + using UV = UVData; + michlib::message("Time: " + data.Time(ind).ToTString()); + RT u, v; + if constexpr(ReadPSupported) + { + u = data.Read("u", p, ind); + v = data.Read("v", p, ind); + } + else if constexpr(ReadSupported) + { + u = data.Read("u", ind); + v = data.Read("v", ind); + } + return UV(u, v); +} + +template UVData> ReadUV(const D& data, const BaseParameters* p, const TIndex& tindex) +{ + using RT = ReadType; + using UV = UVData; + + if(tindex.size() == 1) + return ReadUV(data, p, tindex[0]); + else + { + Averager out; + bool ok = true; + size_t ind; + for(size_t i = 0; i < tindex.size(); i++) + { + if(!ok) break; + ind = tindex[i]; + michlib::message("Time: " + data.Time(ind).ToTString()); + RT u, v; + if constexpr(ReadPSupported) + { + u = data.Read("u", p, ind); + v = data.Read("v", p, ind); + } + else if constexpr(ReadSupported) + { + u = data.Read("u", ind); + v = data.Read("v", ind); + } + UV dat(u, v); + if(dat) + out.Add(dat); + else + ok = false; + } + if(ok) return out.Div(); + } + return UV(); +} + +template std::pair GetRegion(const CLArgs& args) +{ + struct Region reg; + if constexpr(!ParametersRequiredRegion) return {reg, ""}; + if(!(args.contains("lonb") && args.contains("lone") && args.contains("latb") && args.contains("late"))) return {reg, "Region not specified (lonb, lone, latb, late)"}; + reg.lonb = args.at("lonb").ToReal(); + reg.lone = args.at("lone").ToReal(); + real latb = args.at("latb").ToReal(); + real late = args.at("late").ToReal(); + reg.latb = std::min(latb, late); + reg.late = std::max(latb, late); + + return {reg, ""}; +} diff --git a/include/actions.h b/include/actions.h index be59a80..9653596 100644 --- a/include/actions.h +++ b/include/actions.h @@ -1,13 +1,7 @@ #pragma once #include "actionlist.h" -#include "basedata.h" -#include "mdatetime.h" -#include "mregex.h" -#include "uvdata.h" #include "varhelpers.h" -using michlib::MDateTime; - using ActionVariants = std::variant; class Action: public ActionVariants @@ -23,182 +17,3 @@ class Action: public ActionVariants return ""; } }; - -template size_t GetTIndex(const D& data, const MDateTime& t) -{ - size_t nt = data.NTimes(); - - if(t <= data.Time(0)) return 0; - if(t >= data.Time(nt - 1)) return nt - 1; - for(size_t i = 0; i < nt - 1; i++) - if(t >= data.Time(i) && t <= data.Time(i + 1)) return (t - data.Time(i) <= data.Time(i + 1) - t) ? i : (i + 1); - return 0; -} - -template std::pair GetTIndexes(const D& data, const CLArgs& args, michlib_internal::ParameterListEx& pars) -{ - TIndex tindexes; - - if(args.contains("time") && (args.contains("timeb") || args.contains("timee"))) - return {tindexes, "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 {tindexes, "Time must be set via time parameter or timeb and timee parameter"}; - - if(args.contains("time")) - { - MString regex = args.at("time"); - MDateTime time; - - if(time.FromString(regex)) return {TIndex(1, GetTIndex(data, 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, data.NTimes() - 1), ""}; // Last time - - michlib::RegExpSimple reg(regex.Buf()); - if(reg.Compile() != 0) return {tindexes, "Bad regular expression: " + regex}; - - for(size_t i = 0; i < data.NTimes(); i++) - { - MString date = data.Time(i).ToString(); - if(reg.Match(date.Buf())) tindexes.push_back(i); - } - if(tindexes.size() == 0) return {tindexes, "There are no times matching the regular expression: " + regex}; - if(tindexes.size() == 1) - pars.SetParameter("time", data.Time(tindexes[0]).ToString()); - else - pars.SetParameter("timeregex", args.at("time")); - } - else - { - MString tb = args.at("timeb"); - MString te = args.at("timee"); - MDateTime b(tb), e(te); - - auto nt = data.NTimes(); - if(tb == "BEGIN" || tb == "BEG") b = data.Time(0); - if(te == "LAST" || te == "END") e = data.Time(nt - 1); - - const MDateTime& beg = (b < e) ? b : e; - const MDateTime& end = (b > e) ? b : e; - - if(beg > data.Time(nt - 1)) return {tindexes, "Begin time " + b.ToTString() + " is greater then end time in the dataset " + data.Time(nt - 1).ToTString()}; - if(end < data.Time(0)) return {tindexes, "End time " + e.ToTString() + " is lesser then begin time in the dataset " + data.Time(0).ToTString()}; - - size_t ib = 0, ie = nt - 1; - for(size_t i = 0; i < nt; i++) - if(data.Time(i) >= beg) - { - ib = i; - break; - } - - for(size_t i = nt; i != 0; i--) - if(data.Time(i - 1) <= end) - { - ie = i - 1; - break; - } - - tindexes.resize(ie - ib + 1); - for(size_t i = 0; i < ie - ib + 1; i++) tindexes[i] = i + ib; - - if(tindexes.size() == 0) return {tindexes, "There are no times between " + b.ToString() + " and " + e.ToString()}; - pars.SetParameter("timeb", b.ToString()); - pars.SetParameter("timee", e.ToString()); - } - - return {tindexes, ""}; -} - -template ReadType Read(const D& data, const MString& vname, const BaseParameters* p, const TIndex& tindex) -{ - using RT = ReadType; - size_t ind; - if(tindex.size() == 1) - { - ind = tindex[0]; - michlib::message("Time: " + data.Time(ind).ToTString()); - if constexpr(ReadPSupported) - return data.Read(vname, p, ind); - else if constexpr(ReadSupported) - return data.Read(vname, ind); - } - else - { - Averager out; - bool ok = true; - for(size_t i = 0; i < tindex.size(); i++) - { - if(!ok) break; - ind = tindex[i]; - michlib::message("Time: " + data.Time(ind).ToTString()); - RT dat; - if constexpr(ReadPSupported) - dat = data.Read(vname, p, ind); - else if constexpr(ReadSupported) - dat = data.Read(vname, ind); - if(dat) - out.Add(dat); - else - ok = false; - } - if(ok) return out.Div(); - } - return RT(); -} - -template UVData> ReadUV(const D& data, const BaseParameters* p, size_t ind) -{ - using RT = ReadType; - using UV = UVData; - michlib::message("Time: " + data.Time(ind).ToTString()); - RT u, v; - if constexpr(ReadPSupported) - { - u = data.Read("u", p, ind); - v = data.Read("v", p, ind); - } - else if constexpr(ReadSupported) - { - u = data.Read("u", ind); - v = data.Read("v", ind); - } - return UV(u, v); -} - -template UVData> ReadUV(const D& data, const BaseParameters* p, const TIndex& tindex) -{ - using RT = ReadType; - using UV = UVData; - - if(tindex.size() == 1) - return ReadUV(data, p, tindex[0]); - else - { - Averager out; - bool ok = true; - size_t ind; - for(size_t i = 0; i < tindex.size(); i++) - { - if(!ok) break; - ind = tindex[i]; - michlib::message("Time: " + data.Time(ind).ToTString()); - RT u, v; - if constexpr(ReadPSupported) - { - u = data.Read("u", p, ind); - v = data.Read("v", p, ind); - } - else if constexpr(ReadSupported) - { - u = data.Read("u", ind); - v = data.Read("v", ind); - } - UV dat(u, v); - if(dat) - out.Add(dat); - else - ok = false; - } - if(ok) return out.Div(); - } - return UV(); -} diff --git a/include/basedata.h b/include/basedata.h index c78c574..f1544cf 100644 --- a/include/basedata.h +++ b/include/basedata.h @@ -10,6 +10,11 @@ class BaseParameters virtual ~BaseParameters(); }; +struct Region +{ + real lonb, lone, latb, late; +}; + class BaseData { protected: diff --git a/include/layereddata.h b/include/layereddata.h index 72e795a..c88e272 100644 --- a/include/layereddata.h +++ b/include/layereddata.h @@ -133,7 +133,7 @@ class LayeredData: public NCFuncs public: MString Info() const; - std::pair Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const; + std::pair Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const; Data Read(const MString& vname, const BaseParameters* ip, size_t i) const; diff --git a/include/traits.h b/include/traits.h index d4640aa..29271fa 100644 --- a/include/traits.h +++ b/include/traits.h @@ -13,12 +13,22 @@ concept InfoSupported = requires(T t) { }; template -concept ParametersSupported = requires(T t, michlib_internal::ParameterListEx& pars, const CLArgs& args) { +concept ParametersRequiredRegion = requires(T t, michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& r) { + { + t.Parameters(pars, args, r).first + } -> std::convertible_to; +}; + +template +concept ParametersNotRequiredRegion = requires(T t, michlib_internal::ParameterListEx& pars, const CLArgs& args) { { t.Parameters(pars, args).first } -> std::convertible_to; }; +template +concept ParametersSupported = ParametersRequiredRegion || ParametersNotRequiredRegion; + template concept ReadPSupported = requires(T t, const MString& vname, const BaseParameters* ip, size_t i) { { diff --git a/sources/AVISOLOCAL.cpp b/sources/AVISOLOCAL.cpp index 14b35dc..79e6f7c 100644 --- a/sources/AVISOLOCAL.cpp +++ b/sources/AVISOLOCAL.cpp @@ -70,14 +70,13 @@ MString AVISOLOCALData::Open(const CLArgs& args) return ""; } -std::pair AVISOLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const +std::pair AVISOLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const { std::unique_ptr ppar{new struct Parameters}; - if(!(args.contains("lonb") && args.contains("lone") && args.contains("latb") && args.contains("late"))) return {nullptr, "Region not specified (lonb, lone, latb, late)"}; - ppar->lonb = args.at("lonb").ToReal(); - ppar->lone = args.at("lone").ToReal(); - ppar->latb = args.at("latb").ToReal(); - ppar->late = args.at("late").ToReal(); + ppar->lonb = reg.lonb; + ppar->lone = reg.lone; + ppar->latb = reg.latb; + ppar->late = reg.late; pars.SetParameter("lonb", ppar->lonb); pars.SetParameter("latb", ppar->latb); diff --git a/sources/AVISOLOCAL.h b/sources/AVISOLOCAL.h index 2978b17..1365d28 100644 --- a/sources/AVISOLOCAL.h +++ b/sources/AVISOLOCAL.h @@ -37,7 +37,7 @@ class AVISOLOCALData: public NCFuncs // TODO: RetVal MString Open(const CLArgs& args); - std::pair Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const; + std::pair Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const; bool isOk() const { return times.size() > 0; } diff --git a/sources/MODISBINLOCAL.cpp b/sources/MODISBINLOCAL.cpp index bad3d64..a6e5f60 100644 --- a/sources/MODISBINLOCAL.cpp +++ b/sources/MODISBINLOCAL.cpp @@ -66,14 +66,14 @@ MString MODISBINLOCALData::Open(const CLArgs& args) return ""; } -std::pair MODISBINLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const +std::pair MODISBINLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const { std::unique_ptr ppar{new struct Parameters}; - if(!(args.contains("lonb") && args.contains("lone") && args.contains("latb") && args.contains("late"))) return {nullptr, "Region not specified (lonb, lone, latb, late)"}; - ppar->lonb = args.at("lonb").ToReal(); - ppar->lone = args.at("lone").ToReal(); - ppar->latb = args.at("latb").ToReal(); - ppar->late = args.at("late").ToReal(); + + ppar->lonb = reg.lonb; + ppar->lone = reg.lone; + ppar->latb = reg.latb; + ppar->late = reg.late; pars.SetParameter("lonb", ppar->lonb); pars.SetParameter("latb", ppar->latb); diff --git a/sources/MODISBINLOCAL.h b/sources/MODISBINLOCAL.h index 88fb4f4..b6348f8 100644 --- a/sources/MODISBINLOCAL.h +++ b/sources/MODISBINLOCAL.h @@ -43,7 +43,7 @@ class MODISBINLOCALData Data Read(const MString& var, const BaseParameters* ip, size_t tind) const; Data ReadFile(const MString& suf, const struct Parameters* p, size_t tind) const; - std::pair Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const; + std::pair Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const; bool CheckVar(const MString& vname) const { diff --git a/src/layereddata.cpp b/src/layereddata.cpp index bfc646c..1ddfc28 100644 --- a/src/layereddata.cpp +++ b/src/layereddata.cpp @@ -125,7 +125,7 @@ MString LayeredData::Open(const MString& dataset) return ""; } -std::pair LayeredData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const +std::pair LayeredData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const { std::unique_ptr ppar{new struct Parameters}; @@ -133,14 +133,12 @@ std::pair LayeredData::Parameters(michlib_intern 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); - if(!(args.contains("lonb") && args.contains("lone") && args.contains("latb") && args.contains("late"))) return {nullptr, "Region not specified (lonb, lone, latb, late)"}; - { auto dom = DetGeoDomain(lonb, lone); - real lon1 = ToGeoDomain(args.at("lonb").ToReal(), dom); - real lon2 = ToGeoDomain(args.at("lone").ToReal(), dom); - real lat1 = args.at("latb").ToReal(); - real lat2 = args.at("late").ToReal(); + real lon1 = ToGeoDomain(reg.lonb, dom); + real lon2 = ToGeoDomain(reg.lone, dom); + real lat1 = reg.latb; + real lat2 = reg.late; // Special case when the longitude lies in a small sector between the end and the start if(lon1 < lonb) lon1 = lone;