Skip to content

Commit

Permalink
Merge branch 'feature/fesom-2-healpix-via-mir'
Browse files Browse the repository at this point in the history
  • Loading branch information
dsarmany committed Jul 3, 2024
2 parents 46ab308 + f046bd9 commit 9fc42cf
Show file tree
Hide file tree
Showing 21 changed files with 430 additions and 77 deletions.
30 changes: 0 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,7 @@ jobs:
name:
- linux gnu-10
- linux gnu-12
- linux clang-12
- linux clang-14
# - linux intel
# - macos appclang-14

include:
- name: linux gnu-10
Expand All @@ -55,14 +52,6 @@ jobs:
caching: true
cmake_options: -DENABLE_OMP_CXX=OFF

- name: linux clang-12
os: ubuntu-20.04
compiler: clang-12
compiler_cc: clang-12
compiler_cxx: clang++-12
compiler_fc: gfortran-10
caching: true

- name: linux clang-14
os: ubuntu-22.04
compiler: clang-14
Expand All @@ -71,25 +60,6 @@ jobs:
compiler_fc: gfortran-12
caching: true

# - name : linux intel
# os: ubuntu-20.04
# compiler: intel
# compiler_cc: icx
# compiler_cxx: icpx
# compiler_fc: ifx
# caching: true
# coverage: false

# - name: macos appclang-14
# # Xcode compiler requires empty environment variables, so we pass null (~) here
# os: macos-12
# compiler: clang-14
# compiler_cc: ~
# compiler_cxx: ~
# compiler_fc: gfortran-12
# caching: true
# cmake_options: -DMPI_SLOTS=4

runs-on: ${{ matrix.os }}
steps:
- name: Checkout Repository
Expand Down
12 changes: 6 additions & 6 deletions src/multio/action/encode/Encode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,12 @@ std::unique_ptr<GribEncoder> makeEncoder(const eckit::LocalConfiguration& conf,
handleCodesError("eccodes error while reading the grib template: ", err, Here());

if (conf.has("atlas-named-grid")) {
const auto atlasNamedGrid = util::replaceCurly(conf.getString("atlas-named-grid"),
[](std::string_view replace) {
std::string lookUpKey{replace};
char* env = ::getenv(lookUpKey.c_str());
return env ? std::optional<std::string>{env} : std::optional<std::string>{};
});
const auto atlasNamedGrid
= util::replaceCurly(conf.getString("atlas-named-grid"), [](std::string_view replace) {
std::string lookUpKey{replace};
char* env = ::getenv(lookUpKey.c_str());
return env ? std::optional<std::string>{env} : std::optional<std::string>{};
});

eckit::Log::info() << "REQUESTED ATLAS GRID DEFINITION UPDATE: " << atlasNamedGrid << std::endl;

Expand Down
4 changes: 2 additions & 2 deletions src/multio/action/encode/GribEncoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -586,9 +586,9 @@ std::string getTimeReference(GribEncoder& g, const eckit::LocalConfiguration& md
else {
isReferingToStart = true;
}
}
}
else if (types_with_time_reference_offset.find(*queriedMarsFields.type)
!= types_with_time_reference_offset.end()) {
!= types_with_time_reference_offset.end()) {
isReferingToStart = true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/multio/action/interpolate-fesom/FesomCacheValidator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ void FesomCacheValidator::execute(const eckit::option::CmdArgs& args) {
};


void FesomCacheValidator::finish(const eckit::option::CmdArgs&){};
void FesomCacheValidator::finish(const eckit::option::CmdArgs&) {};

} // namespace multio::action::interpolateFESOM

Expand Down
2 changes: 1 addition & 1 deletion src/multio/action/interpolate-fesom/FesomSpmvmValidator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ void FesomCacheValidator::execute(const eckit::option::CmdArgs& args) {
};


void FesomCacheValidator::finish(const eckit::option::CmdArgs&){};
void FesomCacheValidator::finish(const eckit::option::CmdArgs&) {};

} // namespace multio::action::interpolateFESOM

Expand Down
19 changes: 19 additions & 0 deletions src/multio/action/interpolate/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,22 @@ ecbuild_add_library(
multio
mir
)

ecbuild_add_executable(

TARGET
cache-generator-fesom-2-mir

SOURCES
FesomCacheGenerator.cc
../../tools/MultioTool.cc

CONDITION
HAVE_MIR AND HAVE_ATLAS_IO

LIBS
multio
atlas_io
eckit
mir
)
223 changes: 223 additions & 0 deletions src/multio/action/interpolate/FesomCacheGenerator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
#include <iostream>

#include <algorithm>
#include <array>
#include <cmath>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <regex>
#include <sstream>
#include <string>
#include <vector>

#include "eckit/exception/Exceptions.h"
#include "eckit/filesystem/PathName.h"
#include "eckit/linalg/Triplet.h"
#include "eckit/log/Log.h"
#include "eckit/option/CmdArgs.h"
#include "eckit/option/SimpleOption.h"
#include "mir/method/WeightMatrix.h"
#include "multio/tools/MultioTool.h"

namespace multio::action::interpolateFESOM2MIR {

namespace {

enum class orderingConvention_e : unsigned int
{
RING,
NESTED,
UNKNOWN
};

orderingConvention_e orderingConvention_string2enum(const std::string& orderingConvention) {
if (orderingConvention != "ring" && orderingConvention != "nested") {
std::ostringstream os;
os << " - Unexpected value for \"orderingConvention\": "
<< "\"" << orderingConvention << "\"" << std::endl;
throw eckit::SeriousBug(os.str(), Here());
}
return (orderingConvention == "ring" ? orderingConvention_e::RING : orderingConvention_e::NESTED);
}


std::string orderingConvention_enum2string(orderingConvention_e orderingConvention) {
if (orderingConvention == orderingConvention_e::UNKNOWN) {
std::ostringstream os;
os << " - Unexpected value for \"orderingConvention\": "
<< "\"UNKNOWN\"" << std::endl;
throw eckit::SeriousBug(os.str(), Here());
}
return (orderingConvention == orderingConvention_e::RING ? "ring" : "nested");
}


void parseInputFileName(const std::string& fname, std::string& fesomName, std::string& domain, size_t& NSide,
size_t& level, orderingConvention_e& orderingConvention) {
static const std::regex fnameGrammar("([^_]+)_([^_]+)_NSIDE([1-9][0-9]*)_([0-9][0-9]*)_([a-zA-Z]*).csv");
std::smatch matchFName;
if (std::regex_match(fname, matchFName, fnameGrammar)) {
fesomName = matchFName[1].str();
domain = matchFName[2].str();
NSide = static_cast<size_t>(std::stoi(matchFName[3].str()));
level = static_cast<size_t>(std::stoi(matchFName[4].str()));
orderingConvention = orderingConvention_string2enum(matchFName[5].str());
}
else {
throw eckit::SeriousBug("Unable to parse filename: " + fname, Here());
}
return;
}

std::string fesomCacheName(const std::string& fesomName, const std::string& domain, const std::string& precision,
size_t NSide, const std::string& orderingConvention, double level) {
std::ostringstream os;
std::string localDomain{domain};
localDomain.erase(std::remove_if(localDomain.begin(), localDomain.end(), ::isspace), localDomain.end());
std::transform(localDomain.begin(), localDomain.end(), localDomain.begin(),
[](unsigned char c) { return std::tolower(c); });
os << "fesom_" << fesomName << "_" << localDomain << "_to_HEALPix_" << std::setw(6) << std::setfill('0') << NSide
<< "_" << precision << "_" << orderingConvention << "_" << std::setw(8) << std::setfill('0')
<< static_cast<size_t>(std::fabs(level * 1000)) << ".mat";
return os.str();
}

} // namespace


class Fesom2mirCacheGenerator final : public multio::MultioTool {
public: // methods
Fesom2mirCacheGenerator(int argc, char** argv);

private:
void usage(const std::string& tool) const override {
eckit::Log::info() << std::endl << "Usage: " << tool << " [options]" << std::endl;
eckit::Log::info() << "EXAMPLE: " << std::endl
<< "fesom-cache-generator --inputPath=. --inputFile=CORE2_ngrid_NSIDE32_0_ring.csv "
<< std::endl
<< std::endl;
}

void init(const eckit::option::CmdArgs& args) override;

void finish(const eckit::option::CmdArgs&) override;

void execute(const eckit::option::CmdArgs& args) override;

int numberOfPositionalArguments() const override { return 0; }
int minimumPositionalArguments() const override { return 0; }

std::string inputPath_;
std::string outputPath_;
std::string outputPrecision_;
std::string inputFile_;


std::string fesomName_;
std::string domain_;
size_t NSide_;
size_t level_;
size_t Nrow_;
size_t Ncol_;
orderingConvention_e orderingConvention_;

void loadTriplets(std::vector<eckit::linalg::Triplet>& triplets) const;
};


Fesom2mirCacheGenerator::Fesom2mirCacheGenerator(int argc, char** argv) :
multio::MultioTool{argc, argv},
inputPath_{"."},
outputPath_{"."},
inputFile_{"CORE2_ngrid_NSIDE32_0_ring.csv"},
fesomName_{"CORE2"},
domain_{"ngrid"},
NSide_{0},
level_{0},
orderingConvention_{orderingConvention_e::RING} {

options_.push_back(new eckit::option::SimpleOption<std::string>(
"inputPath", "Path of the input files with the triplets. Default( \".\" )"));
options_.push_back(new eckit::option::SimpleOption<std::string>(
"outputPath", "Path of the output files with the triplets. Default( \".\" )"));
options_.push_back(new eckit::option::SimpleOption<std::string>(
"inputFile", "Name of the input file. Default( \"CORE2_ngrid_NSIDE32_0_ring.csv\" )"));
options_.push_back(new eckit::option::SimpleOption<size_t>("nCols", "Size of the fesom grid."));

return;
}


void Fesom2mirCacheGenerator::loadTriplets(std::vector<eckit::linalg::Triplet>& triplets) const {
std::ifstream file(inputPath_ + "/" + inputFile_);
if (!file.good()) {
throw eckit::SeriousBug("Unable to read the input file", Here());
}

std::string line;
triplets.resize(0);
while (std::getline(file, line)) {
int32_t iHEALPix;
int32_t iFESOM;
double weight;
static const std::regex lineGrammar(
"([0-9][0-9]*)\\s+([0-9][0-9]*)\\s*([+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?)");
std::smatch matchLine;
if (std::regex_match(line, matchLine, lineGrammar)) {
iHEALPix = std::stoi(matchLine[1].str());
iFESOM = std::stoi(matchLine[2].str());
weight = std::stod(matchLine[3].str());
}
else {
throw eckit::SeriousBug("Unable to parse line: " + line, Here());
}
triplets.emplace_back(iHEALPix, iFESOM, weight);
}
file.close();
}


void Fesom2mirCacheGenerator::init(const eckit::option::CmdArgs& args) {
args.get("inputPath", inputPath_);
args.get("outputPath", outputPath_);
args.get("inputFile", inputFile_);

eckit::PathName inputPath_tmp{inputPath_};
ASSERT(inputPath_tmp.exists());
eckit::PathName inputFile_tmp{inputPath_ + "/" + inputFile_};
ASSERT(inputFile_tmp.exists());
eckit::PathName outputPath_tmp{outputPath_};
outputPath_tmp.mkdir();
parseInputFileName(inputFile_, fesomName_, domain_, NSide_, level_, orderingConvention_);

args.get("nCols", Ncol_);
Nrow_ = NSide_ * NSide_ * 12;
}

void Fesom2mirCacheGenerator::execute(const eckit::option::CmdArgs& args) {
std::vector<eckit::linalg::Triplet> triplets;
loadTriplets(triplets);

std::sort(begin(triplets), end(triplets), [](const auto& a, const auto& b) { return a.row() < b.row(); });

const auto orderingConvention = orderingConvention_enum2string(orderingConvention_);
const auto cacheFileName = fesomCacheName(fesomName_, domain_, "double", NSide_, orderingConvention, level_);

mir::method::WeightMatrix W(Nrow_, Ncol_);
W.setFromTriplets(triplets);
W.save(cacheFileName);
};


void Fesom2mirCacheGenerator::finish(const eckit::option::CmdArgs&) {}

} // namespace multio::action::interpolateFESOM2MIR


int main(int argc, char** argv) {
multio::action::interpolateFESOM2MIR::Fesom2mirCacheGenerator tool(argc, argv);
return tool.start();
}
Loading

0 comments on commit 9fc42cf

Please sign in to comment.