Ejemplo n.º 1
0
   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];
      }
    }
  }
}