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