//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void ComputeHeatTransferElemWallAlgorithm::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(); // nodal fields to gather std::vector<double> ws_coordinates; std::vector<double> ws_temperature; std::vector<double> ws_thermalCond; std::vector<double> ws_density; std::vector<double> ws_specificHeat; // master element std::vector<double> ws_face_shape_function; std::vector<double> ws_dndx; std::vector<double> ws_det_j; // array for face nodes and nodes off face std::vector<double> ws_nodesOnFace; std::vector<double> ws_nodesOffFace; // 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 = 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_; // size some things that are useful int num_face_nodes = b.topology().num_nodes(); std::vector<int> face_node_ordinals(num_face_nodes); // algorithm related; element ws_coordinates.resize(nodesPerElement*nDim); ws_temperature.resize(nodesPerElement); ws_thermalCond.resize(nodesPerFace); ws_density.resize(nodesPerFace); ws_specificHeat.resize(nodesPerFace); ws_face_shape_function.resize(nodesPerFace*nodesPerFace); ws_dndx.resize(nDim*nodesPerFace*nodesPerElement); ws_det_j.resize(nodesPerFace); ws_nodesOnFace.resize(nodesPerElement); ws_nodesOffFace.resize(nodesPerElement); // pointers double *p_coordinates = &ws_coordinates[0]; double *p_temperature = &ws_temperature[0]; double *p_thermalCond = &ws_thermalCond[0]; double *p_density = &ws_density[0]; double *p_specificHeat = &ws_specificHeat[0]; double *p_face_shape_function = &ws_face_shape_function[0]; double *p_dndx = &ws_dndx[0]; double *p_nodesOnFace = &ws_nodesOnFace[0]; double *p_nodesOffFace = &ws_nodesOffFace[0]; // shape function 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 ) { // get face stk::mesh::Entity face = b[k]; // pointer to face data const double * areaVec = stk::mesh::field_data(*exposedAreaVec_, b, k); //====================================== // gather nodal data off of face //====================================== stk::mesh::Entity const * face_node_rels = bulk_data.begin_nodes(face); 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_density[ni] = *stk::mesh::field_data(*density_, node); const double mu = *stk::mesh::field_data(*viscosity_, node); const double Cp = *stk::mesh::field_data(*specificHeat_, node); p_specificHeat[ni] = Cp; p_thermalCond[ni] = mu*Cp/Pr_; } // 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()); //========================================== // gather nodal data off of element //========================================== 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 ) { // sneak in nodesOn/offFace p_nodesOnFace[ni] = 0.0; p_nodesOffFace[ni] = 1.0; stk::mesh::Entity node = elem_node_rels[ni]; // gather scalars p_temperature[ni] = *stk::mesh::field_data(*temperature_, node); // gather vectors double * coords = stk::mesh::field_data(*coordinates_, node); const int offSet = ni*nDim; for ( int j=0; j < nDim; ++j ) { p_coordinates[offSet+j] = coords[j]; } } // process on/off while looping over face nodes for ( int ip = 0; ip < num_face_nodes; ++ip ) { const int nearestNode = face_node_ordinals[ip]; p_nodesOnFace[nearestNode] = 1.0; p_nodesOffFace[nearestNode] = 0.0; } // compute dndx double scs_error = 0.0; meSCS->face_grad_op(1, face_ordinal, &p_coordinates[0], &p_dndx[0], &ws_det_j[0], &scs_error); for ( int ip = 0; ip < num_face_nodes; ++ip ) { const int nearestNode = face_node_ordinals[ip]; stk::mesh::Entity nodeR = elem_node_rels[nearestNode]; // pointers to nearest node data 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 and types of shape function const int faceOffSet = ip*nDim; const int offSetSF_face = ip*nodesPerFace; // interpolate to bip double thermalCondBip = 0.0; double densityBip = 0.0; double specificHeatBip = 0.0; for ( int ic = 0; ic < nodesPerFace; ++ic ) { const double r = p_face_shape_function[offSetSF_face+ic]; thermalCondBip += r*p_thermalCond[ic]; densityBip += r*p_density[ic]; specificHeatBip += r*p_specificHeat[ic]; } // handle flux due to on and off face in a single loop (on/off provided above) double dndx = 0.0; double dndxOn = 0.0; double dndxOff = 0.0; double invEltLen = 0.0; for ( int ic = 0; ic < nodesPerElement; ++ic ) { const int offSetDnDx = nDim*nodesPerElement*ip + ic*nDim; const double nodesOnFace = p_nodesOnFace[ic]; const double nodesOffFace = p_nodesOffFace[ic]; const double tempIC = p_temperature[ic]; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; const double dndxj = p_dndx[offSetDnDx+j]; const double dTdA = dndxj*axj*tempIC; dndx += dTdA; dndxOn += dTdA*nodesOnFace; dndxOff += dTdA*nodesOffFace; invEltLen += dndxj*axj*nodesOnFace; } } // compute assembled area double aMag = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; aMag += axj*axj; } aMag = std::sqrt(aMag); double eltLen = aMag/invEltLen; // compute coupling parameter const double chi = densityBip * specificHeatBip * eltLen * eltLen / (2 * thermalCondBip * dt); const double alpha = compute_coupling_parameter(thermalCondBip, eltLen, chi); // assemble the nodal quantities *assembledWallArea += aMag; *normalHeatFlux -= thermalCondBip*dndx; *referenceTemperature -= thermalCondBip*dndxOff; *heatTransferCoefficient -= thermalCondBip*dndxOn; *robinCouplingParameter += alpha*aMag; } } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void AssembleMomentumElemSymmetrySolverAlgorithm::execute() { stk::mesh::BulkData & bulk_data = realm_.bulk_data(); 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; // vectors std::vector<double> nx(nDim); // pointers to fixed values double *p_nx = &nx[0]; // nodal fields to gather std::vector<double> ws_velocityNp1; std::vector<double> ws_coordinates; std::vector<double> ws_viscosity; // master element std::vector<double> ws_face_shape_function; std::vector<double> ws_dndx; std::vector<double> ws_det_j; // deal with state VectorFieldType &velocityNp1 = velocity_->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_; // 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; element ws_velocityNp1.resize(nodesPerElement*nDim); ws_coordinates.resize(nodesPerElement*nDim); ws_viscosity.resize(nodesPerFace); ws_face_shape_function.resize(numScsBip*nodesPerFace); ws_dndx.resize(nDim*numScsBip*nodesPerElement); ws_det_j.resize(numScsBip); // pointers double *p_lhs = &lhs[0]; double *p_rhs = &rhs[0]; double *p_velocityNp1 = &ws_velocityNp1[0]; double *p_coordinates = &ws_coordinates[0]; double *p_viscosity = &ws_viscosity[0]; double *p_face_shape_function = &ws_face_shape_function[0]; double *p_dndx = &ws_dndx[0]; // shape function 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]; //====================================== // 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_viscosity[ni] = *stk::mesh::field_data(*viscosity_, node); } // 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! stk::mesh::Entity const * face_elem_rels = bulk_data.begin_elements(face); ThrowAssert( bulk_data.num_elements(face) == 1 ); // get element; its face ordinal number stk::mesh::Entity element = face_elem_rels[0]; const stk::mesh::ConnectivityOrdinal* face_elem_ords = bulk_data.begin_element_ordinals(face); const int face_ordinal = face_elem_ords[0]; // mapping from ip to nodes for this ordinal const int *ipNodeMap = meSCS->ipNodeMap(face_ordinal); //========================================== // gather nodal data off of element //========================================== 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 ) { stk::mesh::Entity node = elem_node_rels[ni]; // set connected nodes connected_nodes[ni] = node; // gather vectors double * uNp1 = stk::mesh::field_data(velocityNp1, node); double * coords = stk::mesh::field_data(*coordinates_, node); const int offSet = ni*nDim; for ( int j=0; j < nDim; ++j ) { p_velocityNp1[offSet+j] = uNp1[j]; p_coordinates[offSet+j] = coords[j]; } } // compute dndx double scs_error = 0.0; meSCS->face_grad_op(1, face_ordinal, &p_coordinates[0], &p_dndx[0], &ws_det_j[0], &scs_error); // loop over boundary ips for ( int ip = 0; ip < numScsBip; ++ip ) { const int nearestNode = ipNodeMap[ip]; // offset for bip area vector and types of shape function const int faceOffSet = ip*nDim; const int offSetSF_face = ip*nodesPerFace; // form unit normal double asq = 0.0; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; asq += axj*axj; } const double amag = std::sqrt(asq); for ( int i = 0; i < nDim; ++i ) { p_nx[i] = areaVec[faceOffSet+i]/amag; } // interpolate to bip double viscBip = 0.0; for ( int ic = 0; ic < nodesPerFace; ++ic ) { const double r = p_face_shape_function[offSetSF_face+ic]; viscBip += r*p_viscosity[ic]; } //================================ // diffusion second //================================ for ( int ic = 0; ic < nodesPerElement; ++ic ) { const int offSetDnDx = nDim*nodesPerElement*ip + ic*nDim; for ( int j = 0; j < nDim; ++j ) { const double axj = areaVec[faceOffSet+j]; const double dndxj = p_dndx[offSetDnDx+j]; const double uxj = p_velocityNp1[ic*nDim+j]; const double divUstress = 2.0/3.0*viscBip*dndxj*uxj*axj*includeDivU_; for ( int i = 0; i < nDim; ++i ) { // matrix entries int indexR = nearestNode*nDim + i; int rowR = indexR*nodesPerElement*nDim; const double dndxi = p_dndx[offSetDnDx+i]; const double uxi = p_velocityNp1[ic*nDim+i]; const double nxi = p_nx[i]; const double nxinxi = nxi*nxi; // -mu*dui/dxj*Aj*ni*ni; sneak in divU (explicit) double lhsfac = - viscBip*dndxj*axj*nxinxi; p_lhs[rowR+ic*nDim+i] += lhsfac; p_rhs[indexR] -= lhsfac*uxi + divUstress*nxinxi; // -mu*duj/dxi*Aj*ni*ni lhsfac = - viscBip*dndxi*axj*nxinxi; p_lhs[rowR+ic*nDim+j] += lhsfac; p_rhs[indexR] -= lhsfac*uxj; // now we need the +nx*ny*Fy + nx*nz*Fz part for ( int l = 0; l < nDim; ++l ) { if ( i != l ) { const double nxinxl = nxi*p_nx[l]; const double uxl = p_velocityNp1[ic*nDim+l]; const double dndxl = p_dndx[offSetDnDx+l]; // -ni*nl*mu*dul/dxj*Aj; sneak in divU (explict) lhsfac = -viscBip*dndxj*axj*nxinxl; p_lhs[rowR+ic*nDim+l] += lhsfac; p_rhs[indexR] -= lhsfac*uxl + divUstress*nxinxl; // -ni*nl*mu*duj/dxl*Aj lhsfac = -viscBip*dndxl*axj*nxinxl; p_lhs[rowR+ic*nDim+j] += lhsfac; p_rhs[indexR] -= lhsfac*uxj; } } } } } } apply_coeff(connected_nodes, scratchIds, scratchVals, rhs, lhs, __FILE__); } } }