int get_entity_subcell_id(const BulkData& mesh, const Entity entity, const EntityRank subcell_rank, stk::topology subcell_topology, const std::vector<Entity>& subcell_nodes) { ThrowAssert(subcell_rank <= stk::topology::ELEMENT_RANK); const int INVALID_SIDE = -1; stk::topology entity_topology = mesh.bucket(entity).topology(); ThrowAssert(entity_topology.num_nodes() == mesh.num_nodes(entity)); const Entity* entity_nodes = mesh.begin_nodes(entity); std::vector<Entity> topology_sub_nodes(subcell_nodes.size()); for(size_t i = 0; i < entity_topology.num_sub_topology(subcell_rank); ++i) { entity_topology.sub_topology_nodes(entity_nodes, subcell_rank, i, topology_sub_nodes.begin()); if(subcell_topology.equivalent(topology_sub_nodes, subcell_nodes).first) { return i; } } return INVALID_SIDE; }
inline typename FieldTraits<FieldType>::data_type* field_data(const FieldType & f, const Bucket& b, Bucket::size_type bucket_ord) { ThrowAssert(f.entity_rank() == b.entity_rank()); ThrowAssert(&f.get_mesh() == &b.mesh()); const FieldMetaData& field_meta_data = f.get_meta_data_for_field()[b.bucket_id()]; return reinterpret_cast<typename FieldTraits<FieldType>::data_type*>(field_meta_data.m_data + field_meta_data.m_bytes_per_entity * bucket_ord); }
inline typename FieldTraits<FieldType>::data_type* field_data(const FieldType & f, Entity e) { const MeshIndex& mi = f.get_mesh().mesh_index(e); ThrowAssert(f.entity_rank() == mi.bucket->entity_rank()); ThrowAssert(&f.get_mesh() == &mi.bucket->mesh()); const FieldMetaData& field_meta_data = f.get_meta_data_for_field()[mi.bucket->bucket_id()]; return reinterpret_cast<typename FieldTraits<FieldType>::data_type*>(field_meta_data.m_data + field_meta_data.m_bytes_per_entity * mi.bucket_ordinal); }
bool Entity::update_relation( const RelationIterator ir , const bool back_rel_flag) const { const Relation::RelationType relType = ir->getRelationType(); ThrowAssert(verify_relation_ordering(internal_begin_relation(relType), internal_end_relation(relType))); ThrowAssertMsg(!internal_is_handled_generically(relType), "update_relation should not be called for STK-managed relations"); Entity & meshObj = *ir->getMeshObj() ; const Relation::RelationType backRelType = back_relation_type(relType); ThrowAssert(verify_relation_ordering(meshObj.internal_begin_relation(backRelType), meshObj.internal_end_relation(backRelType))); // Create the corresponding back relation to ir Relation backRel_obj(const_cast<Entity*>(this), backRelType, ir->getOrdinal(), ir->getOrientation()); RelationIterator backRel_itr = meshObj.find_relation(backRel_obj); const bool exists = backRel_itr != meshObj.internal_end_relation(backRelType) && *backRel_itr == backRel_obj; if (exists && !back_rel_flag) { // Remove back relation and increment the counter meshObj.erase_and_clear_if_empty(backRel_itr); //ThrowAssert(sierra::Fmwk::get_derived_type(meshObj) != Entity::ELEMENT); meshObj.inc_connection(); } else if (!exists && back_rel_flag) { // Insert back relation const unsigned k = backRel_itr - meshObj.internal_begin_relation(backRelType) ; meshObj.reserve_relation(meshObj.aux_relations().size() + 1); meshObj.aux_relations().insert(meshObj.aux_relations().begin() + k, backRel_obj); //ThrowAssert(sierra::Fmwk::get_derived_type(meshObj) != Entity::ELEMENT); meshObj.dec_connection(); } ThrowAssert(verify_relation_ordering(meshObj.internal_begin_relation(relType), meshObj.internal_end_relation(relType))); return true; }
void TemperaturePropAlgorithm::execute() { // make sure that partVec_ is size one ThrowAssert( partVec_.size() == 1 ); std::vector<double> indVarList(1); stk::mesh::Selector selector = stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& node_buckets = realm_.get_buckets( stk::topology::NODE_RANK, selector ); for ( stk::mesh::BucketVector::const_iterator ib = node_buckets.begin(); ib != node_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); double *prop = (double*) stk::mesh::field_data(*prop_, b); const double *temperature = (double*) stk::mesh::field_data(*temperature_, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { indVarList[0] = temperature[k]; prop[k] = propEvaluator_->execute(&indVarList[0], b[k]); } } }
void InverseDualVolumePropAlgorithm::execute() { // make sure that partVec_ is size one ThrowAssert( partVec_.size() == 1 ); stk::mesh::Selector selector = stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& node_buckets = realm_.get_buckets( stk::topology::NODE_RANK, selector ); for ( stk::mesh::BucketVector::const_iterator ib = node_buckets.begin(); ib != node_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); double *prop = (double*)stk::mesh::field_data(*prop_, b); const double *dualNodalVolume = (double*)stk::mesh::field_data(*dualNodalVolume_, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { prop[k] = 1.0/dualNodalVolume[k]; } } }
inline typename FieldTraits<FieldType>::data_type* field_data(const FieldType & f, const unsigned bucket_id, Bucket::size_type bucket_ord, const int knownSize) { ThrowAssertMsg(f.get_meta_data_for_field()[bucket_id].m_bytes_per_entity >= knownSize, "field name= " << f.name() << "knownSize= " << knownSize << ", m_bytes_per_entity= " << f.get_meta_data_for_field()[bucket_id].m_bytes_per_entity); ThrowAssert(f.get_meta_data_for_field()[bucket_id].m_data != NULL); return reinterpret_cast<typename FieldTraits<FieldType>::data_type*>(f.get_meta_data_for_field()[bucket_id].m_data + knownSize * bucket_ord); }
MEField<> *FieldReg::GetCoordField() const { Trace __trace("FieldReg::GetCoordField()"); MEField<> *cf = GetField("coordinates"); ThrowAssert(cf); return cf; }
void LinearPropAlgorithm::execute() { // make sure that partVec_ is size one ThrowAssert( partVec_.size() == 1 ); stk::mesh::Selector selector = stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& node_buckets = realm_.get_buckets( stk::topology::NODE_RANK, selector ); for ( stk::mesh::BucketVector::const_iterator ib = node_buckets.begin(); ib != node_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); double *prop = (double*) stk::mesh::field_data(*prop_, b); const double *indVar = (double*) stk::mesh::field_data(*indVar_, b); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { const double z = indVar[k]; const double om_z = 1.0-z; prop[k] = z*primary_ + om_z*secondary_; } } }
void internal_check_no_null_buckets_invariant() const { #ifndef NDEBUG for (int i = 0, e = m_buckets.size(); i < e; ++i) { ThrowAssert(m_buckets[i] != NULL); } #endif }
BBox BBoxIntersection(const BBox &b1, const BBox &b2) { BBox newbox(b1.dimension()); ThrowAssert(b1.dimension() == b2.dimension()); for (UInt i = 0; i < b1.dimension(); i++) { newbox.setMin(i, std::max(b1.getMin()[i], b2.getMin()[i])); newbox.setMax(i, std::min(b1.getMax()[i], b2.getMax()[i])); } newbox.checkEmpty(); return newbox; }
void mat_chunk( const Scalar* mat, int nrows, Scalar* chunk, int istart, int jstart, int iend, int jend) { // copies matrix section of column major square matrix into contiguous, row-major submatrix ThrowAssert(istart >= 0 && istart < iend); ThrowAssert(jstart >= 0 && jstart < jend); ThrowAssert(iend <= nrows); ThrowAssert(jend <= nrows); int jj = 0; for (int j = jstart; j < jend; ++j) { for (int i = istart; i < iend; ++i, ++jj) { chunk[jj] = mat[i*nrows + j]; } } }
stk::topology get_subcell_nodes(const BulkData& mesh, const Entity entity, EntityRank subcell_rank, unsigned subcell_identifier, EntityVector & subcell_nodes) { ThrowAssert(subcell_rank <= stk::topology::ELEMENT_RANK); subcell_nodes.clear(); // get cell topology stk::topology celltopology = mesh.bucket(entity).topology(); //error checking { //no celltopology defined if(celltopology == stk::topology::INVALID_TOPOLOGY) { return celltopology; } // valid ranks fall within the dimension of the cell topology const bool bad_rank = subcell_rank >= celltopology.dimension(); ThrowInvalidArgMsgIf( bad_rank, "subcell_rank is >= celltopology dimension\n"); // subcell_identifier must be less than the subcell count const bool bad_id = subcell_identifier >= celltopology.num_sub_topology(subcell_rank); ThrowInvalidArgMsgIf( bad_id, "subcell_id is >= subcell_count\n"); } // Get the cell topology of the subcell stk::topology subcell_topology = celltopology.sub_topology(subcell_rank, subcell_identifier); const int num_nodes_in_subcell = subcell_topology.num_nodes(); // For the subcell, get it's local nodes ids std::vector<unsigned> subcell_node_local_ids(num_nodes_in_subcell); celltopology.sub_topology_node_ordinals(subcell_rank, subcell_identifier, subcell_node_local_ids.begin()); Entity const *node_relations = mesh.begin_nodes(entity); subcell_nodes.reserve(num_nodes_in_subcell); for(int i = 0; i < num_nodes_in_subcell; ++i) { subcell_nodes.push_back(node_relations[subcell_node_local_ids[i]]); } return subcell_topology; }
bool BBoxIntersect(const BBox &b1, const BBox &b2, double tol) { double newmin; double newmax; ThrowAssert(b1.dimension() == b2.dimension()); for (UInt i = 0; i < b1.dimension(); i++) { newmin = std::max(b1.getMin()[i], b2.getMin()[i]); newmax = std::min(b1.getMax()[i], b2.getMax()[i]); if (newmin > (newmax+tol)) { //std::cout << "fail, dim=" << i << " newmin=" << newmin << ", newmax=" << newmax << std::endl; return false; } } return true; }
inline void field_fill( const Scalar data, NgpFieldVector<Scalar> & xField, const stk::mesh::Selector selector, const MPI_Comm comm) { ThrowAssert(typeid(Scalar) == xField.get_field().data_traits().type_info); stk::mesh::BucketVector const& buckets = xField.get_buckets(selector); for(size_t i=0; i < buckets.size(); i++) { stk::mesh::Bucket & b = *buckets[i]; KokkosBLAS<Scalar>::fill(field_length(xField, b), data, field_ptr(xField, b)); } }
void MEField<_FIELD>::Addfield(_FIELD *f, UInt nval) { // Store as a hash of fields by nval; std::vector<UInt>::iterator i = std::lower_bound(fidx_table.begin(), fidx_table.end(), nval); // Error if already there if (i == fidx_table.end() || *i != nval) { i = fidx_table.insert(i, nval); } else Throw() << "Field:" << fname << ", already added nval:" << nval; // Insert field at same spot. UInt pos = std::distance(fidx_table.begin(), i); typename std::vector<_FIELD*>::iterator fi = fields.begin() + pos; UInt cursize = fields.size(); if (cursize == 0) primaryfield = f; // if nval is larger, resize. Keeps old fields, assigns null elsewhere ThrowAssert(fields.size() <= pos); fields.insert(fi, f); }
//-------------------------------------------------------------------------- void ElementCondenser::compute_interior_update( double* lhs, const double* rhs, const double* boundary_values, double* delta_interior_values) { // Computes an update to the interior values given the updated rhs vector // and the elemental linear system mat_chunk(lhs, ne_, lhsII_.data(), nb_, nb_, ne_, ne_ ); int jj = 0; for (int j = nb_; j < ne_; ++j, ++jj) { delta_interior_values[jj] = rhs[j]; } // solve for update L_II^-1 rhs_I int info = 0; lapack_.GESV(ni_, 1, lhsII_.data(), ni_, ipiv_.data(), delta_interior_values, ni_, &info); ThrowAssert(info == 0); }
Entity declare_element(BulkData & mesh, PartVector & parts, const EntityId elem_id, const EntityIdVector & node_ids) { MetaData & fem_meta = MetaData::get(mesh); stk::topology top = fem_meta.get_topology(*parts[0]); ThrowAssert(node_ids.size() >= top.num_nodes()); ThrowErrorMsgIf(top == stk::topology::INVALID_TOPOLOGY, "Part " << parts[0]->name() << " does not have a local topology"); PartVector empty; const EntityRank entity_rank = stk::topology::ELEMENT_RANK; Entity elem = mesh.declare_entity(entity_rank, elem_id, parts); const EntityRank node_rank = stk::topology::NODE_RANK; Permutation perm = stk::mesh::Permutation::INVALID_PERMUTATION; OrdinalVector ordinal_scratch; ordinal_scratch.reserve(64); PartVector part_scratch; part_scratch.reserve(64); for(unsigned i = 0; i < top.num_nodes(); ++i) { //declare node if it doesn't already exist Entity node = mesh.get_entity(node_rank, node_ids[i]); if(!mesh.is_valid(node)) { node = mesh.declare_entity(node_rank, node_ids[i], empty); } mesh.declare_relation(elem, node, i, perm, ordinal_scratch, part_scratch); } return elem; }
inline void field_asum( Scalar & glob_result, NgpFieldVector<Scalar>& xField, const stk::mesh::Selector& selector, const MPI_Comm comm) { ThrowAssert(typeid(Scalar) == xField.get_field().data_traits().type_info); stk::mesh::BucketVector const& buckets = xField.get_buckets(selector); KokkosVector& dev_x = xField.device_get(); Scalar local_result = Scalar(0.0); for(size_t i=0; i < buckets.size(); i++) { stk::mesh::Bucket & b = *buckets[i]; int kmax = field_length(xField, b); xField.copy_to_device(kmax, field_ptr(xField, b)); Scalar gpu_result = Scalar(0.0); Kokkos::parallel_reduce( range_policy( 0, kmax), KOKKOS_LAMBDA ( int k, double& update ) { update += dev_x( k ); }, gpu_result );
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleMeshDisplacementElemSolverAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // space for LHS/RHS; nodesPerElem*nDim*nodesPerElem*nDim and nodesPerElem*nDim std::vector<double> lhs; std::vector<double> rhs; std::vector<int> scratchIds; std::vector<double> scratchVals; std::vector<stk::mesh::Entity> connected_nodes; // nodal fields to gather std::vector<double> ws_displacementNp1; std::vector<double> ws_coordinates; std::vector<double> ws_modelCoordinates; std::vector<double> ws_mu; std::vector<double> ws_lambda; // geometry related to populate std::vector<double> ws_scs_areav; std::vector<double> ws_dndx; std::vector<double> ws_deriv; std::vector<double> ws_det_j; std::vector<double> ws_shape_function; // deal with state VectorFieldType &displacementNp1 = meshDisplacement_->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& elem_buckets = realm_.get_buckets( stk::topology::ELEMENT_RANK, s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = elem_buckets.begin(); ib != elem_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // extract master element MasterElement *meSCS = sierra::nalu::MasterElementRepo::get_surface_master_element(b.topology()); // extract master element specifics const int nodesPerElement = meSCS->nodesPerElement_; const int numScsIp = meSCS->numIntPoints_; const int *lrscv = meSCS->adjacentNodes(); // resize some things; matrix related const int lhsSize = nodesPerElement*nDim*nodesPerElement*nDim; const int rhsSize = nodesPerElement*nDim; lhs.resize(lhsSize); rhs.resize(rhsSize); scratchIds.resize(rhsSize); scratchVals.resize(rhsSize); connected_nodes.resize(nodesPerElement); // algorithm related ws_displacementNp1.resize(nodesPerElement*nDim); ws_coordinates.resize(nodesPerElement*nDim); ws_modelCoordinates.resize(nodesPerElement*nDim); ws_mu.resize(nodesPerElement); ws_lambda.resize(nodesPerElement); ws_scs_areav.resize(numScsIp*nDim); ws_dndx.resize(nDim*numScsIp*nodesPerElement); ws_deriv.resize(nDim*numScsIp*nodesPerElement); ws_det_j.resize(numScsIp); ws_shape_function.resize(numScsIp*nodesPerElement); // pointer to lhs/rhs double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_displacementNp1 = &ws_displacementNp1[0]; double *p_coordinates = &ws_coordinates[0]; double *p_modelCoordinates = &ws_modelCoordinates[0]; double *p_mu = &ws_mu[0]; double *p_lambda = &ws_lambda[0]; double *p_scs_areav = &ws_scs_areav[0]; double *p_dndx = &ws_dndx[0]; double *p_shape_function = &ws_shape_function[0]; // extract shape function meSCS->shape_fcn(&p_shape_function[0]); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // 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; //=============================================== // gather nodal data; this is how we do it now.. //=============================================== stk::mesh::Entity const * node_rels = b.begin_nodes(k); int num_nodes = b.num_nodes(k); // sanity check on num nodes ThrowAssert( num_nodes == nodesPerElement ); for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = node_rels[ni]; // set connected nodes connected_nodes[ni] = node; // pointers to real data const double * dxNp1 = stk::mesh::field_data(displacementNp1, node); const double * coords = stk::mesh::field_data(*coordinates_, node); const double * modelCoords = stk::mesh::field_data(*modelCoordinates_, node); const double mu = *stk::mesh::field_data(*mu_, node); const double lambda = *stk::mesh::field_data(*lambda_, node); // gather scalars p_mu[ni] = mu; p_lambda[ni] = lambda; // gather vectors const int niNdim = ni*nDim; for ( int i=0; i < nDim; ++i ) { p_displacementNp1[niNdim+i] = dxNp1[i]; p_coordinates[niNdim+i] = coords[i]; p_modelCoordinates[niNdim+i] = modelCoords[i]; } } // compute geometry double scs_error = 0.0; meSCS->determinant(1, &p_coordinates[0], &p_scs_areav[0], &scs_error); // compute dndx; model coords or displaced? if ( deformWrtModelCoords_ ) { meSCS->grad_op(1, &p_modelCoordinates[0], &p_dndx[0], &ws_deriv[0], &ws_det_j[0], &scs_error); } else { meSCS->grad_op(1, &p_coordinates[0], &p_dndx[0], &ws_deriv[0], &ws_det_j[0], &scs_error); } for ( int ip = 0; ip < numScsIp; ++ip ) { const int ipNdim = ip*nDim; const int offSetSF = ip*nodesPerElement; // left and right nodes for this ip const int il = lrscv[2*ip]; const int ir = lrscv[2*ip+1]; // save off some offsets const int ilNdim = il*nDim; const int irNdim = ir*nDim; // compute scs point values; offset to Shape Function; sneak in divU double muIp = 0.0; double lambdaIp = 0.0; double divDx = 0.0; for ( int ic = 0; ic < nodesPerElement; ++ic ) { const double r = p_shape_function[offSetSF+ic]; muIp += r*p_mu[ic]; lambdaIp += r*p_lambda[ic]; const int offSetDnDx = nDim*nodesPerElement*ip + ic*nDim; for ( int j = 0; j < nDim; ++j ) { const double dxj = p_displacementNp1[ic*nDim+j]; divDx += dxj*p_dndx[offSetDnDx+j]; } } // assemble divDx term (explicit) for ( int i = 0; i < nDim; ++i ) { // divU stress term const double divTerm = -lambdaIp*divDx*p_scs_areav[ipNdim+i]; const int indexL = ilNdim + i; const int indexR = irNdim + i; // right hand side; L and R p_rhs[indexL] -= divTerm; p_rhs[indexR] += divTerm; } // stress for ( int ic = 0; ic < nodesPerElement; ++ic ) { const int icNdim = ic*nDim; for ( int i = 0; i < nDim; ++i ) { const int indexL = ilNdim + i; const int indexR = irNdim + i; const int rowL = indexL*nodesPerElement*nDim; const int rowR = indexR*nodesPerElement*nDim; const int rLiC_i = rowL+icNdim+i; const int rRiC_i = rowR+icNdim+i; // viscous stress const int offSetDnDx = nDim*nodesPerElement*ip + icNdim; double lhs_riC_i = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = p_scs_areav[ipNdim+j]; const double dxj = p_displacementNp1[icNdim+j]; // -mu*dxi/dxj*A_j; fixed i over j loop; see below.. const double lhsfacDiff_i = -muIp*p_dndx[offSetDnDx+j]*axj; // lhs; il then ir lhs_riC_i += lhsfacDiff_i; // -mu*dxj/dxi*A_j const double lhsfacDiff_j = -muIp*p_dndx[offSetDnDx+i]*axj; // lhs; il then ir p_lhs[rowL+icNdim+j] += lhsfacDiff_j; p_lhs[rowR+icNdim+j] -= lhsfacDiff_j; // rhs; il then ir p_rhs[indexL] -= lhsfacDiff_j*dxj; p_rhs[indexR] += lhsfacDiff_j*dxj; } // deal with accumulated lhs and flux for -mu*dxi/dxj*Aj p_lhs[rLiC_i] += lhs_riC_i; p_lhs[rRiC_i] -= lhs_riC_i; const double dxi = p_displacementNp1[icNdim+i]; p_rhs[indexL] -= lhs_riC_i*dxi; p_rhs[indexR] += lhs_riC_i*dxi; } } } apply_coeff(connected_nodes, scratchIds, scratchVals, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- elem_execute ---------------------------------------------------- //-------------------------------------------------------------------------- void MomentumMassBackwardEulerElemSuppAlg::elem_execute( double *lhs, double *rhs, stk::mesh::Entity element, MasterElement */*meSCS*/, MasterElement *meSCV) { // pointer to ME methods const int *ipNodeMap = meSCV->ipNodeMap(); const int nodesPerElement = meSCV->nodesPerElement_; const int numScvIp = meSCV->numIntPoints_; // gather stk::mesh::Entity const * node_rels = bulkData_->begin_nodes(element); int num_nodes = bulkData_->num_nodes(element); // sanity check on num nodes ThrowAssert( num_nodes == nodesPerElement ); for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = node_rels[ni]; // pointers to real data const double * uN = stk::mesh::field_data(*velocityN_, node ); const double * uNp1 = stk::mesh::field_data(*velocityNp1_, node ); const double * Gjp = stk::mesh::field_data(*Gjp_, node ); const double * coords = stk::mesh::field_data(*coordinates_, node); // gather scalars ws_rhoN_[ni] = *stk::mesh::field_data(*densityN_, node); ws_rhoNp1_[ni] = *stk::mesh::field_data(*densityNp1_, node); // gather vectors const int niNdim = ni*nDim_; for ( int j=0; j < nDim_; ++j ) { ws_uN_[niNdim+j] = uN[j]; ws_uNp1_[niNdim+j] = uNp1[j]; ws_Gjp_[niNdim+j] = Gjp[j]; ws_coordinates_[niNdim+j] = coords[j]; } } // compute geometry double scv_error = 0.0; meSCV->determinant(1, &ws_coordinates_[0], &ws_scv_volume_[0], &scv_error); for ( int ip = 0; ip < numScvIp; ++ip ) { // nearest node to ip const int nearestNode = ipNodeMap[ip]; // zero out; scalar and vector double rhoNScv = 0.0; double rhoNp1Scv = 0.0; for ( int j =0; j < nDim_; ++j ) { uNScv_[j] = 0.0; uNp1Scv_[j] = 0.0; GjpScv_[j] = 0.0; } const int offSet = ip*nodesPerElement; for ( int ic = 0; ic < nodesPerElement; ++ic ) { // save off shape function const double r = ws_shape_function_[offSet+ic]; // density rhoNScv += r*ws_rhoN_[ic]; rhoNp1Scv += r*ws_rhoNp1_[ic]; // velocity const int icNdim = ic*nDim_; for ( int j = 0; j < nDim_; ++j ) { uNScv_[j] += r*ws_uN_[icNdim+j]; uNp1Scv_[j] += r*ws_uNp1_[icNdim+j]; GjpScv_[j] += r*ws_Gjp_[icNdim+j]; } } // assemble rhs const double scV = ws_scv_volume_[ip]; const int nnNdim = nearestNode*nDim_; for ( int i = 0; i < nDim_; ++i ) { rhs[nnNdim+i] += -(rhoNp1Scv*uNp1Scv_[i]-rhoNScv*uNScv_[i])*scV/dt_ -GjpScv_[i]*scV; //- ws_Gjp_[nnNdim+i]*scV; } // manage LHS for ( int ic = 0; ic < nodesPerElement; ++ic ) { const int icNdim = ic*nDim_; // save off shape function const double r = ws_shape_function_[offSet+ic]; const double lhsfac = r*rhoNp1Scv*scV/dt_; for ( int i = 0; i < nDim_; ++i ) { const int indexNN = nnNdim + i; const int rowNN = indexNN*nodesPerElement*nDim_; const int rNNiC_i = rowNN+icNdim+i; lhs[rNNiC_i] += lhsfac; } } } }
//-------------------------------------------------------------------------- //-------- 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 AssembleContinuityElemSolverAlgorithm::execute() { stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // 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; nodesPerElem*nodesPerElem and nodesPerElem std::vector<double> lhs; std::vector<double> rhs; std::vector<stk::mesh::Entity> connected_nodes; // supplemental algorithm setup const size_t supplementalAlgSize = supplementalAlg_.size(); for ( size_t i = 0; i < supplementalAlgSize; ++i ) supplementalAlg_[i]->setup(); // nodal fields to gather std::vector<double> ws_vrtm; std::vector<double> ws_Gpdx; std::vector<double> ws_coordinates; std::vector<double> ws_pressure; std::vector<double> ws_density; // geometry related to populate std::vector<double> ws_scs_areav; std::vector<double> ws_dndx; std::vector<double> ws_dndx_lhs; std::vector<double> ws_deriv; std::vector<double> ws_det_j; std::vector<double> ws_shape_function; // integration point data that depends on size std::vector<double> uIp(nDim); std::vector<double> rho_uIp(nDim); std::vector<double> GpdxIp(nDim); std::vector<double> dpdxIp(nDim); // pointers to everyone... double *p_uIp = &uIp[0]; double *p_rho_uIp = &rho_uIp[0]; double *p_GpdxIp = &GpdxIp[0]; double *p_dpdxIp = &dpdxIp[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_) & !(realm_.get_inactive_selector()); stk::mesh::BucketVector const& elem_buckets = realm_.get_buckets( stk::topology::ELEMENT_RANK, s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = elem_buckets.begin(); ib != elem_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // extract master element MasterElement *meSCS = realm_.get_surface_master_element(b.topology()); MasterElement *meSCV = realm_.get_volume_master_element(b.topology()); // extract master element specifics const int nodesPerElement = meSCS->nodesPerElement_; const int numScsIp = meSCS->numIntPoints_; const int *lrscv = meSCS->adjacentNodes(); // resize some things; matrix related const int lhsSize = nodesPerElement*nodesPerElement; const int rhsSize = nodesPerElement; lhs.resize(lhsSize); rhs.resize(rhsSize); connected_nodes.resize(nodesPerElement); // algorithm related ws_vrtm.resize(nodesPerElement*nDim); ws_Gpdx.resize(nodesPerElement*nDim); ws_coordinates.resize(nodesPerElement*nDim); ws_pressure.resize(nodesPerElement); ws_density.resize(nodesPerElement); ws_scs_areav.resize(numScsIp*nDim); ws_dndx.resize(nDim*numScsIp*nodesPerElement); ws_dndx_lhs.resize(nDim*numScsIp*nodesPerElement); ws_deriv.resize(nDim*numScsIp*nodesPerElement); ws_det_j.resize(numScsIp); ws_shape_function.resize(numScsIp*nodesPerElement); // pointers double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_vrtm = &ws_vrtm[0]; double *p_Gpdx = &ws_Gpdx[0]; double *p_coordinates = &ws_coordinates[0]; double *p_pressure = &ws_pressure[0]; double *p_density = &ws_density[0]; double *p_scs_areav = &ws_scs_areav[0]; double *p_dndx = &ws_dndx[0]; double *p_dndx_lhs = reducedSensitivities_ ? &ws_dndx_lhs[0] : &ws_dndx[0]; double *p_shape_function = &ws_shape_function[0]; if ( shiftMdot_) meSCS->shifted_shape_fcn(&p_shape_function[0]); else meSCS->shape_fcn(&p_shape_function[0]); // resize possible supplemental element alg for ( size_t i = 0; i < supplementalAlgSize; ++i ) supplementalAlg_[i]->elem_resize(meSCS, meSCV); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // get elem stk::mesh::Entity elem = b[k]; // 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; //=============================================== // gather nodal data; this is how we do it now.. //=============================================== stk::mesh::Entity const * node_rels = b.begin_nodes(k); int num_nodes = b.num_nodes(k); // sanity check on num nodes ThrowAssert( num_nodes == nodesPerElement ); for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = node_rels[ni]; // set connected nodes connected_nodes[ni] = node; // pointers to real data const double * Gjp = stk::mesh::field_data(*Gpdx_, node ); const double * coords = stk::mesh::field_data(*coordinates_, node ); const double * vrtm = stk::mesh::field_data(*velocityRTM_, node ); // gather scalars p_pressure[ni] = *stk::mesh::field_data(*pressure_, node ); p_density[ni] = *stk::mesh::field_data(densityNp1, node ); // gather vectors const int niNdim = ni*nDim; for ( int j=0; j < nDim; ++j ) { p_vrtm[niNdim+j] = vrtm[j]; p_Gpdx[niNdim+j] = Gjp[j]; p_coordinates[niNdim+j] = coords[j]; } } // compute geometry double scs_error = 0.0; meSCS->determinant(1, &p_coordinates[0], &p_scs_areav[0], &scs_error); // compute dndx for residual if ( shiftPoisson_ ) meSCS->shifted_grad_op(1, &p_coordinates[0], &ws_dndx[0], &ws_deriv[0], &ws_det_j[0], &scs_error); else meSCS->grad_op(1, &p_coordinates[0], &ws_dndx[0], &ws_deriv[0], &ws_det_j[0], &scs_error); // compute dndx for LHS if ( reducedSensitivities_ ) meSCS->shifted_grad_op(1, &p_coordinates[0], &ws_dndx_lhs[0], &ws_deriv[0], &ws_det_j[0], &scs_error); for ( int ip = 0; ip < numScsIp; ++ip ) { // left and right nodes for this ip const int il = lrscv[2*ip]; const int ir = lrscv[2*ip+1]; // corresponding matrix rows int rowL = il*nodesPerElement; int rowR = ir*nodesPerElement; // setup for ip values; sneak in geometry for possible reduced sens for ( int j = 0; j < nDim; ++j ) { p_uIp[j] = 0.0; p_rho_uIp[j] = 0.0; p_GpdxIp[j] = 0.0; p_dpdxIp[j] = 0.0; } double rhoIp = 0.0; const int offSet = ip*nodesPerElement; for ( int ic = 0; ic < nodesPerElement; ++ic ) { const double r = p_shape_function[offSet+ic]; const double nodalPressure = p_pressure[ic]; const double nodalRho = p_density[ic]; rhoIp += r*nodalRho; double lhsfac = 0.0; const int offSetDnDx = nDim*nodesPerElement*ip + ic*nDim; for ( int j = 0; j < nDim; ++j ) { p_GpdxIp[j] += r*p_Gpdx[nDim*ic+j]; p_uIp[j] += r*p_vrtm[nDim*ic+j]; p_rho_uIp[j] += r*nodalRho*p_vrtm[nDim*ic+j]; p_dpdxIp[j] += p_dndx[offSetDnDx+j]*nodalPressure; lhsfac += -p_dndx_lhs[offSetDnDx+j]*p_scs_areav[ip*nDim+j]; } // assemble to lhs; left p_lhs[rowL+ic] += lhsfac; // assemble to lhs; right p_lhs[rowR+ic] -= lhsfac; } // assemble mdot double mdot = 0.0; for ( int j = 0; j < nDim; ++j ) { mdot += (interpTogether*p_rho_uIp[j] + om_interpTogether*rhoIp*p_uIp[j] - projTimeScale*(p_dpdxIp[j] - p_GpdxIp[j]))*p_scs_areav[ip*nDim+j]; } // residual; left and right p_rhs[il] -= mdot/projTimeScale; p_rhs[ir] += mdot/projTimeScale; } // call supplemental for ( size_t i = 0; i < supplementalAlgSize; ++i ) supplementalAlg_[i]->elem_execute( &lhs[0], &rhs[0], elem, meSCS, meSCV); apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- clip_min_distance_to_wall --------------------------------------- //-------------------------------------------------------------------------- void ShearStressTransportEquationSystem::clip_min_distance_to_wall() { // if this is a restart, then min distance has already been clipped if (realm_.restarted_simulation()) return; // okay, no restart: proceed with clipping of minimum wall distance stk::mesh::BulkData & bulk_data = realm_.bulk_data(); stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // extract fields required GenericFieldType *exposedAreaVec = meta_data.get_field<GenericFieldType>(meta_data.side_rank(), "exposed_area_vector"); VectorFieldType *coordinates = meta_data.get_field<VectorFieldType>(stk::topology::NODE_RANK, realm_.get_coordinates_name()); // define vector of parent topos; should always be UNITY in size std::vector<stk::topology> parentTopo; // selector stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(wallBcPart_); stk::mesh::BucketVector const& face_buckets = realm_.get_buckets( meta_data.side_rank(), s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = face_buckets.begin(); ib != face_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; // extract connected element topology b.parent_topology(stk::topology::ELEMENT_RANK, parentTopo); ThrowAssert ( parentTopo.size() == 1 ); stk::topology theElemTopo = parentTopo[0]; // extract master element MasterElement *meSCS = realm_.get_surface_master_element(theElemTopo); // face master element const int nodesPerFace = b.topology().num_nodes(); std::vector<int> face_node_ordinal_vec(nodesPerFace); const stk::mesh::Bucket::size_type length = b.size(); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // get face stk::mesh::Entity face = b[k]; int num_face_nodes = bulk_data.num_nodes(face); // pointer to face data const double * areaVec = stk::mesh::field_data(*exposedAreaVec, face); // extract the connected element to this exposed face; should be single in size! const stk::mesh::Entity* face_elem_rels = bulk_data.begin_elements(face); ThrowAssert( bulk_data.num_elements(face) == 1 ); // get element; its face ordinal number and populate face_node_ordinal_vec stk::mesh::Entity element = face_elem_rels[0]; const int face_ordinal = bulk_data.begin_element_ordinals(face)[0]; theElemTopo.side_node_ordinals(face_ordinal, face_node_ordinal_vec.begin()); // get the relations off of element stk::mesh::Entity const * elem_node_rels = bulk_data.begin_nodes(element); // loop over face nodes for ( int ip = 0; ip < num_face_nodes; ++ip ) { const int offSetAveraVec = ip*nDim; const int opposingNode = meSCS->opposingNodes(face_ordinal,ip); const int nearestNode = face_node_ordinal_vec[ip]; // left and right nodes; right is on the face; left is the opposing node stk::mesh::Entity nodeL = elem_node_rels[opposingNode]; stk::mesh::Entity nodeR = elem_node_rels[nearestNode]; // extract nodal fields const double * coordL = stk::mesh::field_data(*coordinates, nodeL ); const double * coordR = stk::mesh::field_data(*coordinates, nodeR ); double aMag = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[offSetAveraVec+j]; aMag += axj*axj; } aMag = std::sqrt(aMag); // form unit normal and determine yp (approximated by 1/4 distance along edge) double ypbip = 0.0; for ( int j = 0; j < nDim; ++j ) { const double nj = areaVec[offSetAveraVec+j]/aMag; const double ej = 0.25*(coordR[j] - coordL[j]); ypbip += nj*ej*nj*ej; } ypbip = std::sqrt(ypbip); // assemble to nodal quantities double *minD = stk::mesh::field_data(*minDistanceToWall_, nodeR ); *minD = std::max(*minD, ypbip); } } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleScalarElemOpenSolverAlgorithm::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 alphaUpw = realm_.get_alpha_upw_factor(dofName); const double hoUpwind = realm_.get_upw_factor(dofName); // one minus flavor.. const double om_alphaUpw = 1.0-alphaUpw; // space for LHS/RHS; nodesPerElement*nodesPerElement and nodesPerElement 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; only boundary std::vector<double> coordBip(nDim); // pointers to fixed values double *p_coordBip = &coordBip[0]; // nodal fields to gather std::vector<double> ws_face_coordinates; std::vector<double> ws_scalarQNp1; std::vector<double> ws_bcScalarQ; // master element std::vector<double> ws_face_shape_function; // deal with state ScalarFieldType &scalarQNp1 = scalarQ_->field_of_state(stk::mesh::StateNP1); ScalarFieldType &densityNp1 = density_->field_of_state(stk::mesh::StateNP1); // define vector of parent topos; should always be UNITY in size std::vector<stk::topology> parentTopo; // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& face_buckets = realm_.get_buckets( meta_data.side_rank(), s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = face_buckets.begin(); ib != face_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; // extract connected element topology b.parent_topology(stk::topology::ELEMENT_RANK, parentTopo); ThrowAssert ( parentTopo.size() == 1 ); stk::topology theElemTopo = parentTopo[0]; // volume master element MasterElement *meSCS = realm_.get_surface_master_element(theElemTopo); const int nodesPerElement = meSCS->nodesPerElement_; // face master element MasterElement *meFC = realm_.get_surface_master_element(b.topology()); const int nodesPerFace = meFC->nodesPerElement_; const int numScsBip = meFC->numIntPoints_; std::vector<int> face_node_ordinal_vec(nodesPerFace); // resize some things; matrix related const int lhsSize = nodesPerElement*nodesPerElement; const int rhsSize = nodesPerElement; lhs.resize(lhsSize); rhs.resize(rhsSize); scratchIds.resize(rhsSize); scratchVals.resize(rhsSize); connected_nodes.resize(nodesPerElement); // algorithm related; element ws_face_coordinates.resize(nodesPerFace*nDim); ws_scalarQNp1.resize(nodesPerFace); ws_bcScalarQ.resize(nodesPerFace); ws_face_shape_function.resize(numScsBip*nodesPerFace); // pointers double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_face_coordinates = &ws_face_coordinates[0]; double *p_scalarQNp1 = &ws_scalarQNp1[0]; double *p_bcScalarQ = &ws_bcScalarQ[0]; double *p_face_shape_function = &ws_face_shape_function[0]; // shape functions meFC->shape_fcn(&p_face_shape_function[0]); const stk::mesh::Bucket::size_type length = b.size(); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // 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; // get face stk::mesh::Entity face = b[k]; // pointer to face data const double * mdot = stk::mesh::field_data(*openMassFlowRate_, face); //====================================== // gather nodal data off of face //====================================== stk::mesh::Entity const * face_node_rels = bulk_data.begin_nodes(face); int num_face_nodes = bulk_data.num_nodes(face); // sanity check on num nodes ThrowAssert( num_face_nodes == nodesPerFace ); for ( int ni = 0; ni < num_face_nodes; ++ni ) { stk::mesh::Entity node = face_node_rels[ni]; // gather scalars p_scalarQNp1[ni] = *stk::mesh::field_data(scalarQNp1, node); p_bcScalarQ[ni] = *stk::mesh::field_data(*bcScalarQ_, node); // gather vectors double * coords = stk::mesh::field_data(*coordinates_, node); const int offSet = ni*nDim; for ( int i=0; i < nDim; ++i ) { p_face_coordinates[offSet+i] = coords[i]; } } // extract the connected element to this exposed face; should be single in size! const stk::mesh::Entity* face_elem_rels = bulk_data.begin_elements(face); ThrowAssert( bulk_data.num_elements(face) == 1 ); // get element; its face ordinal number and populate face_node_ordinal_vec stk::mesh::Entity element = face_elem_rels[0]; const int face_ordinal = bulk_data.begin_element_ordinals(face)[0]; theElemTopo.side_node_ordinals(face_ordinal, face_node_ordinal_vec.begin()); // mapping from ip to nodes for this ordinal const int *ipNodeMap = meSCS->ipNodeMap(face_ordinal); //========================================== // gather nodal data off of element; n/a //========================================== stk::mesh::Entity const * elem_node_rels = bulk_data.begin_nodes(element); int num_nodes = bulk_data.num_nodes(element); // sanity check on num nodes ThrowAssert( num_nodes == nodesPerElement ); for ( int ni = 0; ni < num_nodes; ++ni ) { // set connected nodes connected_nodes[ni] = elem_node_rels[ni]; } // loop over face nodes for ( int ip = 0; ip < numScsBip; ++ip ) { const int opposingNode = meSCS->opposingNodes(face_ordinal,ip); const int nearestNode = ipNodeMap[ip]; const int offSetSF_face = ip*nodesPerFace; // left and right nodes; right is on the face; left is the opposing node stk::mesh::Entity nodeL = elem_node_rels[opposingNode]; stk::mesh::Entity nodeR = elem_node_rels[nearestNode]; // zero out vector quantities for ( int j = 0; j < nDim; ++j ) p_coordBip[j] = 0.0; // interpolate to bip double qIp = 0.0; double qIpEntrain = 0.0; for ( int ic = 0; ic < nodesPerFace; ++ic ) { const double r = p_face_shape_function[offSetSF_face+ic]; qIp += r*p_scalarQNp1[ic]; qIpEntrain += r*p_bcScalarQ[ic]; const int offSetFN = ic*nDim; for ( int j = 0; j < nDim; ++j ) { p_coordBip[j] += r*p_face_coordinates[offSetFN+j]; } } // Peclet factor; along the edge is fine const double densL = *stk::mesh::field_data(densityNp1, nodeL); const double densR = *stk::mesh::field_data(densityNp1, nodeR); const double diffCoeffL = *stk::mesh::field_data(*diffFluxCoeff_, nodeL); const double diffCoeffR = *stk::mesh::field_data(*diffFluxCoeff_, nodeR); const double scalarQNp1R = *stk::mesh::field_data(scalarQNp1, nodeR); const double *vrtmL = stk::mesh::field_data(*velocityRTM_, nodeL); const double *vrtmR = stk::mesh::field_data(*velocityRTM_, nodeR); const double *coordL = stk::mesh::field_data(*coordinates_, nodeL); const double *coordR = stk::mesh::field_data(*coordinates_, nodeR); const double *dqdxR = stk::mesh::field_data(*dqdx_, nodeR); double udotx = 0.0; double dqR = 0.0; for ( int i = 0; i < nDim; ++i ) { const double dxi = coordR[i] - coordL[i]; udotx += 0.5*dxi*(vrtmL[i] + vrtmR[i]); // extrapolation const double dx_bip = coordBip[i] - coordR[i]; dqR += dx_bip*dqdxR[i]*hoUpwind; } const double qIpUpw = scalarQNp1R + dqR; const double diffIp = 0.5*(diffCoeffL/densL + diffCoeffR/densR); const double pecfac = pecletFunction_->execute(std::abs(udotx)/(diffIp+small)); const double om_pecfac = 1.0-pecfac; //================================ // advection first (and only) //================================ const double tmdot = mdot[ip]; const int rowR = nearestNode*nodesPerElement; // advection; leaving the domain if ( tmdot > 0.0 ) { // central; is simply qIp // upwind const double qUpwind = alphaUpw*qIpUpw + (om_alphaUpw)*qIp; // total advection const double aflux = tmdot*(pecfac*qUpwind+om_pecfac*qIp); p_rhs[nearestNode] -= aflux; // upwind lhs p_lhs[rowR+nearestNode] += tmdot*pecfac*alphaUpw; // central part const double fac = tmdot*(pecfac*om_alphaUpw+om_pecfac); for ( int ic = 0; ic < nodesPerFace; ++ic ) { const double r = p_face_shape_function[offSetSF_face+ic]; const int nn = face_node_ordinal_vec[ic]; p_lhs[rowR+nn] += r*fac; } } else { // extrainment; advect in from specified value const double aflux = tmdot*qIpEntrain; p_rhs[nearestNode] -= aflux; } } apply_coeff(connected_nodes, scratchIds, scratchVals, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleScalarElemSolverAlgorithm::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; nodesPerElem*nodesPerElem* and nodesPerElem std::vector<double> lhs; std::vector<double> rhs; std::vector<stk::mesh::Entity> connected_nodes; // supplemental algorithm size and setup const size_t supplementalAlgSize = supplementalAlg_.size(); for ( size_t i = 0; i < supplementalAlgSize; ++i ) supplementalAlg_[i]->setup(); // nodal fields to gather std::vector<double> ws_velocityNp1; std::vector<double> ws_meshVelocity; std::vector<double> ws_vrtm; std::vector<double> ws_coordinates; std::vector<double> ws_scalarQNp1; std::vector<double> ws_dqdx; std::vector<double> ws_density; std::vector<double> ws_diffFluxCoeff; // geometry related to populate std::vector<double> ws_scs_areav; std::vector<double> ws_dndx; std::vector<double> ws_deriv; std::vector<double> ws_det_j; std::vector<double> ws_shape_function; // ip values std::vector<double>coordIp(nDim); // pointers double *p_coordIp = &coordIp[0]; // deal with state ScalarFieldType &scalarQNp1 = scalarQ_->field_of_state(stk::mesh::StateNP1); 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& elem_buckets = realm_.get_buckets( stk::topology::ELEMENT_RANK, s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = elem_buckets.begin(); ib != elem_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; const stk::mesh::Bucket::size_type length = b.size(); // extract master element MasterElement *meSCS = realm_.get_surface_master_element(b.topology()); // extract master element specifics const int nodesPerElement = meSCS->nodesPerElement_; const int numScsIp = meSCS->numIntPoints_; const int *lrscv = meSCS->adjacentNodes(); // resize some things; matrix related const int lhsSize = nodesPerElement*nodesPerElement; const int rhsSize = nodesPerElement; lhs.resize(lhsSize); rhs.resize(rhsSize); connected_nodes.resize(nodesPerElement); // algorithm related ws_velocityNp1.resize(nodesPerElement*nDim); ws_meshVelocity.resize(nodesPerElement*nDim); ws_vrtm.resize(nodesPerElement*nDim); ws_coordinates.resize(nodesPerElement*nDim); ws_dqdx.resize(nodesPerElement*nDim); ws_scalarQNp1.resize(nodesPerElement); ws_density.resize(nodesPerElement); ws_diffFluxCoeff.resize(nodesPerElement); ws_scs_areav.resize(numScsIp*nDim); ws_dndx.resize(nDim*numScsIp*nodesPerElement); ws_deriv.resize(nDim*numScsIp*nodesPerElement); ws_det_j.resize(numScsIp); ws_shape_function.resize(numScsIp*nodesPerElement); // pointer to lhs/rhs double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_velocityNp1 = &ws_velocityNp1[0]; double *p_meshVelocity = &ws_meshVelocity[0]; double *p_vrtm = &ws_vrtm[0]; double *p_coordinates = &ws_coordinates[0]; double *p_dqdx = &ws_dqdx[0]; double *p_scalarQNp1 = &ws_scalarQNp1[0]; double *p_density = &ws_density[0]; double *p_diffFluxCoeff = &ws_diffFluxCoeff[0]; double *p_scs_areav = &ws_scs_areav[0]; double *p_dndx = &ws_dndx[0]; double *p_shape_function = &ws_shape_function[0]; // extract shape function meSCS->shape_fcn(&p_shape_function[0]); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // get elem stk::mesh::Entity elem = b[k]; // 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; // ip data for this element; scs and scv const double *mdot = stk::mesh::field_data(*massFlowRate_, elem ); //=============================================== // gather nodal data; this is how we do it now.. //=============================================== stk::mesh::Entity const * node_rels = bulk_data.begin_nodes(elem); int num_nodes = bulk_data.num_nodes(elem); // sanity check on num nodes ThrowAssert( num_nodes == nodesPerElement ); for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = node_rels[ni]; // set connected nodes connected_nodes[ni] = node; // pointers to real data const double * uNp1 = stk::mesh::field_data(velocityNp1, node ); const double * vNp1 = stk::mesh::field_data(*meshVelocity_, node); const double * coords = stk::mesh::field_data(*coordinates_, node ); const double * dq = stk::mesh::field_data(*dqdx_, node ); // gather scalars p_scalarQNp1[ni] = *stk::mesh::field_data(scalarQNp1, node ); p_density[ni] = *stk::mesh::field_data(densityNp1, node ); p_diffFluxCoeff[ni] = *stk::mesh::field_data(*diffFluxCoeff_, node ); // gather vectors const int niNdim = ni*nDim; for ( int i=0; i < nDim; ++i ) { p_velocityNp1[niNdim+i] = uNp1[i]; p_vrtm[niNdim+i] = uNp1[i]; p_meshVelocity[niNdim+i] = vNp1[i]; p_coordinates[niNdim+i] = coords[i]; p_dqdx[niNdim+i] = dq[i]; } } // compute geometry double scs_error = 0.0; meSCS->determinant(1, &p_coordinates[0], &p_scs_areav[0], &scs_error); // compute dndx meSCS->grad_op(1, &p_coordinates[0], &p_dndx[0], &ws_deriv[0], &ws_det_j[0], &scs_error); // manage velocity relative to mesh if ( meshMotion_ ) { const int kSize = num_nodes*nDim; for ( int k = 0; k < kSize; ++k ) { p_vrtm[k] -= p_meshVelocity[k]; } } for ( int ip = 0; ip < numScsIp; ++ip ) { // left and right nodes for this ip const int il = lrscv[2*ip]; const int ir = lrscv[2*ip+1]; // corresponding matrix rows const int rowL = il*nodesPerElement; const int rowR = ir*nodesPerElement; // save off mdot const double tmdot = mdot[ip]; // zero out values of interest for this ip for ( int j = 0; j < nDim; ++j ) { p_coordIp[j] = 0.0; } // save off ip values; offset to Shape Function double rhoIp = 0.0; double muIp = 0.0; double qIp = 0.0; const int offSetSF = ip*nodesPerElement; for ( int ic = 0; ic < nodesPerElement; ++ic ) { const double r = p_shape_function[offSetSF+ic]; rhoIp += r*p_density[ic]; muIp += r*p_diffFluxCoeff[ic]; qIp += r*p_scalarQNp1[ic]; // compute scs point values for ( int i = 0; i < nDim; ++i ) { p_coordIp[i] += r*p_coordinates[ic*nDim+i]; } } // Peclet factor; along the edge const double diffIp = 0.5*(p_diffFluxCoeff[il]/p_density[il] + p_diffFluxCoeff[ir]/p_density[ir]); double udotx = 0.0; for(int j = 0; j < nDim; ++j ) { const double dxj = p_coordinates[ir*nDim+j]-p_coordinates[il*nDim+j]; const double uj = 0.5*(p_vrtm[il*nDim+j] + p_vrtm[ir*nDim+j]); udotx += uj*dxj; } double pecfac = hybridFactor*udotx/(diffIp+small); pecfac = pecfac*pecfac/(5.0 + pecfac*pecfac); const double om_pecfac = 1.0-pecfac; // left and right extrapolation double dqL = 0.0; double dqR = 0.0; for(int j = 0; j < nDim; ++j ) { const double dxjL = p_coordIp[j] - p_coordinates[il*nDim+j]; const double dxjR = p_coordinates[ir*nDim+j] - p_coordIp[j]; dqL += dxjL*p_dqdx[nDim*il+j]; dqR += dxjR*p_dqdx[nDim*ir+j]; } // add limiter if appropriate double limitL = 1.0; double limitR = 1.0; if ( useLimiter ) { const double dq = p_scalarQNp1[ir] - p_scalarQNp1[il]; 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 (along edge is fine) const double qIpL = p_scalarQNp1[il] + dqL*hoUpwind*limitL; const double qIpR = p_scalarQNp1[ir] - dqR*hoUpwind*limitR; // assemble advection; rhs and upwind contributions // 2nd order central; simply qIp from above // 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); // right hand side; L and R p_rhs[il] -= aflux; p_rhs[ir] += aflux; // advection operator sens; all but central // upwind advection (includes 4th); left node const double alhsfacL = 0.5*(tmdot+std::abs(tmdot))*pecfac*alphaUpw + 0.5*alpha*om_pecfac*tmdot; p_lhs[rowL+il] += alhsfacL; p_lhs[rowR+il] -= alhsfacL; // upwind advection; right node const double alhsfacR = 0.5*(tmdot-std::abs(tmdot))*pecfac*alphaUpw + 0.5*alpha*om_pecfac*tmdot; p_lhs[rowR+ir] -= alhsfacR; p_lhs[rowL+ir] += alhsfacR; double qDiff = 0.0; for ( int ic = 0; ic < nodesPerElement; ++ic ) { // shape function const double r = p_shape_function[offSetSF+ic]; // upwind (il/ir) handled above; collect terms on alpha and alphaUpw const double lhsfacAdv = r*tmdot*(pecfac*om_alphaUpw + om_pecfac*om_alpha); // advection operator lhs; rhs handled above // lhs; il then ir p_lhs[rowL+ic] += lhsfacAdv; p_lhs[rowR+ic] -= lhsfacAdv; // diffusion double lhsfacDiff = 0.0; const int offSetDnDx = nDim*nodesPerElement*ip + ic*nDim; for ( int j = 0; j < nDim; ++j ) { lhsfacDiff += -muIp*p_dndx[offSetDnDx+j]*p_scs_areav[ip*nDim+j]; } qDiff += lhsfacDiff*p_scalarQNp1[ic]; // lhs; il then ir p_lhs[rowL+ic] += lhsfacDiff; p_lhs[rowR+ic] -= lhsfacDiff; } // rhs; il then ir p_rhs[il] -= qDiff; p_rhs[ir] += qDiff; } // call supplemental for ( size_t i = 0; i < supplementalAlgSize; ++i ) supplementalAlg_[i]->elem_execute( nodesPerElement, numScsIp, &lhs[0], &rhs[0], elem); apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleScalarEdgeOpenSolverAlgorithm::execute() { stk::mesh::BulkData & bulk_data = realm_.bulk_data(); stk::mesh::MetaData & meta_data = realm_.meta_data(); // space for LHS/RHS; nodesPerElement*nodesPerElement and nodesPerElement std::vector<double> lhs; std::vector<double> rhs; std::vector<stk::mesh::Entity> connected_nodes; // deal with state ScalarFieldType &scalarQNp1 = scalarQ_->field_of_state(stk::mesh::StateNP1); // define vector of parent topos; should always be UNITY in size std::vector<stk::topology> parentTopo; // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& face_buckets = realm_.get_buckets( meta_data.side_rank(), s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = face_buckets.begin(); ib != face_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; // extract connected element topology b.parent_topology(stk::topology::ELEMENT_RANK, parentTopo); ThrowAssert ( parentTopo.size() == 1 ); stk::topology theElemTopo = parentTopo[0]; // volume master element MasterElement *meSCS = realm_.get_surface_master_element(theElemTopo); const int nodesPerElement = meSCS->nodesPerElement_; // face master element MasterElement *meFC = realm_.get_surface_master_element(b.topology()); const int nodesPerFace = meFC->nodesPerElement_; std::vector<int> face_node_ordinal_vec(nodesPerFace); // resize some things; matrix related const int lhsSize = nodesPerElement*nodesPerElement; const int rhsSize = nodesPerElement; lhs.resize(lhsSize); rhs.resize(rhsSize); connected_nodes.resize(nodesPerElement); // pointers double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; // size some things that are useful const int num_face_nodes = b.topology().num_nodes(); std::vector<int> face_node_ordinals(num_face_nodes); const stk::mesh::Bucket::size_type length = b.size(); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // 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; // get face stk::mesh::Entity face = b[k]; // pointer to face data const double * mdot = stk::mesh::field_data(*openMassFlowRate_, face); // extract the connected element to this exposed face; should be single in size! const stk::mesh::Entity* face_elem_rels = bulk_data.begin_elements(face); ThrowAssert( bulk_data.num_elements(face) == 1 ); // get element; its face ordinal number and populate face_node_ordinal_vec stk::mesh::Entity element = face_elem_rels[0]; const int face_ordinal = bulk_data.begin_element_ordinals(face)[0]; theElemTopo.side_node_ordinals(face_ordinal, face_node_ordinal_vec.begin()); //========================================== // gather nodal data off of element; n/a //========================================== const stk::mesh::Entity* elem_node_rels = bulk_data.begin_nodes(element); const int num_nodes = bulk_data.num_nodes(element); // sanity check on num nodes ThrowAssert( num_nodes == nodesPerElement ); for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = elem_node_rels[ni]; // set connected nodes connected_nodes[ni] = node; } // loop over face nodes for ( int ip = 0; ip < num_face_nodes; ++ip ) { const int nearestNode = face_node_ordinal_vec[ip]; // left and right nodes; right is on the face; left is the opposing node stk::mesh::Entity nodeR = elem_node_rels[nearestNode]; const double qR = *stk::mesh::field_data( scalarQNp1, nodeR ); const double qEntrain = *stk::mesh::field_data( *bcScalarQ_, nodeR ); //================================ // advection first (and only) //================================ const double tmdot = mdot[ip]; const int rowR = nearestNode*nodesPerElement; // advection; leaving the domain if ( tmdot > 0.0 ) { // total advection const double aflux = tmdot*qR; p_rhs[nearestNode] -= aflux; // upwind lhs p_lhs[rowR+nearestNode] += tmdot; } else { // extrainment; advect in from specified value const double aflux = tmdot*qEntrain; p_rhs[nearestNode] -= aflux; } } apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- elem_execute ---------------------------------------------------- //-------------------------------------------------------------------------- void ScalarMassBDF2ElemSuppAlg::elem_execute( double *lhs, double *rhs, stk::mesh::Entity element, MasterElement */*meSCS*/, MasterElement *meSCV) { // pointer to ME methods const int *ipNodeMap = meSCV->ipNodeMap(); const int nodesPerElement = meSCV->nodesPerElement_; const int numScvIp = meSCV->numIntPoints_; // gather stk::mesh::Entity const * node_rels = bulkData_->begin_nodes(element); int num_nodes = bulkData_->num_nodes(element); // sanity check on num nodes ThrowAssert( num_nodes == nodesPerElement ); for ( int ni = 0; ni < num_nodes; ++ni ) { stk::mesh::Entity node = node_rels[ni]; // pointers to real data const double * coords = stk::mesh::field_data(*coordinates_, node); // gather scalars ws_qNm1_[ni] = *stk::mesh::field_data(*scalarQNm1_, node); ws_qN_[ni] = *stk::mesh::field_data(*scalarQN_, node); ws_qNp1_[ni] = *stk::mesh::field_data(*scalarQNp1_, node); ws_rhoNm1_[ni] = *stk::mesh::field_data(*densityNm1_, node); ws_rhoN_[ni] = *stk::mesh::field_data(*densityN_, node); ws_rhoNp1_[ni] = *stk::mesh::field_data(*densityNp1_, node); // gather vectors const int niNdim = ni*nDim_; for ( int i=0; i < nDim_; ++i ) { ws_coordinates_[niNdim+i] = coords[i]; } } // compute geometry double scv_error = 0.0; meSCV->determinant(1, &ws_coordinates_[0], &ws_scv_volume_[0], &scv_error); for ( int ip = 0; ip < numScvIp; ++ip ) { // nearest node to ip const int nearestNode = ipNodeMap[ip]; // zero out; scalar double qNm1Scv = 0.0; double qNScv = 0.0; double qNp1Scv = 0.0; double rhoNm1Scv = 0.0; double rhoNScv = 0.0; double rhoNp1Scv = 0.0; const int offSet = ip*nodesPerElement; for ( int ic = 0; ic < nodesPerElement; ++ic ) { // save off shape function const double r = ws_shape_function_[offSet+ic]; // scalar q qNm1Scv += r*ws_qNm1_[ic]; qNScv += r*ws_qN_[ic]; qNp1Scv += r*ws_qNp1_[ic]; // density rhoNm1Scv += r*ws_rhoNm1_[ic]; rhoNScv += r*ws_rhoN_[ic]; rhoNp1Scv += r*ws_rhoNp1_[ic]; } // assemble rhs const double scV = ws_scv_volume_[ip]; rhs[nearestNode] += -(gamma1_*rhoNp1Scv*qNp1Scv + gamma2_*rhoNScv*qNScv + gamma3_*rhoNm1Scv*qNm1Scv)*scV/dt_; // manage LHS for ( int ic = 0; ic < nodesPerElement; ++ic ) { // save off shape function const double r = ws_shape_function_[offSet+ic]; const double lhsfac = r*gamma1_*rhoNp1Scv*scV/dt_; const int rNNiC = nearestNode*nodesPerElement+ic; lhs[rNNiC] += lhsfac; } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleMomentumEdgeOpenSolverAlgorithm::execute() { stk::mesh::BulkData & bulk_data = realm_.bulk_data(); stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // nearest face entrainment const double nfEntrain = realm_.solutionOptions_->nearestFaceEntrain_; const double om_nfEntrain = 1.0-nfEntrain; // space for dui/dxj; the modified gradient with NOC std::vector<double> duidxj(nDim*nDim); // lhs/rhs space std::vector<stk::mesh::Entity> connected_nodes; std::vector<double> rhs; std::vector<double> lhs; std::vector<double> nx(nDim); std::vector<double> fx(nDim); // pointers double *p_duidxj = &duidxj[0]; double *p_nx = &nx[0]; double *p_fx = &fx[0]; // deal with state VectorFieldType &velocityNp1 = velocity_->field_of_state(stk::mesh::StateNP1); // define vector of parent topos std::vector<stk::topology> parentTopo; // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& face_buckets = realm_.get_buckets( meta_data.side_rank(), s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = face_buckets.begin(); ib != face_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; // extract connected element topology b.parent_topology(stk::topology::ELEMENT_RANK, parentTopo); ThrowAssert ( parentTopo.size() == 1 ); stk::topology theElemTopo = parentTopo[0]; MasterElement *meSCS = realm_.get_surface_master_element(theElemTopo); const int nodesPerElement = meSCS->nodesPerElement_; // resize some things; matrix related const int lhsSize = nodesPerElement*nDim*nodesPerElement*nDim; const int rhsSize = nodesPerElement*nDim; lhs.resize(lhsSize); rhs.resize(rhsSize); connected_nodes.resize(nodesPerElement); // pointer to lhs/rhs double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; // size some things that are useful const int num_face_nodes = b.topology().num_nodes(); std::vector<int> face_node_ordinals(num_face_nodes); const stk::mesh::Bucket::size_type length = b.size(); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // 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; // pointer to face data const double * areaVec = stk::mesh::field_data(*exposedAreaVec_, b, k); const double * mdot = stk::mesh::field_data(*openMassFlowRate_, b, k); // extract the connected element to this exposed face; should be single in size! stk::mesh::Entity const * face_elem_rels = b.begin_elements(k); ThrowAssert( b.num_elements(k) == 1 ); // get element; its face ordinal number and populate face_node_ordinals stk::mesh::Entity element = face_elem_rels[0]; const int face_ordinal = b.begin_element_ordinals(k)[0]; theElemTopo.side_node_ordinals(face_ordinal, face_node_ordinals.begin()); // get the relations; populate connected nodes stk::mesh::Entity const * elem_node_rels = bulk_data.begin_nodes(element); int num_nodes = bulk_data.num_nodes(element); // sanity check on num nodes ThrowAssert( num_nodes == nodesPerElement ); for ( int ni = 0; ni < num_nodes; ++ni ) { // set connected nodes connected_nodes[ni] = elem_node_rels[ni]; } // loop over face nodes (maps directly to ips) for ( int ip = 0; ip < num_face_nodes; ++ip ) { const int opposingNode = meSCS->opposingNodes(face_ordinal,ip); // "Left" const int nearestNode = face_node_ordinals[ip]; // "Right" // left and right nodes; right is on the face; left is the opposing node stk::mesh::Entity nodeL = elem_node_rels[opposingNode]; stk::mesh::Entity nodeR = elem_node_rels[nearestNode]; // extract nodal fields const double * coordL = stk::mesh::field_data(*coordinates_, nodeL ); const double * coordR = stk::mesh::field_data(*coordinates_, nodeR ); const double * uNp1L = stk::mesh::field_data(velocityNp1, nodeL ); const double * uNp1R = stk::mesh::field_data(velocityNp1, nodeR ); const double viscosityR = *stk::mesh::field_data(*viscosity_, nodeR ); const double viscBip = viscosityR; // a few only required (or even defined) on nodeR const double *bcVelocity = stk::mesh::field_data(*velocityBc_, nodeR ); const double * dudxR = stk::mesh::field_data(*dudx_, nodeR ); // offset for bip area vector const int faceOffSet = ip*nDim; // compute geometry double axdx = 0.0; double asq = 0.0; double udotx = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; const double dxj = coordR[j] - coordL[j]; asq += axj*axj; axdx += axj*dxj; udotx += 0.5*dxj*(uNp1L[j] + uNp1R[j]); } const double inv_axdx = 1.0/axdx; const double amag = std::sqrt(asq); // form duidxj with over-relaxed procedure of Jasak: 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 = 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 = areaVec[faceOffSet+j]; const double GjUi = 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]; double fxnx = 0.0; double uxnx = 0.0; double uxnxip = 0.0; double uspecxnx = 0.0; for (int i = 0; i < nDim; ++i ) { const double axi = areaVec[faceOffSet+i]; double fxi = 2.0/3.0*viscBip*divU*axi*includeDivU_; const int offSetI = nDim*i; const double nxi = axi/amag; for ( int j = 0; j < nDim; ++j ) { const int offSetTrans = nDim*j+i; const double axj = areaVec[faceOffSet+j]; fxi += -viscBip*(p_duidxj[offSetI+j] + p_duidxj[offSetTrans])*axj; } fxnx += nxi*fxi; uxnx += nxi*uNp1R[i]; uxnxip += 0.5*nxi*(uNp1L[i]+uNp1R[i]); uspecxnx += nxi*bcVelocity[i]; // save off normal and force for each component i p_nx[i] = nxi; p_fx[i] = fxi; } // full stress, sigma_ij for (int i = 0; i < nDim; ++i ) { // setup for matrix contribution assembly const int indexL = opposingNode*nDim + i; const int indexR = nearestNode*nDim + i; const int rowR = indexR*nodesPerElement*nDim; const int rRiL_i = rowR+indexL; const int rRiR_i = rowR+indexR; // subtract normal component const double diffFlux = p_fx[i] - p_nx[i]*fxnx; const double om_nxinxi = 1.0-p_nx[i]*p_nx[i]; p_rhs[indexR] -= diffFlux; double lhsFac = -viscBip*asq*inv_axdx*om_nxinxi; p_lhs[rRiL_i] -= lhsFac; p_lhs[rRiR_i] += lhsFac; const double axi = areaVec[faceOffSet+i]; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; lhsFac = -viscBip*axi*axj*inv_axdx*om_nxinxi; const int colL = opposingNode*nDim + j; const int colR = nearestNode*nDim + j; const int rRiL_j = rowR+colL; const int rRiR_j = rowR+colR; p_lhs[rRiL_j] -= lhsFac; p_lhs[rRiR_j] += lhsFac; if ( i == j ) { // nothing } else { const double nxinxj = p_nx[i]*p_nx[j]; lhsFac = viscBip*asq*inv_axdx*nxinxj; p_lhs[rRiL_j] -= lhsFac; p_lhs[rRiR_j] += lhsFac; lhsFac = viscBip*axj*axj*inv_axdx*nxinxj; p_lhs[rRiL_j] -= lhsFac; p_lhs[rRiR_j] += lhsFac; lhsFac = viscBip*axj*axi*inv_axdx*nxinxj; p_lhs[rRiL_i] -= lhsFac; p_lhs[rRiR_i] += lhsFac; } } } // advection const double tmdot = mdot[ip]; if ( tmdot > 0 ) { // leaving the domain for ( int i = 0; i < nDim; ++i ) { // setup for matrix contribution assembly const int indexR = nearestNode*nDim + i; const int rowR = indexR*nodesPerElement*nDim; const int rRiR = rowR+indexR; p_rhs[indexR] -= tmdot*uNp1R[i]; p_lhs[rRiR] += tmdot; } } else { // entraining; constrain to be normal for ( int i = 0; i < nDim; ++i ) { // setup for matrix contribution assembly const int indexR = nearestNode*nDim + i; const int rowR = indexR*nodesPerElement*nDim; // constrain to be normal p_rhs[indexR] -= tmdot*(nfEntrain*uxnx + om_nfEntrain*uxnxip)*p_nx[i]; // user spec entrainment (tangential) p_rhs[indexR] -= tmdot*(bcVelocity[i]-uspecxnx*p_nx[i]); for ( int j = 0; j < nDim; ++j ) { const int colL = opposingNode*nDim + j; const int colR = nearestNode*nDim + j; p_lhs[rowR+colR] += tmdot*(nfEntrain + om_nfEntrain*0.5)*p_nx[i]*p_nx[j]; p_lhs[rowR+colL] += tmdot*om_nfEntrain*0.5*p_nx[i]*p_nx[j]; } } } } apply_coeff(connected_nodes, rhs, lhs, __FILE__); } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void ComputeHeatTransferEdgeWallAlgorithm::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 dt = realm_.get_time_step(); // define vector of parent topos; should always be UNITY in size std::vector<stk::topology> parentTopo; // define some common selectors stk::mesh::Selector s_locally_owned_union = meta_data.locally_owned_part() &stk::mesh::selectUnion(partVec_); stk::mesh::BucketVector const& face_buckets = realm_.get_buckets( meta_data.side_rank(), s_locally_owned_union ); for ( stk::mesh::BucketVector::const_iterator ib = face_buckets.begin(); ib != face_buckets.end() ; ++ib ) { stk::mesh::Bucket & b = **ib ; // extract connected element topology b.parent_topology(stk::topology::ELEMENT_RANK, parentTopo); ThrowAssert ( parentTopo.size() == 1 ); stk::topology theElemTopo = parentTopo[0]; MasterElement *meSCS = sierra::nalu::MasterElementRepo::get_surface_master_element(theElemTopo); // size some things that are useful const int num_face_nodes = b.topology().num_nodes(); const stk::mesh::Bucket::size_type length = b.size(); for ( stk::mesh::Bucket::size_type k = 0 ; k < length ; ++k ) { // pointer to face data const double * areaVec = stk::mesh::field_data(*exposedAreaVec_, b, k); // extract the connected element to this exposed face; should be single in size! stk::mesh::Entity const * face_elem_rels = b.begin_elements(k); ThrowAssert( b.num_elements(k) == 1 ); // get element; its face ordinal number and populate face_node_ordinals stk::mesh::Entity element = face_elem_rels[0]; const int face_ordinal = b.begin_element_ordinals(k)[0]; const int *face_node_ordinals = meSCS->side_node_ordinals(face_ordinal); // get the relations stk::mesh::Entity const * elem_node_rels = bulk_data.begin_nodes(element); for ( int ip = 0; ip < num_face_nodes; ++ip ) { const int opposingNode = meSCS->opposingNodes(face_ordinal,ip); const int nearestNode = face_node_ordinals[ip]; // left and right nodes; right is on the face; left is the opposing node stk::mesh::Entity nodeL = elem_node_rels[opposingNode]; stk::mesh::Entity nodeR = elem_node_rels[nearestNode]; // extract nodal fields const double * coordL = stk::mesh::field_data(*coordinates_, nodeL ); const double * coordR = stk::mesh::field_data(*coordinates_, nodeR ); const double tempL = *stk::mesh::field_data(*temperature_, nodeL ); const double tempR = *stk::mesh::field_data(*temperature_, nodeR ); // nearest nodes; gathered and to-be-scattered const double * dhdxR = stk::mesh::field_data(*dhdx_, nodeR ); const double densityR = *stk::mesh::field_data(*density_, nodeR ); const double thermalCondR = *stk::mesh::field_data(*thermalCond_, nodeR ); const double specificHeatR = *stk::mesh::field_data(*specificHeat_, nodeR ); double *assembledWallArea = stk::mesh::field_data(*assembledWallArea_, nodeR); double *referenceTemperature = stk::mesh::field_data(*referenceTemperature_, nodeR); double *heatTransferCoefficient = stk::mesh::field_data(*heatTransferCoefficient_, nodeR); double *normalHeatFlux = stk::mesh::field_data(*normalHeatFlux_, nodeR); double *robinCouplingParameter = stk::mesh::field_data(*robinCouplingParameter_, nodeR); // offset for bip area vector const int faceOffSet = ip*nDim; // compute geometry double axdx = 0.0; double asq = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; const double dxj = coordR[j] - coordL[j]; asq += axj*axj; axdx += axj*dxj; } const double inv_axdx = 1.0/axdx; const double aMag = std::sqrt(asq); const double edgeLen = axdx/aMag; // NOC; convert dhdx to dTdx double nonOrth = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; const double dxj = coordR[j] - coordL[j]; const double kxj = axj - asq*inv_axdx*dxj; const double GjT = dhdxR[j]/specificHeatR; nonOrth += -thermalCondR*kxj*GjT; } // compute coupling parameter const double chi = densityR * specificHeatR * edgeLen * edgeLen / (2 * thermalCondR * dt); const double alpha = compute_coupling_parameter(thermalCondR, edgeLen, chi); // assemble the nodal quantities; group NOC on reference temp // if NOC is < 0; Too will be greater than Tphyscial // if NOC is > 0; Too will be less than Tphysical // grouping NOC on H reverses the above, however, who knows which is best.. *assembledWallArea += aMag; *referenceTemperature += thermalCondR*tempL*asq*inv_axdx - nonOrth; *heatTransferCoefficient += -thermalCondR*tempR*asq*inv_axdx; *normalHeatFlux += thermalCondR*(tempL-tempR)*asq*inv_axdx - nonOrth; *robinCouplingParameter += alpha*aMag; } } } }