#include "inetcdf4.hpp" #include "netCdfInterface.hpp" #include namespace xios { CINetCDF4::CINetCDF4(const StdString& filename, const MPI_Comm* comm /*= NULL*/, bool multifile /*= true*/) : mpi(comm != NULL && !multifile) { if (comm != NULL) { if (!multifile) CNetCdfInterface::openPar(filename, NC_NOWRITE, *comm, MPI_INFO_NULL, this->ncidp); else CNetCdfInterface::open(filename, NC_NOWRITE, this->ncidp); } else CNetCdfInterface::open(filename, NC_NOWRITE, this->ncidp); } CINetCDF4::~CINetCDF4(void) { /* Nothing to do */ } ///-------------------------------------------------------------- void CINetCDF4::CheckError(int status) { if (status != NC_NOERR) { StdString errormsg(nc_strerror(status)); // fuite mémoire ici ? ERROR("CINetCDF4::CheckError(int status)", << "[ status = " << status << " ] " << errormsg); } } //--------------------------------------------------------------- void CINetCDF4::close(void) { CheckError(nc_close(this->ncidp)); } //--------------------------------------------------------------- int CINetCDF4::getGroup(const CVarPath* const path) { int retvalue = this->ncidp; if (path == NULL) return retvalue; CVarPath::const_iterator it = path->begin(), end = path->end(); for (; it != end; it++) { const StdString& groupid = *it; CheckError(nc_inq_ncid(retvalue, const_cast(groupid.c_str()), &retvalue)); } return retvalue; } int CINetCDF4::getVariable(const StdString& varname, const CVarPath* const path) { int varid = 0; int grpid = this->getGroup(path); CheckError(nc_inq_varid(grpid, varname.c_str(), &varid)); return varid; } int CINetCDF4::getDimension(const StdString& dimname, const CVarPath* const path) { int dimid = 0; int grpid = this->getGroup(path); CheckError(nc_inq_dimid(grpid, dimname.c_str(), &dimid)); return dimid; } std::pair CINetCDF4::getAttribute(const StdString& attname, const StdString* const var, const CVarPath* const path) { std::pair retvalue; int grpid = this->getGroup(path); int varid = (var != NULL) ? this->getVariable(*var, path) : NC_GLOBAL; CheckError(nc_inq_att(grpid, varid, attname.c_str(), &retvalue.first, &retvalue.second)); return retvalue; } int CINetCDF4::getUnlimitedDimension(const CVarPath* const path) { int dimid = 0; int grpid = this->getGroup(path); CheckError(nc_inq_unlimdim(grpid, &dimid)); return dimid; } StdString CINetCDF4::getUnlimitedDimensionName(const CVarPath* const path) { char full_name_in[NC_MAX_NAME +1]; int grpid = this->getGroup(path); int dimid = this->getUnlimitedDimension(path); CheckError(nc_inq_dimname(grpid, dimid, full_name_in)); StdString dimname(full_name_in); return dimname; } //--------------------------------------------------------------- StdSize CINetCDF4::getNbVertex(const StdString& name, const CVarPath* const path) { if (this->isRectilinear(name, path) || this->isCurvilinear(name, path)) { if (this->is3Dim(name, path)) return 8; else return 4; } if (this->isUnstructured(name, path)) { StdString bound = this->getBoundsId (this->getCoordinatesIdList(name, path).back(), path); StdString dim = this->getDimensionsList(&bound, path).back(); return (this->getDimensions(&bound, path)[dim]); } return size_t(-1); } //--------------------------------------------------------------- std::list CINetCDF4::getGroups(const CVarPath* const path) { StdSize strlen = 0; char full_name_in[NC_MAX_NAME +1]; int nbgroup = 0, *groupid = NULL; int grpid = this->getGroup(path); std::list retvalue; CheckError(nc_inq_grps(grpid, &nbgroup, NULL)); groupid = new int[nbgroup](); CheckError(nc_inq_grps(grpid, NULL, groupid)); for (int i = 0; i < nbgroup; i++) { CheckError(nc_inq_grpname_full(groupid[i], &strlen, full_name_in)); StdString groupname(full_name_in, strlen); retvalue.push_back(groupname); } delete [] groupid; return retvalue; } std::list CINetCDF4::getVariables(const CVarPath* const path) { char full_name_in[NC_MAX_NAME +1]; int nbvar = 0, *varid = NULL; int grpid = this->getGroup(path); std::list retvalue; CheckError(nc_inq_varids(grpid, &nbvar, NULL)); varid = new int[nbvar](); CheckError(nc_inq_varids(grpid, NULL, varid)); for (int i = 0; i < nbvar; i++) { CheckError(nc_inq_varname(grpid, varid[i], full_name_in)); StdString varname(full_name_in); retvalue.push_back(varname); } delete [] varid; return retvalue; } StdSize CINetCDF4::getNbOfTimestep(const CVarPath* const path) { return (this->getDimensions(NULL, path)[this->getUnlimitedDimensionName(path)]); } std::set CINetCDF4::getBoundVariables(const CVarPath* const path) { std::set retvalue; std::list variables = this->getVariables(path); std::list::const_iterator it = variables.begin(), end = variables.end(); for (; it != end; it++) { const StdString& var = *it; if (this->hasBounds(var, path)) retvalue.insert(retvalue.end(), this->getBoundsId(var, path)); } return retvalue; } std::set CINetCDF4::getCoordVariables(const CVarPath* const path) { std::set retvalue; std::list variables = this->getVariables(path); std::list::const_iterator it = variables.begin(), end = variables.end(); for (; it != end; it++) { const StdString& var = *it; std::list coords = this->getCoordinatesIdList(var, path); std::list::const_iterator it = coords.begin(), end = coords.end(); for (; it != end; it++) { const StdString& coord = *it; if (this->hasVariable(coord, path)) retvalue.insert(retvalue.end(), coord); } } return retvalue; } std::list CINetCDF4::getDimensionsList(const StdString* const var, const CVarPath* const path) { char full_name_in[NC_MAX_NAME +1]; int nbdim = 0, *dimid = NULL; int grpid = this->getGroup(path); int varid = (var != NULL) ? this->getVariable(*var, path) : NC_GLOBAL; std::list retvalue; if (var != NULL) { CheckError(nc_inq_varndims(grpid, varid, &nbdim)); dimid = new int[nbdim](); CheckError(nc_inq_vardimid(grpid, varid, dimid)); } else { CheckError(nc_inq_dimids(grpid, &nbdim, NULL, 1)); dimid = new int[nbdim](); CheckError(nc_inq_dimids(grpid, NULL, dimid, 1)); } for (int i = 0; i < nbdim; i++) { CheckError(nc_inq_dimname(grpid, dimid[i], full_name_in)); StdString dimname(full_name_in); retvalue.push_back(dimname); } delete [] dimid; return retvalue; } std::map CINetCDF4::getDimensions(const StdString* const var, const CVarPath* const path) { StdSize size = 0; char full_name_in[NC_MAX_NAME + 1]; int nbdim = 0, *dimid = NULL; int grpid = this->getGroup(path); int varid = (var != NULL) ? this->getVariable(*var, path) : NC_GLOBAL; std::map retvalue; if (var != NULL) { CheckError(nc_inq_varndims(grpid, varid, &nbdim)); dimid = new int[nbdim](); CheckError(nc_inq_vardimid(grpid, varid, dimid)); } else { CheckError(nc_inq_dimids(grpid, &nbdim, NULL, 1)); dimid = new int[nbdim](); CheckError(nc_inq_dimids(grpid, NULL, dimid, 1)); } for (int i = 0; i < nbdim; i++) { CheckError(nc_inq_dimname(grpid, dimid[i], full_name_in)); CheckError(nc_inq_dimlen (grpid, dimid[i], &size)); StdString dimname(full_name_in); retvalue.insert(retvalue.end(), std::make_pair(dimname, size)); } delete [] dimid; return retvalue; } std::list CINetCDF4::getAttributes(const StdString* const var, const CVarPath* const path ) { int nbatt = 0; char full_name_in[NC_MAX_NAME +1]; std::list retvalue; int grpid = this->getGroup(path); int varid = (var != NULL) ? this->getVariable(*var, path) : NC_GLOBAL; if (var != NULL) CheckError(nc_inq_varnatts(grpid, varid, &nbatt)); else CheckError(nc_inq_natts(grpid, &nbatt)); for (int i = 0; i < nbatt; i++) { CheckError(nc_inq_attname(grpid, varid, i, full_name_in)); StdString attname(full_name_in); retvalue.push_back(attname); } return retvalue; } int CINetCDF4::getAttributeId(const StdString& name, const StdString* const var, const CVarPath* const path) { int retvalue = 0; std::list atts = this->getAttributes(var, path); std::list::const_iterator it = atts.begin(), end = atts.end(); for (; it != end; it++) { const StdString& attname = *it; if (attname.compare(name) == 0) return retvalue; retvalue++; } return -1; } //--------------------------------------------------------------- bool CINetCDF4::hasMissingValue(const StdString& name, const CVarPath* const path) { return (this->hasAttribute("missing_value", &name, path) || this->hasAttribute("_FillValue", &name, path)); } bool CINetCDF4::hasAttribute(const StdString& name, const StdString* const var , const CVarPath* const path) { std::list atts = this->getAttributes(var, path); std::list::const_iterator it = atts.begin(), end = atts.end(); for (; it != end; it++) { const StdString& attname = *it; if (attname.compare(name) == 0) return true; } return false; } bool CINetCDF4::hasVariable(const StdString& name, const CVarPath* const path) { std::list variables = this->getVariables(path); std::list::const_iterator it = variables.begin(), end = variables.end(); for (; it != end; it++) { const StdString& varname = *it; if (varname.compare(name) == 0) return true; } return false; } bool CINetCDF4::hasCoordinates(const StdString& name, const CVarPath* const path) { return (this->hasAttribute("coordinates", &name, path)); } bool CINetCDF4::hasBounds(const StdString& name, const CVarPath* const path) { return (this->hasAttribute("bounds", &name, path)); } bool CINetCDF4::hasTemporalDim(const CVarPath* const path) { return (this->getUnlimitedDimension(path) != -1); } //--------------------------------------------------------------- #define GET_ATTRIBUTE_VALUE(type, func_ext, type_enum) \ template <> \ std::vector CINetCDF4::getAttributeValue(const StdString& name, \ const StdString* const var, \ const CVarPath* const path) \ { \ int grpid = this->getGroup(path); \ int varid = (var != NULL) ? this->getVariable(*var, path) : NC_GLOBAL; \ std::pair attinfos = this->getAttribute(name, var, path); \ std::vector retvalue(attinfos.second); \ if (attinfos.first != type_enum) \ ERROR("CINetCDF4::getAttributeValue(name, var, path", \ << "[ name : " << name \ << ", type requested :" << attinfos.first \ << ", type stored : " << type_enum << "]" \ << " Invalid type !"); \ CheckError(nc_get_att_##func_ext(grpid, varid, name.c_str(), &(retvalue[0]))); \ return retvalue; \ } GET_ATTRIBUTE_VALUE(double, double, NC_DOUBLE) GET_ATTRIBUTE_VALUE(float, float, NC_FLOAT) GET_ATTRIBUTE_VALUE(int, int , NC_INT) GET_ATTRIBUTE_VALUE(char, text, NC_CHAR) template <> StdString CINetCDF4::getAttributeValue(const StdString& name, const StdString* const var, const CVarPath* const path) { std::vector chart = this->getAttributeValue >(name, var, path); StdString retvalue(&(chart[0]), chart.size()); return retvalue; } template <> int CINetCDF4::getMissingValue(const StdString& name, const CVarPath* const path) { if (this->hasAttribute("missing_value", &name, path)) return (this->getAttributeValue >("missing_value", &name, path)[0]); if (this->hasAttribute("_FillValue", &name, path)) return (this->getAttributeValue >("_FillValue", &name, path)[0]); return 0; } template <> double CINetCDF4::getMissingValue(const StdString& name, const CVarPath* const path) { if (this->hasAttribute("missing_value", &name, path)) return (this->getAttributeValue >("missing_value", &name, path)[0]); if (this->hasAttribute("_FillValue", &name, path)) return (this->getAttributeValue >("_FillValue", &name, path)[0]); return 0; } template <> float CINetCDF4::getMissingValue(const StdString& name, const CVarPath* const path) { if (this->hasAttribute("missing_value", &name, path)) return (this->getAttributeValue >("missing_value", &name, path)[0]); if (this->hasAttribute("_FillValue", &name, path)) return (this->getAttributeValue >("_FillValue", &name, path)[0]); return 0; } //--------------------------------------------------------------- std::list CINetCDF4::getCoordinatesIdList(const StdString& name, const CVarPath* const path) { std::list retvalue; StdString value = this->getCoordinatesId(name, path); boost::split(retvalue, value, boost::is_any_of(" ")); std::list::iterator it = retvalue.begin(), end = retvalue.end(); for (; it != end; it++) { StdString& coord = *it; coord.assign(coord.data()); } return retvalue; } StdString CINetCDF4::getCoordinatesId(const StdString& name, const CVarPath* const path) { StdString retvalue; if (this->hasAttribute("coordinates", &name, path)) { return (this->getAttributeValue("coordinates", &name, path)); } else { std::list dims = this->getDimensionsList(&name, path); std::list::const_iterator it = dims.begin(), end = dims.end(); for (; it != end; it++) { const StdString& value = *it; retvalue.append(value).push_back(' '); } retvalue.erase(retvalue.end() - 1) ; } return retvalue; } StdString CINetCDF4::getBoundsId(const StdString& name, const CVarPath* const path) { StdString retvalue; if (this->hasAttribute("bounds", &name, path)) return (this->getAttributeValue("bounds", &name, path)); return retvalue; } //--------------------------------------------------------------- bool CINetCDF4::isBound(const StdString& name, const CVarPath* const path) { std::set bounds = this->getBoundVariables(path); return (bounds.find(name) != bounds.end()); } bool CINetCDF4::isCoordinate(const StdString& name, const CVarPath* const path) { std::set coords = this->getCoordVariables(path); return (coords.find(name) != coords.end()); } bool CINetCDF4::isRectilinear(const StdString& name, const CVarPath* const path) { std::list coords = this->getCoordinatesIdList(name, path); std::list::const_iterator it = coords.begin(), end = coords.end(); for (; it != end; it++) { const StdString& coord = *it; if (this->hasVariable(coord, path) && !this->isTemporal(coord, path)) { std::map dimvar = this->getDimensions(&coord, path); if ((dimvar.size() == 1) && (dimvar.find(coord) != dimvar.end())) continue; else return false; } } return true; } bool CINetCDF4::isCurvilinear(const StdString& name, const CVarPath* const path) { if (this->isRectilinear(name, path) || !this->hasCoordinates(name, path)) return false; std::list coords = this->getCoordinatesIdList(name, path); std::list::const_iterator it = coords.begin(), end = coords.end(); for (; it != end; it++) { const StdString& coord = *it; if (this->hasVariable(coord, path)) { std::map dimvar = this->getDimensions(&coord, path); if (dimvar.size() != 2) return false; } else return false; } return true; } bool CINetCDF4::isUnstructured(const StdString& name, const CVarPath* const path) { if (this->isRectilinear(name, path) || this->isCurvilinear(name, path) || !this->hasCoordinates(name, path)) return false; StdString dimname = this->getDimensionsList(&name, path).back(); std::list coords = this->getCoordinatesIdList(name, path); std::list::const_iterator it = coords.begin(), end = coords.end(); for (; it != end; it++) { const StdString& coord = *it; if (this->hasVariable(coord, path)) { std::map dimvar = this->getDimensions(&coord, path); if ((dimvar.size() == 1) && (dimvar.find(dimname) != dimvar.end())) continue; else return false; } else return false; } return true; } bool CINetCDF4::isUnknown(const StdString& name, const CVarPath* const path) { return !(this->isRectilinear(name, path) || this->isCurvilinear(name, path) || this->isUnstructured(name, path)); } bool CINetCDF4::isTemporal(const StdString& name, const CVarPath* const path) { if (!this->hasTemporalDim(path)) return false; std::map dims = this->getDimensions(&name, path); if (dims.find(this->getUnlimitedDimensionName(path)) != dims.end()) return true; return false; } bool CINetCDF4::is3Dim(const StdString& name, const CVarPath* const path) { int i = 0; std::list coords = this->getCoordinatesIdList(name, path); std::list::const_iterator it = coords.begin(), end = coords.end(); for (; it != end; it++) { const StdString& coord = *it; if (this->hasVariable(coord, path)) { if (this->isTemporal(coord, path)) continue; i++; } else { if (coord.compare(this->getUnlimitedDimensionName()) == 0) continue; i++; } } return (i == 3); } bool CINetCDF4::isCellGrid(const StdString& name, const CVarPath* const path) { if (this->isCoordinate(name, path)) { return (this->hasBounds(name, path)); } else { std::list coords = this->getCoordinatesIdList(name, path); std::list::const_iterator it = coords.begin(), end = coords.end(); for (; it != end; it++) { const StdString& coord = *it; if (this->hasVariable(coord, path)) { if (this->isTemporal(coord, path)) continue; if (this->isCellGrid(coord, path)) continue; return false; } else { if (coord.compare(this->getUnlimitedDimensionName()) == 0) continue; return false; } } } return true; } //--------------------------------------------------------------- std::list CINetCDF4::getDataVariables(bool _is3D, bool _isRecti, bool _isCurvi, bool _isUnstr, bool _isCellData, bool _isTemporal, const CVarPath* const path) { std::list retvalue; std::list allvars = this->getVariables(path); std::set allcoords = this->getCoordVariables(path); std::list::const_iterator it = allvars.begin(), end = allvars.end(); for (; it != end; it++) { const StdString& var = *it; if (this->isCoordinate(var, path)) continue; if (!_isRecti && this->isRectilinear(var, path)) continue; if (!_isCurvi && this->isCurvilinear(var, path)) continue; if (!_isUnstr && this->isUnstructured(var, path)) continue; if (!_isTemporal && this->isTemporal(var, path)) continue; if (!_is3D && this->is3Dim(var, path)) continue; if (!_isCellData && this->isCellGrid(var, path)) continue; if (this->isUnknown(var, path)) continue; retvalue.push_back(var); } return retvalue; } //--------------------------------------------------------------- void CINetCDF4::getDataInfo(const StdString& var, const CVarPath* const path, StdSize record, std::vector& sstart, std::vector& scount, StdSize& array_size, const std::vector* start /*= NULL*/, const std::vector* count /*= NULL*/) { std::list dimlist = this->getDimensionsList(&var, path); std::map dimmap = this->getDimensions(&var, path); std::list::iterator it = dimlist.begin(); if (this->isTemporal(var, path)) { if (record != UNLIMITED_DIM) sstart.push_back(record); else sstart.push_back(0); scount.push_back(1); it++; } for (int i = 0; it != dimlist.end(); it++, i++) { if (start && count) { sstart.push_back((*start)[i]); scount.push_back((*count)[i]); array_size *= (*count)[i]; } else { sstart.push_back(0); scount.push_back(dimmap[*it]); array_size *= dimmap[*it]; } } } template <> void CINetCDF4::getData(CArray& data, const StdString& var, const CVarPath* const path, StdSize record) { std::vector start, count; int grpid = this->getGroup(path); int varid = this->getVariable(var, path); StdSize array_size = 1; this->getDataInfo(var, path, record, start, count, array_size); data.resize(array_size); CheckError(nc_get_vara_int(grpid, varid, &(start[0]), &(count[0]), data.dataFirst())); } template <> void CINetCDF4::getData(CArray& data, const StdString& var, const CVarPath* const path, StdSize record) { std::vector start, count; int grpid = this->getGroup(path); int varid = this->getVariable(var, path); StdSize array_size = 1; this->getDataInfo(var, path, record, start, count, array_size); data.resize(array_size); CheckError(nc_get_vara_double(grpid, varid, &(start[0]), &(count[0]), data.dataFirst())); } template <> void CINetCDF4::getData(CArray& data, const StdString& var, const CVarPath* const path, StdSize record) { std::vector start, count; int grpid = this->getGroup(path); int varid = this->getVariable(var, path); StdSize array_size = 1; this->getDataInfo(var, path, record, start, count, array_size); data.resize(array_size); CheckError(nc_get_vara_float(grpid, varid, &(start[0]), &(count[0]), data.dataFirst())); } template <> void CINetCDF4::getData(CArray& data, const StdString& var, bool collective, StdSize record, const std::vector* start /*= NULL*/, const std::vector* count /*= NULL*/) { int varid = this->getVariable(var); if (this->mpi && collective) CNetCdfInterface::varParAccess(ncidp, varid, NC_COLLECTIVE); if (this->mpi && !collective) CNetCdfInterface::varParAccess(ncidp, varid, NC_INDEPENDENT); std::vector sstart, scount; StdSize array_size = 1; this->getDataInfo(var, NULL, record, sstart, scount, array_size, start, count); if (data.numElements() != array_size) { ERROR("CONetCDF4::getData(...)", << "[ Array size = " << data.numElements() << ", Data size = " << array_size << " ] Invalid array size"); } CheckError(nc_get_vara_double(ncidp, varid, &(sstart[0]), &(scount[0]), data.dataFirst())); } //--------------------------------------------------------------- StdString CINetCDF4::getLonCoordName(const StdString& varname, const CVarPath* const path) { std::list clist = this->getCoordinatesIdList(varname, path); if (this->hasCoordinates(varname, path)) return (*clist.begin()); else return (*clist.rbegin()); } StdString CINetCDF4::getLatCoordName(const StdString& varname, const CVarPath* const path) { std::list clist = this->getCoordinatesIdList(varname, path); if (this->hasCoordinates(varname, path)) return (*(++clist.begin())); else return (*(++clist.rbegin())); } StdString CINetCDF4::getVertCoordName(const StdString& varname, const CVarPath* const path) { if (!this->is3Dim(varname, path)) return ""; std::list clist = this->getCoordinatesIdList(varname, path); if (this->hasCoordinates(varname, path)) return (*(++(++clist.begin()))); else return (*(++(++clist.rbegin()))); } } // namespace xios