//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleMomentumEdgeSolverAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_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; always edge connectivity const int nodesPerEdge = 2; const int lhsSize = nDim*nodesPerEdge*nDim*nodesPerEdge; const int rhsSize = nDim*nodesPerEdge; std::vector<double> lhs(lhsSize); std::vector<double> rhs(rhsSize); std::vector<stk::mesh::Entity> connected_nodes(2); // area vector; gather into std::vector<double> areaVec(nDim); // pointer for fast access double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_areaVec = &areaVec[0]; // space for dui/dxj. This variable is the modified 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]; // deal with state VectorFieldType &velocityNp1 = velocity_->field_of_state(stk::mesh::StateNP1); ScalarFieldType &densityNp1 = density_->field_of_state(stk::mesh::StateNP1); // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() & stk::mesh::selectUnion(partVec_) & !(realm_.get_inactive_selector()); stk::mesh::BucketVector const& edge_buckets = realm_.get_buckets( stk::topology::EDGE_RANK, s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = edge_buckets.begin(); ib != edge_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // pointer to edge area vector and mdot const double * av = stk::mesh::field_data(*edgeAreaVec_, b); const double * mdot = stk::mesh::field_data(*massFlowRate_, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // zeroing of lhs/rhs for ( int i = 0; i < lhsSize; ++i ) { p_lhs[i] = 0.0; } for ( int i = 0; i < rhsSize; ++i ) { p_rhs[i] = 0.0; } stk::mesh::Entity const * edge_node_rels = b.begin_nodes(k); // pointer to edge area vector for ( int j = 0; j < nDim; ++j ) p_areaVec[j] = av[k*nDim+j]; const double tmdot = mdot[k]; // sanity check on number or nodes ThrowAssert( b.num_nodes(k) == 2 ); // left and right nodes stk::mesh::Entity nodeL = edge_node_rels[0]; stk::mesh::Entity nodeR = edge_node_rels[1]; connected_nodes[0] = nodeL; connected_nodes[1] = nodeR; // extract nodal fields const double * coordL = stk::mesh::field_data(*coordinates_, nodeL); const double * coordR = stk::mesh::field_data(*coordinates_, nodeR); const double * dudxL = stk::mesh::field_data(*dudx_, nodeL); const double * dudxR = stk::mesh::field_data(*dudx_, nodeR); const double * vrtmL = stk::mesh::field_data(*velocityRTM_, nodeL); const double * vrtmR = stk::mesh::field_data(*velocityRTM_, nodeR); const double * uNp1L = stk::mesh::field_data(velocityNp1, nodeL); const double * uNp1R = stk::mesh::field_data(velocityNp1, nodeR); const double densityL = *stk::mesh::field_data(densityNp1, nodeL); const double densityR = *stk::mesh::field_data(densityNp1, nodeR); const double viscosityL = *stk::mesh::field_data(*viscosity_, nodeL); const double viscosityR = *stk::mesh::field_data(*viscosity_, nodeR); // copy in extrapolated values for ( int i = 0; i < nDim; ++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]; } } // 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*(vrtmL[j] + 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; } } // 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); // divU double divU = 0.0; for ( int j = 0; j < nDim; ++j) divU += p_duidxj[j*nDim+j]; // 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 const double tflux = aflux + dflux; const int indexL = i; const int indexR = i + nDim; // total flux left p_rhs[indexL] -= tflux; // total flux right p_rhs[indexR] += tflux; // setup for LHS const int rowL = indexL * nodesPerEdge*nDim; const int rowR = indexR * nodesPerEdge*nDim; //============================== // advection first //============================== const int rLiL = rowL+indexL; const int rLiR = rowL+indexR; const int rRiL = rowR+indexL; const int rRiR = rowR+indexR; // 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; p_lhs[rRiL] -= alhsfac; // upwind advection (incldues 4th); right node alhsfac = 0.5*(tmdot-std::abs(tmdot))*pecfac*alphaUpw + 0.5*alpha*om_pecfac*tmdot; p_lhs[rRiR] -= alhsfac; p_lhs[rLiR] += alhsfac; // central; left; collect terms on alpha and alphaUpw alhsfac = 0.5*tmdot*(pecfac*om_alphaUpw + om_pecfac*om_alpha); p_lhs[rLiL] += alhsfac; p_lhs[rLiR] += alhsfac; // central; right p_lhs[rRiL] -= alhsfac; p_lhs[rRiR] -= alhsfac; //============================== // diffusion second //============================== const double axi = p_areaVec[i]; //diffusion; row IL p_lhs[rLiL] -= dlhsfac; p_lhs[rLiR] += dlhsfac; // diffusion; row IR p_lhs[rRiL] += dlhsfac; p_lhs[rRiR] -= dlhsfac; // 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; // first left; IL,IL; IL,IR p_lhs[rowL + colL] -= lhsfacNS; p_lhs[rowL + colR] += lhsfacNS; // now right, IR,IL; IR,IR p_lhs[rowR + colL] += lhsfacNS; p_lhs[rowR + colR] -= lhsfacNS; } } apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleRadTransEdgeUpwindSolverAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // extract current ordinate direction std::vector<double> Sk(nDim,0.0); radEqSystem_->get_current_ordinate(&Sk[0]); const double *p_Sk = &Sk[0]; intensity_ = radEqSystem_->get_intensity(); // space for LHS/RHS; always nodesPerEdge*nodesPerEdge and nodesPerEdge std::vector<double> lhs(4); std::vector<double> rhs(2); std::vector<int> scratchIds(2); std::vector<double> scratchVals(2); std::vector<stk::mesh::Entity> connected_nodes(2); // area vector; gather into std::vector<double> areaVec(nDim); // pointers for fast access double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_areaVec = &areaVec[0]; // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& edge_buckets = realm_.get_buckets( stk::topology::EDGE_RANK, s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = edge_buckets.begin(); ib != edge_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const size_t length = b.size(); // pointer to edge area vector const double * av = stk::mesh::field_data(*edgeAreaVec_, b); for ( size_t k = 0 ; k < length ; ++k ) { // set ordinal for edge unsigned edge_ordinal = k; // sanity check on number or nodes ThrowAssert( b.num_nodes(edge_ordinal) == 2 ); stk::mesh::Entity const * edge_node_rels = b.begin_nodes(edge_ordinal); // pointer to edge area vector for ( int j = 0; j < nDim; ++j ) p_areaVec[j] = av[k*nDim+j]; // left and right nodes stk::mesh::Entity nodeL = edge_node_rels[0]; stk::mesh::Entity nodeR = edge_node_rels[1]; connected_nodes[0] = nodeL; connected_nodes[1] = nodeR; // extract nodal fields const double intensityL = *stk::mesh::field_data(*intensity_, nodeL); const double intensityR = *stk::mesh::field_data(*intensity_, nodeR); // compute sj*njdS double sjaj = 0.0; for ( int j = 0; j < nDim; ++j ) { sjaj += p_Sk[j]*p_areaVec[j]; } // upwind; left node double lhsfac = 0.5*(sjaj+std::abs(sjaj)); p_lhs[0] = +lhsfac; p_lhs[2] = -lhsfac; // upwind; right node lhsfac = 0.5*(sjaj-std::abs(sjaj)); p_lhs[3] = -lhsfac; p_lhs[1] = +lhsfac; // residual const double intensityIp = (sjaj > 0.0) ? intensityL : intensityR; p_rhs[0] = -sjaj*intensityIp; p_rhs[1] = +sjaj*intensityIp; apply_coeff(connected_nodes, scratchIds, scratchVals, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleContinuityEdgeSolverAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_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; // space for LHS/RHS; always nodesPerEdge*nodesPerEdge and nodesPerEdge std::vector<double> lhs(4); std::vector<double> rhs(2); std::vector<stk::mesh::Entity> connected_nodes(2); // area vector; gather into std::vector<double> areaVec(nDim); // pointers for fast access double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_areaVec = &areaVec[0]; // 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); // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& edge_buckets = realm_.get_buckets( stk::topology::EDGE_RANK, s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = edge_buckets.begin(); ib != edge_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // pointer to edge area vector const double * av = stk::mesh::field_data(*edgeAreaVec_, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // sanity check on number or nodes ThrowAssert( b.num_nodes(k) == 2 ); stk::mesh::Entity const * edge_node_rels = b.begin_nodes(k); // pointer to edge area vector for ( int j = 0; j < nDim; ++j ) p_areaVec[j] = av[k*nDim+j]; // left and right nodes stk::mesh::Entity nodeL = edge_node_rels[0]; stk::mesh::Entity nodeR = edge_node_rels[1]; connected_nodes[0] = nodeL; connected_nodes[1] = nodeR; // extract nodal fields const double * coordL = stk::mesh::field_data(*coordinates_, nodeL); const double * coordR = stk::mesh::field_data(*coordinates_, nodeR); const double * GpdxL = stk::mesh::field_data(*Gpdx_, nodeL); const double * GpdxR = stk::mesh::field_data(*Gpdx_, nodeR); const double * velocityNp1L = stk::mesh::field_data(velocityNp1, nodeL); const double * velocityNp1R = stk::mesh::field_data(velocityNp1, nodeR); const double pressureL = *stk::mesh::field_data(*pressure_, nodeL); const double pressureR = *stk::mesh::field_data(*pressure_, nodeR); const double densityL = *stk::mesh::field_data(densityNp1, nodeL); const double densityR = *stk::mesh::field_data(densityNp1, nodeR); // copy to velcoity 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_, nodeL ); const double * meshVelocityR = stk::mesh::field_data(*meshVelocity_, nodeR ); 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 axj = p_areaVec[j]; const double dxj = coordR[j] - coordL[j]; asq += axj*axj; axdx += axj*dxj; } 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; } const double lhsfac = -asq*inv_axdx; /* lhs[0] = IL,IL; lhs[1] = IL,IR; IR,IL; IR,IR */ // first left p_lhs[0] = -lhsfac; p_lhs[1] = +lhsfac; p_rhs[0] = -tmdot/projTimeScale; // now right p_lhs[2] = +lhsfac; p_lhs[3] = -lhsfac; p_rhs[1] = tmdot/projTimeScale; apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void ComputeMdotEdgeAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_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; // area vector; gather into std::vector<double> areaVec(nDim); // pointers for fast access double *p_areaVec = &areaVec[0]; // deal with state ScalarFieldType &densityNp1 = density_->field_of_state(stk::mesh::StateNP1); // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& edge_buckets = realm_.get_buckets( stk::topology::EDGE_RANK, s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = edge_buckets.begin(); ib != edge_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // pointer to edge area vector and mdot const double * av = stk::mesh::field_data(*edgeAreaVec_, b); double * mdot = stk::mesh::field_data(*massFlowRate_, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { stk::mesh::Entity const * edge_node_rels = b.begin_nodes(k); // sanity check on number or nodes ThrowAssert( b.num_nodes(k) == 2 ); // pointer to edge area vector for ( int j = 0; j < nDim; ++j ) p_areaVec[j] = av[k*nDim+j]; // left and right nodes stk::mesh::Entity nodeL = edge_node_rels[0]; stk::mesh::Entity nodeR = edge_node_rels[1]; // extract nodal fields const double * coordL = stk::mesh::field_data(*coordinates_, nodeL ); const double * coordR = stk::mesh::field_data(*coordinates_, nodeR ); const double * GpdxL = stk::mesh::field_data(*Gpdx_, nodeL ); const double * GpdxR = stk::mesh::field_data(*Gpdx_, nodeR ); const double * vrtmL = stk::mesh::field_data(*velocityRTM_, nodeL ); const double * vrtmR = stk::mesh::field_data(*velocityRTM_, nodeR ); const double pressureL = *stk::mesh::field_data(*pressure_, nodeL ); const double pressureR = *stk::mesh::field_data(*pressure_, nodeR ); const double densityL = *stk::mesh::field_data(densityNp1, nodeL ); const double densityR = *stk::mesh::field_data(densityNp1, nodeR ); // compute geometry double axdx = 0.0; double asq = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = p_areaVec[j]; const double dxj = coordR[j] - coordL[j]; asq += axj*axj; axdx += axj*dxj; } 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*vrtmR[j] + densityL*vrtmL[j]); const double ujIp = 0.5*(vrtmR[j] + 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 mdot[k] = tmdot; } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleScalarEdgeSolverAlgorithm::execute() { stk::mesh::BulkData & bulk_data = realm_.bulk_data(); stk::mesh::MetaData & meta_data = realm_.meta_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 = scalarQ_->name(); const double hybridFactor = realm_.get_hybrid_factor(dofName); 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; always edge connectivity const int nodesPerEdge = 2; const int lhsSize = nodesPerEdge*nodesPerEdge; const int rhsSize = nodesPerEdge; std::vector<double> lhs(lhsSize); std::vector<double> rhs(rhsSize); std::vector<stk::mesh::Entity> connected_nodes(2); // area vector; gather into std::vector<double> areaVec(nDim); // pointer for fast access double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_areaVec = &areaVec[0]; // deal with state ScalarFieldType &scalarQNp1 = scalarQ_->field_of_state(stk::mesh::StateNP1); ScalarFieldType &densityNp1 = density_->field_of_state(stk::mesh::StateNP1); // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() & stk::mesh::selectUnion(partVec_) & !(realm_.get_inactive_selector()); stk::mesh::BucketVector const& edge_buckets = realm_.get_buckets( stk::topology::EDGE_RANK, s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = edge_buckets.begin(); ib != edge_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // pointer to edge area vector and mdot const double * av = stk::mesh::field_data(*edgeAreaVec_, b); const double * mdot = stk::mesh::field_data(*massFlowRate_, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // zeroing of lhs/rhs for ( int i = 0; i < lhsSize; ++i ) { p_lhs[i] = 0.0; } for ( int i = 0; i < rhsSize; ++i ) { p_rhs[i] = 0.0; } // get edge stk::mesh::Entity edge = b[k]; stk::mesh::Entity const * edge_node_rels = bulk_data.begin_nodes(edge); // sanity check on number or nodes ThrowAssert( bulk_data.num_nodes(edge) == 2 ); // pointer to edge area vector for ( int j = 0; j < nDim; ++j ) p_areaVec[j] = av[k*nDim+j]; const double tmdot = mdot[k]; // left and right nodes stk::mesh::Entity nodeL = edge_node_rels[0]; stk::mesh::Entity nodeR = edge_node_rels[1]; connected_nodes[0] = nodeL; connected_nodes[1] = nodeR; // extract nodal fields const double * coordL = stk::mesh::field_data(*coordinates_, nodeL); const double * coordR = stk::mesh::field_data(*coordinates_, nodeR); const double * dqdxL = stk::mesh::field_data(*dqdx_, nodeL); const double * dqdxR = stk::mesh::field_data(*dqdx_, nodeR); const double * vrtmL = stk::mesh::field_data(*velocityRTM_, nodeL); const double * vrtmR = stk::mesh::field_data(*velocityRTM_, nodeR); const double qNp1L = *stk::mesh::field_data(scalarQNp1, nodeL); const double qNp1R = *stk::mesh::field_data(scalarQNp1, nodeR); const double densityL = *stk::mesh::field_data(densityNp1, nodeL); const double densityR = *stk::mesh::field_data(densityNp1, nodeR); const double diffFluxCoeffL = *stk::mesh::field_data(*diffFluxCoeff_, nodeL); const double diffFluxCoeffR = *stk::mesh::field_data(*diffFluxCoeff_, nodeR); // 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]; asq += axj*axj; axdx += axj*dxj; udotx += 0.5*dxj*(vrtmL[j] + vrtmR[j]); } const double inv_axdx = 1.0/axdx; // ip props const double viscIp = 0.5*(diffFluxCoeffL + diffFluxCoeffR); const double diffIp = 0.5*(diffFluxCoeffL/densityL + diffFluxCoeffR/densityR); // Peclet factor double pecfac = hybridFactor*udotx/(diffIp+small); pecfac = pecfac*pecfac/(5.0 + pecfac*pecfac); const double om_pecfac = 1.0-pecfac; // left and right extrapolation; add in diffusion calc double dqL = 0.0; double dqR = 0.0; double nonOrth = 0.0; for ( int j = 0; j < nDim; ++j ) { const double dxj = coordR[j] - coordL[j]; dqL += 0.5*dxj*dqdxL[j]; dqR += 0.5*dxj*dqdxR[j]; // now non-orth (over-relaxed procedure of Jasek) const double axj = p_areaVec[j]; const double kxj = axj - asq*inv_axdx*dxj; const double GjIp = 0.5*(dqdxL[j] + dqdxR[j]); nonOrth += -viscIp*kxj*GjIp; } // add limiter if appropriate double limitL = 1.0; double limitR = 1.0; const double dq = qNp1R - qNp1L; if ( useLimiter ) { const double dqMl = 2.0*2.0*dqL - dq; const double dqMr = 2.0*2.0*dqR - dq; limitL = van_leer(dqMl, dq, small); limitR = van_leer(dqMr, dq, small); } // extrapolated; for now limit const double qIpL = qNp1L + dqL*hoUpwind*limitL; const double qIpR = qNp1R - dqR*hoUpwind*limitR; //==================================== // diffusive flux //==================================== double lhsfac = -viscIp*asq*inv_axdx; double diffFlux = lhsfac*(qNp1R - qNp1L) + nonOrth; // first left p_lhs[0] = -lhsfac; p_lhs[1] = +lhsfac; p_rhs[0] = -diffFlux; // now right p_lhs[2] = +lhsfac; p_lhs[3] = -lhsfac; p_rhs[1] = diffFlux; //==================================== // advective flux //==================================== // 2nd order central const double qIp = 0.5*( qNp1L + qNp1R ); // upwind const double qUpwind = (tmdot > 0) ? alphaUpw*qIpL + om_alphaUpw*qIp : alphaUpw*qIpR + om_alphaUpw*qIp; // generalized central (2nd and 4th order) const double qHatL = alpha*qIpL + om_alpha*qIp; const double qHatR = alpha*qIpR + om_alpha*qIp; const double qCds = 0.5*(qHatL + qHatR); // total advection const double aflux = tmdot*(pecfac*qUpwind + om_pecfac*qCds); // upwind advection (includes 4th); left node double alhsfac = 0.5*(tmdot+std::abs(tmdot))*pecfac*alphaUpw + 0.5*alpha*om_pecfac*tmdot; p_lhs[0] += alhsfac; p_lhs[2] -= alhsfac; // upwind advection; right node alhsfac = 0.5*(tmdot-std::abs(tmdot))*pecfac*alphaUpw + 0.5*alpha*om_pecfac*tmdot; p_lhs[3] -= alhsfac; p_lhs[1] += alhsfac; // central; left; collect terms on alpha and alphaUpw alhsfac = 0.5*tmdot*(pecfac*om_alphaUpw + om_pecfac*om_alpha); p_lhs[0] += alhsfac; p_lhs[1] += alhsfac; // central; right; collect terms on alpha and alphaUpw p_lhs[2] -= alhsfac; p_lhs[3] -= alhsfac; // total flux left p_rhs[0] -= aflux; // total flux right p_rhs[1] += aflux; apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } }