#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 MODISBINLOCALData::Parameters(michlib_internal::ParameterListEx& pars, const CLArgs& args, const struct Region& reg) const { std::unique_ptr ppar{new struct Parameters}; 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); pars.SetParameter("lone", ppar->lone); pars.SetParameter("late", ppar->late); return {ppar.release(), ""}; } bool MODISBINLOCALData::Read(const MString& vname, std::map& cache, const BaseParameters* ip, size_t tind) const { if(cache.contains(vname)) return true; auto p = pointer_cast(ip); Averager out; for(const auto& suf: dataset) { Data dat = ReadFile(suf, p, tind); if(dat) out.Add(std::move(dat)); } if(out) { cache[vname] = std::move(out.Div()); return true; } return false; } 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, 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 { 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 beg; std::vector loc; std::vector val; std::vector bins; // Read index { auto ind = nc.V("/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(Ceil((p->latb + 90.0) * nr / 180.0 - 0.5)); ilate = static_cast(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(Ceil((lb + 180.0) * nl / 360.0 - 0.5)); ilone = static_cast(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("/level-3_binned_data/BinList"); if(!lst) return Data(); auto dat = nc.V("/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(); out.SetUnit(unit); 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 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; }