You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
7.0 KiB
258 lines
7.0 KiB
#pragma once |
|
#include "basedata.h" |
|
#include "mdatetime.h" |
|
#include "mregex.h" |
|
#include "uvdata.h" |
|
#include <variant> |
|
|
|
using michlib::BFileW; |
|
using michlib::MDateTime; |
|
|
|
using TIndex = std::vector<size_t>; |
|
|
|
enum class ActionID |
|
{ |
|
INFO, |
|
TSC, |
|
UV, |
|
GENINTFILE |
|
}; |
|
|
|
template<ActionID id> struct ActionCarrier |
|
{ |
|
constexpr static ActionID action = id; |
|
}; |
|
|
|
template<class T, ActionID id> struct IsActionSupportedTest |
|
{ |
|
static constexpr bool ans = false; |
|
}; |
|
|
|
template<class T> struct IsActionSupportedTest<T, ActionID::INFO> |
|
{ |
|
static constexpr bool ans = InfoSupported<T>; |
|
}; |
|
template<class T> struct IsActionSupportedTest<T, ActionID::TSC> |
|
{ |
|
static constexpr bool ans = ReadPSupported<T> || ReadSupported<T>; |
|
}; |
|
template<class T> struct IsActionSupportedTest<T, ActionID::UV> |
|
{ |
|
static constexpr bool ans = ReadPSupported<T> || ReadSupported<T>; |
|
}; |
|
template<class T> struct IsActionSupportedTest<T, ActionID::GENINTFILE> |
|
{ |
|
static constexpr bool ans = ReadIsGrid<T>; |
|
}; |
|
|
|
template<class T, ActionID id> constexpr bool IsActionSupported = IsActionSupportedTest<T, id>::ans; |
|
|
|
using ActionVariants = std::variant<ActionCarrier<ActionID::INFO>, ActionCarrier<ActionID::TSC>, ActionCarrier<ActionID::UV>, ActionCarrier<ActionID::GENINTFILE>>; |
|
|
|
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<ActionID::INFO>()); |
|
else if(act == "tsc") |
|
*this = ActionVariants(ActionCarrier<ActionID::TSC>()); |
|
else if(act == "uv") |
|
*this = ActionVariants(ActionCarrier<ActionID::UV>()); |
|
else if(act == "genintfile") |
|
*this = ActionVariants(ActionCarrier<ActionID::GENINTFILE>()); |
|
else |
|
return "Unknown action: " + act; |
|
return ""; |
|
} |
|
}; |
|
|
|
template<class D, ActionID id> struct DoAction_ |
|
{ |
|
static MString DoAction(const CLArgs& args, D& data) { return "Internal error"; } |
|
}; |
|
|
|
template<ActionID id, class D> MString DoAction(const CLArgs& args, D& data) { return DoAction_<D, id>::DoAction(args, data); } |
|
|
|
template<class D> 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<class D> std::pair<TIndex, MString> 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<class D> ReadType<D> Read(const D& data, const MString& vname, const BaseParameters* p, const TIndex& tindex) |
|
{ |
|
using RT = ReadType<D>; |
|
size_t ind; |
|
if(tindex.size() == 1) |
|
{ |
|
ind = tindex[0]; |
|
michlib::message("Time: " + data.Time(ind).ToTString()); |
|
if constexpr(ReadPSupported<D>) |
|
return data.Read(vname, p, ind); |
|
else if constexpr(ReadSupported<D>) |
|
return data.Read(vname, ind); |
|
} |
|
else |
|
{ |
|
Averager<RT> 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<D>) |
|
dat = data.Read(vname, p, ind); |
|
else if constexpr(ReadSupported<D>) |
|
dat = data.Read(vname, ind); |
|
if(dat) |
|
out.Add(dat); |
|
else |
|
ok = false; |
|
} |
|
if(ok) return out.Div(); |
|
} |
|
return RT(); |
|
} |
|
|
|
template<class D> UVData<ReadType<D>> ReadUV(const D& data, const BaseParameters* p, size_t ind) |
|
{ |
|
using RT = ReadType<D>; |
|
using UV = UVData<RT>; |
|
michlib::message("Time: " + data.Time(ind).ToTString()); |
|
RT u, v; |
|
if constexpr(ReadPSupported<D>) |
|
{ |
|
u = data.Read("u", p, ind); |
|
v = data.Read("v", p, ind); |
|
} |
|
else if constexpr(ReadSupported<D>) |
|
{ |
|
u = data.Read("u", ind); |
|
v = data.Read("v", ind); |
|
} |
|
return UV(u, v); |
|
} |
|
|
|
template<class D> UVData<ReadType<D>> ReadUV(const D& data, const BaseParameters* p, const TIndex& tindex) |
|
{ |
|
using RT = ReadType<D>; |
|
using UV = UVData<RT>; |
|
|
|
if(tindex.size() == 1) |
|
return ReadUV(data, p, tindex[0]); |
|
else |
|
{ |
|
Averager<UV> 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<D>) |
|
{ |
|
u = data.Read("u", p, ind); |
|
v = data.Read("v", p, ind); |
|
} |
|
else if constexpr(ReadSupported<D>) |
|
{ |
|
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(); |
|
}
|
|
|