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; }
STKUNIT_UNIT_TEST(UnitTestZoltanSimple, testUnit) { #ifdef STK_HAS_MPI stk::ParallelMachine comm(MPI_COMM_WORLD); #else stk::ParallelMachine comm(0); #endif unsigned spatial_dimension = 2; std::vector<std::string> rank_names = stk::mesh::fem::entity_rank_names(spatial_dimension); const stk::mesh::EntityRank constraint_rank = rank_names.size(); rank_names.push_back("Constraint"); stk::mesh::fem::FEMMetaData fem_meta; fem_meta.FEM_initialize( spatial_dimension, rank_names ); stk::mesh::MetaData & meta_data = stk::mesh::fem::FEMMetaData::get_meta_data(fem_meta); stk::mesh::BulkData bulk_data( meta_data , comm , 100 ); const stk::mesh::EntityRank element_rank = fem_meta.element_rank(); stk::mesh::fem::CellTopology quad_top(shards::getCellTopologyData<shards::Quadrilateral<4> >()); stk::mesh::Part & quad_part( fem_meta.declare_part("quad", quad_top ) ); VectorField & coord_field( fem_meta.declare_field< VectorField >( "coordinates" ) ); ScalarField & weight_field( fem_meta.declare_field< ScalarField >( "element_weights" ) ); stk::mesh::put_field( coord_field , NODE_RANK , fem_meta.universal_part() ); stk::mesh::put_field(weight_field , element_rank , fem_meta.universal_part() ); fem_meta.commit(); const unsigned p_size = bulk_data.parallel_size(); const unsigned p_rank = bulk_data.parallel_rank(); bulk_data.modification_begin(); if ( p_rank == 0 ) { std::vector<std::vector<stk::mesh::Entity*> > quads(nx); for ( unsigned ix = 0 ; ix < nx ; ++ix ) quads[ix].resize(ny); const unsigned nnx = nx + 1 ; const unsigned nny = ny + 1 ; for ( unsigned iy = 0 ; iy < ny ; ++iy ) { for ( unsigned ix = 0 ; ix < nx ; ++ix ) { stk::mesh::EntityId elem = 1 + ix + iy * nx ; stk::mesh::EntityId nodes[4] ; nodes[0] = 1 + ix + iy * nnx ; nodes[1] = 2 + ix + iy * nnx ; nodes[2] = 2 + ix + ( iy + 1 ) * nnx ; nodes[3] = 1 + ix + ( iy + 1 ) * nnx ; stk::mesh::Entity &q = stk::mesh::fem::declare_element( bulk_data , quad_part , elem , nodes ); quads[ix][iy] = &q; } } for ( unsigned iy = 0 ; iy < ny ; ++iy ) { for ( unsigned ix = 0 ; ix < nx ; ++ix ) { stk::mesh::EntityId elem = 1 + ix + iy * nx ; stk::mesh::Entity * e = bulk_data.get_entity( element_rank, elem ); double * const e_weight = stk::mesh::field_data( weight_field , *e ); *e_weight = 1.0; } } for ( unsigned iy = 0 ; iy <= ny ; ++iy ) { for ( unsigned ix = 0 ; ix <= nx ; ++ix ) { stk::mesh::EntityId nid = 1 + ix + iy * nnx ; stk::mesh::Entity * n = bulk_data.get_entity( NODE_RANK, nid ); double * const coord = stk::mesh::field_data( coord_field , *n ); coord[0] = .1*ix; coord[1] = .1*iy; coord[2] = 0; } } { const unsigned iy_left = 0; const unsigned iy_right = ny; stk::mesh::PartVector add(1, &fem_meta.locally_owned_part()); for ( unsigned ix = 0 ; ix <= nx ; ++ix ) { stk::mesh::EntityId nid_left = 1 + ix + iy_left * nnx ; stk::mesh::EntityId nid_right = 1 + ix + iy_right * nnx ; stk::mesh::Entity * n_left = bulk_data.get_entity( NODE_RANK, nid_left ); stk::mesh::Entity * n_right = bulk_data.get_entity( NODE_RANK, nid_right ); const stk::mesh::EntityId constraint_entity_id = 1 + ix + nny * nnx; stk::mesh::Entity & c = bulk_data.declare_entity( constraint_rank, constraint_entity_id, add ); bulk_data.declare_relation( c , *n_left , 0 ); bulk_data.declare_relation( c , *n_right , 1 ); } } } // Only P0 has any nodes or elements if ( p_rank == 0 ) { STKUNIT_ASSERT( ! bulk_data.buckets( NODE_RANK ).empty() ); STKUNIT_ASSERT( ! bulk_data.buckets( element_rank ).empty() ); } else { STKUNIT_ASSERT( bulk_data.buckets( NODE_RANK ).empty() ); STKUNIT_ASSERT( bulk_data.buckets( element_rank ).empty() ); } bulk_data.modification_end(); // create some sides and faces to rebalance. stk::mesh::PartVector add_parts; stk::mesh::create_adjacent_entities(bulk_data, add_parts); // Zoltan partition is specialized fomm a virtual base class, stk::rebalance::Partition. // Other specializations are possible. Teuchos::ParameterList emptyList; stk::rebalance::Zoltan zoltan_partition(comm, spatial_dimension, emptyList); { stk::mesh::Selector selector(fem_meta.universal_part()); stk::rebalance::rebalance(bulk_data, selector, &coord_field, &weight_field, zoltan_partition); } const double imbalance_threshold = stk::rebalance::check_balance(bulk_data, &weight_field, element_rank); const bool do_rebal = 1.5 < imbalance_threshold; // Check that we satisfy our threshhold STKUNIT_ASSERT( !do_rebal ); if( (2 == p_size) || (4 == p_size) ) { STKUNIT_ASSERT_NEAR(imbalance_threshold, 1.0, 1.e-8); } else { STKUNIT_ASSERT_LE(imbalance_threshold, 1.5); } // And verify that all dependent entities are on the same proc as their parent element { stk::mesh::EntityVector entities; stk::mesh::Selector selector = fem_meta.locally_owned_part(); get_selected_entities(selector, bulk_data.buckets(NODE_RANK), entities); bool result = stk::rebalance::verify_dependent_ownership(element_rank, entities); //get_selected_entities(selector, bulk_data.buckets(constraint_rank), entities); //result &= stk::rebalance::verify_dependent_ownership(element_rank, entities); STKUNIT_ASSERT( result ); } }