From f9da82612d5be93b7e7d51decb9e69d7b7fd68ad Mon Sep 17 00:00:00 2001 From: Michael Uleysky Date: Tue, 25 Apr 2023 11:00:14 +1000 Subject: [PATCH] Rewrite abstractions --- include/AVISOLOCAL.h | 7 - include/ParseArgs.h | 1 + include/actioninfo.h | 17 ++ include/actions.h | 246 ++++++++++++++++++++++++ include/actiontsc.h | 54 ++++++ src/actionuv.cpp => include/actionuv.h | 95 +++------- include/basedata.h | 81 ++++---- include/data.h | 16 ++ include/layereddata.h | 13 -- include/ncfuncs.h | 1 - include/odm.h | 186 ++---------------- include/traits.h | 74 ++++++++ include/uvdata.h | 252 ++++++++++++++++++------- src/AVISOLOCAL.cpp | 22 --- src/ParseArgs.cpp | 2 - src/actioninfo.cpp | 19 -- src/actiontsc.cpp | 113 ----------- src/basedata.cpp | 1 + src/data.cpp | 39 ++++ src/layereddata.cpp | 22 --- src/ncfuncs.cpp | 4 +- src/odm.cpp | 39 ++-- 22 files changed, 737 insertions(+), 567 deletions(-) create mode 100644 include/actioninfo.h create mode 100644 include/actions.h create mode 100644 include/actiontsc.h rename src/actionuv.cpp => include/actionuv.h (55%) create mode 100644 include/data.h create mode 100644 include/traits.h delete mode 100644 src/actioninfo.cpp delete mode 100644 src/actiontsc.cpp create mode 100644 src/data.cpp diff --git a/include/AVISOLOCAL.h b/include/AVISOLOCAL.h index 9948aab..42c0da3 100644 --- a/include/AVISOLOCAL.h +++ b/include/AVISOLOCAL.h @@ -1,10 +1,7 @@ #pragma once -#include "GPL.h" -#include "ParseArgs.h" #include "mregex.h" #include "ncfuncs.h" #include "simple2ddata.h" -#include "uvdata.h" #include #include @@ -14,8 +11,6 @@ using michlib::Floor; using michlib::GPL; using michlib::int2; using michlib::int4; -using michlib::MString; -using michlib::real; using michlib::RegExp; class AVISOLOCALData: public NCFuncs @@ -66,6 +61,4 @@ class AVISOLOCALData: public NCFuncs Data Read(const MString& vname, const BaseParameters* ip, size_t i) const; template Data ReadVarRaw(const NCFileA& nc, const MString& name, const struct Parameters* p) const; - - UVData ReadUV(const BaseParameters* ip, size_t i) const; }; diff --git a/include/ParseArgs.h b/include/ParseArgs.h index 254bdd0..0932c88 100644 --- a/include/ParseArgs.h +++ b/include/ParseArgs.h @@ -2,6 +2,7 @@ #include "GPL.h" using michlib::MString; +using michlib::SList; using CLArgs = std::map; CLArgs ParseArgs(int argc, char** argv); diff --git a/include/actioninfo.h b/include/actioninfo.h new file mode 100644 index 0000000..7d516c1 --- /dev/null +++ b/include/actioninfo.h @@ -0,0 +1,17 @@ +#pragma once +#include "actions.h" + +using michlib::message; + +template struct DoAction_ +{ + static MString DoAction(const CLArgs& args, D& data); +}; + +template MString DoAction_::DoAction([[maybe_unused]] const CLArgs& args, D& data) +{ + auto info = data.Info(); + if(!info.Exist()) return "No info"; + message(info); + return ""; +}; diff --git a/include/actions.h b/include/actions.h new file mode 100644 index 0000000..e4e952e --- /dev/null +++ b/include/actions.h @@ -0,0 +1,246 @@ +#pragma once +#include "basedata.h" +#include "mdatetime.h" +#include "mregex.h" +#include "uvdata.h" +#include + +using michlib::BFileW; +using michlib::MDateTime; + +using TIndex = std::vector; + +enum class ActionID +{ + INFO, + TSC, + UV +}; + +template struct ActionCarrier +{ + constexpr static ActionID action = id; +}; + +template struct IsActionSupportedTest +{ + static constexpr bool ans = false; +}; + +template struct IsActionSupportedTest +{ + static constexpr bool ans = InfoSupported; +}; +template struct IsActionSupportedTest +{ + static constexpr bool ans = ReadPSupported || ReadSupported; +}; +template struct IsActionSupportedTest +{ + static constexpr bool ans = ReadPSupported || ReadSupported; +}; + +template constexpr bool IsActionSupported = IsActionSupportedTest::ans; + +using ActionVariants = std::variant, ActionCarrier, ActionCarrier>; + +class Action: public ActionVariants +{ + public: + Action() = default; + Action(ActionVariants&& d): ActionVariants(std::move(d)) {} + MString Init(const CLArgs& args) + { + MString act = args.contains("action") ? args.at("action") : "info"; + if(act == "info") + *this = ActionVariants(ActionCarrier()); + else if(act == "tsc") + *this = ActionVariants(ActionCarrier()); + else if(act == "uv") + *this = ActionVariants(ActionCarrier()); + else + return "Unknown action: " + act; + return ""; + } +}; + +template struct DoAction_ +{ + static MString DoAction(const CLArgs& args, D& data) { return "Internal error"; } +}; + +template MString DoAction(const CLArgs& args, D& data) { return DoAction_::DoAction(args, data); } + +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 BaseData 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 BaseData(); +} + +template UVData> ReadUV(const D& data, const BaseParameters* p, const TIndex& tindex) +{ + using RT = ReadType; + using UV = UVData; + size_t ind; + if(tindex.size() == 1) + { + ind = tindex[0]; + 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); + } + 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 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/actiontsc.h b/include/actiontsc.h new file mode 100644 index 0000000..587935a --- /dev/null +++ b/include/actiontsc.h @@ -0,0 +1,54 @@ +#pragma once +#include "actions.h" + +template struct DoAction_ +{ + static MString DoAction(const CLArgs& args, D& data); +}; + +template MString DoAction_::DoAction(const CLArgs& args, D& ds) +{ + michlib_internal::ParameterListEx pars; + pars.UsePrefix(""); + pars.SetParameter("source", args.at("source")); + + auto [tindexes, err] = GetTIndexes(ds, args, pars); + if(err.Exist()) return err; + + if(!args.contains("var")) return "Variable not specified"; + MString vname = args.at("var"); + if(!ds.CheckVar(vname)) return "Variable " + vname + " not exists in this dataset"; + pars.SetParameter("variable", vname); + + std::unique_ptr sourcepars; + if constexpr(ParametersSupported) + { + auto [p, err] = ds.Parameters(pars, args); + if(err.Exist()) return err; + sourcepars.reset(p); + } + auto p = sourcepars.get(); + + auto data = Read(ds, vname, p, tindexes); + 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); + fw.SetColumnName(1, "Longitude"); + fw.SetColumnName(2, "Latitude"); + fw.SetColumnName(3, vname); + fw.SetParameters(pars); + for(size_t i = 0; i < data.N(); i++) + { + fw.Write(data.Lon(i)); + fw.Write(data.Lat(i)); + fw.Write(data(i) == data.Fillval() ? NAN : data(i)); + } + fw.Finalize(); + fw.Close(); + + return ""; +}; diff --git a/src/actionuv.cpp b/include/actionuv.h similarity index 55% rename from src/actionuv.cpp rename to include/actionuv.h index 8c3fb0f..4b756da 100644 --- a/src/actionuv.cpp +++ b/include/actionuv.h @@ -1,87 +1,30 @@ -#define MICHLIB_NOSOURCE -#include "GPL.h" -#include "odm.h" +#pragma once +#include "actions.h" -MString Data::ActionUV(const CLArgs& args) +template struct DoAction_ { - 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"; + static MString DoAction(const CLArgs& args, D& data); +}; +template MString DoAction_::DoAction(const CLArgs& args, D& ds) +{ michlib_internal::ParameterListEx pars; pars.UsePrefix(""); - pars.SetParameter("source", args.at("source")); - TIndex tindexes; - if(args.contains("time")) - { - 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 - { - 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()); - } + auto [tindexes, err] = GetTIndexes(ds, args, pars); + if(err.Exist()) return err; std::unique_ptr sourcepars; + if constexpr(ParametersSupported) { - auto 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); + auto [p, err] = ds.Parameters(pars, args); + if(err.Exist()) return err; + sourcepars.reset(p); } + auto p = sourcepars.get(); - auto p = sourcepars.get(); - size_t ind; - auto read = [p = p, &ind = ind](const auto& arg) -> UVData - { - using T = std::decay_t; - if constexpr(ReadUVPSupported) - return arg.ReadUV(p, ind); - else - return UVData(); - }; - - UVData data; - if(tindexes.size() == 1) - { - ind = tindexes[0]; - michlib::message("Time: " + Time(ind).ToTString()); - data = std::visit(read, *this); - } - else - { - Averager out; - bool ok = true; - for(size_t i = 0; i < tindexes.size(); i++) - { - if(!ok) break; - ind = tindexes[i]; - michlib::message("Time: " + Time(ind).ToTString()); - auto dat = std::visit(read, *this); - if(dat) - out.Add(dat); - else - ok = false; - } - if(ok) data = out.Div(); - } + auto data = ReadUV(ds, p, tindexes); if(!data) return "Can't read data"; // Main file @@ -89,7 +32,7 @@ MString Data::ActionUV(const CLArgs& args) if(name.Exist()) { BFileW fw; - fw.Create(name, 7); + fw.Create(name, 9); fw.SetColumnName(1, "Longitude"); fw.SetColumnName(2, "Latitude"); fw.SetColumnName(3, "u, cm/s"); @@ -97,6 +40,8 @@ MString Data::ActionUV(const CLArgs& args) fw.SetColumnName(5, "Div, (cm/s)/km"); fw.SetColumnName(6, "Rot, (cm/s)/km"); fw.SetColumnName(7, "Okubo-Weiss parameter, (cm^2/s^2)/km^2"); + fw.SetColumnName(8, "Kinetic energy, cm^2/s^2"); + fw.SetColumnName(9, "Eddy kinetic energy, cm^2/s^2"); fw.SetParameters(pars); for(size_t i = 0; i < data.N(); i++) { @@ -107,6 +52,8 @@ MString Data::ActionUV(const CLArgs& args) fw.Write(data.Div(i) == data.Fillval() ? NAN : data.Div(i)); fw.Write(data.Rot(i) == data.Fillval() ? NAN : data.Rot(i)); fw.Write(data.OW(i) == data.Fillval() ? NAN : data.OW(i)); + fw.Write(data.U2(i) == data.Fillval() ? NAN : data.U2(i)); + fw.Write((data.U(i) == data.Fillval() || data.V(i) == data.Fillval()) ? NAN : (data.U2(i) - (data.U(i) * data.U(i) + data.V(i) * data.V(i)))); } fw.Finalize(); fw.Close(); @@ -166,4 +113,4 @@ MString Data::ActionUV(const CLArgs& args) } return ""; -} +}; diff --git a/include/basedata.h b/include/basedata.h index 2a4e445..51e8ca9 100644 --- a/include/basedata.h +++ b/include/basedata.h @@ -1,9 +1,7 @@ #pragma once -#include "comdefs.h" +#include "traits.h" #include -using michlib::real; - class BaseParameters { public: @@ -49,33 +47,17 @@ class BaseData explicit operator bool() const { return N() != 0; } }; -template -concept HaveU = requires(T t) { - { - t.template U(0) - } -> std::convertible_to; -}; - -template -concept HaveV = requires(T t) { - { - t.template V(0) - } -> std::convertible_to; -}; - -template class Averager: public Data +template class DefaultAverager: public Data { + static constexpr bool isuv = IsUVData; std::vector count; - static constexpr bool haveu = HaveU; - static constexpr bool havev = HaveV; static bool DataOk(const Data* d, size_t i) { - bool uok = true; - bool vok = true; - if constexpr(haveu) uok = d->U(i) != Data::Fillval(); - if constexpr(havev) uok = d->V(i) != Data::Fillval(); - return uok && vok; + if constexpr(isuv) + return d->U(i) != Data::Fillval() && d->V(i) != Data::Fillval(); + else + return d->V(i) != Data::Fillval(); } public: @@ -96,33 +78,54 @@ template class Averager: public Data { if(DataOk(this, i)) { - if constexpr(haveu) Data::U(i) += d.U(i); - if constexpr(havev) Data::V(i) += d.V(i); + if constexpr(isuv) + { + Data::U(i) += d.U(i); + Data::U2(i) += d.U2(i); + } + Data::V(i) += d.V(i); count[i]++; } else { - if constexpr(haveu) Data::U(i) = d.U(i); - if constexpr(havev) Data::V(i) = d.V(i); - count[i] = 1; + if constexpr(isuv) + { + Data::U(i) = d.U(i); + Data::U2(i) = d.U2(i); + } + Data::V(i) = d.V(i); + count[i] = 1; } } } - Averager& Div() + DefaultAverager& Div() { if(!*this) return *this; for(size_t i = 0; i < Data::N(); i++) - { - if constexpr(haveu) - { - if(count[i] != 0) Data::U(i) /= count[i]; - } - if constexpr(havev) + if(count[i] != 0) { - if(count[i] != 0) Data::V(i) /= count[i]; + if constexpr(isuv) + { + Data::U(i) /= count[i]; + Data::U2(i) /= count[i]; + } + Data::V(i) /= count[i]; } - } return *this; } }; + +namespace internal +{ +template struct GetAverager_ +{ + using type = DefaultAverager; +}; +template struct GetAverager_> +{ + using type = typename Data::Averager; +}; +} // namespace internal + +template using Averager = internal::GetAverager_::type; diff --git a/include/data.h b/include/data.h new file mode 100644 index 0000000..80a64c1 --- /dev/null +++ b/include/data.h @@ -0,0 +1,16 @@ +#pragma once +#include "AVISO.h" +#include "AVISOLOCAL.h" +#include "HYCOM.h" +#include "NEMO.h" +#include + +using DataVariants = std::variant; +class Data: public DataVariants +{ + public: + Data() = default; + Data(DataVariants&& v): DataVariants(std::move(v)) {} + + MString Init(const CLArgs& args); +}; diff --git a/include/layereddata.h b/include/layereddata.h index e0af873..72e795a 100644 --- a/include/layereddata.h +++ b/include/layereddata.h @@ -1,25 +1,14 @@ #pragma once -#include "DataAdapters/ncfilealt.h" -#include "ParseArgs.h" #include "gsw.h" -#include "mdatetime.h" #include "ncfuncs.h" #include "simple2ddata.h" -#include "uvdata.h" -#include #include -#include using michlib::Ceil; using michlib::DetGeoDomain; using michlib::Floor; using michlib::GPL; using michlib::int2; -using michlib::int4; -using michlib::MDateTime; -using michlib::MString; -using michlib::NCFileA; -using michlib::ToGeoDomain; class LayeredData: public NCFuncs { @@ -148,8 +137,6 @@ class LayeredData: public NCFuncs Data Read(const MString& vname, const BaseParameters* ip, size_t i) const; - UVData ReadUV(const BaseParameters* ip, size_t i) const; - bool isOk() const { return nc.size() > 0; } explicit operator bool() const { return nc.size() > 0; } diff --git a/include/ncfuncs.h b/include/ncfuncs.h index f9445b4..f77be7b 100644 --- a/include/ncfuncs.h +++ b/include/ncfuncs.h @@ -1,6 +1,5 @@ #pragma once #include "DataAdapters/ncfilealt.h" -#include "StringFunctions.h" #include "mdatetime.h" #include #include diff --git a/include/odm.h b/include/odm.h index 3d73836..ac6fdd3 100644 --- a/include/odm.h +++ b/include/odm.h @@ -1,180 +1,18 @@ #pragma once -#include "AVISO.h" -#include "AVISOLOCAL.h" -#include "BFileW.h" -#include "HYCOM.h" -#include "NEMO.h" -#include -#include +#include "actioninfo.h" +#include "actiontsc.h" +#include "actionuv.h" +#include "data.h" -using michlib::BFileW; using michlib::errmessage; -using michlib::GPL; -using michlib::message; -using DataVariants = std::variant; - -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 MString& vname, const BaseParameters* ip, size_t i) { - { - t.template Read(vname, ip, i)(0) - } -> std::convertible_to; -}; -template -concept ReadSupported = requires(T t, const MString& vname, size_t i) { - { - t.template Read(vname, i)(0) - } -> std::convertible_to; -}; - -template -concept ReadUVPSupported = requires(T t, const BaseParameters* ip, size_t i) { - { - t.template ReadUV(ip, i).U(0, 0) + t.template ReadUV(ip, i).V(0, 0) - } -> std::convertible_to; -}; - -class Data: public DataVariants +template consteval bool MustSupported() { - public: - using TIndex = std::vector; - - private: - TIndex GetTIndexes(const MDateTime& b, const MDateTime& e) const - { - 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++) - { - MString date = Time(i).ToString(); - if(0 != regexec(regbuf.get(), date.Buf(), 0, 0, 0)) continue; - out.push_back(i); - } - - 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: - Data() = default; - - Data(DataVariants&& d): DataVariants(std::move(d)) {} - - MDateTime Time(size_t it) const - { - return std::visit([it = it](const auto& arg) -> auto { return arg.Time(it); }, *this); - } - size_t NTimes() const - { - return std::visit([](const auto& arg) -> auto { return arg.NTimes(); }, *this); - } - - auto CheckVar(const MString& vname) const - { - return std::visit([&vname = std::as_const(vname)](const auto& arg) -> auto { return arg.CheckVar(vname); }, *this); - } - - MString Init(const CLArgs& args) - { - 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 if(src == "AVISO") - { - AVISOData data; - auto res = data.Open(args); - if(res.Exist()) return "Can't open source " + src + ":\n" + res; - *this = Data(std::move(data)); - } - else if(src == "AVISOLOCAL") - { - AVISOLOCALData data; - auto res = data.Open(args); - if(res.Exist()) return "Can't open source " + src + ":\n" + res; - *this = Data(std::move(data)); - } - else if(src == "HYCOM") - { - HYCOMData 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 ""; - } - - MString ActionInfo(const CLArgs& args); - MString ActionTsc(const CLArgs& args); - MString ActionUV(const CLArgs& args); + static_assert(IsActionSupported); + return true; }; + +constexpr bool supported = MustSupported() && MustSupported() && MustSupported() && + MustSupported() && MustSupported() && MustSupported() && + MustSupported() && MustSupported() && MustSupported() && + MustSupported() && MustSupported() && MustSupported(); diff --git a/include/traits.h b/include/traits.h new file mode 100644 index 0000000..84bc5b5 --- /dev/null +++ b/include/traits.h @@ -0,0 +1,74 @@ +#pragma once +#include "ParseArgs.h" +#include + +class BaseParameters; +using michlib::real; + +template +concept InfoSupported = requires(T t) { + { + t.Info() + } -> std::convertible_to; +}; + +template +concept ParametersSupported = requires(T t, michlib_internal::ParameterListEx& pars, const CLArgs& args) { + { + t.Parameters(pars, args).first + } -> std::convertible_to; +}; + +template +concept ReadPSupported = requires(T t, const MString& vname, const BaseParameters* ip, size_t i) { + { + t.Read(vname, ip, i)(0) + } -> std::convertible_to; +}; +template +concept ReadSupported = requires(T t, const MString& vname, size_t i) { + { + t.Read(vname, i)(0) + } -> std::convertible_to; +}; + +template +concept ReadUVPSupported = requires(T t, const BaseParameters* ip, size_t i) { + { + t.ReadUV(ip, i).U(0, 0) + t.template ReadUV(ip, i).V(0, 0) + } -> std::convertible_to; +}; + +template +concept IsUVData = requires(T t) { + { + t.U(0) + } -> std::convertible_to; + { + t.V(0) + } -> std::convertible_to; + { + t.U2(0) + } -> std::convertible_to; +}; + +namespace internal +{ +template using void_ = void; + +template struct GetReadType_; + +template struct GetReadType_ +{ + using p = BaseParameters*; + using type = decltype(D().Read(MString(), p(), 0)); +}; + +template struct GetReadType_ +{ + using type = decltype(D().Read(MString(), 0)); +}; + +} // namespace internal + +template using ReadType = internal::GetReadType_, ReadSupported>::type; diff --git a/include/uvdata.h b/include/uvdata.h index 4b16e39..ba358c7 100644 --- a/include/uvdata.h +++ b/include/uvdata.h @@ -6,22 +6,35 @@ using michlib::M_PI; using michlib::real; using michlib::Sqrt; +namespace internal +{ +template +concept HaveXYStep = requires(T t) { + { + t.XStep() + } -> std::convertible_to; + { + t.YStep() + } -> std::convertible_to; +}; +} + enum class Metric { EUCLID, SPHERIC }; -class UVData +class UVDataStorage { + protected: static constexpr real fillval = 1.0e10; - real x0 = 0.0, y0 = 0.0; - size_t nx = 0, ny = 0; - real xstep = 0.0, ystep = 0.0; - std::vector u, v; + std::vector u, v, u2; + size_t nx = 0, ny = 0; Metric metric; + UVDataStorage() = default; real D(real lon1, real lat1, real lon2, real lat2) const { switch(metric) @@ -37,43 +50,6 @@ class UVData real Ud(size_t ix, size_t iy) const { return IsCoast(ix, iy) ? 0.0 : U(ix, iy); } real Vd(size_t ix, size_t iy) const { return IsCoast(ix, iy) ? 0.0 : V(ix, iy); } - real dUdX(size_t ix, size_t iy) const - { - if(IsCoast(ix, iy)) return fillval; - if(ix == 0) return (Ud(1, iy) - Ud(0, iy)) / D(Lon(0, iy), Lat(0, iy), Lon(1, iy), Lat(1, iy)); - if(ix == nx - 1) return (Ud(nx - 1, iy) - Ud(nx - 2, iy)) / D(Lon(nx - 2, iy), Lat(nx - 2, iy), Lon(nx - 1, iy), Lat(nx - 1, iy)); - return 0.5 * ((Ud(ix + 1, iy) - Ud(ix, iy)) / D(Lon(ix, iy), Lat(ix, iy), Lon(ix + 1, iy), Lat(ix + 1, iy)) + - (Ud(ix, iy) - Ud(ix - 1, iy)) / D(Lon(ix - 1, iy), Lat(ix - 1, iy), Lon(ix, iy), Lat(ix, iy))); - } - real dVdX(size_t ix, size_t iy) const - { - if(IsCoast(ix, iy)) return fillval; - if(ix == 0) return (Vd(1, iy) - Vd(0, iy)) / D(Lon(0, iy), Lat(0, iy), Lon(1, iy), Lat(1, iy)); - if(ix == nx - 1) return (Vd(nx - 1, iy) - Vd(nx - 2, iy)) / D(Lon(nx - 2, iy), Lat(nx - 2, iy), Lon(nx - 1, iy), Lat(nx - 1, iy)); - return 0.5 * ((Vd(ix + 1, iy) - Vd(ix, iy)) / D(Lon(ix, iy), Lat(ix, iy), Lon(ix + 1, iy), Lat(ix + 1, iy)) + - (Vd(ix, iy) - Vd(ix - 1, iy)) / D(Lon(ix - 1, iy), Lat(ix - 1, iy), Lon(ix, iy), Lat(ix, iy))); - } - real dUdY(size_t ix, size_t iy) const - { - if(IsCoast(ix, iy)) return fillval; - if(iy == 0) return (Ud(ix, 1) - Ud(ix, 0)) / D(Lon(ix, 0), Lat(ix, 0), Lon(ix, 1), Lat(ix, 1)); - if(iy == ny - 1) return (Ud(ix, ny - 1) - Ud(ix, ny - 2)) / D(Lon(ix, ny - 2), Lat(ix, ny - 2), Lon(ix, ny - 1), Lat(ix, ny - 1)); - return 0.5 * ((Ud(ix, iy + 1) - Ud(ix, iy)) / D(Lon(ix, iy), Lat(ix, iy), Lon(ix, iy + 1), Lat(ix, iy + 1)) + - (Ud(ix, iy) - Ud(ix, iy - 1)) / D(Lon(ix, iy - 1), Lat(ix, iy - 1), Lon(ix, iy), Lat(ix, iy))); - } - real dVdY(size_t ix, size_t iy) const - { - if(IsCoast(ix, iy)) return fillval; - if(iy == 0) return (Vd(ix, 1) - Vd(ix, 0)) / D(Lon(ix, 0), Lat(ix, 0), Lon(ix, 1), Lat(ix, 1)); - if(iy == ny - 1) return (Vd(ix, ny - 1) - Vd(ix, ny - 2)) / D(Lon(ix, ny - 2), Lat(ix, ny - 2), Lon(ix, ny - 1), Lat(ix, ny - 1)); - return 0.5 * ((Vd(ix, iy + 1) - Vd(ix, iy)) / D(Lon(ix, iy), Lat(ix, iy), Lon(ix, iy + 1), Lat(ix, iy + 1)) + - (Vd(ix, iy) - Vd(ix, iy - 1)) / D(Lon(ix, iy - 1), Lat(ix, iy - 1), Lon(ix, iy), Lat(ix, iy))); - } - - // For stationary points - real LonR(real x, [[maybe_unused]] real y) const { return x0 + x * xstep; } - real LatR([[maybe_unused]] real x, real y) const { return y0 + y * ystep; } - public: enum STPOINT { @@ -93,12 +69,6 @@ class UVData STPOINT type = NOPOINT; }; - UVData() = default; - UVData(size_t nx_, size_t ny_, real x0_, real y0_, real xs_, real ys_, Metric m_ = Metric::SPHERIC): - x0(x0_), y0(y0_), nx(nx_), ny(ny_), xstep(xs_), ystep(ys_), u(nx_ * ny_), v(nx_ * ny_), metric(m_) - { - } - const real& U(size_t i) const { return u[i]; } const real& V(size_t i) const { return v[i]; } const real& U(size_t ix, size_t iy) const { return U(iy * nx + ix); } @@ -109,38 +79,188 @@ class UVData real& U(size_t ix, size_t iy) { return U(iy * nx + ix); } real& V(size_t ix, size_t iy) { return V(iy * nx + ix); } + const real& U2(size_t i) const { return u2[i]; } + const real& U2(size_t ix, size_t iy) const { return U2(iy * nx + ix); } + + real& U2(size_t i) { return u2[i]; } + real& U2(size_t ix, size_t iy) { return U2(iy * nx + ix); } + size_t N() const { return u.size(); } size_t Nx() const { return nx; } size_t Ny() const { return ny; } + explicit operator bool() const { return N() != 0; } + + bool IsCoast(size_t i) const { return U(i) == fillval || V(i) == fillval; } + bool IsCoast(size_t ix, size_t iy) const { return U(ix, iy) == fillval || V(ix, iy) == fillval; } + + static real Fillval() { return fillval; } +}; + +template class UVDataDims; + +template class UVDataDims: public UVDataStorage +{ + real x0 = 0.0, y0 = 0.0; + real xstep = 0.0, ystep = 0.0; + + void Resize(size_t sz) + { + UVDataStorage::u.resize(sz); + UVDataStorage::v.resize(sz); + UVDataStorage::u2.resize(sz); + } + + protected: + UVDataDims() = default; + UVDataDims(const OneVarData& u, const OneVarData& v, Metric m = Metric::SPHERIC) + { + if(!(u && v)) + { + *this = UVDataDims(); + return; + } + x0 = u.Lon(0); + y0 = u.Lat(0); + xstep = u.XStep(); + ystep = u.YStep(); + metric = m; + nx = u.Nx(); + ny = u.Ny(); + + Resize(u.N()); + for(size_t i = 0; i < u.N(); i++) + { + if(u(i) == u.Fillval() || v(i) == v.Fillval()) + U(i) = V(i) = U2(i) = Fillval(); + else + { + U(i) = u(i); + V(i) = v(i); + U2(i) = u(i) * u(i) + v(i) * v(i); + } + } + } + + public: real Lon(size_t ix, [[maybe_unused]] size_t iy) const { return x0 + ix * xstep; } real Lat([[maybe_unused]] size_t ix, size_t iy) const { return y0 + iy * ystep; } - real Lon(size_t i) const { return Lon(i % nx, i / nx); } real Lat(size_t i) const { return Lat(i % nx, i / nx); } +}; - explicit operator bool() const { return N() != 0; } +template class UVDataDims: public UVDataStorage +{ + std::vector lon, lat; - bool IsCoast(size_t i) const { return U(i) == fillval || V(i) == fillval; } - bool IsCoast(size_t ix, size_t iy) const { return U(ix, iy) == fillval || V(ix, iy) == fillval; } + void Resize(size_t sz) + { + UVDataStorage::u.resize(sz); + UVDataStorage::v.resize(sz); + UVDataStorage::u2.resize(sz); + lon.resize(sz); + lat.resize(sz); + } - static real Fillval() { return fillval; } + protected: + UVDataDims() = default; + UVDataDims(const OneVarData& u, const OneVarData& v, Metric m = Metric::SPHERIC) + { + if(!(u && v)) + { + *this = UVDataDims(); + return; + } + metric = m; + nx = u.Nx(); + ny = u.Ny(); + + Resize(u.N()); + for(size_t i = 0; i < u.N(); i++) + { + lon[i] = u.Lon(i); + lat[i] = u.Lat(i); + if(u(i) == u.Fillval() || v(i) == v.Fillval()) + U(i) = V(i) = U2(i) = Fillval(); + else + { + U(i) = u(i); + V(i) = v(i); + U2(i) = u(i) * u(i) + v(i) * v(i); + } + } + } + + public: + real Lon(size_t ix, [[maybe_unused]] size_t iy) const { return Lon(nx * iy + ix); } + real Lat([[maybe_unused]] size_t ix, size_t iy) const { return Lat(nx * iy + ix); } + real Lon(size_t i) const { return lon[i]; } + real Lat(size_t i) const { return lat[i]; } +}; + +template class UVData: public UVDataDims> +{ + using B = UVDataDims>; + using B::Ud, B::Vd, B::nx, B::ny, B::D; + + // For stationary points. Works only for meridian-parallel grids. + real LonR(size_t i, size_t j, real x, [[maybe_unused]] real y) const { return B::Lon(i, j) + x * (B::Lon(i + 1, j) - B::Lon(i, j)); } + real LatR(size_t i, size_t j, [[maybe_unused]] real x, real y) const { return B::Lat(i, j) + y * (B::Lat(i, j + 1) - B::Lat(i, j)); } + + real dUdX(size_t ix, size_t iy) const + { + if(IsCoast(ix, iy)) return Fillval(); + if(ix == 0) return (Ud(1, iy) - Ud(0, iy)) / D(Lon(0, iy), Lat(0, iy), Lon(1, iy), Lat(1, iy)); + if(ix == nx - 1) return (Ud(nx - 1, iy) - Ud(nx - 2, iy)) / D(Lon(nx - 2, iy), Lat(nx - 2, iy), Lon(nx - 1, iy), Lat(nx - 1, iy)); + return 0.5 * ((Ud(ix + 1, iy) - Ud(ix, iy)) / D(Lon(ix, iy), Lat(ix, iy), Lon(ix + 1, iy), Lat(ix + 1, iy)) + + (Ud(ix, iy) - Ud(ix - 1, iy)) / D(Lon(ix - 1, iy), Lat(ix - 1, iy), Lon(ix, iy), Lat(ix, iy))); + } + real dVdX(size_t ix, size_t iy) const + { + if(IsCoast(ix, iy)) return Fillval(); + if(ix == 0) return (Vd(1, iy) - Vd(0, iy)) / D(Lon(0, iy), Lat(0, iy), Lon(1, iy), Lat(1, iy)); + if(ix == nx - 1) return (Vd(nx - 1, iy) - Vd(nx - 2, iy)) / D(Lon(nx - 2, iy), Lat(nx - 2, iy), Lon(nx - 1, iy), Lat(nx - 1, iy)); + return 0.5 * ((Vd(ix + 1, iy) - Vd(ix, iy)) / D(Lon(ix, iy), Lat(ix, iy), Lon(ix + 1, iy), Lat(ix + 1, iy)) + + (Vd(ix, iy) - Vd(ix - 1, iy)) / D(Lon(ix - 1, iy), Lat(ix - 1, iy), Lon(ix, iy), Lat(ix, iy))); + } + real dUdY(size_t ix, size_t iy) const + { + if(IsCoast(ix, iy)) return Fillval(); + if(iy == 0) return (Ud(ix, 1) - Ud(ix, 0)) / D(Lon(ix, 0), Lat(ix, 0), Lon(ix, 1), Lat(ix, 1)); + if(iy == ny - 1) return (Ud(ix, ny - 1) - Ud(ix, ny - 2)) / D(Lon(ix, ny - 2), Lat(ix, ny - 2), Lon(ix, ny - 1), Lat(ix, ny - 1)); + return 0.5 * ((Ud(ix, iy + 1) - Ud(ix, iy)) / D(Lon(ix, iy), Lat(ix, iy), Lon(ix, iy + 1), Lat(ix, iy + 1)) + + (Ud(ix, iy) - Ud(ix, iy - 1)) / D(Lon(ix, iy - 1), Lat(ix, iy - 1), Lon(ix, iy), Lat(ix, iy))); + } + real dVdY(size_t ix, size_t iy) const + { + if(IsCoast(ix, iy)) return Fillval(); + if(iy == 0) return (Vd(ix, 1) - Vd(ix, 0)) / D(Lon(ix, 0), Lat(ix, 0), Lon(ix, 1), Lat(ix, 1)); + if(iy == ny - 1) return (Vd(ix, ny - 1) - Vd(ix, ny - 2)) / D(Lon(ix, ny - 2), Lat(ix, ny - 2), Lon(ix, ny - 1), Lat(ix, ny - 1)); + return 0.5 * ((Vd(ix, iy + 1) - Vd(ix, iy)) / D(Lon(ix, iy), Lat(ix, iy), Lon(ix, iy + 1), Lat(ix, iy + 1)) + + (Vd(ix, iy) - Vd(ix, iy - 1)) / D(Lon(ix, iy - 1), Lat(ix, iy - 1), Lon(ix, iy), Lat(ix, iy))); + } + + public: + using B::Fillval, B::IsCoast, B::Lon, B::Lat, B::U, B::V, B::Nx, B::Ny; + + UVData() = default; + UVData(const OneVarData& u, const OneVarData& v, Metric m = Metric::SPHERIC): B(u, v, m) {} - real Div(size_t i) const { return Div(i % nx, i / nx); } - real Rot(size_t i) const { return Rot(i % nx, i / nx); } + real Div(size_t i) const { return Div(i % nx, i / B::nx); } + real Rot(size_t i) const { return Rot(i % nx, i / B::nx); } real Div(size_t ix, size_t iy) const { if(!*this) return 0.0; real ux = dUdX(ix, iy); real vy = dVdY(ix, iy); - return (ux == fillval || vy == fillval) ? fillval : (ux + vy); + return (ux == Fillval() || vy == Fillval()) ? Fillval() : (ux + vy); } real Rot(size_t ix, size_t iy) const { if(!*this) return 0.0; real vx = dVdX(ix, iy); real uy = dUdY(ix, iy); - return (vx == fillval || uy == fillval) ? fillval : (vx - uy); + return (vx == Fillval() || uy == Fillval()) ? Fillval() : (vx - uy); } // Okubo-Weiss parameter real OW(size_t i) const { return OW(i % nx, i / nx); } @@ -152,7 +272,7 @@ class UVData real vx = dVdX(ix, iy); real vy = dVdY(ix, iy); - if(ux == fillval || uy == fillval || vx == fillval || vy == fillval) return fillval; + if(ux == Fillval() || uy == Fillval() || vx == Fillval() || vy == Fillval()) return Fillval(); real sn = ux - vy; real ss = vx + uy; @@ -162,7 +282,7 @@ class UVData auto StablePoints(size_t ix, size_t iy) const { - std::vector points; + std::vector points; if(!*this) return points; if(ix >= Nx() - 1 || iy >= Ny() - 1) return points; if(IsCoast(ix, iy) || IsCoast(ix + 1, iy) || IsCoast(ix, iy + 1) || IsCoast(ix + 1, iy + 1)) return points; @@ -202,24 +322,24 @@ class UVData if(des > 0.0) { if(std::max(-b + Sqrt(des), -b - Sqrt(des)) > 0.0 && c > 0.0) - return UKNOT; + return UVDataStorage::UKNOT; else if(std::max(-b + Sqrt(des), -b - Sqrt(des)) > 0.0) - return SADDLE; + return UVDataStorage::SADDLE; else - return SKNOT; + return UVDataStorage::SKNOT; } else { bool acyclcrit = (av * y + cv > 0.0); if(b < 0.0) - return acyclcrit ? SACICFOCUS : SCICFOCUS; + return acyclcrit ? UVDataStorage::SACICFOCUS : UVDataStorage::SCICFOCUS; else - return acyclcrit ? UACICFOCUS : UCICFOCUS; + return acyclcrit ? UVDataStorage::UACICFOCUS : UVDataStorage::UCICFOCUS; } }; - if(x1 >= 0.0 && x1 < 1.0 && y1 >= 0.0 && y1 < 1.0) points.emplace_back(LonR(x1 + ix, y1 + iy), LatR(x1 + ix, y1 + iy), PointType(x1, y1)); - if(x2 >= 0.0 && x2 < 1.0 && y2 >= 0.0 && y2 < 1.0) points.emplace_back(LonR(x2 + ix, y2 + iy), LatR(x2 + ix, y2 + iy), PointType(x2, y2)); + if(x1 >= 0.0 && x1 < 1.0 && y1 >= 0.0 && y1 < 1.0) points.emplace_back(LonR(ix, iy, x1, y1), LatR(ix, iy, x1, y1), PointType(x1, y1)); + if(x2 >= 0.0 && x2 < 1.0 && y2 >= 0.0 && y2 < 1.0) points.emplace_back(LonR(ix, iy, x2, y2), LatR(ix, iy, x2, y2), PointType(x2, y2)); return points; } }; diff --git a/src/AVISOLOCAL.cpp b/src/AVISOLOCAL.cpp index 615682e..69aa683 100644 --- a/src/AVISOLOCAL.cpp +++ b/src/AVISOLOCAL.cpp @@ -234,25 +234,3 @@ template AVISOLOCALData::Data AVISOLOCALData::ReadVarRaw(const N } return data; } - -UVData AVISOLOCALData::ReadUV(const BaseParameters* ip, size_t i) const -{ - if(!isOk()) return UVData(); - - auto u = Read("u", ip, i); - auto v = Read("v", ip, i); - if(!(u && v)) return UVData(); - - UVData out{u.Nx(), u.Ny(), u.Lon(0, 0), u.Lat(0, 0), u.XStep(), u.YStep()}; - for(size_t i = 0; i < out.N(); i++) - { - if(u(i) == Data::Fillval() || v(i) == Data::Fillval()) - out.U(i) = out.V(i) = UVData::Fillval(); - else - { - out.U(i) = u(i); - out.V(i) = v(i); - } - } - return out; -} diff --git a/src/ParseArgs.cpp b/src/ParseArgs.cpp index 9b2d623..c858d0f 100644 --- a/src/ParseArgs.cpp +++ b/src/ParseArgs.cpp @@ -1,8 +1,6 @@ #define MICHLIB_NOSOURCE #include "ParseArgs.h" -using michlib::SList; - CLArgs ParseArgs(int argc, char** argv) { CLArgs out; diff --git a/src/actioninfo.cpp b/src/actioninfo.cpp deleted file mode 100644 index 496318c..0000000 --- a/src/actioninfo.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#define MICHLIB_NOSOURCE -#include "odm.h" - -MString Data::ActionInfo(const CLArgs& args) -{ - 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 deleted file mode 100644 index 14a7abc..0000000 --- a/src/actiontsc.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#define MICHLIB_NOSOURCE -#include "GPL.h" -#include "odm.h" - -MString Data::ActionTsc(const CLArgs& args) -{ - 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")); - TIndex tindexes; - - if(args.contains("time")) - { - 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 - { - 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("var")) return "Variable not specified"; - MString vname = args.at("var"); - if(!CheckVar(vname)) return "Variable " + vname + " not exists in this dataset"; - pars.SetParameter("variable", vname); - - std::unique_ptr sourcepars; - { - 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); - } - - auto p = sourcepars.get(); - size_t ind; - auto read = [&vname = std::as_const(vname), p = p, &ind = ind](const auto& arg) -> BaseData - { - using T = std::decay_t; - if constexpr(ParametersSupported && ReadPSupported) - return arg.Read(vname, p, ind); - else if constexpr(!ParametersSupported && ReadSupported) - return arg.Read(vname, ind); - else - return BaseData(); - }; - - BaseData data; - if(tindexes.size() == 1) - { - ind = tindexes[0]; - michlib::message("Time: " + Time(ind).ToTString()); - data = std::visit(read, *this); - } - else - { - Averager out; - bool ok = true; - for(size_t i = 0; i < tindexes.size(); i++) - { - if(!ok) break; - ind = tindexes[i]; - michlib::message("Time: " + Time(ind).ToTString()); - 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); - fw.SetColumnName(1, "Longitude"); - fw.SetColumnName(2, "Latitude"); - fw.SetColumnName(3, vname); - fw.SetParameters(pars); - for(size_t i = 0; i < data.N(); i++) - { - fw.Write(data.Lon(i)); - fw.Write(data.Lat(i)); - fw.Write(data(i) == data.Fillval() ? NAN : data(i)); - } - fw.Finalize(); - fw.Close(); - - return ""; -} diff --git a/src/basedata.cpp b/src/basedata.cpp index 43a5ddc..9b08c4f 100644 --- a/src/basedata.cpp +++ b/src/basedata.cpp @@ -1,3 +1,4 @@ +#define MICHLIB_NOSOURCE #include "basedata.h" BaseParameters::~BaseParameters() {} diff --git a/src/data.cpp b/src/data.cpp new file mode 100644 index 0000000..655de5a --- /dev/null +++ b/src/data.cpp @@ -0,0 +1,39 @@ +#define MICHLIB_NOSOURCE +#include "data.h" + +MString Data::Init(const CLArgs& args) +{ + 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 if(src == "AVISO") + { + AVISOData data; + auto res = data.Open(args); + if(res.Exist()) return "Can't open source " + src + ":\n" + res; + *this = Data(std::move(data)); + } + else if(src == "AVISOLOCAL") + { + AVISOLOCALData data; + auto res = data.Open(args); + if(res.Exist()) return "Can't open source " + src + ":\n" + res; + *this = Data(std::move(data)); + } + else if(src == "HYCOM") + { + HYCOMData 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 ""; +} diff --git a/src/layereddata.cpp b/src/layereddata.cpp index 991a06c..c7eada3 100644 --- a/src/layereddata.cpp +++ b/src/layereddata.cpp @@ -270,28 +270,6 @@ LayeredData::Data LayeredData::Read(const MString& vname, const BaseParameters* return Data(); } -UVData LayeredData::ReadUV(const BaseParameters* ip, size_t i) const -{ - if(!isOk()) return UVData(); - - auto u = Read("u", ip, i); - auto v = Read("v", ip, i); - if(!(u && v)) return UVData(); - - UVData out{u.Nx(), u.Ny(), u.Lon(0, 0), u.Lat(0, 0), lonstep, latstep}; - for(size_t i = 0; i < out.N(); i++) - { - if(u(i) == Data::Fillval() || v(i) == Data::Fillval()) - out.U(i) = out.V(i) = UVData::Fillval(); - else - { - out.U(i) = u(i); - out.V(i) = v(i); - } - } - return out; -} - template LayeredData::Data LayeredData::ReadVarRaw(const NC& f, const MString& name, size_t i, bool nodepth, const struct LayeredData::Parameters* p) const { real unitmul = 1.0; diff --git a/src/ncfuncs.cpp b/src/ncfuncs.cpp index 6110e5c..8b7fa35 100644 --- a/src/ncfuncs.cpp +++ b/src/ncfuncs.cpp @@ -95,8 +95,8 @@ std::tuple NCFuncs::Refdate(const MString& refdate) if(*ci == "days") step = 3600 * 24; ci++; } - if(ci != words.end()) ci++; // skip "since" - if(ci != words.end()) rstr = *ci; // Day + if(ci != words.end()) ci++; // skip "since" + if(ci != words.end()) rstr = *ci; // Day if(ci != words.end()) ci++; if(ci != words.end()) rstr += " " + *ci; // Hours bool success = out.FromString(rstr); diff --git a/src/odm.cpp b/src/odm.cpp index 66912ac..e1e7699 100644 --- a/src/odm.cpp +++ b/src/odm.cpp @@ -4,7 +4,7 @@ inline void Usage(const MString& arg0) { message(arg0 + " (=...)"); message("Keys are:"); - message(" action. What the program should do. May be: info, tsc, uv. Default: tsc."); + message(" action. What the program should do. May be: info, tsc, uv. Default: info."); message(" Keys for action=info. Print some information about dataset."); message(" source. Required. May be: NEMO, HYCOM, AVISO, AVISOLOCAL"); message(" Keys for source=NEMO"); @@ -50,7 +50,7 @@ int main(int argc, char** argv) } auto args = ParseArgs(argc, argv); - MString action = args.contains("action") ? args["action"] : "tsc"; + MString action = args.contains("action") ? args["action"] : "info"; Data data; { @@ -61,19 +61,32 @@ int main(int argc, char** argv) return 1; } } - - MString ret; - if(action == "info") - ret = data.ActionInfo(args); - else if(action == "tsc") - ret = data.ActionTsc(args); - else if(action == "uv") - ret = data.ActionUV(args); - else + Action act; { - errmessage("Unknown action " + action); - return 1; + auto ret = act.Init(args); + if(ret.Exist()) + { + errmessage(ret); + return 1; + } } + + auto ret = std::visit( + [&act = std::as_const(act), &args = std::as_const(args)](auto& arg) + { + using DT = std::decay_t; + return std::visit( + [&data = arg, &args = std::as_const(args)](const auto& arg) + { + using AT = std::decay_t; + if constexpr(IsActionSupported) + return DoAction(args, data); + else + return MString("Unsupported combination of action and source"); + }, + act); + }, + data); if(ret.Exist()) { errmessage(ret);