Compare commits
13 Commits
e00de4e6cb
...
17b04d63de
Author | SHA1 | Date |
---|---|---|
Michael Uleysky | 17b04d63de | 10 months ago |
Michael Uleysky | 09e22b67cd | 10 months ago |
Michael Uleysky | 9e1f686ba6 | 10 months ago |
Michael Uleysky | 467a24e51c | 10 months ago |
Michael Uleysky | 0213249f78 | 11 months ago |
Michael Uleysky | 72d88e3c67 | 11 months ago |
Michael Uleysky | d37d5b6708 | 11 months ago |
Michael Uleysky | 153045016d | 11 months ago |
Michael Uleysky | a73f996ce5 | 11 months ago |
Michael Uleysky | fb7000b2ab | 11 months ago |
Michael Uleysky | 1c144c65c8 | 11 months ago |
Michael Uleysky | 5e244b8b4e | 12 months ago |
Michael Uleysky | 9b11464de2 | 12 months ago |
35 changed files with 911 additions and 469 deletions
@ -0,0 +1,17 @@
|
||||
#pragma once |
||||
#include "actiondep.h" |
||||
#include "merrors.h" |
||||
|
||||
using michlib::message; |
||||
|
||||
ADD_ACTION(Info, info, InfoSupported<Source>); |
||||
|
||||
template<class D> MString ActionInfo::DoAction(const CLArgs& args, D& data) |
||||
{ |
||||
auto resop = data.Open(args); |
||||
if(resop.Exist()) return "Can't open source: " + resop; |
||||
auto info = data.Info(); |
||||
if(!info.Exist()) return "No info"; |
||||
message(info); |
||||
return ""; |
||||
}; |
@ -0,0 +1,199 @@
|
||||
#pragma once |
||||
#include "BFileW.h" |
||||
#include "actiondep.h" |
||||
#include "ncfuncs.h" |
||||
#include <memory> |
||||
|
||||
using michlib::BFileW; |
||||
|
||||
ADD_ACTION(TSC, tsc, ReadPSupported<Source> || ReadSupported<Source>); |
||||
|
||||
template<class D> MString ActionTSC::DoAction(const CLArgs& args, D& ds) |
||||
{ |
||||
auto [reg, regerr] = GetRegion<D>(args); |
||||
if(regerr.Exist()) return regerr; |
||||
|
||||
auto resop = ds.Open(args); |
||||
if(resop.Exist()) return "Can't open source: " + resop; |
||||
|
||||
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<const BaseParameters> sourcepars; |
||||
if constexpr(ParametersSupported<D>) |
||||
{ |
||||
if constexpr(ParametersRequiredRegion<D>) |
||||
{ |
||||
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(); |
||||
|
||||
auto data = Read(ds, vname, p, tindexes); |
||||
if(!data) return "Can't read data"; |
||||
if(!data.Unit().Exist()) michlib::errmessage("Unknown measurement unit!"); |
||||
|
||||
MString outfmt = args.contains("format") ? args.at("format") : "bin"; |
||||
|
||||
if(outfmt == "bin") |
||||
{ |
||||
BFileW fw; |
||||
MString name = args.contains("out") ? args.at("out") : "out.bin"; |
||||
|
||||
fw.Create(name, 3); |
||||
fw.SetColumnName(1, "Longitude"); |
||||
fw.SetColumnName(2, "Latitude"); |
||||
fw.SetColumnName(3, vname + ", " + (data.Unit().Exist() ? data.Unit() : "unknown")); |
||||
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.IsFill(i) ? NAN : data(i)); |
||||
} |
||||
fw.Finalize(); |
||||
fw.Close(); |
||||
return ""; |
||||
} |
||||
|
||||
if(outfmt == "nc" || outfmt == "netcdf") |
||||
{ |
||||
MString name = args.contains("out") ? args.at("out") : "out.nc"; |
||||
int ret; |
||||
int ncid, dimid, dimidxy[2]; |
||||
int lonid, latid, vid; |
||||
MString text; |
||||
auto fill = std::numeric_limits<float>::max(); |
||||
float fval; |
||||
int compress = 3; |
||||
|
||||
if(args.contains("compress")) compress = args.at("compress").ToInt(); |
||||
|
||||
ret = nc_create(name.Buf(), NC_CLOBBER | NC_NETCDF4, &ncid); |
||||
if(ret != NC_NOERR) return "Can't create netcdf file: " + name; |
||||
|
||||
ret = nc_put_att_text(ncid, NC_GLOBAL, "history", args.at("_cmdline").Len() + 1, args.at("_cmdline").Buf()); |
||||
if(ret != NC_NOERR) return "Can't write history attribute in the netcdf file"; |
||||
|
||||
if constexpr(ReadIs2DGeoRectArray<D>) |
||||
{ |
||||
ret = nc_def_dim(ncid, "longitude", data.Nx(), &dimidxy[0]); |
||||
if(ret != NC_NOERR) return "Can't create x-dimension in the netcdf file"; |
||||
ret = nc_def_dim(ncid, "latitude", data.Ny(), &dimidxy[1]); |
||||
if(ret != NC_NOERR) return "Can't create y-dimension in the netcdf file"; |
||||
ret = nc_def_var(ncid, "longitude", NC_FLOAT, 1, &dimidxy[0], &lonid); |
||||
if(ret != NC_NOERR) return "Can't create longitude variable in the netcdf file"; |
||||
ret = nc_def_var(ncid, "latitude", NC_FLOAT, 1, &dimidxy[1], &latid); |
||||
if(ret != NC_NOERR) return "Can't create latitude variable in the netcdf file"; |
||||
ret = nc_def_var(ncid, vname.Buf(), NC_FLOAT, 2, dimidxy, &vid); |
||||
if(ret != NC_NOERR) return "Can't create " + vname + " variable in the netcdf file"; |
||||
} |
||||
else |
||||
{ |
||||
ret = nc_def_dim(ncid, "i", data.N(), &dimid); |
||||
if(ret != NC_NOERR) return "Can't create dimension in the netcdf file"; |
||||
ret = nc_def_var(ncid, "longitude", NC_FLOAT, 1, &dimid, &lonid); |
||||
if(ret != NC_NOERR) return "Can't create longitude variable in the netcdf file"; |
||||
ret = nc_def_var(ncid, "latitude", NC_FLOAT, 1, &dimid, &latid); |
||||
if(ret != NC_NOERR) return "Can't create latitude variable in the netcdf file"; |
||||
ret = nc_def_var(ncid, vname.Buf(), NC_FLOAT, 1, &dimid, &vid); |
||||
if(ret != NC_NOERR) return "Can't create " + vname + " variable in the netcdf file"; |
||||
} |
||||
|
||||
ret = nc_def_var_deflate(ncid, lonid, 1, 1, compress); |
||||
if(ret != NC_NOERR) return "Can't set deflate parameters for longitude variable in the netcdf file"; |
||||
ret = nc_def_var_deflate(ncid, latid, 1, 1, compress); |
||||
if(ret != NC_NOERR) return "Can't set deflate parameters for latitude variable in the netcdf file"; |
||||
ret = nc_def_var_deflate(ncid, vid, 1, 1, compress); |
||||
if(ret != NC_NOERR) return "Can't set deflate parameters for " + vname + " variable in the netcdf file"; |
||||
|
||||
text = "longitude"; |
||||
ret = nc_put_att_text(ncid, lonid, "standard_name", text.Len() + 1, text.Buf()); |
||||
if(ret != NC_NOERR) return "Can't write standard_name attribute of longitude variable in the netcdf file"; |
||||
text = "latitude"; |
||||
ret = nc_put_att_text(ncid, latid, "standard_name", text.Len() + 1, text.Buf()); |
||||
if(ret != NC_NOERR) return "Can't write standard_name attribute of latitude variable in the netcdf file"; |
||||
|
||||
text = NCFuncs::Name2StName(vname); |
||||
if(text.Exist()) |
||||
{ |
||||
ret = nc_put_att_text(ncid, vid, "standard_name", text.Len() + 1, text.Buf()); |
||||
if(ret != NC_NOERR) return "Can't write standard_name attribute of " + vname + " variable in the netcdf file"; |
||||
} |
||||
else |
||||
{ |
||||
text = NCFuncs::Name2LongName(vname); |
||||
ret = nc_put_att_text(ncid, vid, "long_name", text.Len() + 1, text.Buf()); |
||||
if(ret != NC_NOERR) return "Can't write long_name attribute of " + vname + " variable in the netcdf file"; |
||||
} |
||||
|
||||
ret = nc_put_att_float(ncid, vid, "_FillValue", NC_FLOAT, 1, &fill); |
||||
if(ret != NC_NOERR) return "Can't write _FillValue attribute of " + vname + " variable in the netcdf file"; |
||||
|
||||
ret = nc_enddef(ncid); |
||||
if(ret != NC_NOERR) return "Can't finish definition of the netcdf file"; |
||||
|
||||
if constexpr(ReadIs2DGeoRectArray<D>) |
||||
{ |
||||
size_t i[2]; |
||||
for(i[0] = 0; i[0] < data.Nx(); i[0]++) |
||||
{ |
||||
fval = data.Ix2Lon(i[0]); |
||||
ret = nc_put_var1_float(ncid, lonid, &i[0], &fval); |
||||
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file: " + MString(i[0]); |
||||
} |
||||
for(i[1] = 0; i[1] < data.Ny(); i[1]++) |
||||
{ |
||||
fval = data.Iy2Lat(i[1]); |
||||
ret = nc_put_var1_float(ncid, latid, &i[1], &fval); |
||||
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file: " + MString(i[1]); |
||||
} |
||||
for(i[0] = 0; i[0] < data.Nx(); i[0]++) |
||||
for(i[1] = 0; i[1] < data.Ny(); i[1]++) |
||||
{ |
||||
fval = data.IsFill(i[0], i[1]) ? fill : data(i[0], i[1]); |
||||
ret = nc_put_var1_float(ncid, vid, i, &fval); |
||||
if(ret != NC_NOERR) return "Can't write " + vname + " variable in the netcdf file: " + MString(i[0]) + ", " + i[1]; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
for(size_t i = 0; i < data.N(); i++) |
||||
{ |
||||
fval = data.Lon(i); |
||||
ret = nc_put_var1_float(ncid, lonid, &i, &fval); |
||||
if(ret != NC_NOERR) return "Can't write longitude variable in the netcdf file: " + MString(i); |
||||
fval = data.Lat(i); |
||||
ret = nc_put_var1_float(ncid, latid, &i, &fval); |
||||
if(ret != NC_NOERR) return "Can't write latitude variable in the netcdf file: " + MString(i); |
||||
fval = data.IsFill(i) ? fill : data(i); |
||||
ret = nc_put_var1_float(ncid, vid, &i, &fval); |
||||
if(ret != NC_NOERR) return "Can't write " + vname + " variable in the netcdf file: " + MString(i); |
||||
} |
||||
} |
||||
|
||||
ret = nc_close(ncid); |
||||
if(ret != NC_NOERR) return "Can't close netcdf file"; |
||||
|
||||
return ""; |
||||
} |
||||
|
||||
return "Unknown format: " + outfmt; |
||||
}; |
@ -0,0 +1,216 @@
|
||||
#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 |
||||
#else |
||||
#define ADD_ACTION(actclass, actname, suptest, ...) \ |
||||
class Action##actclass __VA_OPT__( : public) __VA_ARGS__ \
|
||||
{ \
|
||||
public: \
|
||||
static constexpr const char* name = #actname; \
|
||||
template<class Source> static constexpr bool IsSupported = (suptest); \
|
||||
template<class Source> static MString DoAction(const CLArgs& args, Source& data); \
|
||||
}; |
||||
#endif |
||||
|
||||
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(); |
||||
} |
||||
|
||||
template<class D> std::pair<struct Region, MString> GetRegion(const CLArgs& args) |
||||
{ |
||||
struct Region reg; |
||||
if constexpr(!ParametersRequiredRegion<D>) 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, ""}; |
||||
} |
@ -1,17 +0,0 @@
|
||||
#pragma once |
||||
#include "actions.h" |
||||
|
||||
using michlib::message; |
||||
|
||||
template<class D> struct DoAction_<D, ActionID::INFO> |
||||
{ |
||||
static MString DoAction(const CLArgs& args, D& data); |
||||
}; |
||||
|
||||
template<class D> MString DoAction_<D, ActionID::INFO>::DoAction([[maybe_unused]] const CLArgs& args, D& data) |
||||
{ |
||||
auto info = data.Info(); |
||||
if(!info.Exist()) return "No info"; |
||||
message(info); |
||||
return ""; |
||||
}; |
@ -1,54 +0,0 @@
|
||||
#pragma once |
||||
#include "actions.h" |
||||
|
||||
template<class D> struct DoAction_<D, ActionID::TSC> |
||||
{ |
||||
static MString DoAction(const CLArgs& args, D& data); |
||||
}; |
||||
|
||||
template<class D> MString DoAction_<D, ActionID::TSC>::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<const BaseParameters> sourcepars; |
||||
if constexpr(ParametersSupported<D>) |
||||
{ |
||||
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 ""; |
||||
}; |
@ -0,0 +1,109 @@
|
||||
#pragma once |
||||
#include "actions.h" |
||||
#include "data.h" |
||||
#include <array> |
||||
|
||||
template<class A, class D> struct CompatTableS; |
||||
|
||||
template<template<class...> class A, template<class...> class D, class... Acts, class... Datas> struct CompatTableS<A<Acts...>, D<Datas...>> |
||||
{ |
||||
size_t static consteval StrLen(const char* str) { return *str ? 1 + StrLen(str + 1) : 0; } |
||||
|
||||
template<class D1, class... Dd> static consteval size_t MaxNameLen() |
||||
{ |
||||
if constexpr(sizeof...(Dd) == 0) |
||||
return StrLen(D1::name); |
||||
else |
||||
return std::max(StrLen(D1::name), MaxNameLen<Dd...>()); |
||||
} |
||||
|
||||
static constexpr size_t W = MaxNameLen<Datas...>(); |
||||
|
||||
template<size_t N> static consteval auto C2A(const char (&s)[N]) |
||||
{ |
||||
std::array<char, N> out; |
||||
for(size_t i = 0; i < N; i++) out[i] = s[i]; |
||||
return out; |
||||
} |
||||
|
||||
static constexpr auto em = C2A(""); |
||||
static constexpr auto sp = C2A(" "); |
||||
static constexpr auto nd = C2A("\n"); |
||||
|
||||
template<class T> static consteval auto N2A() |
||||
{ |
||||
std::array<char, StrLen(T::name) + 1> out; |
||||
for(size_t i = 0; i <= StrLen(T::name); i++) out[i] = T::name[i]; |
||||
return out; |
||||
} |
||||
template<class T> static constexpr auto name = N2A<T>(); |
||||
|
||||
template<size_t N, size_t M, class... T> static consteval auto Merge(const std::array<char, N>& arg1, const std::array<char, M>& arg2, const T&... args) |
||||
{ |
||||
if constexpr(sizeof...(T) == 0) |
||||
{ |
||||
std::array<char, N + M - 1> out; |
||||
for(size_t i = 0; i < N - 1; i++) out[i] = arg1[i]; |
||||
for(size_t i = 0; i < M; i++) out[i + N - 1] = arg2[i]; |
||||
return out; |
||||
} |
||||
else |
||||
return Merge(arg1, Merge(arg2, args...)); |
||||
} |
||||
|
||||
template<size_t n> static consteval auto Spaces() |
||||
{ |
||||
if constexpr(n == 0) |
||||
return em; |
||||
else |
||||
return Merge(sp, Spaces<n - 1>()); |
||||
} |
||||
|
||||
template<size_t n, class T> static consteval auto AlignR(const T& s) |
||||
{ |
||||
constexpr size_t len = std::tuple_size_v<T> - 1; |
||||
if constexpr(len > n) return s; |
||||
return Merge(Spaces<n - len>(), s); |
||||
} |
||||
|
||||
template<size_t n, class T> static consteval auto AlignL(const T& s) |
||||
{ |
||||
constexpr size_t len = std::tuple_size_v<T> - 1; |
||||
if constexpr(len > n) return s; |
||||
return Merge(s, Spaces<n - len>()); |
||||
} |
||||
|
||||
template<class A1, class... Aa> static consteval auto MergeNames() |
||||
{ |
||||
if constexpr(sizeof...(Aa) == 0) |
||||
return name<A1>; |
||||
else |
||||
return Merge(name<A1>, sp, MergeNames<Aa...>()); |
||||
} |
||||
|
||||
static constexpr auto header = Merge(Spaces<W>(), MergeNames<Acts...>()); |
||||
|
||||
template<class Dat, class A1, class... Aa> static consteval auto MergeSup() |
||||
{ |
||||
constexpr bool issup = A1::template IsSupported<Dat> && !IsDisabled<A1, Dat>(); |
||||
constexpr auto v = Merge(Spaces<StrLen(A1::name) - 1>(), C2A(issup ? "\033[32mY\033[0m" : "\033[31mN\033[0m")); |
||||
//constexpr auto v = AlignR<StrLen(A1::name)>(C2A(issup ? "X" : " "));
|
||||
if constexpr(sizeof...(Aa) == 0) |
||||
return v; |
||||
else |
||||
return Merge(v, sp, MergeSup<Dat, Aa...>()); |
||||
} |
||||
|
||||
template<class D1, class... Dd> static consteval auto MergeRows() |
||||
{ |
||||
constexpr auto r = Merge(AlignL<W>(name<D1>), MergeSup<D1, Acts...>()); |
||||
if constexpr(sizeof...(Dd) == 0) |
||||
return r; |
||||
else |
||||
return Merge(r, nd, MergeRows<Dd...>()); |
||||
} |
||||
|
||||
static constexpr auto value = Merge(header, nd, MergeRows<Datas...>()); |
||||
}; |
||||
|
||||
static constexpr auto CompatTable = CompatTableS<ActionVariants, DataVariants>::value.data(); |
@ -0,0 +1,20 @@
|
||||
#pragma once |
||||
#include <variant> |
||||
|
||||
namespace internal |
||||
{ |
||||
template<class T1, class... T, class... Vargs> bool InitV1(std::variant<Vargs...>& v, const michlib::MString& n) |
||||
{ |
||||
if(T1::name != n) |
||||
{ |
||||
if constexpr(sizeof...(T) > 0) |
||||
return InitV1<T...>(v, n); |
||||
else |
||||
return false; |
||||
} |
||||
v = T1(); |
||||
return true; |
||||
} |
||||
|
||||
template<class... Vargs> bool InitV(std::variant<Vargs...>& v, const michlib::MString& n) { return InitV1<Vargs...>(v, n); } |
||||
} // namespace internal
|
@ -1,13 +1,71 @@
|
||||
set(EXENAME odm) |
||||
set(ACTIONLISTINC ${CMAKE_CURRENT_BINARY_DIR}/../include/actionlist.h) # Include actions files and define the actions classes list |
||||
set(DATALISTINC ${CMAKE_CURRENT_BINARY_DIR}/../include/datalist.h) # Include data sources files and define the data sources classes list |
||||
|
||||
find_library(netcdf netcdf REQUIRED) |
||||
find_package(OpenMP REQUIRED) |
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") |
||||
|
||||
include_directories(../michlib/michlib) |
||||
file(GLOB srcs CONFIGURE_DEPENDS *.cpp) |
||||
add_executable(${EXENAME} ${srcs} ${ACTIONLISTINC} ${SOURCELISTINC}) |
||||
target_include_directories(${EXENAME} PRIVATE ../michlib/michlib ${CMAKE_CURRENT_BINARY_DIR}/../include) |
||||
|
||||
file(GLOB srcs *.cpp) |
||||
add_executable(${EXENAME} ${srcs}) |
||||
target_link_libraries(${EXENAME} ${linker_options} ${netcdf} OpenMP::OpenMP_CXX teos) |
||||
set_target_properties(${EXENAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) |
||||
install(TARGETS ${EXENAME}) |
||||
|
||||
# Begin generation of actions list |
||||
get_target_property(INCS ${EXENAME} INCLUDE_DIRECTORIES) |
||||
list(TRANSFORM INCS PREPEND "-I") |
||||
|
||||
separate_arguments(excluded UNIX_COMMAND "${EXCLUDE_ACTIONS}") |
||||
|
||||
file(GLOB actfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS ../actions/action*.h ../actions-add/action*.h) |
||||
foreach(actfile ${actfiles}) |
||||
execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${INCS} -E -DGENACTIONLIST ${actfile} OUTPUT_VARIABLE outfull ERROR_VARIABLE err WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) |
||||
string(REGEX MATCH "ADD ACTION CLASS: [^ ;\n]+" outstr "${outfull}") |
||||
string(REGEX REPLACE ".+: " "" act "${outstr}") |
||||
if(NOT (("${act}" EQUAL "") OR ("${act}" IN_LIST excluded))) |
||||
message("Action: ${Yellow}${act}${ColorReset} in file ${actfile}") |
||||
list(APPEND actlist ${act}) |
||||
list(APPEND actfilelist ${actfile}) |
||||
endif() |
||||
endforeach(actfile) |
||||
|
||||
list(TRANSFORM actlist PREPEND "Action") |
||||
string(REPLACE ";" "," actclist "${actlist}") |
||||
file(WRITE ${ACTIONLISTINC} "#define ACTLIST ${actclist}\n") |
||||
|
||||
foreach(actfile ${actfilelist}) |
||||
string(REGEX REPLACE "\.h$" ".cpp" actcpp "${actfile}") |
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${actcpp} ) |
||||
target_sources(${EXENAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${actcpp}) |
||||
endif() |
||||
file(APPEND ${ACTIONLISTINC} "#include \"${actfile}\"\n") |
||||
endforeach(actfile) |
||||
# End generation of actions list |
||||
|
||||
# Begin generation of data sources list |
||||
separate_arguments(excluded UNIX_COMMAND "${EXCLUDE_SOURCES}") |
||||
file(GLOB sourcefiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS ../sources/*.h ../sources-add/*.h) |
||||
foreach(sourcefile ${sourcefiles}) |
||||
string(REGEX REPLACE "(\.h$|.*/)" "" source "${sourcefile}") |
||||
string(REGEX REPLACE "\.h$" ".cpp" sourcecpp "${sourcefile}") |
||||
if(NOT (("${source}" EQUAL "") OR ("${source}" IN_LIST excluded))) |
||||
message("Source: ${Cyan}${source}${ColorReset} in file ${sourcefile}") |
||||
list(APPEND sourcelist ${source}) |
||||
list(APPEND sourcefilelist ${sourcefile}) |
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${sourcecpp} ) |
||||
target_sources(${EXENAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${sourcecpp}) |
||||
endif() |
||||
endif() |
||||
endforeach(sourcefile) |
||||
|
||||
list(TRANSFORM sourcelist APPEND "Data") |
||||
string(REPLACE ";" "," sourceclist "${sourcelist}") |
||||
file(WRITE ${DATALISTINC} "#define DATALIST ${sourceclist}\n") |
||||
|
||||
foreach(sourcefile ${sourcefilelist}) |
||||
file(APPEND ${DATALISTINC} "#include \"${sourcefile}\"\n") |
||||
endforeach(sourcefile) |
||||
# End generation of sources list |
||||
|
Loading…
Reference in new issue