Matrix3f Plane3f::basis() const { auto n = unitNormal(); Vector3f u; Vector3f v; GeometryUtils::getBasis( n, &u, &v ); return Matrix3f( u, v, n ); }
float Plane3f::distance( const Vector3f& p ) const { // pick a point x on the plane // get the vector x --> p // distance is the projection on the unit normal // xp dot unitNormal auto x = pointOnPlane(); auto xp = p - x; return Vector3f::dot( xp, unitNormal() ); }
void EricksonManufacturedSolution::getConstraints(FieldContainer<double> &physicalPoints, FieldContainer<double> &unitNormals, vector<map<int,FieldContainer<double > > > &constraintCoeffs, vector<FieldContainer<double > > &constraintValues){ int numCells = physicalPoints.dimension(0); int numPoints = physicalPoints.dimension(1); int spaceDim = physicalPoints.dimension(2); map<int,FieldContainer<double> > outflowConstraint; FieldContainer<double> uCoeffs(numCells,numPoints); FieldContainer<double> beta_sigmaCoeffs(numCells,numPoints); FieldContainer<double> outflowValues(numCells,numPoints); double tol = 1e-12; // default to no constraints, apply on outflow only uCoeffs.initialize(0.0); beta_sigmaCoeffs.initialize(0.0); outflowValues.initialize(0.0); Teuchos::Array<int> pointDimensions; pointDimensions.push_back(2); for (int cellIndex=0;cellIndex<numCells;cellIndex++){ for (int pointIndex=0;pointIndex<numPoints;pointIndex++){ FieldContainer<double> physicalPoint(pointDimensions, &physicalPoints(cellIndex,pointIndex,0)); FieldContainer<double> unitNormal(pointDimensions, &unitNormals(cellIndex,pointIndex,0)); double x = physicalPoints(cellIndex,pointIndex,0); double y = physicalPoints(cellIndex,pointIndex,1); double beta_n = _beta_x*unitNormals(cellIndex,pointIndex,0)+_beta_y*unitNormals(cellIndex,pointIndex,1); if ( abs(x-1.0) < tol ) { // if on outflow boundary TEUCHOS_TEST_FOR_EXCEPTION(beta_n < 0,std::invalid_argument,"Inflow condition on boundary"); // this combo isolates sigma_n //uCoeffs(cellIndex,pointIndex) = 1.0; uCoeffs(cellIndex,pointIndex) = beta_n; beta_sigmaCoeffs(cellIndex,pointIndex) = -1.0; double beta_n_u_minus_sigma_n = solutionValue(ConfusionBilinearForm::BETA_N_U_MINUS_SIGMA_HAT, physicalPoint, unitNormal); double u_hat = solutionValue(ConfusionBilinearForm::U_HAT, physicalPoint, unitNormal); outflowValues(cellIndex,pointIndex) = beta_n*u_hat - beta_n_u_minus_sigma_n; // sigma_n } } } outflowConstraint[ConfusionBilinearForm::U_HAT] = uCoeffs; outflowConstraint[ConfusionBilinearForm::BETA_N_U_MINUS_SIGMA_HAT] = beta_sigmaCoeffs; if (!_useWallBC){ constraintCoeffs.push_back(outflowConstraint); // only one constraint on outflow constraintValues.push_back(outflowValues); // only one constraint on outflow } }
void EricksonManufacturedSolution::imposeBC(int varID, FieldContainer<double> &physicalPoints, FieldContainer<double> &unitNormals, FieldContainer<double> &dirichletValues, FieldContainer<bool> &imposeHere) { int numCells = physicalPoints.dimension(0); int numPoints = physicalPoints.dimension(1); int spaceDim = physicalPoints.dimension(2); TEUCHOS_TEST_FOR_EXCEPTION( ( spaceDim != 2 ), std::invalid_argument, "ConfusionBC expects spaceDim==2."); TEUCHOS_TEST_FOR_EXCEPTION( ( dirichletValues.dimension(0) != numCells ) || ( dirichletValues.dimension(1) != numPoints ) || ( dirichletValues.rank() != 2 ), std::invalid_argument, "dirichletValues dimensions should be (numCells,numPoints)."); TEUCHOS_TEST_FOR_EXCEPTION( ( imposeHere.dimension(0) != numCells ) || ( imposeHere.dimension(1) != numPoints ) || ( imposeHere.rank() != 2 ), std::invalid_argument, "imposeHere dimensions should be (numCells,numPoints)."); Teuchos::Array<int> pointDimensions; pointDimensions.push_back(2); for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { FieldContainer<double> physicalPoint(pointDimensions, &physicalPoints(cellIndex,ptIndex,0)); FieldContainer<double> unitNormal(pointDimensions, &unitNormals(cellIndex,ptIndex,0)); double beta_n = unitNormals(cellIndex,ptIndex,0)*_beta_x + unitNormals(cellIndex,ptIndex,1)*_beta_y; double x = physicalPoint(cellIndex,ptIndex,0); double y = physicalPoint(cellIndex,ptIndex,1); imposeHere(cellIndex,ptIndex) = false; // if (varID==ConfusionBilinearForm::BETA_N_U_MINUS_SIGMA_HAT) { // dirichletValues(cellIndex,ptIndex) = solutionValue(varID, physicalPoint, unitNormal); if (varID==ConfusionBilinearForm::U_HAT) { dirichletValues(cellIndex,ptIndex) = solutionValue(varID, physicalPoint); if ( abs(x-1.0) > 1e-12) { // if not the outflow (pts on boundary already) imposeHere(cellIndex,ptIndex) = true; } // wall boundary if (abs(x-1.0)<1e-12 && _useWallBC){ dirichletValues(cellIndex,ptIndex) = solutionValue(varID, physicalPoint); imposeHere(cellIndex,ptIndex) = true; } } } } }
Matrix3f Plane3f::basis( const Vector3f& u ) const { // normalize u first auto u2 = u.normalized(); auto n = unitNormal(); // u is the vector triple product: ( n x u ) x n // // u is the preferred direction, which may be be in the plane // we want u to be the projection of u in the plane // and v to be perpendicular to both // but v is n cross u regardless of whether u is in the plane or not // so compute v, then cross v with n to get u in the plane auto v = Vector3f::cross( n, u ).normalized(); u2 = Vector3f::cross( v, n ).normalized(); return Matrix3f( u2, v, n ); }
bool Plane3f::intersectRay( const Vector3f& origin, const Vector3f& direction, float* tIntersect ) { Vector3f u = unitNormal(); float vd = Vector3f::dot( u, direction ); // ray is parallel to plane if( vd == 0 ) { return false; } float v0 = -( Vector3f::dot( u, origin ) + d ); float t = v0 / vd; if( tIntersect != nullptr ) { *tIntersect = t; } return( t > 0 ); }
void ExactSolution::solutionValues(FieldContainer<double> &values, int trialID, FieldContainer<double> &physicalPoints, FieldContainer<double> &unitNormals) { int numCells = physicalPoints.dimension(0); int numPoints = physicalPoints.dimension(1); int spaceDim = physicalPoints.dimension(2); Teuchos::Array<int> pointDimensions; pointDimensions.push_back(spaceDim); // cout << "ExactSolution: physicalPoints:\n" << physicalPoints; for (int cellIndex=0; cellIndex<numCells; cellIndex++) { for (int ptIndex=0; ptIndex<numPoints; ptIndex++) { FieldContainer<double> point(pointDimensions,&physicalPoints(cellIndex,ptIndex,0)); FieldContainer<double> unitNormal(pointDimensions,&unitNormals(cellIndex,ptIndex,0)); double value = solutionValue(trialID, point, unitNormal); values(cellIndex,ptIndex) = value; } } }
//-------------------------------------------------------------------------- //-------- execute --------------------------------------------------------- //-------------------------------------------------------------------------- void SurfaceForceAndMomentWallFunctionAlgorithm::execute() { // check to see if this is a valid step to process output file const int timeStepCount = realm_.get_time_step_count(); const bool processMe = (timeStepCount % frequency_) == 0 ? true : false; // do not waste time here if ( !processMe ) return; stk::mesh::BulkData & bulk_data = realm_.bulk_data(); stk::mesh::MetaData & meta_data = realm_.meta_data(); const int nDim = meta_data.spatial_dimension(); // set min and max values double yplusMin = 1.0e8; double yplusMax = -1.0e8; // bip values std::vector<double> uBip(nDim); std::vector<double> uBcBip(nDim); std::vector<double> unitNormal(nDim); // tangential work array std::vector<double> uiTangential(nDim); std::vector<double> uiBcTangential(nDim); // pointers to fixed values double *p_uBip = &uBip[0]; double *p_uBcBip = &uBcBip[0]; double *p_unitNormal= &unitNormal[0]; double *p_uiTangential = &uiTangential[0]; double *p_uiBcTangential = &uiBcTangential[0]; // nodal fields to gather std::vector<double> ws_velocityNp1; std::vector<double> ws_bcVelocity; std::vector<double> ws_pressure; std::vector<double> ws_density; std::vector<double> ws_viscosity; // master element std::vector<double> ws_face_shape_function; // deal with state VectorFieldType &velocityNp1 = velocity_->field_of_state(stk::mesh::StateNP1); ScalarFieldType &densityNp1 = density_->field_of_state(stk::mesh::StateNP1); const double currentTime = realm_.get_current_time(); // local force and MomentWallFunction; i.e., to be assembled double l_force_moment[9] = {}; // work force, MomentWallFunction and radius; i.e., to be pused to cross_product() double ws_p_force[3] = {}; double ws_v_force[3] = {}; double ws_t_force[3] = {}; double ws_moment[3] = {}; double ws_radius[3] = {}; // centroid double centroid[3] = {}; for ( size_t k = 0; k < parameters_.size(); ++k) centroid[k] = parameters_[k]; // 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 ; // face master element MasterElement *meFC = realm_.get_surface_master_element(b.topology()); const int nodesPerFace = meFC->nodesPerElement_; // algorithm related; element ws_velocityNp1.resize(nodesPerFace*nDim); ws_bcVelocity.resize(nodesPerFace*nDim); ws_pressure.resize(nodesPerFace); ws_density.resize(nodesPerFace); ws_viscosity.resize(nodesPerFace); ws_face_shape_function.resize(nodesPerFace*nodesPerFace); // pointers double *p_velocityNp1 = &ws_velocityNp1[0]; double *p_bcVelocity = &ws_bcVelocity[0]; double *p_pressure = &ws_pressure[0]; double *p_density = &ws_density[0]; double *p_viscosity = &ws_viscosity[0]; double *p_face_shape_function = &ws_face_shape_function[0]; // shape functions if ( useShifted_ ) meFC->shifted_shape_fcn(&p_face_shape_function[0]); else 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]; // face node relations stk::mesh::Entity const * face_node_rels = bulk_data.begin_nodes(face); //====================================== // gather nodal data off of face //====================================== for ( int ni = 0; ni < nodesPerFace; ++ni ) { stk::mesh::Entity node = face_node_rels[ni]; // gather scalars p_pressure[ni] = *stk::mesh::field_data(*pressure_, node); p_density[ni] = *stk::mesh::field_data(densityNp1, node); p_viscosity[ni] = *stk::mesh::field_data(*viscosity_, node); // gather vectors double * uNp1 = stk::mesh::field_data(velocityNp1, node); double * uBc = stk::mesh::field_data(*bcVelocity_, node); const int offSet = ni*nDim; for ( int j=0; j < nDim; ++j ) { p_velocityNp1[offSet+j] = uNp1[j]; p_bcVelocity[offSet+j] = uBc[j]; } } // pointer to face data const double * areaVec = stk::mesh::field_data(*exposedAreaVec_, face); const double *wallNormalDistanceBip = stk::mesh::field_data(*wallNormalDistanceBip_, face); const double *wallFrictionVelocityBip = stk::mesh::field_data(*wallFrictionVelocityBip_, face); for ( int ip = 0; ip < nodesPerFace; ++ip ) { // offsets const int offSetAveraVec = ip*nDim; const int offSetSF_face = ip*nodesPerFace; // zero out vector quantities; squeeze in aMag double aMag = 0.0; for ( int j = 0; j < nDim; ++j ) { p_uBip[j] = 0.0; p_uBcBip[j] = 0.0; const double axj = areaVec[offSetAveraVec+j]; aMag += axj*axj; } aMag = std::sqrt(aMag); // interpolate to bip double pBip = 0.0; double rhoBip = 0.0; double muBip = 0.0; for ( int ic = 0; ic < nodesPerFace; ++ic ) { const double r = p_face_shape_function[offSetSF_face+ic]; pBip += r*p_pressure[ic]; rhoBip += r*p_density[ic]; muBip += r*p_viscosity[ic]; const int offSetFN = ic*nDim; for ( int j = 0; j < nDim; ++j ) { p_uBip[j] += r*p_velocityNp1[offSetFN+j]; p_uBcBip[j] += r*p_bcVelocity[offSetFN+j]; } } // form unit normal for ( int j = 0; j < nDim; ++j ) { p_unitNormal[j] = areaVec[offSetAveraVec+j]/aMag; } // determine tangential velocity double uTangential = 0.0; for ( int i = 0; i < nDim; ++i ) { double uiTan = 0.0; double uiBcTan = 0.0; for ( int j = 0; j < nDim; ++j ) { const double ninj = p_unitNormal[i]*p_unitNormal[j]; if ( i==j ) { const double om_nini = 1.0 - ninj; uiTan += om_nini*p_uBip[j]; uiBcTan += om_nini*p_uBcBip[j]; } else { uiTan -= ninj*p_uBip[j]; uiBcTan -= ninj*p_uBcBip[j]; } } // save off tangential components and augment magnitude p_uiTangential[i] = uiTan; p_uiBcTangential[i] = uiBcTan; uTangential += (uiTan-uiBcTan)*(uiTan-uiBcTan); } uTangential = std::sqrt(uTangential); // extract bip data const double yp = wallNormalDistanceBip[ip]; const double utau= wallFrictionVelocityBip[ip]; // determine yplus const double yplusBip = rhoBip*yp*utau/muBip; // min and max yplusMin = std::min(yplusMin, yplusBip); yplusMax = std::max(yplusMax, yplusBip); double lambda = muBip/yp*aMag; if ( yplusBip > yplusCrit_) lambda = rhoBip*kappa_*utau/std::log(elog_*yplusBip)*aMag; // extract nodal fields stk::mesh::Entity node = face_node_rels[ip]; const double * coord = stk::mesh::field_data(*coordinates_, node ); double *pressureForce = stk::mesh::field_data(*pressureForce_, node ); double *tauWall = stk::mesh::field_data(*tauWall_, node ); double *yplus = stk::mesh::field_data(*yplus_, node ); const double assembledArea = *stk::mesh::field_data(*assembledArea_, node ); // load radius; assemble force -sigma_ij*njdS double uParallel = 0.0; for ( int i = 0; i < nDim; ++i ) { const double ai = areaVec[offSetAveraVec+i]; ws_radius[i] = coord[i] - centroid[i]; const double uDiff = p_uiTangential[i] - p_uiBcTangential[i]; ws_p_force[i] = pBip*ai; ws_v_force[i] = lambda*uDiff; ws_t_force[i] = ws_p_force[i] + ws_v_force[i]; pressureForce[i] += ws_p_force[i];; uParallel += uDiff*uDiff; } cross_product(&ws_t_force[0], &ws_moment[0], &ws_radius[0]); // assemble for and moment for ( int j = 0; j < 3; ++j ) { l_force_moment[j] += ws_p_force[j]; l_force_moment[j+3] += ws_v_force[j]; l_force_moment[j+6] += ws_moment[j]; } // assemble tauWall; area weighting is hiding in lambda/assembledArea *tauWall += lambda*std::sqrt(uParallel)/assembledArea; // deal with yplus *yplus += yplusBip*aMag/assembledArea; } } } if ( processMe ) { // parallel assemble and output double g_force_moment[9] = {}; stk::ParallelMachine comm = NaluEnv::self().parallel_comm(); // Parallel assembly of L2 stk::all_reduce_sum(comm, &l_force_moment[0], &g_force_moment[0], 9); // min/max double g_yplusMin = 0.0, g_yplusMax = 0.0; stk::all_reduce_min(comm, &yplusMin, &g_yplusMin, 1); stk::all_reduce_max(comm, &yplusMax, &g_yplusMax, 1); // deal with file name and banner if ( NaluEnv::self().parallel_rank() == 0 ) { std::ofstream myfile; myfile.open(outputFileName_.c_str(), std::ios_base::app); myfile << std::setprecision(6) << std::setw(w_) << currentTime << std::setw(w_) << g_force_moment[0] << std::setw(w_) << g_force_moment[1] << std::setw(w_) << g_force_moment[2] << std::setw(w_) << g_force_moment[3] << std::setw(w_) << g_force_moment[4] << std::setw(w_) << g_force_moment[5] << std::setw(w_) << g_force_moment[6] << std::setw(w_) << g_force_moment[7] << std::setw(w_) << g_force_moment[8] << std::setw(w_) << g_yplusMin << std::setw(w_) << g_yplusMax << std::endl; myfile.close(); } } }
Vector3f Plane3f::closestPointOnPlane( const Vector3f& p ) const { float d = distance( p ); return ( p - d * unitNormal() ); }