Beispiel #1
0
inline
void setupKeyholeMesh2D_case2(stk::mesh::BulkData& bulk)
{
//
//   proc 0      proc 1
//            |
//            | block_2 block_3
//            |
// block_1    |         12---11
//            |         | 4  |
//    4----3  | 3----6  6----10
//    | 1  |  | |  2 |
//    1----2  | 2----5  5----9
//            |         | 3  |
//            |         7----8
//            |
//
//nodes 5 and 6 are ghosts (aura) on proc 0,
//and should be members of block_2 and block_3 on proc 0
//if edges are added, the edge between nodes 5 and 6 should
//be a member of block_2 not block_3.
//

  stk::mesh::MetaData& meta = bulk.mesh_meta_data();

  stk::mesh::Part& block_1 = meta.declare_part_with_topology("block_1", stk::topology::QUAD_4_2D);
  stk::mesh::Part& block_2 = meta.declare_part_with_topology("block_2", stk::topology::QUAD_4_2D);
  stk::mesh::Part& block_3 = meta.declare_part_with_topology("block_3", stk::topology::QUAD_4_2D);
  meta.commit();

  bulk.modification_begin();

  stk::mesh::EntityIdVector elem1_nodes {1, 2, 3, 4};
  stk::mesh::EntityIdVector elem2_nodes {2, 5, 6, 3};
  stk::mesh::EntityIdVector elem3_nodes {7, 8, 9, 5};
  stk::mesh::EntityIdVector elem4_nodes {6, 10, 11, 12};

  stk::mesh::EntityId elemId = 1;
  if (bulk.parallel_rank() == 0) {
    stk::mesh::declare_element(bulk, block_1, elemId, elem1_nodes);
    stk::mesh::Entity node2 = bulk.get_entity(stk::topology::NODE_RANK, 2);
    stk::mesh::Entity node3 = bulk.get_entity(stk::topology::NODE_RANK, 3);
    bulk.add_node_sharing(node2, 1);
    bulk.add_node_sharing(node3, 1);
  }
  else if (bulk.parallel_rank() == 1) {
    elemId = 2;
    stk::mesh::declare_element(bulk, block_2, elemId, elem2_nodes);
    elemId = 3;
    stk::mesh::declare_element(bulk, block_3, elemId, elem3_nodes);
    elemId = 4;
    stk::mesh::declare_element(bulk, block_3, elemId, elem4_nodes);
    stk::mesh::Entity node2 = bulk.get_entity(stk::topology::NODE_RANK, 2);
    stk::mesh::Entity node3 = bulk.get_entity(stk::topology::NODE_RANK, 3);
    bulk.add_node_sharing(node2, 0);
    bulk.add_node_sharing(node3, 0);
  }

  bulk.modification_end();
}
// ========================================================================
void process_surface_entity(const Ioss::SideSet* sset ,
                            stk::mesh::BulkData & bulk)
{
    assert(sset->type() == Ioss::SIDESET);

    const stk::mesh::MetaData& meta = stk::mesh::MetaData::get(bulk);
    const stk::mesh::EntityRank element_rank = stk::topology::ELEMENT_RANK;

    int block_count = sset->block_count();
    for (int i=0; i < block_count; i++) {
        Ioss::SideBlock *block = sset->get_block(i);
        if (stk::io::include_entity(block)) {
            std::vector<int> side_ids ;
            std::vector<int> elem_side ;

            stk::mesh::Part * const side_block_part = meta.get_part(block->name());
            stk::mesh::EntityRank side_rank = side_block_part->primary_entity_rank();

            block->get_field_data("ids", side_ids);
            block->get_field_data("element_side", elem_side);

            assert(side_ids.size() * 2 == elem_side.size());
            stk::mesh::PartVector add_parts( 1 , side_block_part );

            size_t side_count = side_ids.size();
            std::vector<stk::mesh::Entity> sides(side_count);
            for(size_t is=0; is<side_count; ++is) {

                stk::mesh::Entity const elem = bulk.get_entity(element_rank, elem_side[is*2]);

                // If NULL, then the element was probably assigned to an
                // element block that appears in the database, but was
                // subsetted out of the analysis mesh. Only process if
                // non-null.
                if (bulk.is_valid(elem)) {
                    // Ioss uses 1-based side ordinal, stk::mesh uses 0-based.
                    // Hence the '-1' in the following line.
                    int side_ordinal = elem_side[is*2+1] - 1 ;

                    stk::mesh::Entity side = stk::mesh::Entity();
                    if (side_rank == 2) {
                        side = stk::mesh::declare_element_side(bulk, side_ids[is], elem, side_ordinal);
                    } else {
                        side = stk::mesh::declare_element_edge(bulk, side_ids[is], elem, side_ordinal);
                    }
                    bulk.change_entity_parts( side, add_parts );
                    sides[is] = side;
                } else {
                    sides[is] = stk::mesh::Entity();
                }
            }

            const stk::mesh::FieldBase *df_field = stk::io::get_distribution_factor_field(*side_block_part);

            if (df_field != NULL) {
                stk::io::field_data_from_ioss(bulk, df_field, sides, block, "distribution_factors");
            }
        }
    }
}
inline stk::mesh::Entity get_face_between_element_ids(stk::mesh::ElemElemGraph& graph, stk::mesh::BulkData& bulkData, stk::mesh::EntityId elem1Id, stk::mesh::EntityId elem2Id)
{
    stk::mesh::Entity elem1 = bulkData.get_entity(stk::topology::ELEM_RANK, elem1Id);
    stk::mesh::Entity elem2 = bulkData.get_entity(stk::topology::ELEM_RANK, elem2Id);

    bool isElem1LocallyOwnedAndValid = bulkData.is_valid(elem1) && bulkData.bucket(elem1).owned();
    bool isElem2LocallyOwnedAndValid = bulkData.is_valid(elem2) && bulkData.bucket(elem2).owned();

    stk::mesh::Entity face_between_elem1_and_elem2;

    if(isElem1LocallyOwnedAndValid && isElem2LocallyOwnedAndValid)
    {
        int side = graph.get_side_from_element1_to_locally_owned_element2(elem1, elem2);
        EXPECT_TRUE(side != -1);
        face_between_elem1_and_elem2 = stk::mesh::impl::get_side_for_element(bulkData, elem1, side);
    }
    else if(isElem1LocallyOwnedAndValid)
    {
        int side = graph.get_side_from_element1_to_remote_element2(elem1, elem2Id);
        EXPECT_TRUE(side != -1);
        face_between_elem1_and_elem2 = stk::mesh::impl::get_side_for_element(bulkData, elem1, side);
    }
    else if(isElem2LocallyOwnedAndValid)
    {
        int side = graph.get_side_from_element1_to_remote_element2(elem2, elem1Id);
        EXPECT_TRUE(side != -1);
        face_between_elem1_and_elem2 = stk::mesh::impl::get_side_for_element(bulkData, elem2, side);
    }
    return face_between_elem1_and_elem2;
}
 void convert_elem_sides_pairs_into_sideset(const stk::mesh::BulkData& bulk, const std::vector<int>& elem_side, stk::mesh::SideSet& sideset)
 {
     for(size_t is=0; is<elem_side.size() / 2; ++is)
     {
         stk::mesh::Entity const elem = bulk.get_entity(stk::topology::ELEMENT_RANK, elem_side[is*2]);
         if (bulk.is_valid(elem))
             sideset.push_back(add_elem_side_pair(elem, elem_side[is*2+1]));
     }
 }
inline void test_num_faces_on_this_element(const stk::mesh::BulkData& bulkData, stk::mesh::EntityId id, size_t gold_num_faces_this_elem)
{
    stk::mesh::Entity element = bulkData.get_entity(stk::topology::ELEM_RANK, id);
    if(bulkData.is_valid(element))
    {
        unsigned num_faces_this_elem = bulkData.num_faces(element);
        EXPECT_EQ(gold_num_faces_this_elem, num_faces_this_elem);
    }
}
void heterogeneous_mesh_bulk_data(
  stk::mesh::BulkData & bulk_data ,
  const VectorFieldType & node_coord )
{
  static const char method[] =
    "stk_mesh::fixtures::heterogenous_mesh_bulk_data" ;

  bulk_data.modification_begin();

  const stk::mesh::MetaData & meta_data = stk::mesh::MetaData::get(bulk_data);

  stk::mesh::Part & hex_block        = * meta_data.get_part("hexes",method);
  stk::mesh::Part & wedge_block      = * meta_data.get_part("wedges",method);
  stk::mesh::Part & tetra_block      = * meta_data.get_part("tets",method);
  stk::mesh::Part & pyramid_block    = * meta_data.get_part("pyramids",method);
  stk::mesh::Part & quad_shell_block = * meta_data.get_part("quad_shells",method);
  stk::mesh::Part & tri_shell_block  = * meta_data.get_part("tri_shells",method);

  unsigned elem_id = 1 ;

  for ( unsigned i = 0 ; i < number_hex ; ++i , ++elem_id ) {
    stk::mesh::declare_element( bulk_data, hex_block, elem_id, hex_node_ids[i] );
  }

  for ( unsigned i = 0 ; i < number_wedge ; ++i , ++elem_id ) {
    stk::mesh::declare_element( bulk_data, wedge_block, elem_id, wedge_node_ids[i] );
  }

  for ( unsigned i = 0 ; i < number_tetra ; ++i , ++elem_id ) {
    stk::mesh::declare_element( bulk_data, tetra_block, elem_id, tetra_node_ids[i] );
  }

  for ( unsigned i = 0 ; i < number_pyramid ; ++i , ++elem_id ) {
    stk::mesh::declare_element( bulk_data, pyramid_block, elem_id, pyramid_node_ids[i] );
  }

  for ( unsigned i = 0 ; i < number_shell_quad ; ++i , ++elem_id ) {
    stk::mesh::declare_element( bulk_data, quad_shell_block, elem_id, shell_quad_node_ids[i]);
  }

  for ( unsigned i = 0 ; i < number_shell_tri ; ++i , ++elem_id ) {
    stk::mesh::declare_element( bulk_data, tri_shell_block, elem_id, shell_tri_node_ids[i] );
  }
  
  for ( unsigned i = 0 ; i < node_count ; ++i ) {

    stk::mesh::Entity const node = bulk_data.get_entity( stk::topology::NODE_RANK , i + 1 );

    double * const coord = stk::mesh::field_data( node_coord , node );

    coord[0] = node_coord_data[i][0] ;
    coord[1] = node_coord_data[i][1] ;
    coord[2] = node_coord_data[i][2] ;
  }

  bulk_data.modification_end();
}
Beispiel #7
0
inline
void setupKeyholeMesh3D_case2(stk::mesh::BulkData& bulk)
{
    ThrowRequire(bulk.parallel_size() == 3);
    stk::io::fill_mesh("generated:3x1x3", bulk);

    stk::mesh::EntityProcVec elementProcChanges;
    if (bulk.parallel_rank() == 1) {
        elementProcChanges.push_back(stk::mesh::EntityProc(bulk.get_entity(stk::topology::ELEM_RANK,4),2));
        elementProcChanges.push_back(stk::mesh::EntityProc(bulk.get_entity(stk::topology::ELEM_RANK,6),2));
    }
    bulk.change_entity_owner(elementProcChanges);
    bulk.modification_begin();
    if (bulk.parallel_rank() == 1) {
        stk::mesh::Entity local_element5 = bulk.get_entity(stk::topology::ELEM_RANK,5);
        const bool delete_success = bulk.destroy_entity(local_element5);
        ThrowRequire(delete_success);
    }
    bulk.modification_end();
}
Beispiel #8
0
std::string get_non_unique_key_messages(const stk::mesh::BulkData& bulkData, const std::vector<stk::mesh::EntityKeyProc> &badKeyProcs)
{
    std::ostringstream os;
    for(const stk::mesh::EntityKeyProc& keyProc : badKeyProcs)
    {
        stk::mesh::Entity entity = bulkData.get_entity(keyProc.first);
        os << "[" << bulkData.parallel_rank() << "] Key " << keyProc.first <<
                get_topology(bulkData.bucket(entity).topology()) << "is also present (inappropriately) on processor " <<
                keyProc.second << "." << std::endl;
    }
    return os.str();
}
Beispiel #9
0
// element ids / proc_id:
// |-------|-------|-------|
// |       |       |       |
// |  1/0  |  4/2  |  7/2  |
// |       |       |       |
// |-------|-------|-------|
// |       |       |       |
// |  2/0  |  5/1  |  8/2  |
// |       |       |       |
// |-------|-------|-------|
// |       |       |       |
// |  3/0  |  6/2  |  9/2  |
// |       |       |       |
// |-------|-------|-------|
inline
void setupKeyholeMesh3D_case1(stk::mesh::BulkData& bulk)
{
    ThrowRequire(bulk.parallel_size() == 3);
    stk::io::fill_mesh("generated:3x1x3", bulk);

    stk::mesh::EntityProcVec elementProcChanges;
    if (bulk.parallel_rank() == 1) {
        elementProcChanges.push_back(stk::mesh::EntityProc(bulk.get_entity(stk::topology::ELEM_RANK,4u),2));
        elementProcChanges.push_back(stk::mesh::EntityProc(bulk.get_entity(stk::topology::ELEM_RANK,6u),2));
    }
    bulk.change_entity_owner(elementProcChanges);
}
stk::mesh::GraphEdge unpack_edge(stk::CommSparse& comm, const stk::mesh::BulkData& bulkData, const ElemElemGraph& graph, int proc_id)
{
    stk::mesh::EntityId id1 = 0, id2 = 0;
    unsigned side1 = 0, side2 = 0;
    comm.recv_buffer(proc_id).unpack<stk::mesh::EntityId>(id1);
    comm.recv_buffer(proc_id).unpack<unsigned>(side1);
    comm.recv_buffer(proc_id).unpack<stk::mesh::EntityId>(id2);
    comm.recv_buffer(proc_id).unpack<unsigned>(side2);

    stk::mesh::Entity element = bulkData.get_entity(stk::topology::ELEM_RANK, id2);
    ThrowRequireWithSierraHelpMsg(bulkData.is_valid(element));

    stk::mesh::impl::LocalId localId2 = graph.get_local_element_id(element);
    stk::mesh::GraphEdge edge(localId2, side2, -id1, side1);
    return edge;
}
void addNodesToPart(
    const Teuchos::ArrayView<const stk::mesh::EntityId> &nodeIds,
    stk::mesh::Part &samplePart,
    stk::mesh::BulkData& bulkData)
{
  const stk::mesh::PartVector samplePartVec(1, &samplePart);
  const stk::mesh::Selector locallyOwned = stk::mesh::MetaData::get(bulkData).locally_owned_part();

  BulkModification mod(bulkData);
  typedef Teuchos::ArrayView<const stk::mesh::EntityId>::const_iterator Iter;
  for (Iter it = nodeIds.begin(), it_end = nodeIds.end(); it != it_end; ++it) {
    stk::mesh::Entity node = bulkData.get_entity(stk::topology::NODE_RANK, *it);
    if (bulkData.is_valid(node) && locallyOwned(bulkData.bucket(node))) {
      bulkData.change_entity_parts(node, samplePartVec);
    }
  }
}
void addNodesToPart(
    const Teuchos::ArrayView<const stk::mesh::EntityId> &nodeIds,
    stk::mesh::Part &samplePart,
    stk::mesh::BulkData& bulkData)
{
  const stk::mesh::EntityRank nodeEntityRank(0);
  const stk::mesh::PartVector samplePartVec(1, &samplePart);
  const stk::mesh::Selector locallyOwned = stk::mesh::MetaData::get(bulkData).locally_owned_part();

  BulkModification mod(bulkData);
  typedef Teuchos::ArrayView<const stk::mesh::EntityId>::const_iterator Iter;
  for (Iter it = nodeIds.begin(), it_end = nodeIds.end(); it != it_end; ++it) {
    const Teuchos::Ptr<stk::mesh::Entity> node(bulkData.get_entity(nodeEntityRank, *it));
    if (Teuchos::nonnull(node) && locallyOwned(*node)) {
      bulkData.change_entity_parts(*node, samplePartVec);
    }
  }
}
Beispiel #13
0
std::string get_message_for_split_coincident_elements(const stk::mesh::BulkData& bulkData, const std::map<stk::mesh::EntityId, std::pair<stk::mesh::EntityId, int> > & splitCoincidentElements)
{
    std::ostringstream out;
    for(const auto& item : splitCoincidentElements) {
        stk::mesh::Entity element = bulkData.get_entity(stk::topology::ELEM_RANK,item.first);
        const stk::mesh::PartVector& elementParts = bulkData.bucket(element).supersets();
        std::string blockNames;
        blockNames = "{";
        for (const stk::mesh::Part* part : elementParts) {
            if (stk::mesh::impl::is_element_block(*part)) {
                blockNames += " " + part->name();
            }
        }
        blockNames += " }";
        out << "[" << bulkData.parallel_rank() << "] Element " << item.first << " (" << bulkData.bucket(element).topology() << ") in blocks " << blockNames << " is coincident with element " << item.second.first << " on processor " << item.second.second << std::endl;
    }
    return out.str();
}
// ========================================================================
void process_nodesets(Ioss::Region &region, stk::mesh::BulkData &bulk)
{
    // Should only process nodes that have already been defined via the element
    // blocks connectivity lists.
    const Ioss::NodeSetContainer& node_sets = region.get_nodesets();

    for(Ioss::NodeSetContainer::const_iterator it = node_sets.begin();
            it != node_sets.end(); ++it) {
        Ioss::NodeSet *entity = *it;

        if (stk::io::include_entity(entity)) {
            const std::string & name = entity->name();
            const stk::mesh::MetaData& meta = stk::mesh::MetaData::get(bulk);
            stk::mesh::Part* const part = meta.get_part(name);
            STKIORequire(part != NULL);
            stk::mesh::PartVector add_parts( 1 , part );

            std::vector<int> node_ids ;
            int node_count = entity->get_field_data("ids", node_ids);

            std::vector<stk::mesh::Entity> nodes(node_count);
            for(int i=0; i<node_count; ++i) {
                nodes[i] = bulk.get_entity( stk::topology::NODE_RANK, node_ids[i] );
                if (bulk.is_valid(nodes[i])) {
                    bulk.declare_entity(stk::topology::NODE_RANK, node_ids[i], add_parts );
                }
            }

            /** \todo REFACTOR Application would probably store this field
             * (and others) somewhere after the declaration instead of
             * looking it up each time it is needed.
             */
            stk::mesh::Field<double> *df_field =
                meta.get_field<stk::mesh::Field<double> >(stk::topology::NODE_RANK, "distribution_factors");

            if (df_field != NULL) {
                stk::io::field_data_from_ioss(bulk, df_field, nodes, entity, "distribution_factors");
            }
        }
    }
}
Beispiel #15
0
inline
void setupKeyholeMesh2D_case1(stk::mesh::BulkData& bulk)
{
//
//   proc 0      proc 1
//            |
//            |  block_2 block_3
//            |
//  block_1   |  10---9  9----12
//            |  | 3  |  |  4  |
//    4----3  |  3----8  8----11
//    | 1  |  |
//    1----2  |  2----7
//            |  | 2  |
//            |  5----6
//            |
//
//shared nodes 2 and 3 should be members of block_1 and block_2 on both procs
//nodes 8 and 9 are ghosts on proc 0, and should be members of block_2 and block_3
//
//if edges are added, the edge between nodes 2 and 3 should be a member of block_1 not block_2.
//
//also, the edge between nodes 8 and 9 should be a member of block_2 and block_3 on both procs.

  stk::mesh::MetaData& meta = bulk.mesh_meta_data();

  stk::mesh::Part& block_1 = meta.declare_part_with_topology("block_1", stk::topology::QUAD_4_2D);
  stk::mesh::Part& block_2 = meta.declare_part_with_topology("block_2", stk::topology::QUAD_4_2D);
  stk::mesh::Part& block_3 = meta.declare_part_with_topology("block_3", stk::topology::QUAD_4_2D);
  meta.commit();

  bulk.modification_begin();

  stk::mesh::EntityIdVector elem1_nodes {1, 2, 3, 4};
  stk::mesh::EntityIdVector elem2_nodes {5, 6, 7, 2};
  stk::mesh::EntityIdVector elem3_nodes {3, 8, 9, 10};
  stk::mesh::EntityIdVector elem4_nodes {8, 11, 12, 9};

  stk::mesh::EntityId elemId = 1;
  if (bulk.parallel_rank() == 0) {
    stk::mesh::declare_element(bulk, block_1, elemId, elem1_nodes);
    stk::mesh::Entity node2 = bulk.get_entity(stk::topology::NODE_RANK, 2);
    stk::mesh::Entity node3 = bulk.get_entity(stk::topology::NODE_RANK, 3);
    bulk.add_node_sharing(node2, 1);
    bulk.add_node_sharing(node3, 1);
  }
  else if (bulk.parallel_rank() == 1) {
    elemId = 2;
    stk::mesh::declare_element(bulk, block_2, elemId, elem2_nodes);
    elemId = 3;
    stk::mesh::declare_element(bulk, block_2, elemId, elem3_nodes);
    elemId = 4;
    stk::mesh::declare_element(bulk, block_3, elemId, elem4_nodes);
    stk::mesh::Entity node2 = bulk.get_entity(stk::topology::NODE_RANK, 2);
    stk::mesh::Entity node3 = bulk.get_entity(stk::topology::NODE_RANK, 3);
    bulk.add_node_sharing(node2, 0);
    bulk.add_node_sharing(node3, 0);
  }

  bulk.modification_end();
}
inline
void setup2Block2HexMesh(stk::mesh::BulkData& bulk)
{
//
//   proc 0      proc 1
//             |
//    block_1  |  block_2
//             |
//      8----7 |    7----12
//     /    /| |   /    / |
//    5----6 3 |  6----11 10
//    | 1  |/  |  | 2  | /
//    1----2   |  2----9
//             |
//             |
//             |
//
//shared nodes 2, 3, 6, 7
//

  if (bulk.parallel_size() > 2) {
    return;
  }

  stk::mesh::MetaData& meta = bulk.mesh_meta_data();

  stk::topology hex = stk::topology::HEX_8;
  stk::mesh::Part& block_1 = meta.declare_part_with_topology("block_1", hex);
  stk::mesh::Part& block_2 = meta.declare_part_with_topology("block_2", hex);
  meta.commit();

  bulk.modification_begin();

  stk::mesh::EntityIdVector elem1_nodes {1, 2, 3, 4, 5, 6, 7, 8};
  stk::mesh::EntityIdVector elem2_nodes {2, 9, 10, 3, 6, 11, 12, 7};

  stk::mesh::EntityId elemId = 1;
  if (bulk.parallel_rank() == 0) {
    stk::mesh::declare_element(bulk, block_1, elemId, elem1_nodes);
  }
  if (bulk.parallel_rank() == 1 || bulk.parallel_size() == 1) {
    elemId = 2;
    stk::mesh::declare_element(bulk, block_2, elemId, elem2_nodes);
  }
  if(bulk.parallel_rank() == 0 && bulk.parallel_size() == 2)
  {
    bulk.add_node_sharing(bulk.get_entity(stk::topology::NODE_RANK , 2), 1);
    bulk.add_node_sharing(bulk.get_entity(stk::topology::NODE_RANK , 3), 1);
    bulk.add_node_sharing(bulk.get_entity(stk::topology::NODE_RANK , 6), 1);
    bulk.add_node_sharing(bulk.get_entity(stk::topology::NODE_RANK , 7), 1);
  }
  if(bulk.parallel_rank() == 1 && bulk.parallel_size() == 2)
  {
    bulk.add_node_sharing(bulk.get_entity(stk::topology::NODE_RANK , 2), 0);
    bulk.add_node_sharing(bulk.get_entity(stk::topology::NODE_RANK , 3), 0);
    bulk.add_node_sharing(bulk.get_entity(stk::topology::NODE_RANK , 6), 0);
    bulk.add_node_sharing(bulk.get_entity(stk::topology::NODE_RANK , 7), 0);
  }

  bulk.modification_end();
}
Beispiel #17
0
void build_element_from_topology_verify_ordinals_and_permutations(stk::mesh::BulkData &bulk,
                                                                 const stk::topology topo,
                                                                 const stk::mesh::EntityIdVector & elem_node_ids,
                                                                 const stk::mesh::EntityIdVector & edge_ids,
                                                                 const std::vector < std::vector < unsigned > > &gold_side_node_ids,
                                                                 const unsigned * gold_side_permutations,
                                                                 const std::vector < std::vector < unsigned > > &gold_edge_node_ids,
                                                                 const unsigned * gold_edge_permutations)
{
  stk::mesh::EntityId element_id[1] = {1};
  stk::mesh::MetaData &meta = bulk.mesh_meta_data();
  stk::mesh::Part &elem_part = meta.declare_part_with_topology("elem_part", topo);

  meta.commit();
  bulk.modification_begin();

  stk::mesh::Entity elem = stk::mesh::declare_element(bulk, elem_part, element_id[0], elem_node_ids);

  stk::mesh::EntityVector side_nodes;
  uint num_sides = topo.num_sides();
  stk::topology::rank_t sub_topo_rank = topo.side_rank();

  for(uint i = 0; i < num_sides; ++i)
  {
    stk::topology sub_topo = topo.side_topology(i);
    bulk.declare_element_side(elem, i, {&meta.get_topology_root_part(sub_topo)});

    side_nodes.clear();

    for (uint j = 0; j < sub_topo.num_nodes(); ++j)
    {
      stk::mesh::Entity side_node = bulk.get_entity(stk::topology::NODE_RANK, gold_side_node_ids[i][j]);
      side_nodes.push_back(side_node);
    }

    stk::mesh::OrdinalAndPermutation ordinalAndPermutation = stk::mesh::get_ordinal_and_permutation(bulk, elem, sub_topo_rank, side_nodes);

    EXPECT_EQ(ordinalAndPermutation.second, gold_side_permutations[i]) << topo;
    EXPECT_EQ(ordinalAndPermutation.first, i) << topo;
  }

  if (edge_ids.empty()) {
    bulk.modification_end();
    return;
  }

  stk::mesh::EntityVector edge_nodes;
  uint num_edges = topo.num_edges();

  for(uint i = 0; i < num_edges; ++i)
  {
    edge_nodes.clear();

    stk::mesh::Entity edge = bulk.declare_entity(stk::topology::EDGE_RANK, edge_ids[i],
                                                 meta.get_topology_root_part(topo.edge_topology()));

    for (uint j = 0; j < topo.edge_topology().num_nodes(); ++j)
    {
      stk::mesh::Entity edge_node = bulk.get_entity(stk::topology::NODE_RANK, gold_edge_node_ids[i][j]);
      edge_nodes.push_back(edge_node);
      bulk.declare_relation(edge, edge_node, j);
    }

    std::pair<stk::mesh::ConnectivityOrdinal, stk::mesh::Permutation> ordinalAndPermutation
      = stk::mesh::get_ordinal_and_permutation(bulk, elem, stk::topology::EDGE_RANK, edge_nodes);

    EXPECT_EQ(ordinalAndPermutation.second, gold_edge_permutations[i]) << topo;
    EXPECT_EQ(ordinalAndPermutation.first, i) << topo;
  }

  bulk.modification_end();
}
Beispiel #18
0
void verify_unbuildable_element(stk::mesh::BulkData &bulk,
                                const stk::topology topo,
                                const stk::mesh::EntityIdVector & elem_node_ids,
                                const stk::mesh::EntityIdVector & side_ids,
                                const std::vector < std::vector < unsigned > > &gold_side_node_ids,
                                bool *sides_connectibility_check,
                                const stk::mesh::EntityIdVector & edge_ids,
                                const std::vector < std::vector < unsigned > > &gold_edge_node_ids,
                                bool *edges_connectibility_check)
{
  stk::mesh::EntityId element_id[1] = {1};
  stk::mesh::MetaData &meta = bulk.mesh_meta_data();
  stk::mesh::Part &elem_part = meta.declare_part_with_topology("elem_part", topo);

  meta.commit();
  bulk.modification_begin();

  stk::mesh::Entity elem = stk::mesh::declare_element(bulk, elem_part, element_id[0], elem_node_ids);

  stk::mesh::EntityVector side_nodes;
  uint num_sides = topo.num_sides();
  stk::topology::rank_t sub_topo_rank = topo.side_rank();

  for(uint i = 0; i < num_sides; ++i)
  {
    stk::topology sub_topo = topo.side_topology(i);
    side_nodes.clear();

    stk::mesh::Entity side = bulk.declare_entity(sub_topo_rank, side_ids[i], meta.get_topology_root_part(sub_topo));

    for (uint j = 0; j < sub_topo.num_nodes(); ++j)
    {
      stk::mesh::Entity side_node = bulk.get_entity(stk::topology::NODE_RANK, gold_side_node_ids[i][j]);
      side_nodes.push_back(side_node);
      bulk.declare_relation(side, side_node, j);
    }

    std::pair<stk::mesh::ConnectivityOrdinal, stk::mesh::Permutation> ordinalAndPermutation
      = stk::mesh::get_ordinal_and_permutation(bulk, elem, sub_topo_rank, side_nodes);

    if (sides_connectibility_check[i])
    {
      EXPECT_NE(ordinalAndPermutation.first, stk::mesh::ConnectivityOrdinal::INVALID_CONNECTIVITY_ORDINAL);
      EXPECT_NE(ordinalAndPermutation.second, stk::mesh::Permutation::INVALID_PERMUTATION);
    }
    else
    {
      EXPECT_EQ(ordinalAndPermutation.first, stk::mesh::ConnectivityOrdinal::INVALID_CONNECTIVITY_ORDINAL);
      EXPECT_EQ(ordinalAndPermutation.second, stk::mesh::Permutation::INVALID_PERMUTATION);
    }
  }

  if (edge_ids.empty()) {
    bulk.modification_end();
    return;
  }

  stk::mesh::EntityVector edge_nodes;
  uint num_edges = topo.num_edges();

  for(uint i = 0; i < num_edges; ++i)
  {
    edge_nodes.clear();

    stk::mesh::Entity edge = bulk.declare_entity(stk::topology::EDGE_RANK, edge_ids[i],
                                                 meta.get_topology_root_part(topo.edge_topology()));

    for (uint j = 0; j < topo.edge_topology().num_nodes(); ++j)
    {
      stk::mesh::Entity edge_node = bulk.get_entity(stk::topology::NODE_RANK, gold_edge_node_ids[i][j]);
      edge_nodes.push_back(edge_node);
      bulk.declare_relation(edge, edge_node, j);
    }

    std::pair<stk::mesh::ConnectivityOrdinal, stk::mesh::Permutation> ordinalAndPermutation
      = stk::mesh::get_ordinal_and_permutation(bulk, elem, stk::topology::EDGE_RANK, edge_nodes);

    if (edges_connectibility_check[i])
    {
      EXPECT_NE(ordinalAndPermutation.first, stk::mesh::ConnectivityOrdinal::INVALID_CONNECTIVITY_ORDINAL);
      EXPECT_NE(ordinalAndPermutation.second, stk::mesh::Permutation::INVALID_PERMUTATION);
    }
    else
    {
      EXPECT_EQ(ordinalAndPermutation.first, stk::mesh::ConnectivityOrdinal::INVALID_CONNECTIVITY_ORDINAL);
      EXPECT_EQ(ordinalAndPermutation.second, stk::mesh::Permutation::INVALID_PERMUTATION);
    }
  }

  bulk.modification_end();
}
Beispiel #19
0
void Gear::mesh( stk::mesh::BulkData & M )
{
  stk::mesh::EntityRank element_rank = stk::topology::ELEMENT_RANK;
  stk::mesh::EntityRank side_rank = m_mesh_meta_data.side_rank();

  M.modification_begin();

  m_mesh = & M ;

  const unsigned p_size = M.parallel_size();
  const unsigned p_rank = M.parallel_rank();

  std::vector<size_t> counts ;
  stk::mesh::comm_mesh_counts(M, counts);

  // max_id is no longer available from comm_mesh_stats.
  // If we assume uniform numbering from 1.., then max_id
  // should be equal to counts...
  const stk::mesh::EntityId node_id_base = counts[ stk::topology::NODE_RANK ] + 1 ;
  const stk::mesh::EntityId elem_id_base = counts[ element_rank ] + 1 ;

  const unsigned long elem_id_gear_max =
    m_angle_num * ( m_rad_num - 1 ) * ( m_z_num - 1 );

  std::vector<stk::mesh::Part*> elem_parts ;
  std::vector<stk::mesh::Part*> face_parts ;
  std::vector<stk::mesh::Part*> node_parts ;

  {
    stk::mesh::Part * const p_gear = & m_gear ;
    stk::mesh::Part * const p_surf = & m_surf ;

    elem_parts.push_back( p_gear );
    face_parts.push_back( p_surf );
  }

  for ( unsigned ia = 0 ; ia < m_angle_num ; ++ia ) {
    for ( unsigned ir = 0 ; ir < m_rad_num - 1 ; ++ir ) {
      for ( unsigned iz = 0 ; iz < m_z_num - 1 ; ++iz ) {

        stk::mesh::EntityId elem_id_gear = identifier( m_z_num-1 , m_rad_num-1 , iz , ir , ia );

        if ( ( ( elem_id_gear * p_size ) / elem_id_gear_max ) == p_rank ) {

          stk::mesh::EntityId elem_id = elem_id_base + elem_id_gear ;

          // Create the node and set the model_coordinates

          const size_t ia_1 = ( ia + 1 ) % m_angle_num ;
          const size_t ir_1 = ir + 1 ;
          const size_t iz_1 = iz + 1 ;

          stk::mesh::Entity node[8] ;

          node[0] = create_node( node_parts, node_id_base, iz  , ir  , ia_1 );
          node[1] = create_node( node_parts, node_id_base, iz_1, ir  , ia_1 );
          node[2] = create_node( node_parts, node_id_base, iz_1, ir  , ia   );
          node[3] = create_node( node_parts, node_id_base, iz  , ir  , ia   );
          node[4] = create_node( node_parts, node_id_base, iz  , ir_1, ia_1 );
          node[5] = create_node( node_parts, node_id_base, iz_1, ir_1, ia_1 );
          node[6] = create_node( node_parts, node_id_base, iz_1, ir_1, ia   );
          node[7] = create_node( node_parts, node_id_base, iz  , ir_1, ia   );
#if 0 /* VERIFY_CENTROID */

          // Centroid of the element for verification

          const double TWO_PI = 2.0 * acos( -1.0 );
          const double angle = m_ang_inc * (0.5 + ia);
          const double z = m_center[2] + m_z_min + m_z_inc * (0.5 + iz);

          double c[3] = { 0 , 0 , 0 };

          for ( size_t j = 0 ; j < 8 ; ++j ) {
            double * const coord_data = field_data( m_model_coord , *node[j] );
            c[0] += coord_data[0] ;
            c[1] += coord_data[1] ;
            c[2] += coord_data[2] ;
          }
          c[0] /= 8 ; c[1] /= 8 ; c[2] /= 8 ;
          c[0] -= m_center[0] ;
          c[1] -= m_center[1] ;

          double val_a = atan2( c[1] , c[0] );
          if ( val_a < 0 ) { val_a += TWO_PI ; }
          const double err_a = angle - val_a ;
          const double err_z = z - c[2] ;

          const double eps = 100 * std::numeric_limits<double>::epsilon();

          if ( err_z < - eps || eps < err_z ||
               err_a < - eps || eps < err_a ) {
            std::string msg ;
            msg.append("problem setup element centroid error" );
            throw std::logic_error( msg );
          }
#endif

          stk::mesh::Entity elem =
            M.declare_entity( element_rank, elem_id, elem_parts );

          for ( size_t j = 0 ; j < 8 ; ++j ) {
            M.declare_relation( elem , node[j] ,
                                static_cast<unsigned>(j) );
          }
        }
      }
    }
  }

  // Array of faces on the surface

  {
    const size_t ir = m_rad_num - 1 ;

    for ( size_t ia = 0 ; ia < m_angle_num ; ++ia ) {
      for ( size_t iz = 0 ; iz < m_z_num - 1 ; ++iz ) {

        stk::mesh::EntityId elem_id_gear =
          identifier( m_z_num-1 , m_rad_num-1 , iz , ir-1 , ia );

        if ( ( ( elem_id_gear * p_size ) / elem_id_gear_max ) == p_rank ) {

          stk::mesh::EntityId elem_id = elem_id_base + elem_id_gear ;

          unsigned face_ord = 5 ;
          stk::mesh::EntityId face_id = elem_id * 10 + face_ord + 1;

          stk::mesh::Entity node[4] ;

          const size_t ia_1 = ( ia + 1 ) % m_angle_num ;
          const size_t iz_1 = iz + 1 ;

          node[0] = create_node( node_parts, node_id_base, iz  , ir  , ia_1 );
          node[1] = create_node( node_parts, node_id_base, iz_1, ir  , ia_1 );
          node[2] = create_node( node_parts, node_id_base, iz_1, ir  , ia   );
          node[3] = create_node( node_parts, node_id_base, iz  , ir  , ia   );

          stk::mesh::Entity face =
            M.declare_entity( side_rank, face_id, face_parts );

          for ( size_t j = 0 ; j < 4 ; ++j ) {
            M.declare_relation( face , node[j] ,
                                static_cast<unsigned>(j) );
          }

          stk::mesh::Entity elem = M.get_entity(element_rank, elem_id);

          M.declare_relation( elem , face , face_ord );
        }
      }
    }
  }
  M.modification_begin();
}
Beispiel #20
0
void fixup_ghosted_to_shared_nodes(stk::mesh::BulkData & bulk)
{
    stk::mesh::EntityVector ghosted_nodes_that_are_now_shared;
    find_ghosted_nodes_that_need_to_be_shared(bulk, ghosted_nodes_that_are_now_shared);

    stk::CommSparse comm(bulk.parallel());

    for (int phase=0;phase<2;++phase)
    {
        for (size_t i = 0; i < ghosted_nodes_that_are_now_shared.size(); ++i)
        {
            stk::mesh::Entity node = ghosted_nodes_that_are_now_shared[i];
            int proc = bulk.parallel_owner_rank(node);
            comm.send_buffer(proc).pack<stk::mesh::EntityKey>(bulk.entity_key(node));
        }
        if (phase == 0 )
        {
            comm.allocate_buffers();
        }
        else
        {
            comm.communicate();
        }
    }

    stk::mesh::EntityVector sharedNodes;
    for (int process=0;process<bulk.parallel_size();++process)
    {
        while(comm.recv_buffer(process).remaining())
        {
            stk::mesh::EntityKey key;
            comm.recv_buffer(process).unpack<stk::mesh::EntityKey>(key);

            stk::mesh::Entity entity = bulk.get_entity(key);
            if ( bulk.state(entity) != stk::mesh::Deleted && bulk.is_valid(entity) )
            {
                bulk.add_node_sharing(entity, process);
                sharedNodes.push_back(entity);
            }
        }
    }
/////////////////////////

    stk::CommSparse commSecondStage(bulk.parallel());
    for (int phase=0;phase<2;++phase)
    {
        for (size_t i=0;i<sharedNodes.size();++i)
        {
            std::vector<int> procs;
            stk::mesh::EntityKey key = bulk.entity_key(sharedNodes[i]);
            bulk.comm_shared_procs(key, procs);
            for (size_t j=0;j<procs.size();++j)
            {
                if ( procs[j] != bulk.parallel_rank() )
                {
                    commSecondStage.send_buffer(procs[j]).pack<int>(bulk.parallel_rank()).pack<stk::mesh::EntityKey>(key);
                    for (size_t k=0;k<procs.size();++k)
                    {
                        commSecondStage.send_buffer(procs[j]).pack<int>(procs[k]).pack<stk::mesh::EntityKey>(key);
                    }
                }
            }
        }
        if (phase == 0 )
        {
            commSecondStage.allocate_buffers();
        }
        else
        {
            commSecondStage.communicate();
        }
    }

    for (int proc_that_sent_message=0;proc_that_sent_message<bulk.parallel_size();++proc_that_sent_message)
    {
        if ( proc_that_sent_message == bulk.parallel_rank() ) continue;
        while(commSecondStage.recv_buffer(proc_that_sent_message).remaining())
        {
            stk::mesh::EntityKey key;
            int sharingProc;
            commSecondStage.recv_buffer(proc_that_sent_message).unpack<int>(sharingProc).unpack<stk::mesh::EntityKey>(key);
            if ( sharingProc != bulk.parallel_rank() )
            {
                stk::mesh::Entity entity = bulk.get_entity(key);
                if ( bulk.state(entity) != stk::mesh::Deleted && bulk.is_valid(entity) && !bulk.in_shared(key, sharingProc) )
                {
                    bulk.add_node_sharing(entity, sharingProc);
                }
            }
        }
    }
}
void use_case_5_generate_mesh(
  const std::string& mesh_options ,
  stk::mesh::BulkData & mesh ,
  const VectorFieldType & node_coord ,
  stk::mesh::Part & hex_block ,
  stk::mesh::Part & quad_shell_block )
{
  mesh.modification_begin();

  const unsigned parallel_size = mesh.parallel_size();
  const unsigned parallel_rank = mesh.parallel_rank();

  double t = 0 ;
  size_t num_hex = 0 ;
  size_t num_shell = 0 ;
  size_t num_nodes = 0 ;
  size_t num_block = 0 ;
  int error_flag = 0 ;

  try {

    Iogn::GeneratedMesh gmesh( mesh_options, parallel_size, parallel_rank );

    num_nodes = gmesh.node_count_proc();
    num_block = gmesh.block_count();

    t = stk::wall_time();

    std::vector<int> node_map( num_nodes , 0 );

    gmesh.node_map( node_map );

    {

      for ( size_t i = 1 ; i <= num_block ; ++i ) {
        const size_t                        num_elem = gmesh.element_count_proc(i);
        const std::pair<std::string,int> top_info = gmesh.topology_type(i);

	std::vector<int> elem_map( num_elem , 0 );
        std::vector<int> elem_conn( num_elem * top_info.second );

	gmesh.element_map( i, elem_map );
        gmesh.connectivity( i , elem_conn );

        if ( top_info.second == 8 ) {

          for ( size_t j = 0 ; j < num_elem ; ++j ) {

            const int * const local_node_id = & elem_conn[ j * 8 ] ;

            const stk::mesh::EntityId node_id[8] = {
              local_node_id[0] ,
              local_node_id[1] ,
              local_node_id[2] ,
              local_node_id[3] ,
              local_node_id[4] ,
              local_node_id[5] ,
              local_node_id[6] ,
              local_node_id[7]
            };

            const stk::mesh::EntityId elem_id = elem_map[ j ];

            stk::mesh::fem::declare_element( mesh , hex_block , elem_id , node_id );

            ++num_hex ;
          }
        }
        else if ( top_info.second == 4 ) {

          for ( size_t j = 0 ; j < num_elem ; ++j ) {

            const int * const local_node_id = & elem_conn[ j * 4 ] ;

            const stk::mesh::EntityId node_id[4] = {
              local_node_id[0] ,
              local_node_id[1] ,
              local_node_id[2] ,
              local_node_id[3]
            };

            const stk::mesh::EntityId elem_id = elem_map[ j ];

            stk::mesh::fem::declare_element( mesh , quad_shell_block , elem_id , node_id );

            ++num_shell ;
          }
        }
      }
    }

    std::vector<double> node_coordinates( 3 * node_map.size() );

    gmesh.coordinates( node_coordinates );

    if ( 3 * node_map.size() != node_coordinates.size() ) {
      std::ostringstream msg ;
      msg << "  P" << mesh.parallel_rank()
          << ": ERROR, node_map.size() = "
          << node_map.size()
          << " , node_coordinates.size() / 3 = "
          << ( node_coordinates.size() / 3 );
      throw std::runtime_error( msg.str() );
    }

    for ( unsigned i = 0 ; i < node_map.size() ; ++i ) {
      const unsigned i3 = i * 3 ;

      stk::mesh::Entity * const node = mesh.get_entity( stk::mesh::fem::FEMMetaData::NODE_RANK , node_map[i] );

      if ( NULL == node ) {
        std::ostringstream msg ;
        msg << "  P:" << mesh.parallel_rank()
            << " ERROR, Node not found: "
            << node_map[i] << " = node_map[" << i << "]" ;
        throw std::runtime_error( msg.str() );
      }

      double * const data = field_data( node_coord , *node );
      data[0] = node_coordinates[ i3 + 0 ];
      data[1] = node_coordinates[ i3 + 1 ];
      data[2] = node_coordinates[ i3 + 2 ];
    }
  }
  catch ( const std::exception & X ) {
    std::cout << "  P:" << mesh.parallel_rank() << ": " << X.what()
              << std::endl ;
    std::cout.flush();
    error_flag = 1 ;
  }
  catch( ... ) {
    std::cout << "  P:" << mesh.parallel_rank()
              << " Caught unknown exception"
              << std::endl ;
    std::cout.flush();
    error_flag = 1 ;
  }

  stk::all_reduce( mesh.parallel() , stk::ReduceMax<1>( & error_flag ) );

  if ( error_flag ) {
    std::string msg( "Failed mesh generation" );
    throw std::runtime_error( msg );
  }

  mesh.modification_end();

  double dt = stk::wall_dtime( t );

  stk::all_reduce( mesh.parallel() , stk::ReduceMax<1>( & dt ) );

  std::cout << "  P" << mesh.parallel_rank()
            << ": Meshed Hex = " << num_hex
            << " , Shell = " << num_shell
            << " , Node = " << num_nodes
            << " in " << dt << " sec"
            << std::endl ;
  std::cout.flush();
}
void make_small_hybrid_mesh(stk::mesh::MetaData &meta, stk::mesh::BulkData &mesh,
                            bool user_attempt_no_induce = false, bool user_parts_force_no_induce = true)
{
    stk::ParallelMachine pm = MPI_COMM_WORLD;
    int p_size = stk::parallel_machine_size(pm);

    if(p_size > 2)
    {
        return;
    }

    const unsigned p_rank = mesh.parallel_rank();

    stk::mesh::Part * hexPart = &meta.get_topology_root_part(stk::topology::HEX_8);
    stk::mesh::Part * pyrPart = &meta.get_topology_root_part(stk::topology::PYRAMID_5);
    stk::mesh::Part * tetPart = &meta.get_topology_root_part(stk::topology::TET_4);

    if (user_attempt_no_induce)
    {
        hexPart = &meta.declare_part_with_topology("my_hex_part",stk::topology::HEX_8, user_parts_force_no_induce);
        pyrPart = &meta.declare_part_with_topology("my_pyr_part",stk::topology::PYRAMID_5, user_parts_force_no_induce);
        tetPart = &meta.declare_part_with_topology("my_tet_part",stk::topology::TET_4, user_parts_force_no_induce);

        EXPECT_EQ(user_parts_force_no_induce, hexPart->force_no_induce());
        EXPECT_EQ(user_parts_force_no_induce, pyrPart->force_no_induce());
        EXPECT_EQ(user_parts_force_no_induce, tetPart->force_no_induce());
    }

    meta.commit();

    const size_t numHex = 1;
    stk::mesh::EntityIdVector hexNodeIDs[] {
        { 1, 2, 3, 4, 5, 6, 7, 8 }
    };
    stk::mesh::EntityId hexElemIDs[] = { 1 };

    const size_t numPyr = 1;
    stk::mesh::EntityIdVector pyrNodeIDs[] {
        { 5, 6, 7, 8, 9 }
    };
    stk::mesh::EntityId pyrElemIDs[] = { 2 };

    const size_t numTet = 4;
    stk::mesh::EntityIdVector tetNodeIDs[] {
        { 7, 8, 9, 12 },
        { 6, 9, 10, 7 },
        { 7, 9, 10, 12 },
        { 7, 12, 10, 11 }
    };
    stk::mesh::EntityId tetElemIDs[] = { 3, 4, 5, 6 };

    // list of triplets: (owner-proc, shared-nodeID, sharing-proc)
    std::vector< std::vector<unsigned> > shared_nodeIDs_and_procs
    {
        { 0, 5, 1 },  // proc 0
        { 0, 6, 1 },
        { 0, 7, 1 },
        { 0, 8, 1 },
        { 1, 5, 0 },  // proc 1
        { 1, 6, 0 },
        { 1, 7, 0 },
        { 1, 8, 0 }
    };

    mesh.modification_begin();

    if (0 == p_rank) {
        for (size_t i = 0; i < numHex; ++i) {
          stk::mesh::declare_element(mesh, *hexPart, hexElemIDs[i], hexNodeIDs[i]);
        }
    }
    if ( (1 == p_rank) || (1 == p_size) )  { // setup the pyramids/tets for either np 2 or serial
        for (size_t i = 0; i < numPyr; ++i) {
          stk::mesh::declare_element(mesh, *pyrPart, pyrElemIDs[i], pyrNodeIDs[i]);
        }
        for (size_t i = 0; i < numTet; ++i) {
          stk::mesh::declare_element(mesh, *tetPart, tetElemIDs[i], tetNodeIDs[i]);
        }
    }

    if (p_size > 1)
    {
        for (size_t nodeIdx = 0, end = shared_nodeIDs_and_procs.size(); nodeIdx < end; ++nodeIdx) {
            if (p_rank == shared_nodeIDs_and_procs[nodeIdx][0]) {
                stk::mesh::EntityId nodeID = shared_nodeIDs_and_procs[nodeIdx][1];
                int sharingProc = shared_nodeIDs_and_procs[nodeIdx][2];
                stk::mesh::Entity node = mesh.get_entity(stk::topology::NODE_RANK, nodeID);
                mesh.add_node_sharing(node, sharingProc);
            }
        }
    }

    mesh.modification_end();
}