void compute_dual_nodal_volume() { auto basis = sierra::nalu::LagrangeBasis(elemDesc->inverseNodeMap, elemDesc->nodeLocs1D); auto quad = sierra::nalu::TensorProductQuadratureRule("GaussLegendre", poly_order); sierra::nalu::HigherOrderHexSCV meSCV(*elemDesc, basis, quad); // extract master element specifics const int nodesPerElement = meSCV.nodesPerElement_; const int numScvIp = meSCV.numIntPoints_; const int* ipNodeMap = meSCV.ipNodeMap(); // define scratch fields std::vector<double> ws_scv_volume(numScvIp); std::vector<double> ws_coordinates(nodesPerElement * nDim); const stk::mesh::Selector superSelector = stk::mesh::selectUnion(superParts); const auto& elem_buckets = bulk->get_buckets(stk::topology::ELEM_RANK, superSelector); sierra::nalu::bucket_loop(elem_buckets, [&](stk::mesh::Entity elem) { stk::mesh::Entity const* node_rels = bulk->begin_nodes(elem); for (int ni = 0; ni < nodesPerElement; ++ni) { const double* const coords = stk::mesh::field_data(*coordField, node_rels[ni]); const int offSet = ni * nDim; for (unsigned j = 0; j < nDim; ++j) { ws_coordinates[offSet + j] = coords[j]; } } // compute integration point volume double scv_error = 1.0; meSCV.determinant(1, ws_coordinates.data(), ws_scv_volume.data(), &scv_error); // assemble dual volume while scattering ip volume for (int ip = 0; ip < numScvIp; ++ip) { *stk::mesh::field_data(*dnvField, node_rels[ipNodeMap[ip]]) += ws_scv_volume[ip]; } }); }
//-------------------------------------------------------------------------- //-------- add_elem_gradq -------------------------------------------------- //-------------------------------------------------------------------------- void AssembleNodalGradElemContactAlgorithm::add_elem_gradq() { stk::mesh::MetaData & meta_data = realm_.meta_data(); stk::mesh::BulkData & bulk_data = realm_.bulk_data(); // fields VectorFieldType *coordinates = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, realm_.get_coordinates_name()); VectorFieldType *haloDxj = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, "halo_dxj"); const int nDim = meta_data.spatial_dimension(); // loop over locally owned faces and construct missing elemental contributions stk::mesh::Selector s_locally_owned = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& face_buckets = realm_.get_buckets( meta_data.side_rank(), s_locally_owned ); for ( stk::mesh::BucketVector::const_iterator ib = face_buckets.begin(); ib != face_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib; // extract master element; hard coded for quad or hex; // quad is always true for 2D while for 3D, either hex or wedge apply const stk::topology & theElemTopo = (nDim == 2) ? stk::topology::QUAD_4_2D : stk::topology::HEX_8; const int num_face_nodes = (nDim == 2) ? 2 : 4; std::vector<int> face_node_ordinals(num_face_nodes); // extract master element for extruded element type MasterElement *meSCS = realm_.get_surface_master_element(theElemTopo); MasterElement *meSCV = realm_.get_volume_master_element(theElemTopo); // extract master element specifics const int nodesPerElement = meSCV->nodesPerElement_; const int numScsIp = meSCS->numIntPoints_; // mapping between exposed face and extruded element's overlapping face const int *faceNodeOnExtrudedElem = meSCS->faceNodeOnExtrudedElem(); // mapping between exposed face and extruded element's opposing face const int *opposingNodeOnExtrudedElem = meSCS->opposingNodeOnExtrudedElem(); // mapping between exposed face scs ips and halo edge const int *faceScsIpOnExtrudedElem = meSCS->faceScsIpOnExtrudedElem(); // mapping between exposed face scs ips and exposed face edge const int *faceScsIpOnFaceEdges = meSCS->faceScsIpOnFaceEdges(); // alignment of face:edge ordering and scsip area vector const double *edgeAlignedArea = meSCS->edgeAlignedArea(); // define scratch field std::vector<double > ws_coordinates(nodesPerElement*nDim); std::vector<double > ws_scs_areav(numScsIp*nDim); std::vector<double > ws_scalarQ(nodesPerElement); std::vector<double> ws_shape_function(numScsIp*nodesPerElement); // pointers double *p_shape_function = &ws_shape_function[0]; meSCS->shape_fcn(&p_shape_function[0]); const stk::mesh::Bucket::size_type length = b.size(); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // get face stk::mesh::Entity face = b[k]; // extract the connected element to this exposed face; should be single in size! stk::mesh::Entity const* face_elem_rels = bulk_data.begin_elements(face); stk::mesh::ConnectivityOrdinal const* face_elem_ords = bulk_data.begin_element_ordinals(face); const int num_elements = bulk_data.num_elements(face); ThrowRequire( num_elements == 1 ); stk::mesh::Entity element = face_elem_rels[0]; const int face_ordinal = face_elem_ords[0]; theElemTopo.side_node_ordinals(face_ordinal, face_node_ordinals.begin()); // concentrate on loading up the nodal coordinates/scalarQ for the extruded element stk::mesh::Entity const * face_node_rels = b.begin_nodes(k); int num_nodes = b.num_nodes(k); for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = face_node_rels[ni]; const double * coords = stk::mesh::field_data(*coordinates, node); const double * hDxj = stk::mesh::field_data( *haloDxj, node ); const int faceNode = faceNodeOnExtrudedElem[face_ordinal*num_nodes + ni]; const int opposingNode = opposingNodeOnExtrudedElem[face_ordinal*num_nodes + ni]; const int offSetFN = faceNode*nDim; const int offSetON = opposingNode*nDim; // populate scalars ws_scalarQ[faceNode] = *stk::mesh::field_data(*scalarQ_, node); ws_scalarQ[opposingNode] = *stk::mesh::field_data(*haloQ_, node); // now vectors for ( int j=0; j < nDim; ++j ) { // face node ws_coordinates[offSetFN+j] = coords[j]; ws_coordinates[offSetON+j] = coords[j] + hDxj[j]; } } // compute scs integration point areavec double scs_error = 0.0; meSCS->determinant(1, &ws_coordinates[0], &ws_scs_areav[0], &scs_error); // assemble halo ip contribution for face node for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = face_node_rels[ni]; const double &dualNodalVolume = *stk::mesh::field_data( *dualNodalVolume_, node ); // area vector for halo edge; // face ordinal 0 for extruded element has all scs area vectors pointing from face to opposing face const int scsIp = faceScsIpOnExtrudedElem[face_ordinal*num_nodes + ni]; // interpolate element nodal values to this scsIp of interest double scalarQ_scsIp = 0.0; for ( int ic = 0; ic < nodesPerElement; ++ic ) scalarQ_scsIp += p_shape_function[scsIp*nodesPerElement + ic]*ws_scalarQ[ic]; // add in nodal gradient contribution double *dqdx = stk::mesh::field_data( *dqdx_, node ); for ( int j = 0; j < nDim; ++j ) { dqdx[j] += scalarQ_scsIp*ws_scs_areav[scsIp*nDim+j]/dualNodalVolume; } } // deal with edges on the exposed face and each stk::mesh::Entity const* elem_node_rels = bulk_data.begin_nodes(element); // face edge relations; if this is 2D then the face is a edge and size is unity stk::mesh::Entity const* face_edge_rels = bulk_data.begin_edges(face); const int num_face_edges = bulk_data.num_edges(face); int num_edges = (nDim == 3) ? num_face_edges : 1; for ( int i = 0; i < num_edges; ++i ) { // get edge stk::mesh::Entity edge = (nDim == 3) ? face_edge_rels[i] : face; // get the relations from edge stk::mesh::Entity const* edge_node_rels = bulk_data.begin_nodes(edge); const int edge_num_nodes = bulk_data.num_nodes(edge); // sanity check on num nodes if ( edge_num_nodes != 2 ){ throw std::runtime_error("num nodes is not 2"); } // extract ip for this edge const int scsIp = faceScsIpOnFaceEdges[face_ordinal*num_edges + i]; // correct area for edge and scs area vector from extruded element alignment const double alignmentFac = edgeAlignedArea[face_ordinal*num_edges + i]; // interpolate element nodal values to this scsIp of interest double scalarQ_scsIp = 0.0; for ( int ic = 0; ic < nodesPerElement; ++ic ) scalarQ_scsIp += p_shape_function[scsIp*nodesPerElement + ic]*ws_scalarQ[ic]; // left and right nodes on the edge stk::mesh::Entity nodeL = edge_node_rels[0]; stk::mesh::Entity nodeR = edge_node_rels[1]; // does edge point correctly const int leftNode = face_node_ordinals[i]; const size_t iglob_Lelem = bulk_data.identifier(elem_node_rels[leftNode]); const size_t iglob_Ledge = bulk_data.identifier(edge_node_rels[0]); // determine the sign value for area vector; if Left node is the same, // then the element and edge relations are aligned const double sign = ( iglob_Lelem == iglob_Ledge ) ? 1.0 : -1.0; // add in nodal gradient contribution double *dqdxL = stk::mesh::field_data( *dqdx_, nodeL ); double *dqdxR = stk::mesh::field_data( *dqdx_, nodeR ); const double &dualNodalVolumeL = *stk::mesh::field_data( *dualNodalVolume_, nodeL ); const double &dualNodalVolumeR = *stk::mesh::field_data( *dualNodalVolume_, nodeR ); for ( int j = 0; j < nDim; ++j ) { dqdxL[j] += scalarQ_scsIp*ws_scs_areav[scsIp*nDim+j]/dualNodalVolumeL*sign*alignmentFac; dqdxR[j] -= scalarQ_scsIp*ws_scs_areav[scsIp*nDim+j]/dualNodalVolumeR*sign*alignmentFac; } } } } // parallel assembly handled elsewhere }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void ExtrusionMeshDistanceBoundaryAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_data(); stk::mesh::BulkData & bulk_data = realm_.bulk_data(); const int nDim = meta_data.spatial_dimension(); // extract extrusion factor const double extrusionCorrectionFac = realm_.solutionOptions_->extrusionCorrectionFac_; const double om_extrusioneCorrectionFac = 1.0 - extrusionCorrectionFac; //============================================ // zero out haloNormal and correction factors //============================================= VectorFieldType *haloNormal = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, "halo_normal"); ScalarFieldType *extDistCorrFac = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "extrusion_distance_correct_fac"); ScalarFieldType *extDistCorrCount = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "extrusion_distance_correct_count"); stk::mesh::Selector s_all = stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& all_node_buckets = realm_.get_buckets( stk::topology::NODE_RANK, s_all ); for ( stk::mesh::BucketVector::const_iterator ib = all_node_buckets.begin(); ib != all_node_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // pointer to data double * hNormal = stk::mesh::field_data(*haloNormal, b); double * extDCF = stk::mesh::field_data(*extDistCorrFac,b); double * extDCC = stk::mesh::field_data(*extDistCorrCount,b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { extDCF[k] = 0.0; extDCC[k] = 0.0; const size_t offSet = k*nDim; for ( int j = 0; j < nDim; ++j ) hNormal[offSet+j] = 0.0; } } //===================================================================== // compute exposed area vector; increment faces touching contact nodes //===================================================================== GenericFieldType *exposedAreaVec = meta_data.get_field<GenericFieldType>(meta_data.side_rank(), "exposed_area_vector"); VectorFieldType *coordinates = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, realm_.get_coordinates_name()); stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& face_buckets = realm_.get_buckets( meta_data.side_rank(), s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = face_buckets.begin(); ib != face_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; // extract master element MasterElement *meFC = realm_.get_surface_master_element(b.topology()); // extract master element specifics const int nodesPerElement = meFC->nodesPerElement_; const int numScsIp = meFC->numIntPoints_; // define scratch field std::vector<double > ws_coordinates(nodesPerElement*nDim); std::vector<double > ws_scs_areav(numScsIp*nDim); const stk::mesh::Bucket::size_type length = b.size(); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // face data double * areaVec = stk::mesh::field_data(*exposedAreaVec, b, k); // face node relations for nodal gather stk::mesh::Entity const * face_node_rels = b.begin_nodes(k); //=============================================== // gather nodal data; this is how we do it now.. //=============================================== int num_nodes = b.num_nodes(k); for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = face_node_rels[ni]; double * coords = stk::mesh::field_data(*coordinates, node); const int offSet = ni*nDim; for ( int j=0; j < nDim; ++j ) { ws_coordinates[offSet+j] = coords[j]; } } // compute scs integration point areavec double scs_error = 0.0; meFC->determinant(1, &ws_coordinates[0], &ws_scs_areav[0], &scs_error); for ( int ip = 0; ip < num_nodes; ++ip ) { // offset for bip area vector const int faceOffSet = ip*nDim; double aMag = 0.0; for ( int j=0; j < nDim; ++j ) { const double axj = ws_scs_areav[faceOffSet+j]; areaVec[faceOffSet+j] = axj; aMag += axj*axj; } aMag = std::sqrt(aMag); // extract node; increment count; assemble normal stk::mesh::Entity node = face_node_rels[ip]; // get nodal fields tocuhing this ip (nearest node); zeroed above double * extDCC = stk::mesh::field_data(*extDistCorrCount,node); double * hNormal = stk::mesh::field_data(*haloNormal, node); // accumulate number of faces that touch this node *extDCC += 1.0; // accumulate normal for ( int j = 0; j < nDim; ++j ) { hNormal[j] += areaVec[faceOffSet+j]/aMag; } } } } // parallel assemble correction count and nodal normals std::vector<stk::mesh::FieldBase*> sum_halo_vec; sum_halo_vec.push_back(extDistCorrCount); sum_halo_vec.push_back(haloNormal); stk::mesh::parallel_sum(bulk_data, sum_halo_vec); // normalize hNormal for ( stk::mesh::BucketVector::const_iterator ib = all_node_buckets.begin(); ib != all_node_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // pointer to data; to be modified and constant double * hNormal = stk::mesh::field_data(*haloNormal, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { const size_t offSet = k*nDim; double nMag = 0.0; for ( int j = 0; j < nDim; ++j ) { nMag += hNormal[offSet+j]*hNormal[offSet+j]; } nMag = std::sqrt(nMag); for ( int j = 0; j < nDim; ++j ) { hNormal[offSet+j] /= nMag; } } } //============================================== // assemble n^nodal_k (dot) n^bip_k //============================================== for ( stk::mesh::BucketVector::const_iterator ib = face_buckets.begin(); ib != face_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; // size some things that are useful const int num_face_nodes = b.topology().num_nodes(); const stk::mesh::Bucket::size_type length = b.size(); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // get face stk::mesh::Entity face = b[k]; // pointer to face data const double * areaVec = stk::mesh::field_data(*exposedAreaVec, face); // face node relations for nodal gather stk::mesh::Entity const* face_node_rels = bulk_data.begin_nodes(face); // one to one mapping between ips and nodes for ( int ip = 0; ip < num_face_nodes; ++ip ) { // offset for bip area vector const int faceOffSet = ip*nDim; double aMag = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; aMag += axj*axj; } aMag = std::sqrt(aMag); stk::mesh::Entity node = face_node_rels[ip]; double *hNormal = stk::mesh::field_data(*haloNormal, node); double * eDCF = stk::mesh::field_data(*extDistCorrFac, node); double sum = 0.0; for ( int j = 0; j < nDim; ++j ) { const double nj = areaVec[faceOffSet+j]/aMag; const double nodal_nj = hNormal[j]; sum += nodal_nj*nj; } *eDCF += sum; } } } // parallel assemble correction factor; not yet normalized and in inverse state std::vector<stk::mesh::FieldBase*> sum_fields(1, extDistCorrFac); stk::mesh::parallel_sum(bulk_data, sum_fields); //============================================== // compute final nodal extrusion distance //============================================== VectorFieldType *haloDxj = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, "halo_dxj"); ScalarFieldType *extrusionDistance = meta_data.get_field<ScalarFieldType>(stk::topology::NODE_RANK, "extrusion_distance"); for ( stk::mesh::BucketVector::const_iterator ib = all_node_buckets.begin(); ib != all_node_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // pointer to data; to be modified and constant double * hDxj = stk::mesh::field_data(*haloDxj, b); double * eDCF = stk::mesh::field_data(*extDistCorrFac, b); const double * extDist = stk::mesh::field_data(*extrusionDistance, b); const double * eDCC = stk::mesh::field_data(*extDistCorrCount, b); const double * hNormal = stk::mesh::field_data(*haloNormal, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // choose non-planar correction; user controled to shut it off const double nonPlanarCorrection = eDCC[k]/eDCF[k]*extrusionCorrectionFac + om_extrusioneCorrectionFac; eDCF[k] = nonPlanarCorrection; const double fac = extDist[k]*nonPlanarCorrection; const size_t offSet = k*nDim; for ( int j = 0; j < nDim; ++j ) { hDxj[offSet+j] = fac*hNormal[offSet+j]; } } } }