Compare commits

...

4 Commits

  1. 60
      include/MODISBINLOCAL.h
  2. 44
      include/NEMOBIO.h
  3. 4
      include/actions.h
  4. 35
      include/basedata.h
  5. 4
      include/data.h
  6. 8
      include/odm.h
  7. 13
      include/simple2ddata.h
  8. 262
      src/MODISBINLOCAL.cpp
  9. 16
      src/data.cpp
  10. 6
      src/ncfuncs.cpp
  11. 11
      src/odm.cpp

60
include/MODISBINLOCAL.h

@ -0,0 +1,60 @@
#pragma once
#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::GPL;
using michlib::MDateTime;
using michlib::RegExp;
using michlib::uint2;
using michlib::uint4;
using michlib::Floor;
using michlib::Ceil;
using michlib::pointer_cast;
class MODISBINLOCALData
{
MString datapath;
std::vector<MString> dataset;
std::vector<MDateTime> times;
bool SufFromDataset(const MString& datasetstr);
struct Parameters: public BaseParameters
{
real lonb, latb, lone, late;
virtual ~Parameters() override = default;
};
public:
using Data = UngriddedData;
MString Info() const;
MString Open(const CLArgs& args);
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;
bool CheckVar(const MString& vname) const
{
if(dataset.empty()) return false;
bool ischl = dataset.front() == "A_CHL" || dataset.front() == "T_CHL";
return (vname == "chl" && ischl) || (vname == "temp" && !ischl);
}
bool isOk() const { return times.size() > 0; }
size_t NTimes() const { return times.size(); }
MDateTime Time(size_t i) const
{
if(!isOk() || i >= times.size()) return MDateTime();
return times[i];
}
};

44
include/NEMOBIO.h

@ -0,0 +1,44 @@
#pragma once
#include "layereddata.h"
class NEMOBIOData: public LayeredData
{
enum Type
{
TYPE_UNKNOWN,
TYPE_DT,
TYPE_NRT,
};
Type type = TYPE_UNKNOWN;
public:
NEMOBIOData() = default;
MString DataTitle() const
{
switch(type)
{
case(TYPE_DT): return "NEMO BIO Delayed time (DT)";
case(TYPE_NRT): return "NEMO BIO Near-real time (NRT)";
default: return "No title";
}
}
// TODO: RetVal
MString Open(const CLArgs& args)
{
MString dataset = args.contains("dataset") ? args.at("dataset") : "DT";
GPL.UsePrefix("NEMOBIO");
if(dataset == "DT")
type = TYPE_DT;
else if(dataset == "NRT")
type = TYPE_NRT;
else
return "Unknown dataset: " + dataset;
SetTitle(DataTitle());
return LayeredData::Open(dataset);
}
};

4
include/actions.h

@ -162,7 +162,7 @@ template<class D> std::pair<TIndex, MString> GetTIndexes(const D& data, const CL
return {tindexes, ""};
}
template<class D> BaseData Read(const D& data, const MString& vname, const BaseParameters* p, const TIndex& tindex)
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;
@ -196,7 +196,7 @@ template<class D> BaseData Read(const D& data, const MString& vname, const BaseP
}
if(ok) return out.Div();
}
return BaseData();
return RT();
}
template<class D> UVData<ReadType<D>> ReadUV(const D& data, const BaseParameters* p, size_t ind)

35
include/basedata.h

@ -13,18 +13,8 @@ class BaseData
protected:
static constexpr real fillval = 1.0e10;
std::vector<real> data;
std::vector<real> lons, lats;
BaseData(size_t n): data(n), lons(n), lats(n) {}
template<class Lon, class Lat> BaseData(size_t n, Lon genlon, Lat genlat): data(n), lons(n), lats(n)
{
for(size_t i = 0; i < n; i++)
{
lons[i] = genlon(i);
lats[i] = genlat(i);
}
};
BaseData(size_t n): data(n) {}
public:
BaseData() = default;
@ -35,9 +25,6 @@ class BaseData
const real& operator()(size_t i) const { return data[i]; }
real& operator()(size_t i) { return data[i]; }
real Lon(size_t i) const { return lons[i]; }
real Lat(size_t i) const { return lats[i]; }
size_t N() const { return data.size(); }
bool IsFill(size_t i) const { return V(i) == Fillval(); }
@ -47,6 +34,26 @@ class BaseData
explicit operator bool() const { return N() != 0; }
};
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)
{
for(size_t i = 0; i < n; i++)
{
lons[i] = genlon(i);
lats[i] = genlat(i);
}
};
UngriddedData() = default;
real Lon(size_t i) const { return lons[i]; }
real Lat(size_t i) const { return lats[i]; }
};
template<class Data> class DefaultAverager: public Data
{
static constexpr bool isuv = IsUVData<Data>;

4
include/data.h

@ -3,10 +3,12 @@
#include "AVISOLOCAL.h"
#include "BINFILE.h"
#include "HYCOM.h"
#include "MODISBINLOCAL.h"
#include "NEMO.h"
#include "NEMOBIO.h"
#include <variant>
using DataVariants = std::variant<NEMOData, HYCOMData, AVISOData, AVISOLOCALData, BINFILEData>;
using DataVariants = std::variant<NEMOData, NEMOBIOData, HYCOMData, AVISOData, AVISOLOCALData, BINFILEData, MODISBINLOCALData>;
class Data: public DataVariants
{
public:

8
include/odm.h

@ -16,6 +16,8 @@ template<class T, ActionID id> consteval bool MustSup()
constexpr bool NEMOsup =
MustSup<NEMOData, ActionID::INFO>() && MustSup<NEMOData, ActionID::TSC>() && MustSup<NEMOData, ActionID::UV>() && MustSup<NEMOData, ActionID::GENINTFILE>();
constexpr bool NEMOBIOsup = MustSup<NEMOBIOData, ActionID::INFO>() && MustSup<NEMOBIOData, ActionID::TSC>();
constexpr bool HYCOMsup =
MustSup<HYCOMData, ActionID::INFO>() && MustSup<HYCOMData, ActionID::TSC>() && MustSup<HYCOMData, ActionID::UV>() && MustSup<HYCOMData, ActionID::GENINTFILE>();
@ -30,4 +32,8 @@ constexpr bool BINFILEsup = MustSup<BINFILEData, ActionID::INFO>() && MustSup<BI
template<class T, ActionID id> static constexpr bool DisableAction = false;
// Exceptions
template<> constexpr bool DisableAction<BINFILEData, ActionID::GENINTFILE> = true;
template<> constexpr bool DisableAction<BINFILEData, ActionID::GENINTFILE> = true;
template<> constexpr bool DisableAction<MODISBINLOCALData, ActionID::UV> = true;
template<> constexpr bool DisableAction<MODISBINLOCALData, ActionID::GENINTFILE> = true;
template<> constexpr bool DisableAction<NEMOBIOData, ActionID::UV> = true;
template<> constexpr bool DisableAction<NEMOBIOData, ActionID::GENINTFILE> = true;

13
include/simple2ddata.h

@ -10,18 +10,7 @@ class Simple2DData: public BaseData
public:
Simple2DData() = default;
Simple2DData(size_t nx_, size_t ny_, real x0_, real y0_, real xs_, real ys_):
BaseData(
nx_ * ny_, [x0 = x0_, nx = nx_, xstep = xs_](size_t i) -> real { return x0 + (i % nx) * xstep; },
[y0 = y0_, nx = nx_, ystep = ys_](size_t i) -> real { return y0 + (i / nx) * ystep; }),
x0(x0_),
y0(y0_),
nx(nx_),
ny(ny_),
xstep(xs_),
ystep(ys_)
{
}
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); }

262
src/MODISBINLOCAL.cpp

@ -0,0 +1,262 @@
#define MICHLIB_NOSOURCE
#include "MODISBINLOCAL.h"
MString MODISBINLOCALData::Info() const
{
MString ds = "";
for(size_t i = 0; i < dataset.size(); i++)
{
if(i != 0) ds += " ";
ds += dataset[i];
}
// clang-format off
return
"Dataset: MODIS Level-3 Binned Data 4.6 km - " + ds + "\n" +
" Begin date: " + Time(0).ToString() + "\n" +
" End date: " + Time(NTimes()-1).ToString() + "\n" +
" Time moments: " + NTimes() + "\n" +
" Supported variables: temp, chl";
// clang-format on
}
MString MODISBINLOCALData::Open(const CLArgs& args)
{
GPL.UsePrefix("MODISBINLOCAL");
datapath = GPL.ParameterSValue("Datapath", "");
MString var, datasetstr;
if(!args.contains("var") && !args.contains("dataset")) var = "temp";
if(args.contains("var"))
{
var = args.at("var");
if(var != "temp" && var != "chl") return "Unknown variable: " + var;
}
if(var.Exist() && !args.contains("dataset")) datasetstr = (var == "temp") ? "ALL" : "CHL";
if(args.contains("dataset")) datasetstr = args.at("dataset");
bool ischl = SufFromDataset(datasetstr);
if(dataset.size() == 0) return "Incorrect dataset: " + datasetstr;
if(!var.Exist()) var = ischl ? "chl" : "temp";
if((var == "temp" && ischl) || (var == "chl" && !ischl)) return "Arguments dataset and var are in contradiction";
MString regstring = "([0-9]{4}-[0-9]{2}-[0-9]{2})_(";
for(size_t i = 0; i < dataset.size(); i++)
{
if(i != 0) regstring += "|";
regstring += dataset[i];
}
regstring += ").nc";
RegExp regex(regstring.Buf());
regex.Compile();
DIR* dir = opendir(datapath.Buf());
struct dirent* de;
if(nullptr == dir) return "Can't open directory " + datapath;
while((de = readdir(dir)))
{
if(!regex.Match(de->d_name)) continue;
times.emplace_back(MString(de->d_name + regex.Off(1), regex.Len(1)));
}
closedir(dir);
std::sort(times.begin(), times.end());
auto last = std::unique(times.begin(), times.end());
times.erase(last, times.end());
times.shrink_to_fit();
return "";
}
std::pair<const BaseParameters*, MString> MODISBINLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args) 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();
pars.SetParameter("lonb", ppar->lonb);
pars.SetParameter("latb", ppar->latb);
pars.SetParameter("lone", ppar->lone);
pars.SetParameter("late", ppar->late);
return {ppar.release(), ""};
}
MODISBINLOCALData::Data MODISBINLOCALData::Read(const MString& var, const BaseParameters* ip, size_t tind) const
{
auto p = pointer_cast<const struct Parameters*>(ip);
Averager<Data> out;
for(const auto& suf: dataset)
{
Data dat = ReadFile(suf, p, tind);
if(dat) out.Add(dat);
}
return out.Div();
}
MODISBINLOCALData::Data MODISBINLOCALData::ReadFile(const MString& suf, const struct MODISBINLOCALData::Parameters* p, size_t tind) const
{
michlib::NCFileA nc;
michlib::message("Reading " + datapath + "/" + times[tind].ToString() + "_" + suf + ".nc");
nc.Reset(datapath + "/" + times[tind].ToString() + "_" + suf + ".nc");
if(!nc) return Data();
MString dname;
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";
struct BinIndexType
{
uint4 start_num;
uint4 begin;
uint4 extent;
uint4 max;
};
struct BinListType
{
uint4 bin_num;
uint2 nobs;
uint2 nscenes;
float weights;
float time_rec;
};
struct BinDataType
{
float sum;
float sum_squared;
};
std::vector<uint4> beg;
std::vector<uint4> loc;
std::vector<float> val;
std::vector<uint4> bins;
// Read index
{
auto ind = nc.V<struct BinIndexType>("/level-3_binned_data/BinIndex");
if(!ind) return Data();
beg.resize(ind.DimLen(0) + 1);
beg[0] = 1;
for(size_t i = 1; i <= ind.DimLen(0); i++) beg[i] = beg[i - 1] + ind(i - 1).max;
}
size_t ilatb, ilate;
{
size_t nr = beg.size() - 2;
ilatb = static_cast<size_t>(Ceil((p->latb + 90.0) * nr / 180.0 - 0.5));
ilate = static_cast<size_t>(Floor((p->late + 90.0) * nr / 180.0 - 0.5));
}
for(size_t i = ilatb; i <= ilate; i++)
{
real lb = michlib::ToGeoDomainNeg(p->lonb);
real le = michlib::ToGeoDomainNeg(p->lone);
size_t nl = beg[i + 1] - beg[i];
size_t ilonb, ilone, il;
ilonb = static_cast<size_t>(Ceil((lb + 180.0) * nl / 360.0 - 0.5));
ilone = static_cast<size_t>(Floor((le + 180.0) * nl / 360.0 - 0.5));
il = ilonb;
do bins.push_back(beg[i] + il);
while(++il % nl != ilone + 1);
}
std::sort(bins.begin(), bins.end());
auto InReg = [&bins = std::as_const(bins)](uint4 n) -> size_t
{
size_t a = 0, b = bins.size() - 1;
if(bins[a] == n) return a;
if(bins[b] == n) return b;
while(true)
{
size_t c = (a + b) / 2;
if(bins[c] == n) return c;
if(n < bins[c])
b = c;
else
a = c;
if(b - a == 1) return bins.size();
}
};
auto Row = [&beg = std::as_const(beg)](uint4 n) -> size_t
{
if(n >= beg.back() || n == 0) return beg.size() - 1;
size_t a = 0, b = beg.size() - 2;
if(n >= beg[a] && n < beg[a + 1]) return a;
if(n >= beg[b] && n < beg[b + 1]) return b;
while(true)
{
size_t c = (a + b) / 2;
if(n >= beg[c] && n < beg[c + 1]) return c;
if(n < beg[c])
b = c;
else
a = c;
}
};
auto Lat = [&Row = Row](uint4 n)
{
auto r = Row(n);
auto nr = Row(0) - 1; // Number of rows
return -90.0 + (r + 0.5) * (180.0 / nr);
};
auto Lon = [&Row = Row, &beg = std::as_const(beg)](uint4 n) -> real
{
auto r = Row(n);
if(r == beg.size() - 1) return NAN;
return -180.0 + (n - beg[r] + 0.5) * (360.0 / (beg[r + 1] - beg[r]));
};
{
auto lst = nc.V<struct BinListType>("/level-3_binned_data/BinList");
if(!lst) return Data();
auto dat = nc.V<struct BinDataType>("/level-3_binned_data/" + dname);
if(!dat) return Data();
if(dat.DimLen(0) != lst.DimLen(0)) return Data();
val.resize(dat.DimLen(0));
loc.resize(lst.DimLen(0));
for(size_t i = 0; i < dat.DimLen(0); i++)
{
loc[i] = lst(i).bin_num;
val[i] = dat(i).sum / lst(i).weights;
}
}
if(loc.size() != val.size()) return Data();
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();
for(size_t i = 0; i < loc.size(); i++)
{
auto ind = InReg(loc[i]);
if(ind < bins.size()) out.V(ind) = val[i];
}
return out;
}
bool MODISBINLOCALData::SufFromDataset(const MString& datasetstr)
{
std::set<MString> sufs;
auto words = michlib::Split_on_words(datasetstr, ", \t\x00", false);
bool ischl = words.front() == "A_CHL" || words.front() == "T_CHL" || words.front() == "CHL";
for(auto ci = words.cbegin(); ci != words.cend(); ++ci)
{
if(ischl && (*ci == "A_CHL" || *ci == "CHL")) sufs.insert("A_CHL");
if(ischl && (*ci == "T_CHL" || *ci == "CHL")) sufs.insert("T_CHL");
if(!ischl && (*ci == "A_SST" || *ci == "SST" || *ci == "DSST" || *ci == "A_DSST" || *ci == "A_ALL" || *ci == "ALL")) sufs.insert("A_SST");
if(!ischl && (*ci == "T_SST" || *ci == "SST" || *ci == "DSST" || *ci == "T_DSST" || *ci == "T_ALL" || *ci == "ALL")) sufs.insert("T_SST");
if(!ischl && (*ci == "A_SST4" || *ci == "SST4" || *ci == "DSST" || *ci == "A_DSST" || *ci == "A_ALL" || *ci == "ALL")) sufs.insert("A_SST4");
if(!ischl && (*ci == "T_SST4" || *ci == "SST4" || *ci == "DSST" || *ci == "T_DSST" || *ci == "T_ALL" || *ci == "ALL")) sufs.insert("T_SST4");
if(!ischl && (*ci == "A_NSST" || *ci == "NSST" || *ci == "A_ALL" || *ci == "ALL")) sufs.insert("A_NSST");
if(!ischl && (*ci == "T_NSST" || *ci == "NSST" || *ci == "T_ALL" || *ci == "ALL")) sufs.insert("T_NSST");
}
for(const auto& w: sufs) dataset.push_back(w);
return ischl;
}

16
src/data.cpp

@ -12,6 +12,13 @@ MString Data::Init(const CLArgs& args)
if(res.Exist()) return "Can't open source " + src + ":\n" + res;
*this = Data(std::move(data));
}
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;
@ -36,7 +43,14 @@ MString Data::Init(const CLArgs& args)
else if(src == "BINFILE")
{
BINFILEData data;
auto res = data.Open(args);
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));
}

6
src/ncfuncs.cpp

@ -116,6 +116,12 @@ MString NCFuncs::StName2Name(const MString& stname)
if(stname == "surface_geostrophic_eastward_sea_water_velocity") return "u";
if(stname == "surface_geostrophic_northward_sea_water_velocity") return "v";
if(stname == "upward_sea_water_velocity") return "w";
if(stname == "mass_concentration_of_chlorophyll_a_in_sea_water") return "chl";
if(stname == "mole_concentration_of_nitrate_in_sea_water") return "NO3";
if(stname == "net_primary_production_of_biomass_expressed_as_carbon_per_unit_volume_in_sea_water") return "prprod";
if(stname == "mole_concentration_of_phytoplankton_expressed_as_carbon_in_sea_water") return "Cchl";
if(stname == "mole_concentration_of_phosphate_in_sea_water") return "PO4";
if(stname == "mole_concentration_of_silicate_in_sea_water") return "Si";
return "";
}

11
src/odm.cpp

@ -6,16 +6,18 @@ inline void Usage(const MString& arg0)
message("Keys are:");
message(" action. What the program should do. May be: info, tsc, uv, genintfile. Default: info.");
message(" Keys for action=info. Print some information about dataset.");
message(" source. Required. May be: NEMO, HYCOM, AVISO, AVISOLOCAL, BINFILE");
message(" source. Required. May be: NEMO, NEMOBIO, HYCOM, AVISO, AVISOLOCAL, BINFILE");
message(" Keys for source=NEMO");
message(" dataset. Can be DT, NRT or NRT6. Default: DT");
message(" Keys for source=NEMOBIO");
message(" dataset. Can be DT or NRT. Default: DT");
message(" Keys for source=HYCOM");
message(" dataset. Can be Forecast, Hindcast or Reanalysis. Default: Forecast");
message(" Keys for source=AVISO");
message(" dataset. Can be DT, NRT, EckmanDT or EckmanNRT. Default: DT");
message(" Keys for action=tsc. Get temperature, salinity, chlorofill from dataset.");
message(" source. Required. May be: NEMO, HYCOM, AVISO, AVISOLOCAL, BINFILE");
message(" var. Required. May be: U, U2, u, v, temp, ptemp, pdens, sal, chl, mld, ssh or w.");
message(" source. Required. May be: NEMO, NEMOBIO, HYCOM, AVISO, AVISOLOCAL, BINFILE");
message(" var. Required. May be: U, U2, u, v, temp, ptemp, pdens, sal, chl, mld, ssh, w, NO3, PO4, Si, prprod, Cchl.");
message(" time. Time moment or regular expression. If present, timeb and timee must be absent");
message(" timeb, timee. Time interval. If present, time must be absent");
message(" lonb, lone, latb, late. Required. Region of interest");
@ -23,6 +25,9 @@ inline void Usage(const MString& arg0)
message(" Keys for source=NEMO");
message(" dataset. Can be DT, NRT or NRT6. Default: DT");
message(" layer and/or depth. Layer or depth of NEMO dataset. If depth is specified, layer is ignored. Both ignored, if var=mld or var=ssh. Default: layer=0");
message(" Keys for source=NEMOBIO");
message(" dataset. Can be DT or NRT. Default: DT");
message(" layer and/or depth. Layer or depth of NEMOBIO dataset. If depth is specified, layer is ignored. Default: layer=0");
message(" Keys for source=HYCOM");
message(" dataset. Can be Forecast, Hindcast or Reanalysis. Default: Forecast");
message(" layer and/or depth. Layer or depth of HYCOM dataset. If depth is specified, layer is ignored. Both ignored, if var=mld or var=ssh. Default: layer=0");

Loading…
Cancel
Save