[MOAB-dev] commit/MOAB: danwu: Introduced ScdNCWriteHelper and UcdNCWriteHelper classes to NC writer and refactored some code, to support parallel write in next step.
commits-noreply at bitbucket.org
commits-noreply at bitbucket.org
Thu Apr 17 18:13:08 CDT 2014
1 new commit in MOAB:
https://bitbucket.org/fathomteam/moab/commits/8d793ea8d0d8/
Changeset: 8d793ea8d0d8
Branch: ncwriter
User: danwu
Date: 2014-04-18 01:12:46
Summary: Introduced ScdNCWriteHelper and UcdNCWriteHelper classes to NC writer and refactored some code, to support parallel write in next step.
Affected #: 13 files
diff --git a/src/io/NCWriteEuler.cpp b/src/io/NCWriteEuler.cpp
index 41661a7..4b3f1ff 100644
--- a/src/io/NCWriteEuler.cpp
+++ b/src/io/NCWriteEuler.cpp
@@ -20,123 +20,4 @@ NCWriteEuler::~NCWriteEuler()
// TODO Auto-generated destructor stub
}
-ErrorCode NCWriteEuler::write_values(std::vector<std::string>& var_names)
-{
- Interface*& mbImpl = _writeNC->mbImpl;
- std::set<std::string>& usedCoordinates = _writeNC->usedCoordinates;
- std::set<std::string>& dummyVarNames = _writeNC->dummyVarNames;
- std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
-
- // Start with coordinates
- for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
- setIt != usedCoordinates.end(); ++setIt) {
- std::string coordName = *setIt; // Deep copy
-
- // Skip dummy coordinate variables (if any)
- if (dummyVarNames.find(coordName) != dummyVarNames.end())
- continue;
-
- std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(coordName);
- if (vit == varInfo.end())
- ERRORR(MB_FAILURE, "Can't find one coordinate variable.");
-
- WriteNC::VarData& varCoordData = vit->second;
-
- int success = 0;
- switch (varCoordData.varDataType) {
- case NC_DOUBLE:
- success = NCFUNCAP(_vara_double)(_fileId, varCoordData.varId, &varCoordData.writeStarts[0],
- &varCoordData.writeCounts[0], (double*)(varCoordData.memoryHogs[0]));
- ERRORS(success, "Failed to write double data.");
- break;
- case NC_INT:
- success = NCFUNCAP(_vara_int)(_fileId, varCoordData.varId, &varCoordData.writeStarts[0],
- &varCoordData.writeCounts[0], (int*)(varCoordData.memoryHogs[0]));
- ERRORS(success, "Failed to write int data.");
- break;
- default:
- success = 1;
- break;
- }
- }
-
- // Now look at requested var_names; if they have time, we will have a list, and write one at a time
- // Need to transpose from lev dimension
- ErrorCode rval;
-
- // For each variable tag in the indexed lists, write a time step data
- // Assume the first dimension is time (need to check); if not, just write regularly
- for (size_t i = 0; i < var_names.size(); i++) {
- std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(var_names[i]);
- if (vit == varInfo.end())
- ERRORR(MB_FAILURE, "Can't find variable requested.");
-
- WriteNC::VarData& variableData = vit->second;
- int numTimeSteps = (int)variableData.varTags.size();
- if (variableData.has_tsteps) {
- // Get entities of this variable
- Range ents;
- switch (variableData.entLoc) {
- case WriteNC::ENTLOCFACE:
- // Faces
- rval = mbImpl->get_entities_by_dimension(_fileSet, 2, ents);
- ERRORR(rval, "Can't get entities for faces.");
- break;
- default:
- ERRORR(MB_FAILURE, "Unexpected entity location type for CAM-EUL non-set variable.");
- }
-
- // A typical variable has 4 dimensions as (time, lev, lat, lon)
- // At each timestep, we need to transpose tag format (lat, lon, lev) back
- // to NC format (lev, lat, lon) for writing
- size_t ni = variableData.writeCounts[3]; // lon
- size_t nj = variableData.writeCounts[2]; // lat
- size_t nk = variableData.writeCounts[1]; // lev
-
- variableData.writeCounts[0] = 1; // We will write one time step
- for (int j = 0; j < numTimeSteps; j++) {
- // We will write one time step, and count will be one; start will be different
- // We will write values directly from tag_iterate, but we should also transpose for level
- // so that means deep copy for transpose
- variableData.writeStarts[0] = j; // This is time, again
- int count;
- void* dataptr;
- rval = mbImpl->tag_iterate(variableData.varTags[j], ents.begin(), ents.end(), count, dataptr);
- assert(count == (int)ents.size());
-
- // Now write from memory directly
- int success = 0;
- switch (variableData.varDataType) {
- case NC_DOUBLE: {
- std::vector<double> tmpdoubledata(ni*nj*nk);
- // Transpose (lat, lon, lev) back to (lev, lat, lon)
- jik_to_kji(ni, nj, nk, &tmpdoubledata[0], (double*)(dataptr));
- success = NCFUNCAP(_vara_double)(_fileId, variableData.varId,
- &variableData.writeStarts[0], &variableData.writeCounts[0],
- &tmpdoubledata[0]);
- ERRORS(success, "Failed to write double data.");
- break;
- }
- default:
- ERRORR(MB_FAILURE, "Not implemented yet.");
- }
- }
- }
- else {
- int success = 0;
- switch (variableData.varDataType) {
- case NC_DOUBLE:
- success = NCFUNCAP(_vara_double)(_fileId, variableData.varId, &variableData.writeStarts[0],
- &variableData.writeCounts[0], (double*)(variableData.memoryHogs[0]));
- ERRORS(success, "Failed to write double data.");
- break;
- default:
- ERRORR(MB_FAILURE, "Not implemented yet.");
- }
- }
- }
-
- return MB_SUCCESS;
-}
-
} /* namespace moab */
diff --git a/src/io/NCWriteEuler.hpp b/src/io/NCWriteEuler.hpp
index e7009e7..2cb6486 100644
--- a/src/io/NCWriteEuler.hpp
+++ b/src/io/NCWriteEuler.hpp
@@ -13,16 +13,13 @@
namespace moab {
-class NCWriteEuler: public NCWriteHelper
+class NCWriteEuler: public ScdNCWriteHelper
{
public:
- NCWriteEuler(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet) :
- NCWriteHelper(writeNC, fileId, opts, fileSet) {}
+ NCWriteEuler(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
+: ScdNCWriteHelper(writeNC, fileId, opts, fileSet) {}
virtual ~NCWriteEuler();
-
-private:
- ErrorCode write_values(std::vector<std::string>& var_names);
};
} // namespace moab
diff --git a/src/io/NCWriteFV.cpp b/src/io/NCWriteFV.cpp
index 39e325e..8de489f 100644
--- a/src/io/NCWriteFV.cpp
+++ b/src/io/NCWriteFV.cpp
@@ -20,9 +20,4 @@ NCWriteFV::~NCWriteFV()
// TODO Auto-generated destructor stub
}
-ErrorCode NCWriteFV::write_values(std::vector<std::string>& var_names)
-{
- return MB_NOT_IMPLEMENTED;
-}
-
} /* namespace moab */
diff --git a/src/io/NCWriteFV.hpp b/src/io/NCWriteFV.hpp
index c9c6a7d..d3286fc 100644
--- a/src/io/NCWriteFV.hpp
+++ b/src/io/NCWriteFV.hpp
@@ -13,16 +13,13 @@
namespace moab {
-class NCWriteFV: public NCWriteHelper
+class NCWriteFV: public ScdNCWriteHelper
{
public:
- NCWriteFV(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet) :
- NCWriteHelper(writeNC, fileId, opts, fileSet) {}
+ NCWriteFV(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
+: ScdNCWriteHelper(writeNC, fileId, opts, fileSet) {}
virtual ~NCWriteFV();
-
-private:
- ErrorCode write_values(std::vector<std::string>& var_names);
};
} // namespace moab
diff --git a/src/io/NCWriteHOMME.cpp b/src/io/NCWriteHOMME.cpp
index bc92cc4..45ccff0 100644
--- a/src/io/NCWriteHOMME.cpp
+++ b/src/io/NCWriteHOMME.cpp
@@ -20,18 +20,116 @@ NCWriteHOMME::~NCWriteHOMME()
// TODO Auto-generated destructor stub
}
-ErrorCode NCWriteHOMME::write_values(std::vector<std::string>& var_names)
+ErrorCode NCWriteHOMME::collect_mesh_info()
{
Interface*& mbImpl = _writeNC->mbImpl;
+ std::vector<std::string>& dimNames = _writeNC->dimNames;
+ std::vector<int>& dimLens = _writeNC->dimLens;
Tag& mGlobalIdTag = _writeNC->mGlobalIdTag;
+
+ ErrorCode rval;
+
+ // Look for time dimension
+ std::vector<std::string>::iterator vecIt;
+ if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "time")) != dimNames.end())
+ tDim = vecIt - dimNames.begin();
+ else {
+ ERRORR(MB_FAILURE, "Couldn't find 'time' dimension.");
+ }
+ nTimeSteps = dimLens[tDim];
+
+ // Get number of levels
+ if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "lev")) != dimNames.end())
+ levDim = vecIt - dimNames.begin();
+ else {
+ ERRORR(MB_FAILURE, "Couldn't find 'lev' dimension.");
+ }
+ nLevels = dimLens[levDim];
+
+ Range local_verts;
+ rval = mbImpl->get_entities_by_dimension(_fileSet, 0, local_verts);
+ ERRORR(rval, "Trouble getting local vertices in current file set.");
+ assert(!local_verts.empty());
+
+ std::vector<int> gids(local_verts.size());
+ rval = mbImpl->tag_get_data(mGlobalIdTag, local_verts, &gids[0]);
+ ERRORR(rval, "Trouble getting global IDs on local vertices.");
+
+ // Restore localGidVerts
+ std::copy(gids.rbegin(), gids.rend(), range_inserter(localGidVerts));
+ nLocalVertices = localGidVerts.size();
+
+ return MB_SUCCESS;
+}
+
+ErrorCode NCWriteHOMME::collect_variable_data(std::vector<std::string>& var_names)
+{
+ NCWriteHelper::collect_variable_data(var_names);
+
+ std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
+
+ for (size_t i = 0; i < var_names.size(); i++) {
+ std::string varname = var_names[i];
+ std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(varname);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find one variable.");
+
+ WriteNC::VarData& currentVarData = vit->second;
+ if (currentVarData.has_tsteps) {
+ // Support non-set variables with 3 dimensions like (time, lev, ncol)
+ assert(3 == currentVarData.varDims.size());
+
+ // Time should be the first dimension
+ assert(tDim == currentVarData.varDims[0]);
+
+ // Set up writeStarts and writeCounts
+ currentVarData.writeStarts.resize(3);
+ currentVarData.writeCounts.resize(3);
+
+ // First: time
+ currentVarData.writeStarts[0] = 0; // This value is timestep dependent, will be set later
+ currentVarData.writeCounts[0] = 1;
+
+ // Next: lev
+ currentVarData.writeStarts[1] = 0;
+ currentVarData.writeCounts[1] = currentVarData.numLev;
+
+ // Finally: ncol
+ switch (currentVarData.entLoc) {
+ case WriteNC::ENTLOCVERT:
+ // Vertices
+ // Start from the first localGidVerts
+ // Actually, this will be reset later for writing
+ currentVarData.writeStarts[2] = localGidVerts[0] - 1;
+ currentVarData.writeCounts[2] = nLocalVertices;
+ break;
+ default:
+ ERRORR(MB_FAILURE, "Unexpected entity location type for HOMME non-set variable.");
+ }
+ }
+
+ // Get variable size
+ currentVarData.sz = 1;
+ for (std::size_t idx = 0; idx != currentVarData.writeCounts.size(); idx++)
+ currentVarData.sz *= currentVarData.writeCounts[idx];
+ }
+
+ return MB_SUCCESS;
+}
+
+ErrorCode NCWriteHOMME::write_values(std::vector<std::string>& var_names)
+{
+ Interface*& mbImpl = _writeNC->mbImpl;
std::set<std::string>& usedCoordinates = _writeNC->usedCoordinates;
std::set<std::string>& dummyVarNames = _writeNC->dummyVarNames;
std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
+ ErrorCode rval;
+
// Start with coordinates
for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
setIt != usedCoordinates.end(); ++setIt) {
- std::string coordName = *setIt; // Deep copy
+ const std::string& coordName = *setIt;
// Skip dummy coordinate variables (e.g. ncol)
if (dummyVarNames.find(coordName) != dummyVarNames.end())
@@ -59,25 +157,10 @@ ErrorCode NCWriteHOMME::write_values(std::vector<std::string>& var_names)
success = 1;
break;
}
- }
+ }
// Now look at requested var_names; if they have time, we will have a list, and write one at a time
// Need to transpose from lev dimension
- Range localGidVerts;
- Range local_verts;
- ErrorCode rval = mbImpl->get_entities_by_dimension(_fileSet, 0, local_verts);
- ERRORR(rval, "Trouble getting local vertices in current file set.");
-
- if (!local_verts.empty()) {
- std::vector<int> gids(local_verts.size());
-
- rval = mbImpl->tag_get_data(mGlobalIdTag, local_verts, &gids[0]);
- ERRORR(rval, "Trouble getting global IDs on local vertices.");
-
- // Restore localGidVerts
- std::copy(gids.rbegin(), gids.rend(), range_inserter(localGidVerts));
- }
-
// For each variable tag in the indexed lists, write a time step data
// Assume the first dimension is time (need to check); if not, just write regularly
for (size_t i = 0; i < var_names.size(); i++) {
@@ -103,10 +186,7 @@ ErrorCode NCWriteHOMME::write_values(std::vector<std::string>& var_names)
// A typical variable has 3 dimensions as (time, lev, ncol)
// At each timestep, we need to transpose tag format (ncol, lev) back
// to NC format (lev, ncol) for writing
- int nLocalVertices = localGidVerts.size(); // ncol
- size_t numLev = variableData.writeCounts[1]; // lev
-
- variableData.writeCounts[0] = 1; // We will write one time step
+ // FIXME: Should use tstep_nums (from writing options) later
for (int j = 0; j < numTimeSteps; j++) {
// We will write one time step, and count will be one; start will be different
// We will write values directly from tag_iterate, but we should also transpose for level
@@ -127,9 +207,9 @@ ErrorCode NCWriteHOMME::write_values(std::vector<std::string>& var_names)
int success = 0;
switch (variableData.varDataType) {
case NC_DOUBLE: {
- std::vector<double> tmpdoubledata(nLocalVertices * numLev);
+ std::vector<double> tmpdoubledata(nLocalVertices * variableData.numLev);
// Transpose (ncol, lev) back to (lev, ncol)
- jik_to_kji(nLocalVertices, 1, numLev, &tmpdoubledata[0], (double*)(dataptr));
+ jik_to_kji(nLocalVertices, 1, variableData.numLev, &tmpdoubledata[0], (double*)(dataptr));
size_t indexInDoubleArray = 0;
size_t ic = 0;
@@ -154,7 +234,7 @@ ErrorCode NCWriteHOMME::write_values(std::vector<std::string>& var_names)
ERRORS(success, "Failed to read double data in loop");
// We need to increment the index in double array for the
// next subrange
- indexInDoubleArray += (endh - starth + 1) * numLev;
+ indexInDoubleArray += (endh - starth + 1) * variableData.numLev;
}
assert(ic == localGidVerts.psize());
#ifdef PNETCDF_FILE
diff --git a/src/io/NCWriteHOMME.hpp b/src/io/NCWriteHOMME.hpp
index 4cdf299..7bb99d9 100644
--- a/src/io/NCWriteHOMME.hpp
+++ b/src/io/NCWriteHOMME.hpp
@@ -13,16 +13,23 @@
namespace moab {
-class NCWriteHOMME: public NCWriteHelper
+class NCWriteHOMME: public UcdNCWriteHelper
{
public:
- NCWriteHOMME(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet) :
- NCWriteHelper(writeNC, fileId, opts, fileSet) {}
+ NCWriteHOMME(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
+: UcdNCWriteHelper(writeNC, fileId, opts, fileSet) {}
virtual ~NCWriteHOMME();
private:
- ErrorCode write_values(std::vector<std::string>& var_names);
+ //! Implementation of NCWriteHelper::collect_mesh_info()
+ virtual ErrorCode collect_mesh_info();
+
+ //! Collect data for specified variables
+ virtual ErrorCode collect_variable_data(std::vector<std::string>& var_names);
+
+ //! Implementation of NCWriteHelper::write_values()
+ virtual ErrorCode write_values(std::vector<std::string>& var_names);
};
} // namespace moab
diff --git a/src/io/NCWriteHelper.cpp b/src/io/NCWriteHelper.cpp
index e70b701..8e50903 100644
--- a/src/io/NCWriteHelper.cpp
+++ b/src/io/NCWriteHelper.cpp
@@ -11,6 +11,16 @@
#include "NCWriteHOMME.hpp"
#include "NCWriteMPAS.hpp"
+#include "moab/WriteUtilIface.hpp"
+
+#include <sstream>
+
+#define ERRORR(rval, str) \
+ if (MB_SUCCESS != rval) { _writeNC->mWriteIface->report_error("%s", str); return rval; }
+
+#define ERRORS(err, str) \
+ if (err) { _writeNC->mWriteIface->report_error("%s", str); return MB_FAILURE; }
+
namespace moab {
//! Get appropriate helper instance for WriteNC class; based on some info in the file set
@@ -30,4 +40,534 @@ NCWriteHelper* NCWriteHelper::get_nc_helper(WriteNC* writeNC, int fileId, const
return NULL;
}
+ErrorCode NCWriteHelper::collect_variable_data(std::vector<std::string>& var_names)
+{
+ Interface*& mbImpl = _writeNC->mbImpl;
+ std::vector<std::string>& dimNames = _writeNC->dimNames;
+ std::vector<int>& dimLens = _writeNC->dimLens;
+ std::set<std::string>& usedCoordinates = _writeNC->usedCoordinates;
+ std::set<std::string>& dummyVarNames = _writeNC->dummyVarNames;
+ std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
+ DebugOutput& dbgOut = _writeNC->dbgOut;
+
+ ErrorCode rval;
+
+ usedCoordinates.clear();
+
+ for (size_t i = 0; i < var_names.size(); i++) {
+ std::string varname = var_names[i];
+ std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(varname);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find one variable.");
+
+ WriteNC::VarData& currentVarData = vit->second;
+
+ currentVarData.has_tsteps = false;
+ if ((std::find(currentVarData.varDims.begin(), currentVarData.varDims.end(), tDim) != currentVarData.varDims.end())
+ && (currentVarData.varDims.size() > 1)) // So it is not time itself
+ currentVarData.has_tsteps = true;
+
+ currentVarData.numLev = 1;
+ if ((std::find(currentVarData.varDims.begin(), currentVarData.varDims.end(), tDim) != currentVarData.varDims.end()))
+ currentVarData.numLev = nLevels;
+
+ dbgOut.tprintf(2, " for variable %s varDims.size %d \n", varname.c_str(), (int)currentVarData.varDims.size());
+ for (size_t j = 0; j < currentVarData.varDims.size(); j++) {
+ std::string dimName = dimNames[currentVarData.varDims[j]];
+ vit = varInfo.find(dimName);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find one coordinate variable.");
+
+ usedCoordinates.insert(dimName); // Collect those used, we will need to write them to the file
+ dbgOut.tprintf(2, " for variable %s need dimension %s with length %d\n", varname.c_str(), dimName.c_str(), dimLens[currentVarData.varDims[j]]);
+ }
+
+ if (currentVarData.has_tsteps) {
+ int index = 0;
+ // FIXME: Should use tstep_nums (from writing options) later
+ while (true) {
+ Tag indexedTag = 0;
+ std::stringstream ssTagNameWithIndex;
+ ssTagNameWithIndex << varname << index;
+ rval = mbImpl->tag_get_handle(ssTagNameWithIndex.str().c_str(), indexedTag);
+ if (MB_SUCCESS != rval)
+ break;
+ dbgOut.tprintf(2, " found indexed tag %d with name %s\n", index, ssTagNameWithIndex.str().c_str());
+ currentVarData.varTags.push_back(indexedTag);
+ index++; // We should get out of the loop at some point
+
+ // The type of the tag is fixed though
+ DataType type;
+ rval = mbImpl->tag_get_data_type(indexedTag, type);
+ ERRORR(rval, "Can't get tag type.");
+
+ currentVarData.varDataType = NC_DOUBLE;
+ if (MB_TYPE_INTEGER == type)
+ currentVarData.varDataType = NC_INT;
+ }
+ }
+ else {
+ // Get the tag with varname
+ Tag tag = 0;
+ rval = mbImpl->tag_get_handle(varname.c_str(), tag);
+ ERRORR(rval, "Can't find one tag.");
+ currentVarData.varTags.push_back(tag); // Really, only one for these
+ const void* data;
+ int size;
+ rval = mbImpl->tag_get_by_ptr(tag, &_fileSet, 1, &data, &size);
+ ERRORR(rval, "Can't get tag values.");
+
+ // Find the type of tag, and use it
+ DataType type;
+ rval = mbImpl->tag_get_data_type(tag, type);
+ ERRORR(rval, "Can't get tag type.");
+
+ currentVarData.varDataType = NC_DOUBLE;
+ if (MB_TYPE_INTEGER == type)
+ currentVarData.varDataType = NC_INT;
+
+ assert(currentVarData.memoryHogs.size() == 0); // Nothing so far
+ currentVarData.memoryHogs.push_back((void*)data);
+
+ if (currentVarData.varDims.empty()) {
+ // Scalar variable
+ currentVarData.writeStarts.push_back(0);
+ currentVarData.writeCounts.push_back(1);
+ }
+ else {
+ for (unsigned int idx = 0; idx != currentVarData.varDims.size(); idx++){
+ currentVarData.writeStarts.push_back(0);
+ currentVarData.writeCounts.push_back(dimLens[currentVarData.varDims[idx]]);
+ }
+ }
+ }
+ }
+
+ // Check that for used coordinates we have found the tags
+ for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
+ setIt != usedCoordinates.end(); ++setIt) {
+ const std::string& coordName = *setIt;
+
+ std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(coordName);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find one coordinate variable.");
+
+ WriteNC::VarData& varCoordData = vit->second;
+ Tag coordTag = 0;
+ rval = mbImpl->tag_get_handle(coordName.c_str(), coordTag);
+ ERRORR(rval, "Can't find one tag.");
+ varCoordData.varTags.push_back(coordTag); // Really, only one for these
+
+ const void* data;
+ int sizeCoordinate;
+ rval = mbImpl->tag_get_by_ptr(coordTag, &_fileSet, 1, &data, &sizeCoordinate);
+ ERRORR(rval, "Can't get coordinate values.");
+ dbgOut.tprintf(2, " found coordinate tag with name %s and length %d\n", coordName.c_str(),
+ sizeCoordinate);
+
+ // Get dimension length (the only dimension of this coordinate variable, with the same name)
+ assert(1 == varCoordData.varDims.size());
+ int coordDimLen = dimLens[varCoordData.varDims[0]];
+
+ if (dummyVarNames.find(coordName) != dummyVarNames.end()) {
+ // For a dummy coordinate variable, the tag size is always 1
+ // The number of coordinates should be set to dimension length, instead of 1
+ assert(1 == sizeCoordinate);
+ sizeCoordinate = coordDimLen;
+ }
+ else {
+ // The number of coordinates should be exactly the same as dimension length
+ assert(sizeCoordinate == coordDimLen);
+ }
+
+ // This is the length
+ varCoordData.sz = sizeCoordinate;
+ varCoordData.writeStarts.resize(1);
+ varCoordData.writeStarts[0] = 0;
+ varCoordData.writeCounts.resize(1);
+ varCoordData.writeCounts[0] = sizeCoordinate;
+
+ // Find the type of tag, and use it
+ DataType type;
+ rval = mbImpl->tag_get_data_type(coordTag, type);
+ ERRORR(rval, "Can't get tag type.");
+
+ varCoordData.varDataType = NC_DOUBLE;
+ if (MB_TYPE_INTEGER == type)
+ varCoordData.varDataType = NC_INT;
+
+ assert(0 == varCoordData.memoryHogs.size()); // Nothing so far
+ varCoordData.memoryHogs.push_back((void*)data);
+ }
+
+ return MB_SUCCESS;
+}
+
+ErrorCode NCWriteHelper::init_file(std::vector<std::string>& var_names)
+{
+ std::vector<std::string>& dimNames = _writeNC->dimNames;
+ std::set<std::string>& usedCoordinates = _writeNC->usedCoordinates;
+ std::set<std::string>& dummyVarNames = _writeNC->dummyVarNames;
+ std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
+ std::map<std::string, WriteNC::AttData>& globalAtts = _writeNC->globalAtts;
+ DebugOutput& dbgOut = _writeNC->dbgOut;
+
+ // First initialize all coordinates, then fill VarData for actual variables (and dimensions)
+ // Check that for used coordinates we have found the tags
+ for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
+ setIt != usedCoordinates.end(); ++setIt) {
+ const std::string& coordName = *setIt;
+
+ std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(coordName);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find one coordinate variable.");
+
+ WriteNC::VarData& varCoordData = vit->second;
+ varCoordData.varDims.resize(1);
+
+ /* int nc_def_dim (int ncid, const char *name, size_t len, int *dimidp);
+ * example: status = nc_def_dim(fileId, "lat", 18L, &latid);
+ */
+
+ // Actually define a dimension
+ if (NCFUNC(def_dim)(_fileId, coordName.c_str(), (size_t)varCoordData.sz,
+ &varCoordData.varDims[0]) != NC_NOERR)
+ ERRORR(MB_FAILURE, "Failed to generate dimension.");
+
+ dbgOut.tprintf(2, " for coordName %s dim id is %d \n", coordName.c_str(), (int)varCoordData.varDims[0]);
+
+ // Create a variable with the same name, and its only dimension the one we just defined
+ /*
+ * int nc_def_var (int ncid, const char *name, nc_type xtype,
+ int ndims, const int dimids[], int *varidp);
+ example: http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c/nc_005fdef_005fvar.html#nc_005fdef_005fvar
+ */
+
+ // Skip dummy coordinate variables (e.g. ncol)
+ if (dummyVarNames.find(coordName) != dummyVarNames.end())
+ continue;
+
+ // Define a coordinate variable
+ if (NCFUNC(def_var)(_fileId, coordName.c_str(), varCoordData.varDataType,
+ 1, &(varCoordData.varDims[0]), &varCoordData.varId) != NC_NOERR)
+ ERRORR(MB_FAILURE, "Failed to create coordinate variable.");
+
+ dbgOut.tprintf(2, " for coordName %s variable id is %d \n", coordName.c_str(), varCoordData.varId);
+ }
+
+ // Now look at requested variables, and update from the index in dimNames to the actual dimension id
+ for (size_t i = 0; i < var_names.size(); i++) {
+ std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(var_names[i]);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find variable requested.");
+
+ WriteNC::VarData& variableData = vit->second;
+ int numDims = (int)variableData.varDims.size();
+ // The index is for dimNames; we need to find out the actual dimension id (from above)
+ for (int j = 0; j < numDims; j++) {
+ std::string dimName = dimNames[variableData.varDims[j]];
+ std::map<std::string, WriteNC::VarData>::iterator vit2 = varInfo.find(dimName);
+ if (vit2 == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find coordinate variable requested.");
+
+ WriteNC::VarData& coordData = vit2->second;
+ // Index in dimNames to actual dimension id
+ variableData.varDims[j] = coordData.varDims[0]; // This one, being a coordinate, is the only one
+ dbgOut.tprintf(2, " dimension with index %d name %s has ID %d \n",
+ j, dimName.c_str(), variableData.varDims[j]);
+ }
+
+ // Define the variable now:
+ if (NCFUNC(def_var)(_fileId, var_names[i].c_str(), variableData.varDataType,
+ (int)variableData.varDims.size(), &(variableData.varDims[0]),
+ &variableData.varId) != NC_NOERR)
+ ERRORR(MB_FAILURE, "Failed to create coordinate variable.");
+
+ dbgOut.tprintf(2, " for variable %s variable id is %d \n", var_names[i].c_str(), variableData.varId);
+ // Now define the variable, with all dimensions
+ }
+
+ // Define global attributes (exactly copied from the original file for the time being)
+ // Should we modify some of them (e.g. revision_Id) later?
+ std::map<std::string, WriteNC::AttData>::iterator attIt;
+ for (attIt = globalAtts.begin(); attIt != globalAtts.end(); ++attIt) {
+ const std::string& attName = attIt->first;
+ WriteNC::AttData& attData = attIt->second;
+ NCDF_SIZE& attLen = attData.attLen;
+ nc_type& attDataType = attData.attDataType;
+ const std::string& attValue = attData.attValue;
+
+ switch (attDataType) {
+ case NC_BYTE:
+ case NC_CHAR:
+ if (NC_NOERR != NCFUNC(put_att_text)(_fileId, NC_GLOBAL, attName.c_str(), attLen, attValue.c_str()))
+ ERRORR(MB_FAILURE, "Failed to define text type attribute.");
+ break;
+ case NC_DOUBLE:
+ if (NC_NOERR != NCFUNC(put_att_double)(_fileId, NC_GLOBAL, attName.c_str(), NC_DOUBLE, 1, (double*)attValue.c_str()))
+ ERRORR(MB_FAILURE, "Failed to define double type attribute.");
+ break;
+ case NC_FLOAT:
+ if (NC_NOERR != NCFUNC(put_att_float)(_fileId, NC_GLOBAL, attName.c_str(), NC_FLOAT, 1, (float*)attValue.c_str()))
+ ERRORR(MB_FAILURE, "Failed to define float type attribute.");
+ break;
+ case NC_INT:
+ if (NC_NOERR != NCFUNC(put_att_int)(_fileId, NC_GLOBAL, attName.c_str(), NC_INT, 1, (int*)attValue.c_str()))
+ ERRORR(MB_FAILURE, "Failed to define int type attribute.");
+ break;
+ case NC_SHORT:
+ if (NC_NOERR != NCFUNC(put_att_short)(_fileId, NC_GLOBAL, attName.c_str(), NC_SHORT, 1, (short*)attValue.c_str()))
+ ERRORR(MB_FAILURE, "Failed to define short type attribute.");
+ break;
+ default:
+ ERRORR(MB_FAILURE, "Unknown attribute data type.");
+ }
+ }
+
+ // Take it out of define mode
+ if (NC_NOERR != NCFUNC(enddef)(_fileId))
+ ERRORR(MB_FAILURE, "Failed to close define mode.");
+
+ return MB_SUCCESS;
+}
+
+ErrorCode ScdNCWriteHelper::collect_mesh_info()
+{
+ Interface*& mbImpl = _writeNC->mbImpl;
+ std::vector<std::string>& dimNames = _writeNC->dimNames;
+ std::vector<int>& dimLens = _writeNC->dimLens;
+
+ ErrorCode rval;
+
+ // Look for time dimension
+ std::vector<std::string>::iterator vecIt;
+ if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "time")) != dimNames.end())
+ tDim = vecIt - dimNames.begin();
+ else if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "t")) != dimNames.end())
+ tDim = vecIt - dimNames.begin();
+ else {
+ ERRORR(MB_FAILURE, "Couldn't find 'time' or 't' dimension.");
+ }
+ nTimeSteps = dimLens[tDim];
+
+ // Get number of levels
+ if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "lev")) != dimNames.end())
+ levDim = vecIt - dimNames.begin();
+ else if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "ilev")) != dimNames.end())
+ levDim = vecIt - dimNames.begin();
+ else {
+ ERRORR(MB_FAILURE, "Couldn't find 'lev' or 'ilev' dimension.");
+ }
+ nLevels = dimLens[levDim];
+
+ // __<dim_name>_LOC_MINMAX (for slon, slat, lon and lat)
+ Tag convTag = 0;
+ rval = mbImpl->tag_get_handle("__slon_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY);
+ ERRORR(rval, "Trouble getting conventional tag __slon_LOC_MINMAX.");
+ int val[2];
+ rval = mbImpl->tag_get_data(convTag, &_fileSet, 1, val);
+ ERRORR(rval, "Trouble getting values for conventional tag __slon_LOC_MINMAX.");
+ lDims[0] = val[0];
+ lDims[3] = val[1];
+
+ rval = mbImpl->tag_get_handle("__slat_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY);
+ ERRORR(rval, "Trouble getting conventional tag __slat_LOC_MINMAX.");
+ rval = mbImpl->tag_get_data(convTag, &_fileSet, 1, val);
+ ERRORR(rval, "Trouble getting values for conventional tag __slat_LOC_MINMAX.");
+ lDims[1] = val[0];
+ lDims[4] = val[1];
+
+ rval = mbImpl->tag_get_handle("__lon_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY);
+ ERRORR(rval, "Trouble getting conventional tag __lon_LOC_MINMAX.");
+ rval = mbImpl->tag_get_data(convTag, &_fileSet, 1, val);
+ ERRORR(rval, "Trouble getting values for conventional tag __lon_LOC_MINMAX.");
+ lCDims[0] = val[0];
+ lCDims[3] = val[1];
+
+ rval = mbImpl->tag_get_handle("__lat_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY);
+ ERRORR(rval, "Trouble getting conventional tag __lat_LOC_MINMAX.");
+ rval = mbImpl->tag_get_data(convTag, &_fileSet, 1, val);
+ ERRORR(rval, "Trouble getting values for conventional tag __lat_LOC_MINMAX.");
+ lCDims[1] = val[0];
+ lCDims[4] = val[1];
+
+ return MB_SUCCESS;
+}
+
+ErrorCode ScdNCWriteHelper::collect_variable_data(std::vector<std::string>& var_names)
+{
+ NCWriteHelper::collect_variable_data(var_names);
+
+ std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
+
+ for (size_t i = 0; i < var_names.size(); i++) {
+ std::string varname = var_names[i];
+ std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(varname);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find one variable.");
+
+ WriteNC::VarData& currentVarData = vit->second;
+ if (currentVarData.has_tsteps) {
+ // Support non-set variables with 4 dimensions like (time, lev, lat, lon)
+ assert(4 == currentVarData.varDims.size());
+
+ // Time should be the first dimension
+ assert(tDim == currentVarData.varDims[0]);
+
+ // Set up writeStarts and writeCounts
+ currentVarData.writeStarts.resize(4);
+ currentVarData.writeCounts.resize(4);
+
+ // First: time
+ currentVarData.writeStarts[0] = 0; // This value is timestep dependent, will be set later
+ currentVarData.writeCounts[0] = 1;
+
+ // Next: lev
+ currentVarData.writeStarts[1] = 0;
+ currentVarData.writeCounts[1] = currentVarData.numLev;
+
+ // Finally: lat (or slat) and lon (or slon)
+ switch (currentVarData.entLoc) {
+ case WriteNC::ENTLOCFACE:
+ // Faces
+ currentVarData.writeStarts[2] = lCDims[1];
+ currentVarData.writeCounts[2] = lCDims[4] - lCDims[1] + 1;
+ currentVarData.writeStarts[3] = lCDims[0];
+ currentVarData.writeCounts[3] = lCDims[3] - lCDims[0] + 1;
+ break;
+ default:
+ ERRORR(MB_FAILURE, "Not implemented yet.");
+ }
+ }
+
+ // Get variable size
+ currentVarData.sz = 1;
+ for (std::size_t idx = 0; idx != currentVarData.writeCounts.size(); idx++)
+ currentVarData.sz *= currentVarData.writeCounts[idx];
+ }
+
+ return MB_SUCCESS;
+}
+
+ErrorCode ScdNCWriteHelper::write_values(std::vector<std::string>& var_names)
+{
+ Interface*& mbImpl = _writeNC->mbImpl;
+ std::set<std::string>& usedCoordinates = _writeNC->usedCoordinates;
+ std::set<std::string>& dummyVarNames = _writeNC->dummyVarNames;
+ std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
+
+ ErrorCode rval;
+
+ // Start with coordinates
+ for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
+ setIt != usedCoordinates.end(); ++setIt) {
+ const std::string& coordName = *setIt;
+
+ // Skip dummy coordinate variables (if any)
+ if (dummyVarNames.find(coordName) != dummyVarNames.end())
+ continue;
+
+ std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(coordName);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find one coordinate variable.");
+
+ WriteNC::VarData& varCoordData = vit->second;
+
+ int success = 0;
+ switch (varCoordData.varDataType) {
+ case NC_DOUBLE:
+ success = NCFUNCAP(_vara_double)(_fileId, varCoordData.varId, &varCoordData.writeStarts[0],
+ &varCoordData.writeCounts[0], (double*)(varCoordData.memoryHogs[0]));
+ ERRORS(success, "Failed to write double data.");
+ break;
+ case NC_INT:
+ success = NCFUNCAP(_vara_int)(_fileId, varCoordData.varId, &varCoordData.writeStarts[0],
+ &varCoordData.writeCounts[0], (int*)(varCoordData.memoryHogs[0]));
+ ERRORS(success, "Failed to write int data.");
+ break;
+ default:
+ success = 1;
+ break;
+ }
+ }
+
+ // Now look at requested var_names; if they have time, we will have a list, and write one at a time
+ // if not, just write regularly
+ for (size_t i = 0; i < var_names.size(); i++) {
+ std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(var_names[i]);
+ if (vit == varInfo.end())
+ ERRORR(MB_FAILURE, "Can't find variable requested.");
+
+ WriteNC::VarData& variableData = vit->second;
+ int numTimeSteps = (int)variableData.varTags.size();
+ if (variableData.has_tsteps) {
+ // Time should be the first dimension
+ assert(tDim == variableData.varDims[0]);
+
+ // Get entities of this variable
+ Range ents;
+ switch (variableData.entLoc) {
+ case WriteNC::ENTLOCFACE:
+ // Faces
+ rval = mbImpl->get_entities_by_dimension(_fileSet, 2, ents);
+ ERRORR(rval, "Can't get entities for faces.");
+ break;
+ default:
+ ERRORR(MB_FAILURE, "Not implemented yet.");
+ }
+
+ // A typical variable has 4 dimensions as (time, lev, lat, lon)
+ // At each timestep, we need to transpose tag format (lat, lon, lev) back
+ // to NC format (lev, lat, lon) for writing
+ size_t ni = variableData.writeCounts[3]; // lon
+ size_t nj = variableData.writeCounts[2]; // lat
+ size_t nk = variableData.writeCounts[1]; // lev
+
+ variableData.writeCounts[0] = 1; // We will write one time step
+ // FIXME: Should use tstep_nums (from writing options) later
+ for (int j = 0; j < numTimeSteps; j++) {
+ // We will write one time step, and count will be one; start will be different
+ // We will write values directly from tag_iterate, but we should also transpose for level
+ // so that means deep copy for transpose
+ variableData.writeStarts[0] = j; // This is time, again
+ int count;
+ void* dataptr;
+ rval = mbImpl->tag_iterate(variableData.varTags[j], ents.begin(), ents.end(), count, dataptr);
+ assert(count == (int)ents.size());
+
+ // Now write from memory directly
+ int success = 0;
+ switch (variableData.varDataType) {
+ case NC_DOUBLE: {
+ std::vector<double> tmpdoubledata(ni*nj*nk);
+ // Transpose (lat, lon, lev) back to (lev, lat, lon)
+ jik_to_kji(ni, nj, nk, &tmpdoubledata[0], (double*)(dataptr));
+ success = NCFUNCAP(_vara_double)(_fileId, variableData.varId,
+ &variableData.writeStarts[0], &variableData.writeCounts[0],
+ &tmpdoubledata[0]);
+ ERRORS(success, "Failed to write double data.");
+ break;
+ }
+ default:
+ ERRORR(MB_FAILURE, "Not implemented yet.");
+ }
+ }
+ }
+ else {
+ int success = 0;
+ switch (variableData.varDataType) {
+ case NC_DOUBLE:
+ success = NCFUNCAP(_vara_double)(_fileId, variableData.varId, &variableData.writeStarts[0],
+ &variableData.writeCounts[0], (double*)(variableData.memoryHogs[0]));
+ ERRORS(success, "Failed to write double data.");
+ break;
+ default:
+ ERRORR(MB_FAILURE, "Not implemented yet.");
+ }
+ }
+ }
+
+ return MB_SUCCESS;
+}
+
} /* namespace moab */
diff --git a/src/io/NCWriteHelper.hpp b/src/io/NCWriteHelper.hpp
index d190922..6678bb5 100644
--- a/src/io/NCWriteHelper.hpp
+++ b/src/io/NCWriteHelper.hpp
@@ -16,16 +16,26 @@ class NCWriteHelper
{
public:
NCWriteHelper(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
- :_writeNC(writeNC), _fileId(fileId), _opts(opts), _fileSet(fileSet) {}
-
+: _writeNC(writeNC), _fileId(fileId), _opts(opts), _fileSet(fileSet),
+ nTimeSteps(0), nLevels(1), tDim(-1), levDim(-1) {}
virtual ~NCWriteHelper() {};
- //! Get appropriate helper instance for WriteNC class; based on some info in the file set
+ //! Get appropriate helper instance for WriteNC class based on some info in the file set
static NCWriteHelper* get_nc_helper(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet);
+ //! Collect necessary info about local mesh
+ virtual ErrorCode collect_mesh_info() = 0;
+
+ //! Collect data for specified variables
+ virtual ErrorCode collect_variable_data(std::vector<std::string>& var_names);
+
//! Take the info from VarData and write first the coordinates, then the actual variables
virtual ErrorCode write_values(std::vector<std::string>& var_names) = 0;
+ //! Initialize file: this is where all defines are done
+ //! The VarData dimension ids are filled up after define
+ ErrorCode init_file(std::vector<std::string>& var_names);
+
protected:
template <typename T> void jik_to_kji(size_t ni, size_t nj, size_t nk, T* dest, T* source)
{
@@ -36,6 +46,7 @@ protected:
dest[k*nij + j*ni + i] = source[j*nik + i*nk + k];
}
+protected:
//! Allow NCWriteHelper to directly access members of WriteNC
WriteNC* _writeNC;
@@ -43,9 +54,69 @@ protected:
int _fileId;
const FileOptions& _opts;
EntityHandle _fileSet;
+
+ //! Dimensions of time and level
+ int nTimeSteps, nLevels;
+
+ //! Dimension numbers for time and level
+ int tDim, levDim;
+};
+
+//! Child helper class for scd mesh, e.g. CAM_EL or CAM_FV
+class ScdNCWriteHelper : public NCWriteHelper
+{
+public:
+ ScdNCWriteHelper(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
+: NCWriteHelper(writeNC, fileId, opts, fileSet)
+ {
+ for (unsigned int i = 0; i < 6; i++) {
+ lDims[i] = -1;
+ lCDims[i] = -1;
+ }
+ }
+ virtual ~ScdNCWriteHelper() {}
+
+private:
+ //! Implementation of NCWriteHelper::collect_mesh_info()
+ virtual ErrorCode collect_mesh_info();
+
+ //! Collect data for specified variables
+ virtual ErrorCode collect_variable_data(std::vector<std::string>& var_names);
+
+ //! Implementation of NCWriteHelper::write_values()
+ virtual ErrorCode write_values(std::vector<std::string>& var_names);
+
+protected:
+ //! Dimensions of my local part of grid
+ int lDims[6];
+
+ //! Center dimensions of my local part of grid
+ int lCDims[6];
+};
+
+//! Child helper class for ucd mesh, e.g. CAM_SE (HOMME) or MPAS
+class UcdNCWriteHelper : public NCWriteHelper
+{
+public:
+ UcdNCWriteHelper(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
+: NCWriteHelper(writeNC, fileId, opts, fileSet),
+ nLocalCells(0), nLocalEdges(0), nLocalVertices(0),
+ cDim(-1), eDim(-1), vDim(-1) {}
+ virtual ~UcdNCWriteHelper() {}
+
+protected:
+ //! Dimensions of my local part of grid
+ int nLocalCells;
+ int nLocalEdges;
+ int nLocalVertices;
+
+ //! Dimension numbers for nCells, nEdges and nVertices
+ int cDim, eDim, vDim;
+
+ //! Local global ID for cells, edges and vertices
+ Range localGidCells, localGidEdges, localGidVerts;
};
} // namespace moab
#endif
-
diff --git a/src/io/NCWriteMPAS.cpp b/src/io/NCWriteMPAS.cpp
index f544e96..72dc35f 100644
--- a/src/io/NCWriteMPAS.cpp
+++ b/src/io/NCWriteMPAS.cpp
@@ -20,7 +20,12 @@ NCWriteMPAS::~NCWriteMPAS()
// TODO Auto-generated destructor stub
}
-ErrorCode NCWriteMPAS::write_values(std::vector<std::string>& var_names)
+ErrorCode NCWriteMPAS::collect_mesh_info()
+{
+ return MB_NOT_IMPLEMENTED;
+}
+
+ErrorCode NCWriteMPAS::write_values(std::vector<std::string>& /* var_names */)
{
return MB_NOT_IMPLEMENTED;
}
diff --git a/src/io/NCWriteMPAS.hpp b/src/io/NCWriteMPAS.hpp
index 3d9e829..702984f 100644
--- a/src/io/NCWriteMPAS.hpp
+++ b/src/io/NCWriteMPAS.hpp
@@ -13,16 +13,20 @@
namespace moab {
-class NCWriteMPAS: public NCWriteHelper
+class NCWriteMPAS: public UcdNCWriteHelper
{
public:
- NCWriteMPAS(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet) :
- NCWriteHelper(writeNC, fileId, opts, fileSet) {}
+ NCWriteMPAS(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
+: UcdNCWriteHelper(writeNC, fileId, opts, fileSet) {}
virtual ~NCWriteMPAS();
private:
- ErrorCode write_values(std::vector<std::string>& var_names);
+ //! Implementation of NCWriteHelper::collect_mesh_info()
+ virtual ErrorCode collect_mesh_info();
+
+ //! Collect data for specified variables
+ virtual ErrorCode write_values(std::vector<std::string>& var_names);
};
} // namespace moab
diff --git a/src/io/WriteNC.cpp b/src/io/WriteNC.cpp
index af20151..2f96223 100644
--- a/src/io/WriteNC.cpp
+++ b/src/io/WriteNC.cpp
@@ -29,12 +29,12 @@ WriterIface *WriteNC::factory(Interface* iface)
}
WriteNC::WriteNC(Interface* impl) :
- mbImpl(impl), dbgOut(stderr), partMethod(ScdParData::ALLJORKORI), scdi(NULL),
+ mbImpl(impl), dbgOut(stderr),
#ifdef USE_MPI
myPcomm(NULL),
#endif
- noMesh(false), noVars(false), /*spectralMesh(false), noMixedElements(false), noEdges(false),*/
- gatherSetRank(-1), mGlobalIdTag(0), isParallel(false),
+ noMesh(false), noVars(false),
+ mGlobalIdTag(0), isParallel(false),
myHelper(NULL)
{
assert(impl != NULL);
@@ -82,7 +82,7 @@ ErrorCode WriteNC::write_file(const char* file_name,
// new variables still need to have some way of defining their dimensions
// maybe it will be passed as write options
rval = process_conventional_tags(*file_set);
- ERRORR(rval, "Trouble getting conventional tags.");
+ ERRORR(rval, "Trouble processing conventional tags.");
// Create the file ; assume we will overwrite always, for the time being
dbgOut.tprintf(1, "creating file %s\n", file_name);
@@ -90,7 +90,7 @@ ErrorCode WriteNC::write_file(const char* file_name,
int success;
#ifdef PNETCDF_FILE
- int cmode= overwrite ? NC_CLOBBER : NC_NOCLOBBER;
+ int cmode = overwrite ? NC_CLOBBER : NC_NOCLOBBER;
if (isParallel)
success = NCFUNC(create)(myPcomm->proc_config().proc_comm(), file_name, cmode, MPI_INFO_NULL, &fileId);
else
@@ -110,10 +110,13 @@ ErrorCode WriteNC::write_file(const char* file_name,
ERRORR(MB_FAILURE, "Failed to get NCWriteHelper class instance.");
}
- rval = collect_variable_data(var_names, tstep_nums, tstep_vals, *file_set);
- ERRORR(rval, "Trouble collecting data.");
+ rval = myHelper->collect_mesh_info();
+ ERRORR(rval, "Trouble collecting mesh info.");
- rval = initialize_file(var_names);
+ rval = myHelper->collect_variable_data(var_names);
+ ERRORR(rval, "Trouble collecting variable data.");
+
+ rval = myHelper->init_file(var_names);
ERRORR(rval, "Failed to initialize file.");
rval = myHelper->write_values(var_names);
@@ -145,19 +148,6 @@ ErrorCode WriteNC::parse_options(const FileOptions& opts, std::vector<std::strin
if (MB_SUCCESS == rval)
noMesh = true;
- /* these are not used yet, maybe later
- rval = opts.get_null_option("SPECTRAL_MESH");
- if (MB_SUCCESS == rval)
- spectralMesh = true;
-
- rval = opts.get_null_option("NO_MIXED_ELEMENTS");
- if (MB_SUCCESS == rval)
- noMixedElements = true;
-
- rval = opts.get_null_option("NO_EDGES");
- if (MB_SUCCESS == rval)
- noEdges = true;*/
-
if (2 <= dbgOut.get_verbosity()) {
if (!var_names.empty()) {
std::cerr << "Variables requested: ";
@@ -179,17 +169,9 @@ ErrorCode WriteNC::parse_options(const FileOptions& opts, std::vector<std::strin
}
}
- // The gather set will be important in parallel, this will be the rank that will accumulate the data
- // to be written in serial
- // Improvement will be for writing in true parallel
- rval = opts.get_int_option("GATHER_SET", 0, gatherSetRank);
- if (MB_TYPE_OUT_OF_RANGE == rval) {
- mWriteIface->report_error("Invalid value for GATHER_SET option.");
- return rval;
- }
// FIXME: copied from readnc, may need revise
#ifdef USE_MPI
- isParallel = (opts.match_option("PARALLEL", "READ_PART") != MB_ENTITY_NOT_FOUND);
+ isParallel = (opts.match_option("PARALLEL", "WRITE_PART") != MB_ENTITY_NOT_FOUND);
if (!isParallel)
// Return success here, since rval still has _NOT_FOUND from not finding option
@@ -209,17 +191,6 @@ ErrorCode WriteNC::parse_options(const FileOptions& opts, std::vector<std::strin
}
const int rank = myPcomm->proc_config().proc_rank();
dbgOut.set_rank(rank);
-
- int dum;
- rval = opts.match_option("PARTITION_METHOD", ScdParData::PartitionMethodNames, dum);
- if (rval == MB_FAILURE) {
- mWriteIface->report_error("Unknown partition method specified.");
- partMethod = ScdParData::ALLJORKORI;
- }
- else if (rval == MB_ENTITY_NOT_FOUND)
- partMethod = ScdParData::ALLJORKORI;
- else
- partMethod = dum;
#endif
return MB_SUCCESS;
@@ -301,8 +272,6 @@ ErrorCode WriteNC::process_conventional_tags(EntityHandle fileSet)
std::vector<int> varNamesLocs(varNamesLocsSz);
std::copy(int_p, int_p + varNamesLocsSz, varNamesLocs.begin());
- int nthVar = 0;
-
Tag varNamesTag = 0;
tag_name = "__VAR_NAMES";
rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, varNamesTag, MB_TAG_ANY);
@@ -323,8 +292,8 @@ ErrorCode WriteNC::process_conventional_tags(EntityHandle fileSet)
std::string var_name(&p[start], i - start);
dbgOut.tprintf(2, "var name: %s index %d \n", var_name.c_str(), idxVar);
- // process var name:
- // This will create/initiate map; we will populate variableDataStruct wit info about dims, tags, etc
+ // Process var name:
+ // This will create/initiate map; we will populate variableDataStruct with info about dims, tags, etc
// reference & is important; otherwise variableDataStruct will go out of scope, and deleted :(
VarData& variableDataStruct = varInfo[var_name];
variableDataStruct.varName = var_name;
@@ -336,19 +305,13 @@ ErrorCode WriteNC::process_conventional_tags(EntityHandle fileSet)
Tag dims_tag = 0;
std::string dim_names = "__" + var_name + "_DIMS";
rval = mbImpl->tag_get_handle(dim_names.c_str(), 0, MB_TYPE_OPAQUE, dims_tag, MB_TAG_ANY);
+ // FIXME: Doesn't handle variables with 0 dimension
ERRORR(rval, "Failed to get tag for a variable dimensions.");
- // FIXME: Doesn't handle variables have 0 dimension
- if (MB_SUCCESS != rval) {
- start = i + 1;
- ++nthVar;
- continue;
- }
rval = mbImpl->tag_get_length(dims_tag, sz);
ERRORR(rval, " size of dimensions for variable");
dbgOut.tprintf(2, "var name: %s has %d dimensions \n", var_name.c_str(), sz);
variableDataStruct.varDims.resize(sz);
- //std::vector<const pcdim*> dims(sz, NULL);
const void* ptr = NULL;
rval = mbImpl->tag_get_by_ptr(dims_tag, &fileSet, 1, &ptr);
@@ -363,9 +326,6 @@ ErrorCode WriteNC::process_conventional_tags(EntityHandle fileSet)
ERRORR(MB_FAILURE, "Dimension not found\n");
variableDataStruct.varDims[j] = (int)(vit - dimNames.begin()); // Will be used for writing
// This will have to change to actual file dimension, for writing
-
- // Do we have a variable for each dimension? I mean, a tag?
- //dims[j] = &(get_dim(dim_name));
}
// Attributes for this variable
@@ -503,273 +463,4 @@ ErrorCode WriteNC::process_concatenated_attribute(const void* attPtr, int attSz,
return MB_SUCCESS;
}
-ErrorCode WriteNC::collect_variable_data(std::vector<std::string>& var_names, std::vector<int>& /* tstep_nums */,
- std::vector<double>& /* tstep_vals */, EntityHandle fileSet)
-{
- // In general, in netcdf, variables that have the same name as their only dimension are called
- // coordinate variables
- // For the time being, check if all dimensions for variables are coordinate variables
- ErrorCode rval;
-
- usedCoordinates.clear();
-
- for (size_t i = 0; i < var_names.size(); i++) {
- std::string varname = var_names[i];
- std::map<std::string, VarData>::iterator vit = varInfo.find(varname);
- if (vit == varInfo.end())
- ERRORR(MB_FAILURE, "Can't find one variable.");
-
- size_t sizeVar = 1; // Get multiplied by dim lengths
- VarData& currentVarData = vit->second;
- dbgOut.tprintf(2, " for variable %s varDims.size %d \n", varname.c_str(), (int)currentVarData.varDims.size());
- for (size_t j = 0; j < currentVarData.varDims.size(); j++) {
- std::string dimName = dimNames[currentVarData.varDims[j]];
- vit = varInfo.find(dimName);
- if (vit == varInfo.end())
- ERRORR(MB_FAILURE, "Can't find one coordinate variable.");
-
- if ((dimName == "time" || dimName == "Time" || dimName == "t") &&
- currentVarData.varDims.size() > 1) // So it is not time itself
- currentVarData.has_tsteps = true;
-
- // Probably will have to look at tstep_vals to match them
- sizeVar *= dimLens[currentVarData.varDims[j]];
- usedCoordinates.insert(dimName); // Collect those used, we will need to write them to the file
- dbgOut.tprintf(2, " for variable %s need dimension %s with length %d\n", varname.c_str(), dimName.c_str(), dimLens[currentVarData.varDims[j]]);
- }
-
- currentVarData.sz = sizeVar;
-
- if (currentVarData.has_tsteps) {
- int index = 0;
- while (true) {
- Tag indexedTag = 0;
- std::stringstream ssTagNameWithIndex;
- ssTagNameWithIndex << varname << index;
- rval = mbImpl->tag_get_handle(ssTagNameWithIndex.str().c_str(), indexedTag);
- if (MB_SUCCESS != rval)
- break;
- dbgOut.tprintf(2, " found indexed tag %d with name %s\n", index, ssTagNameWithIndex.str().c_str());
- currentVarData.varTags.push_back(indexedTag);
- index++; // We should get out of the loop at some point
- // We will have to collect data for these tags; maybe even allocate memory again
-
- // The type of the tag is fixed though
- DataType type;
- rval = mbImpl->tag_get_data_type(indexedTag, type);
- ERRORR(rval, "Can't get tag type.");
-
- currentVarData.varDataType = NC_DOUBLE;
- if (MB_TYPE_INTEGER == type)
- currentVarData.varDataType = NC_INT;
- }
- }
- else {
- // Get the tag with varname
- Tag tag = 0;
- rval = mbImpl->tag_get_handle(varname.c_str(), tag);
- ERRORR(rval, "Can't find one tag.");
- currentVarData.varTags.push_back(tag); // Really, only one for these
- const void* data;
- int size;
- rval = mbImpl->tag_get_by_ptr(tag, &fileSet, 1, &data, &size);
- ERRORR(rval, "Can't get tag values.");
-
- // Find the type of tag, and use it
- DataType type;
- rval = mbImpl->tag_get_data_type(tag, type);
- ERRORR(rval, "Can't get tag type.");
-
- currentVarData.varDataType = NC_DOUBLE;
- if (MB_TYPE_INTEGER == type)
- currentVarData.varDataType = NC_INT;
-
- assert(currentVarData.memoryHogs.size() == 0); // Nothing so far
- currentVarData.memoryHogs.push_back((void*)data);
- }
- }
-
- // Check that for used coordinates we have found the tags
- for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
- setIt != usedCoordinates.end(); ++setIt) {
- std::string coordName = *setIt; // Deep copy
-
- std::map<std::string, VarData>::iterator vit = varInfo.find(coordName);
- if (vit == varInfo.end())
- ERRORR(MB_FAILURE, "Can't find one coordinate variable.");
-
- VarData& varCoordData = vit->second;
- Tag coordTag = 0;
- rval = mbImpl->tag_get_handle(coordName.c_str(), coordTag);
- ERRORR(rval, "Can't find one tag.");
- varCoordData.varTags.push_back(coordTag); // Really, only one for these
-
- const void* data;
- int sizeCoordinate;
- rval = mbImpl->tag_get_by_ptr(coordTag, &fileSet, 1, &data, &sizeCoordinate);
- ERRORR(rval, "Can't get coordinate values.");
- dbgOut.tprintf(2, " found coordinate tag with name %s and length %d\n", coordName.c_str(),
- sizeCoordinate);
-
- // Get dimension length (the only dimension of this coordinate variable, with the same name)
- assert(1 == varCoordData.varDims.size());
- int coordDimLen = dimLens[varCoordData.varDims[0]];
-
- if (dummyVarNames.find(coordName) != dummyVarNames.end()) {
- // For a dummy coordinate variable, the tag size is always 1
- // The number of coordinates should be set to dimension length, instead of 1
- assert(1 == sizeCoordinate);
- sizeCoordinate = coordDimLen;
- }
- else {
- // The number of coordinates should be exactly the same as dimension length
- assert(sizeCoordinate == coordDimLen);
- }
-
- // This is the length
- varCoordData.sz = sizeCoordinate;
- varCoordData.writeStarts.resize(1);
- varCoordData.writeStarts[0] = 0;
- varCoordData.writeCounts.resize(1);
- varCoordData.writeCounts[0] = sizeCoordinate;
-
- // Find the type of tag, and use it
- DataType type;
- rval = mbImpl->tag_get_data_type(coordTag, type);
- ERRORR(rval, "Can't get tag type.");
-
- varCoordData.varDataType = NC_DOUBLE;
- if (MB_TYPE_INTEGER == type)
- varCoordData.varDataType = NC_INT;
-
- assert(varCoordData.memoryHogs.size() == 0); // Nothing so far
- varCoordData.memoryHogs.push_back((void*)data);
- }
-
- return MB_SUCCESS;
-}
-
-ErrorCode WriteNC::initialize_file(std::vector<std::string>& var_names)
-{
- // First initialize all coordinates, then fill VarData for actual variables (and dimensions)
- // Check that for used coordinates we have found the tags
- for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
- setIt != usedCoordinates.end(); ++setIt) {
- std::string coordName = *setIt; // Deep copy
-
- std::map<std::string, VarData>::iterator vit = varInfo.find(coordName);
- if (vit == varInfo.end())
- ERRORR(MB_FAILURE, "Can't find one coordinate variable.");
-
- VarData& varCoordData = vit->second;
- varCoordData.varDims.resize(1);
-
- /* int nc_def_dim (int ncid, const char *name, size_t len, int *dimidp);
- * example: status = nc_def_dim(fileId, "lat", 18L, &latid);
- */
-
- // Actually define a dimension
- if (NCFUNC(def_dim)(fileId, coordName.c_str(), (size_t)varCoordData.sz,
- &varCoordData.varDims[0]) != NC_NOERR)
- ERRORR(MB_FAILURE, "Failed to generate dimension.");
-
- dbgOut.tprintf(2, " for coordName %s dim id is %d \n", coordName.c_str(), (int)varCoordData.varDims[0]);
-
- // Create a variable with the same name, and its only dimension the one we just defined
- /*
- * int nc_def_var (int ncid, const char *name, nc_type xtype,
- int ndims, const int dimids[], int *varidp);
- example: http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c/nc_005fdef_005fvar.html#nc_005fdef_005fvar
- */
-
- // Skip dummy coordinate variables (e.g. ncol)
- if (dummyVarNames.find(coordName) != dummyVarNames.end())
- continue;
-
- // Define a coordinate variable
- if (NCFUNC(def_var)(fileId, coordName.c_str(), varCoordData.varDataType,
- 1, &(varCoordData.varDims[0]), &varCoordData.varId) != NC_NOERR)
- ERRORR(MB_FAILURE, "Failed to create coordinate variable.");
-
- dbgOut.tprintf(2, " for coordName %s variable id is %d \n", coordName.c_str(), varCoordData.varId);
- }
-
- // Now look at requested variables, and update from the index in dimNames to the actual dimension id
- for (size_t i = 0; i < var_names.size(); i++) {
- std::map<std::string, VarData>::iterator vit = varInfo.find(var_names[i]);
- if (vit == varInfo.end())
- ERRORR(MB_FAILURE, "Can't find variable requested.");
-
- VarData& variableData = vit->second;
- int numDims = (int)variableData.varDims.size();
- // The index is for dimNames; we need to find out the actual dimension id (from above)
- for (int j = 0; j < numDims; j++) {
- std::string dimName = dimNames[variableData.varDims[j]];
- std::map<std::string, VarData>::iterator vit2 = varInfo.find(dimName);
- if (vit2 == varInfo.end())
- ERRORR(MB_FAILURE, "Can't find coordinate variable requested.");
-
- VarData& coordData = vit2->second;
- variableData.varDims[j] = coordData.varDims[0]; // This one, being a coordinate, is the only one
- dbgOut.tprintf(2, " dimension with index %d name %s has ID %d \n",
- j, dimName.c_str(), variableData.varDims[j]);
-
- variableData.writeStarts.push_back(0); // Assume we will write all, so start at 0 for all dimensions
- variableData.writeCounts.push_back(coordData.sz); // Again, write all; times will be one at a time
- }
-
- // Define the variable now:
- if (NCFUNC(def_var)(fileId, var_names[i].c_str(), variableData.varDataType,
- (int)variableData.varDims.size(), &(variableData.varDims[0]),
- &variableData.varId) != NC_NOERR)
- ERRORR(MB_FAILURE, "Failed to create coordinate variable.");
-
- dbgOut.tprintf(2, " for variable %s variable id is %d \n", var_names[i].c_str(), variableData.varId);
- // Now define the variable, with all dimensions
- }
-
- // Define global attributes (exactly copied from the original file for the time being)
- // Should we modify some of them (e.g. revision_Id) later?
- std::map<std::string, WriteNC::AttData>::iterator attIt;
- for (attIt = globalAtts.begin(); attIt != globalAtts.end(); ++attIt) {
- const std::string& attName = attIt->first;
- WriteNC::AttData& attData = attIt->second;
- NCDF_SIZE& attLen = attData.attLen;
- nc_type& attDataType = attData.attDataType;
- const std::string& attValue = attData.attValue;
-
- switch (attDataType) {
- case NC_BYTE:
- case NC_CHAR:
- if (NC_NOERR != NCFUNC(put_att_text)(fileId, NC_GLOBAL, attName.c_str(), attLen, attValue.c_str()))
- ERRORR(MB_FAILURE, "Failed to define text type attribute.");
- break;
- case NC_DOUBLE:
- if (NC_NOERR != NCFUNC(put_att_double)(fileId, NC_GLOBAL, attName.c_str(), NC_DOUBLE, 1, (double*)attValue.c_str()))
- ERRORR(MB_FAILURE, "Failed to define double type attribute.");
- break;
- case NC_FLOAT:
- if (NC_NOERR != NCFUNC(put_att_float)(fileId, NC_GLOBAL, attName.c_str(), NC_FLOAT, 1, (float*)attValue.c_str()))
- ERRORR(MB_FAILURE, "Failed to define float type attribute.");
- break;
- case NC_INT:
- if (NC_NOERR != NCFUNC(put_att_int)(fileId, NC_GLOBAL, attName.c_str(), NC_INT, 1, (int*)attValue.c_str()))
- ERRORR(MB_FAILURE, "Failed to define int type attribute.");
- break;
- case NC_SHORT:
- if (NC_NOERR != NCFUNC(put_att_short)(fileId, NC_GLOBAL, attName.c_str(), NC_SHORT, 1, (short*)attValue.c_str()))
- ERRORR(MB_FAILURE, "Failed to define short type attribute.");
- break;
- default:
- ERRORR(MB_FAILURE, "Unknown attribute data type.");
- }
- }
-
- // Take it out of define mode
- if (NC_NOERR != NCFUNC(enddef)(fileId))
- ERRORR(MB_FAILURE, "Failed to close define mode.");
-
- return MB_SUCCESS;
-}
-
} // namespace moab
diff --git a/src/io/WriteNC.hpp b/src/io/WriteNC.hpp
index 47debd5..f9af683 100644
--- a/src/io/WriteNC.hpp
+++ b/src/io/WriteNC.hpp
@@ -57,7 +57,6 @@
namespace moab {
class WriteUtilIface;
-class ScdInterface;
class NCWriteHelper;
/**
@@ -66,13 +65,14 @@ class NCWriteHelper;
class WriteNC : public WriterIface
{
friend class NCWriteHelper;
+ friend class ScdNCWriteHelper;
+ friend class UcdNCWriteHelper;
friend class NCWriteEuler;
friend class NCWriteFV;
friend class NCWriteHOMME;
friend class NCWriteMPAS;
public:
-
//! Factory method
static WriterIface* factory(Interface*);
@@ -94,7 +94,6 @@ public:
int export_dimension = 3);
private:
-
//! ENTLOCNSEDGE for north/south edge
//! ENTLOCWEEDGE for west/east edge
enum EntityLocation {ENTLOCVERT = 0, ENTLOCNSEDGE, ENTLOCEWEDGE, ENTLOCFACE, ENTLOCSET, ENTLOCEDGE, ENTLOCREGION};
@@ -162,37 +161,19 @@ private:
std::vector<int>& attLen,
std::map<std::string, AttData>& attributes);
- //! Will collect data; it should be only on gather processor, but for the time being, collect
- //! for everybody
- ErrorCode collect_variable_data(std::vector<std::string>& var_names, std::vector<int>& tstep_nums,
- std::vector<double>& tstep_vals, EntityHandle fileSet);
-
- //! Initialize file: this is where all defines are done
- //! the VarData dimension ids are filled up after define
- ErrorCode initialize_file(std::vector<std::string>& var_names); // These are from options
-
//! Interface instance
Interface* mbImpl;
WriteUtilIface* mWriteIface;
//! File var
const char* fileName;
- int IndexFile;
+
//! File numbers assigned by (p)netcdf
int fileId;
//! Debug stuff
DebugOutput dbgOut;
- //! Partitioning method
- int partMethod;
-
- //! Scd interface
- ScdInterface* scdi;
-
- //! Parallel data object, to be cached with ScdBox
- ScdParData parData;
-
#ifdef USE_MPI
ParallelComm* myPcomm;
#endif
@@ -201,14 +182,7 @@ private:
bool noMesh;
bool noVars;
- /*
- * Not used yet, maybe later
- bool spectralMesh;
- bool noMixedElements;
- bool noEdges;*/
- int gatherSetRank;
-
- //! Cached tags for writing. this will be important for ordering the data, in parallel
+ //! Cached tags for writing. This will be important for ordering the data, in parallel
Tag mGlobalIdTag;
//! Are we writing in parallel? (probably in the future)
diff --git a/test/io/write_nc.cpp b/test/io/write_nc.cpp
index a9b9e0c..30b3f15 100644
--- a/test/io/write_nc.cpp
+++ b/test/io/write_nc.cpp
@@ -71,13 +71,13 @@ void test_eul_read_write_T()
CHECK_ERR(rval);
// Load non-set variable T, set variable gw, and the mesh
- std::string opts = orig + std::string(";DEBUG_IO=3;VARIABLE=T,gw");
+ std::string opts = orig + std::string(";DEBUG_IO=0;VARIABLE=T,gw");
rval = mb.load_file(example_eul, &set, opts.c_str());
CHECK_ERR(rval);
// Write variables T and gw
std::string writeopts;
- writeopts = std::string(";;VARIABLE=T,gw;DEBUG_IO=2;");
+ writeopts = std::string(";;VARIABLE=T,gw;DEBUG_IO=0;");
rval = mb.write_file("test_eul_T.nc", 0, writeopts.c_str(), &set, 1);
CHECK_ERR(rval);
}
Repository URL: https://bitbucket.org/fathomteam/moab/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
More information about the moab-dev
mailing list