Example #1
0
typename stk_classic::mesh::FieldTraits<field_type>::data_type
dot( const stk_classic::AlgorithmRunnerInterface & alg_runner ,
     const stk_classic::mesh::BulkData& bulk,
     const stk_classic::mesh::EntityRank entitytype,
     const field_type & x ,
     const field_type & y )
{
  // Construct algorithm to hand to local parallel algorithm runner

  DotAlg<field_type> alg_dot(x,y);

  const std::vector<stk_classic::mesh::Bucket*>
    & all_entity_buckets = bulk.buckets( entitytype );

  stk_classic::mesh::Selector
    select_owned( stk_classic::mesh::MetaData::get(bulk).locally_owned_part());

  double local_dot = 0 ;
  double global_dot = 0 ;

  // Local parallel execution of the algorithm

  stk_classic::mesh::PartVector empty_union_vector;
  alg_runner.run( select_owned , empty_union_vector, all_entity_buckets , alg_dot , & local_dot );

  // Global sum

#if defined( STK_HAS_MPI )
  MPI_Comm comm = bulk.parallel();

  MPI_Allreduce(& local_dot , & global_dot, 1, MPI_DOUBLE, MPI_SUM, comm);
#else
  global_dot = local_dot;
#endif

  return global_dot ;
}
Example #2
0
bool use_case_5_driver( MPI_Comm comm ,
                        const std::string& mesh_options,
                        const std::string& solver_params )
{
  if ( 0 == stk::parallel_machine_rank( comm ) ) {
    std::cout << "stk_linsys use case 5" << std::endl
              << "  Number Processes = " << stk::parallel_machine_size( comm )
              << std::endl ;
  }

  //--------------------------------------------------------------------

  {
    //------------------------------------------------------------------
    // Declare the mesh meta data: element blocks and associated fields

    stk::mesh::fem::FEMMetaData fem_meta(SpatialDim, stk::mesh::fem::entity_rank_names(SpatialDim) ) ;
    Ioss::Init::Initializer init_db;

    stk::mesh::MetaData & mesh_meta_data = stk::mesh::fem::FEMMetaData::get_meta_data(fem_meta);

    {
      const stk::mesh::fem::FEMMetaData &fmd = fem_meta.get ( mesh_meta_data );
      std::cout <<fmd.is_FEM_initialized()<<endl;
    }

    const stk::mesh::EntityRank element_rank = fem_meta.element_rank();

    //--------------------------------
    // Element-block declarations typically occur when reading the
    // mesh-file meta-data, and thus won't usually appear in application code.
    // Declaring the element blocks and associating an element traits
    // with each element block.

    stk::mesh::Part & universal        = fem_meta.universal_part();
    stk::mesh::Part & block_hex        = fem_meta.declare_part("block_1", element_rank);
    stk::mesh::Part & block_quad_shell = fem_meta.declare_part("block_2", element_rank);

    stk::mesh::fem::CellTopology hex_top(shards::getCellTopologyData<shards::Hexahedron<> >());
    stk::mesh::fem::CellTopology qshell_top(shards::getCellTopologyData<shards::ShellQuadrilateral<> >());
    stk::mesh::fem::set_cell_topology( block_hex, hex_top );
    stk::mesh::fem::set_cell_topology( block_quad_shell, qshell_top );

    stk::io::put_io_part_attribute(block_hex);
    stk::io::put_io_part_attribute(block_quad_shell);

    //--------------------------------
    // Declaring fields of specified types on all nodes:

    VectorFieldType & coordinates_field =
      stk::mesh::put_field(
        fem_meta.declare_field< VectorFieldType >( "coordinates" ) ,
        stk::mesh::fem::FEMMetaData::NODE_RANK , universal , SpatialDim );

    VectorFieldType & displacements_field =
      stk::mesh::put_field(
        fem_meta.declare_field< VectorFieldType >( "displacements" ) ,
        stk::mesh::fem::FEMMetaData::NODE_RANK , universal , SpatialDim );

    //--------------------------------
    // rotation_field only exists on the shell-nodes:

    VectorFieldType & rotation_field =
      stk::mesh::put_field(
        fem_meta.declare_field< VectorFieldType >( "rotation" ),
        stk::mesh::fem::FEMMetaData::NODE_RANK , block_quad_shell , SpatialDim );

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

    // Define the transient fields that will be output.
    stk::io::set_field_role(displacements_field, Ioss::Field::TRANSIENT);

    //--------------------------------
    // Commit (finalize) the meta data.  Is now ready to be used
    // in the creation and management of mesh bulk data.

    fem_meta.commit();

    //------------------------------------------------------------------
    // stk::mesh::BulkData bulk data conforming to the meta data.

    stk::mesh::BulkData mesh_bulk_data( mesh_meta_data , comm );

    // In a typical app, the mesh would be read from file at this point.
    // But in this use-case, we generate the mesh and initialize
    // field data to use-case defined values.

    use_case_5_generate_mesh(
      mesh_options ,
      mesh_bulk_data ,
      coordinates_field ,
      block_hex ,
      block_quad_shell );

    use_case_5_initialize_data(
      mesh_bulk_data ,
      coordinates_field ,
      displacements_field ,
      rotation_field );

    //Add a node to our boundary-condition part 'bcpart'.
    //let's choose the first locally-owned node. (This will produce a
    //different boundary-condition for different numbers of processors...
    //A more realistic case would simply pick a specific set of nodes
    //regardless of which processors they are on.)

    mesh_bulk_data.modification_begin();

    std::vector<stk::mesh::Entity*> local_nodes;
    stk::mesh::Selector select_owned(fem_meta.locally_owned_part());
    stk::mesh::get_selected_entities(select_owned,
                                     mesh_bulk_data.buckets(stk::mesh::fem::FEMMetaData::NODE_RANK),
                                     local_nodes);

    if (local_nodes.size() > 0) {
      stk::mesh::PartVector partvector;
      partvector.push_back(&bcpart);
      mesh_bulk_data.change_entity_parts(*local_nodes[0], partvector);
    }

    mesh_bulk_data.modification_end();

    //set owner-processors to lowest-sharing (stk::mesh defaults to
    //highest-sharing) If highest-sharing owns, then it isn't correct for the
    //way the fei library sets ownership of shared nodes for vectors etc.
    stk::mesh::set_owners<stk::mesh::LowestRankSharingProcOwns>( mesh_bulk_data );

    //Note: set_owners should throw an error if not done inside a modification_begin/end block.
    //------------------------------------------------------------------

    const unsigned myProc = mesh_bulk_data.parallel_rank();

    //Now begin the use-case:
    //Create a fei::Factory of type Factory_Trilinos, which will produce
    //fei::Matrix and fei::Vector objects with run-time-type compatible with Trilinos.

    fei::SharedPtr<fei::Factory> feifactory(new Factory_Trilinos(comm));
    stk::linsys::LinearSystem ls(comm, feifactory);

    if (myProc == 0) {
      std::cout << "Adding element-node connectivities for displacements field for all locally-owned "
        << "elements..." << std::endl;
    }

    //Add connectivities for our mesh to the linsys::LinearSystem object. This
    //will enable us to generate a matrix-graph:

    stk::linsys::add_connectivities(ls, element_rank,
                                    stk::mesh::fem::FEMMetaData::NODE_RANK,
                                    displacements_field, select_owned, mesh_bulk_data);

    ls.synchronize_mappings_and_structure();

    ls.create_fei_LinearSystem();

    fei::SharedPtr<fei::MatrixGraph> matgraph = ls.get_fei_MatrixGraph();
    fei::SharedPtr<fei::Matrix> matrix = ls.get_fei_LinearSystem()->getMatrix();
    fei::SharedPtr<fei::Vector> rhs = ls.get_fei_LinearSystem()->getRHS();
    fei::SharedPtr<fei::Vector> solution = ls.get_fei_LinearSystem()->getSolutionVector();

    //Now we'll run through the mesh and load up dense element-matrices and element-vectors
    //to assemble into the global sparse linear-system:
    {
      const std::vector<stk::mesh::Bucket*>& mesh_buckets = mesh_bulk_data.buckets(element_rank);
      std::vector<stk::mesh::Bucket*> part_buckets;
      stk::mesh::get_buckets(select_owned, mesh_buckets, part_buckets);

      stk::linsys::DofMapper& dof_mapper = ls.get_DofMapper();

      int field_id = dof_mapper.get_field_id(displacements_field);

      stk::mesh::Entity& first_entity = *(part_buckets[0]->begin());
      stk::mesh::PairIterRelation rel = first_entity.relations(stk::mesh::fem::FEMMetaData::NODE_RANK);
      int num_nodes_per_elem = rel.second - rel.first;

      int pattern_id = matgraph->definePattern(num_nodes_per_elem, stk::mesh::fem::FEMMetaData::NODE_RANK, field_id);

      std::vector<int> node_ids(num_nodes_per_elem);

      const int field_size = dof_mapper.get_fei_VectorSpace()->getFieldSize(field_id);
      const int matsize = num_nodes_per_elem*field_size*num_nodes_per_elem*field_size;
      const int vecsize = num_nodes_per_elem*field_size;

      std::vector<double> elem_matrix_1d(matsize, 0);
      std::vector<double*> elem_matrix_2d(vecsize);

      std::vector<double> elem_vector(vecsize, 0);

      for(size_t i=0; i<elem_matrix_2d.size(); ++i) {
        elem_matrix_2d[i] = &elem_matrix_1d[i*vecsize];
      }

      //fill our dummy elem-matrix:
      //This dummy matrix will be the same for every element. A real application
      //would form a different elem-matrix for each element.
      for(size_t i=0; i<elem_matrix_2d.size(); ++i) {
        double* row = elem_matrix_2d[i];
        if (i>=1) row[i-1] = -1;
        row[i] = 2;
        if (i<elem_matrix_2d.size()-1) row[i+1] = -1;

        elem_vector[i] = 1;
      }

      std::vector<int> eqn_indices(vecsize);

      for(size_t i=0; i<part_buckets.size(); ++i) {
        stk::mesh::Bucket::iterator
          b_iter = part_buckets[i]->begin(),
                 b_end  = part_buckets[i]->end();
        for(; b_iter != b_end; ++b_iter) {
          stk::mesh::Entity& elem = *b_iter;
          rel = elem.relations(stk::mesh::fem::FEMMetaData::NODE_RANK);
          for(int j=0; rel.first != rel.second; ++rel.first, ++j) {
            node_ids[j] = rel.first->entity()->identifier();
          }

          matgraph->getPatternIndices(pattern_id, &node_ids[0], eqn_indices);

          matrix->sumIn(vecsize, &eqn_indices[0], vecsize, &eqn_indices[0],
                        &elem_matrix_2d[0]);
          rhs->sumIn(vecsize, &eqn_indices[0], &elem_vector[0]);
        }
      }

      stk::linsys::dirichlet_bc(ls, mesh_bulk_data, bcpart, stk::mesh::fem::FEMMetaData::NODE_RANK,
                                displacements_field, 0, 3.14159265);

      ls.finalize_assembly();

      //Read solver-parameters out of a file. In a real application this would
      //be done during a parsing phase, *not* here in the assembly code.

      Teuchos::ParameterList params;
      if (solver_params != "") {
        Teuchos::ParameterXMLFileReader param_file(solver_params);
        params = param_file.getParameters();
      }

      //Launch the linear-solver:
      int status = 0, ret;
      ret = ls.solve(status, params);

      if (ret != 0) {
        throw std::runtime_error("Error in the linear solver.");
      }

      //Copy the contents of the solution-vector back into our mesh-data:
      copy_vector_to_mesh( *solution, dof_mapper, mesh_bulk_data);
    }

    //This following section writes mesh data out to an exodus file:
    {
      const std::string out_filename("mesh.e");

      stk::io::MeshData mesh;
      stk::io::create_output_mesh(out_filename, comm, mesh_bulk_data, mesh);
      stk::io::define_output_fields(mesh, fem_meta);

      // Write the model to the mesh file (topology, coordinates, attributes, etc)
      stk::io::process_output_request(mesh, mesh_bulk_data, 0.0);
    }

    //Write out our assembled linear-system to files:

    matrix->writeToFile("A.mtx");
    rhs->writeToFile("rhs.vec");
    solution->writeToFile("solution.vec");
  }
  return true;
}
STKUNIT_UNIT_TEST(UnitTestLinsysFunctions, test1)
{
    static const size_t spatial_dimension = 3;

    MPI_Barrier( MPI_COMM_WORLD );
    MPI_Comm comm = MPI_COMM_WORLD;
    //First create and fill MetaData and BulkData objects:

    const unsigned bucket_size = 100; //for a real application mesh, bucket_size would be much bigger...

    stk::mesh::fem::FEMMetaData fem_meta;
    stk::mesh::fem::FEMMetaData fem_meta2;
    fem_meta.FEM_initialize(spatial_dimension);
    fem_meta2.FEM_initialize(spatial_dimension);

    stk::mesh::MetaData & meta_data = stk::mesh::fem::FEMMetaData::get_meta_data(fem_meta);
    stk::mesh::MetaData & meta_data2 = stk::mesh::fem::FEMMetaData::get_meta_data(fem_meta2);

    const stk::mesh::EntityRank element_rank = fem_meta.element_rank();

    stk::mesh::BulkData bulk_data( meta_data, comm, bucket_size );
    stk::mesh::BulkData bulk_data2( meta_data2, comm, bucket_size );

    //create a boundary-condition part for testing later:
    stk::mesh::Part& bcpart = fem_meta.declare_part("bcpart");

    fill_utest_mesh_meta_data( fem_meta );

    bool use_temperature=false;
    fill_utest_mesh_meta_data( fem_meta2, use_temperature );

    fill_utest_mesh_bulk_data( bulk_data );
    fill_utest_mesh_bulk_data( bulk_data2 );

    //set owner-processors to lowest-sharing (stk::mesh defaults to
    //highest-sharing) If highest-sharing owns, then it isn't correct for the
    //way the fei library sets ownership of shared nodes for vectors etc.
    stk::mesh::set_owners<stk::mesh::LowestRankSharingProcOwns>( bulk_data );

    //put a node in our boundary-condition part. arbitrarily choose the
    //first locally-owned node:

    bulk_data.modification_begin();

    std::vector<stk::mesh::Entity*> local_nodes;
    stk::mesh::Selector select_owned(meta_data.locally_owned_part());
    stk::mesh::get_selected_entities(select_owned,
                                     bulk_data.buckets(NODE_RANK),
                                     local_nodes);

    stk::mesh::EntityId bc_node_id = 0;

    if (local_nodes.size() > 0) {
        stk::mesh::PartVector partvector;
        partvector.push_back(&bcpart);
        bulk_data.change_entity_parts(*local_nodes[0], partvector);
        bc_node_id = stk::linsys::impl::entityid_to_int(local_nodes[0]->identifier());
    }

    bulk_data.modification_end();

    stk::mesh::Selector selector = ( meta_data.locally_owned_part() | meta_data.globally_shared_part() ) & *meta_data.get_part("block_1");
    std::vector<unsigned> count;
    stk::mesh::count_entities(selector, bulk_data, count);

    STKUNIT_ASSERT_EQUAL( count[element_rank], (unsigned)4 );
    STKUNIT_ASSERT_EQUAL( count[NODE_RANK],     (unsigned)20 );

    ScalarField* temperature_field = meta_data.get_field<ScalarField>("temperature");

    //Create a fei Factory and stk::linsys::LinearSystem object:

    fei::SharedPtr<fei::Factory> factory(new Factory_Trilinos(comm));

    stk::linsys::LinearSystem ls(comm, factory);

    stk::linsys::add_connectivities(ls, element_rank, NODE_RANK,
                                    *temperature_field, selector, bulk_data);

    fei::SharedPtr<fei::MatrixGraph> matgraph = ls.get_fei_MatrixGraph();
    int num_blocks = matgraph->getNumConnectivityBlocks();

    STKUNIT_ASSERT_EQUAL( num_blocks, (int)1 );

    ls.synchronize_mappings_and_structure();
    ls.create_fei_LinearSystem();

    //put 0 throughout the matrix and 3 throughout the rhs:
    fei::SharedPtr<fei::Matrix> mat = ls.get_fei_LinearSystem()->getMatrix();
    ls.get_fei_LinearSystem()->getMatrix()->putScalar(0);
    ls.get_fei_LinearSystem()->getRHS()->putScalar(3.0);

    //put 10 on the matrix diagonal to ensure it will be easy to solve later.
    fei::SharedPtr<fei::VectorSpace> vspace = ls.get_fei_LinearSystem()->getRHS()->getVectorSpace();
    int numLocalRows = vspace->getNumIndices_Owned();
    std::vector<int> local_rows(numLocalRows);
    vspace->getIndices_Owned(numLocalRows, &local_rows[0], numLocalRows);

    for(size_t i=0; i<local_rows.size(); ++i) {
        int col = local_rows[i];
        double coef = 10;
        double* coefPtr = &coef;
        mat->sumIn(1, &local_rows[i], 1, &col, &coefPtr);
    }

    //now we'll impose a dirichlet bc on our one-node bcpart:
    stk::linsys::dirichlet_bc(ls, bulk_data, bcpart, NODE_RANK,
                              *temperature_field, 0, 9.0);

    ls.finalize_assembly();

    //now confirm that the rhs value for the equation corresponding to our
    //bc node is 9.0:

    fei::SharedPtr<fei::Vector> rhsvec = ls.get_fei_LinearSystem()->getRHS();
    double rhs_bc_val = 0;
    int bc_eqn_index = ls.get_DofMapper().get_global_index(NODE_RANK,
                       bc_node_id, *temperature_field);
    rhsvec->copyOut(1, &bc_eqn_index, &rhs_bc_val);

    bool bc_val_is_correct = std::abs(rhs_bc_val - 9.0) < 1.e-13;
    STKUNIT_ASSERT( bc_val_is_correct );

    stk::linsys::copy_vector_to_mesh( *rhsvec, ls.get_DofMapper(), bulk_data);

    stk::mesh::Entity* bc_node = bulk_data.get_entity(NODE_RANK, local_nodes[0]->identifier());

    stk::mesh::FieldTraits<ScalarField>::data_type* bc_node_data = stk::mesh::field_data(*temperature_field, *bc_node);

    bool bc_node_data_is_correct = std::abs(bc_node_data[0] - 9.0) < 1.e-13;
    STKUNIT_ASSERT( bc_node_data_is_correct );

    //now make sure we get a throw if we use the wrong bulk-data (that doesn't have the
    //temperature field defined)
    STKUNIT_ASSERT_THROW(stk::linsys::copy_vector_to_mesh( *rhsvec, ls.get_DofMapper(), bulk_data2), std::runtime_error);

    //obtain and zero the solution vector
    fei::SharedPtr<fei::Vector> solnvec = ls.get_fei_LinearSystem()->getSolutionVector();
    solnvec->putScalar(0);

    //copy the vector of zeros into the mesh:
    stk::linsys::copy_vector_to_mesh( *solnvec, ls.get_DofMapper(), bulk_data);

    //assert that our bc node's data is now zero.
    bc_node_data_is_correct = std::abs(bc_node_data[0] - 0) < 1.e-13;
    STKUNIT_ASSERT( bc_node_data_is_correct );

    //call the linear-system solve function.
    //(note that when we add options to the solve method, we'll need to enhance this
    //testing to exercise various specific solves.)
    Teuchos::ParameterList params;

    int status = 0;
    ls.solve(status, params);

    //copy the solution-vector into the mesh:
    stk::linsys::copy_vector_to_mesh( *solnvec, ls.get_DofMapper(), bulk_data);

    //now assert that the value 9 (bc value) produced by the solve is in this
    //node's data.
    //note that we use a loose tolerance, because the default solver tolerance
    //is (I think) only 1.e-6.
    bc_node_data_is_correct = std::abs(bc_node_data[0] - 9.0) < 1.e-6;
    STKUNIT_ASSERT( bc_node_data_is_correct );
    STKUNIT_ASSERT(bc_node_data_is_correct);
}
void UnitTestBulkData::testChangeParts_loop( ParallelMachine pm )
{
  enum { nPerProc = 10 };
  const unsigned p_rank = parallel_machine_rank( pm );
  const unsigned p_size = parallel_machine_size( pm );
  const unsigned nLocalNode = nPerProc + ( 1 < p_size ? 1 : 0 );
  const unsigned nLocalEdge = nPerProc ;

  UnitTestRingMeshFixture ring_mesh( pm , nPerProc , true /* generate parts */ );
  ring_mesh.m_meta_data.commit();
  ring_mesh.generate_mesh( false /* no aura */ );

  Part & part_owns = ring_mesh.m_meta_data.locally_owned_part();
  Part & part_univ = ring_mesh.m_meta_data.universal_part();

  Selector select_owned( ring_mesh.m_meta_data.locally_owned_part() );
  Selector select_used = select_owned | ring_mesh.m_meta_data.globally_shared_part();
  Selector select_all(   ring_mesh.m_meta_data.universal_part() );

  std::vector<unsigned> local_count ;

  for ( unsigned i = 0 ; i < nLocalEdge ; ++i ) {
    const unsigned n = i + nPerProc * p_rank ;
    Entity * const edge = ring_mesh.m_bulk_data.get_entity( 1 , ring_mesh.m_edge_ids[n] );
    STKUNIT_ASSERT( edge != NULL );
    STKUNIT_ASSERT( edge->bucket().member( part_univ ) );
    STKUNIT_ASSERT( edge->bucket().member( part_owns ) );
    STKUNIT_ASSERT( edge->bucket().member( * ring_mesh.m_edge_parts[ n % ring_mesh.m_edge_parts.size() ] ) );
  }

  for ( unsigned i = 0 ; i < nLocalNode ; ++i ) {
    const unsigned n = ( i + nPerProc * p_rank ) % ring_mesh.m_node_ids.size();
    const unsigned e0 = n ;
    const unsigned e1 = ( n + ring_mesh.m_edge_ids.size() - 1 ) % ring_mesh.m_edge_ids.size();
    const unsigned ns = ring_mesh.m_edge_parts.size();
    const unsigned n0 = e0 % ns ;
    const unsigned n1 = e1 % ns ;
    Part * const epart_0 = ring_mesh.m_edge_parts[ n0 < n1 ? n0 : n1 ];
    Part * const epart_1 = ring_mesh.m_edge_parts[ n0 < n1 ? n1 : n0 ];

    Entity * const node = ring_mesh.m_bulk_data.get_entity( 0 , ring_mesh.m_node_ids[n] );
    STKUNIT_ASSERT( node != NULL );
    if ( node->owner_rank() == p_rank ) {
      STKUNIT_ASSERT( node->bucket().member( part_univ ) );
      STKUNIT_ASSERT( node->bucket().member( part_owns ) );
      STKUNIT_ASSERT( node->bucket().member( *epart_0 ) );
      STKUNIT_ASSERT( node->bucket().member( *epart_1 ) );
    }
    else {
      STKUNIT_ASSERT( node->bucket().member( part_univ ) );
      STKUNIT_ASSERT( ! node->bucket().member( part_owns ) );
      STKUNIT_ASSERT( node->bucket().member( * epart_0 ) );
      STKUNIT_ASSERT( node->bucket().member( * epart_1 ) );
    }
  }

  ring_mesh.m_bulk_data.modification_begin();

  if ( 0 == p_rank ) {

    for ( unsigned i = 0 ; i < nLocalEdge ; ++i ) {
      const unsigned n = i + nPerProc * p_rank ;

      PartVector add(1); add[0] = & ring_mesh.m_edge_part_extra ;
      PartVector rem(1); rem[0] = ring_mesh.m_edge_parts[ n % ring_mesh.m_edge_parts.size() ];

      Entity * const edge = ring_mesh.m_bulk_data.get_entity( 1 , ring_mesh.m_edge_ids[n] );
      ring_mesh.m_bulk_data.change_entity_parts( *edge , add , rem );
      STKUNIT_ASSERT( edge->bucket().member( part_univ ) );
      STKUNIT_ASSERT( edge->bucket().member( part_owns ) );
      STKUNIT_ASSERT( edge->bucket().member(ring_mesh.m_edge_part_extra ) );
    }
  }

  ring_mesh.m_bulk_data.modification_end();

  for ( unsigned i = 0 ; i < nLocalNode ; ++i ) {
    const unsigned n = ( i + nPerProc * p_rank ) % ring_mesh.m_node_ids.size();
    const unsigned e0 = n ;
    const unsigned e1 = ( n + ring_mesh.m_edge_ids.size() - 1 ) % ring_mesh.m_edge_ids.size();
    const unsigned ns = ring_mesh.m_edge_parts.size();
    const unsigned n0 = e0 % ns ;
    const unsigned n1 = e1 % ns ;
    Part * ep_0 = e0 < nLocalEdge ? & ring_mesh.m_edge_part_extra : ring_mesh.m_edge_parts[n0] ;
    Part * ep_1 = e1 < nLocalEdge ? & ring_mesh.m_edge_part_extra : ring_mesh.m_edge_parts[n1] ;

    Part * epart_0 = ep_0->mesh_meta_data_ordinal() < ep_1->mesh_meta_data_ordinal() ? ep_0 : ep_1 ;
    Part * epart_1 = ep_0->mesh_meta_data_ordinal() < ep_1->mesh_meta_data_ordinal() ? ep_1 : ep_0 ;

    Entity * const node = ring_mesh.m_bulk_data.get_entity( 0 , ring_mesh.m_node_ids[n] );
    STKUNIT_ASSERT( node != NULL );
    if ( node->owner_rank() == p_rank ) {
      STKUNIT_ASSERT( node->bucket().member( part_owns ) );
    }
    else {
      STKUNIT_ASSERT( ! node->bucket().member( part_owns ) );
    }

    STKUNIT_ASSERT( node->bucket().member( part_univ ) );
    STKUNIT_ASSERT( node->bucket().member( *epart_0 ) );
    STKUNIT_ASSERT( node->bucket().member( *epart_1 ) );
  }
}
Example #5
0
void assemble_elem_matrices_and_vectors(stk::mesh::BulkData& mesh,
                                        stk::mesh::FieldBase& field,
                                        stk::linsys::DofMapper& dof_mapper,
                                        fei::Matrix& matrix,
                                        fei::Vector& rhs)
{
  stk::mesh::fem::FEMMetaData &fem = stk::mesh::fem::FEMMetaData::get(mesh);
  const stk::mesh::EntityRank element_rank = fem.element_rank();

  const std::vector<stk::mesh::Bucket*>& mesh_buckets = mesh.buckets(element_rank);

  std::vector<stk::mesh::Bucket*> part_buckets;
  stk::mesh::Selector select_owned(stk::mesh::MetaData::get(mesh).locally_owned_part());
  stk::mesh::get_buckets(select_owned, mesh_buckets, part_buckets);

  int field_id = dof_mapper.get_field_id(field);

  stk::mesh::Entity& first_entity = *(part_buckets[0]->begin());
  stk::mesh::PairIterRelation rel = first_entity.relations(stk::mesh::fem::FEMMetaData::NODE_RANK);
  int num_nodes_per_elem = rel.second - rel.first;

  fei::SharedPtr<fei::MatrixGraph> matgraph = matrix.getMatrixGraph();
  int pattern_id = matgraph->definePattern(num_nodes_per_elem, stk::mesh::fem::FEMMetaData::NODE_RANK, field_id);

  std::vector<int> node_ids(num_nodes_per_elem);

  const int field_size = dof_mapper.get_fei_VectorSpace()->getFieldSize(field_id);
  const int matsize = num_nodes_per_elem*field_size*num_nodes_per_elem*field_size;
  const int vecsize = num_nodes_per_elem*field_size;

  std::vector<double> elem_matrix_1d(matsize, 0);
  std::vector<double*> elem_matrix_2d(vecsize);

  std::vector<double> elem_vector(vecsize, 0);

  for(size_t i=0; i<elem_matrix_2d.size(); ++i) {
    elem_matrix_2d[i] = &elem_matrix_1d[i*vecsize];
  }

  //fill our dummy elem-matrix:
  //This dummy matrix will be the same for every element. A real application
  //would form a different elem-matrix for each element.
  for(size_t i=0; i<elem_matrix_2d.size(); ++i) {
    double* row = elem_matrix_2d[i];
    if (i>=1) row[i-1] = -1;
    row[i] = 2;
    if (i<elem_matrix_2d.size()-1) row[i+1] = -1;

    elem_vector[i] = 1;
  }

  std::vector<int> eqn_indices(vecsize);

  for(size_t i=0; i<part_buckets.size(); ++i) {
    stk::mesh::Bucket::iterator
      b_iter = part_buckets[i]->begin(),
             b_end  = part_buckets[i]->end();
    for(; b_iter != b_end; ++b_iter) {
      stk::mesh::Entity& elem = *b_iter;
      rel = elem.relations(stk::mesh::fem::FEMMetaData::NODE_RANK);
      for(int j=0; rel.first != rel.second; ++rel.first, ++j) {
        node_ids[j] = rel.first->entity()->identifier();
      }

      matgraph->getPatternIndices(pattern_id, &node_ids[0], eqn_indices);

      matrix.sumIn(vecsize, &eqn_indices[0], vecsize, &eqn_indices[0],
                    &elem_matrix_2d[0]);
      rhs.sumIn(vecsize, &eqn_indices[0], &elem_vector[0]);
    }
  }
}