Program Listing for File RectGridIO.cpp

Return to documentation for file (core/src/RectGridIO.cpp)

#include "include/RectGridIO.hpp"

#include "include/CommonRestartMetadata.hpp"
#include "include/IStructure.hpp"
#include "include/MissingData.hpp"
#include "include/ModelArray.hpp"
#include "include/ModelMPI.hpp"
#include "include/ModelState.hpp"
#include "include/NetCDFUtils.hpp"
#include "include/gridNames.hpp"

#ifdef USE_MPI
#include "include/ParallelNetcdfFile.hpp"
#endif

#include <ncDim.h>
#include <ncDouble.h>
#include <ncFile.h>
#include <ncFloat.h>
#include <ncVar.h>

#include <algorithm>
#include <list>
#include <map>
#include <string>
#include <vector>

namespace Nextsim {

#ifdef USE_MPI
void dimensionSetter(
    const netCDF::NcFile& ncFile, const std::string& fieldName, ModelArray::Type type)
{
    size_t nDims = ncFile.getVar(fieldName).getDimCount();
    ModelArray::MultiDim dims;
    dims.resize(nDims);
    for (size_t d = 0; d < nDims; ++d) {
        dims[d] = ncFile.getVar(fieldName).getDim(d).getSize();
    }
    // The dimensions in the netCDF are in the reverse order compared to ModelArray
    std::reverse(dims.begin(), dims.end());
    // Replace X, Y dimensions with local extends
    auto& metadata = ModelMetadata::getInstance();
    dims[0] = metadata.getLocalExtentX();
    dims[1] = metadata.getLocalExtentY();
    ModelArray::setDimensions(type, dims);
}
#else
void dimensionSetter(
    const netCDF::NcFile& ncFile, const std::string& fieldName, ModelArray::Type type)
{
    size_t nDims = ncFile.getVar(fieldName).getDimCount();
    ModelArray::MultiDim dims;
    dims.resize(nDims);
    for (size_t d = 0; d < nDims; ++d) {
        dims[d] = ncFile.getVar(fieldName).getDim(d).getSize();
    }
    // The dimensions in the netCDF are in the reverse order compared to ModelArray
    std::reverse(dims.begin(), dims.end());
    ModelArray::setDimensions(type, dims);
}
#endif

ModelState RectGridIO::getModelState(const std::string& filePath)
{
    ModelState state;
#ifdef USE_MPI
    auto& modelMPI = ModelMPI::getInstance();
    netCDF::NcFilePar ncFile(filePath, netCDF::NcFile::read, modelMPI.getComm());
#else
    netCDF::NcFile ncFile(filePath, netCDF::NcFile::read);
#endif

    // Get the sizes of the three types of field
    // HField from hice
    dimensionSetter(ncFile, hiceName, ModelArray::Type::H);
    // UField from hice
    dimensionSetter(ncFile, hiceName, ModelArray::Type::U);
    // VField from hice
    dimensionSetter(ncFile, hiceName, ModelArray::Type::V);

#ifdef USE_MPI
    // Set the origins and extensions for reading 2D data based
    // on MPI decomposition
    const auto& metadata = ModelMetadata::getInstance();
    const std::vector<size_t> start = { metadata.getLocalCornerY(), metadata.getLocalCornerX() };
    const std::vector<size_t> size = { metadata.getLocalExtentY(), metadata.getLocalExtentX() };
#else
    const std::vector<size_t> start = { 0, 0 };
    const std::vector<size_t> size(ModelArray::dimensions(ModelArray::Type::H).rbegin(),
        ModelArray::dimensions(ModelArray::Type::H).rend());
#endif
    state.data[maskName] = ModelArray::HField();
    readNetCDFVar(ncFile.getVar(maskName), start, size, &state.data[maskName][0]);
    state.data[hiceName] = ModelArray::HField();
    readNetCDFVar(ncFile.getVar(hiceName), start, size, &state.data[hiceName][0]);
    state.data[ciceName] = ModelArray::HField();
    readNetCDFVar(ncFile.getVar(ciceName), start, size, &state.data[ciceName][0]);
    state.data[hsnowName] = ModelArray::HField();
    readNetCDFVar(ncFile.getVar(hsnowName), start, size, &state.data[hsnowName][0]);
    state.data[tsurfName] = ModelArray::HField();
    readNetCDFVar(ncFile.getVar(tsurfName), start, size, &state.data[tsurfName][0]);
    // coordinates on the H grid
    if (ncFile.getVars().count(xName) > 0) {
        state.data[xName] = ModelArray::HField();
        readNetCDFVar(ncFile.getVar(xName), start, size, &state.data[xName][0]);
        state.data[yName] = ModelArray::HField();
        readNetCDFVar(ncFile.getVar(yName), start, size, &state.data[yName][0]);
    } else {
        state.data[longitudeName] = ModelArray::HField();
        readNetCDFVar(ncFile.getVar(longitudeName), start, size, &state.data[longitudeName][0]);
        state.data[latitudeName] = ModelArray::HField();
        readNetCDFVar(ncFile.getVar(latitudeName), start, size, &state.data[latitudeName][0]);
    }

    ncFile.close();
    return state;
}

void RectGridIO::dumpModelState(
    const ModelState& state, const std::string& filePath, bool isRestart) const
{
#ifdef USE_MPI
    auto& modelMPI = ModelMPI::getInstance();
    netCDF::NcFilePar ncFile(filePath, netCDF::NcFile::replace, modelMPI.getComm());
#else
    netCDF::NcFile ncFile(filePath, netCDF::NcFile::replace);
#endif

    CommonRestartMetadata::writeStructureType(ncFile);
    CommonRestartMetadata::writeRestartMetadata(ncFile);
    typedef ModelArray::Type Type;

    int nx = ModelArray::dimensions(Type::H)[0];
    int ny = ModelArray::dimensions(Type::H)[1];

    std::vector<std::string> dimensionNames = { "xdim", "ydim", "t", "component", "u", "v", "w" };

    // Create the dimension data
#ifdef USE_MPI
    auto& metadata = ModelMetadata::getInstance();
    netCDF::NcDim xDim = ncFile.addDim(dimensionNames[0], metadata.getGlobalExtentX());
    netCDF::NcDim yDim = ncFile.addDim(dimensionNames[1], metadata.getGlobalExtentY());
#else
    netCDF::NcDim xDim = ncFile.addDim(dimensionNames[0], nx);
    netCDF::NcDim yDim = ncFile.addDim(dimensionNames[1], ny);
#endif
    std::vector<netCDF::NcDim> dims2 = { yDim, xDim };
#ifdef USE_MPI
    // Set the origins and extensions for reading 2D data based
    // on MPI decomposition
    std::vector<size_t> start2 = { static_cast<size_t>(metadata.getLocalCornerY()),
        static_cast<size_t>(metadata.getLocalCornerX()) };
    std::vector<size_t> size2 = { static_cast<size_t>(metadata.getLocalExtentY()),
        static_cast<size_t>(metadata.getLocalExtentX()) };
#endif

    for (const auto entry : state.data) {
        const std::string& name = entry.first;
        if (entry.second.trueSize() > 0) {
            netCDF::NcVar var(ncFile.addVar(name, ToNetCDFType<FloatType>::get(), dims2));
            var.putAtt(mdiName, ToNetCDFType<FloatType>::get(), MissingData::value());
#ifdef USE_MPI
            var.putVar(start2, size2, entry.second.getData());
#else
            var.putVar(entry.second.getData());
#endif
        }
    }

    ncFile.close();
}

} /* namespace Nextsim */