//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleOversetSolverConstraintAlgorithm::execute() { // first thing to do is to zero out the row (lhs and rhs) prepare_constraints(); // extract the rank const int theRank = NaluEnv::self().parallel_rank(); stk::mesh::BulkData & bulkData = realm_.bulk_data(); // space for LHS/RHS (nodesPerElem+1)*numDof*(nodesPerElem+1)*numDof; (nodesPerElem+1)*numDof std::vector<double> lhs; std::vector<double> rhs; std::vector<int> scratchIds; std::vector<double> scratchVals; std::vector<stk::mesh::Entity> connected_nodes; // master element data std::vector <double > ws_general_shape_function; // interpolate nodal values to point-in-elem const int sizeOfDof = eqSystem_->linsys_->numDof(); // size interpolated value std::vector<double> qNp1Orphan(sizeOfDof, 0.0); // Parallel communication of ghosted entities has been already handled in // EquationSystems::pre_iter_work // iterate oversetInfoVec_ std::vector<OversetInfo *>::iterator ii; for( ii=realm_.oversetManager_->oversetInfoVec_.begin(); ii!=realm_.oversetManager_->oversetInfoVec_.end(); ++ii ) { // overset info object of interest OversetInfo * infoObject = (*ii); // extract element and node mesh object stk::mesh::Entity owningElement = infoObject->owningElement_; stk::mesh::Entity orphanNode = infoObject->orphanNode_; // extract the owning rank for this node const int nodeRank = bulkData.parallel_owner_rank(orphanNode); // check to see if this node is locally owned by this rank; we only want to process locally owned nodes, not shared if ( theRank != nodeRank ) continue; // get master element type for this contactInfo MasterElement *meSCS = infoObject->meSCS_; const int nodesPerElement = meSCS->nodesPerElement_; std::vector <double > elemNodalQ(nodesPerElement*sizeOfDof); std::vector <double > shpfc(nodesPerElement); // resize some things; matrix related const int npePlusOne = nodesPerElement+1; const int lhsSize = npePlusOne*sizeOfDof*npePlusOne*sizeOfDof; const int rhsSize = npePlusOne*sizeOfDof; lhs.resize(lhsSize); rhs.resize(rhsSize); scratchIds.resize(rhsSize); scratchVals.resize(rhsSize); connected_nodes.resize(npePlusOne); // algorithm related; element ws_general_shape_function.resize(nodesPerElement); // pointer to lhs/rhs double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; // zeroing of lhs/rhs for ( int k = 0; k < lhsSize; ++k ) { p_lhs[k] = 0.0; } for ( int k = 0; k < rhsSize; ++k ) { p_rhs[k] = 0.0; } // extract nodal value for scalarQ const double *qNp1Nodal = (double *)stk::mesh::field_data(*fieldQ_, orphanNode); stk::mesh::Entity const* elem_node_rels = bulkData.begin_nodes(owningElement); const int num_nodes = bulkData.num_nodes(owningElement); // now load the elemental values for future interpolation; fill in connected nodes; first connected node is orhpan connected_nodes[0] = orphanNode; for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = elem_node_rels[ni]; connected_nodes[ni+1] = node; const double *qNp1 = (double *)stk::mesh::field_data(*fieldQ_, node ); for ( int i = 0; i < sizeOfDof; ++i ) { elemNodalQ[i*nodesPerElement + ni] = qNp1[i]; } } // interpolate dof to elemental ips (assigns qNp1) meSCS->interpolatePoint( sizeOfDof, &(infoObject->isoParCoords_[0]), &elemNodalQ[0], &qNp1Orphan[0]); // lhs; extract general shape function meSCS->general_shape_fcn(1, &(infoObject->isoParCoords_[0]), &ws_general_shape_function[0]); // rhs; orphan node is defined to be the zeroth connected node for ( int i = 0; i < sizeOfDof; ++i) { const int rowOi = i * npePlusOne * sizeOfDof; const double residual = qNp1Nodal[i] - qNp1Orphan[i]; p_rhs[i] = -residual; // row is zero by design (first connected node is the orphan node); assign it fully p_lhs[rowOi+i] += 1.0; for ( int ic = 0; ic < nodesPerElement; ++ic ) { const int indexR = i + sizeOfDof*(ic+1); const int rOiR = rowOi+indexR; p_lhs[rOiR] -= ws_general_shape_function[ic]; } } // apply to linear system apply_coeff(connected_nodes, scratchIds, scratchVals, rhs, lhs, __FILE__); } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleContinuityNonConformalSolverAlgorithm::execute() { stk::mesh::BulkData & bulk_data = realm_.bulk_data(); stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // continuity equation scales by projection time scale const double dt = realm_.get_time_step(); const double gamma1 = realm_.get_gamma1(); const double projTimeScale = dt/gamma1; // deal with interpolation procedure const double interpTogether = realm_.get_mdot_interp(); const double om_interpTogether = 1.0-interpTogether; // space for LHS/RHS; nodesPerElem*nodesPerElem and nodesPerElem std::vector<double> lhs; std::vector<double> rhs; std::vector<int> scratchIds; std::vector<double> scratchVals; std::vector<stk::mesh::Entity> connected_nodes; // ip values; both boundary and opposing surface std::vector<double> currentIsoParCoords(nDim); std::vector<double> opposingIsoParCoords(nDim); std::vector<double> cNx(nDim); std::vector<double> oNx(nDim); std::vector<double> currentVelocityBip(nDim); std::vector<double> opposingVelocityBip(nDim); std::vector<double> currentRhoVelocityBip(nDim); std::vector<double> opposingRhoVelocityBip(nDim); std::vector<double> currentMeshVelocityBip(nDim); std::vector<double> currentRhoMeshVelocityBip(nDim); // pressure stabilization std::vector<double> currentGjpBip(nDim); std::vector<double> opposingGjpBip(nDim); std::vector<double> currentDpdxBip(nDim); std::vector<double> opposingDpdxBip(nDim); // mapping for -1:1 -> -0.5:0.5 volume element std::vector<double> currentElementIsoParCoords(nDim); std::vector<double> opposingElementIsoParCoords(nDim); // interpolate nodal values to point-in-elem const int sizeOfScalarField = 1; const int sizeOfVectorField = nDim; // pointers to fixed values double *p_cNx = &cNx[0]; double *p_oNx = &oNx[0]; // nodal fields to gather; face std::vector<double> ws_c_pressure; std::vector<double> ws_o_pressure; std::vector<double> ws_c_Gjp; std::vector<double> ws_o_Gjp; std::vector<double> ws_c_velocity; std::vector<double> ws_o_velocity; std::vector<double> ws_c_meshVelocity; // only require current std::vector<double> ws_c_density; std::vector<double> ws_o_density; std::vector<double> ws_o_coordinates; // only require opposing // element std::vector<double> ws_c_elem_pressure; std::vector<double> ws_o_elem_pressure; std::vector<double> ws_c_elem_coordinates; std::vector<double> ws_o_elem_coordinates; // master element data std::vector<double> ws_c_dndx; std::vector<double> ws_o_dndx; std::vector<double> ws_c_det_j; std::vector<double> ws_o_det_j; std::vector <double > ws_c_general_shape_function; std::vector <double > ws_o_general_shape_function; // deal with state ScalarFieldType &pressureNp1 = pressure_->field_of_state(stk::mesh::StateNP1); // parallel communicate ghosted entities if ( NULL != realm_.nonConformalManager_->nonConformalGhosting_ ) stk::mesh::communicate_field_data(*(realm_.nonConformalManager_->nonConformalGhosting_), ghostFieldVec_); // iterate nonConformalManager's dgInfoVec std::vector<NonConformalInfo *>::iterator ii; for( ii=realm_.nonConformalManager_->nonConformalInfoVec_.begin(); ii!=realm_.nonConformalManager_->nonConformalInfoVec_.end(); ++ii ) { // extract vector of DgInfo std::vector<std::vector<DgInfo *> > &dgInfoVec = (*ii)->dgInfoVec_; std::vector<std::vector<DgInfo*> >::iterator idg; for( idg=dgInfoVec.begin(); idg!=dgInfoVec.end(); ++idg ) { std::vector<DgInfo *> &faceDgInfoVec = (*idg); // now loop over all the DgInfo objects on this particular exposed face for ( size_t k = 0; k < faceDgInfoVec.size(); ++k ) { DgInfo *dgInfo = faceDgInfoVec[k]; // extract current/opposing face/element stk::mesh::Entity currentFace = dgInfo->currentFace_; stk::mesh::Entity opposingFace = dgInfo->opposingFace_; stk::mesh::Entity currentElement = dgInfo->currentElement_; stk::mesh::Entity opposingElement = dgInfo->opposingElement_; const int currentFaceOrdinal = dgInfo->currentFaceOrdinal_; const int opposingFaceOrdinal = dgInfo->opposingFaceOrdinal_; // master element; face and volume MasterElement * meFCCurrent = dgInfo->meFCCurrent_; MasterElement * meFCOpposing = dgInfo->meFCOpposing_; MasterElement * meSCSCurrent = dgInfo->meSCSCurrent_; MasterElement * meSCSOpposing = dgInfo->meSCSOpposing_; // local ip, ordinals, etc const int currentGaussPointId = dgInfo->currentGaussPointId_; currentIsoParCoords = dgInfo->currentIsoParCoords_; opposingIsoParCoords = dgInfo->opposingIsoParCoords_; // mapping from ip to nodes for this ordinal const int *ipNodeMap = meSCSCurrent->ipNodeMap(currentFaceOrdinal); // extract some master element info const int currentNodesPerFace = meFCCurrent->nodesPerElement_; const int opposingNodesPerFace = meFCOpposing->nodesPerElement_; const int currentNodesPerElement = meSCSCurrent->nodesPerElement_; const int opposingNodesPerElement = meSCSOpposing->nodesPerElement_; // resize some things; matrix related const int totalNodes = currentNodesPerElement + opposingNodesPerElement; const int lhsSize = totalNodes*totalNodes; const int rhsSize = totalNodes; lhs.resize(lhsSize); rhs.resize(rhsSize); scratchIds.resize(rhsSize); scratchVals.resize(rhsSize); connected_nodes.resize(totalNodes); // algorithm related; face ws_c_pressure.resize(currentNodesPerFace); ws_o_pressure.resize(opposingNodesPerFace); ws_c_Gjp.resize(currentNodesPerFace*nDim); ws_o_Gjp.resize(opposingNodesPerFace*nDim); ws_c_velocity.resize(currentNodesPerFace*nDim); ws_o_velocity.resize(opposingNodesPerFace*nDim); ws_c_meshVelocity.resize(currentNodesPerFace*nDim); ws_c_density.resize(currentNodesPerFace); ws_o_density.resize(opposingNodesPerFace); ws_o_coordinates.resize(opposingNodesPerFace*nDim); ws_c_general_shape_function.resize(currentNodesPerFace); ws_o_general_shape_function.resize(opposingNodesPerFace); // algorithm related; element; dndx will be at a single gauss point ws_c_elem_pressure.resize(currentNodesPerElement); ws_o_elem_pressure.resize(opposingNodesPerElement); ws_c_elem_coordinates.resize(currentNodesPerElement*nDim); ws_o_elem_coordinates.resize(opposingNodesPerElement*nDim); ws_c_dndx.resize(nDim*currentNodesPerElement); ws_o_dndx.resize(nDim*opposingNodesPerElement); ws_c_det_j.resize(1); ws_o_det_j.resize(1); // pointers double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; // face double *p_c_pressure = &ws_c_pressure[0]; double *p_o_pressure = &ws_o_pressure[0]; double *p_c_Gjp = &ws_c_Gjp[0]; double *p_o_Gjp = &ws_o_Gjp[0]; double *p_c_velocity = &ws_c_velocity[0]; double *p_o_velocity= &ws_o_velocity[0]; double *p_c_meshVelocity = &ws_c_meshVelocity[0]; double *p_c_density = &ws_c_density[0]; double *p_o_density = &ws_o_density[0]; double *p_o_coordinates = &ws_o_coordinates[0]; // element double *p_c_elem_pressure = &ws_c_elem_pressure[0]; double *p_o_elem_pressure = &ws_o_elem_pressure[0]; double *p_c_elem_coordinates = &ws_c_elem_coordinates[0]; double *p_o_elem_coordinates = &ws_o_elem_coordinates[0]; // me pointers double *p_c_general_shape_function = &ws_c_general_shape_function[0]; double *p_o_general_shape_function = &ws_o_general_shape_function[0]; double *p_c_dndx = &ws_c_dndx[0]; double *p_o_dndx = &ws_o_dndx[0]; // populate current face_node_ordinals const int *c_face_node_ordinals = meSCSCurrent->side_node_ordinals(currentFaceOrdinal); // gather current face data stk::mesh::Entity const* current_face_node_rels = bulk_data.begin_nodes(currentFace); const int current_num_face_nodes = bulk_data.num_nodes(currentFace); for ( int ni = 0; ni < current_num_face_nodes; ++ni ) { stk::mesh::Entity node = current_face_node_rels[ni]; // gather; scalar p_c_pressure[ni] = *stk::mesh::field_data(pressureNp1, node); p_c_density[ni] = *stk::mesh::field_data(*density_, node); // gather; vector const double *velocity = stk::mesh::field_data(*velocity_, node ); const double *meshVelocity = stk::mesh::field_data(*meshVelocity_, node ); const double *Gjp = stk::mesh::field_data(*Gjp_, node ); for ( int i = 0; i < nDim; ++i ) { const int offSet = i*current_num_face_nodes + ni; p_c_velocity[offSet] = velocity[i]; p_c_meshVelocity[offSet] = meshVelocity[i]; p_c_Gjp[offSet] = Gjp[i]; } } // populate opposing face_node_ordinals const int *o_face_node_ordinals = meSCSOpposing->side_node_ordinals(opposingFaceOrdinal); // gather opposing face data stk::mesh::Entity const* opposing_face_node_rels = bulk_data.begin_nodes(opposingFace); const int opposing_num_face_nodes = bulk_data.num_nodes(opposingFace); for ( int ni = 0; ni < opposing_num_face_nodes; ++ni ) { stk::mesh::Entity node = opposing_face_node_rels[ni]; // gather; scalar p_o_pressure[ni] = *stk::mesh::field_data(pressureNp1, node); p_o_density[ni] = *stk::mesh::field_data(*density_, node); // gather; vector const double *velocity = stk::mesh::field_data(*velocity_, node ); const double *Gjp = stk::mesh::field_data(*Gjp_, node ); const double *coords = stk::mesh::field_data(*coordinates_, node); for ( int i = 0; i < nDim; ++i ) { const int offSet = i*opposing_num_face_nodes + ni; p_o_velocity[offSet] = velocity[i]; p_o_Gjp[offSet] = Gjp[i]; p_o_coordinates[ni*nDim+i] = coords[i]; } } // gather current element data stk::mesh::Entity const* current_elem_node_rels = bulk_data.begin_nodes(currentElement); const int current_num_elem_nodes = bulk_data.num_nodes(currentElement); for ( int ni = 0; ni < current_num_elem_nodes; ++ni ) { stk::mesh::Entity node = current_elem_node_rels[ni]; // set connected nodes connected_nodes[ni] = node; // gather; scalar p_c_elem_pressure[ni] = *stk::mesh::field_data(pressureNp1, node); // gather; vector const double *coords = stk::mesh::field_data(*coordinates_, node); const int niNdim = ni*nDim; for ( int i = 0; i < nDim; ++i ) { p_c_elem_coordinates[niNdim+i] = coords[i]; } } // gather opposing element data; sneak in second connected nodes stk::mesh::Entity const* opposing_elem_node_rels = bulk_data.begin_nodes(opposingElement); const int opposing_num_elem_nodes = bulk_data.num_nodes(opposingElement); for ( int ni = 0; ni < opposing_num_elem_nodes; ++ni ) { stk::mesh::Entity node = opposing_elem_node_rels[ni]; // set connected nodes connected_nodes[ni+current_num_elem_nodes] = node; // gather; scalar p_o_elem_pressure[ni] = *stk::mesh::field_data(pressureNp1, node); // gather; vector const double *coords = stk::mesh::field_data(*coordinates_, node); const int niNdim = ni*nDim; for ( int i = 0; i < nDim; ++i ) { p_o_elem_coordinates[niNdim+i] = coords[i]; } } // compute opposing normal through master element call, not using oppoing exposed area meFCOpposing->general_normal(&opposingIsoParCoords[0], &p_o_coordinates[0], &p_oNx[0]); // pointer to face data const double * c_areaVec = stk::mesh::field_data(*exposedAreaVec_, currentFace); double c_amag = 0.0; for ( int j = 0; j < nDim; ++j ) { const double c_axj = c_areaVec[currentGaussPointId*nDim+j]; c_amag += c_axj*c_axj; } c_amag = std::sqrt(c_amag); // now compute normal for ( int i = 0; i < nDim; ++i ) { p_cNx[i] = c_areaVec[currentGaussPointId*nDim+i]/c_amag; } // override opposing normal if ( useCurrentNormal_ ) { for ( int i = 0; i < nDim; ++i ) p_oNx[i] = -p_cNx[i]; } // project from side to element; method deals with the -1:1 isInElement range to the proper underlying CVFEM range meSCSCurrent->sidePcoords_to_elemPcoords(currentFaceOrdinal, 1, ¤tIsoParCoords[0], ¤tElementIsoParCoords[0]); meSCSOpposing->sidePcoords_to_elemPcoords(opposingFaceOrdinal, 1, &opposingIsoParCoords[0], &opposingElementIsoParCoords[0]); // compute dndx double scs_error = 0.0; meSCSCurrent->general_face_grad_op(currentFaceOrdinal, ¤tElementIsoParCoords[0], &p_c_elem_coordinates[0], &p_c_dndx[0], &ws_c_det_j[0], &scs_error); meSCSOpposing->general_face_grad_op(opposingFaceOrdinal, &opposingElementIsoParCoords[0], &p_o_elem_coordinates[0], &p_o_dndx[0], &ws_o_det_j[0], &scs_error); // current inverse length scale; can loop over face nodes to avoid "nodesOnFace" array double currentInverseLength = 0.0; for ( int ic = 0; ic < current_num_face_nodes; ++ic ) { const int faceNodeNumber = c_face_node_ordinals[ic]; const int offSetDnDx = faceNodeNumber*nDim; // single intg. point for ( int j = 0; j < nDim; ++j ) { const double nxj = p_cNx[j]; const double dndxj = p_c_dndx[offSetDnDx+j]; currentInverseLength += dndxj*nxj; } } // opposing inverse length scale; can loop over face nodes to avoid "nodesOnFace" array double opposingInverseLength = 0.0; for ( int ic = 0; ic < opposing_num_face_nodes; ++ic ) { const int faceNodeNumber = o_face_node_ordinals[ic]; const int offSetDnDx = faceNodeNumber*nDim; // single intg. point for ( int j = 0; j < nDim; ++j ) { const double nxj = p_oNx[j]; const double dndxj = p_o_dndx[offSetDnDx+j]; opposingInverseLength += dndxj*nxj; } } // projected nodal gradient; zero out for ( int j = 0; j < nDim; ++j ) { currentDpdxBip[j] = 0.0; opposingDpdxBip[j] = 0.0; } // current pressure gradient for ( int ic = 0; ic < currentNodesPerElement; ++ic ) { const int offSetDnDx = ic*nDim; // single intg. point const double pNp1 = p_c_elem_pressure[ic]; for ( int j = 0; j < nDim; ++j ) { const double dndxj = p_c_dndx[offSetDnDx+j]; currentDpdxBip[j] += dndxj*pNp1; } } // opposing pressure gradient for ( int ic = 0; ic < opposingNodesPerElement; ++ic ) { const int offSetDnDx = ic*nDim; // single intg. point const double pNp1 = p_o_elem_pressure[ic]; for ( int j = 0; j < nDim; ++j ) { const double dndxj = p_o_dndx[offSetDnDx+j]; opposingDpdxBip[j] += dndxj*pNp1; } } // interpolate to boundary ips double currentPressureBip = 0.0; meFCCurrent->interpolatePoint( sizeOfScalarField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_pressure[0], ¤tPressureBip); double opposingPressureBip = 0.0; meFCOpposing->interpolatePoint( sizeOfScalarField, &(dgInfo->opposingIsoParCoords_[0]), &ws_o_pressure[0], &opposingPressureBip); // velocity meFCCurrent->interpolatePoint( sizeOfVectorField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_velocity[0], ¤tVelocityBip[0]); meFCOpposing->interpolatePoint( sizeOfVectorField, &(dgInfo->opposingIsoParCoords_[0]), &ws_o_velocity[0], &opposingVelocityBip[0]); // mesh velocity; only required at current meFCCurrent->interpolatePoint( sizeOfVectorField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_meshVelocity[0], ¤tMeshVelocityBip[0]); // projected nodal gradient meFCCurrent->interpolatePoint( sizeOfVectorField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_Gjp[0], ¤tGjpBip[0]); meFCOpposing->interpolatePoint( sizeOfVectorField, &(dgInfo->opposingIsoParCoords_[0]), &ws_o_Gjp[0], &opposingGjpBip[0]); // density double currentDensityBip = 0.0; meFCCurrent->interpolatePoint( sizeOfScalarField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_density[0], ¤tDensityBip); double opposingDensityBip = 0.0; meFCOpposing->interpolatePoint( sizeOfScalarField, &(dgInfo->opposingIsoParCoords_[0]), &ws_o_density[0], &opposingDensityBip); // product of density and velocity; current (take over previous nodal value for velocity) for ( int ni = 0; ni < current_num_face_nodes; ++ni ) { const double density = p_c_density[ni]; for ( int i = 0; i < nDim; ++i ) { const int offSet = i*current_num_face_nodes + ni; p_c_velocity[offSet] *= density; p_c_meshVelocity[offSet] *= density; } } // opposite for ( int ni = 0; ni < opposing_num_face_nodes; ++ni ) { const double density = p_o_density[ni]; for ( int i = 0; i < nDim; ++i ) { const int offSet = i*opposing_num_face_nodes + ni; p_o_velocity[offSet] *= density; } } // interpolate velocity with density scaling meFCCurrent->interpolatePoint( sizeOfVectorField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_velocity[0], ¤tRhoVelocityBip[0]); meFCOpposing->interpolatePoint( sizeOfVectorField, &(dgInfo->opposingIsoParCoords_[0]), &ws_o_velocity[0], &opposingRhoVelocityBip[0]); // interpolate mesh velocity with density scaling; only current meFCCurrent->interpolatePoint( sizeOfVectorField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_meshVelocity[0], ¤tRhoMeshVelocityBip[0]); // zero lhs/rhs for ( int p = 0; p < lhsSize; ++p ) p_lhs[p] = 0.0; for ( int p = 0; p < rhsSize; ++p ) p_rhs[p] = 0.0; const double penaltyIp = projTimeScale*0.5*(currentInverseLength + opposingInverseLength); double ncFlux = 0.0; double ncPstabFlux = 0.0; for ( int j = 0; j < nDim; ++j ) { const double cRhoVelocity = interpTogether*currentRhoVelocityBip[j] + om_interpTogether*currentDensityBip*currentVelocityBip[j]; const double oRhoVelocity = interpTogether*opposingRhoVelocityBip[j] + om_interpTogether*opposingDensityBip*opposingVelocityBip[j]; const double cRhoMeshVelocity = interpTogether*currentRhoMeshVelocityBip[j] + om_interpTogether*currentDensityBip*currentMeshVelocityBip[j]; ncFlux += 0.5*(cRhoVelocity*p_cNx[j] - oRhoVelocity*p_oNx[j]) - meshMotionFac_*cRhoMeshVelocity*p_cNx[j]; const double cPstab = currentDpdxBip[j] - currentGjpBip[j]; const double oPstab = opposingDpdxBip[j] - opposingGjpBip[j]; ncPstabFlux += 0.5*(cPstab*p_cNx[j] - oPstab*p_oNx[j]); } const double mdot = (ncFlux - includePstab_*projTimeScale*ncPstabFlux + penaltyIp*(currentPressureBip - opposingPressureBip))*c_amag; // form residual const int nn = ipNodeMap[currentGaussPointId]; p_rhs[nn] -= mdot/projTimeScale; // set-up row for matrix const int rowR = nn*totalNodes; double lhsFac = penaltyIp*c_amag/projTimeScale; // sensitivities; current face (penalty); use general shape function for this single ip meFCCurrent->general_shape_fcn(1, ¤tIsoParCoords[0], &ws_c_general_shape_function[0]); for ( int ic = 0; ic < currentNodesPerFace; ++ic ) { const int icnn = c_face_node_ordinals[ic]; const double r = p_c_general_shape_function[ic]; p_lhs[rowR+icnn] += r*lhsFac; } // sensitivities; current element (diffusion) for ( int ic = 0; ic < currentNodesPerElement; ++ic ) { const int offSetDnDx = ic*nDim; // single intg. point double lhscd = 0.0; for ( int j = 0; j < nDim; ++j ) { const double nxj = p_cNx[j]; const double dndxj = p_c_dndx[offSetDnDx+j]; lhscd -= dndxj*nxj; } p_lhs[rowR+ic] += 0.5*lhscd*c_amag*includePstab_; } // sensitivities; opposing face (penalty); use general shape function for this single ip meFCOpposing->general_shape_fcn(1, &opposingIsoParCoords[0], &ws_o_general_shape_function[0]); for ( int ic = 0; ic < opposingNodesPerFace; ++ic ) { const int icnn = o_face_node_ordinals[ic]; const double r = p_o_general_shape_function[ic]; p_lhs[rowR+icnn+currentNodesPerElement] -= r*lhsFac; } // sensitivities; opposing element (diffusion) for ( int ic = 0; ic < opposingNodesPerElement; ++ic ) { const int offSetDnDx = ic*nDim; // single intg. point double lhscd = 0.0; for ( int j = 0; j < nDim; ++j ) { const double nxj = p_oNx[j]; const double dndxj = p_o_dndx[offSetDnDx+j]; lhscd -= dndxj*nxj; } p_lhs[rowR+ic+currentNodesPerElement] -= 0.5*lhscd*c_amag*includePstab_; } apply_coeff(connected_nodes, scratchIds, scratchVals, rhs, lhs, __FILE__); } } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleScalarEdgeDiffContactSolverAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_data(); stk::mesh::BulkData & bulk_data = realm_.bulk_data(); const int nDim = meta_data.spatial_dimension(); // space for LHS/RHS (nodesPerElem+1)*(nodesPerElem+1); nodesPerElem+1 std::vector<double> lhs; std::vector<double> rhs; std::vector<int> scratchIds; std::vector<double> scratchVals; std::vector<stk::mesh::Entity> connected_nodes; // deal with state ScalarFieldType &scalarQNp1 = scalarQ_->field_of_state(stk::mesh::StateNP1); // space for interpolated right state (halo) double qNp1R; double diffFluxCoeffR; std::vector<double> dqdxR(nDim); // interpolate nodal values to point-in-elem const int sizeOfScalarField = 1; const int sizeOfVectorField = nDim; // parallel communicate ghosted entities if ( NULL != realm_.contactManager_->contactGhosting_ ) stk::mesh::communicate_field_data(*(realm_.contactManager_->contactGhosting_), ghostFieldVec_); // iterate contactInfoVec_ std::vector<ContactInfo *>::iterator ii; for( ii=realm_.contactManager_->contactInfoVec_.begin(); ii!=realm_.contactManager_->contactInfoVec_.end(); ++ii ) { // get master element type for this contactInfo MasterElement *meSCS = (*ii)->meSCS_; const int nodesPerElement = meSCS->nodesPerElement_; std::vector <double > elemNodalQ(nodesPerElement); std::vector <double > elemNodalDiffFluxCoeff(nodesPerElement); std::vector <double > elemNodalCoords(nDim*nodesPerElement); std::vector <double > elemNodalDqdx(nDim*nodesPerElement); std::vector <double > shpfc(nodesPerElement); // resize some things; matrix related const int npePlusOne = nodesPerElement+1; const int lhsSize = npePlusOne*npePlusOne; const int rhsSize = npePlusOne; lhs.resize(lhsSize); rhs.resize(rhsSize); scratchIds.resize(rhsSize); scratchVals.resize(rhsSize); connected_nodes.resize(npePlusOne); // pointer to lhs/rhs double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; // iterate halo face nodes std::map<uint64_t, HaloInfo *>::iterator iterHalo; for (iterHalo = (*ii)->haloInfoMap_.begin(); iterHalo != (*ii)->haloInfoMap_.end(); ++iterHalo) { // halo info object of interest HaloInfo * infoObject = (*iterHalo).second; // zeroing of lhs/rhs for ( int k = 0; k < lhsSize; ++k ) { p_lhs[k] = 0.0; } for ( int k = 0; k < rhsSize; ++k ) { p_rhs[k] = 0.0; } // pointer to edge area vector const double *p_areaVec = &infoObject->haloEdgeAreaVec_[0]; // extract element mesh object and global id for face node stk::mesh::Entity elem = infoObject->owningElement_; stk::mesh::Entity const* elem_node_rels = bulk_data.begin_nodes(elem); const int num_nodes = bulk_data.num_nodes(elem); // now load the elemental values for future interpolation; fill in connected nodes connected_nodes[0] = infoObject->faceNode_; for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = elem_node_rels[ni]; connected_nodes[ni+1] = node; elemNodalQ[ni] = *stk::mesh::field_data(*scalarQ_, node); elemNodalDiffFluxCoeff[ni] = *stk::mesh::field_data(*diffFluxCoeff_, node); // load up vectors const double * Gjq = stk::mesh::field_data(*dqdx_, node ); const double * coords = stk::mesh::field_data(*coordinates_, node ); for ( int j = 0; j < nDim; ++j ) { const int offSet = j*nodesPerElement +ni; elemNodalDqdx[offSet] = Gjq[j]; elemNodalCoords[offSet] = coords[j]; } } // extract nodal fields; right state is Halo and requires inperpolation const double *coordL = stk::mesh::field_data(*coordinates_, infoObject->faceNode_); const double *coordR = &infoObject->haloNodalCoords_[0]; const double qNp1L = *stk::mesh::field_data(scalarQNp1, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfScalarField, &(infoObject->isoParCoords_[0]), &elemNodalQ[0], &qNp1R); // possible Hermite polynomial interpolation if (NULL != hermite_) { double qNp1H = 0; hermite_->do_hermite(&elemNodalQ[0], &elemNodalCoords[0], &elemNodalDqdx[0], &coordR[0], qNp1H); qNp1R = qNp1H; } const double diffFluxCoeffL = *stk::mesh::field_data(*diffFluxCoeff_, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfScalarField, &(infoObject->isoParCoords_[0]), &elemNodalDiffFluxCoeff[0], &diffFluxCoeffR); // deal with nodal dqdx const double *dqdxL = stk::mesh::field_data(*dqdx_, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfVectorField, &(infoObject->isoParCoords_[0]), &elemNodalDqdx[0], &(dqdxR[0])); // ip props const double viscIp = 0.5*(diffFluxCoeffL + diffFluxCoeffR); // compute geometry double axdx = 0.0; double asq = 0.0; for (int j = 0; j < nDim; ++j ) { const double dxj = coordR[j] - coordL[j]; const double axj = p_areaVec[j]; axdx += axj*dxj; asq += axj*axj; } const double inv_axdx = 1.0/axdx; // NOC double nonOrth = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = p_areaVec[j]; const double dxj = coordR[j] - coordL[j]; // now non-orth (over-relaxed procedure of Jasek) const double kxj = axj - asq*inv_axdx*dxj; const double GjIp = 0.5*(dqdxL[j] + dqdxR[j]); nonOrth += -viscIp*kxj*GjIp; } // iterate owning element nodes and form pair meSCS->general_shape_fcn(1, &(infoObject->isoParCoords_[0]), &shpfc[0]); const double lhsFac = -viscIp*asq*inv_axdx; const double diffFlux = lhsFac*(qNp1R-qNp1L) + nonOrth; // setup for LHS; row left is easy - simply zero // left node (face) p_rhs[0] = -diffFlux; p_lhs[0] = -lhsFac; for ( int ni = 0; ni < num_nodes; ++ni ) { p_lhs[ni+1] = lhsFac*shpfc[ni]; } // apply to linear system apply_coeff(connected_nodes, scratchIds, scratchVals, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleMomentumEdgeContactSolverAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_data(); stk::mesh::BulkData & bulk_data = realm_.bulk_data(); const int nDim = meta_data.spatial_dimension(); const double small = 1.0e-16; // extract user advection options (allow to potentially change over time) const std::string dofName = "velocity"; const double alpha = realm_.get_alpha_factor(dofName); const double alphaUpw = realm_.get_alpha_upw_factor(dofName); const double hoUpwind = realm_.get_upw_factor(dofName); const bool useLimiter = realm_.primitive_uses_limiter(dofName); // one minus flavor const double om_alpha = 1.0-alpha; const double om_alphaUpw = 1.0-alphaUpw; // space for LHS/RHS; (nodesPerElem+1)*nDim*(nodesPerElem+1)*nDim; (nodesPerElem+1)*nDim std::vector<double> lhs; std::vector<double> rhs; std::vector<stk::mesh::Entity> connected_nodes; // space for dui/dxj. This variable is the modifed gradient with NOC std::vector<double> duidxj(nDim*nDim); // extrapolated value from the L/R direction std::vector<double> uIpL(nDim); std::vector<double> uIpR(nDim); // limiter values from the L/R direction, 0:1 std::vector<double> limitL(nDim,1.0); std::vector<double> limitR(nDim,1.0); // extrapolated gradient from L/R direction std::vector<double> duL(nDim); std::vector<double> duR(nDim); // pointers for fast access double *p_duidxj = &duidxj[0]; double *p_uIpL = &uIpL[0]; double *p_uIpR = &uIpR[0]; double *p_limitL = &limitL[0]; double *p_limitR = &limitR[0]; double *p_duL = &duL[0]; double *p_duR = &duR[0]; // space for interpolated right state (halo) double densityR; double viscosityR; std::vector<double> uNp1R(nDim); std::vector<double> dudxR(nDim*nDim); // interpolate nodal values to point-in-elem const int sizeOfScalarField = 1; const int sizeOfVectorField = nDim; const int sizeOfTensorField = nDim*nDim; // deal with state VectorFieldType &velocityNp1 = velocity_->field_of_state(stk::mesh::StateNP1); ScalarFieldType &densityNp1 = density_->field_of_state(stk::mesh::StateNP1); // mesh motion std::vector<double> vrtmL(nDim); std::vector<double> vrtmR(nDim); double * p_vrtmL = &vrtmL[0]; double * p_vrtmR = &vrtmR[0]; // parallel communicate ghosted entities if ( NULL != realm_.contactManager_->contactGhosting_ ) stk::mesh::communicate_field_data(*(realm_.contactManager_->contactGhosting_), ghostFieldVec_); // iterate contactInfoVec_ std::vector<ContactInfo *>::iterator ii; for( ii=realm_.contactManager_->contactInfoVec_.begin(); ii!=realm_.contactManager_->contactInfoVec_.end(); ++ii ) { // get master element type for this contactInfo MasterElement *meSCS = (*ii)->meSCS_; const int nodesPerElement = meSCS->nodesPerElement_; std::vector<double> elemNodalP(nodesPerElement); std::vector<double> elemNodalUnp1(nDim*nodesPerElement); std::vector<double> elemNodalVisc(nodesPerElement); std::vector<double> elemNodalRho(nodesPerElement); std::vector<double> elemNodalDudx(nDim*nDim*nodesPerElement); std::vector<double> shpfc(nodesPerElement); // resize some things; matrix related const int npePlusOne = nodesPerElement+1; const int lhsSize = npePlusOne*nDim*npePlusOne*nDim; const int rhsSize = npePlusOne*nDim; lhs.resize(lhsSize); rhs.resize(rhsSize); connected_nodes.resize(npePlusOne); // pointer to lhs/rhs double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; // scaling for lhs const double inv_nodesPerElement = 1.0/double(nodesPerElement); // iterate halo face nodes std::map<uint64_t, HaloInfo *>::iterator iterHalo; for (iterHalo = (*ii)->haloInfoMap_.begin(); iterHalo != (*ii)->haloInfoMap_.end(); ++iterHalo) { // halo info object of interest HaloInfo * infoObject = (*iterHalo).second; // zeroing of lhs/rhs for ( int k = 0; k < lhsSize; ++k ) { p_lhs[k] = 0.0; } for ( int k = 0; k < rhsSize; ++k ) { p_rhs[k] = 0.0; } // pointer to edge area vector and mdot const double *p_areaVec = &infoObject->haloEdgeAreaVec_[0]; const double tmdot = *stk::mesh::field_data(*haloMdot_, infoObject->faceNode_); // extract element mesh object and global id for face node stk::mesh::Entity elem = infoObject->owningElement_; stk::mesh::Entity const* elem_node_rels = bulk_data.begin_nodes(elem); const int num_nodes = bulk_data.num_nodes(elem); // now load the elemental values for future interpolation; fill in connected nodes connected_nodes[0] = infoObject->faceNode_; for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = elem_node_rels[ni]; connected_nodes[ni+1] = node; elemNodalRho[ni] = *stk::mesh::field_data(densityNp1, node); elemNodalVisc[ni] = *stk::mesh::field_data(*viscosity_, node); // load up vectors/tensor const double *uNp1 = stk::mesh::field_data(velocityNp1, node ); const double *dudx = stk::mesh::field_data(*dudx_, node ); for ( int i = 0; i < nDim; ++i ) { const int offSet = i*nodesPerElement + ni; elemNodalUnp1[offSet] = uNp1[i]; const int rowI = i*nDim; const int offSetT = i*nodesPerElement*nDim; for ( int j = 0; j < nDim; ++j ) { elemNodalDudx[offSetT+j*nodesPerElement+ni] = dudx[rowI+j]; } } } // extract nodal fields; right state is Halo and requires inperpolation const double *coordL = stk::mesh::field_data(*coordinates_, infoObject->faceNode_); const double *coordR = &infoObject->haloNodalCoords_[0]; const double *dudxL = stk::mesh::field_data(*dudx_, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfTensorField, &(infoObject->isoParCoords_[0]), &elemNodalDudx[0], &(dudxR[0])); const double *uNp1L = stk::mesh::field_data(velocityNp1, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfVectorField, &(infoObject->isoParCoords_[0]), &elemNodalUnp1[0], &(uNp1R[0])); const double densityL = *stk::mesh::field_data(densityNp1, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfScalarField, &(infoObject->isoParCoords_[0]), &elemNodalRho[0], &densityR); const double viscosityL = *stk::mesh::field_data(*viscosity_, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfScalarField, &(infoObject->isoParCoords_[0]), &elemNodalVisc[0], &viscosityR); // copy to velocity relative to mesh; squeeze in extrapolated values for ( int i = 0; i < nDim; ++i ) { p_vrtmL[i] = uNp1L[i]; p_vrtmR[i] = uNp1R[i]; // extrapolated du p_duL[i] = 0.0; p_duR[i] = 0.0; const int offSet = nDim*i; for ( int j = 0; j < nDim; ++j ) { const double dxj = 0.5*(coordR[j] - coordL[j]); p_duL[i] += dxj*dudxL[offSet+j]; p_duR[i] += dxj*dudxR[offSet+j]; } } // deal with mesh motion if ( meshMotion_ ) { const double * meshVelocityL = stk::mesh::field_data(*meshVelocity_, infoObject->faceNode_); const double * meshVelocityR = &(infoObject->haloMeshVelocity_[0]); for (int j = 0; j < nDim; ++j ) { p_vrtmL[j] -= meshVelocityL[j]; p_vrtmR[j] -= meshVelocityR[j]; } } // compute geometry double axdx = 0.0; double asq = 0.0; double udotx = 0.0; for (int j = 0; j < nDim; ++j ) { const double axj = p_areaVec[j]; const double dxj = coordR[j] - coordL[j]; axdx += axj*dxj; asq += axj*axj; udotx += 0.5*dxj*(p_vrtmL[j] + p_vrtmR[j]); } const double inv_axdx = 1.0/axdx; // ip props const double viscIp = 0.5*(viscosityL + viscosityR); const double diffIp = 0.5*(viscosityL/densityL + viscosityR/densityR); // Peclet factor const double pecfac = pecletFunction_->execute(std::abs(udotx)/(diffIp+small)); const double om_pecfac = 1.0-pecfac; // determine limiter if applicable if ( useLimiter ) { for ( int i = 0; i < nDim; ++i ) { const double dq = uNp1R[i] - uNp1L[i]; const double dqMl = 2.0*2.0*p_duL[i] - dq; const double dqMr = 2.0*2.0*p_duR[i] - dq; p_limitL[i] = van_leer(dqMl, dq, small); p_limitR[i] = van_leer(dqMr, dq, small); } } // final upwind extrapolation; with limiter for ( int i = 0; i < nDim; ++i ) { p_uIpL[i] = uNp1L[i] + p_duL[i]*hoUpwind*p_limitL[i]; p_uIpR[i] = uNp1R[i] - p_duR[i]*hoUpwind*p_limitR[i]; } /* form duidxj with over-relaxed procedure of Jasak: dui/dxj = GjUi +[(uiR - uiL) - GlUi*dxl]*Aj/AxDx where Gp is the interpolated pth nodal gradient for ui */ for ( int i = 0; i < nDim; ++i ) { // difference between R and L nodes for component i const double uidiff = uNp1R[i] - uNp1L[i]; // offset into all forms of dudx const int offSetI = nDim*i; // start sum for NOC contribution double GlUidxl = 0.0; for ( int l = 0; l< nDim; ++l ) { const int offSetIL = offSetI+l; const double dxl = coordR[l] - coordL[l]; const double GlUi = 0.5*(dudxL[offSetIL] + dudxR[offSetIL]); GlUidxl += GlUi*dxl; } // form full tensor dui/dxj with NOC for ( int j = 0; j < nDim; ++j ) { const int offSetIJ = offSetI+j; const double axj = p_areaVec[j]; const double GjUi = 0.5*(dudxL[offSetIJ] + dudxR[offSetIJ]); p_duidxj[offSetIJ] = GjUi + (uidiff - GlUidxl)*axj*inv_axdx; } } // divU double divU = 0.0; for ( int j = 0; j < nDim; ++j) divU += p_duidxj[j*nDim+j]; // lhs diffusion; only -mu*dui/dxj*Aj contribution for now const double dlhsfac = -viscIp*asq*inv_axdx; for ( int i = 0; i < nDim; ++i ) { // 2nd order central const double uiIp = 0.5*(uNp1R[i] + uNp1L[i]); // upwind const double uiUpwind = (tmdot > 0) ? alphaUpw*p_uIpL[i] + om_alphaUpw*uiIp : alphaUpw*p_uIpR[i] + om_alphaUpw*uiIp; // generalized central (2nd and 4th order) const double uiHatL = alpha*p_uIpL[i] + om_alpha*uiIp; const double uiHatR = alpha*p_uIpR[i] + om_alpha*uiIp; const double uiCds = 0.5*(uiHatL + uiHatR); // total advection; pressure contribution in time term expression const double aflux = tmdot*(pecfac*uiUpwind + om_pecfac*uiCds); // diffusive flux; viscous tensor doted with area vector double dflux = 2.0/3.0*viscIp*divU*p_areaVec[i]*includeDivU_; const int offSetI = nDim*i; for ( int j = 0; j < nDim; ++j ) { const int offSetTrans = nDim*j+i; const double axj = p_areaVec[j]; dflux += -viscIp*(p_duidxj[offSetI+j] + p_duidxj[offSetTrans])*axj; } // residal for total flux meSCS->general_shape_fcn(1, &(infoObject->isoParCoords_[0]), &shpfc[0]); const double tflux = aflux + dflux; const int indexL = i; // setup for LHS; row left is easy const int rowL = indexL * npePlusOne * nDim; const int rLiL = rowL+indexL; // total flux left p_rhs[indexL] -= tflux; // for ease of reading, scale left node by nodesPerElement for ( int ni = 0; ni < num_nodes; ++ni ) { const int indexR = i + nDim*(ni+1); const int rLiR = rowL+indexR; //============================== // advection first //============================== // upwind advection (includes 4th); left node double alhsfac = 0.5*(tmdot+std::abs(tmdot))*pecfac*alphaUpw + 0.5*alpha*om_pecfac*tmdot; p_lhs[rLiL] += alhsfac*inv_nodesPerElement; // upwind advection (incldues 4th); right node alhsfac = 0.5*(tmdot-std::abs(tmdot))*pecfac*alphaUpw + 0.5*alpha*om_pecfac*tmdot; p_lhs[rLiR] += alhsfac*shpfc[ni]; // central; left; collect terms on alpha and alphaUpw alhsfac = 0.5*tmdot*(pecfac*om_alphaUpw + om_pecfac*om_alpha); p_lhs[rLiL] += alhsfac*inv_nodesPerElement; p_lhs[rLiR] += alhsfac*shpfc[ni]; // central; right n/a //============================== // diffusion second //============================== const double axi = p_areaVec[i]; //diffusion; row IL p_lhs[rLiL] -= dlhsfac*inv_nodesPerElement; p_lhs[rLiR] += dlhsfac*shpfc[ni]; // diffusion; row IR; n/a // more diffusion; see theory manual for ( int j = 0; j < nDim; ++j ) { const double lhsfacNS = -viscIp*axi*p_areaVec[j]*inv_axdx; const int colL = j; const int colR = j + nDim*(ni+1); // first left; IL,IL; IL,IR p_lhs[rowL + colL] -= lhsfacNS*inv_nodesPerElement; p_lhs[rowL + colR] += lhsfacNS*shpfc[ni]; // now right, IR,IL; IR,IR; n/a } } } // apply to linear system apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleNodalGradUNonConformalAlgorithm::execute() { stk::mesh::BulkData & bulk_data = realm_.bulk_data(); stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // ip values; both boundary and opposing surface std::vector<double> currentIsoParCoords(nDim); std::vector<double> opposingIsoParCoords(nDim); // space for current/opposing interpolated value for scalarQ std::vector<double> currentVectorQBip(nDim); std::vector<double> opposingVectorQBip(nDim); // interpolate nodal values to point-in-elem const int sizeOfVectorField = nDim; // nodal fields to gather std::vector<double> ws_c_vectorQ; std::vector<double> ws_o_vectorQ; // parallel communicate ghosted entities if ( NULL != realm_.nonConformalManager_->nonConformalGhosting_ ) stk::mesh::communicate_field_data(*(realm_.nonConformalManager_->nonConformalGhosting_), ghostFieldVec_); // iterate nonConformalManager's dgInfoVec std::vector<NonConformalInfo *>::iterator ii; for( ii=realm_.nonConformalManager_->nonConformalInfoVec_.begin(); ii!=realm_.nonConformalManager_->nonConformalInfoVec_.end(); ++ii ) { // extract vector of DgInfo std::vector<std::vector<DgInfo *> > &dgInfoVec = (*ii)->dgInfoVec_; std::vector<std::vector<DgInfo*> >::iterator idg; for( idg=dgInfoVec.begin(); idg!=dgInfoVec.end(); ++idg ) { std::vector<DgInfo *> &faceDgInfoVec = (*idg); // now loop over all the DgInfo objects on this particular exposed face for ( size_t k = 0; k < faceDgInfoVec.size(); ++k ) { DgInfo *dgInfo = faceDgInfoVec[k]; // extract current/opposing face/element stk::mesh::Entity currentFace = dgInfo->currentFace_; stk::mesh::Entity opposingFace = dgInfo->opposingFace_; // master element MasterElement * meFCCurrent = dgInfo->meFCCurrent_; MasterElement * meFCOpposing = dgInfo->meFCOpposing_; // local ip, ordinals, etc const int currentGaussPointId = dgInfo->currentGaussPointId_; currentIsoParCoords = dgInfo->currentIsoParCoords_; opposingIsoParCoords = dgInfo->opposingIsoParCoords_; // extract some master element info const int currentNodesPerFace = meFCCurrent->nodesPerElement_; const int opposingNodesPerFace = meFCOpposing->nodesPerElement_; // algorithm related; face ws_c_vectorQ.resize(currentNodesPerFace*nDim); ws_o_vectorQ.resize(opposingNodesPerFace*nDim); double *p_c_vectorQ = &ws_c_vectorQ[0]; double *p_o_vectorQ = &ws_o_vectorQ[0]; // gather current face data stk::mesh::Entity const* current_face_node_rels = bulk_data.begin_nodes(currentFace); const int current_num_face_nodes = bulk_data.num_nodes(currentFace); for ( int ni = 0; ni < current_num_face_nodes; ++ni ) { stk::mesh::Entity node = current_face_node_rels[ni]; // gather... const double *qNp1 = stk::mesh::field_data(*vectorQ_, node ); for ( int i = 0; i < nDim; ++i ) { const int offSet = i*current_num_face_nodes + ni; p_c_vectorQ[offSet] = qNp1[i]; } } // gather opposing face data stk::mesh::Entity const* opposing_face_node_rels = bulk_data.begin_nodes(opposingFace); const int opposing_num_face_nodes = bulk_data.num_nodes(opposingFace); for ( int ni = 0; ni < opposing_num_face_nodes; ++ni ) { stk::mesh::Entity node = opposing_face_node_rels[ni]; // gather... const double *qNp1 = stk::mesh::field_data(*vectorQ_, node ); for ( int i = 0; i < nDim; ++i ) { const int offSet = i*opposing_num_face_nodes + ni; p_o_vectorQ[offSet] = qNp1[i]; } } meFCCurrent->interpolatePoint( sizeOfVectorField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_vectorQ[0], ¤tVectorQBip[0]); meFCOpposing->interpolatePoint( sizeOfVectorField, &(dgInfo->opposingIsoParCoords_[0]), &ws_o_vectorQ[0], &opposingVectorQBip[0]); // extract pointers to nearest node fields const int nn = currentGaussPointId; stk::mesh::Entity nNode = current_face_node_rels[nn]; const double volNN = *stk::mesh::field_data(*dualNodalVolume_, nNode); double *dqdx = stk::mesh::field_data(*dqdx_, nNode); // nearest node inverse volume double inv_volNN = 1.0/volNN; // pointer to face data const double * c_areaVec = stk::mesh::field_data(*exposedAreaVec_, currentFace); // assemble to nearest node for ( int i = 0; i < nDim; ++i ) { const int row_gradQ = i*nDim; double qip = 0.5*(currentVectorQBip[i] + opposingVectorQBip[i]); for ( int j = 0; j < nDim; ++j ) { double fac = qip*c_areaVec[currentGaussPointId*nDim+j]; dqdx[row_gradQ+j] += fac*inv_volNN; } } } } } }
//-------------------------------------------------------------------------- //-------- populate_halo_state --------------------------------------------- //-------------------------------------------------------------------------- void AssembleNodalGradElemContactAlgorithm::populate_halo_state() { stk::mesh::BulkData & bulk_data = realm_.bulk_data(); // parallel communicate ghosted entities if ( NULL != realm_.contactManager_->contactGhosting_ ) stk::mesh::communicate_field_data(*(realm_.contactManager_->contactGhosting_), ghostFieldVec_); // iterate contactInfoVec_ std::vector<ContactInfo *>::iterator ii; for( ii=realm_.contactManager_->contactInfoVec_.begin(); ii!=realm_.contactManager_->contactInfoVec_.end(); ++ii ) { // get master element type for this contactInfo MasterElement *meSCS = (*ii)->meSCS_; const int nodesPerElement = meSCS->nodesPerElement_; std::vector <double > elemNodalScalarQ(nodesPerElement); std::vector <double > shpfc(nodesPerElement); // iterate halo face nodes std::map<uint64_t, HaloInfo *>::iterator iterHalo; for (iterHalo = (*ii)->haloInfoMap_.begin(); iterHalo != (*ii)->haloInfoMap_.end(); ++iterHalo) { // halo info object of interest HaloInfo * infoObject = (*iterHalo).second; // extract element mesh object and global id for face node stk::mesh::Entity elem = infoObject->owningElement_; stk::mesh::Entity const *elem_node_rels = bulk_data.begin_nodes(elem); const unsigned num_nodes = bulk_data.num_nodes(elem); // now load the elemental values for future interpolation for ( unsigned ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = elem_node_rels[ni]; elemNodalScalarQ[ni] = *stk::mesh::field_data(*scalarQ_, node); } // extract nodal fields; right state is Halo and requires inperpolation const int sizeOfScalarField = 1; double scalarQR = 0.0; meSCS->interpolatePoint( sizeOfScalarField, &(infoObject->isoParCoords_[0]), &elemNodalScalarQ[0], &scalarQR); double *haloQ = stk::mesh::field_data(*haloQ_, infoObject->faceNode_); *haloQ = scalarQR; } } // parallel communicate locally owned nodes to shared std::vector< const stk::mesh::FieldBase *> fieldVec(1, haloQ_); stk::mesh::copy_owned_to_shared( bulk_data, fieldVec); }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleScalarNonConformalSolverAlgorithm::execute() { stk::mesh::BulkData & bulk_data = realm_.bulk_data(); stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // current flux sensitivity is based on Robin const double robinCurrentFluxFac = robinStyle_ ? 0.0 : 1.0; // space for LHS/RHS; nodesPerElem*nodesPerElem and nodesPerElem std::vector<double> lhs; std::vector<double> rhs; std::vector<stk::mesh::Entity> connected_nodes; // ip values; both boundary and opposing surface std::vector<double> currentIsoParCoords(nDim); std::vector<double> opposingIsoParCoords(nDim); std::vector<double> cNx(nDim); std::vector<double> oNx(nDim); // mapping for -1:1 -> -0.5:0.5 volume element std::vector<double> currentElementIsoParCoords(nDim); std::vector<double> opposingElementIsoParCoords(nDim); // interpolate nodal values to point-in-elem const int sizeOfScalarField = 1; // pointers to fixed values double *p_cNx = &cNx[0]; double *p_oNx = &oNx[0]; // nodal fields to gather std::vector<double> ws_c_face_scalarQ; std::vector<double> ws_o_face_scalarQ; std::vector<double> ws_c_elem_scalarQ; std::vector<double> ws_o_elem_scalarQ; std::vector<double> ws_c_elem_coordinates; std::vector<double> ws_o_elem_coordinates; std::vector<double> ws_c_diffFluxCoeff; std::vector<double> ws_o_diffFluxCoeff; // master element data std::vector<double> ws_c_dndx; std::vector<double> ws_o_dndx; std::vector<double> ws_c_det_j; std::vector<double> ws_o_det_j; std::vector <double > ws_c_general_shape_function; std::vector <double > ws_o_general_shape_function; std::vector<int> ws_c_face_node_ordinals; std::vector<int> ws_o_face_node_ordinals; // deal with state ScalarFieldType &scalarQNp1 = scalarQ_->field_of_state(stk::mesh::StateNP1); // parallel communicate ghosted entities if ( NULL != realm_.nonConformalManager_->nonConformalGhosting_ ) stk::mesh::communicate_field_data(*(realm_.nonConformalManager_->nonConformalGhosting_), ghostFieldVec_); // iterate nonConformalManager's dgInfoVec std::vector<NonConformalInfo *>::iterator ii; for( ii=realm_.nonConformalManager_->nonConformalInfoVec_.begin(); ii!=realm_.nonConformalManager_->nonConformalInfoVec_.end(); ++ii ) { // extract vector of DgInfo std::vector<std::vector<DgInfo *> > &dgInfoVec = (*ii)->dgInfoVec_; std::vector<std::vector<DgInfo*> >::iterator idg; for( idg=dgInfoVec.begin(); idg!=dgInfoVec.end(); ++idg ) { std::vector<DgInfo *> &faceDgInfoVec = (*idg); // now loop over all the DgInfo objects on this particular exposed face for ( size_t k = 0; k < faceDgInfoVec.size(); ++k ) { DgInfo *dgInfo = faceDgInfoVec[k]; // extract current/opposing face/element stk::mesh::Entity currentFace = dgInfo->currentFace_; stk::mesh::Entity opposingFace = dgInfo->opposingFace_; stk::mesh::Entity currentElement = dgInfo->currentElement_; stk::mesh::Entity opposingElement = dgInfo->opposingElement_; stk::topology currentElementTopo = dgInfo->currentElementTopo_; stk::topology opposingElementTopo = dgInfo->opposingElementTopo_; const int currentFaceOrdinal = dgInfo->currentFaceOrdinal_; const int opposingFaceOrdinal = dgInfo->opposingFaceOrdinal_; // master element; face and volume MasterElement * meFCCurrent = dgInfo->meFCCurrent_; MasterElement * meFCOpposing = dgInfo->meFCOpposing_; MasterElement * meSCSCurrent = dgInfo->meSCSCurrent_; MasterElement * meSCSOpposing = dgInfo->meSCSOpposing_; // local ip, ordinals, etc const int currentGaussPointId = dgInfo->currentGaussPointId_; currentIsoParCoords = dgInfo->currentIsoParCoords_; opposingIsoParCoords = dgInfo->opposingIsoParCoords_; // extract some master element info const int currentNodesPerFace = meFCCurrent->nodesPerElement_; const int opposingNodesPerFace = meFCOpposing->nodesPerElement_; const int currentNodesPerElement = meSCSCurrent->nodesPerElement_; const int opposingNodesPerElement = meSCSOpposing->nodesPerElement_; // resize some things; matrix related const int totalNodes = currentNodesPerElement + opposingNodesPerElement; const int lhsSize = totalNodes*totalNodes; const int rhsSize = totalNodes; lhs.resize(lhsSize); rhs.resize(rhsSize); connected_nodes.resize(totalNodes); // algorithm related; element; dndx will be at a single gauss point... ws_c_elem_scalarQ.resize(currentNodesPerElement); ws_o_elem_scalarQ.resize(opposingNodesPerElement); ws_c_elem_coordinates.resize(currentNodesPerElement*nDim); ws_o_elem_coordinates.resize(opposingNodesPerElement*nDim); ws_c_dndx.resize(nDim*currentNodesPerElement); ws_o_dndx.resize(nDim*opposingNodesPerElement); ws_c_det_j.resize(1); ws_o_det_j.resize(1); // algorithm related; face ws_c_face_scalarQ.resize(currentNodesPerFace); ws_o_face_scalarQ.resize(opposingNodesPerFace); ws_c_diffFluxCoeff.resize(currentNodesPerFace); ws_o_diffFluxCoeff.resize(opposingNodesPerFace); ws_c_general_shape_function.resize(currentNodesPerFace); ws_o_general_shape_function.resize(opposingNodesPerFace); // face node identification ws_c_face_node_ordinals.resize(currentNodesPerFace); ws_o_face_node_ordinals.resize(opposingNodesPerFace); // pointers double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_c_face_scalarQ = &ws_c_face_scalarQ[0]; double *p_o_face_scalarQ = &ws_o_face_scalarQ[0]; double *p_c_elem_scalarQ = &ws_c_elem_scalarQ[0]; double *p_o_elem_scalarQ = &ws_o_elem_scalarQ[0]; double *p_c_elem_coordinates = &ws_c_elem_coordinates[0]; double *p_o_elem_coordinates = &ws_o_elem_coordinates[0]; double *p_c_diffFluxCoeff = &ws_c_diffFluxCoeff[0]; double *p_o_diffFluxCoeff = &ws_o_diffFluxCoeff[0]; // me pointers double *p_c_general_shape_function = &ws_c_general_shape_function[0]; double *p_o_general_shape_function = &ws_o_general_shape_function[0]; double *p_c_dndx = &ws_c_dndx[0]; double *p_o_dndx = &ws_o_dndx[0]; // populate current face_node_ordinals currentElementTopo.side_node_ordinals(currentFaceOrdinal, ws_c_face_node_ordinals.begin()); // gather current face data stk::mesh::Entity const* current_face_node_rels = bulk_data.begin_nodes(currentFace); const int current_num_face_nodes = bulk_data.num_nodes(currentFace); for ( int ni = 0; ni < current_num_face_nodes; ++ni ) { stk::mesh::Entity node = current_face_node_rels[ni]; // gather... p_c_face_scalarQ[ni] = *stk::mesh::field_data(scalarQNp1, node); p_c_diffFluxCoeff[ni] = *stk::mesh::field_data(*diffFluxCoeff_, node); } // populate opposing face_node_ordinals opposingElementTopo.side_node_ordinals(opposingFaceOrdinal, ws_o_face_node_ordinals.begin()); // gather opposing face data stk::mesh::Entity const* opposing_face_node_rels = bulk_data.begin_nodes(opposingFace); const int opposing_num_face_nodes = bulk_data.num_nodes(opposingFace); for ( int ni = 0; ni < opposing_num_face_nodes; ++ni ) { stk::mesh::Entity node = opposing_face_node_rels[ni]; // gather... p_o_face_scalarQ[ni] = *stk::mesh::field_data(scalarQNp1, node); p_o_diffFluxCoeff[ni] = *stk::mesh::field_data(*diffFluxCoeff_, node); } // gather current element data; sneak in first of connected nodes stk::mesh::Entity const* current_elem_node_rels = bulk_data.begin_nodes(currentElement); const int current_num_elem_nodes = bulk_data.num_nodes(currentElement); for ( int ni = 0; ni < current_num_elem_nodes; ++ni ) { stk::mesh::Entity node = current_elem_node_rels[ni]; // set connected nodes connected_nodes[ni] = node; // gather; scalar p_c_elem_scalarQ[ni] = *stk::mesh::field_data(scalarQNp1, node); // gather; vector const double *coords = stk::mesh::field_data(*coordinates_, node); const int niNdim = ni*nDim; for ( int i = 0; i < nDim; ++i ) { p_c_elem_coordinates[niNdim+i] = coords[i]; } } // gather opposing element data; sneak in second connected nodes stk::mesh::Entity const* opposing_elem_node_rels = bulk_data.begin_nodes(opposingElement); const int opposing_num_elem_nodes = bulk_data.num_nodes(opposingElement); for ( int ni = 0; ni < opposing_num_elem_nodes; ++ni ) { stk::mesh::Entity node = opposing_elem_node_rels[ni]; // set connected nodes connected_nodes[ni+current_num_elem_nodes] = node; // gather; scalar p_o_elem_scalarQ[ni] = *stk::mesh::field_data(scalarQNp1, node); // gather; vector const double *coords = stk::mesh::field_data(*coordinates_, node); const int niNdim = ni*nDim; for ( int i = 0; i < nDim; ++i ) { p_o_elem_coordinates[niNdim+i] = coords[i]; } } // pointer to face data const double * c_areaVec = stk::mesh::field_data(*exposedAreaVec_, currentFace); const double * o_areaVec = stk::mesh::field_data(*exposedAreaVec_, opposingFace); const double * ncMassFlowRate = stk::mesh::field_data(*ncMassFlowRate_, currentFace); double c_amag = 0.0; double o_amag = 0.0; for ( int j = 0; j < nDim; ++j ) { const double c_axj = c_areaVec[currentGaussPointId*nDim+j]; c_amag += c_axj*c_axj; // FIXME: choose first area vector on opposing surface? probably need something better for HO const double o_axj = o_areaVec[0*nDim+j]; o_amag += o_axj*o_axj; } c_amag = std::sqrt(c_amag); o_amag = std::sqrt(o_amag); // now compute normal for ( int i = 0; i < nDim; ++i ) { p_cNx[i] = c_areaVec[currentGaussPointId*nDim+i]/c_amag; p_oNx[i] = o_areaVec[0*nDim+i]/o_amag; } // project from side to element; method deals with the -1:1 isInElement range to the proper -0.5:0.5 CVFEM range meSCSCurrent->sidePcoords_to_elemPcoords(currentFaceOrdinal, 1, ¤tIsoParCoords[0], ¤tElementIsoParCoords[0]); meSCSOpposing->sidePcoords_to_elemPcoords(opposingFaceOrdinal, 1, &opposingIsoParCoords[0], &opposingElementIsoParCoords[0]); // compute dndx double scs_error = 0.0; meSCSCurrent->general_face_grad_op(currentFaceOrdinal, ¤tElementIsoParCoords[0], &p_c_elem_coordinates[0], &p_c_dndx[0], &ws_c_det_j[0], &scs_error); meSCSOpposing->general_face_grad_op(opposingFaceOrdinal, &opposingElementIsoParCoords[0], &p_o_elem_coordinates[0], &p_o_dndx[0], &ws_o_det_j[0], &scs_error); // current diffusive flux double currentDiffFluxBip = 0.0; for ( int ic = 0; ic < currentNodesPerElement; ++ic ) { const int offSetDnDx = ic*nDim; // single intg. point const double scalarQIC = p_c_elem_scalarQ[ic]; for ( int j = 0; j < nDim; ++j ) { const double nxj = p_cNx[j]; const double dndxj = p_c_dndx[offSetDnDx+j]; currentDiffFluxBip += dndxj*nxj*scalarQIC; } } // current inverse length scale; can loop over face nodes to avoid "nodesOnFace" array double currentInverseLength = 0.0; for ( int ic = 0; ic < current_num_face_nodes; ++ic ) { const int faceNodeNumber = ws_c_face_node_ordinals[ic]; const int offSetDnDx = faceNodeNumber*nDim; // single intg. point for ( int j = 0; j < nDim; ++j ) { const double nxj = p_cNx[j]; const double dndxj = p_c_dndx[offSetDnDx+j]; currentInverseLength += dndxj*nxj; } } // opposing flux double opposingDiffFluxBip = 0.0; for ( int ic = 0; ic < opposingNodesPerElement; ++ic ) { const int offSetDnDx = ic*nDim; // single intg. point const double scalarQIC = p_o_elem_scalarQ[ic]; for ( int j = 0; j < nDim; ++j ) { const double nxj = p_oNx[j]; const double dndxj = p_o_dndx[offSetDnDx+j]; opposingDiffFluxBip += dndxj*nxj*scalarQIC; } } // opposing inverse length scale; can loop over face nodes to avoid "nodesOnFace" array double opposingInverseLength = 0.0; for ( int ic = 0; ic < opposing_num_face_nodes; ++ic ) { const int faceNodeNumber = ws_o_face_node_ordinals[ic]; const int offSetDnDx = faceNodeNumber*nDim; // single intg. point for ( int j = 0; j < nDim; ++j ) { const double nxj = p_oNx[j]; const double dndxj = p_o_dndx[offSetDnDx+j]; opposingInverseLength += dndxj*nxj; } } // interpolate face data; current and opposing... double currentScalarQBip = 0.0; meFCCurrent->interpolatePoint( sizeOfScalarField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_face_scalarQ[0], ¤tScalarQBip); double opposingScalarQBip = 0.0; meFCOpposing->interpolatePoint( sizeOfScalarField, &(dgInfo->opposingIsoParCoords_[0]), &ws_o_face_scalarQ[0], &opposingScalarQBip); double currentDiffFluxCoeffBip = 0.0; meFCCurrent->interpolatePoint( sizeOfScalarField, &(dgInfo->currentIsoParCoords_[0]), &ws_c_diffFluxCoeff[0], ¤tDiffFluxCoeffBip); double opposingDiffFluxCoeffBip = 0.0; meFCOpposing->interpolatePoint( sizeOfScalarField, &(dgInfo->opposingIsoParCoords_[0]), &ws_o_diffFluxCoeff[0], &opposingDiffFluxCoeffBip); // properly scaled diffusive flux currentDiffFluxBip *= -currentDiffFluxCoeffBip; opposingDiffFluxBip *= -opposingDiffFluxCoeffBip; // zero lhs/rhs for ( int p = 0; p < lhsSize; ++p ) p_lhs[p] = 0.0; for ( int p = 0; p < rhsSize; ++p ) p_rhs[p] = 0.0; // save mdot const double tmdot = ncMassFlowRate[currentGaussPointId]; // compute penalty const double penaltyIp = 0.5*(currentDiffFluxCoeffBip*currentInverseLength + opposingDiffFluxCoeffBip*opposingInverseLength) + std::abs(tmdot)/2.0; // non conformal diffusive flux const double ncDiffFlux = robinStyle_ ? -opposingDiffFluxBip : 0.5*(currentDiffFluxBip - opposingDiffFluxBip); // non conformal advection; find upwind (upwind prevails over Robin or DG approach) const double upwindScalarQBip = tmdot > 0.0 ? currentScalarQBip : opposingScalarQBip; const double ncAdv = upwindAdvection_ ? tmdot*upwindScalarQBip : robinStyle_ ? tmdot*opposingScalarQBip : 0.5*tmdot*(currentScalarQBip + opposingScalarQBip); // form residual const int nn = ws_c_face_node_ordinals[currentGaussPointId]; p_rhs[nn] -= ((dsFactor_*ncDiffFlux + penaltyIp*(currentScalarQBip-opposingScalarQBip))*c_amag + dsFactor_*ncAdv); // set-up row for matrix const int rowR = nn*totalNodes; double lhsFac = penaltyIp*c_amag; // sensitivities; current face (penalty and advection); use general shape function for this single ip meFCCurrent->general_shape_fcn(1, ¤tIsoParCoords[0], &ws_c_general_shape_function[0]); for ( int ic = 0; ic < currentNodesPerFace; ++ic ) { const int icnn = ws_c_face_node_ordinals[ic]; const double r = p_c_general_shape_function[ic]; p_lhs[rowR+icnn] += r*(lhsFac+0.5*tmdot); } // sensitivities; current element (diffusion) for ( int ic = 0; ic < currentNodesPerElement; ++ic ) { const int offSetDnDx = ic*nDim; // single intg. point double lhscd = 0.0; for ( int j = 0; j < nDim; ++j ) { const double nxj = p_cNx[j]; const double dndxj = p_c_dndx[offSetDnDx+j]; lhscd -= dndxj*nxj; } p_lhs[rowR+ic] += 0.5*currentDiffFluxCoeffBip*lhscd*c_amag*robinCurrentFluxFac; } // sensitivities; opposing face (penalty); use general shape function for this single ip meFCOpposing->general_shape_fcn(1, &opposingIsoParCoords[0], &ws_o_general_shape_function[0]); for ( int ic = 0; ic < opposingNodesPerFace; ++ic ) { const int icnn = ws_o_face_node_ordinals[ic]; const double r = p_o_general_shape_function[ic]; p_lhs[rowR+icnn+currentNodesPerElement] -= r*(lhsFac-0.5*tmdot); } // sensitivities; opposing element (diffusion) for ( int ic = 0; ic < opposingNodesPerElement; ++ic ) { const int offSetDnDx = ic*nDim; // single intg. point double lhscd = 0.0; for ( int j = 0; j < nDim; ++j ) { const double nxj = p_oNx[j]; const double dndxj = p_o_dndx[offSetDnDx+j]; lhscd -= dndxj*nxj; } p_lhs[rowR+ic+currentNodesPerElement] -= 0.5*opposingDiffFluxCoeffBip*lhscd*c_amag; } apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void ComputeMdotEdgeContactAlgorithm::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 noc const std::string dofName = "pressure"; const double nocFac = (realm_.get_noc_usage(dofName) == true) ? 1.0 : 0.0; // time step const double dt = realm_.get_time_step(); const double gamma1 = realm_.get_gamma1(); const double projTimeScale = dt/gamma1; // deal with interpolation procedure const double interpTogether = realm_.get_mdot_interp(); const double om_interpTogether = 1.0-interpTogether; // mesh motion std::vector<double> vrtmL(nDim); std::vector<double> vrtmR(nDim); double * p_vrtmL = &vrtmL[0]; double * p_vrtmR = &vrtmR[0]; // deal with state VectorFieldType &velocityNp1 = velocity_->field_of_state(stk::mesh::StateNP1); ScalarFieldType &densityNp1 = density_->field_of_state(stk::mesh::StateNP1); // space for interpolated right state (halo) double pressureR; double densityR; std::vector<double> GpdxR(nDim); std::vector<double> velocityNp1R(nDim); // interpolate nodal values to point-in-elem const int sizeOfScalarField = 1; const int sizeOfVectorField = nDim; // parallel communicate ghosted entities if ( NULL != realm_.contactManager_->contactGhosting_ ) stk::mesh::communicate_field_data(*(realm_.contactManager_->contactGhosting_), ghostFieldVec_); // iterate contactInfoVec_ std::vector<ContactInfo *>::iterator ii; for( ii=realm_.contactManager_->contactInfoVec_.begin(); ii!=realm_.contactManager_->contactInfoVec_.end(); ++ii ) { // get master element type for this contactInfo MasterElement *meSCS = (*ii)->meSCS_; const int nodesPerElement = meSCS->nodesPerElement_; std::vector <double > elemNodalP(nodesPerElement); std::vector <double > elemNodalUnp1(nDim*nodesPerElement); std::vector <double > elemNodalRho(nodesPerElement); std::vector <double > elemNodalGpdx(nDim*nodesPerElement); std::vector <double > shpfc(nodesPerElement); // iterate halo face nodes std::map<uint64_t, HaloInfo *>::iterator iterHalo; for (iterHalo = (*ii)->haloInfoMap_.begin(); iterHalo != (*ii)->haloInfoMap_.end(); ++iterHalo) { // halo info object of interest HaloInfo * infoObject = (*iterHalo).second; // extract element mesh object and global id for face node stk::mesh::Entity elem = infoObject->owningElement_; // pointer to edge area vector const double *p_areaVec = &infoObject->haloEdgeAreaVec_[0]; stk::mesh::Entity const* elem_node_rels = bulk_data.begin_nodes(elem); const int num_nodes = bulk_data.num_nodes(elem); // now load the elemental values for future interpolation for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = elem_node_rels[ni]; elemNodalP[ni] = *stk::mesh::field_data(*pressure_, node); elemNodalRho[ni] = *stk::mesh::field_data(densityNp1, node); // load up vectors const double * uNp1 = stk::mesh::field_data(velocityNp1, node ); const double * Gjp = stk::mesh::field_data(*Gpdx_, node ); for ( int j = 0; j < nDim; ++j ) { const int offSet = j*nodesPerElement +ni; elemNodalGpdx[offSet] = Gjp[j]; elemNodalUnp1[offSet] = uNp1[j]; } } // extract nodal fields; right state is Halo and requires inperpolation const double *coordL = stk::mesh::field_data(*coordinates_, infoObject->faceNode_); const double *coordR = &infoObject->haloNodalCoords_[0]; // interpolate nodal values to point-in-elem const double pressureL = *stk::mesh::field_data(*pressure_, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfScalarField, &(infoObject->isoParCoords_[0]), &elemNodalP[0], &pressureR); const double densityL = *stk::mesh::field_data(densityNp1, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfScalarField, &(infoObject->isoParCoords_[0]), &elemNodalRho[0], &densityR); const double *velocityNp1L = stk::mesh::field_data(velocityNp1, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfVectorField, &(infoObject->isoParCoords_[0]), &elemNodalUnp1[0], &(velocityNp1R[0])); const double *GpdxL = stk::mesh::field_data(*Gpdx_, infoObject->faceNode_); meSCS->interpolatePoint( sizeOfVectorField, &(infoObject->isoParCoords_[0]), &elemNodalGpdx[0], &(GpdxR[0])); // copy to velocity relative to mesh for ( int j = 0; j < nDim; ++j ) { p_vrtmL[j] = velocityNp1L[j]; p_vrtmR[j] = velocityNp1R[j]; } // deal with mesh motion if ( meshMotion_ ) { const double * meshVelocityL = stk::mesh::field_data(*meshVelocity_, infoObject->faceNode_); const double * meshVelocityR = &(infoObject->haloMeshVelocity_[0]); for (int j = 0; j < nDim; ++j ) { p_vrtmL[j] -= meshVelocityL[j]; p_vrtmR[j] -= meshVelocityR[j]; } } // compute geometry double axdx = 0.0; double asq = 0.0; for (int j = 0; j < nDim; ++j ) { const double dxj = coordR[j] - coordL[j]; const double axj = p_areaVec[j]; axdx += axj*dxj; asq += axj*axj; } const double inv_axdx = 1.0/axdx; const double rhoIp = 0.5*(densityR + densityL); // mdot double tmdot = -projTimeScale*(pressureR - pressureL)*asq*inv_axdx; for ( int j = 0; j < nDim; ++j ) { const double axj = p_areaVec[j]; const double dxj = coordR[j] - coordL[j]; const double kxj = axj - asq*inv_axdx*dxj; // NOC const double rhoUjIp = 0.5*(densityR*p_vrtmR[j] + densityL*p_vrtmL[j]); const double ujIp = 0.5*(p_vrtmR[j] + p_vrtmL[j]); const double GjIp = 0.5*(GpdxR[j] + GpdxL[j]); tmdot += (interpTogether*rhoUjIp + om_interpTogether*rhoIp*ujIp + projTimeScale*GjIp)*axj - projTimeScale*kxj*GjIp*nocFac; } // scatter to mdot double *haloMdot = stk::mesh::field_data(*haloMdot_, infoObject->faceNode_); *haloMdot = tmdot; } } }