#pragma once #include "ParseArgs.h" #include "basedata.h" #include "mdatetime.h" #include "mregex.h" #include "traits.h" #include "uvdata.h" #include #include using michlib::MDateTime; #if defined GENACTIONLIST #define ADD_ACTION(actclass, actname, suptest, ...) ADD ACTION CLASS: actclass #else #define ADD_ACTION(actclass, actname, suptest, ...) \ class Action##actclass __VA_OPT__( : protected) __VA_ARGS__ \ { \ public: \ static constexpr const char* name = #actname; \ template static constexpr bool IsSupported = (suptest); \ template static MString DoAction(const CLArgs& args, Source& data); \ }; #endif enum class VelSource { AUTOSEL, STANDART, GEOSTROPHIC, GEOSTROPHICSSH }; struct TimeData { static constexpr auto stepunits = std::to_array({3600 * 24, 3600, 60, 1}); static constexpr std::array stepnames{"days", "hours", "minutes", "seconds"}; MDateTime refdate; size_t unitind; std::vector steps; template TimeData(const D& data, const TIndex& tindexes): refdate(), unitind(stepunits.size()), steps(tindexes.size()) { if(steps.size() == 0) return; refdate = data.Time(tindexes[0]); unitind = 0; for(size_t i = 0; i < steps.size(); i++) { auto delta = data.Time(tindexes[i]) - refdate; while(delta.Seconds() % stepunits[unitind] != 0) unitind++; } for(size_t i = 0; i < steps.size(); i++) { auto delta = data.Time(tindexes[i]) - refdate; steps[i] = michlib::int_cast(delta.Seconds() / stepunits[unitind]); } } MString UnitName() const { MString out = stepnames[unitind].c_str(); return out + " since " + refdate.ToString(); } }; 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)) // Time, not regex tindexes.push_back(GetTIndex(data, time)); else if(regex == "BEGIN" || regex == "BEG" || regex == "FIRST") // First time tindexes.push_back(0); else if(regex == "END" || regex == "LAST") // Last time tindexes.push_back(data.NTimes() - 1); else // Regular expression { 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]).ToTString()); 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()}; for(size_t i = 0; i < nt; i++) if(data.Time(i) >= beg && data.Time(i) <= end) tindexes.push_back(i); if(tindexes.size() == 0) return {tindexes, "There are no times between " + b.ToString() + " and " + e.ToString()}; pars.SetParameter("timeb", b.ToTString()); pars.SetParameter("timee", e.ToTString()); } std::ranges::sort(tindexes, [&data = std::as_const(data)](size_t a, size_t b) { return data.Time(a) < data.Time(b); }); return {tindexes, ""}; } template std::vector> Read(const D& data, const std::vector& vnames, const BaseParameters* p, size_t ind) { using RT = ReadType; std::vector out; michlib::message("Time: " + data.Time(ind).ToTString()); std::map cache; for(const auto& vname: vnames) { bool res; if constexpr(ReadPSupported) res = data.Read(vname, cache, p, ind); else if constexpr(ReadSupported) res = data.Read(vname, cache, ind); if(!res) return out; } for(size_t i = 0; i < vnames.size(); i++) out.emplace_back(std::move(cache[vnames[i]])); return out; } template std::vector> Read(const D& data, const std::vector& vnames, const BaseParameters* p, const TIndex& tindex) { using RT = ReadType; size_t ind; std::vector out; if(tindex.size() == 1) return Read(data, vnames, p, tindex[0]); else { std::vector> aver(vnames.size()); for(size_t i = 0; i < tindex.size(); i++) { ind = tindex[i]; michlib::message("Time: " + data.Time(ind).ToTString()); std::map cache; for(const auto& vname: vnames) { bool res; if constexpr(ReadPSupported) res = data.Read(vname, cache, p, ind); else if constexpr(ReadSupported) res = data.Read(vname, cache, ind); if(!res) return out; } for(size_t i = 0; i < vnames.size(); i++) aver[i].Add(std::move(cache[vnames[i]])); } for(size_t i = 0; i < vnames.size(); i++) out.emplace_back(std::move(aver[i].Div())); return out; } return out; } template UVData> ReadUV(const D& data, const BaseParameters* p, size_t ind, VelSource usegeo) { using RT = ReadType; using UV = UVData; michlib::message("Time: " + data.Time(ind).ToTString()); std::map cache; bool res = false; MString uname, vname; switch(usegeo) { case(VelSource::AUTOSEL): { if(data.CheckVar("u") == VarPresence::INTERNAL && data.CheckVar("v") == VarPresence::INTERNAL) { uname = "u"; vname = "v"; } else { uname = "ugs"; vname = "vgs"; } break; } case(VelSource::STANDART): { uname = "u"; vname = "v"; break; } case(VelSource::GEOSTROPHIC): { uname = "ugs"; vname = "vgs"; break; } case(VelSource::GEOSTROPHICSSH): { uname = "ugeo"; vname = "vgeo"; break; } } if constexpr(ReadPSupported) res = data.Read(uname, cache, p, ind) && data.Read(vname, cache, p, ind); else if constexpr(ReadSupported) res = data.Read(uname, cache, ind) && data.Read(vname, cache, ind); if(!res) return UV(); return UV(cache.at(uname), cache.at(vname)); } template UVData> ReadUV(const D& data, const BaseParameters* p, const TIndex& tindex, VelSource usegeo) { using RT = ReadType; using UV = UVData; MString uname, vname; switch(usegeo) { case(VelSource::AUTOSEL): { if(data.CheckVar("u") == VarPresence::INTERNAL && data.CheckVar("v") == VarPresence::INTERNAL) { uname = "u"; vname = "v"; } else { uname = "ugs"; vname = "vgs"; } break; } case(VelSource::STANDART): { uname = "u"; vname = "v"; break; } case(VelSource::GEOSTROPHIC): { uname = "ugs"; vname = "vgs"; break; } case(VelSource::GEOSTROPHICSSH): { uname = "ugeo"; vname = "vgeo"; break; } } if(tindex.size() == 1) return ReadUV(data, p, tindex[0], usegeo); 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()); std::map cache; bool res = false; if constexpr(ReadPSupported) res = data.Read(uname, cache, p, ind) && data.Read(vname, cache, p, ind); else if constexpr(ReadSupported) res = data.Read(uname, cache, ind) && data.Read(vname, cache, ind); if(!res) return UV(); UV dat(cache.at(uname), cache.at(vname)); if(dat) out.Add(std::move(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, ""}; }