void bi::InputNetCDFBuffer::map() { int ncDim, ncVar; Var* var; std::string name; VarType type; int i, k, id; /* ns dimension */ nsDim = nc_inq_dimid(ncid, "ns"); if (nsDim >= 0) { BI_ERROR_MSG(ns < (int )nc_inq_dimlen(ncid, nsDim), "Given index " << ns << " outside range of ns dimension"); } /* np dimension */ npDim = nc_inq_dimid(ncid, "np"); if (npDim >= 0) { BI_ERROR_MSG(np < 0 || np < (int )nc_inq_dimlen(ncid, npDim), "Given index " << np << " outside range of np dimension"); } /* record dimensions, time and coordinate variables */ int nvars = nc_inq_nvars(ncid); for (i = 0; i < nvars; ++i) { ncVar = i; name = nc_inq_varname(ncid, i); if (name.find("time") == 0) { /* is a time variable */ ncDim = mapTimeDim(ncVar); if (ncDim >= 0) { BOOST_AUTO(iter, std::find(recDims.begin(), recDims.end(), ncDim)); if (iter == recDims.end()) { /* newly encountered record dimension */ recDims.push_back(ncDim); timeVars.push_back(ncVar); coordVars.push_back(-1); } else { /* record dimension encountered before */ k = std::distance(recDims.begin(), iter); BI_ASSERT_MSG(timeVars[k] < 0, "Time variables " << nc_inq_varname(ncid, timeVars[k]) << " and " << name << " cannot share the same record dimension " << nc_inq_dimname(ncid, *iter)); timeVars[k] = ncVar; } } } else if (name.find("coord") == 0) { /* is a coordinate variable */ ncDim = mapCoordDim(ncVar); if (ncDim >= 0) { BOOST_AUTO(iter, std::find(recDims.begin(), recDims.end(), ncDim)); if (iter == recDims.end()) { /* newly encountered record dimension */ recDims.push_back(ncDim); timeVars.push_back(-1); coordVars.push_back(ncVar); } else { /* record dimension encountered before */ k = std::distance(recDims.begin(), iter); BI_ASSERT_MSG(coordVars[k] < 0, "Coordinate variables " << nc_inq_varname(ncid, coordVars[k]) << " and " << name << " cannot share the same record dimension " << nc_inq_dimname(ncid, *iter)); coordVars[k] = ncVar; } } } } /* model variables */ for (i = 0; i < NUM_VAR_TYPES; ++i) { type = static_cast<VarType>(i); /* initialise NetCDF variables for this type */ vars[type].resize(m.getNumVars(type), -1); /* map model variables */ for (id = 0; id < m.getNumVars(type); ++id) { var = m.getVar(type, id); if (var->hasInput()) { BOOST_AUTO(pair, mapVarDim(var)); k = pair.first; ncVar = pair.second; if (ncVar >= 0) { vars[type][id] = ncVar; } modelVars.insert(std::make_pair(k, var)); } } } /* preload random access tables */ std::multimap<real,int> seq; std::vector<size_t> starts(recDims.size(), 0), lens(recDims.size(), 0); real tnxt; for (k = 0; k < int(recDims.size()); ++k) { if (timeVars[k] >= 0 && modelVars.count(k) > 0) { /* ^ ignores record dimensions with no associated time or model * variables */ readTime(timeVars[k], starts[k], &lens[k], &tnxt); seq.insert(std::make_pair(tnxt, k)); } } while (!seq.empty()) { /* next in time */ tnxt = seq.begin()->first; k = seq.begin()->second; seq.erase(seq.begin()); ncDim = recDims[k]; ncVar = timeVars[k]; if (times.empty() || times.back() != tnxt) { times.push_back(tnxt); recStarts.push_back(std::vector < size_t > (recDims.size(), 0)); recLens.push_back(std::vector < size_t > (recDims.size(), 0)); } recStarts.back()[k] = starts[k]; recLens.back()[k] = lens[k]; /* read next time and range for this time variable */ starts[k] += lens[k]; if (starts[k] < nc_inq_dimlen(ncid, ncDim)) { /* more to come on this record dimension */ readTime(ncVar, starts[k], &lens[k], &tnxt); seq.insert(std::make_pair(tnxt, k)); } } }