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);

}
Ejemplo n.º 2
0
      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;
}
Ejemplo n.º 5
0
//=============================================================================
//=============================================================================
//=============================================================================
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 );
  }
}
Ejemplo n.º 9
0
/// 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);
  }
}
Ejemplo n.º 10
0
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 );
    }

}
Ejemplo n.º 14
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);
  }
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);
}