From 4f27af5c3440b9e9c9c870dfd7b2b341fec3fe53 Mon Sep 17 00:00:00 2001 From: Ryan Wollaeger Date: Fri, 7 Jun 2019 17:12:13 -0600 Subject: [PATCH 1/7] Prepare Draco_Mesh for 1D and 3D. + Add optional face type (nodes per face) argument to mesh ctor. + Use face type to compute dimension-agnostic cell connectivity. + Add 1D and 2D tests to tstDraco_Mesh.cc. --- src/mesh/Draco_Mesh.cc | 252 ++++++++++++++++++++++++--- src/mesh/Draco_Mesh.hh | 21 ++- src/mesh/test/Test_Mesh_Interface.hh | 66 +++++-- src/mesh/test/tstDraco_Mesh.cc | 130 ++++++++++++-- 4 files changed, 417 insertions(+), 52 deletions(-) diff --git a/src/mesh/Draco_Mesh.cc b/src/mesh/Draco_Mesh.cc index 38bf00ab50..c02978c6cd 100644 --- a/src/mesh/Draco_Mesh.cc +++ b/src/mesh/Draco_Mesh.cc @@ -1,4 +1,4 @@ -//----------------------------------*-C++-*----------------------------------// +//-----------------------------------*-C++-*----------------------------------// /*! * \file mesh/Draco_Mesh.cc * \author Ryan Wollaeger @@ -6,13 +6,14 @@ * \brief Draco_Mesh class implementation file. * \note Copyright (C) 2018-2019 Triad National Security, LLC. * All rights reserved. */ -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// #include "Draco_Mesh.hh" #include "ds++/Assert.hh" #include #include #include +#include namespace rtt_mesh { @@ -23,17 +24,24 @@ unsigned safe_convert_from_size_t(size_t const in_) { return static_cast(in_); } -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// // CONSTRUCTOR -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// /*! * \brief Draco_Mesh constructor. * * \param[in] dimension_ dimension of mesh * \param[in] geometry_ enumerator of possible coordinate system geometries - * \param[in] cell_type_ number of vertices for each cell + * \param[in] cell_type_ number of vertices for each cell if face_type_ is + * size 0 (empty), otherwise number of faces for each cell. * \param[in] cell_to_node_linkage_ serialized map of cell indices to node - * indices. + * indices. if face_type_ is supplied then nodes are listed per + * cell face. so there are duplicate node entries in 2D or 3D + * since adjacent cell faces will share one or more nodes. when + * face_type_ is supplied, in 2D node ordering will be assumed to + * still be counterclockwise around the cell, in 3D the node + * ordering per face is assumed to be counterclockwise from inside + * the cell looking at the face. * \param[in] side_set_flag_ map of side indices (per cell) to side flag (global * index for a side). * \param[in] side_node_count_ number of nodes per each cell on a side of @@ -50,6 +58,7 @@ unsigned safe_convert_from_size_t(size_t const in_) { * ghost cells to local index of ghost nodes. * \param[in] ghost_cell_number_ cell index local to other processor. * \param[in] ghost_cell_rank_ rank of each ghost cell. + * \param[in] face_type_ number of vertices per face per cell. */ Draco_Mesh::Draco_Mesh(unsigned dimension_, Geometry geometry_, const std::vector &cell_type_, @@ -62,7 +71,8 @@ Draco_Mesh::Draco_Mesh(unsigned dimension_, Geometry geometry_, const std::vector &ghost_cell_type_, const std::vector &ghost_cell_to_node_linkage_, const std::vector &ghost_cell_number_, - const std::vector &ghost_cell_rank_) + const std::vector &ghost_cell_rank_, + const std::vector &face_type_) : dimension(dimension_), geometry(geometry_), num_cells(safe_convert_from_size_t(cell_type_.size())), num_nodes(safe_convert_from_size_t(global_node_number_.size())), @@ -73,13 +83,7 @@ Draco_Mesh::Draco_Mesh(unsigned dimension_, Geometry geometry_, m_side_node_count(side_node_count_), m_side_to_node_linkage(side_to_node_linkage_) { - // Require(dimension_ <= 3); - // \todo: generalize mesh generation to 1D,3D (and uncomment requirment above) - Insist(dimension_ == 2, "dimension_ != 2"); - - // require some constraints on vector sizes - Require(cell_to_node_linkage_.size() == - std::accumulate(cell_type_.begin(), cell_type_.end(), 0u)); + Require(dimension_ <= 3); Require( side_to_node_linkage_.size() == std::accumulate(side_node_count_.begin(), side_node_count_.end(), 0u)); @@ -92,15 +96,31 @@ Draco_Mesh::Draco_Mesh(unsigned dimension_, Geometry geometry_, ghost_cell_to_node_linkage_.size() == std::accumulate(ghost_cell_type_.begin(), ghost_cell_type_.end(), 0u)); - // build the layout (or linkage) of the mesh - compute_cell_to_cell_linkage(cell_type_, cell_to_node_linkage_, - side_node_count_, side_to_node_linkage_, - ghost_cell_type_, ghost_cell_to_node_linkage_); + if (face_type_.size() == 0) { + + // continue to support the original linkage generation for 2D + Insist(dimension_ == 2, "dimension_ != 2"); + + // require some constraints on vector sizes + Check(cell_to_node_linkage_.size() == + std::accumulate(cell_type_.begin(), cell_type_.end(), 0u)); + + // build the layout (or linkage) of the mesh + compute_cell_to_cell_linkage(cell_type_, cell_to_node_linkage_, + side_node_count_, side_to_node_linkage_, + ghost_cell_type_, ghost_cell_to_node_linkage_); + } else { + + // build the layout using face types (number of nodes per face per cell) + compute_cell_to_cell_linkage(cell_type_, cell_to_node_linkage_, face_type_, + side_node_count_, side_to_node_linkage_, + ghost_cell_type_, ghost_cell_to_node_linkage_); + } } -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// // PRIVATE FUNCTIONS -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// /*! * \brief Build the cell-face index map to the corresponding coordinates. * @@ -136,7 +156,7 @@ std::vector> Draco_Mesh::compute_node_coord_vec( return ret_node_coord_vec; } -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// /*! * \brief Build the cell-face index map to the corresponding coordinates. * @@ -183,7 +203,6 @@ void Draco_Mesh::compute_cell_to_cell_linkage( // STEP 4: identify faces and create cell to cell map // \todo: global face index? - // \todo: extend to 1D, 3D // \todo: add all cells as keys to each layout, even without values // identify faces per cell and create cell-to-cell linkage @@ -323,7 +342,150 @@ void Draco_Mesh::compute_cell_to_cell_linkage( Ensure(cell_to_side_linkage.size() <= num_cells); } -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// +/*! + * \brief Build the cell-face index map to the corresponding coordinates. + * + * \param[in] cell_type number of faces per cell. + * \param[in] cell_to_node_linkage serial map of cell to face to node indices. + * \param[in] face_type number of nodes per face per cell + * \param[in] side_node_count number of vertices per side. + * \param[in] side_to_node_linkage serial map of side index to node indices. + * \param[in] ghost_cell_type number of common vertices per ghost cell. + * \param[in] ghost_cell_to_node_linkage vertices in common per ghost cell. + */ +void Draco_Mesh::compute_cell_to_cell_linkage( + const std::vector &cell_type, + const std::vector &cell_to_node_linkage, + const std::vector &face_type, + const std::vector &side_node_count, + const std::vector &side_to_node_linkage, + const std::vector &ghost_cell_type, + const std::vector &ghost_cell_to_node_linkage) { + + Require(face_type.size() > 0); + Require(face_type.size() == + std::accumulate(cell_type.begin(), cell_type.end(), 0u)); + + // (1) create map of cell face to node set + + std::map> cface_to_nodes; + + // initialize cell face counter and cell-node iterator + unsigned cf_counter = 0; + std::vector::const_iterator cn_first = cell_to_node_linkage.begin(); + + // convert cell-node linkage to map of cell face to + for (unsigned cell = 0; cell < num_cells; ++cell) { + for (unsigned face = 0; face < cell_type[cell]; ++face) { + + // convert iterator to node indices to set of node indices + cface_to_nodes[cf_counter] = + std::set(cn_first, cn_first + face_type[cf_counter]); + + // increment iterator and counter + cn_first += face_type[cf_counter]; + cf_counter++; + } + } + + Check(cn_first == cell_to_node_linkage.end()); + + // (2) create a map of node-sets to cells + + std::map, std::vector> nodes_to_cells; + + // reset cf_counter + cf_counter = 0; + + for (unsigned cell = 0; cell < num_cells; ++cell) { + for (unsigned face = 0; face < cell_type[cell]; ++face) { + + // invert the map + nodes_to_cells[cface_to_nodes[cf_counter]].push_back(cell); + + // increment counter + cf_counter++; + } + } + + // (3) create maps of nodes to boundary faces (sides) and parallel faces + + std::map, unsigned> nodes_to_side = + compute_node_vec_indx_map(side_node_count, side_to_node_linkage); + + std::map, unsigned> nodes_to_ghost = + compute_node_vec_indx_map(ghost_cell_type, ghost_cell_to_node_linkage); + + // (4) create cell-to-cell, cell-to-side, cell-to-ghost-cell linkage + + // reset cf_counter and cell-node iterator + cf_counter = 0; + cn_first = cell_to_node_linkage.begin(); + + for (unsigned cell = 0; cell < num_cells; ++cell) { + for (unsigned face = 0; face < cell_type[cell]; ++face) { + + // initialize this face to not having a condition + bool has_face_cond = false; + + // get the cells associated with this cell face from the nodes + const std::vector &cells = + nodes_to_cells[cface_to_nodes[cf_counter]]; + + Check(cells.size() >= 1); + Check(cells.size() <= 2); + + // get ordered node vector from cell_to_node_linkage + const std::vector node_vec(cn_first, + cn_first + face_type[cf_counter]); + + // check how many cells are associated with the face + if (cells.size() == 2) { + + // get neighbor cell index + const unsigned oth_cell = cell == cells[0] ? cells[1] : cells[0]; + + Check(oth_cell != cell); + + // add to cell-cell linkage + cell_to_cell_linkage[cell].push_back( + std::make_pair(oth_cell, node_vec)); + + // a neighbor cell was found + has_face_cond = true; + } + + // check if a boundary/side exists for this node set + if (nodes_to_side.find(node_vec) != nodes_to_side.end()) { + + // populate cell-boundary face layout + cell_to_side_linkage[cell].push_back( + std::make_pair(nodes_to_side[node_vec], node_vec)); + + has_face_cond = true; + } + + // check if a parallel face exists for this node set + if (nodes_to_ghost.find(node_vec) != nodes_to_ghost.end()) { + + // populate cell-parallel face layout + cell_to_ghost_cell_linkage[cell].push_back( + std::make_pair(nodes_to_ghost[node_vec], node_vec)); + + has_face_cond = true; + } + + // increment iterator and counter + cn_first += face_type[cf_counter]; + cf_counter++; + } + } + + Ensure(cn_first == cell_to_node_linkage.end()); +} + +//----------------------------------------------------------------------------// /*! * \brief Build an intermediate node-index map to support layout generation. * @@ -360,8 +522,48 @@ std::map> Draco_Mesh::compute_node_indx_map( return node_to_indx_map; } +//----------------------------------------------------------------------------// +/*! + * \brief Build a map of node vectors to indices map for boundary layouts. + * + * Note: the ordering of the nodes in the mesh ctor must match the node ordering + * of the corresponding (local) cell face. + * + * \param[in] indx_type vector of number of nodes, subscripted by index. + * \param[in] indx_to_node_linkage serial map of index to node indices. + * \return a map of node index to vector of indexes adjacent to the node. + */ +std::map, unsigned> Draco_Mesh::compute_node_vec_indx_map( + const std::vector &indx_type, + const std::vector &indx_to_node_linkage) const { + + // map to return + std::map, unsigned> nodes_to_indx_map; + + // generate map + const size_t num_indxs = indx_type.size(); + std::vector::const_iterator i2n_first = + indx_to_node_linkage.begin(); + for (unsigned indx = 0; indx < num_indxs; ++indx) { + + // extract the node vector + const std::vector node_vec(i2n_first, + i2n_first + indx_type[indx]); + + // set the node vector as the key and index as the value + nodes_to_indx_map[node_vec] = indx; + + // increment iterator + i2n_first += indx_type[indx]; + } + + Ensure(i2n_first == indx_to_node_linkage.end()); + + return nodes_to_indx_map; +} + } // end namespace rtt_mesh -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// // end of mesh/Draco_Mesh.cc -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// diff --git a/src/mesh/Draco_Mesh.hh b/src/mesh/Draco_Mesh.hh index ec6032c472..3f0a3b7111 100644 --- a/src/mesh/Draco_Mesh.hh +++ b/src/mesh/Draco_Mesh.hh @@ -48,7 +48,6 @@ class Draco_Mesh { public: // >>> TYPEDEFS typedef rtt_mesh_element::Geometry Geometry; - // \todo: update this to a full layout class? typedef std::map>>> Layout; @@ -101,7 +100,6 @@ private: public: //! Constructor. - DLL_PUBLIC_mesh Draco_Mesh(unsigned dimension_, Geometry geometry_, const std::vector &cell_type_, const std::vector &cell_to_node_linkage_, @@ -113,7 +111,8 @@ public: const std::vector &ghost_cell_type_ = {}, const std::vector &ghost_cell_to_node_linkage_ = {}, const std::vector &ghost_cell_number_ = {}, - const std::vector &ghost_cell_rank_ = {}); + const std::vector &ghost_cell_rank_ = {}, + const std::vector &face_type_ = {}); // >>> ACCESSORS @@ -156,7 +155,6 @@ private: std::vector> compute_node_coord_vec(const std::vector &coordinates) const; - // \todo: add layout class and complete temporary version of this function. //! Calculate the cell-to-cell linkage (layout) void compute_cell_to_cell_linkage( const std::vector &cell_type, @@ -166,10 +164,25 @@ private: const std::vector &ghost_cell_type, const std::vector &ghost_cell_to_node_linkage); + //! Calculate the cell-to-cell linkage with face type vector (overload) + void compute_cell_to_cell_linkage( + const std::vector &cell_type, + const std::vector &cell_to_node_linkage, + const std::vector &face_type, + const std::vector &side_node_count, + const std::vector &side_to_node_linkage, + const std::vector &ghost_cell_type, + const std::vector &ghost_cell_to_node_linkage); + //! Calculate a map of node to vectors of indices (cells, sides, ghost cells) std::map> compute_node_indx_map( const std::vector &indx_type, const std::vector &indx_to_node_linkage) const; + + //! Calculate a map of node vectors to indices (sides, ghost cells) + std::map, unsigned> compute_node_vec_indx_map( + const std::vector &indx_type, + const std::vector &indx_to_node_linkage) const; }; } // end namespace rtt_mesh diff --git a/src/mesh/test/Test_Mesh_Interface.hh b/src/mesh/test/Test_Mesh_Interface.hh index 0de328e392..90ef19fb86 100644 --- a/src/mesh/test/Test_Mesh_Interface.hh +++ b/src/mesh/test/Test_Mesh_Interface.hh @@ -39,6 +39,7 @@ public: const size_t num_nodes; const size_t num_sides; const unsigned num_nodes_per_cell; + const unsigned num_faces_per_cell; std::vector cell_type; std::vector cell_to_node_linkage; std::vector side_set_flag; @@ -46,13 +47,15 @@ public: std::vector side_to_node_linkage; std::vector coordinates; std::vector global_node_number; + std::vector face_type; public: //! Constructor. Test_Mesh_Interface(const size_t num_xdir_, const size_t num_ydir_, const std::vector &global_node_number_ = {}, const double xdir_offset_ = 0.0, - const double ydir_offset_ = 0.0); + const double ydir_offset_ = 0.0, + const bool use_face_types = false); // >>> SERVICES @@ -70,11 +73,11 @@ public: Test_Mesh_Interface::Test_Mesh_Interface( const size_t num_xdir_, const size_t num_ydir_, const std::vector &global_node_number_, const double xdir_offset_, - const double ydir_offset_) + const double ydir_offset_, const bool use_face_types) : dim(2), num_cells(num_xdir_ * num_ydir_), num_nodes((num_xdir_ + 1) * (num_ydir_ + 1)), num_sides(2 * (num_xdir_ + num_ydir_)), num_nodes_per_cell(4), - global_node_number(global_node_number_) { + num_faces_per_cell(4), global_node_number(global_node_number_) { // set the number of cells and nodes const size_t num_xdir = num_xdir_; @@ -84,10 +87,23 @@ Test_Mesh_Interface::Test_Mesh_Interface( const size_t poff = num_xdir + num_ydir; // parallel side offset // use two dimensions and Cartesian geometry - cell_type.resize(num_cells, num_nodes_per_cell); + if (use_face_types) { + cell_type.resize(num_cells, num_faces_per_cell); + } else { + cell_type.resize(num_cells, num_nodes_per_cell); + } + + // size cell-node linkage based on whether or not face types are being used + if (use_face_types) { + + face_type.resize(num_cells * 4, 2); + cell_to_node_linkage.resize(num_cells * 2 * num_faces_per_cell); + + } else { + cell_to_node_linkage.resize(num_cells * num_nodes_per_cell); + } // set the cell-to-node linkage counterclockwise about each cell - cell_to_node_linkage.resize(num_cells * num_nodes_per_cell); for (size_t j = 0; j < num_ydir; ++j) { for (size_t i = 0; i < num_xdir; ++i) { @@ -96,12 +112,40 @@ Test_Mesh_Interface::Test_Mesh_Interface( // set each node entry per cell Check(cell + num_xdir + 1 + j + 1 < UINT_MAX); - cell_to_node_linkage[4 * cell] = static_cast(cell + j); - cell_to_node_linkage[4 * cell + 1] = static_cast(cell + j + 1); - cell_to_node_linkage[4 * cell + 2] = - static_cast(cell + num_xdir + 1 + j + 1); - cell_to_node_linkage[4 * cell + 3] = - static_cast(cell + num_xdir + 1 + j); + if (use_face_types) { + + // 1st face + cell_to_node_linkage[8 * cell] = static_cast(cell + j); + cell_to_node_linkage[8 * cell + 1] = + static_cast(cell + j + 1); + + // 2nd face + cell_to_node_linkage[8 * cell + 2] = + static_cast(cell + j + 1); + cell_to_node_linkage[8 * cell + 3] = + static_cast(cell + num_xdir + 1 + j + 1); + + // 3rd face + cell_to_node_linkage[8 * cell + 4] = + static_cast(cell + num_xdir + 1 + j + 1); + cell_to_node_linkage[8 * cell + 5] = + static_cast(cell + num_xdir + 1 + j); + + // 4th face + cell_to_node_linkage[8 * cell + 6] = + static_cast(cell + num_xdir + 1 + j); + cell_to_node_linkage[8 * cell + 7] = static_cast(cell + j); + + } else { + + cell_to_node_linkage[4 * cell] = static_cast(cell + j); + cell_to_node_linkage[4 * cell + 1] = + static_cast(cell + j + 1); + cell_to_node_linkage[4 * cell + 2] = + static_cast(cell + num_xdir + 1 + j + 1); + cell_to_node_linkage[4 * cell + 3] = + static_cast(cell + num_xdir + 1 + j); + } } } diff --git a/src/mesh/test/tstDraco_Mesh.cc b/src/mesh/test/tstDraco_Mesh.cc index 5ee8bb5c15..cc36edbb77 100644 --- a/src/mesh/test/tstDraco_Mesh.cc +++ b/src/mesh/test/tstDraco_Mesh.cc @@ -1,4 +1,4 @@ -//----------------------------------*-C++-*----------------------------------// +//-----------------------------------*-C++-*----------------------------------// /*! * \file mesh/test/tstDraco_Mesh.cc * \author Ryan Wollaeger @@ -6,7 +6,7 @@ * \brief Draco_Mesh class unit test. * \note Copyright (C) 2018-2019 Triad National Security, LLC. * All rights reserved. */ -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// #include "Test_Mesh_Interface.hh" #include "c4/ParallelUnitTest.hh" @@ -14,15 +14,81 @@ using rtt_mesh::Draco_Mesh; -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// // TESTS -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// + +// 1D Spherical mesh construction test +void spherical_mesh_1d(rtt_c4::ParallelUnitTest &ut) { + + // use Spherical geometry and 1D + const unsigned dimension = 1; + const Draco_Mesh::Geometry geometry = Draco_Mesh::Geometry::SPHERICAL; + + //>>> SET UP CELL AND NODE DATA + + // mesh: | | | | + // 0.0 1.0 2.0 3.0 + + const size_t num_cells = 3; + const std::vector cell_type = {2, 2, 2}; + const std::vector cell_to_node_linkage = {0, 1, 1, 2, 2, 3}; + const std::vector side_set_flag = {0, 0}; + const std::vector side_node_count = {1, 1}; + const std::vector side_to_node_linkage = {0, 4}; + const std::vector coordinates = {0.0, 1.0, 2.0, 3.0}; + const std::vector global_node_number = {0, 1, 2, 3}; + const std::vector face_type = {1, 1, 1, 1, 1, 1}; + + // instantiate a mesh with face type input + std::shared_ptr mesh(new Draco_Mesh( + dimension, geometry, cell_type, cell_to_node_linkage, side_set_flag, + side_node_count, side_to_node_linkage, coordinates, global_node_number, + {}, {}, {}, {}, face_type)); + + //>>> TEST THE MESH LAYOUTS + + // get the layout generated by the mesh + const Draco_Mesh::Layout &layout = mesh->get_cc_linkage(); + FAIL_IF_NOT(layout.size() == num_cells); + + // check inner boundary cell + FAIL_IF_NOT(layout.at(0).size() == 1); + FAIL_IF_NOT(layout.at(0)[0].first == 1); + FAIL_IF_NOT(layout.at(0)[0].second.size() == 1); + FAIL_IF_NOT(layout.at(0)[0].second[0] == 1); + + // check outer boundary cell + FAIL_IF_NOT(layout.at(num_cells - 1).size() == 1); + FAIL_IF_NOT(layout.at(num_cells - 1)[0].first == 1); + FAIL_IF_NOT(layout.at(num_cells - 1)[0].second.size() == 1); + FAIL_IF_NOT(layout.at(num_cells - 1)[0].second[0] == 2); + + // check internal connectivity + for (size_t cell = 1; cell < num_cells - 1; ++cell) { + + // check neighbor cells + FAIL_IF_NOT(layout.at(cell).size() == 2); + FAIL_IF_NOT(layout.at(cell)[0].first == cell - 1); + FAIL_IF_NOT(layout.at(cell)[1].first == cell + 1); + + // check connecting nodes + FAIL_IF_NOT(layout.at(cell)[0].second.size() == 1); + FAIL_IF_NOT(layout.at(cell)[0].second[0] == cell_to_node_linkage[2 * cell]); + FAIL_IF_NOT(layout.at(cell)[1].second.size() == 1); + FAIL_IF_NOT(layout.at(cell)[1].second[0] == + cell_to_node_linkage[2 * cell + 1]); + } + + // successful test output + if (ut.numFails == 0) + PASSMSG("1D Draco_Mesh tests ok."); + return; +} // 2D Cartesian mesh construction test void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { - // TODO: parse mesh data instead of hard-coding - // use Cartesian geometry const Draco_Mesh::Geometry geometry = Draco_Mesh::Geometry::CARTESIAN; @@ -35,6 +101,10 @@ void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { // generate a constainer for data needed in mesh construction rtt_mesh_test::Test_Mesh_Interface mesh_iface(num_xdir, num_ydir); + // generate an interface for the alternate form of the mesh ctor + rtt_mesh_test::Test_Mesh_Interface mesh_iface_alt(num_xdir, num_ydir, {}, 0.0, + 0.0, true); + // short-cut to some arrays const std::vector &cell_type = mesh_iface.cell_type; const std::vector &cell_to_node_linkage = @@ -49,6 +119,14 @@ void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { mesh_iface.side_set_flag, side_node_count, side_to_node_linkage, mesh_iface.coordinates, mesh_iface.global_node_number)); + // instantiate a mesh with face type input + std::shared_ptr mesh_alt(new Draco_Mesh( + mesh_iface_alt.dim, geometry, mesh_iface_alt.cell_type, + mesh_iface_alt.cell_to_node_linkage, mesh_iface_alt.side_set_flag, + mesh_iface_alt.side_node_count, mesh_iface_alt.side_to_node_linkage, + mesh_iface_alt.coordinates, mesh_iface_alt.global_node_number, {}, {}, {}, + {}, mesh_iface_alt.face_type)); + // check that the scalar data is correct FAIL_IF_NOT(mesh->get_dimension() == 2); FAIL_IF_NOT(mesh->get_geometry() == Draco_Mesh::Geometry::CARTESIAN); @@ -59,6 +137,11 @@ void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { FAIL_IF_NOT(mesh->get_cell_type() == cell_type); FAIL_IF_NOT(mesh->get_cell_to_node_linkage() == cell_to_node_linkage); + // check that alterate cell type and cell-node linkage data is correct + FAIL_IF_NOT(mesh_alt->get_cell_type() == mesh_iface_alt.cell_type); + FAIL_IF_NOT(mesh_alt->get_cell_to_node_linkage() == + mesh_iface_alt.cell_to_node_linkage); + // check that flat side type and side to node linkage is correct FAIL_IF_NOT(mesh->get_side_node_count() == side_node_count); FAIL_IF_NOT(mesh->get_side_to_node_linkage() == side_to_node_linkage); @@ -67,8 +150,12 @@ void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { // get the layout generated by the mesh const Draco_Mesh::Layout &layout = mesh->get_cc_linkage(); + // get the alternate layout + const Draco_Mesh::Layout &layout_alt = mesh_alt->get_cc_linkage(); + // check that the layout has been generated FAIL_IF_NOT(layout.size() == mesh_iface.num_cells); + FAIL_IF_NOT(layout_alt == layout); // check that each cell has the correct neighbors { @@ -86,9 +173,6 @@ void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { test_cell_map[cell].push_back(cell + 1); if (j > 0) test_cell_map[cell].push_back(cell - num_xdir); - // always false: num_ydir==1, thus j==0 ==> if( 0<0 )... - //if (j < num_ydir - 1) - // test_cell_map[cell].push_back(cell + num_xdir); } } @@ -103,20 +187,36 @@ void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { // check that cell neighbors are correct for (unsigned face = 0; face < num_faces; ++face) FAIL_IF_NOT(layout.at(cell)[face].first == test_cell_map[cell][face]); + + // check alternate mesh + const size_t num_faces_alt = layout_alt.at(cell).size(); + FAIL_IF_NOT(num_faces_alt == num_faces); + + // check that cell-cell layout of alternate mesh is correct + for (unsigned face = 0; face < num_faces; ++face) { + FAIL_IF_NOT(layout_alt.at(cell)[face].first == + test_cell_map[cell][face]); + FAIL_IF_NOT(layout_alt.at(cell)[face].second == + layout.at(cell)[face].second); + } } } // get the boundary layout generated by the mesh const Draco_Mesh::Layout &bd_layout = mesh->get_cs_linkage(); + const Draco_Mesh::Layout &bd_layout_alt = mesh_alt->get_cs_linkage(); // check that the boundary (or side) layout has been generated FAIL_IF_NOT(bd_layout.size() == mesh_iface.num_cells); + FAIL_IF_NOT(bd_layout_alt == bd_layout); // get the ghost-cell layout generated by the mesh const Draco_Mesh::Layout &go_layout = mesh->get_cg_linkage(); + const Draco_Mesh::Layout &go_layout_alt = mesh_alt->get_cg_linkage(); // check that there are no ghost cells for this mesh FAIL_IF_NOT(go_layout.size() == 0); + FAIL_IF_NOT(go_layout_alt.size() == 0); // check that cell-to-node linkage data is correct { @@ -139,6 +239,11 @@ void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { cn_first += cell_type[cell]; test_cn_first += cell_type[cell]; } + + // check that flattend linkage from alternate mesh matches original + std::vector test_cn_linkage_alt = + mesh_iface.flatten_cn_linkage(layout_alt, bd_layout_alt, go_layout_alt); + FAIL_IF_NOT(test_cn_linkage_alt == test_cn_linkage); } // check that each cell has the correct sides @@ -190,17 +295,18 @@ void cartesian_mesh_2d(rtt_c4::ParallelUnitTest &ut) { return; } -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// int main(int argc, char *argv[]) { rtt_c4::ParallelUnitTest ut(argc, argv, rtt_dsxx::release); try { Insist(rtt_c4::nodes() == 1, "This test only uses 1 PE."); + spherical_mesh_1d(ut); cartesian_mesh_2d(ut); } UT_EPILOG(ut); } -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// // end of mesh/test/tstDraco_Mesh.cc -//---------------------------------------------------------------------------// +//----------------------------------------------------------------------------// From 2bf0e201fec60825efb3473774e17e40685d89f7 Mon Sep 17 00:00:00 2001 From: Ryan Wollaeger Date: Fri, 7 Jun 2019 17:54:26 -0600 Subject: [PATCH 2/7] Add 1-3D default boundary connectivity generation. + Add default boundary data generation when face types are given. + Add test of default boundary generation to new 1D unit test. --- src/mesh/Draco_Mesh.cc | 21 ++++++++++++++++++++- src/mesh/test/tstDraco_Mesh.cc | 29 +++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/mesh/Draco_Mesh.cc b/src/mesh/Draco_Mesh.cc index c02978c6cd..2050ed3a5d 100644 --- a/src/mesh/Draco_Mesh.cc +++ b/src/mesh/Draco_Mesh.cc @@ -11,7 +11,7 @@ #include "Draco_Mesh.hh" #include "ds++/Assert.hh" #include -#include +// #include #include #include @@ -476,6 +476,25 @@ void Draco_Mesh::compute_cell_to_cell_linkage( has_face_cond = true; } + // make face a boundary if no face conditions have been found + if (!has_face_cond) { + + // augment side flags with vacuum b.c. + side_set_flag.push_back(0); + + // augment side-node count + m_side_node_count.push_back(face_type[cf_counter]); + Check(m_side_node_count.size() == side_set_flag.size()); + + // augment side-node linkage + m_side_to_node_linkage.insert(m_side_to_node_linkage.begin(), + node_vec.begin(), node_vec.end()); + + // augment cell-side linkage + cell_to_side_linkage[cell].push_back(std::make_pair( + static_cast(m_side_node_count.size() - 1), node_vec)); + } + // increment iterator and counter cn_first += face_type[cf_counter]; cf_counter++; diff --git a/src/mesh/test/tstDraco_Mesh.cc b/src/mesh/test/tstDraco_Mesh.cc index cc36edbb77..5ef6ac34d3 100644 --- a/src/mesh/test/tstDraco_Mesh.cc +++ b/src/mesh/test/tstDraco_Mesh.cc @@ -35,7 +35,7 @@ void spherical_mesh_1d(rtt_c4::ParallelUnitTest &ut) { const std::vector cell_to_node_linkage = {0, 1, 1, 2, 2, 3}; const std::vector side_set_flag = {0, 0}; const std::vector side_node_count = {1, 1}; - const std::vector side_to_node_linkage = {0, 4}; + const std::vector side_to_node_linkage = {0, 3}; const std::vector coordinates = {0.0, 1.0, 2.0, 3.0}; const std::vector global_node_number = {0, 1, 2, 3}; const std::vector face_type = {1, 1, 1, 1, 1, 1}; @@ -46,9 +46,30 @@ void spherical_mesh_1d(rtt_c4::ParallelUnitTest &ut) { side_node_count, side_to_node_linkage, coordinates, global_node_number, {}, {}, {}, {}, face_type)); + // instantiate a mesh without boundary faces supplied + std::shared_ptr mesh_nobdy(new Draco_Mesh( + dimension, geometry, cell_type, cell_to_node_linkage, {}, {}, {}, + coordinates, global_node_number, {}, {}, {}, {}, face_type)); + //>>> TEST THE MESH LAYOUTS - // get the layout generated by the mesh + // check that no ghost data has been generated + FAIL_IF_NOT(mesh->get_cg_linkage().size() == 0); + FAIL_IF_NOT(mesh_nobdy->get_cg_linkage().size() == 0); + + // get the cell-side layout generated by the mesh + const Draco_Mesh::Layout &bd_layout = mesh->get_cs_linkage(); + FAIL_IF_NOT(bd_layout.size() == 2); + FAIL_IF_NOT(bd_layout.at(0).size() == 1); + FAIL_IF_NOT(bd_layout.at(0)[0].first == 0); + FAIL_IF_NOT(bd_layout.at(num_cells - 1).size() == 1); + FAIL_IF_NOT(bd_layout.at(num_cells - 1)[0].first == 1); + + // check that the default boundary data was correctly generated + const Draco_Mesh::Layout &bd_layout_nobdy = mesh_nobdy->get_cs_linkage(); + FAIL_IF_NOT(bd_layout_nobdy == bd_layout); + + // get the cell-cell layout generated by the mesh const Draco_Mesh::Layout &layout = mesh->get_cc_linkage(); FAIL_IF_NOT(layout.size() == num_cells); @@ -80,6 +101,10 @@ void spherical_mesh_1d(rtt_c4::ParallelUnitTest &ut) { cell_to_node_linkage[2 * cell + 1]); } + // get the layout generated by the mesh + const Draco_Mesh::Layout &layout_nobdy = mesh->get_cc_linkage(); + FAIL_IF_NOT(layout_nobdy == layout); + // successful test output if (ut.numFails == 0) PASSMSG("1D Draco_Mesh tests ok."); From a4704900159d97e3d65fec8a7e14f6e05ef0c702 Mon Sep 17 00:00:00 2001 From: Ryan Wollaeger Date: Fri, 7 Jun 2019 19:47:35 -0600 Subject: [PATCH 3/7] Make layout robust against side and ghost to node linkage ordering. --- src/mesh/Draco_Mesh.cc | 26 +++++++++++++------------- src/mesh/Draco_Mesh.hh | 3 ++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/mesh/Draco_Mesh.cc b/src/mesh/Draco_Mesh.cc index 2050ed3a5d..25ff9e4192 100644 --- a/src/mesh/Draco_Mesh.cc +++ b/src/mesh/Draco_Mesh.cc @@ -13,7 +13,6 @@ #include // #include #include -#include namespace rtt_mesh { @@ -411,10 +410,10 @@ void Draco_Mesh::compute_cell_to_cell_linkage( // (3) create maps of nodes to boundary faces (sides) and parallel faces - std::map, unsigned> nodes_to_side = + std::map, unsigned> nodes_to_side = compute_node_vec_indx_map(side_node_count, side_to_node_linkage); - std::map, unsigned> nodes_to_ghost = + std::map, unsigned> nodes_to_ghost = compute_node_vec_indx_map(ghost_cell_type, ghost_cell_to_node_linkage); // (4) create cell-to-cell, cell-to-side, cell-to-ghost-cell linkage @@ -429,9 +428,11 @@ void Draco_Mesh::compute_cell_to_cell_linkage( // initialize this face to not having a condition bool has_face_cond = false; + // get the node set for this cell and face + const std::set &node_set = cface_to_nodes[cf_counter]; + // get the cells associated with this cell face from the nodes - const std::vector &cells = - nodes_to_cells[cface_to_nodes[cf_counter]]; + const std::vector &cells = nodes_to_cells[node_set]; Check(cells.size() >= 1); Check(cells.size() <= 2); @@ -457,21 +458,21 @@ void Draco_Mesh::compute_cell_to_cell_linkage( } // check if a boundary/side exists for this node set - if (nodes_to_side.find(node_vec) != nodes_to_side.end()) { + if (nodes_to_side.find(node_set) != nodes_to_side.end()) { // populate cell-boundary face layout cell_to_side_linkage[cell].push_back( - std::make_pair(nodes_to_side[node_vec], node_vec)); + std::make_pair(nodes_to_side[node_set], node_vec)); has_face_cond = true; } // check if a parallel face exists for this node set - if (nodes_to_ghost.find(node_vec) != nodes_to_ghost.end()) { + if (nodes_to_ghost.find(node_set) != nodes_to_ghost.end()) { // populate cell-parallel face layout cell_to_ghost_cell_linkage[cell].push_back( - std::make_pair(nodes_to_ghost[node_vec], node_vec)); + std::make_pair(nodes_to_ghost[node_set], node_vec)); has_face_cond = true; } @@ -552,12 +553,12 @@ std::map> Draco_Mesh::compute_node_indx_map( * \param[in] indx_to_node_linkage serial map of index to node indices. * \return a map of node index to vector of indexes adjacent to the node. */ -std::map, unsigned> Draco_Mesh::compute_node_vec_indx_map( +std::map, unsigned> Draco_Mesh::compute_node_vec_indx_map( const std::vector &indx_type, const std::vector &indx_to_node_linkage) const { // map to return - std::map, unsigned> nodes_to_indx_map; + std::map, unsigned> nodes_to_indx_map; // generate map const size_t num_indxs = indx_type.size(); @@ -566,8 +567,7 @@ std::map, unsigned> Draco_Mesh::compute_node_vec_indx_map( for (unsigned indx = 0; indx < num_indxs; ++indx) { // extract the node vector - const std::vector node_vec(i2n_first, - i2n_first + indx_type[indx]); + const std::set node_vec(i2n_first, i2n_first + indx_type[indx]); // set the node vector as the key and index as the value nodes_to_indx_map[node_vec] = indx; diff --git a/src/mesh/Draco_Mesh.hh b/src/mesh/Draco_Mesh.hh index 3f0a3b7111..2c135eda98 100644 --- a/src/mesh/Draco_Mesh.hh +++ b/src/mesh/Draco_Mesh.hh @@ -15,6 +15,7 @@ #include "mesh_element/Geometry.hh" #include #include +#include namespace rtt_mesh { @@ -180,7 +181,7 @@ private: const std::vector &indx_to_node_linkage) const; //! Calculate a map of node vectors to indices (sides, ghost cells) - std::map, unsigned> compute_node_vec_indx_map( + std::map, unsigned> compute_node_vec_indx_map( const std::vector &indx_type, const std::vector &indx_to_node_linkage) const; }; From 0d35f0b19528852fc7ced6465f0c33bdf97cbba7 Mon Sep 17 00:00:00 2001 From: Ryan Wollaeger Date: Fri, 7 Jun 2019 19:49:47 -0600 Subject: [PATCH 4/7] Add missing file from previous commit. --- src/mesh/Draco_Mesh.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Draco_Mesh.hh b/src/mesh/Draco_Mesh.hh index 2c135eda98..f725bed19f 100644 --- a/src/mesh/Draco_Mesh.hh +++ b/src/mesh/Draco_Mesh.hh @@ -14,8 +14,8 @@ #include "ds++/config.h" #include "mesh_element/Geometry.hh" #include -#include #include +#include namespace rtt_mesh { From 9cc3d7461db1566aeea94e7e9ba0c44b1650dc5e Mon Sep 17 00:00:00 2001 From: Ryan Wollaeger Date: Fri, 7 Jun 2019 20:31:03 -0600 Subject: [PATCH 5/7] Generalize X3D mesh parser to provide 1-3D data to mesh builder. + Instantiate reader with optional use_face_type parameter. + Set cell type and as faces per cell when use_face_type is true. + Preserve cell->face->node in linkage when use_face_type is true. + Set face_type vector in mesh builder when use_face_type is true. + Enforce use_face_type in mesh reader virtual base class. + Add corresponding function stubs to RTT (not implemented). + Update unit test to test alternate mesh reader/builder. --- src/mesh/Draco_Mesh.cc | 3 - src/mesh/Draco_Mesh_Builder.t.hh | 40 +++++++---- src/mesh/Draco_Mesh_Reader.hh | 1 + src/mesh/RTT_Draco_Mesh_Reader.hh | 6 ++ src/mesh/X3D_Draco_Mesh_Reader.cc | 81 +++++++++++++++++++---- src/mesh/X3D_Draco_Mesh_Reader.hh | 10 ++- src/mesh/test/tstX3D_Draco_Mesh_Reader.cc | 24 +++++-- 7 files changed, 130 insertions(+), 35 deletions(-) diff --git a/src/mesh/Draco_Mesh.cc b/src/mesh/Draco_Mesh.cc index 25ff9e4192..288815440d 100644 --- a/src/mesh/Draco_Mesh.cc +++ b/src/mesh/Draco_Mesh.cc @@ -334,9 +334,6 @@ void Draco_Mesh::compute_cell_to_cell_linkage( Check(node_offset == cell_to_node_linkage.size()); - // STEP 5: instantiate the full layout - // \todo: finish Draco_Layout class - Ensure(cell_to_cell_linkage.size() <= num_cells); Ensure(cell_to_side_linkage.size() <= num_cells); } diff --git a/src/mesh/Draco_Mesh_Builder.t.hh b/src/mesh/Draco_Mesh_Builder.t.hh index 89c2984041..537717e9d2 100644 --- a/src/mesh/Draco_Mesh_Builder.t.hh +++ b/src/mesh/Draco_Mesh_Builder.t.hh @@ -13,6 +13,7 @@ #include "ds++/Assert.hh" #include #include +#include namespace rtt_mesh { @@ -28,8 +29,6 @@ template Draco_Mesh_Builder::Draco_Mesh_Builder(std::shared_ptr reader_) : reader(reader_) { Require(reader_ != nullptr); - // \todo remove constraint of 2 dimensions - Insist(reader->get_numdim() == 2, "Mesh must be 2D."); } //---------------------------------------------------------------------------// @@ -46,19 +45,14 @@ template std::shared_ptr Draco_Mesh_Builder::build_mesh(rtt_mesh_element::Geometry geometry) { - // \todo: Should geometry be to RTT format parsing? - // \todo: Generate ghost node and cell data for domain-decomposed meshes. - Require(geometry != rtt_mesh_element::END_GEOMETRY); - // \todo: Eventually allow spherical geometry - Require(geometry != rtt_mesh_element::SPHERICAL); // >>> GENERATE MESH CONSTRUCTOR ARGUMENTS // get the number of dimensions unsigned dimension = reader->get_numdim(); - // \todo: Eventually allow dim = 1, 3 - Check(dimension == 2); + Check(dimension >= 1); + Check(dimension <= 3); // get the number of cells size_t num_cells = reader->get_numcells(); @@ -131,10 +125,6 @@ Draco_Mesh_Builder::build_mesh(rtt_mesh_element::Geometry geometry) { Check(num_nodes >= num_cells); Check(num_nodes <= cn_linkage_size); - // \todo: add global node numbers to RTT mesh reader? - // \todo: or, remove global_node_number from mesh constructor? - // assume domain is not decomposed, for now - // generate the global node number serialized vector of coordinates std::vector global_node_number(num_nodes); std::vector coordinates(dimension * num_nodes); @@ -152,6 +142,27 @@ Draco_Mesh_Builder::build_mesh(rtt_mesh_element::Geometry geometry) { coordinates[dimension * node + d] = node_coord[d]; } + std::vector face_type; + if (reader->get_use_face_types()) { + + // reserve some space for face_type + face_type.reserve(std::accumulate(cell_type.begin(), cell_type.end(), 0u)); + + // generate face_type vector + unsigned cf_counter = 0; + for (size_t cell = 0; cell < num_cells; ++cell) { + for (size_t face = 0; face < cell_type[cell]; ++face) { + + // stor number of nodes for this face + face_type.push_back(static_cast( + reader->get_cellfacenodes(cell, face).size())); + + // increment counter + cf_counter++; + } + } + } + Remember(auto cn_minmax = std::minmax_element(cell_to_node_linkage.begin(), cell_to_node_linkage.end())); Remember(auto sn_minmax = std::minmax_element(side_to_node_linkage.begin(), @@ -166,7 +177,8 @@ Draco_Mesh_Builder::build_mesh(rtt_mesh_element::Geometry geometry) { std::shared_ptr mesh(new Draco_Mesh( dimension, geometry, cell_type, cell_to_node_linkage, side_set_flag, - side_node_count, side_to_node_linkage, coordinates, global_node_number)); + side_node_count, side_to_node_linkage, coordinates, global_node_number, + {}, {}, {}, {}, face_type)); return mesh; } diff --git a/src/mesh/Draco_Mesh_Reader.hh b/src/mesh/Draco_Mesh_Reader.hh index 91be639016..e72e1d16ad 100644 --- a/src/mesh/Draco_Mesh_Reader.hh +++ b/src/mesh/Draco_Mesh_Reader.hh @@ -33,6 +33,7 @@ public: // >>> ACCESSORS + virtual bool get_use_face_types() const = 0; virtual unsigned get_numdim() const = 0; virtual size_t get_numcells() const = 0; virtual size_t get_numnodes() const = 0; diff --git a/src/mesh/RTT_Draco_Mesh_Reader.hh b/src/mesh/RTT_Draco_Mesh_Reader.hh index 0a36cb21ca..fb76384015 100644 --- a/src/mesh/RTT_Draco_Mesh_Reader.hh +++ b/src/mesh/RTT_Draco_Mesh_Reader.hh @@ -42,6 +42,7 @@ public: // >>> ACCESSORS + bool get_use_face_types() const { return false; } unsigned get_numdim() const { return rtt_reader->get_dims_ndim(); } size_t get_numcells() const { return rtt_reader->get_dims_ncells(); } size_t get_numnodes() const { return rtt_reader->get_dims_nnodes(); } @@ -51,6 +52,11 @@ public: std::vector get_cellnodes(size_t cell) const { return rtt_reader->get_cells_nodes(cell); } + std::vector get_cellfacenodes(size_t /*cell*/, + size_t /*face*/) const { + Insist(false, "cell-face nodes not implemented with RTT reader."); + return std::vector(); + } size_t get_numsides() const { return rtt_reader->get_dims_nsides(); } unsigned get_sideflag(size_t side) const { return rtt_reader->get_sides_flags(side, 0); diff --git a/src/mesh/X3D_Draco_Mesh_Reader.cc b/src/mesh/X3D_Draco_Mesh_Reader.cc index 59195a8069..66728dafa0 100644 --- a/src/mesh/X3D_Draco_Mesh_Reader.cc +++ b/src/mesh/X3D_Draco_Mesh_Reader.cc @@ -24,15 +24,15 @@ namespace rtt_mesh { * * \param[in] filename_ name of file to be parsed * \param[in] bdy_filenames_ names of files with lists of side node indexes - * \param[in] bdy_flags_ unsigned int indicating B.C. per side file + * \param[in] bdy_flags_ unsigned int indicating B.C. per side file * (bdy_filenames_) */ X3D_Draco_Mesh_Reader::X3D_Draco_Mesh_Reader( const std::string &filename_, const std::vector &bdy_filenames_, - const std::vector &bdy_flags_) - : filename(filename_), bdy_filenames(bdy_filenames_), - bdy_flags(bdy_flags_) { + const std::vector &bdy_flags_, const bool use_face_types_) + : filename(filename_), bdy_filenames(bdy_filenames_), bdy_flags(bdy_flags_), + use_face_types(use_face_types_) { // check for valid file name Insist(filename_.size() > 0, "No file name supplied."); Insist(bdy_flags_.size() <= bdy_filenames_.size(), @@ -152,15 +152,30 @@ void X3D_Draco_Mesh_Reader::read_mesh() { */ unsigned X3D_Draco_Mesh_Reader::get_celltype(size_t cell) const { - // get the list of cell nodes - const std::vector node_indexes = get_cellnodes(cell); + if (!use_face_types) { - // merely the size of the vector of unique nodes - size_t num_nodes_pc = node_indexes.size(); + // get the list of cell nodes + const std::vector node_indexes = get_cellnodes(cell); - Ensure(num_nodes_pc > 0); - Ensure(num_nodes_pc < UINT_MAX); - return static_cast(num_nodes_pc); + // merely the size of the vector of unique nodes + size_t num_nodes_pc = node_indexes.size(); + + Ensure(num_nodes_pc > 0); + Ensure(num_nodes_pc < UINT_MAX); + return static_cast(num_nodes_pc); + + } else { + + // x3d file's node, face, and cell indexes start from 1 + Check(cell + 1 < INT_MAX); + const std::vector &cell_data = + x3d_cellface_map.at(static_cast(cell + 1)); + const size_t num_faces = cell_data[0]; + + Ensure(num_faces > 0); + Ensure(num_faces < UINT_MAX); + return static_cast(num_faces); + } } //---------------------------------------------------------------------------// @@ -195,8 +210,13 @@ std::vector X3D_Draco_Mesh_Reader::get_cellnodes(size_t cell) const { std::vector tmp_vec = get_facenodes(face); // insert into the cell vector - for (auto j : tmp_vec) { - if (node_index_set.insert(j).second) + if (!use_face_types) { + for (auto j : tmp_vec) { + if (node_index_set.insert(j).second) + node_indexes.push_back(j); + } + } else { + for (auto j : tmp_vec) node_indexes.push_back(j); } } @@ -209,6 +229,41 @@ std::vector X3D_Draco_Mesh_Reader::get_cellnodes(size_t cell) const { return node_indexes; } +//---------------------------------------------------------------------------// +/*! + * \brief Return the vector of node indices for a given cell. + * + * \param[in] cell index of cell + * \param[in] face face index local to cell + * + * \return vector of int node indices + */ +std::vector +X3D_Draco_Mesh_Reader::get_cellfacenodes(size_t cell, size_t face) const { + + Require(cell < static_cast(x3d_header_map.at("elements")[0])); + + // x3d file's node, face, and cell indexes start from 1 + Check(cell + 1 < INT_MAX); + const std::vector &cell_data = + x3d_cellface_map.at(static_cast(cell + 1)); + const size_t num_faces = cell_data[0]; + Check(face < num_faces); + + // get the face index, which will by key for face-to-node map + int map_face = cell_data[face + 1]; + + // get a vector of nodes for this face + std::vector node_indexes = get_facenodes(map_face); + + // subtract 1 to get base 0 nodes + for (size_t i = 0; i < node_indexes.size(); ++i) + node_indexes[i]--; + + Ensure(node_indexes.size() > 0); + return node_indexes; +} + //---------------------------------------------------------------------------// // PRIVATE FUNCTIONS //---------------------------------------------------------------------------// diff --git a/src/mesh/X3D_Draco_Mesh_Reader.hh b/src/mesh/X3D_Draco_Mesh_Reader.hh index 77f3773fbb..e116da406f 100644 --- a/src/mesh/X3D_Draco_Mesh_Reader.hh +++ b/src/mesh/X3D_Draco_Mesh_Reader.hh @@ -60,6 +60,9 @@ private: //! Boundary conditions per boundary file (optional data) const std::vector bdy_flags; + //! Switch for providing dimension-agnostic data to mesh builder + const bool use_face_types; + //! Vector of all parsed key-value data pairs (includes valueless delimiters) Parsed_Elements parsed_pairs; @@ -89,7 +92,8 @@ public: DLL_PUBLIC_mesh X3D_Draco_Mesh_Reader(const std::string &filename_, const std::vector &bdy_filenames_ = {}, - const std::vector &bdy_flags_ = {}); + const std::vector &bdy_flags_ = {}, + const bool use_face_types = false); // >>> SERVICES @@ -97,6 +101,9 @@ public: // >>> ACCESSORS + // reader type + bool get_use_face_types() const { return use_face_types; } + // header data unsigned get_process() const { Check(x3d_header_map.at("process")[0] - 1 < UINT_MAX); @@ -118,6 +125,7 @@ public: // accessors with deferred implementations unsigned get_celltype(size_t cell) const; std::vector get_cellnodes(size_t cell) const; + std::vector get_cellfacenodes(size_t cell, size_t face) const; // data needed from x3d boundary file size_t get_numsides() const { return x3d_sidenode_map.size(); } diff --git a/src/mesh/test/tstX3D_Draco_Mesh_Reader.cc b/src/mesh/test/tstX3D_Draco_Mesh_Reader.cc index 9a5ed623e4..6e5c87a353 100644 --- a/src/mesh/test/tstX3D_Draco_Mesh_Reader.cc +++ b/src/mesh/test/tstX3D_Draco_Mesh_Reader.cc @@ -39,8 +39,13 @@ void read_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { std::shared_ptr x3d_reader( new X3D_Draco_Mesh_Reader(filename, bdy_filenames, bdy_flags)); - // read mesh + // construct alternate reader using face types + std::shared_ptr x3d_reader_alt( + new X3D_Draco_Mesh_Reader(filename, bdy_filenames, bdy_flags, true)); + + // read meshes x3d_reader->read_mesh(); + x3d_reader_alt->read_mesh(); // >>> CHECK HEADER DATA @@ -52,10 +57,14 @@ void read_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { // >>> CHECK CELL-NODE DATA FAIL_IF_NOT(x3d_reader->get_celltype(0) == 4); + FAIL_IF_NOT(x3d_reader_alt->get_celltype(0) == 4); std::vector test_cellnodes = {0, 1, 3, 2}; FAIL_IF_NOT(x3d_reader->get_cellnodes(0) == test_cellnodes); + std::vector test_cellnodes_alt = {0, 1, 1, 3, 3, 2, 2, 0}; + FAIL_IF_NOT(x3d_reader_alt->get_cellnodes(0) == test_cellnodes_alt); + // >>> CHECK NODE-COORD DATA std::vector> test_coords = { @@ -66,6 +75,7 @@ void read_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { // >>> CHECK SIDE DATA FAIL_IF_NOT(x3d_reader->get_numsides() == 4); + FAIL_IF_NOT(x3d_reader_alt->get_numsides() == 4); std::vector> test_sidenodes = { {0, 1}, {1, 3}, {2, 3}, {0, 2}}; @@ -75,13 +85,16 @@ void read_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { // sides must always give 2 nodes per face in X3D FAIL_IF_NOT(x3d_reader->get_sidetype(side) == 2); + FAIL_IF_NOT(x3d_reader_alt->get_sidetype(side) == 2); // boundary conditions are not supplied in X3D // (note this check is specialized for the 1-cell mesh) FAIL_IF_NOT(x3d_reader->get_sideflag(side) == bdy_flags[side]); + FAIL_IF_NOT(x3d_reader_alt->get_sideflag(side) == bdy_flags[side]); // check node indices FAIL_IF_NOT(x3d_reader->get_sidenodes(side) == test_sidenodes[side]); + FAIL_IF_NOT(x3d_reader_alt->get_sidenodes(side) == test_sidenodes[side]); } // >>> CHECK BC-NODE MAP @@ -118,7 +131,8 @@ void build_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { const size_t num_ydir = 1; // generate a constainer for data needed in mesh construction - rtt_mesh_test::Test_Mesh_Interface mesh_iface(num_xdir, num_ydir); + rtt_mesh_test::Test_Mesh_Interface mesh_iface(num_xdir, num_ydir, {}, 0.0, + 0.0, true); // short-cut to some arrays const std::vector &cell_type = mesh_iface.cell_type; @@ -132,7 +146,8 @@ void build_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { std::shared_ptr ref_mesh(new Draco_Mesh( mesh_iface.dim, geometry, cell_type, cell_to_node_linkage, mesh_iface.side_set_flag, side_node_count, side_to_node_linkage, - mesh_iface.coordinates, mesh_iface.global_node_number)); + mesh_iface.coordinates, mesh_iface.global_node_number, {}, {}, {}, {}, + mesh_iface.face_type)); // >>> PARSE AND BUILD MESH @@ -144,7 +159,7 @@ void build_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { // construct reader std::shared_ptr x3d_reader( - new X3D_Draco_Mesh_Reader(filename, bdy_filenames)); + new X3D_Draco_Mesh_Reader(filename, bdy_filenames, {}, true)); // read mesh x3d_reader->read_mesh(); @@ -196,6 +211,7 @@ void build_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { side_to_node_linkage.begin(); std::vector::const_iterator test_sn_first = test_sn_linkage.begin(); + for (unsigned side = 0; side < mesh_iface.num_sides; ++side) { // check that sn_linkage is a permutation of the original side-node From a92fc0ad147972adf13fb4d61268f9f4a1d76dd6 Mon Sep 17 00:00:00 2001 From: Ryan Wollaeger Date: Sun, 9 Jun 2019 17:09:07 -0600 Subject: [PATCH 6/7] + Add autodocumentation for use_face_type_ arg in X3D reader. + Remove DLL_PUBLIC macros from X3D and RTT functions. + Update X3D unit test with newer failure macros. --- src/mesh/RTT_Draco_Mesh_Reader.hh | 4 +-- src/mesh/X3D_Draco_Mesh_Reader.cc | 2 ++ src/mesh/X3D_Draco_Mesh_Reader.hh | 3 +- src/mesh/test/tstX3D_Draco_Mesh_Reader.cc | 42 ++++++++--------------- 4 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/mesh/RTT_Draco_Mesh_Reader.hh b/src/mesh/RTT_Draco_Mesh_Reader.hh index fb76384015..d7f2148d9b 100644 --- a/src/mesh/RTT_Draco_Mesh_Reader.hh +++ b/src/mesh/RTT_Draco_Mesh_Reader.hh @@ -34,11 +34,11 @@ private: public: //! Constructor - DLL_PUBLIC_mesh explicit RTT_Draco_Mesh_Reader(const std::string filename_); + explicit RTT_Draco_Mesh_Reader(const std::string filename_); // >>> SERVICES - DLL_PUBLIC_mesh void read_mesh(); + void read_mesh(); // >>> ACCESSORS diff --git a/src/mesh/X3D_Draco_Mesh_Reader.cc b/src/mesh/X3D_Draco_Mesh_Reader.cc index 66728dafa0..a4989f54a5 100644 --- a/src/mesh/X3D_Draco_Mesh_Reader.cc +++ b/src/mesh/X3D_Draco_Mesh_Reader.cc @@ -26,6 +26,8 @@ namespace rtt_mesh { * \param[in] bdy_filenames_ names of files with lists of side node indexes * \param[in] bdy_flags_ unsigned int indicating B.C. per side file * (bdy_filenames_) + * \param[in] use_face_types_ provide dimension-independent connectivity data + * to Draco_Mesh_Builder. */ X3D_Draco_Mesh_Reader::X3D_Draco_Mesh_Reader( const std::string &filename_, diff --git a/src/mesh/X3D_Draco_Mesh_Reader.hh b/src/mesh/X3D_Draco_Mesh_Reader.hh index e116da406f..5797086339 100644 --- a/src/mesh/X3D_Draco_Mesh_Reader.hh +++ b/src/mesh/X3D_Draco_Mesh_Reader.hh @@ -89,7 +89,6 @@ private: public: //! Constructor - DLL_PUBLIC_mesh X3D_Draco_Mesh_Reader(const std::string &filename_, const std::vector &bdy_filenames_ = {}, const std::vector &bdy_flags_ = {}, @@ -97,7 +96,7 @@ public: // >>> SERVICES - DLL_PUBLIC_mesh void read_mesh(); + void read_mesh(); // >>> ACCESSORS diff --git a/src/mesh/test/tstX3D_Draco_Mesh_Reader.cc b/src/mesh/test/tstX3D_Draco_Mesh_Reader.cc index 6e5c87a353..9a2a6b2c19 100644 --- a/src/mesh/test/tstX3D_Draco_Mesh_Reader.cc +++ b/src/mesh/test/tstX3D_Draco_Mesh_Reader.cc @@ -169,37 +169,26 @@ void build_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { std::shared_ptr mesh = mesh_builder.build_mesh(geometry); // check that the scalar data is correct - if (mesh->get_dimension() != ref_mesh->get_dimension()) - ITFAILS; - if (mesh->get_geometry() != ref_mesh->get_geometry()) - ITFAILS; - if (mesh->get_num_cells() != ref_mesh->get_num_cells()) - ITFAILS; - if (mesh->get_num_nodes() != ref_mesh->get_num_nodes()) - ITFAILS; + FAIL_IF(mesh->get_dimension() != ref_mesh->get_dimension()); + FAIL_IF(mesh->get_geometry() != ref_mesh->get_geometry()); + FAIL_IF(mesh->get_num_cells() != ref_mesh->get_num_cells()); + FAIL_IF(mesh->get_num_nodes() != ref_mesh->get_num_nodes()); // check that layout is correct (empty for one cell, no side or ghost data) - if ((mesh->get_cc_linkage()).size() > 0) - ITFAILS; - if ((mesh->get_cs_linkage()).size() != 1) - ITFAILS; - if ((mesh->get_cg_linkage()).size() > 0) - ITFAILS; + FAIL_IF((mesh->get_cc_linkage()).size() > 0); + FAIL_IF((mesh->get_cs_linkage()).size() != 1); + FAIL_IF((mesh->get_cg_linkage()).size() > 0); // check side flag indices (should be different) - if (mesh->get_side_set_flag() == ref_mesh->get_side_set_flag()) - ITFAILS; + FAIL_IF(mesh->get_side_set_flag() == ref_mesh->get_side_set_flag()); // check ghost cell data (should be empty defaults) - if (mesh->get_ghost_cell_numbers() != ref_mesh->get_ghost_cell_numbers()) - ITFAILS; - if (mesh->get_ghost_cell_ranks() != ref_mesh->get_ghost_cell_ranks()) - ITFAILS; + FAIL_IF(mesh->get_ghost_cell_numbers() != ref_mesh->get_ghost_cell_numbers()); + FAIL_IF(mesh->get_ghost_cell_ranks() != ref_mesh->get_ghost_cell_ranks()); // check that the vector of coordinates match the reference mesh - if (!rtt_dsxx::soft_equiv(mesh->get_node_coord_vec(), - ref_mesh->get_node_coord_vec())) - ITFAILS; + FAIL_IF(!rtt_dsxx::soft_equiv(mesh->get_node_coord_vec(), + ref_mesh->get_node_coord_vec())); // check that each cell has the correct sides { @@ -216,10 +205,9 @@ void build_x3d_mesh_2d(rtt_c4::ParallelUnitTest &ut) { // check that sn_linkage is a permutation of the original side-node // linkage - if (!std::is_permutation(test_sn_first, - test_sn_first + side_node_count[side], sn_first, - sn_first + side_node_count[side])) - ITFAILS; + FAIL_IF(!std::is_permutation(test_sn_first, + test_sn_first + side_node_count[side], + sn_first, sn_first + side_node_count[side])); // update the iterators sn_first += side_node_count[side]; From be9dc1834e923c092cf788714c273b5ca030c448 Mon Sep 17 00:00:00 2001 From: Ryan Wollaeger Date: Mon, 10 Jun 2019 09:16:35 -0600 Subject: [PATCH 7/7] Incorporate suggestions from KT. + Put variable unused in release builds in Remember macro. + Add noreturn decorator to function that only throws assertion. + Remove commented out code. --- src/mesh/Draco_Mesh.cc | 1 - src/mesh/Draco_Mesh_Builder.t.hh | 9 ++++++++- src/mesh/RTT_Draco_Mesh_Reader.hh | 8 ++++---- src/mesh/X3D_Draco_Mesh_Reader.cc | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/mesh/Draco_Mesh.cc b/src/mesh/Draco_Mesh.cc index 288815440d..03ee437eac 100644 --- a/src/mesh/Draco_Mesh.cc +++ b/src/mesh/Draco_Mesh.cc @@ -11,7 +11,6 @@ #include "Draco_Mesh.hh" #include "ds++/Assert.hh" #include -// #include #include namespace rtt_mesh { diff --git a/src/mesh/Draco_Mesh_Builder.t.hh b/src/mesh/Draco_Mesh_Builder.t.hh index 537717e9d2..2f8709c04b 100644 --- a/src/mesh/Draco_Mesh_Builder.t.hh +++ b/src/mesh/Draco_Mesh_Builder.t.hh @@ -163,6 +163,12 @@ Draco_Mesh_Builder::build_mesh(rtt_mesh_element::Geometry geometry) { } } + // assume parallel face data is empty + const std::vector ghost_cell_type; + const std::vector ghost_cell_to_node_linkage; + const std::vector ghost_cell_number; + const std::vector ghost_cell_rank; + Remember(auto cn_minmax = std::minmax_element(cell_to_node_linkage.begin(), cell_to_node_linkage.end())); Remember(auto sn_minmax = std::minmax_element(side_to_node_linkage.begin(), @@ -178,7 +184,8 @@ Draco_Mesh_Builder::build_mesh(rtt_mesh_element::Geometry geometry) { std::shared_ptr mesh(new Draco_Mesh( dimension, geometry, cell_type, cell_to_node_linkage, side_set_flag, side_node_count, side_to_node_linkage, coordinates, global_node_number, - {}, {}, {}, {}, face_type)); + ghost_cell_type, ghost_cell_to_node_linkage, ghost_cell_number, + ghost_cell_rank, face_type)); return mesh; } diff --git a/src/mesh/RTT_Draco_Mesh_Reader.hh b/src/mesh/RTT_Draco_Mesh_Reader.hh index d7f2148d9b..1a7b232260 100644 --- a/src/mesh/RTT_Draco_Mesh_Reader.hh +++ b/src/mesh/RTT_Draco_Mesh_Reader.hh @@ -52,12 +52,12 @@ public: std::vector get_cellnodes(size_t cell) const { return rtt_reader->get_cells_nodes(cell); } - std::vector get_cellfacenodes(size_t /*cell*/, - size_t /*face*/) const { + [[noreturn]] std::vector get_cellfacenodes(size_t /*cell*/, + size_t /*face*/) const { Insist(false, "cell-face nodes not implemented with RTT reader."); - return std::vector(); + } size_t get_numsides() const { + return rtt_reader->get_dims_nsides(); } - size_t get_numsides() const { return rtt_reader->get_dims_nsides(); } unsigned get_sideflag(size_t side) const { return rtt_reader->get_sides_flags(side, 0); } diff --git a/src/mesh/X3D_Draco_Mesh_Reader.cc b/src/mesh/X3D_Draco_Mesh_Reader.cc index a4989f54a5..d30e2bf8a0 100644 --- a/src/mesh/X3D_Draco_Mesh_Reader.cc +++ b/src/mesh/X3D_Draco_Mesh_Reader.cc @@ -249,7 +249,7 @@ X3D_Draco_Mesh_Reader::get_cellfacenodes(size_t cell, size_t face) const { Check(cell + 1 < INT_MAX); const std::vector &cell_data = x3d_cellface_map.at(static_cast(cell + 1)); - const size_t num_faces = cell_data[0]; + Remember(const size_t num_faces = cell_data[0]); Check(face < num_faces); // get the face index, which will by key for face-to-node map