/// ==================================================================================== /// <summary> /// This method performs the integration in y-direction /// torque. /// </summary> /// <param name="Grad_UARes"> /// The gradient of the velocity. /// </param> /// <param name="pARes"> /// The pressure. /// </param> /// <param name="NormalVector"> /// The normal vector at the current node in the current cell. /// </param> /// <param name="FluidViscosity"> /// The viscosity of the fluid. /// </param> /// <param name="k"> /// The current node ID. /// </param> /// <param name="j"> /// The current cell ID /// </param> /// ==================================================================================== private double CalculateStressTensorY(MultidimensionalArray Grad_UARes, MultidimensionalArray pARes, MultidimensionalArray NormalVector, double FluidViscosity, int k, int j) { double[] SummandsVelGradient = new double[3]; double SummandsPressure; SummandsVelGradient[0] = -2 * Grad_UARes[j, k, 1, 1] * NormalVector[j, k, 1]; SummandsVelGradient[1] = -Grad_UARes[j, k, 1, 0] * NormalVector[j, k, 0]; SummandsVelGradient[2] = -Grad_UARes[j, k, 0, 1] * NormalVector[j, k, 0]; SummandsPressure = pARes[j, k] * NormalVector[j, k, 1]; return ParticleAuxillary.SummationWithNeumaier(SummandsVelGradient, SummandsPressure, FluidViscosity); }
/// ==================================================================================== /// <summary> /// This method calculates the stress tensor in case of a 3D-probem /// torque. /// </summary> /// <param name="Grad_UARes"> /// The gradient of the velocity. /// </param> /// <param name="pARes"> /// The pressure. /// </param> /// <param name="NormalVector"> /// The normal vector at the current node in the current cell. /// </param> /// <param name="FluidViscosity"> /// The viscosity of the fluid. /// </param> /// <param name="k"> /// The current node ID. /// </param> /// <param name="j"> /// The current cell ID /// </param> /// <param name="currentDimension"> /// The current dimension to be calculated. /// </param> /// ==================================================================================== private double CalculateStressTensor3D(MultidimensionalArray Grad_UARes, MultidimensionalArray pARes, MultidimensionalArray NormalVector, double FluidViscosity, int k, int j, int currentDimension) { double acc = 0.0; double[] SummandsVelGradient = new double[5]; double SummandsPressure; switch (currentDimension) { case 0: SummandsPressure = pARes[j, k] * NormalVector[j, k, 0]; SummandsVelGradient[0] = -2 * Grad_UARes[j, k, 0, 0] * NormalVector[j, k, 0]; SummandsVelGradient[1] = -Grad_UARes[j, k, 0, 2] * NormalVector[j, k, 2]; SummandsVelGradient[2] = -Grad_UARes[j, k, 0, 1] * NormalVector[j, k, 1]; SummandsVelGradient[3] = -Grad_UARes[j, k, 1, 0] * NormalVector[j, k, 1]; SummandsVelGradient[4] = -Grad_UARes[j, k, 2, 0] * NormalVector[j, k, 2]; acc += ParticleAuxillary.SummationWithNeumaier(SummandsVelGradient, SummandsPressure, FluidViscosity); break; case 1: SummandsPressure = pARes[j, k] * NormalVector[j, k, 1]; SummandsVelGradient[0] = -2 * Grad_UARes[j, k, 1, 1] * NormalVector[j, k, 1]; SummandsVelGradient[1] = -Grad_UARes[j, k, 1, 2] * NormalVector[j, k, 2]; SummandsVelGradient[2] = -Grad_UARes[j, k, 1, 0] * NormalVector[j, k, 0]; SummandsVelGradient[3] = -Grad_UARes[j, k, 0, 1] * NormalVector[j, k, 0]; SummandsVelGradient[4] = -Grad_UARes[j, k, 2, 1] * NormalVector[j, k, 2]; acc += ParticleAuxillary.SummationWithNeumaier(SummandsVelGradient, SummandsPressure, FluidViscosity); break; case 2: SummandsPressure = pARes[j, k] * NormalVector[j, k, 2]; SummandsVelGradient[0] = -2 * Grad_UARes[j, k, 2, 2] * NormalVector[j, k, 2]; SummandsVelGradient[1] = -Grad_UARes[j, k, 2, 0] * NormalVector[j, k, 0]; SummandsVelGradient[2] = -Grad_UARes[j, k, 2, 1] * NormalVector[j, k, 1]; SummandsVelGradient[3] = -Grad_UARes[j, k, 0, 2] * NormalVector[j, k, 0]; SummandsVelGradient[4] = -Grad_UARes[j, k, 1, 2] * NormalVector[j, k, 1]; acc += ParticleAuxillary.SummationWithNeumaier(SummandsVelGradient, SummandsPressure, FluidViscosity); break; default: throw new NotImplementedException(); } return acc; }
/// <summary> /// Update Forces and Torque acting from fluid onto the particle /// </summary> /// <param name="U"></param> /// <param name="P"></param> /// <param name="LsTrk"></param> /// <param name="muA"></param> public void UpdateForcesAndTorque(VectorField <SinglePhaseField> U, SinglePhaseField P, LevelSetTracker LsTrk, double muA, double dt, double fluidDensity, bool NotFullyCoupled) { if (skipForceIntegration) { skipForceIntegration = false; return; } HydrodynamicForces[0][0] = 0; HydrodynamicForces[0][1] = 0; HydrodynamicTorque[0] = 0; int RequiredOrder = U[0].Basis.Degree * 3 + 2; Console.WriteLine("Forces coeff: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); double[] Forces = new double[SpatialDim]; SinglePhaseField[] UA = U.ToArray(); ConventionalDGField pA = null; pA = P; if (IncludeTranslation) { for (int d = 0; d < SpatialDim; d++) { void ErrFunc(int CurrentCellID, int Length, NodeSet Ns, MultidimensionalArray result) { int NumberOfNodes = result.GetLength(1); MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Length, NumberOfNodes, SpatialDim, SpatialDim); MultidimensionalArray pARes = MultidimensionalArray.Create(Length, NumberOfNodes); var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, CurrentCellID, Length); for (int i = 0; i < SpatialDim; i++) { UA[i].EvaluateGradient(CurrentCellID, Length, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } pA.Evaluate(CurrentCellID, Length, Ns, pARes); for (int j = 0; j < Length; j++) { for (int k = 0; k < NumberOfNodes; k++) { result[j, k] = ForceIntegration.CalculateStressTensor(Grad_UARes, pARes, Normals, muA, k, j, this.SpatialDim, d); } } } var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, CutCells_P(LsTrk)); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { Forces[d] = ParticleAuxillary.ForceTorqueSummationWithNeumaierArray(Forces[d], ResultsOfIntegration, Length); } ).Execute(); } } double Torque = 0; if (IncludeRotation) { void ErrFunc2(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, SpatialDim, SpatialDim);; MultidimensionalArray pARes = MultidimensionalArray.Create(Len, K); // Evaluate tangential velocity to level-set surface var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int i = 0; i < SpatialDim; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } pA.Evaluate(j0, Len, Ns, pARes); for (int j = 0; j < Len; j++) { MultidimensionalArray tempArray = Ns.CloneAs(); LsTrk.GridDat.TransformLocal2Global(Ns, tempArray, j0 + j); for (int k = 0; k < K; k++) { result[j, k] = ForceIntegration.CalculateTorqueFromStressTensor2D(Grad_UARes, pARes, Normals, tempArray, muA, k, j, Position[0]); } } } var SchemeHelper2 = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs2 = SchemeHelper2.GetLevelSetquadScheme(0, CutCells_P(LsTrk)); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs2.Compile(LsTrk.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc2(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { Torque = ParticleAuxillary.ForceTorqueSummationWithNeumaierArray(Torque, ResultsOfIntegration, Length); } ).Execute(); } // add gravity { Forces[1] += (particleDensity - fluidDensity) * Area_P * GravityVertical; } // Sum forces and moments over all MPI processors // ============================================== { int NoOfVars = 1 + SpatialDim; double[] StateBuffer = new double[NoOfVars]; StateBuffer[0] = Torque; for (int d = 0; d < SpatialDim; d++) { StateBuffer[1 + d] = Forces[d]; } double[] GlobalStateBuffer = StateBuffer.MPISum(); Torque = GlobalStateBuffer[0]; for (int d = 0; d < SpatialDim; d++) { Forces[d] = GlobalStateBuffer[1 + d]; } } if (neglectAddedDamping == false) { double fest = Forces[0]; Forces[0] = Forces[0] + AddedDampingCoefficient * dt * (AddedDampingTensor[0, 0] * TranslationalAcceleration[0][0] + AddedDampingTensor[1, 0] * TranslationalAcceleration[0][1] + AddedDampingTensor[0, 2] * RotationalAcceleration[0]); Forces[1] = Forces[1] + AddedDampingCoefficient * dt * (AddedDampingTensor[0, 1] * TranslationalAcceleration[0][0] + AddedDampingTensor[1, 1] * TranslationalAcceleration[0][1] + AddedDampingTensor[1, 2] * RotationalAcceleration[0]); Torque += AddedDampingCoefficient * dt * (AddedDampingTensor[2, 0] * TranslationalAcceleration[0][0] + AddedDampingTensor[2, 1] * TranslationalAcceleration[0][1] + AddedDampingTensor[2, 2] * RotationalAcceleration[0]); } if (iteration_counter_P == -1 || NotFullyCoupled || iteration_counter_P == 250 || stupidcounter == 0) { Console.WriteLine(); if (iteration_counter_P == 1) { Console.WriteLine("First iteration of the current timestep, all relaxation factors are set to 1"); } if (iteration_counter_P == 250) { Console.WriteLine("250 iterations, I'm trying to jump closer to the real solution"); } for (int d = 0; d < SpatialDim; d++) { HydrodynamicForces[0][d] = 0; if (Math.Abs(Forces[d]) < ForceAndTorque_convergence * 1e-2 && ClearSmallValues == true) { Forces[d] = 0; } HydrodynamicForces[0][d] = Forces[d]; } HydrodynamicTorque[0] = 0; if (Math.Abs(Torque) < ForceAndTorque_convergence * 1e-2 && ClearSmallValues == true) { Torque = 0; } HydrodynamicTorque[0] = Torque; stupidcounter = 1; } else { double[] RelaxatedForceAndTorque = Underrelaxation.RelaxatedForcesAndTorque(Forces, Torque, ForcesPrevIteration, TorquePrevIteration, ForceAndTorque_convergence, underrelaxation_factor, ClearSmallValues, AddaptiveUnderrelaxation, AverageDistance, iteration_counter_P); for (int d = 0; d < SpatialDim; d++) { HydrodynamicForces[0][d] = RelaxatedForceAndTorque[d]; } HydrodynamicTorque[0] = RelaxatedForceAndTorque[SpatialDim]; } //for (int d = 0; d < SpatialDim; d++)// changes sign depending on the sign of Forces[d], should increase the convergence rate. (testing needed) //{ // if (Math.Abs(HydrodynamicForces[0][d] - Forces[0]) > Math.Abs(Forces[d])) // { // HydrodynamicForces[0][d] *= -1; // } //} if (double.IsNaN(HydrodynamicForces[0][0]) || double.IsInfinity(HydrodynamicForces[0][0])) { throw new ArithmeticException("Error trying to calculate hydrodynamic forces (x). Value: " + HydrodynamicForces[0][0]); } if (double.IsNaN(HydrodynamicForces[0][1]) || double.IsInfinity(HydrodynamicForces[0][1])) { throw new ArithmeticException("Error trying to calculate hydrodynamic forces (y). Value: " + HydrodynamicForces[0][1]); } if (double.IsNaN(HydrodynamicTorque[0]) || double.IsInfinity(HydrodynamicTorque[0])) { throw new ArithmeticException("Error trying to calculate hydrodynamic torque. Value: " + HydrodynamicTorque[0]); } }