STKUNIT_UNIT_TEST(function, stringFunction_vector_valued) { EXCEPTWATCH; double x = 1.234; double y = 5.678; double z = 3.456; double t = 0; bool didCatch = false; try { StringFunction sfv0("v[0]=x; v[1]=y; v[2]=z; x", Name("sfv"), Dimensions(1,4), Dimensions(1,3) ); eval_vec3_print(1,2,3,0, sfv0); } catch (...) { didCatch = true; std::cout << "TEST::function::stringFunctionVector: expected to catch this since dom/codomain dimensions should be rank-1" << std::endl; } STKUNIT_EXPECT_TRUE(didCatch); StringFunction sfv("v[0]=x*y*z; v[1]=y; v[2]=z; x", Name("sfv"), Dimensions(3), Dimensions(3) ); eval_vec3_print(1.234, 2.345e-3, 3.456e+5, 0., sfv); MDArray vec = eval_vec3(x, y, z, t, sfv); std::cout << " x = " << x << " y = " << y << " z = " << z << " val = " << (vec[0]*vec[1]*vec[2]) << std::endl; STKUNIT_EXPECT_DOUBLE_EQ(vec[0], x*y*z); STKUNIT_EXPECT_DOUBLE_EQ(vec[1], y); STKUNIT_EXPECT_DOUBLE_EQ(vec[2], z); }
void UnitTestSupport::save_or_diff(PerceptMesh& eMesh, std::string filename, int option ) { if (always_do_regression_tests || option == 1) { unsigned p_size = eMesh.get_parallel_size(); unsigned p_rank = eMesh.get_parallel_rank(); std::string par_filename = filename; if (p_size > 1) { par_filename = filename+"."+toString(p_size)+"."+toString(p_rank); } if (Util::file_exists(par_filename)) { int spatialDim = eMesh.get_spatial_dim(); PerceptMesh eMesh1(spatialDim); eMesh.save_as("./tmp.e"); eMesh1.open_read_only("./tmp.e"); PerceptMesh eMesh_gold(spatialDim); eMesh_gold.open_read_only(filename); //eMesh_gold.print_info("gold copy: "+filename, 2); //eMesh1.print_info("compare to: "+filename, 2); { std::string diff_msg = "gold file diff report: "+filename+" \n"; bool print_during_diff = false; bool diff = PerceptMesh::mesh_difference(eMesh1, eMesh_gold, diff_msg, print_during_diff); if (diff) { //std::cout << "tmp writing and reading to cleanup parts" << std::endl; // write out and read back in to cleanup old parts eMesh1.save_as("./tmp.e"); PerceptMesh eMesh2(spatialDim); eMesh2.open_read_only("./tmp.e"); //std::cout << "tmp done writing and reading to cleanup parts" << std::endl; bool diff_2 = PerceptMesh::mesh_difference(eMesh2, eMesh_gold, diff_msg, print_during_diff); //std::cout << "tmp diff_2= " << diff_2 << std::endl; diff = diff_2; if (diff_2) { //bool diff_3 = PerceptMesh::mesh_difference(eMesh2, eMesh_gold, diff_msg, true); } } STKUNIT_EXPECT_TRUE(!diff); } } else { eMesh.save_as(filename); } } else { eMesh.save_as(filename); } }
void UnitTestSTKParallelDistributedIndex::test_ctor() { typedef stk::parallel::DistributedIndex PDIndex ; stk::ParallelMachine comm = MPI_COMM_WORLD ; int mpi_rank = stk::parallel_machine_rank(comm); int mpi_size = stk::parallel_machine_size(comm); std::vector< PDIndex::KeySpan > partition_spans ; generate_test_spans_10x10000( partition_spans ); PDIndex di( comm , partition_spans ); STKUNIT_EXPECT_EQ( di.m_comm_rank , mpi_rank ); STKUNIT_EXPECT_EQ( di.m_comm_size , mpi_size ); STKUNIT_EXPECT_TRUE( di.m_key_usage.empty() ); STKUNIT_ASSERT_EQ( di.m_key_span.size() , partition_spans.size() ); for ( size_t i = 0 ; i < di.m_key_span.size() ; ++i ) { STKUNIT_EXPECT_EQ( di.m_key_span[i].first , partition_spans[i].first ); STKUNIT_EXPECT_EQ( di.m_key_span[i].second , partition_spans[i].second ); } // All queries will be empty: std::vector<PDIndex::KeyType> keys_to_query ; std::vector<PDIndex::KeyProc> sharing_of_local_keys ; di.query( sharing_of_local_keys ); STKUNIT_EXPECT_TRUE( sharing_of_local_keys.empty() ); di.query( keys_to_query , sharing_of_local_keys ); STKUNIT_EXPECT_TRUE( sharing_of_local_keys.empty() ); keys_to_query.push_back( 10 ); di.query( keys_to_query , sharing_of_local_keys ); STKUNIT_EXPECT_TRUE( sharing_of_local_keys.empty() ); }
void force_calculation( long long sum ) { static int count = 0; //volatile to prevent the compiler from optimizing the loops away static volatile long long value; if( count && value != sum ) { STKUNIT_EXPECT_TRUE(false); } value = sum; ++count; }
//============================================================================= //============================================================================= //============================================================================= STKUNIT_UNIT_TEST(unit_tests_percept, noMallocArray) { NoMallocArray<unsigned, 4u> nma; STKUNIT_EXPECT_TRUE(nma.max_size() == 4u); STKUNIT_EXPECT_TRUE(nma.size() == 0u); STKUNIT_EXPECT_TRUE(nma.max_size() == nma.max_capacity()); bool got_it = false; try { NoMallocArray<unsigned, 4> nma1(5, 0u); } catch (std::runtime_error& e) { got_it = true; } if (!got_it) { STKUNIT_EXPECT_TRUE(false); } NoMallocArray<unsigned, 4> nma2(4u, 0u); std::cout << "nma.size()= " << nma2.size() << std::endl; STKUNIT_EXPECT_TRUE(nma2.size() == 4u); nma2.resize(0u); STKUNIT_EXPECT_TRUE(nma2.size() == 0u); nma2.insert(0u); nma2.insert(1u); nma2.insert(2u); nma2.insert(3u); STKUNIT_EXPECT_TRUE(nma2.size() == 4u); STKUNIT_EXPECT_TRUE(nma2[1] == 1); STKUNIT_EXPECT_TRUE(*nma2.begin() == 0); STKUNIT_EXPECT_TRUE(*(nma2.end()-1) == 3); }
STKUNIT_UNIT_TEST( UnitTestDeclareElement , inject_shell ) { // This tests creates a small HexFixture with two hexes then, in a separate // modification cycle, inserts a shell between the two elements. stk::ParallelMachine pm = MPI_COMM_WORLD ; // Create the fixture, adding a part for the shell stk::mesh::fixtures::HexFixture fixture( pm , 2 , 1 , 1 ); const unsigned p_rank = fixture.m_bulk_data.parallel_rank(); stk::mesh::Part & shell_part = stk::mesh::fem::declare_part<shards::ShellQuadrilateral<4> >( fixture.m_fem_meta, "shell_part"); fixture.m_fem_meta.commit(); fixture.generate_mesh(); stk::mesh::Entity * elem = fixture.elem( 0 , 0 , 0 ); fixture.m_bulk_data.modification_begin(); bool no_throw = true; // Whoever owns the 0,0,0 element create the shell and insert it between // the two elements. if ( elem != NULL && p_rank == elem->owner_rank() ) { stk::mesh::EntityId elem_node[4] ; elem_node[0] = fixture.node_id( 1, 0, 0 ); elem_node[1] = fixture.node_id( 1, 1, 0 ); elem_node[2] = fixture.node_id( 1, 1, 1 ); elem_node[3] = fixture.node_id( 1, 0, 1 ); stk::mesh::EntityId elem_id = 3; try { stk::mesh::fem::declare_element( fixture.m_bulk_data, shell_part, elem_id, elem_node); } catch (...) { no_throw = false; } } fixture.m_bulk_data.modification_end(); STKUNIT_EXPECT_TRUE(no_throw); }
STKUNIT_UNIT_TEST( PerformanceTestSelector, timings) { // Construction // If we are running with STL in debug mode we shrink the problem // down in order to keep things running in a reasonable amount of // time. #ifdef _GLIBCXX_DEBUG size_t N = 1000; #else size_t N = 10000; #endif VariableSelectorFixture fix(N); std::vector<double> selector_creation(N/2); std::vector<double> get_buckets_usage(N/2); double start_time = stk::wall_time(); size_t timing_index = 0; for (size_t n = 1 ; n<N; n*=2) { // Selector creation stk::mesh::Selector selectUnion; for (size_t part_i = 0 ; part_i<n ; ++part_i) { selectUnion |= *fix.m_declared_part_vector[part_i]; } selector_creation[timing_index] = stk::wall_dtime(start_time); // Selector usage: std::vector<stk::mesh::Bucket*> buckets_out; unsigned entity_rank = 0; get_buckets(selectUnion, fix.m_BulkData.buckets(entity_rank), buckets_out); get_buckets_usage[timing_index] = stk::wall_dtime(start_time); ++timing_index; } // Print out table std::cout << "\"N\" \"selector_creation_time\" \"get_buckets_time\" " << std::endl; timing_index = 0; for (size_t n = 1 ; n<N; n*=2) { std::cout << n << " " << selector_creation[timing_index] << " " << get_buckets_usage[timing_index] << std::endl; ++timing_index; } STKUNIT_EXPECT_TRUE(true); }
STKUNIT_UNIT_TEST( PerformanceTestSkinning, 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*10, NY = 20, NZ = 25; #endif /* 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[6] = {0}; double start_time = 0; //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 = fixture.m_fem_meta.element_rank(); const EntityRank side_rank = fixture.m_fem_meta.side_rank(); stk::mesh::fem::FEMMetaData & fem_meta = fixture.m_fem_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::skin_mesh(mesh, element_rank, &skin_part); 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 (element != NULL && element->owner_rank() == mesh.parallel_rank()) { entities_to_separate.push_back(element); num_detached_this_proc++; } } } } STKUNIT_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 (element != NULL && element->owner_rank() == 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::skin_mesh( mesh, element_rank, &skin_part); 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]; } stk::all_reduce(pm, stk::ReduceMax<5>(timings)); 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; 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; } STKUNIT_EXPECT_EQUAL( num_skin_entities, expected_num_skin ); } }
/// This test uses a back door to the function that passes in the element to avoid the lookup of the element when the /// StringFunction contains references to FieldFunctions void TEST_norm_string_function_turbo_verify_correctness(TurboOption turboOpt) { EXCEPTWATCH; //stk::diag::WriterThrowSafe _write_throw_safe(dw()); //dw().setPrintMask(dw_option_mask.parse(vm["dw"].as<std::string>().c_str())); //dw().setPrintMask(LOG_NORM+LOG_ALWAYS); dw().m(LOG_NORM) << "TEST.norm.string_function " << stk::diag::dendl; LocalFixture fix(4); mesh::fem::FEMMetaData& metaData = fix.metaData; mesh::BulkData& bulkData = fix.bulkData; PerceptMesh& eMesh = fix.eMesh; mesh::FieldBase* coords_field = fix.coords_field; StringFunction sfx = fix.sfx; ConstantFunction sfx_res = fix.sfx_res; /// create a field function from the existing coordinates field FieldFunction ff_coords("ff_coords", coords_field, &bulkData, Dimensions(3), Dimensions(3), FieldFunction::SIMPLE_SEARCH ); /// the function to be integrated: sqrt(Integral[x^2, dxdydz]) =?= sqrt(x^3/3 @ [-0.5, 0.5]) ==> sqrt(0.25/3) //StringFunction sfx("x", Name("sfx"), Dimensions(3), Dimensions(1) ); ff_coords.add_alias("mc"); //StringFunction sfcm("sqrt(mc[0]*mc[0]+mc[1]*mc[1]+mc[2]*mc[2])", Name("sfcm"), Dimensions(3), Dimensions(1)); StringFunction sfx_mc("mc[0]", Name("sfx_mc"), Dimensions(3), Dimensions(1) ); StringFunction sfx_mc1("mc[0]", Name("sfx_mc1"), Dimensions(3), Dimensions(1) ); if (1) { double x = -0.49+0.98*Math::random01(); double y = -0.49+0.98*Math::random01(); double z = -0.49+0.98*Math::random01(); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(eval(x,y,z,0.0, sfx), eval(x,y,z,0.0, sfx_mc)); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(eval(.034,0,0,0.0, sfx), eval(.034,0,0,0.0, sfx_mc)); } /// A place to hold the result. /// This is a "writable" function (we may want to make this explicit - StringFunctions are not writable; FieldFunctions are /// since we interpolate values to them from other functions). ConstantFunction sfx_res_turbo(0.0, "sfx_res_turbo"); ConstantFunction sfx_res_slow(0.0, "sfx_res_slow"); ConstantFunction sfx_res_fast(0.0, "sfx_res_fast"); ConstantFunction sfx_res_bucket(0.0, "sfx_res_bucket"); // STATE m_element.... /// Create the operator that will do the work /// get the l2 norm Norm<2> l2Norm(bulkData, &metaData.universal_part(), TURBO_NONE); l2Norm(sfx, sfx_res); Norm<2> l2Norm_turbo(bulkData, &metaData.universal_part(), turboOpt); Norm<2> l2Norm_turbo_bucket(bulkData, &metaData.universal_part(), TURBO_BUCKET); Norm<2> l2Norm_turbo1(bulkData, &metaData.universal_part(), turboOpt); l2Norm_turbo(sfx, sfx_res_turbo); l2Norm_turbo1(sfx_mc1, sfx_res_fast); l2Norm_turbo_bucket(sfx_mc1, sfx_res_bucket); l2Norm(sfx_mc, sfx_res_slow); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(eval(.023,0,0,0.0, sfx), eval(.023,0,0,0.0, sfx_mc)); double sfx_expect = std::sqrt(0.25/3.); std::cout << "sfx_expect= " << sfx_expect << std::endl; STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res_bucket.getValue()); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res.getValue()); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res_turbo.getValue()); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res_slow.getValue()); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res_fast.getValue()); //! STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res.getValue()); //Util::pause(true, "13a"); //STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_res_turbo.getValue(), sfx_expect); STKUNIT_EXPECT_DOUBLE_EQ_APPROX_TOL(sfx_expect, sfx_res_turbo.getValue(), 1.e-8); //Util::pause(true, "13"); /// the function to be integrated: (Integral[ abs(x), dxdydz]) =?= (2 * |x|^2/2 @ [0, 0.5]) ==> .25) Norm<1> l1Norm(bulkData, &metaData.universal_part(), TURBO_NONE); l1Norm(sfx, sfx_res); Norm<1> l1Norm_turbo(bulkData, &metaData.universal_part(), TURBO_NONE); l1Norm_turbo(sfx, sfx_res_turbo); l1Norm_turbo(sfx_mc, sfx_res_fast); l1Norm(sfx_mc, sfx_res_slow); sfx_expect = 0.25; STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res.getValue()); STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res_turbo.getValue()); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res_slow.getValue()); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res_fast.getValue()); //// ----- here /// the function to be integrated: sqrt(Integral[(x*y*z)^2, dxdydz]) =?= (see unitTest1.py) StringFunction sfxyz("x*y*z", Name("sfxyz"), Dimensions(3), Dimensions(1) ); l2Norm(sfxyz, sfx_res); l2Norm_turbo(sfxyz, sfx_res_turbo); sfx_expect = 0.0240562612162344; STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res.getValue()); STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res_turbo.getValue()); /// the function to be integrated (but over a rotated domain): sqrt(Integral[(x*y*z)^2, dxdydz]) =?= (see unitTest2.py) /// now rotate the mesh Math::Matrix rmz = Math::rotationMatrix(2, 30); Math::Matrix rm = rmz; eMesh.transform_mesh(rm); l2Norm(sfxyz, sfx_res); l2Norm_turbo(sfxyz, sfx_res_turbo); sfx_expect = 0.0178406008037016; // NOTE: we need extra quadrature accuracy to reproduce this result (cubDegree==4 in IntegratedOp almost gets it right) // for now, we are satisfied with 3 digits //STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_res.getValue(), sfx_expect); if (std::fabs(sfx_res.getValue()-sfx_expect) > 0.01*sfx_expect) { STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res.getValue()); STKUNIT_EXPECT_TRUE(false); } if (std::fabs(sfx_res_turbo.getValue()-sfx_expect) > 0.01*sfx_expect) { STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res_turbo.getValue()); STKUNIT_EXPECT_TRUE(false); } }
STKUNIT_UNIT_TEST(norm, string_function) { EXCEPTWATCH; //stk::diag::WriterThrowSafe _write_throw_safe(dw()); //dw().setPrintMask(dw_option_mask.parse(vm["dw"].as<std::string>().c_str())); //dw().setPrintMask(LOG_NORM+LOG_ALWAYS); dw().m(LOG_NORM) << "TEST.norm.string_function " << stk::diag::dendl; LocalFixture fix(4); mesh::fem::FEMMetaData& metaData = fix.metaData; mesh::BulkData& bulkData = fix.bulkData; PerceptMesh& eMesh = fix.eMesh; //mesh::FieldBase* coords_field = fix.coords_field; StringFunction sfx = fix.sfx; ConstantFunction sfx_res = fix.sfx_res; /// Create the operator that will do the work /// get the l2 norm Norm<2> l2Norm(bulkData, &metaData.universal_part(), TURBO_NONE); l2Norm(sfx, sfx_res); double sfx_expect = std::sqrt(0.25/3.); Teuchos::ScalarTraits<double>::seedrandom(12345); STKUNIT_EXPECT_DOUBLE_EQ_APPROX(sfx_expect, sfx_res.getValue()); int niter=1; for (int iter=0; iter < niter; iter++) { STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, eval(Math::random01(), Math::random01(), Math::random01(), 0.0, sfx_res)); } /// the function to be integrated: (Integral[ abs(x), dxdydz]) =?= (2 * |x|^2/2 @ [0, 0.5]) ==> .25) Norm<1> l1Norm(bulkData, &metaData.universal_part(), TURBO_NONE); l1Norm(sfx, sfx_res); sfx_expect = 0.25; STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res.getValue()); /// the function to be integrated: (Max[ x^2+y^3+z^4, dxdydz]) =?= (@ [-0.5, 0.5]^3 ) ==> .5^2+.5^3+.5^4) StringFunction sfmax("x^2 + y^3 + z^4", Name("sfmax"), Dimensions(3), Dimensions(1) ); Norm<-1> lInfNorm(bulkData, &metaData.universal_part(), TURBO_NONE); lInfNorm.setCubDegree(10); lInfNorm(sfmax, sfx_res); double sf1=eval(.5,.5,.5,0.0, sfmax); sfx_expect = 0.5*0.5 + 0.5*0.5*0.5 + 0.5*0.5*0.5*0.5; std::cout << "sfmax= " << sf1 << " sfx_expect= " << sfx_expect << " sfx_res= " << sfx_res.getValue() << std::endl; STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res.getValue()); /// indirection StringFunction sfmax_1("sfmax", Name("sfmax_1"), Dimensions(3), Dimensions(1) ); double sf1_1=eval(.5,.5,.5,0.0, sfmax_1); std::cout << "sfmax_1= " << sf1_1 << " sfx_expect= " << sfx_expect << std::endl; STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sf1_1); /// the function to be integrated: sqrt(Integral[(x*y*z)^2, dxdydz]) =?= (see unitTest1.py) StringFunction sfxyz("x*y*z", Name("sfxyz"), Dimensions(3), Dimensions(1) ); l2Norm(sfxyz, sfx_res); sfx_expect = 0.0240562612162344; STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res.getValue()); /// indirection std::cout << "tmp srk start..." << std::endl; StringFunction sfxyz_2("sfxyz", Name("sfxyz_2"), Dimensions(3), Dimensions(1) ); l2Norm(sfxyz_2, sfx_res); sfx_expect = 0.0240562612162344; STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res.getValue()); /// the function to be integrated (but over a rotated domain): sqrt(Integral[(x*y*z)^2, dxdydz]) =?= (see unitTest2.py) /// now rotate the mesh Math::Matrix rmz = Math::rotationMatrix(2, 30); Math::Matrix rm = rmz; eMesh.transform_mesh(rm); l2Norm(sfxyz, sfx_res); sfx_expect = 0.0178406008037016; // NOTE: we need extra quadrature accuracy to reproduce this result (cubDegree==4 in IntegratedOp almost gets it right) // for now, we are satisfied with 2-3 digits //STKUNIT_EXPECT_DOUBLE_EQ(sfx_res.getValue(), sfx_expect); if (std::fabs(sfx_res.getValue()-sfx_expect) > 0.01*sfx_expect) { STKUNIT_EXPECT_DOUBLE_EQ_APPROX( sfx_expect, sfx_res.getValue()); STKUNIT_EXPECT_TRUE(false); } }
void UnitTestSTKParallelDistributedIndex::test_update_generate() { typedef stk::parallel::DistributedIndex PDIndex ; stk::ParallelMachine comm = MPI_COMM_WORLD ; int p_rank = stk::parallel_machine_rank(comm); int p_size = stk::parallel_machine_size(comm); std::vector< PDIndex::KeySpan > partition_spans ; generate_test_spans_10x10000( partition_spans ); PDIndex di( comm , partition_spans ); std::vector<size_t> requests( partition_spans.size() , size_t(0) ); std::vector< std::vector<PDIndex::KeyType> > generated_keys ; std::vector<PDIndex::KeyProc> sharing_of_local_keys ; std::vector<PDIndex::KeyType> keys_to_add ; std::vector<PDIndex::KeyType> keys_to_remove ; //------------------------------ // Add ( 5 * j ) odd keys per process // starting at the beginning of the partition. const size_t old_size_multiplier = 5 ; for ( size_t j = 0 ; j < partition_spans.size() ; ++j ) { PDIndex::KeyType key_first = partition_spans[j].first ; if ( 0 == key_first % 2 ) { ++key_first ; // Make it odd } key_first += old_size_multiplier * p_rank ; const size_t n = old_size_multiplier * j ; for ( size_t i = 0 ; i < n ; ++i ) { PDIndex::KeyType key = key_first + 2 * i ; keys_to_add.push_back( key ); } } di.update_keys( keys_to_add , keys_to_remove ); //------------------------------ // Request 20 new keys per process per span // The maximum new key will be larger than some spans // and within the gaps of other spans. const size_t gen_count = 20 ; for ( size_t i = 0 ; i < requests.size() ; ++i ) { if ( i % 2 ) { requests[i] = gen_count ; } else { requests[i] = 0 ; } } di.generate_new_keys( requests , generated_keys ); for ( size_t i = 0 ; i < requests.size() ; ++i ) { STKUNIT_EXPECT_EQ( requests[i] , generated_keys[i].size() ); const size_t old_count = p_size * old_size_multiplier * i ; const size_t tot_request = p_size * requests[i] ; PDIndex::KeyType max_gen_key = partition_spans[i].first ; if ( 0 == tot_request ) { STKUNIT_EXPECT_TRUE( generated_keys[i].size() == 0 ); } else if ( tot_request < old_count ) { // Will only fill in gaps between odd keys max_gen_key += 2 * old_count ; STKUNIT_EXPECT_TRUE( max_gen_key > generated_keys[i][ requests[i] - 1 ] ); } else { // Will fill in gaps contiguously after the old max key max_gen_key += old_count + tot_request - 1 ; STKUNIT_EXPECT_TRUE( max_gen_key >= generated_keys[i][ requests[i] - 1 ] ); } // Sorted for ( size_t j = 0 ; j < generated_keys[i].size() ; ++j ) { if ( 0 < j ) { STKUNIT_EXPECT_TRUE( generated_keys[i][j-1] < generated_keys[i][j] ); } } } }
void UnitTestSTKParallelDistributedIndex::test_generate() { typedef stk::parallel::DistributedIndex PDIndex ; stk::ParallelMachine comm = MPI_COMM_WORLD ; int mpi_rank = stk::parallel_machine_rank(comm); // int mpi_size = stk::parallel_machine_size(comm); std::vector< PDIndex::KeySpan > partition_spans ; generate_test_spans_10x10000( partition_spans ); PDIndex di( comm , partition_spans ); std::vector<size_t> requests( partition_spans.size() , size_t(0) ); std::vector< std::vector<PDIndex::KeyType> > generated_keys ; std::vector<PDIndex::KeyProc> sharing_of_local_keys ; di.generate_new_keys( requests , generated_keys ); STKUNIT_EXPECT_TRUE( di.m_key_usage.empty() ); STKUNIT_ASSERT_EQ( generated_keys.size() , partition_spans.size() ); for ( size_t i = 0 ; i < generated_keys.size() ; ++i ) { STKUNIT_EXPECT_TRUE( generated_keys[i].empty() ); } //---------------------------------------- size_t total = 0 ; for ( size_t i = 0 ; i < requests.size() ; ++i ) { requests[i] = i + mpi_rank ; total += requests[i] ; } di.generate_new_keys( requests , generated_keys ); STKUNIT_ASSERT_EQ( generated_keys.size() , partition_spans.size() ); for ( size_t i = 0 ; i < generated_keys.size() ; ++i ) { STKUNIT_EXPECT_EQ( generated_keys[i].size() , requests[i] ); for ( size_t j = 0 ; j < generated_keys[i].size() ; ++j ) { STKUNIT_EXPECT_TRUE( partition_spans[i].first <= generated_keys[i][j] ); STKUNIT_EXPECT_TRUE( generated_keys[i][j] <= partition_spans[i].second ); if ( 0 < j ) { STKUNIT_EXPECT_TRUE( generated_keys[i][j-1] < generated_keys[i][j] ); } } } //---------------------------------------- di.query( sharing_of_local_keys ); STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , total ); // Confirm global uniqueness for ( size_t i = 0 ; i < generated_keys.size() ; ++i ) { di.query( generated_keys[i] , sharing_of_local_keys ); STKUNIT_EXPECT_EQ( generated_keys[i].size() , sharing_of_local_keys.size() ); for ( size_t j = 0 ; j < sharing_of_local_keys.size() ; ++j ) { STKUNIT_EXPECT_EQ( sharing_of_local_keys[j].second , mpi_rank ); } } //---------------------------------------- // Double the number of keys di.generate_new_keys( requests , generated_keys ); STKUNIT_ASSERT_EQ( generated_keys.size() , partition_spans.size() ); for ( size_t i = 0 ; i < generated_keys.size() ; ++i ) { STKUNIT_EXPECT_EQ( generated_keys[i].size() , requests[i] ); for ( size_t j = 0 ; j < generated_keys[i].size() ; ++j ) { STKUNIT_EXPECT_TRUE( partition_spans[i].first <= generated_keys[i][j] ); STKUNIT_EXPECT_TRUE( generated_keys[i][j] <= partition_spans[i].second ); if ( 0 < j ) { STKUNIT_EXPECT_TRUE( generated_keys[i][j-1] < generated_keys[i][j] ); } } } di.query( sharing_of_local_keys ); STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , total * 2 ); }
void UnitTestSTKParallelDistributedIndex::test_update() { typedef stk::parallel::DistributedIndex PDIndex ; stk::ParallelMachine comm = MPI_COMM_WORLD ; int mpi_rank = stk::parallel_machine_rank(comm); int mpi_size = stk::parallel_machine_size(comm); std::vector< PDIndex::KeySpan > partition_spans ; generate_test_spans_10x10000( partition_spans ); PDIndex di( comm , partition_spans ); std::vector<PDIndex::KeyType> keys_to_add ; std::vector<PDIndex::KeyType> keys_to_remove ; std::vector<PDIndex::KeyProc> sharing_of_local_keys ; //------------------------------ // Update nothing: di.update_keys( keys_to_add , keys_to_remove ); STKUNIT_EXPECT_TRUE( di.m_key_usage.empty() ); //------------------------------ // Update one key on all processes and // one key unique to each process. keys_to_add.push_back( partition_spans[0].first + 1 ); keys_to_add.push_back( partition_spans[1].first + 2 + mpi_rank ); di.update_keys( keys_to_add , keys_to_remove ); di.query( sharing_of_local_keys ); // First key shared by all processes // Second key shared just by this process STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , size_t(mpi_size + 1) ); di.query( keys_to_add , sharing_of_local_keys ); STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , size_t(mpi_size + 1) ); //------------------------------ // Repeat the update, should result in no changes. di.update_keys( keys_to_add , keys_to_remove ); di.query( sharing_of_local_keys ); // First key shared by all processes // Second key shared just by this process STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , size_t(mpi_size + 1) ); //------------------------------ keys_to_remove.clear(); keys_to_add.clear(); keys_to_remove.push_back( partition_spans[0].second ); di.update_keys( keys_to_add , keys_to_remove ); di.query( sharing_of_local_keys ); STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , size_t(mpi_size + 1) ); //------------------------------ // Remove shared key keys_to_remove.clear(); keys_to_add.clear(); keys_to_remove.push_back( partition_spans[0].first + 1 ); di.update_keys( keys_to_add , keys_to_remove ); di.query( sharing_of_local_keys ); STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , size_t(1) ); //------------------------------ // Add two shared-by-all keys_to_remove.clear(); keys_to_add.clear(); keys_to_add.push_back( partition_spans[0].first + 1 ); keys_to_add.push_back( partition_spans[0].first + 2 ); di.update_keys( keys_to_add , keys_to_remove ); di.query( sharing_of_local_keys ); STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , size_t(2*mpi_size + 1) ); di.query( keys_to_add , sharing_of_local_keys ); STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , size_t(2*mpi_size) ); //------------------------------ keys_to_remove.clear(); keys_to_add.clear(); // Shared by even rank processes: if ( 0 == mpi_rank % 2 ) { keys_to_add.push_back( partition_spans[2].first ); } di.update_keys( keys_to_add , keys_to_remove ); di.query( sharing_of_local_keys ); { size_t expected = 2 * mpi_size + 1 ; if ( 0 == mpi_rank % 2 ) { expected += ( mpi_size + 1 ) / 2 ; } STKUNIT_EXPECT_EQ( sharing_of_local_keys.size() , expected ); } }
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); }
void UnitTestStkMeshBoundaryAnalysis::test_boundary_analysis() { // This test will only work for np=1 if (m_num_procs > 1) { return; } // set up grid_mesh stk::mesh::fixtures::GridFixture grid_mesh(MPI_COMM_WORLD); stk::mesh::BulkData& bulk_data = grid_mesh.bulk_data(); stk::mesh::MetaData& meta_data = grid_mesh.meta_data(); stk::mesh::TopologicalMetaData& top_data = grid_mesh.top_data(); // make shell part stk::mesh::Part& shell_part = top_data.declare_part<shards::ShellLine<2> >("shell_part"); meta_data.commit(); bulk_data.modification_begin(); grid_mesh.generate_grid(); // Add some shells const unsigned num_shell_faces = 4; // get a count of entities that have already been created std::vector<unsigned> count; stk::mesh::Selector locally_owned(meta_data.locally_owned_part()); stk::mesh::count_entities(locally_owned, bulk_data, count); const unsigned num_entities = count[top_data.node_rank] + count[top_data.element_rank]; std::vector<stk::mesh::Entity*> shell_faces; stk::mesh::PartVector shell_parts; shell_parts.push_back(&shell_part); for (unsigned i = 1; i <= num_shell_faces; ++i) { stk::mesh::Entity& new_shell = bulk_data.declare_entity(top_data.element_rank, num_entities + i, shell_parts); shell_faces.push_back(&new_shell); } // declare shell relationships unsigned node_list[5] = {20, 25, 30, 35, 40}; for (unsigned i = 0; i < num_shell_faces; ++i) { stk::mesh::Entity& shell = *(shell_faces[i]); stk::mesh::Entity& node1 = *(bulk_data.get_entity(top_data.node_rank, node_list[i])); stk::mesh::Entity& node2 = *(bulk_data.get_entity(top_data.node_rank, node_list[i+1])); bulk_data.declare_relation(shell, node1, 0); bulk_data.declare_relation(shell, node2, 1); } bulk_data.modification_end(); // create the closure we want to analyze std::vector<stk::mesh::Entity*> closure; unsigned num_faces_in_closure = 6; unsigned ids_of_entities_in_closure[] = {6, 7, 10, 11, 14, 15, 23, 24, 25, 28, 29, 30, 33, 34, 35, 38, 39, 40}; for (unsigned i = 0; i < sizeof(ids_of_entities_in_closure)/sizeof(unsigned); ++i) { stk::mesh::EntityRank rank_of_entity; if (i < num_faces_in_closure) { rank_of_entity = top_data.element_rank; } else { rank_of_entity = 0; } stk::mesh::Entity* closure_entity = bulk_data.get_entity(rank_of_entity, ids_of_entities_in_closure[i]); closure.push_back(closure_entity); } // sort the closure std::sort(closure.begin(), closure.end(), stk::mesh::EntityLess()); stk::mesh::EntitySideVector boundary; stk::mesh::boundary_analysis(bulk_data, closure, top_data.element_rank, boundary); STKUNIT_EXPECT_TRUE(!boundary.empty()); std::vector<std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> > > results; std::vector<std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> > > expected_results; { std::pair<unsigned, unsigned> inside(6, 0); std::pair<unsigned, unsigned> outside(5, 2); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(6, 3); std::pair<unsigned, unsigned> outside(2, 1); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(7, 2); std::pair<unsigned, unsigned> outside(8, 0); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(7, 2); std::pair<unsigned, unsigned> outside(43, 0); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(7, 3); std::pair<unsigned, unsigned> outside(3, 1); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(10, 0); std::pair<unsigned, unsigned> outside(9, 2); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(11, 2); std::pair<unsigned, unsigned> outside(12, 0); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(11, 2); std::pair<unsigned, unsigned> outside(44, 0); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(14, 0); std::pair<unsigned, unsigned> outside(13, 2); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(14, 1); std::pair<unsigned, unsigned> outside(0, 0); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(15, 1); std::pair<unsigned, unsigned> outside(0, 0); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(15, 2); std::pair<unsigned, unsigned> outside(16, 0); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } { std::pair<unsigned, unsigned> inside(15, 2); std::pair<unsigned, unsigned> outside(45, 0); expected_results.push_back( std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } for (stk::mesh::EntitySideVector::iterator itr = boundary.begin(); itr != boundary.end(); ++itr) { stk::mesh::EntitySide& side = *itr; stk::mesh::EntitySideComponent& inside_closure = side.inside; stk::mesh::EntityId inside_id = inside_closure.entity != NULL ? inside_closure.entity->identifier() : 0; stk::mesh::EntityId inside_side = inside_closure.entity != NULL ? inside_closure.side_ordinal : 0; stk::mesh::EntitySideComponent& outside_closure = side.outside; stk::mesh::EntityId outside_id = outside_closure.entity != NULL ? outside_closure.entity->identifier() : 0; stk::mesh::EntityId outside_side = outside_closure.entity != NULL ? outside_closure.side_ordinal : 0; std::pair<unsigned, unsigned> inside(inside_id, inside_side); std::pair<unsigned, unsigned> outside(outside_id, outside_side); results.push_back(std::pair<std::pair<unsigned, unsigned>, std::pair<unsigned, unsigned> >(inside, outside)); } STKUNIT_EXPECT_TRUE(results == expected_results); }