[MOAB-dev] commit/MOAB: 2 new changesets
commits-noreply at bitbucket.org
commits-noreply at bitbucket.org
Sat Mar 29 07:41:10 CDT 2014
2 new commits in MOAB:
https://bitbucket.org/fathomteam/moab/commits/c2765784f964/
Changeset: c2765784f964
Branch: None
User: iulian07
Date: 2014-03-29 04:56:25
Summary: first pass at nc writer
need to finish processing conventional tags, and form the
VarData and global attributes structure
a test is added for writing a temperature after reading
Affected #: 10 files
diff --git a/src/ReaderWriterSet.cpp b/src/ReaderWriterSet.cpp
index 5015a7f..1f254b0 100644
--- a/src/ReaderWriterSet.cpp
+++ b/src/ReaderWriterSet.cpp
@@ -48,6 +48,7 @@
#ifdef NETCDF_FILE
# include "ReadNCDF.hpp"
# include "WriteNCDF.hpp"
+# include "WriteNC.hpp"
# include "WriteSLAC.hpp"
# include "ReadNC.hpp"
# include "ReadGCRM.hpp"
@@ -105,7 +106,7 @@ ReaderWriterSet::ReaderWriterSet( Core* mdb, Error* handler )
const char* exo_sufxs[] = { "exo", "exoII", "exo2", "g", "gen", NULL };
register_factory( ReadNCDF::factory, WriteNCDF::factory, "Exodus II", exo_sufxs, "EXODUS" );
register_factory( ReadGCRM::factory, NULL, "GCRM NC", "nc", "GCRM" );
- register_factory( ReadNC::factory, NULL, "Climate NC", "nc", "NC" );
+ register_factory( ReadNC::factory, WriteNC::factory, "Climate NC", "nc", "NC" );
#endif
#ifdef CGNS_FILE
diff --git a/src/io/Makefile.am b/src/io/Makefile.am
index 09fe3d3..232de85 100644
--- a/src/io/Makefile.am
+++ b/src/io/Makefile.am
@@ -15,6 +15,9 @@ AM_CPPFLAGS += -DIS_BUILDING_MB \
if NETCDF_FILE
MOAB_NETCDF_SRCS = ReadNCDF.cpp ReadNCDF.hpp \
WriteNCDF.cpp WriteNCDF.hpp \
+ WriteNC.cpp WriteNC.hpp \
+ NCWriteHelper.cpp NCWriteHelper.hpp \
+ NCWriteEuler.cpp NCWriteEuler.hpp \
WriteSLAC.cpp WriteSLAC.hpp \
ReadNC.cpp ReadNC.hpp \
NCHelper.cpp NCHelper.hpp \
diff --git a/src/io/NCWriteEuler.cpp b/src/io/NCWriteEuler.cpp
new file mode 100644
index 0000000..f17727b
--- /dev/null
+++ b/src/io/NCWriteEuler.cpp
@@ -0,0 +1,16 @@
+/*
+ * NCWriteEuler.cpp
+ *
+ * Created on: Mar 28, 2014
+ */
+
+#include "NCWriteEuler.hpp"
+
+namespace moab {
+
+NCWriteEuler::~NCWriteEuler()
+{
+ // TODO Auto-generated destructor stub
+}
+
+} /* namespace moab */
diff --git a/src/io/NCWriteEuler.hpp b/src/io/NCWriteEuler.hpp
new file mode 100644
index 0000000..3e7f728
--- /dev/null
+++ b/src/io/NCWriteEuler.hpp
@@ -0,0 +1,25 @@
+/*
+ * NCWriteEuler.hpp
+ *
+ * nc write helper for euler type data (CAM)
+ * Created on: Mar 28, 2014
+ *
+ */
+
+#ifndef NCWRITEEULER_HPP_
+#define NCWRITEEULER_HPP_
+
+#include "NCWriteHelper.hpp"
+
+namespace moab {
+
+class NCWriteEuler: public NCWriteHelper
+{
+public:
+ NCWriteEuler(WriteNC* writeNC, const FileOptions& opts, EntityHandle fileSet) :
+ NCWriteHelper(writeNC, opts, fileSet) {};
+ virtual ~NCWriteEuler();
+};
+
+} /* namespace moab */
+#endif /* NCWRITEEULER_HPP_ */
diff --git a/src/io/NCWriteHelper.cpp b/src/io/NCWriteHelper.cpp
new file mode 100644
index 0000000..37817d8
--- /dev/null
+++ b/src/io/NCWriteHelper.cpp
@@ -0,0 +1,22 @@
+/*
+ * NCWriteHelper.cpp
+ *
+ * Created on: Mar 28, 2014
+ * Author: iulian
+ */
+
+#include "NCWriteHelper.hpp"
+#include "NCWriteEuler.hpp"
+
+namespace moab {
+
+//! Get appropriate helper instance for WriteNC class; based on some info in the file set
+NCWriteHelper* NCWriteHelper::get_nc_helper(WriteNC* writeNC, const FileOptions& opts, EntityHandle fileSet)
+{
+
+ // right now, get a cam euler helper
+ return new (std::nothrow) NCWriteEuler(writeNC, opts, fileSet);
+}
+
+
+} /* namespace moab */
diff --git a/src/io/NCWriteHelper.hpp b/src/io/NCWriteHelper.hpp
new file mode 100644
index 0000000..54ce967
--- /dev/null
+++ b/src/io/NCWriteHelper.hpp
@@ -0,0 +1,206 @@
+/*
+ * NCWriteHelper.hpp
+ *
+ * Purpose : Climate NC writer file helper; abstract, will be implemented for each type
+ *
+ * Created on: Mar 28, 2014
+ */
+
+#ifndef NCWRITEHELPER_HPP_
+#define NCWRITEHELPER_HPP_
+#include "WriteNC.hpp"
+
+namespace moab {
+
+class NCWriteHelper
+{
+public:
+ NCWriteHelper(WriteNC* writeNC, const FileOptions& opts, EntityHandle fileSet)
+ :_writeNC(writeNC), _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
+ static NCWriteHelper* get_nc_helper(WriteNC* readNC, const FileOptions& opts, EntityHandle fileSet);
+
+ //! process NC conventional tags
+ ErrorCode process_conventional_tags(EntityHandle fileSet);
+protected:
+ //! Allow NCWriteHelper to directly access members of WriteNC
+ WriteNC* _writeNC;
+
+ const FileOptions& _opts;
+ EntityHandle _fileSet;
+
+ //! Dimensions of time and level
+ int nTimeSteps, nLevels;
+
+ //! Values for time and level
+ std::vector<double> tVals, levVals;
+
+ //! Dimension numbers for time and level
+ int tDim, levDim;
+
+ //! Ignored variables
+ std::set<std::string> ignoredVarNames;
+
+ //! Dummy variables
+ std::set<std::string> dummyVarNames;
+};
+
+#if 0
+
+//! Child helper class for scd mesh, e.g. CAM_EL or CAM_FV
+class ScdNCHelper : public NCHelper
+{
+public:
+ ScdNCHelper(ReadNC* readNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
+: NCHelper(readNC, fileId, opts, fileSet),
+ iDim(-1), jDim(-1), iCDim(-1), jCDim(-1)
+ {
+ for (unsigned int i = 0; i < 6; i++) {
+ gDims[i] = -1;
+ lDims[i] = -1;
+ gCDims[i] = -1;
+ lCDims[i] = -1;
+ }
+
+ locallyPeriodic[0] = locallyPeriodic[1] = locallyPeriodic[2] = 0;
+ globallyPeriodic[0] = globallyPeriodic[1] = globallyPeriodic[2] = 0;
+ }
+ virtual ~ScdNCHelper() {}
+
+private:
+ //! Implementation of NCHelper::check_existing_mesh()
+ virtual ErrorCode check_existing_mesh();
+ //! Implementation of NCHelper::create_mesh()
+ virtual ErrorCode create_mesh(Range& faces);
+ //! Implementation of NCHelper::read_variables()
+ virtual ErrorCode read_variables(std::vector<std::string>& var_names, std::vector<int>& tstep_nums);
+
+ //! Read non-set variables for scd mesh
+ ErrorCode read_scd_variable_to_nonset_allocate(std::vector<ReadNC::VarData>& vdatas,
+ std::vector<int>& tstep_nums);
+ ErrorCode read_scd_variable_to_nonset(std::vector<ReadNC::VarData>& vdatas,
+ std::vector<int>& tstep_nums);
+
+ //! Create COORDS tag for quads coordinate
+ ErrorCode create_quad_coordinate_tag();
+
+ template <typename T> ErrorCode kji_to_jik(size_t ni, size_t nj, size_t nk, void* dest, T* source)
+ {
+ size_t nik = ni * nk, nij = ni * nj;
+ T* tmp_data = reinterpret_cast<T*>(dest);
+ for (std::size_t j = 0; j != nj; j++)
+ for (std::size_t i = 0; i != ni; i++)
+ for (std::size_t k = 0; k != nk; k++)
+ tmp_data[j*nik + i*nk + k] = source[k*nij + j*ni + i];
+ return MB_SUCCESS;
+ }
+
+protected:
+ //! Dimensions of global grid in file
+ int gDims[6];
+
+ //! Dimensions of my local part of grid
+ int lDims[6];
+
+ //! Center dimensions of global grid in file
+ int gCDims[6];
+
+ //! Center dimensions of my local part of grid
+ int lCDims[6];
+
+ //! Values for i/j
+ std::vector<double> ilVals, jlVals;
+
+ //! Center values for i/j
+ std::vector<double> ilCVals, jlCVals;
+
+ //! Dimension numbers for i/j
+ int iDim, jDim;
+
+ //! Center dimension numbers for i/j
+ int iCDim, jCDim;
+
+ //! Whether mesh is locally periodic in i or j or k
+ int locallyPeriodic[3];
+
+ //! Whether mesh is globally periodic in i or j or k
+ int globallyPeriodic[3];
+};
+
+//! Child helper class for ucd mesh, e.g. CAM_SE (HOMME) or MPAS
+class UcdNCHelper : public NCHelper
+{
+public:
+ UcdNCHelper(ReadNC* readNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
+: NCHelper(readNC, fileId, opts, fileSet),
+ nCells(0), nEdges(0), nVertices(0),
+ nLocalCells(0), nLocalEdges(0), nLocalVertices(0),
+ cDim(-1), eDim(-1), vDim(-1) {}
+ virtual ~UcdNCHelper() {}
+
+private:
+ //! Implementation of NCHelper::read_variables()
+ virtual ErrorCode read_variables(std::vector<std::string>& var_names,
+ std::vector<int> &tstep_nums);
+
+ //! Read non-set variables for ucd mesh (implemented differently in child classes)
+ virtual ErrorCode read_ucd_variable_to_nonset_allocate(std::vector<ReadNC::VarData>& vdatas,
+ std::vector<int>& tstep_nums) = 0;
+#ifdef PNETCDF_FILE
+ virtual ErrorCode read_ucd_variable_to_nonset_async(std::vector<ReadNC::VarData>& vdatas,
+ std::vector<int>& tstep_nums) = 0;
+#else
+ virtual ErrorCode read_ucd_variable_to_nonset(std::vector<ReadNC::VarData>& vdatas,
+ std::vector<int>& tstep_nums) = 0;
+#endif
+
+protected:
+ //! This version takes as input the moab range, from which we actually need just the
+ //! size of each sequence, for a proper transpose of the data
+ template <typename T> ErrorCode kji_to_jik_stride(size_t , size_t nj, size_t nk, void* dest, T* source, Range& localGid)
+ {
+ std::size_t idxInSource = 0; // Position of the start of the stride
+ // For each subrange, we will transpose a matrix of size
+ // subrange*nj*nk (subrange takes the role of ni)
+ T* tmp_data = reinterpret_cast<T*>(dest);
+ for (Range::pair_iterator pair_iter = localGid.pair_begin();
+ pair_iter != localGid.pair_end(); ++pair_iter) {
+ std::size_t size_range = pair_iter->second - pair_iter->first + 1;
+ std::size_t nik = size_range * nk, nij = size_range * nj;
+ for (std::size_t j = 0; j != nj; j++)
+ for (std::size_t i = 0; i != size_range; i++)
+ for (std::size_t k = 0; k != nk; k++)
+ tmp_data[idxInSource + j*nik + i*nk + k] = source[idxInSource + k*nij + j*size_range + i];
+ idxInSource += (size_range*nj*nk);
+ }
+ return MB_SUCCESS;
+ }
+
+ //! Dimensions of global grid in file
+ int nCells;
+ int nEdges;
+ int nVertices;
+
+ //! Dimensions of my local part of grid
+ int nLocalCells;
+ int nLocalEdges;
+ int nLocalVertices;
+
+ //! Coordinate values for vertices
+ std::vector<double> xVertVals, yVertVals, zVertVals;
+
+ //! Dimension numbers for nCells, nEdges and nVertices
+ int cDim, eDim, vDim;
+
+ //! Local global ID for cells, edges and vertices
+ Range localGidCells, localGidEdges, localGidVerts;
+};
+#endif
+
+} // namespace moab
+
+#endif
+
diff --git a/src/io/WriteNC.cpp b/src/io/WriteNC.cpp
new file mode 100644
index 0000000..4a3fd6e
--- /dev/null
+++ b/src/io/WriteNC.cpp
@@ -0,0 +1,490 @@
+#include "WriteNC.hpp"
+#include "moab/CN.hpp"
+#include "MBTagConventions.hpp"
+#include "MBParallelConventions.h"
+#include "moab/Interface.hpp"
+#include "moab/Range.hpp"
+#include "moab/WriteUtilIface.hpp"
+#include "moab/FileOptions.hpp"
+#include "NCWriteHelper.hpp"
+
+#include <fstream>
+#include <map>
+#include <set>
+
+#include <iostream>
+
+#define ERRORR(rval, str) \
+ if (MB_SUCCESS != rval) { mWriteIface->report_error("%s", str); return rval; }
+
+#define ERRORS(err, str) \
+ if (err) { mWriteIface->report_error("%s", str); return MB_FAILURE; }
+
+namespace moab {
+
+WriterIface *WriteNC::factory( Interface* iface )
+ { return new WriteNC( iface ); }
+
+WriteNC::WriteNC(Interface *impl)
+ : mbImpl(impl), dbgOut(stderr), partMethod(ScdParData::ALLJORKORI), scdi(NULL),
+
+#ifdef USE_MPI
+ myPcomm(NULL),
+#endif
+
+ noMesh(false), noVars(false), /*spectralMesh(false), noMixedElements(false), noEdges(false),*/
+ gatherSetRank(-1), mGlobalIdTag(0), isParallel(false),
+ myHelper(NULL)
+{
+ assert(impl != NULL);
+ impl->query_interface(mWriteIface);
+}
+
+WriteNC::~WriteNC()
+{
+ mbImpl->release_interface(mWriteIface);
+ if (myHelper != NULL)
+ delete myHelper;
+}
+
+//! writes out a file
+ErrorCode WriteNC::write_file(const char *file_name,
+ const bool overwrite,
+ const FileOptions& options,
+ const EntityHandle *file_set,
+ const int num_set,
+ const std::vector<std::string>&,
+ const Tag*,
+ int,
+ int )
+{
+
+ ErrorCode rval;
+ // See if opts has variable(s) specified
+ std::vector<std::string> var_names;
+ std::vector<int> tstep_nums;
+ std::vector<double> tstep_vals;
+
+ // Get and cache predefined tag handles
+ int dum_val = 0;
+ rval = mbImpl->tag_get_handle(GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER, mGlobalIdTag, MB_TAG_DENSE , &dum_val);
+ if (MB_SUCCESS != rval)
+ return rval;
+
+ // num set has to be 1, we will write only one set, the original file set used to load
+ if (num_set!=1)
+ ERRORR(MB_FAILURE, "we should write only one set, the file set used to read data into");
+
+ rval = parse_options(options, var_names, tstep_nums, tstep_vals);
+ ERRORR(rval, "Trouble parsing option string.");
+
+ // important to create some data that will be used to write the file; dimensions, variables, etc
+ // 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.");
+
+ // Create the file ; assume we will overwrite always, for the time being
+ dbgOut.tprintf(1, "creating file %s\n", file_name);
+ fileName = file_name;
+ int success;
+
+#ifdef PNETCDF_FILE
+ 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
+ success = NCFUNC(create)(MPI_COMM_SELF, file_name, cmode, MPI_INFO_NULL, &fileId);
+#else
+ // this is regular netcdf file
+ success = NCFUNC(create)(file_name, overwrite ? NC_CLOBBER : NC_NOCLOBBER, &fileId);
+#endif
+ ERRORS(success, "failed to create file");
+
+ /* int nc_def_dim (int ncid, const char *name, size_t len, int *dimidp);
+ * example: status = nc_def_dim(fileId, "lat", 18L, &latid);
+ * */
+
+ /*
+ * 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
+ */
+
+ /*
+ * Write an Entire Variable: nc_put_var_ type (double, int)
+ * int nc_put_var_double(int ncid, int varid, const double *dp);
+ */
+ /*
+ * Write an Array of Values: nc_put_vara_ type
+ * int nc_put_vara_double(int ncid, int varid, const size_t start[],
+ const size_t count[], const double *dp);
+ */
+
+
+ return MB_SUCCESS;
+}
+
+ErrorCode WriteNC::parse_options(const FileOptions& opts, std::vector<std::string>& var_names, std::vector<int>& tstep_nums,
+ std::vector<double>& tstep_vals)
+{
+ int tmpval;
+ if (MB_SUCCESS == opts.get_int_option("DEBUG_IO", 1, tmpval)) {
+ dbgOut.set_verbosity(tmpval);
+ dbgOut.set_prefix("NCWrite");
+ }
+
+ ErrorCode rval = opts.get_strs_option("VARIABLE", var_names);
+ if (MB_TYPE_OUT_OF_RANGE == rval)
+ noVars = true;
+ else
+ noVars = false;
+ opts.get_ints_option("TIMESTEP", tstep_nums);
+ opts.get_reals_option("TIMEVAL", tstep_vals);
+ rval = opts.get_null_option("NOMESH");
+ 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: ";
+ for (unsigned int i = 0; i < var_names.size(); i++)
+ std::cerr << var_names[i];
+ std::cerr << std::endl;
+ }
+ if (!tstep_nums.empty()) {
+ std::cerr << "Timesteps requested: ";
+ for (unsigned int i = 0; i < tstep_nums.size(); i++)
+ std::cerr << tstep_nums[i];
+ std::cerr << std::endl;
+ }
+ if (!tstep_vals.empty()) {
+ std::cerr << "Time vals requested: ";
+ for (unsigned int i = 0; i < tstep_vals.size(); i++)
+ std::cerr << tstep_vals[i];
+ std::cerr << std::endl;
+ }
+ }
+
+ // 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);
+
+ if (!isParallel)
+ // Return success here, since rval still has _NOT_FOUND from not finding option
+ // in this case, myPcomm will be NULL, so it can never be used; always check for isParallel
+ // before any use for myPcomm
+ return MB_SUCCESS;
+
+ int pcomm_no = 0;
+ rval = opts.get_int_option("PARALLEL_COMM", pcomm_no);
+ if (rval == MB_TYPE_OUT_OF_RANGE) {
+ mWriteIface->report_error("Invalid value for PARALLEL_COMM option");
+ return rval;
+ }
+ myPcomm = ParallelComm::get_pcomm(mbImpl, pcomm_no);
+ if (0 == myPcomm) {
+ myPcomm = new ParallelComm(mbImpl, MPI_COMM_WORLD);
+ }
+ 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;
+}
+
+// this is the inverse process to create conventional tags
+// will look at <pargal_source>/src/core/fileinfo.cpp, init dim, vars, atts
+ErrorCode WriteNC::process_conventional_tags(EntityHandle fileSet)
+{
+ ErrorCode rval;
+ // start copy
+ Tag tag = 0;
+ std::string tag_name = "__DIM_NAMES";
+ const void * data = NULL;
+ int num_dims = 0;
+ rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, tag, MB_TAG_ANY);
+ ERRORR(rval, "Failed getting conventional tag __DIM_NAMES.");
+ rval = mbImpl->tag_get_by_ptr(tag, &fileSet, 1, &data, &num_dims);
+ ERRORR(rval, "Failed getting values for conventional tag __DIM_NAMES.");
+
+ dbgOut.tprintf(1, "dim names size: %d\n", num_dims);
+
+ std::size_t start = 0;
+ const char * p = static_cast<const char *>(data);
+ Tag dimValsTag = 0;
+ tag_name = "__DIM_LENS";
+ const void * valdata = NULL;
+ int num_vals = 0;
+ rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_INTEGER,
+ dimValsTag, MB_TAG_ANY);
+ ERRORR(rval, "Failed getting conventional tag __DIM_LENS.");
+
+ rval = mbImpl->tag_get_by_ptr(dimValsTag, &fileSet, 1, &valdata, &num_vals);
+ ERRORR(rval, "Failed getting values for conventional tag __DIM_LENS.");
+
+ dbgOut.tprintf(1, "num vals in dim lens tag %d\n", num_vals);
+ const int * intp = static_cast<const int*>(valdata);
+ int idx = -1;
+
+ for (std::size_t i = 0; i != static_cast<std::size_t>(num_dims); ++i)
+ {
+ if (p[i] == '\0')
+ {
+ std::string dim_name(&p[start], i - start);
+ ++idx;
+ int sz = intp[idx];
+ dimNames.push_back(dim_name);
+ dimLens.push_back(sz);
+ dbgOut.tprintf(2, "dimension %s has length %d\n", dim_name.c_str(), sz);
+ // fixme: need info from moab to set unlimited dimension
+ // currently assume each file has the same number of time dimensions
+ /*if ((dim_name == "time") || (dim_name == "Time"))
+ insert(dim_name,
+ *(new pcdim(dim_name, sz * m_file_names.size(), true)));
+ else
+ insert(dim_name, *(new pcdim(dim_name, sz)));*/
+ start = i + 1;
+ }
+ }
+
+ Tag tagMeshType = 0;
+ tag_name = "__MESH_TYPE";
+ data = NULL;
+ int sz = 0;
+ rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, tagMeshType, MB_TAG_ANY);
+ ERRORR(rval, "Failed getting conventional tag __MESH_TYPE.");
+ rval = mbImpl->tag_get_by_ptr(tagMeshType, &fileSet, 1, &data, &sz);
+ ERRORR(rval, "Failed getting values for conventional tag __MESH_TYPE.");
+
+ p = static_cast<const char *>(data);
+ grid_type = std::string(&p[0], sz);
+ dbgOut.tprintf(2, "mesh type: %s \n", grid_type.c_str());
+ // read <__VAR_NAMES_LOCATIONS> tag
+ Tag varLocTag = 0;
+ tag_name = "__VAR_NAMES_LOCATIONS";
+ const void * loc_data = NULL;
+ int loc_sz = 0;
+ rval = mbImpl->tag_get_handle(tag_name.c_str(), 0,
+ MB_TYPE_INTEGER, varLocTag, MB_TAG_ANY);
+ ERRORR(rval, "Failed getting conventional tag __VAR_NAMES_LOCATIONS.");
+ rval = mbImpl->tag_get_by_ptr(varLocTag, &fileSet, 1, &loc_data, &loc_sz);
+ ERRORR(rval, "Failed getting values for conventional tag __VAR_NAMES_LOCATIONS.");
+ const int * loc_p = static_cast<const int *>(loc_data);
+ std::vector<int> varLoc(loc_sz);
+ std::copy(loc_p, loc_p + loc_sz, varLoc.begin());
+
+ /*
+ std::map<int, std::string> locmap;
+ locmap[0] = "VERTEX";
+ locmap[1] = "NSEDGE";
+ locmap[2] = "EWEDGE";
+ if (grid_type == "MPAS")
+ {
+ locmap[3] = "POLYGON";
+ }
+ else
+ {
+ locmap[3] = "QUAD";
+ }
+ locmap[4] = "SET";
+ locmap[5] = "EDGE";
+ locmap[6] = "REGION";
+ */
+ int nthVar = 0;
+
+ Tag tagVarNames = 0;
+ tag_name = "__VAR_NAMES";
+ rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, tagVarNames,
+ MB_TAG_ANY);
+ ERRORR(rval, "Failed getting conventional tag __VAR_NAMES.");
+ data = NULL;
+ int num_vars = 0;
+ rval = mbImpl->tag_get_by_ptr(tagVarNames, &fileSet, 1, &data, &num_vars);
+ ERRORR(rval, "Failed getting values for conventional tag __VAR_NAMES.");
+ p = static_cast<const char *>(data);
+ start = 0;
+ for (std::size_t i = 0; i != static_cast<std::size_t>(num_vars); ++i)
+ {
+ if (p[i] == '\0')
+ {
+ std::string var_name(&p[start], i - start);
+
+ sz = 0;
+ 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);
+ ERRORR(rval, "FAILED to get tag for a variable dimensions");
+ //fixme: doesn't handle variables have 0 dimension
+ if (rval != moab::MB_SUCCESS)
+ {
+ 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);
+ //std::vector<const pcdim*> dims(sz, NULL);
+ const void* ptr = NULL;
+ rval = mbImpl->tag_get_by_ptr(dims_tag, &fileSet, 1, &ptr);
+ //
+ const Tag * ptags = static_cast<const moab::Tag*>(ptr);
+ for (std::size_t j = 0; j != static_cast<std::size_t>(sz); ++j)
+ {
+ std::string dim_name;
+ rval = mbImpl->tag_get_name(ptags[j], dim_name);
+ ERRORR(rval, "name of tag for dimension");
+ dbgOut.tprintf(2, "var name: %s has %d dimensions \n", var_name.c_str(), sz);
+ //dims[j] = &(get_dim(dim_name));
+ }
+ /*insert(var_name,
+ *(new fvar(var_name, moab::MB_TYPE_DOUBLE, dims,
+ locmap[varLoc[nthVar++]])));*/
+ start = i + 1;
+ }
+ }
+
+ // attributes
+#if 0
+ std::vector<std::string> nameVec(num_vars+1);
+ nameVec[0] = "GLOBAL";
+ std::map<std::string, const fvar*>::iterator it = m_vars.begin();
+ for (std::size_t i=1; it != m_vars.end(); ++it, ++i)
+ nameVec[i] = it->first;
+
+ for (std::size_t vec_counter = 0; vec_counter != nameVec.size(); ++vec_counter)
+ {
+ // read __<var_name>_ATTRIBS tag
+ moab::Tag tag = 0;
+ std::string tag_name = "__"+nameVec[vec_counter]+"_ATTRIBS";
+ const void * data = NULL;
+ int sz = 0;
+ moab::ErrorCode rval = m_mb.tag_get_handle(tag_name.c_str(), 0, moab::MB_TYPE_OPAQUE, tag, moab::MB_TAG_ANY);
+ if (rval != moab::MB_SUCCESS)
+ throw pargal_except("Error: " + m_mb.get_error_string(rval),
+ __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+ rval = m_mb.tag_get_by_ptr(tag, &m_file_set, 1, &data, &sz);
+ const char * p = static_cast<const char *>(data);
+ std::string att_val(&p[0], sz);
+ if (vec_counter == 0) nameVec[0]="MOAB_GLOBAL";
+ const std::string& var_name = nameVec[vec_counter];
+
+ // read __<var_name>_ATTRIBS_LEN tag
+ moab::Tag attLenTag = 0;
+ tag_name = tag_name + "_LEN";
+ const void * len_data = NULL;
+ int len_sz = 0;
+ rval = m_mb.tag_get_handle(tag_name.c_str(), 0, moab::MB_TYPE_INTEGER, attLenTag, moab::MB_TAG_ANY);
+ rval = m_mb.tag_get_by_ptr(attLenTag, &m_file_set, 1, &len_data, &len_sz);
+ const int * len_p = static_cast<const int *>(len_data);
+ std::vector<int> attLen(len_sz);
+ std::copy(len_p, len_p+len_sz, attLen.begin());
+
+ // create attribute
+ insert(var_name, *(new pcatt(var_name, att_val, attLen)));
+#endif
+ return MB_SUCCESS;
+}
+#if 0
+
+
+ void
+ fileinfo::init_atts()
+ {
+ std::vector<std::string> nameVec(m_vars.size()+1);
+ nameVec[0] = "GLOBAL";
+ std::map<std::string, const fvar*>::iterator it = m_vars.begin();
+ for (std::size_t i=1; it != m_vars.end(); ++it, ++i)
+ nameVec[i] = it->first;
+
+ for (std::size_t vec_counter = 0; vec_counter != nameVec.size(); ++vec_counter)
+ {
+ // read __<var_name>_ATTRIBS tag
+ moab::Tag tag = 0;
+ std::string tag_name = "__"+nameVec[vec_counter]+"_ATTRIBS";
+ const void * data = NULL;
+ int sz = 0;
+ moab::ErrorCode rval = m_mb.tag_get_handle(tag_name.c_str(), 0, moab::MB_TYPE_OPAQUE, tag, moab::MB_TAG_ANY);
+ if (rval != moab::MB_SUCCESS)
+ throw pargal_except("Error: " + m_mb.get_error_string(rval),
+ __FILE__, __LINE__, __PRETTY_FUNCTION__);
+
+ rval = m_mb.tag_get_by_ptr(tag, &m_file_set, 1, &data, &sz);
+ const char * p = static_cast<const char *>(data);
+ std::string att_val(&p[0], sz);
+ if (vec_counter == 0) nameVec[0]="MOAB_GLOBAL";
+ const std::string& var_name = nameVec[vec_counter];
+
+ // read __<var_name>_ATTRIBS_LEN tag
+ moab::Tag attLenTag = 0;
+ tag_name = tag_name + "_LEN";
+ const void * len_data = NULL;
+ int len_sz = 0;
+ rval = m_mb.tag_get_handle(tag_name.c_str(), 0, moab::MB_TYPE_INTEGER, attLenTag, moab::MB_TAG_ANY);
+ rval = m_mb.tag_get_by_ptr(attLenTag, &m_file_set, 1, &len_data, &len_sz);
+ const int * len_p = static_cast<const int *>(len_data);
+ std::vector<int> attLen(len_sz);
+ std::copy(len_p, len_p+len_sz, attLen.begin());
+
+ // create attribute
+ insert(var_name, *(new pcatt(var_name, att_val, attLen)));
+ }
+ }
+
+ void
+ fileinfo::init_grid_type()
+ {
+ moab::Tag tag = 0;
+ std::string tag_name = "__MESH_TYPE";
+ const void * data = NULL;
+ int sz = 0;
+ moab::ErrorCode rval;
+ rval = m_mb.tag_get_handle(tag_name.c_str(), 0, moab::MB_TYPE_OPAQUE, tag, moab::MB_TAG_ANY);
+ rval = m_mb.tag_get_by_ptr(tag, &m_file_set, 1, &data, &sz);
+ if (rval != moab::MB_SUCCESS)
+ throw pargal_except("Error: " + m_mb.get_error_string(rval),
+ __FILE__, __LINE__, __PRETTY_FUNCTION__);
+ const char * p = static_cast<const char *>(data);
+ m_grid_type = std::string(&p[0], sz);
+ }
+
+ return MB_SUCCESS;
+}
+#endif
+
+} // end moab namespace
diff --git a/src/io/WriteNC.hpp b/src/io/WriteNC.hpp
new file mode 100644
index 0000000..c3b893a
--- /dev/null
+++ b/src/io/WriteNC.hpp
@@ -0,0 +1,208 @@
+/**
+ * MOAB, a Mesh-Oriented datABase, is a software component for creating,
+ * storing and accessing finite element mesh data.
+ *
+ * Copyright 2004 Sandia Corporation. Under the terms of Contract
+ * DE-AC04-94AL85000 with Sandia Coroporation, the U.S. Government
+ * retains certain rights in this software.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef WRITENC_HPP_
+#define WRITENC_HPP_
+
+
+#ifndef IS_BUILDING_MB
+//#error "ReadNC.hpp isn't supposed to be included into an application"
+#endif
+
+#include <vector>
+#include <map>
+#include <set>
+#include <string>
+
+#include "moab/WriterIface.hpp"
+#include "moab/ScdInterface.hpp"
+#include "DebugOutput.hpp"
+
+#ifdef USE_MPI
+#include "moab_mpi.h"
+#include "moab/ParallelComm.hpp"
+#endif
+
+#ifdef PNETCDF_FILE
+#include "pnetcdf.h"
+#define NCFUNC(func) ncmpi_ ## func
+
+//! Collective I/O mode get
+#define NCFUNCAG(func) ncmpi_get ## func ## _all
+
+//! Independent I/O mode get
+#define NCFUNCG(func) ncmpi_get ## func
+
+//! Nonblocking get (request aggregation), used so far only for ucd mesh
+#define NCFUNCREQG(func) ncmpi_iget ## func
+
+#define NCDF_SIZE MPI_Offset
+#define NCDF_DIFF MPI_Offset
+#else
+#include "netcdf.h"
+#define NCFUNC(func) nc_ ## func
+#define NCFUNCAG(func) nc_get ## func
+#define NCFUNCG(func) nc_get ## func
+#define NCDF_SIZE size_t
+#define NCDF_DIFF ptrdiff_t
+#endif
+
+namespace moab {
+
+class WriteUtilIface;
+class ScdInterface;
+class NCWriteHelper;
+
+/**
+ * \brief Export NC files.
+ */
+
+class WriteNC : public WriterIface
+{
+ friend class NCWriteHelper;
+ friend class NCWriteEuler;
+
+public:
+
+ //! factory method
+ static WriterIface* factory( Interface* );
+
+ //! Constructor
+ WriteNC(Interface *impl);
+
+ //! Destructor
+ virtual ~WriteNC();
+
+
+ //! writes out a file
+ ErrorCode write_file(const char *file_name,
+ const bool overwrite,
+ const FileOptions& opts,
+ const EntityHandle *output_list,
+ const int num_sets,
+ const std::vector<std::string>& qa_list,
+ const Tag* tag_list = NULL,
+ int num_tags = 0,
+ int export_dimension = 3);
+
+
+private:
+
+ enum EntityLocation {ENTLOCVERT = 0, ENTLOCNSEDGE, ENTLOCEWEDGE, ENTLOCFACE, ENTLOCSET, ENTLOCEDGE, ENTLOCREGION};
+
+ class AttData
+ {
+ public:
+ AttData() : attId(-1), attLen(0), attVarId(-2) {}
+ int attId;
+ NCDF_SIZE attLen;
+ int attVarId;
+ nc_type attDataType;
+ std::string attName;
+ };
+
+ class VarData
+ {
+ public:VarData() : varId(-1), numAtts(-1), entLoc(ENTLOCSET), numLev(1), sz(0), has_tsteps(false) {}
+ int varId;
+ int numAtts;
+ nc_type varDataType;
+ std::vector<int> varDims; // The dimension indices making up this multi-dimensional variable
+ std::map<std::string, AttData> varAtts;
+ std::string varName;
+ std::vector<Tag> varTags; // Tags created for this variable, e.g. one tag per timestep
+ std::vector<void*> memoryHogs; // these will point to the real data; fill before writing the data
+ std::vector<NCDF_SIZE> writeStarts; // Starting index for reading data values along each dimension
+ std::vector<NCDF_SIZE> writeCounts; // Number of data values to be read along each dimension
+ int entLoc;
+ int numLev;
+ int sz;
+ bool has_tsteps; // Indicate whether timestep numbers are appended to tag names
+ };
+
+ // this info will be reconstructed from metadata stored on conventional fileSet tags
+ //! Dimension names
+ std::vector<std::string> dimNames;
+
+ //! Dimension lengths
+ std::vector<int> dimLens;
+
+ //! Global attribs
+ std::map<std::string, AttData> globalAtts;
+
+ //! Variable info
+ std::map<std::string, VarData> varInfo;
+
+ ErrorCode parse_options(const FileOptions& opts, std::vector<std::string>& var_names, std::vector<int>& tstep_nums,
+ std::vector<double>& tstep_vals);
+ /*
+ * map out the header, from tags on file set; it is the inverse process from
+ * ErrorCode NCHelper::create_conventional_tags
+ */
+ ErrorCode process_conventional_tags(EntityHandle fileSet);
+ // 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
+ //! write options
+ //
+ 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
+ //
+ Tag mGlobalIdTag;
+
+ //! Are we writing in parallel? (probably in the future)
+ bool isParallel;
+
+ // CAM Euler, etc,
+ std::string grid_type;
+ //! Helper class instance
+ NCWriteHelper* myHelper;
+
+};
+
+} // namespace moab
+
+#endif
diff --git a/test/io/Makefile.am b/test/io/Makefile.am
index 61f932a..dd09c0e 100644
--- a/test/io/Makefile.am
+++ b/test/io/Makefile.am
@@ -12,7 +12,7 @@ AM_CPPFLAGS += -DSRCDIR=$(srcdir) \
if NETCDF_FILE
EXODUS_TEST = exodus_test
- NC_TEST = read_nc read_ucd_nc read_mpas_nc
+ NC_TEST = read_nc read_ucd_nc read_mpas_nc write_nc
else
EXODUS_TEST =
NC_TEST =
diff --git a/test/io/write_nc.cpp b/test/io/write_nc.cpp
new file mode 100644
index 0000000..713f886
--- /dev/null
+++ b/test/io/write_nc.cpp
@@ -0,0 +1,90 @@
+#include "TestUtil.hpp"
+#include "moab/Core.hpp"
+
+using namespace moab;
+
+#ifdef MESHDIR
+static const char example_eul[] = STRINGIFY(MESHDIR) "/io/camEul26x48x96.t3.nc";
+#else
+static const char example_eul[] = "/io/camEul26x48x96.t3.nc";
+#endif
+
+#ifdef USE_MPI
+#include "moab_mpi.h"
+#include "moab/ParallelComm.hpp"
+#endif
+
+// CAM-EUL
+void test_read_write_one_var();
+
+ErrorCode get_options(std::string& opts);
+
+int main(int argc, char* argv[])
+{
+ int result = 0;
+
+#ifdef USE_MPI
+ int fail = MPI_Init(&argc, &argv);
+ if (fail)
+ return 1;
+#else
+ argv[0] = argv[argc - argc]; // To remove the warnings in serial mode about unused variables
+#endif
+
+ result += RUN_TEST(test_read_write_one_var);
+
+#ifdef USE_MPI
+ fail = MPI_Finalize();
+ if (fail)
+ return 1;
+#endif
+
+ return result;
+}
+
+void test_read_write_one_var()
+{
+ Core moab;
+ Interface& mb = moab;
+
+ std::string orig;
+ ErrorCode rval = get_options(orig);
+ CHECK_ERR(rval);
+
+ // we will have to read without mesh and without var first, to create some tags that we need
+ // later when we write
+ std::string opts;
+ opts = orig + std::string(";DEBUG_IO=3;NOMESH;VARIABLE=");
+
+ // Need a set for nomesh to work right
+ // this set will have as tags a lot of header information, that will be used for writing back the file
+ EntityHandle set;
+ rval = mb.create_meshset(MESHSET_SET, set);
+ CHECK_ERR(rval);
+
+ rval = mb.load_file(example_eul, &set, opts.c_str());
+ CHECK_ERR(rval);
+
+ // load one variable, and the mesh
+ opts= orig + std::string(";DEBUG_IO=3;VARIABLE=T");
+ rval = mb.load_file(example_eul, &set, opts.c_str());
+ CHECK_ERR(rval);
+
+ // first test will write information about one variable
+ std::string writeopts;
+ writeopts = std::string(";;VARIABLE=T;DEBUG_IO=2;");
+ rval = mb.write_file( "testT.nc", 0, writeopts.c_str(), &set, 1);
+ CHECK_ERR(rval);
+}
+
+ErrorCode get_options(std::string& opts)
+{
+#ifdef USE_MPI
+ // Use parallel options
+ opts = std::string(";;PARALLEL=READ_PART;PARTITION_METHOD=SQIJ");
+ return MB_SUCCESS;
+#else
+ opts = std::string(";;");
+ return MB_SUCCESS;
+#endif
+}
https://bitbucket.org/fathomteam/moab/commits/b92a2bb6602e/
Changeset: b92a2bb6602e
Branch: ncwriter
User: iulian07
Date: 2014-03-29 13:39:46
Summary: print some variables tags during debugging
Affected #: 1 file
diff --git a/src/io/WriteNC.cpp b/src/io/WriteNC.cpp
index 4a3fd6e..a65548a 100644
--- a/src/io/WriteNC.cpp
+++ b/src/io/WriteNC.cpp
@@ -333,15 +333,21 @@ ErrorCode WriteNC::process_conventional_tags(EntityHandle fileSet)
data = NULL;
int num_vars = 0;
rval = mbImpl->tag_get_by_ptr(tagVarNames, &fileSet, 1, &data, &num_vars);
+ dbgOut.tprintf(2, "var names has %d names \n", num_vars );
ERRORR(rval, "Failed getting values for conventional tag __VAR_NAMES.");
p = static_cast<const char *>(data);
start = 0;
+ int idxVar=0;
for (std::size_t i = 0; i != static_cast<std::size_t>(num_vars); ++i)
{
if (p[i] == '\0')
{
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
+ VarData variableDataStruct = varInfo[var_name];
sz = 0;
Tag dims_tag = 0;
std::string dim_names = "__" + var_name + "_DIMS";
@@ -358,6 +364,7 @@ ErrorCode WriteNC::process_conventional_tags(EntityHandle fileSet)
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);
+
//std::vector<const pcdim*> dims(sz, NULL);
const void* ptr = NULL;
rval = mbImpl->tag_get_by_ptr(dims_tag, &fileSet, 1, &ptr);
@@ -368,13 +375,14 @@ ErrorCode WriteNC::process_conventional_tags(EntityHandle fileSet)
std::string dim_name;
rval = mbImpl->tag_get_name(ptags[j], dim_name);
ERRORR(rval, "name of tag for dimension");
- dbgOut.tprintf(2, "var name: %s has %d dimensions \n", var_name.c_str(), sz);
+ dbgOut.tprintf(2, "var name: %s has %s as dimension \n", var_name.c_str(), dim_name.c_str() );
//dims[j] = &(get_dim(dim_name));
}
/*insert(var_name,
*(new fvar(var_name, moab::MB_TYPE_DOUBLE, dims,
locmap[varLoc[nthVar++]])));*/
start = i + 1;
+ idxVar++;
}
}
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