Compare commits

...

13 Commits

  1. 2
      .gitignore
  2. 20
      CMakeLists.txt
  3. 34
      actions/actiongenintfile.h
  4. 17
      actions/actioninfo.h
  5. 199
      actions/actiontsc.h
  6. 34
      actions/actionuv.h
  7. 216
      include/actiondep.h
  8. 17
      include/actioninfo.h
  9. 249
      include/actions.h
  10. 54
      include/actiontsc.h
  11. 16
      include/basedata.h
  12. 109
      include/compattable.h
  13. 13
      include/data.h
  14. 2
      include/layereddata.h
  15. 2
      include/ncfuncs.h
  16. 9
      include/odm.h
  17. 19
      include/simple2ddata.h
  18. 60
      include/traits.h
  19. 20
      include/varhelpers.h
  20. 2
      sources/AVISO.h
  21. 26
      sources/AVISOLOCAL.cpp
  22. 4
      sources/AVISOLOCAL.h
  23. 3
      sources/BINFILE.cpp
  24. 4
      sources/BINFILE.h
  25. 2
      sources/HYCOM.h
  26. 19
      sources/MODISBINLOCAL.cpp
  27. 14
      sources/MODISBINLOCAL.h
  28. 2
      sources/NEMO.h
  29. 4
      sources/NEMOBIO.h
  30. 64
      src/CMakeLists.txt
  31. 7
      src/ParseArgs.cpp
  32. 54
      src/data.cpp
  33. 30
      src/layereddata.cpp
  34. 43
      src/ncfuncs.cpp
  35. 10
      src/odm.cpp

2
.gitignore vendored

@ -2,3 +2,5 @@
*.so
*.kdev4
.kdev4/*
actions-add/*
sources-add/*

20
CMakeLists.txt

@ -13,6 +13,24 @@ if(${srcdir} STREQUAL ${bindir})
" Please remove them.")
endif()
string(ASCII 27 Esc)
set(ColorReset "${Esc}[m")
set(ColorBold "${Esc}[1m")
set(Red "${Esc}[31m")
set(Green "${Esc}[32m")
set(Yellow "${Esc}[33m")
set(Blue "${Esc}[34m")
set(Magenta "${Esc}[35m")
set(Cyan "${Esc}[36m")
set(White "${Esc}[37m")
set(BoldRed "${Esc}[1;31m")
set(BoldGreen "${Esc}[1;32m")
set(BoldYellow "${Esc}[1;33m")
set(BoldBlue "${Esc}[1;34m")
set(BoldMagenta "${Esc}[1;35m")
set(BoldCyan "${Esc}[1;36m")
set(BoldWhite "${Esc}[1;37m")
set(STATIC_ANALYZER OFF CACHE BOOL "Using GCC static analyzer if available")
project(odm C CXX)
@ -20,7 +38,7 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
include_directories(include GSW-C)
include_directories(include sources sources-add GSW-C)
add_compile_options(-Wall)
# Dwarf-4 support check

34
include/actiongenintfile.h → actions/actiongenintfile.h

@ -1,15 +1,22 @@
#pragma once
#include "actions.h"
#include "BFileW.h"
#include "actiondep.h"
#include <memory>
using michlib::BFileW;
using michlib::Cos;
using michlib::M_PI;
template<class D> struct DoAction_<D, ActionID::GENINTFILE>
{
static MString DoAction(const CLArgs& args, D& data);
};
ADD_ACTION(GenIntFile, genintfile, ReadIsGrid<Source>);
template<class D> MString DoAction_<D, ActionID::GENINTFILE>::DoAction(const CLArgs& args, D& ds)
template<class D> MString ActionGenIntFile::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"));
@ -26,9 +33,18 @@ template<class D> MString DoAction_<D, ActionID::GENINTFILE>::DoAction(const CLA
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);
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();

17
actions/actioninfo.h

@ -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 "";
};

199
actions/actiontsc.h

@ -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;
};

34
include/actionuv.h → actions/actionuv.h

@ -1,13 +1,20 @@
#pragma once
#include "actions.h"
#include "BFileW.h"
#include "actiondep.h"
#include <memory>
template<class D> struct DoAction_<D, ActionID::UV>
{
static MString DoAction(const CLArgs& args, D& data);
};
using michlib::BFileW;
ADD_ACTION(UV, uv, ReadPSupported<Source> || ReadSupported<Source>);
template<class D> MString DoAction_<D, ActionID::UV>::DoAction(const CLArgs& args, D& ds)
template<class D> MString ActionUV::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"));
@ -18,9 +25,18 @@ template<class D> MString DoAction_<D, ActionID::UV>::DoAction(const CLArgs& arg
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);
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();

216
include/actiondep.h

@ -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, ""};
}

17
include/actioninfo.h

@ -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 "";
};

249
include/actions.h

@ -1,53 +1,8 @@
#pragma once
#include "basedata.h"
#include "mdatetime.h"
#include "mregex.h"
#include "uvdata.h"
#include <variant>
#include "actionlist.h"
#include "varhelpers.h"
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>>;
using ActionVariants = std::variant<ACTLIST>;
class Action: public ActionVariants
{
@ -57,202 +12,8 @@ class Action: public ActionVariants
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;
bool res = internal::InitV(*this, act);
if(!res) 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();
}

54
include/actiontsc.h

@ -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 "";
};

16
include/basedata.h

@ -2,19 +2,27 @@
#include "traits.h"
#include <vector>
using TIndex = std::vector<size_t>;
class BaseParameters
{
public:
virtual ~BaseParameters();
};
struct Region
{
real lonb, lone, latb, late;
};
class BaseData
{
protected:
static constexpr real fillval = 1.0e10;
std::vector<real> data;
MString unit;
BaseData(size_t n): data(n) {}
BaseData(size_t n, MString&& unit_ = ""): data(n), unit(std::move(unit_)) {}
public:
BaseData() = default;
@ -32,6 +40,10 @@ class BaseData
static real Fillval() { return fillval; }
explicit operator bool() const { return N() != 0; }
void SetUnit(const MString& str) { unit = str; }
const MString& Unit() const { return unit; }
};
class UngriddedData: public BaseData
@ -39,7 +51,7 @@ class UngriddedData: public BaseData
std::vector<real> lons, lats;
public:
template<class Lon, class Lat> UngriddedData(size_t n, Lon genlon, Lat genlat): BaseData(n), lons(n), lats(n)
template<class Lon, class Lat> UngriddedData(size_t n, Lon genlon, Lat genlat, MString&& unit = ""): BaseData(n, std::move(unit)), lons(n), lats(n)
{
for(size_t i = 0; i < n; i++)
{

109
include/compattable.h

@ -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();

13
include/data.h

@ -1,14 +1,9 @@
#pragma once
#include "AVISO.h"
#include "AVISOLOCAL.h"
#include "BINFILE.h"
#include "HYCOM.h"
#include "MODISBINLOCAL.h"
#include "NEMO.h"
#include "NEMOBIO.h"
#include <variant>
#include "datalist.h"
#include "varhelpers.h"
#include <utility>
using DataVariants = std::variant<NEMOData, NEMOBIOData, HYCOMData, AVISOData, AVISOLOCALData, BINFILEData, MODISBINLOCALData>;
using DataVariants = std::variant<DATALIST>;
class Data: public DataVariants
{
public:

2
include/layereddata.h

@ -133,7 +133,7 @@ class LayeredData: public NCFuncs
public:
MString Info() const;
std::pair<const BaseParameters*, MString> Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const;
std::pair<const BaseParameters*, MString> 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;

2
include/ncfuncs.h

@ -18,6 +18,8 @@ class NCFuncs
};
static MString StName2Name(const MString& stname);
static MString Name2StName(const MString& name);
static MString Name2LongName(const MString& name);
static std::tuple<MDateTime, time_t, bool> Refdate(const MString& refdate);
static void GetVars(const NCFileA& nc, std::set<MString>& vars);
static CoordNames GetCNames(const NCFileA& nc);

9
include/odm.h

@ -1,12 +1,10 @@
#pragma once
#include "actiongenintfile.h"
#include "actioninfo.h"
#include "actiontsc.h"
#include "actionuv.h"
#include "data.h"
#include "compattable.h"
using michlib::errmessage;
using michlib::message;
/*
template<class T, ActionID id> consteval bool MustSup()
{
static_assert(IsActionSupported<T, id>);
@ -37,3 +35,4 @@ template<> constexpr bool DisableAction<MODISBINLOCALData, ActionID::UV>
template<> constexpr bool DisableAction<MODISBINLOCALData, ActionID::GENINTFILE> = true;
template<> constexpr bool DisableAction<NEMOBIOData, ActionID::UV> = true;
template<> constexpr bool DisableAction<NEMOBIOData, ActionID::GENINTFILE> = true;
*/

19
include/simple2ddata.h

@ -8,15 +8,15 @@ class Simple2DData: public BaseData
real xstep = 0.0, ystep = 0.0;
public:
using BaseData::IsFill;
using BaseData::V;
using BaseData::operator();
Simple2DData() = default;
Simple2DData(size_t nx_, size_t ny_, real x0_, real y0_, real xs_, real ys_): BaseData(nx_ * ny_), x0(x0_), y0(y0_), nx(nx_), ny(ny_), xstep(xs_), ystep(ys_) {}
const real& V(size_t i) const { return BaseData::V(i); }
real& V(size_t i) { return BaseData::V(i); }
const real& operator()(size_t i) const { return BaseData::V(i); }
real& operator()(size_t i) { return BaseData::V(i); }
Simple2DData(size_t nx_, size_t ny_, real x0_, real y0_, real xs_, real ys_, MString&& unit = ""):
BaseData(nx_ * ny_, std::move(unit)), x0(x0_), y0(y0_), nx(nx_), ny(ny_), xstep(xs_), ystep(ys_)
{
}
const real& V(size_t ix, size_t iy) const { return V(iy * nx + ix); }
real& V(size_t ix, size_t iy) { return V(iy * nx + ix); }
@ -27,12 +27,17 @@ class Simple2DData: public BaseData
size_t Nx() const { return nx; }
size_t Ny() const { return ny; }
bool IsFill(size_t ix, size_t iy) const { return IsFill(iy * nx + ix); }
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); }
real Ix2Lon(size_t ix) const { return x0 + ix * xstep; }
real Iy2Lat(size_t iy) const { return y0 + iy * ystep; }
real XStep() const { return xstep; }
real YStep() const { return ystep; }
};

60
include/traits.h

@ -13,12 +13,22 @@ concept InfoSupported = requires(T t) {
};
template<class T>
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<const BaseParameters*>;
};
template<class T>
concept ParametersNotRequiredRegion = requires(T t, michlib_internal::ParameterListEx& pars, const CLArgs& args) {
{
t.Parameters(pars, args).first
} -> std::convertible_to<const BaseParameters*>;
};
template<class T>
concept ParametersSupported = ParametersRequiredRegion<T> || ParametersNotRequiredRegion<T>;
template<class T>
concept ReadPSupported = requires(T t, const MString& vname, const BaseParameters* ip, size_t i) {
{
@ -56,10 +66,7 @@ concept HaveXYStep = requires(T t) {
t.YStep()
} -> std::convertible_to<real>;
};
}
namespace internal
{
template<typename...> using void_ = void;
template<class D, bool RP, bool R> struct GetReadType_;
@ -75,8 +82,43 @@ template<class D> struct GetReadType_<D, false, true>
using type = decltype(D().Read(MString(), 0));
};
template<class T>
concept HaveDisable = requires(T t) {
{
T::disabledactions
} -> std::convertible_to<const char*>;
};
consteval bool cmpspace(const char* s1, const char* s2)
{
size_t i = 0;
while(true)
{
if(s1[i] != s2[i]) return false;
i++;
if(s1[i] == 0 && (s2[i] == 0 || s2[i] == ' ')) return true;
if(s1[i] == 0 || s2[i] == 0 || s2[i] == ' ') return false;
}
return false;
}
} // namespace internal
template<class Act, class S> consteval bool IsDisabled()
{
if constexpr(!internal::HaveDisable<S>)
return false;
else
{
bool prsp = true;
size_t i = 0;
do {
if(prsp && internal::cmpspace(Act::name, S::disabledactions + i)) return true;
prsp = S::disabledactions[i] == ' ';
} while(S::disabledactions[++i] != 0);
return false;
}
}
template<class D> using ReadType = internal::GetReadType_<D, ReadPSupported<D>, ReadSupported<D>>::type;
template<class T>
@ -88,3 +130,13 @@ concept ReadIsGrid = requires {
ReadType<T>().YStep()
} -> std::convertible_to<real>;
};
template<class T>
concept ReadIs2DGeoRectArray = requires {
{
ReadType<T>().Ix2Lon(0)
} -> std::convertible_to<real>;
{
ReadType<T>().Iy2Lat(0)
} -> std::convertible_to<real>;
};

20
include/varhelpers.h

@ -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

2
include/AVISO.h → sources/AVISO.h

@ -15,6 +15,8 @@ class AVISOData: public LayeredData
Type type = TYPE_UNKNOWN;
public:
static constexpr const char* name = "AVISO";
AVISOData() = default;
MString DataTitle() const

26
src/AVISOLOCAL.cpp → sources/AVISOLOCAL.cpp

@ -70,14 +70,13 @@ MString AVISOLOCALData::Open(const CLArgs& args)
return "";
}
std::pair<const BaseParameters*, MString> AVISOLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const
std::pair<const BaseParameters*, MString> AVISOLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const
{
std::unique_ptr<struct Parameters> 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);
@ -124,6 +123,7 @@ AVISOLOCALData::Data AVISOLOCALData::Read(const MString& vname, const BaseParame
auto v = Read("v", ip, i);
if(!(u && v)) return Data();
auto out = u;
out.SetUnit(square ? ("(" + u.Unit() + ")2") : u.Unit());
for(size_t ind = 0; ind < out.N(); ind++)
{
if(u.IsFill(ind) || v.IsFill(ind))
@ -197,10 +197,18 @@ template<class DataType> AVISOLOCALData::Data AVISOLOCALData::ReadVarRaw(const N
if(xb == xe) return Data();
auto unit = nc.A<MString>(name, "units");
if(unit && (unit.Get() == "m s-1" || unit.Get() == "m/s")) unitmul = 100.0;
MString unit;
{
auto unitatt = nc.A<MString>(name, "units");
if(unitatt) unit = unitatt;
}
if(unit == "m s-1" || unit == "m/s")
{
unitmul = 100.0;
unit = "cm/s";
}
Data data((xb < xe) ? (xe - xb + 1) : (dn.nx + xe - xb + 1), ye - yb + 1, lons(xb), lats(yb), lonstep, latstep);
Data data((xb < xe) ? (xe - xb + 1) : (dn.nx + xe - xb + 1), ye - yb + 1, lons(xb), lats(yb), lonstep, latstep, std::move(unit));
if(xb < xe)
{

4
include/AVISOLOCAL.h → sources/AVISOLOCAL.h

@ -25,6 +25,8 @@ class AVISOLOCALData: public NCFuncs
};
public:
static constexpr const char* name = "AVISOLOCAL";
using Data = Simple2DData;
AVISOLOCALData() = default;
@ -35,7 +37,7 @@ class AVISOLOCALData: public NCFuncs
// TODO: RetVal
MString Open(const CLArgs& args);
std::pair<const BaseParameters*, MString> Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const;
std::pair<const BaseParameters*, MString> Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const;
bool isOk() const { return times.size() > 0; }

3
src/BINFILE.cpp → sources/BINFILE.cpp

@ -60,7 +60,7 @@ BINFILEData::Data BINFILEData::Read(const MString& vname, size_t i) const
// Only rectangular grids are supported
real xs = (data->Lon(data->Nx() - 1, data->Ny() - 1) - data->Lon(0, 0)) / (data->Nx() - 1);
real ys = (data->Lat(data->Nx() - 1, data->Ny() - 1) - data->Lat(0, 0)) / (data->Ny() - 1);
Data out(data->Nx(), data->Ny(), data->Lon(0, 0), data->Lat(0, 0), xs, ys);
Data out(data->Nx(), data->Ny(), data->Lon(0, 0), data->Lat(0, 0), xs, ys, "cm/s"); // TODO: Information about unit must be taken from datafile
// U and U2 from u and v
if(vname == "U" || vname == "U2")
@ -70,6 +70,7 @@ BINFILEData::Data BINFILEData::Read(const MString& vname, size_t i) const
auto v = Read("v", i);
if(!(u && v)) return Data();
auto out = u;
out.SetUnit(square ? ("(" + u.Unit() + ")2") : u.Unit());
for(size_t ind = 0; ind < out.N(); ind++)
{
if(u.IsFill(ind) || v.IsFill(ind))

4
include/BINFILE.h → sources/BINFILE.h

@ -16,6 +16,10 @@ class BINFILEData
std::unique_ptr<michlib::IntData> data;
public:
static constexpr const char* name = "BINFILE";
static constexpr const char* disabledactions = "genintfile";
using Data = Simple2DData;
BINFILEData() = default;

2
include/HYCOM.h → sources/HYCOM.h

@ -14,6 +14,8 @@ class HYCOMData: public LayeredData
Type type = TYPE_UNKNOWN;
public:
static constexpr const char* name = "HYCOM";
HYCOMData() = default;
MString DataTitle() const

19
src/MODISBINLOCAL.cpp → sources/MODISBINLOCAL.cpp

@ -66,14 +66,14 @@ MString MODISBINLOCALData::Open(const CLArgs& args)
return "";
}
std::pair<const BaseParameters*, MString> MODISBINLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const
std::pair<const BaseParameters*, MString> MODISBINLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const
{
std::unique_ptr<struct Parameters> 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);
@ -103,11 +103,15 @@ MODISBINLOCALData::Data MODISBINLOCALData::ReadFile(const MString& suf, const st
michlib::message("Reading " + datapath + "/" + times[tind].ToString() + "_" + suf + ".nc");
nc.Reset(datapath + "/" + times[tind].ToString() + "_" + suf + ".nc");
if(!nc) return Data();
MString dname;
MString dname, unit;
if(suf == "A_CHL" || suf == "T_CHL") dname = "chlor_a";
if(suf == "A_SST" || suf == "T_SST") dname = "sst";
if(suf == "A_NSST" || suf == "T_NSST") dname = "sst";
if(suf == "A_SST4" || suf == "T_SST4") dname = "sst4";
if(suf == "A_CHL" || suf == "T_CHL")
unit = "mg m-3";
else
unit = "degrees_C";
struct BinIndexType
{
@ -231,6 +235,7 @@ MODISBINLOCALData::Data MODISBINLOCALData::ReadFile(const MString& suf, const st
Data out(
bins.size(), [&bins = std::as_const(bins), &Lon = Lon](size_t i) { return Lon(bins[i]); }, [&bins = std::as_const(bins), &Lat = Lat](size_t i) { return Lat(bins[i]); });
for(size_t i = 0; i < out.N(); i++) out(i) = out.Fillval();
out.SetUnit(unit);
for(size_t i = 0; i < loc.size(); i++)
{

14
include/MODISBINLOCAL.h → sources/MODISBINLOCAL.h

@ -1,21 +1,21 @@
#pragma once
#include "DataAdapters/ncfilealt.h"
#include "ParseArgs.h"
#include "basedata.h"
#include "mdatetime.h"
#include "mregex.h"
#include "DataAdapters/ncfilealt.h"
#include <dirent.h>
#include <set>
#include <utility>
using michlib::Ceil;
using michlib::Floor;
using michlib::GPL;
using michlib::MDateTime;
using michlib::pointer_cast;
using michlib::RegExp;
using michlib::uint2;
using michlib::uint4;
using michlib::Floor;
using michlib::Ceil;
using michlib::pointer_cast;
class MODISBINLOCALData
{
@ -32,6 +32,10 @@ class MODISBINLOCALData
};
public:
static constexpr const char* name = "MODISBINLOCAL";
static constexpr const char* disabledactions = "genintfile uv";
using Data = UngriddedData;
MString Info() const;
@ -39,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<const BaseParameters*, MString> Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const;
std::pair<const BaseParameters*, MString> Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const;
bool CheckVar(const MString& vname) const
{

2
include/NEMO.h → sources/NEMO.h

@ -14,6 +14,8 @@ class NEMOData: public LayeredData
Type type = TYPE_UNKNOWN;
public:
static constexpr const char* name = "NEMO";
NEMOData() = default;
MString DataTitle() const

4
include/NEMOBIO.h → sources/NEMOBIO.h

@ -13,6 +13,10 @@ class NEMOBIOData: public LayeredData
Type type = TYPE_UNKNOWN;
public:
static constexpr const char* name = "NEMOBIO";
static constexpr const char* disabledactions = "genintfile uv";
NEMOBIOData() = default;
MString DataTitle() const

64
src/CMakeLists.txt

@ -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

7
src/ParseArgs.cpp

@ -5,12 +5,15 @@ CLArgs ParseArgs(int argc, char** argv)
{
CLArgs out;
out["_name"] = argv[0];
for(int i = 0; i < argc; i++)
out["_nargs"] = MString(argc);
out["_cmdline"] = out["_name"] = out["_arg0"] = argv[0];
for(int i = 1; i < argc; i++)
{
MString carg = argv[i];
out["_arg" + MString(i)] = carg;
bool namevalue = false;
out["_cmdline"] += " " + carg;
for(size_t c = 0; c < carg.Len(); c++)
if(carg[c] == '=')

54
src/data.cpp

@ -5,56 +5,8 @@ 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 == "NEMOBIO")
{
NEMOBIOData 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 if(src == "BINFILE")
{
BINFILEData 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 == "MODISBINLOCAL")
{
MODISBINLOCALData 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;
bool res = internal::InitV(*this, src);
if(!res) return "Unknown source: " + src;
return "";
}

30
src/layereddata.cpp

@ -125,7 +125,7 @@ MString LayeredData::Open(const MString& dataset)
return "";
}
std::pair<const BaseParameters*, MString> LayeredData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) const
std::pair<const BaseParameters*, MString> LayeredData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const
{
std::unique_ptr<struct Parameters> ppar{new struct Parameters};
@ -133,14 +133,12 @@ std::pair<const BaseParameters*, MString> 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;
@ -196,6 +194,7 @@ LayeredData::Data LayeredData::Read(const MString& vname, const BaseParameters*
auto sal = Read("sal", ip, i);
if(!(temp && sal)) return Data();
auto out = temp;
out.SetUnit("degrees_C");
for(size_t ind = 0; ind < out.N(); ind++)
{
if(temp.IsFill(ind) || sal.IsFill(ind))
@ -212,6 +211,7 @@ LayeredData::Data LayeredData::Read(const MString& vname, const BaseParameters*
auto sal = Read("sal", ip, i);
if(!(temp && sal)) return Data();
auto out = temp;
out.SetUnit("degrees_C");
for(size_t ind = 0; ind < out.N(); ind++)
{
if(temp.IsFill(ind) || sal.IsFill(ind))
@ -229,6 +229,7 @@ LayeredData::Data LayeredData::Read(const MString& vname, const BaseParameters*
auto sal = Read("sal", ip, i);
if(!(temp && sal)) return Data();
auto out = temp;
out.SetUnit("kg m-3");
for(size_t ind = 0; ind < out.N(); ind++)
{
if(temp.IsFill(ind) || sal.IsFill(ind))
@ -247,6 +248,7 @@ LayeredData::Data LayeredData::Read(const MString& vname, const BaseParameters*
auto v = Read("v", ip, i);
if(!(u && v)) return Data();
auto out = u;
out.SetUnit(square ? ("(" + u.Unit() + ")2") : u.Unit());
for(size_t ind = 0; ind < out.N(); ind++)
{
if(u.IsFill(ind) || v.IsFill(ind))
@ -301,10 +303,18 @@ template<class DataType> LayeredData::Data LayeredData::ReadVarRaw(const NC& f,
if(a_scale_f) scale = a_scale_f;
}
auto unit = f->A<MString>(name, "units");
if(unit && (unit.Get() == "m s-1" || unit.Get() == "m/s")) unitmul = 100.0;
MString unit;
{
auto unitatt = f->A<MString>(name, "units");
if(unitatt) unit = unitatt;
}
if(unit == "m s-1" || unit == "m/s")
{
unitmul = 100.0;
unit = "cm/s";
}
Data data((p->xb < p->xe) ? (p->xe - p->xb + 1) : (dname.nx + p->xe - p->xb + 1), p->ye - p->yb + 1, Lon(p->xb), Lat(p->yb), lonstep, latstep);
Data data((p->xb < p->xe) ? (p->xe - p->xb + 1) : (dname.nx + p->xe - p->xb + 1), p->ye - p->yb + 1, Lon(p->xb), Lat(p->yb), lonstep, latstep, std::move(unit));
if(p->xb < p->xe)
{

43
src/ncfuncs.cpp

@ -91,6 +91,7 @@ std::tuple<MDateTime, time_t, bool> NCFuncs::Refdate(const MString& refdate)
auto ci = words.begin();
if(ci != words.end())
{
if(*ci == "minutes") step = 60;
if(*ci == "hours") step = 3600;
if(*ci == "days") step = 3600 * 24;
ci++;
@ -125,6 +126,32 @@ MString NCFuncs::StName2Name(const MString& stname)
return "";
}
MString NCFuncs::Name2StName(const MString& name)
{
if(name == "ptemp") return "sea_water_potential_temperature";
if(name == "temp") return "sea_water_temperature";
if(name == "sal") return "sea_water_salinity";
if(name == "mld") return "ocean_mixed_layer_thickness_defined_by_sigma_theta";
if(name == "ssh") return "sea_surface_height_above_geoid";
if(name == "u") return "eastward_sea_water_velocity";
if(name == "v") return "northward_sea_water_velocity";
if(name == "w") return "upward_sea_water_velocity";
if(name == "chl") return "mass_concentration_of_chlorophyll_a_in_sea_water";
if(name == "NO3") return "mole_concentration_of_nitrate_in_sea_water";
if(name == "prprod") return "net_primary_production_of_biomass_expressed_as_carbon_per_unit_volume_in_sea_water";
if(name == "Cchl") return "mole_concentration_of_phytoplankton_expressed_as_carbon_in_sea_water";
if(name == "PO4") return "mole_concentration_of_phosphate_in_sea_water";
if(name == "Si") return "mole_concentration_of_silicate_in_sea_water";
return "";
}
MString NCFuncs::Name2LongName(const MString& name)
{
if(name == "U") return "Module of horizontal velocity";
if(name == "U2") return "Squared horizontal velocity";
return "";
}
bool NCFuncs::HaveVar(const NCFileA& nc, const MString& vname)
{
auto head = nc.Header();
@ -136,19 +163,3 @@ bool NCFuncs::HaveVar(const NCFileA& nc, const MString& vname)
}
return false;
}
/*
template<class HV> bool NCFuncs::CheckVar(const MString& vname, HV hv)
{
if(!hv(vname))
{
bool varexist = false;
if(vname == "temp" && hv("ptemp") && hv("sal")) varexist = true;
if(vname == "ptemp" && hv("temp") && hv("sal")) varexist = true;
if(vname == "pdens" && (hv("ptemp") || hv("temp")) && hv("sal")) varexist = true;
if((vname == "U" || vname == "U2") && hv("u") && hv("v")) varexist = true;
if(!varexist) return false;
}
return true;
}
*/

10
src/odm.cpp

@ -61,6 +61,12 @@ int main(int argc, char** argv)
Usage(argv[0]);
return 2;
}
if(argc == 2 && (argv[1] == MString("table") || argv[1] == MString("compattable")))
{
message(CompatTable);
return 2;
}
auto args = ParseArgs(argc, argv);
MString action = args.contains("action") ? args["action"] : "info";
@ -92,8 +98,8 @@ int main(int argc, char** argv)
[&data = arg, &args = std::as_const(args)](const auto& arg)
{
using AT = std::decay_t<decltype(arg)>;
if constexpr(IsActionSupported<DT, AT::action> && !DisableAction<DT,AT::action>)
return DoAction<AT::action>(args, data);
if constexpr(AT::template IsSupported<DT> && !IsDisabled<AT, DT>())
return AT::DoAction(args, data);
else
return MString("Unsupported combination of action and source");
},

Loading…
Cancel
Save