Ejemplo n.º 1
0
static void /* ie., parts that require opening the message file */
add_file_parts (JsonBuilder *bob, MuMsg *msg, MuMsgOptions opts)
{
	const char	*str;
	GError		*err;

	err = NULL;

	if (!mu_msg_load_msg_file (msg, &err)) {
		g_warning ("failed to load message file: %s",
			   err ? err->message : "some error occured");
		g_clear_error (&err);
		return;
	}

	add_parts (bob, msg, opts);
	add_contacts (bob, msg);

	/* add the user-agent / x-mailer */
	str = mu_msg_get_header (msg, "User-Agent");
	if (!str)
		str = mu_msg_get_header (msg, "X-Mailer");
	add_string_member (bob, "user-agent", str);
	add_body_txt_params (bob, msg, opts);
	add_string_member (bob, "body-txt", mu_msg_get_body_text(msg, opts));
	add_string_member (bob, "body-html", mu_msg_get_body_html(msg, opts));
}
Ejemplo n.º 2
0
// ========================================================================
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");
            }
        }
    }
}
Ejemplo n.º 3
0
void move_killed_elements_out_of_parts(stk::mesh::BulkData& bulkData,
                                  const stk::mesh::EntityVector& killedElements,
                                  const stk::mesh::PartVector& removeParts)
{
    std::vector<stk::mesh::PartVector> add_parts(killedElements.size());
    std::vector<stk::mesh::PartVector> rm_parts(killedElements.size());

    for (size_t j=0;j<killedElements.size();++j)
    {
        rm_parts[j] = removeParts;
    }

    bulkData.batch_change_entity_parts(killedElements, add_parts, rm_parts);
}
Ejemplo n.º 4
0
Archivo: q6.c Proyecto: eokeeffe/C-code
int main()
{
	add_parts();
	
	get_information_from_file();
	
	int loop_counter;
	
	for(loop_counter=0;loop_counter<10;loop_counter++)
	{
		printf("Part Name    : %s \r\n",list[loop_counter].part_name);
		printf("Part section : %s \r\n",list[loop_counter].part_section);
		printf("Part number  : %d \r\n",list[loop_counter].part_number);
		printf("Price        : %.2f \r\n",list[loop_counter].part_price);
		printf("part rating  : %.2lf \r\n\n",list[loop_counter].part_rating);
	}
	
	return 0;
}
Ejemplo n.º 5
0
// ========================================================================
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");
            }
        }
    }
}
Ejemplo n.º 6
0
bool use_case_7_driver(stk::ParallelMachine  comm,
                      const std::string &working_directory,
                      const std::string &domain_mesh,
                      const std::string &domain_filetype)
{
  stk::diag::Timer timer("Transfer Use Case 7",
                          use_case::TIMER_TRANSFER,
                          use_case::timer());
  stk::diag::Timer timer_node_to_node(" Node To Point", timer);
  use_case::timerSet().setEnabledTimerMask(use_case::TIMER_ALL);

  bool status = true;

  enum {           DIM = 3  };
  const double TOLERANCE = 0.000001;
  const double  rand_max = RAND_MAX;
  enum {   TONUMPOINTS = 100  };

  typedef Intrepid::FieldContainer<double>  MDArray;

  MDArray ToPoints   (  TONUMPOINTS,DIM),
          ToValues   (  TONUMPOINTS,  1);
  for (unsigned i=0 ; i<TONUMPOINTS; ++i) {
    for (unsigned j=0 ; j<DIM; ++j) {
      ToPoints(i,j) = rand()/rand_max;
    }
  }

  const stk::mesh::EntityRank node_rank = stk::topology::NODE_RANK;
  const std::string data_field_name = "Sum_Of_Coordinates";

  stk::io::StkMeshIoBroker domain_mesh_data(comm);
  const std::string filename = working_directory + domain_mesh;
  domain_mesh_data.add_mesh_database(filename, domain_filetype, stk::io::READ_MESH);
  domain_mesh_data.create_input_mesh();

  stk::mesh::MetaData &domain_meta_data = domain_mesh_data.meta_data();
  stk::mesh::Part & domain_block        = domain_meta_data.declare_part("nodes", node_rank);
  stk::mesh::CellTopology hex_top (shards::getCellTopologyData<shards::Hexahedron<> >());
  stk::mesh::CellTopology quad_top(shards::getCellTopologyData<shards::Quadrilateral<> >());
  stk::mesh::set_cell_topology( domain_block,      hex_top );
  stk::mesh::set_cell_topology( domain_block,      quad_top );
  const stk::mesh::EntityRank side_rank    = domain_meta_data.side_rank();
  stk::mesh::Part & block_skin       = domain_meta_data.declare_part("skin", side_rank);
  stk::mesh::set_cell_topology( block_skin, quad_top );

  ScalarField &domain_coord_sum_field = stk::mesh::put_field(
                        domain_meta_data.declare_field<ScalarField>(stk::topology::NODE_RANK, data_field_name),
                        domain_meta_data.universal_part() );
  domain_meta_data.commit();

  domain_mesh_data.populate_bulk_data();
  stk::mesh::BulkData &domain_bulk_data = domain_mesh_data.bulk_data();
  stk::mesh::PartVector add_parts(1,&block_skin);
  stk::mesh::skin_mesh(domain_bulk_data, add_parts);
  // For this use case, the domain consists of an axis-aligned
  // bounding box for each 'domain_entity' in the mesh.  The range is a
  // PointBoundingBox3D at the centroid of each 'range_entity'.  The id of the point
  // will be the same as the id of the containing entity.  If the
  // mesh contains solid elements only, and the range_mesh matches the
  // domain_mesh, then the search should return a single box for each
  // point and the id of the box should match the id of the point.

  CartesianField const& domain_coord_field = static_cast<CartesianField const&>(domain_mesh_data.get_coordinate_field());

  stk::mesh::Selector domain_nodes= domain_meta_data.locally_owned_part();

  std::vector<stk::mesh::Entity> domain_entities;
  {
    stk::mesh::get_selected_entities(domain_nodes, domain_bulk_data.buckets(stk::topology::NODE_RANK), domain_entities);
    const size_t num_entities = domain_entities.size();
    for (size_t i = 0; i < num_entities; ++i) {
      const stk::mesh::Entity entity = domain_entities[i];
      double *entity_coordinates = stk::mesh::field_data(domain_coord_field, entity);
      double *entity_coord_sum   = stk::mesh::field_data(domain_coord_sum_field, entity);
      *entity_coord_sum = entity_coordinates[0] + entity_coordinates[1] + entity_coordinates[2];
    }
  }

  const double radius=.25;
  const std::vector<stk::mesh::FieldBase*> from_fields(1, &domain_coord_sum_field);
  boost::shared_ptr<stk::transfer::STKNode >
    transfer_domain_mesh (new stk::transfer::STKNode(domain_entities, domain_coord_field, from_fields, radius));
  boost::shared_ptr<stk::transfer:: MDMesh >
    transfer_range_mesh  (new stk::transfer:: MDMesh(ToValues, ToPoints,   radius, comm));


  stk::transfer::GeometricTransfer<
    class stk::transfer::LinearInterpolate<
      class stk::transfer::STKNode,
      class stk::transfer::MDMesh
    >
  >
  transfer(transfer_domain_mesh, transfer_range_mesh, "STK Transfer test Use case 7");

  {
    stk::diag::TimeBlock __timer_node_to_node(timer_node_to_node);
    try {
      transfer.initialize();
      transfer.apply();
    } catch (std::exception &e) {
      std::cout <<__FILE__<<":"<<__LINE__
                <<" Caught an std::exception with what string:"
                <<e.what()
                <<"      rethrowing....."
                <<std::endl;
      status = status && false;
    } catch (...) {
      std::cout <<__FILE__<<":"<<__LINE__
                <<" Caught an exception, rethrowing..."
                <<std::endl;
      status = status && false;
    }
  }

  if (status) {

    bool success = true;
    for (unsigned i=0 ; i<TONUMPOINTS; ++i) {
      double check_l = 0;
      for (unsigned j=0 ; j<DIM; ++j) check_l += ToPoints(i,j);
      if (TOLERANCE < fabs(check_l-ToValues(i,0))) {
        std::cout <<__FILE__<<":"<<__LINE__
                  <<" EntityKey:"<<i
                  <<" ToPoints:"<<ToPoints(i,0)<<" "<<ToPoints(i,1)<<" "<<ToPoints(i,2)
                  <<" ToValues:"<<ToValues(i,0)
                  <<" check:"<<check_l
                  <<" error:"<<fabs(check_l-ToValues(i,0))
                  <<std::endl;
        success = false;
      }
    }
    status = status && success;
  }
  timer.stop();
//stk::diag::printTimersTable(std::cout, timer,
//      stk::diag::METRICS_CPU_TIME | stk::diag::METRICS_WALL_TIME, false, comm);


  const bool collective_result = use_case::print_status(comm, status);
  return collective_result;
}
Ejemplo n.º 7
0
STKUNIT_UNIT_TEST(nodeRegistry, test_parallel_1_0)
{
  EXCEPTWATCH;
  MPI_Barrier( MPI_COMM_WORLD );

  // start_demo_nodeRegistry_test_parallel_1

  percept::PerceptMesh eMesh(3u);

  unsigned p_size = eMesh.get_parallel_size();
  unsigned p_rank = eMesh.get_rank();
  Util::setRank(eMesh.get_rank());

  eMesh.new_mesh(percept::GMeshSpec(std::string("1x1x")+toString(p_size)+std::string("|bbox:0,0,0,1,1,1")));

  // prepare for adding some quadratic elements
  mesh::Part& block_hex_20 = eMesh.get_fem_meta_data()->declare_part("block_hex_20", eMesh.element_rank());
  /// set cell topology for the part block_hex_20
  mesh::fem::set_cell_topology< shards::Hexahedron<20>  >( block_hex_20 );
  stk_classic::io::put_io_part_attribute(block_hex_20);

  eMesh.commit();
  eMesh.print_info();
  eMesh.save_as("./cube1x1x2_hex-20-orig.e");

  mesh::Part* block_hex_8 = const_cast<mesh::Part *>(eMesh.getPart("block_1"));

  NodeRegistry nodeRegistry(eMesh);
  nodeRegistry.initialize();

  if (p_size <= 2)
  {
    // pick an element on the processor boundary
    unsigned elem_num_local = 1;
    unsigned elem_num_ghost = 2;
    if (p_size == 1)
      elem_num_ghost = 1;

    stk_classic::mesh::Entity* element_local_p = eMesh.get_bulk_data()->get_entity(eMesh.element_rank(), elem_num_local);
    stk_classic::mesh::Entity* element_ghost_p = eMesh.get_bulk_data()->get_entity(eMesh.element_rank(), elem_num_ghost);
    if (p_rank == 1)
    {
      element_local_p = eMesh.get_bulk_data()->get_entity(eMesh.element_rank(), elem_num_ghost);
      element_ghost_p = eMesh.get_bulk_data()->get_entity(eMesh.element_rank(), elem_num_local);
    }

    dw() << "P["<<p_rank<<"] elem_num_local = " << elem_num_local << DWENDL;
    dw() << "P["<<p_rank<<"] elem_num_ghost = " << elem_num_ghost << DWENDL;

    stk_classic::mesh::Entity& element_local = *element_local_p;
    stk_classic::mesh::Entity& element_ghost = *element_ghost_p;

    std::cout << "P["<<p_rank<<"] element_local = " << element_local << std::endl;
    std::cout << "P["<<p_rank<<"] element_ghost = " << element_ghost << std::endl;

    // choose edges to be used for new node locations (i.e., this would model a serendipity-like element with only edge Lagrange nodes)
    stk_classic::mesh::EntityRank stk_mesh_Edge = 1;
    NeededEntityType needed_entity_rank( stk_mesh_Edge, 1u);
    std::vector<NeededEntityType> needed_entity_ranks(1, needed_entity_rank);

    /*
     * 1st of three steps to create and associate new nodes - register need for new nodes, then check if node is remote, then get
     *   from remote proc if necessary; finally, the local node database is ready to be queried
     *
     * The pattern is to begin the step, loop over all elements (including ghosts) and invoke the local operation
     * The method doForAllSubEntities is a utility for performing the operation on all the sub entities.
     * If more granularity is desired, the member functions can be invoked directly for a particular sub-entity.
     */
    nodeRegistry.beginRegistration();
    nodeRegistry.doForAllSubEntities(&NodeRegistry::registerNeedNewNode, element_local, needed_entity_ranks);
    nodeRegistry.doForAllSubEntities(&NodeRegistry::registerNeedNewNode, element_ghost, needed_entity_ranks);
    nodeRegistry.endRegistration();

    std::cout << "P["<<p_rank<<"] nodeRegistry size  = " << nodeRegistry.total_size() << std::endl;
    std::cout << "P["<<p_rank<<"] nodeRegistry lsize = " << nodeRegistry.local_size() << std::endl;

    dw() << "P["<<p_rank<<"] nodeRegistry size       = " << nodeRegistry.total_size() << DWENDL;
    dw() << "P["<<p_rank<<"] nodeRegistry lsize      = " << nodeRegistry.local_size() << DWENDL;

    // could do local create of elements here
    nodeRegistry.beginLocalMeshMods();
    nodeRegistry.endLocalMeshMods();

    // check if the newly requested nodes are local or remote
    nodeRegistry.beginCheckForRemote();
    nodeRegistry.doForAllSubEntities(&NodeRegistry::checkForRemote, element_local, needed_entity_ranks);
    nodeRegistry.doForAllSubEntities(&NodeRegistry::checkForRemote, element_ghost, needed_entity_ranks);
    nodeRegistry.endCheckForRemote();

    // get the new nodes from other procs if they are nonlocal
    nodeRegistry.beginGetFromRemote();
    nodeRegistry.doForAllSubEntities(&NodeRegistry::getFromRemote, element_local, needed_entity_ranks);
    nodeRegistry.doForAllSubEntities(&NodeRegistry::getFromRemote, element_ghost, needed_entity_ranks);
    nodeRegistry.endGetFromRemote();

    // now we can get the new node's id and entity
    unsigned iSubDimOrd = 4u;
    if (p_rank)
    {
      iSubDimOrd = 0u;
    }
    NodeIdsOnSubDimEntityType& nodeIds_onSE_0 = *( nodeRegistry.getNewNodesOnSubDimEntity(element_local, needed_entity_rank.first, iSubDimOrd));
    stk_classic::mesh::Entity*  node_0   = eMesh.get_bulk_data()->get_entity(stk_classic::mesh::fem::FEMMetaData::NODE_RANK, nodeIds_onSE_0[0]->identifier());

    // should be the same node on each proc
    std::cout << "P[" << p_rank << "] nodeId_0 = " << nodeIds_onSE_0 << " node_0= " << node_0 << std::endl;

    // end_demo

#if STK_ADAPT_HAVE_YAML_CPP
    if (p_size == 1)
      {
        if (1) {
          YAML::Emitter out;
          out << YAML::Anchor("NodeRegistry::map");
          out << YAML::BeginMap;
          out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq << YAML::Value << YAML::BeginSeq << -1 << -2 << YAML::EndSeq;
          out << YAML::Key << 1;
          out << YAML::Value << 2;
          out << YAML::Key << 3;
          out << YAML::Value << 4;
          out << YAML::EndMap;
          //std::cout << "out=\n" << out.c_str() << "\n=out" << std::endl;
          std::string expected_result = "&NodeRegistry::map\n?\n  - 1\n  - 2\n:\n  - -1\n  - -2\n1: 2\n3: 4";
          //std::cout << "out2=\n" << expected_result << std::endl;
          STKUNIT_EXPECT_TRUE(expected_result == std::string(out.c_str()));
        }

        YAML::Emitter yaml;
        std::cout << "\nnodeRegistry.serialize_write(yaml)" << std::endl;
        SerializeNodeRegistry::serialize_write(nodeRegistry, yaml, 0);
        //std::cout << yaml.c_str() << std::endl;
        if (!yaml.good())
          {
            std::cout << "Emitter error: " << yaml.good() << " " <<yaml.GetLastError() << "\n";
            STKUNIT_EXPECT_TRUE(false);
          }
        std::ofstream file1("out.yaml");
        file1 << yaml.c_str();
        file1.close();
        std::ifstream file2("out.yaml");
        YAML::Parser parser(file2);
        YAML::Node doc;

        try {
          while(parser.GetNextDocument(doc)) {
            std::cout << "\n read doc.Type() = " << doc.Type() << " doc.Tag()= " << doc.Tag() << " doc.size= " << doc.size() << std::endl;
            if (doc.Type() == YAML::NodeType::Map)
              {
                for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
                  int key, value;
                  std::cout << "read it.first().Type() = " << it.first().Type() << " it.first().Tag()= " << it.first().Tag() << std::endl;
                  std::cout << "read it.second().Type() = " << it.second().Type() << " it.second().Tag()= " << it.second().Tag() << std::endl;
                  const YAML::Node& keySeq = it.first();
                  for(YAML::Iterator itk=keySeq.begin();itk!=keySeq.end();++itk) {
                    *itk >> key;
                    std::cout << "read key= " << key << std::endl;
                  }
              
                  const YAML::Node& valSeq = it.second();
                  for(YAML::Iterator itv=valSeq.begin();itv!=valSeq.end();++itv) {
                    *itv >> value;
                    std::cout << "read value= " << value << std::endl;
                  }
              
                }
              }
          }
        }
        catch(YAML::ParserException& e) {
          std::cout << e.what() << "\n";
          STKUNIT_EXPECT_TRUE(false);
        }

        file2.close();
        std::ifstream file3("out.yaml");
        NodeRegistry nrNew(eMesh);
        SerializeNodeRegistry::serialize_read(nrNew, file3);
        YAML::Emitter yaml3;
        std::cout << "\nnrNew.serialize_write(yaml3)" << std::endl;
        SerializeNodeRegistry::serialize_write(nrNew, yaml3, 0);
        std::cout << yaml3.c_str() << std::endl;
        
        //exit(1);
      }
#endif
    // start_demo_nodeRegistry_test_parallel_1_quadratic_elem

    // change element to be a serendipity quadratic element
    eMesh.get_bulk_data()->modification_begin();

    //getCellTopologyData< shards::Node  >()
    const CellTopologyData *const cell_topo_data =stk_classic::percept::PerceptMesh::get_cell_topology(block_hex_20);
    CellTopology cell_topo(cell_topo_data);

    for (unsigned isd = 0; isd < 12; isd++)
    {
      nodeRegistry.makeCentroidCoords(element_local, needed_entity_rank.first, isd);
      NodeIdsOnSubDimEntityType& nodeIds_onSE_0_loc = *( nodeRegistry.getNewNodesOnSubDimEntity(element_local, needed_entity_rank.first, isd));

      stk_classic::mesh::Entity*  node   = eMesh.get_bulk_data()->get_entity(stk_classic::mesh::fem::FEMMetaData::NODE_RANK, nodeIds_onSE_0_loc[0]->identifier());

      unsigned edge_ord = 8u + isd;
      //unsigned n_edge_ord = cell_topo_data->edge[isd].topology->node_count;
      //std::cout << "n_edge_ord = " << n_edge_ord << std::endl;
      edge_ord = cell_topo_data->edge[isd].node[2];
      eMesh.get_bulk_data()->declare_relation(element_local, *node, edge_ord);
    }

    std::vector<stk_classic::mesh::Part*> add_parts(1, &block_hex_20);
    std::vector<stk_classic::mesh::Part*> remove_parts(1, block_hex_8);
    eMesh.get_bulk_data()->change_entity_parts( element_local, add_parts, remove_parts );

    eMesh.get_bulk_data()->modification_end();
    eMesh.print_info("After quadratic");

    eMesh.save_as("./cube1x1x2_hex-20.e");
    //exit(1);
  }
Ejemplo n.º 8
0
TEST( skinning_large_cube, skinning_large_cube)
{
  stk::ParallelMachine pm = MPI_COMM_WORLD;

  const size_t p_size = stk::parallel_machine_size(pm);
  const size_t p_rank = stk::parallel_machine_rank(pm);

  // Every processor will be involved in detachment and skin-update up to 500 processors.
  // This puts 5000 elements on each process unless we are running with STL
  // in debug mode in which case we shrink the problem down in order
  // to keep things running in a reasonable amount of time.
#ifdef _GLIBCXX_DEBUG
  const size_t NX = p_size*10, NY = 4, NZ = 5;
#else
  const size_t NX = p_size*100, NY = 100, NZ = 100;
#endif

  static const int TIMER_COUNT = 6;
  /* timings[0] = create mesh
   * timings[1] = intial skin mesh
   * timings[2] = detach mesh
   * timings[3] = delete skin
   * timings[4] = reskin mesh
   * timings[5] = sum(timings[0:4])
   */
  double timings[TIMER_COUNT] = {0};
  double timing_sums[TIMER_COUNT] = {0};
  const char* timer_names[TIMER_COUNT] = {"Create mesh", "Initial skin", "Detach mesh", "Delete skin", "Reskin", "Total time"};
  double start_time = 0;
  size_t memory_max[2] = {0};
  const char* memory_names[2] = {"Current memory", "Memory high water"};

  //recreate skin
  for ( int test_run = 0; test_run < 4; ++test_run) {
    //create the mesh

    start_time = stk::wall_time();
    stk::mesh::fixtures::HexFixture fixture(pm,NX,NY,NZ);
    const EntityRank element_rank = stk::topology::ELEMENT_RANK;
    const EntityRank side_rank = fixture.m_meta.side_rank();

    stk::mesh::MetaData & fem_meta = fixture.m_meta;
    stk::mesh::BulkData & mesh = fixture.m_bulk_data;

    stk::mesh::Part & skin_part = fem_meta.declare_part("skin_part");
    fem_meta.commit();

    fixture.generate_mesh();
    timings[0] = stk::wall_dtime(start_time);

    //intial skin of the mesh
    start_time = stk::wall_time();
    {
      stk::mesh::PartVector add_parts(1,&skin_part);
      stk::mesh::skin_mesh(mesh, add_parts);
    }
    timings[1] = stk::wall_dtime(start_time);

    stk::mesh::EntityVector entities_to_separate;

    if ( test_run < 2) {
      //detach 1/3 of the mesh
      size_t num_detached_this_proc = 0;
      for (size_t ix=NX/3; ix < 2*NX/3; ++ix) {
      for (size_t iy=0; iy < NY; ++iy) {
      for (size_t iz=0; iz < NZ; ++iz) {
        stk::mesh::Entity element = fixture.elem(ix,iy,iz);
        if (mesh.is_valid(element) && mesh.parallel_owner_rank(element) == mesh.parallel_rank()) {
          entities_to_separate.push_back(element);
          num_detached_this_proc++;
        }
      }
      }
      }
      EXPECT_TRUE( num_detached_this_proc > 0u );
    } else {
      //detach middle of the mesh
      for (size_t ix=NX/2; ix < NX/2+1; ++ix) {
      for (size_t iy=NY/2; iy < NY/2+1; ++iy) {
      for (size_t iz=NZ/2; iz < NZ/2+1; ++iz) {
        stk::mesh::Entity element = fixture.elem(ix,iy,iz);
        if (mesh.is_valid(element) && mesh.parallel_owner_rank(element) == mesh.parallel_rank()) {
          entities_to_separate.push_back(element);
        }
      }
      }
      }
    }

    start_time = stk::wall_time();
    separate_and_skin_mesh(
        fem_meta,
        mesh,
        skin_part,
        entities_to_separate
        );
    timings[2] = stk::wall_dtime(start_time);

    if (test_run%2 == 0) { // delete the skin
      start_time = stk::wall_time();
      delete_skin( mesh, skin_part, side_rank );
      timings[3] = stk::wall_dtime(start_time);

      //reskin the entire mesh
      start_time = stk::wall_time();
      {
        stk::mesh::PartVector add_parts(1,&skin_part);
        stk::mesh::skin_mesh( mesh, add_parts);
      }
      timings[4] = stk::wall_dtime(start_time);
    }
    else { //update the skin
      timings[3] = 0;

      //update the skin of the mesh
      start_time = stk::wall_time();
      update_skin( mesh, &skin_part, element_rank);
      timings[4] = stk::wall_dtime(start_time);
    }

    //total the timings
    timings[5] = 0;
    for (int i=0; i <5; ++i) {
      timings[5] += timings[i];
    }

    size_t mem_now = 0, mem_hwm = 0;
    stk::get_memory_usage(mem_now, mem_hwm);

    stk::all_reduce(pm, stk::ReduceMax<5>(timings));
    stk::all_reduce(pm, stk::ReduceMax<1>(&mem_now));
    stk::all_reduce(pm, stk::ReduceMax<1>(&mem_hwm));

    if (mem_now > memory_max[0]) {
      memory_max[0] = mem_now;
    }
    if (mem_hwm > memory_max[1]) {
      memory_max[1] = mem_hwm;
    }

    //compute sums
    for (int i=0; i<TIMER_COUNT; ++i) {
      timing_sums[i] += timings[i];
    }

    if (p_rank == 0) {
      std::cout << "\n\n";
      switch (test_run) {
        case 0:
          std::cout << "Recreate entire skin after detaching 1/3 of the mesh:\n";
          break;
        case 1:
          std::cout << "Update skin after detaching 1/3 of the mesh:\n";
          break;
        case 2:
          std::cout << "Recreate entire skin after detaching middle of the mesh:\n";
          break;
        case 3:
          std::cout << "Update skin after detaching middle of the mesh:\n";
          break;
      }

      std::cout << "Num procs: " << p_size << "\n";
      std::cout << "Mesh size: " << NX << 'x' << NY << 'x' << NZ << " = " << NX*NY*NZ << " elements\n";
      std::cout << "Total time: "     << timings[5] << "\n";
      std::cout << "\tCreate mesh: "  << timings[0] << "\n";
      std::cout << "\tInitial skin: " << timings[1] << "\n";
      std::cout << "\tDetach mesh: "  << timings[2] << "\n";
      std::cout << "\tDelete skin: "  << timings[3] << "\n";
      std::cout << "\tReskin:      "  << timings[4] << "\n";
      std::cout << "\n\n";
    }

    size_t num_skin_entities = count_skin_entities(mesh, skin_part, side_rank );

    stk::all_reduce(pm, stk::ReduceSum<1>(&num_skin_entities));

    size_t expected_num_skin = 0;

    if ( test_run < 2) {
      expected_num_skin = 2*(NX*NY + NX*NZ + 3*NY*NZ);
    } else {
      expected_num_skin = 2*(NX*NY + NX*NZ + NY*NZ) + 12;
    }

    EXPECT_EQ( num_skin_entities, expected_num_skin );
  }

  if (p_rank == 0) {
    stk::print_timers_and_memory(&timer_names[0], &timing_sums[0], TIMER_COUNT, &memory_names[0], &memory_max[0], 2);
  }

  stk::parallel_print_time_without_output_and_hwm(pm, timings[5]);
}