/// <summary> /// Calculate Forces acting from fluid onto the particle /// </summary> internal double Torque(double[] position, CellMask cutCells) { double tempTorque = new double(); void ErrFunc2(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, m_SpatialDim, m_SpatialDim);; MultidimensionalArray pARes = MultidimensionalArray.Create(Len, K); MultidimensionalArray Normals = m_LevelSetTracker.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int i = 0; i < m_SpatialDim; i++) { m_U[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } m_P.Evaluate(j0, Len, Ns, pARes); for (int j = 0; j < Len; j++) { MultidimensionalArray Ns_Global = Ns.CloneAs(); m_LevelSetTracker.GridDat.TransformLocal2Global(Ns, Ns_Global, j0 + j); for (int k = 0; k < K; k++) { result[j, k] = TorqueStressTensor(Grad_UARes, pARes, Normals, Ns_Global, m_FluidViscosity, k, j, position); } } } var SchemeHelper2 = m_LevelSetTracker.GetXDGSpaceMetrics(new[] { m_LevelSetTracker.GetSpeciesId("A") }, m_RequiredOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs2 = SchemeHelper2.GetLevelSetquadScheme(0, cutCells); CellQuadrature.GetQuadrature(new int[] { 1 }, m_LevelSetTracker.GridDat, cqs2.Compile(m_LevelSetTracker.GridDat, m_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) { tempTorque = ForceTorqueSummationWithNeumaierArray(tempTorque, ResultsOfIntegration, Length); } ).Execute(); return(tempTorque); }
/// <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) { if (skipForceIntegration) { skipForceIntegration = false; return; } int D = LsTrk.GridDat.SpatialDimension; // var UA = U.Select(u => u.GetSpeciesShadowField("A")).ToArray(); var UA = U.ToArray(); int RequiredOrder = U[0].Basis.Degree * 3 + 2; //int RequiredOrder = LsTrk.GetXQuadFactoryHelper(momentFittingVariant).GetCachedSurfaceOrders(0).Max(); //Console.WriteLine("Order reduction: {0} -> {1}", _RequiredOrder, RequiredOrder); //if (RequiredOrder > agg.HMForder) // throw new ArgumentException(); Console.WriteLine("Forces coeff: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); ConventionalDGField pA = null; //pA = P.GetSpeciesShadowField("A"); pA = P; #region Force double[] forces = new double[D]; for (int d = 0; d < D; d++) { ScalarFunctionEx ErrFunc = delegate(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, D, D);; 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 < D; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } pA.Evaluate(j0, Len, Ns, pARes); if (LsTrk.GridDat.SpatialDimension == 2) { for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; // pressure switch (d) { case 0: acc += (pARes[j, k]) * Normals[j, k, 0]; acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; break; case 1: acc += (pARes[j, k]) * Normals[j, k, 1]; acc -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; break; default: throw new NotImplementedException(); } result[j, k] = acc; } } } else { for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; // pressure switch (d) { case 0: acc += pARes[j, k] * Normals[j, k, 0]; acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 2, 0] * Normals[j, k, 2]; break; case 1: acc += pARes[j, k] * Normals[j, k, 1]; acc -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 2, 1] * Normals[j, k, 2]; break; case 2: acc += pARes[j, k] * Normals[j, k, 2]; acc -= (2 * muA) * Grad_UARes[j, k, 2, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 2, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 2, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 0, 2] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 1, 2] * Normals[j, k, 1]; break; default: throw new NotImplementedException(); } result[j, k] = acc; } } } }; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; //var SchemeHelper = new XQuadSchemeHelper(LsTrk, momentFittingVariant, ); //CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, this.cutCells_P(LsTrk)); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, RequiredOrder), // agg.HMForder), 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) { for (int i = 0; i < Length; i++) { forces[d] += ResultsOfIntegration[i, 0]; } } ).Execute(); } #endregion #region Torque double torque = 0; ScalarFunctionEx ErrFunc2 = delegate(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, D, D);; 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 < D; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } //var trafo = LsTrk.GridDat.Edges.Edge2CellTrafos; //var trafoIdx = LsTrk.GridDat.TransformLocal2Global(Ns) //var transFormed = trafo[trafoIdx].Transform(Nodes); //var newVertices = transFormed.CloneAs(); //GridData.TransformLocal2Global(transFormed, newVertices, jCell); MultidimensionalArray tempArray = Ns.CloneAs(); LsTrk.GridDat.TransformLocal2Global(Ns, tempArray, j0); pA.Evaluate(j0, Len, Ns, pARes); for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; double acc2 = 0.0; // Calculate the torque around a circular particle with a given radius (Paper Wan and Turek 2005) acc += (pARes[j, k] * Normals[j, k, 0]); acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; //acc *= -Normals[j, k, 1] * this.radius_P; acc *= -Normals[j, k, 1] * (this.currentPos_P[0][1] - tempArray[k, 1]).Abs(); acc2 += pARes[j, k] * Normals[j, k, 1]; acc2 -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc2 -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc2 -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; //acc2 *= Normals[j, k, 0] * this.radius_P; acc2 *= Normals[j, k, 0] * (this.currentPos_P[0][0] - tempArray[k, 0]).Abs(); result[j, k] = acc + acc2; } } }; var SchemeHelper2 = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; //var SchemeHelper = new XQuadSchemeHelper(LsTrk, momentFittingVariant, ); //CellQuadratureScheme cqs2 = SchemeHelper2.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadratureScheme cqs2 = SchemeHelper2.GetLevelSetquadScheme(0, this.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) { for (int i = 0; i < Length; i++) { torque += ResultsOfIntegration[i, 0]; } } ).Execute(); double underrelaxationFT = 1.0; double[] temp_underR = new double[D + 1]; for (int k = 0; k < D + 1; k++) { temp_underR[k] = underrelaxation_factor; } if (iteration_counter_P == 0) { underrelaxationFT = 1; } else if (underrelaxationFT_constant == true) { underrelaxationFT = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } else if (underrelaxationFT_constant == false) { //double[] temp_underR = new double[D + 1]; bool underrelaxation_ok = false; underrelaxationFT_exponent = 1; for (int j = 0; j < D; j++) { underrelaxation_ok = false; temp_underR[j] = underrelaxation_factor; for (int i = 0; underrelaxation_ok == false; i++) { if (Math.Abs(temp_underR[j] * forces[j]) > Math.Abs(forces_P[0][j])) { underrelaxationFT_exponent -= 1; temp_underR[j] = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } else { underrelaxation_ok = true; if (underrelaxationFT_exponent > -0) { underrelaxationFT_exponent = -0; temp_underR[j] = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } } } } underrelaxation_ok = false; temp_underR[D] = underrelaxation_factor; for (int i = 0; underrelaxation_ok == false; i++) { if (Math.Abs(temp_underR[D] * torque) > Math.Abs(torque_P[0])) { underrelaxationFT_exponent -= 1; temp_underR[D] = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } else { underrelaxation_ok = true; if (underrelaxationFT_exponent > -0) { underrelaxationFT_exponent = -0; temp_underR[D] = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } } } } double[] forces_underR = new double[D]; for (int i = 0; i < D; i++) { forces_underR[i] = temp_underR[i] * forces[i] + (1 - temp_underR[i]) * forces_P[0][i]; } double torque_underR = temp_underR[D] * torque + (1 - temp_underR[D]) * torque_P[0]; this.forces_P.Insert(0, forces_underR); forces_P.Remove(forces_P.Last()); this.torque_P.Remove(torque_P.Last()); this.torque_P.Insert(0, torque_underR); #endregion }
/// <summary> /// Calculates the added damping tensor by integrating over the level set of the particle. /// </summary> /// <param name="particle"> /// The current particle. /// </param> /// <param name="levelSetTracker"> /// The level set tracker. /// </param> /// <param name="fluidViscosity"></param> /// <param name="fluidDensity"></param> /// <param name="dt"></param> /// <param name="currentPosition"></param> /// <returns></returns> internal double[,] IntegrationOverLevelSet(Particle particle, LevelSetTracker levelSetTracker, double fluidViscosity, double fluidDensity, double dt, double[] currentPosition) { double[,] addedDampingTensor = new double[6, 6]; double alpha = 0.5; int RequiredOrder = 2; for (int DampingTensorID = 0; DampingTensorID < 4; DampingTensorID++) { for (int d1 = 0; d1 < 3; d1++) { for (int d2 = 0; d2 < 3; d2++) { void evalfD(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); MultidimensionalArray Normals = levelSetTracker.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); MultidimensionalArray NodeSetGlobal = Ns.CloneAs(); if (levelSetTracker.GridDat.SpatialDimension == 2) { for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { levelSetTracker.GridDat.TransformLocal2Global(Ns, NodeSetGlobal, j0 + j); double dh = CalculateNormalMeshSpacing(levelSetTracker, Ns, Normals, j, k); double delta = dh * Math.Sqrt(fluidDensity) / (Math.Sqrt(alpha * fluidViscosity * dt)); double dn = dh / (1 - Math.Exp(-delta)); double[] R = new double[3]; R[0] = NodeSetGlobal[k, 0] - currentPosition[0]; R[1] = NodeSetGlobal[k, 1] - currentPosition[1]; R[2] = 0; double[] NormalComponent = new double[3]; double test = NodeSetGlobal[k, 0]; double test2 = NodeSetGlobal[k, 1]; NormalComponent[0] = Normals[j, k, 0]; NormalComponent[1] = Normals[j, k, 1]; NormalComponent[2] = 0; switch (DampingTensorID) { case 0: //D^{vv} result[j, k] = d1 == d2 ? (1 - NormalComponent[d1] * NormalComponent[d2]) * fluidViscosity / dn : -NormalComponent[d1] * NormalComponent[d2] * fluidViscosity / dn; break; case 1: //D^{vw} if (d1 == 2 && d2 != 2) { result[j, k] = R[1 - d2] * Math.Pow(-1, d2) * fluidViscosity / dn; } else if (d1 != 2 && d2 == 2) { result[j, k] = ((1 - NormalComponent[d1] * NormalComponent[d1]) * (-R[1 - d1]) - NormalComponent[d1] * NormalComponent[1 - d1] * R[d1]) * Math.Pow(-1, d1) * fluidViscosity / dn; } else { result[j, k] = 0; } break; case 2: //D^{wv} if (d2 == 2 && d1 != 2) { result[j, k] = R[1 - d1] * Math.Pow(-1, d1) * fluidViscosity / dn; } else if (d2 != 2 && d1 == 2) { result[j, k] = ((1 - NormalComponent[d2] * NormalComponent[d2]) * (-R[1 - d2]) - NormalComponent[d2] * NormalComponent[1 - d2] * R[d2]) * Math.Pow(-1, d2) * fluidViscosity / dn; } else { result[j, k] = 0; } break; case 3: //D^{ww} if (d1 == d2 && d1 != 2) { result[j, k] = R[1 - d1].Pow2() * fluidViscosity / dn; } else if (d1 != d2 && d1 != 2 && d2 != 2) { result[j, k] = -R[0] * R[1] * fluidViscosity / dn; } else if (d1 == 2 && d2 == 2) { result[j, k] = (((1 - NormalComponent[0] * NormalComponent[0]) * R[1] + NormalComponent[0] * NormalComponent[1] * R[0]) * R[1] + ((1 - NormalComponent[1] * NormalComponent[1]) * R[0] + NormalComponent[0] * NormalComponent[1] * R[1]) * R[0]) * fluidViscosity / dn; } else { result[j, k] = 0; } break; } } } } else { throw new NotImplementedException("Currently the calculation of the Damping tensors is only available for 2D"); } } var SchemeHelper = levelSetTracker.GetXDGSpaceMetrics(new[] { levelSetTracker.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, particle.CutCells_P(levelSetTracker)); CellQuadrature.GetQuadrature(new int[] { 1 }, levelSetTracker.GridDat, cqs.Compile(levelSetTracker.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { evalfD(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int l = 0; l < Length; l++) { switch (DampingTensorID) { case 0: addedDampingTensor[d1, d2] += ResultsOfIntegration[l, 0]; break; case 1: addedDampingTensor[d1, d2 + 3] += ResultsOfIntegration[l, 0]; break; case 2: addedDampingTensor[d1 + 3, d2] += ResultsOfIntegration[l, 0]; break; case 3: addedDampingTensor[d1 + 3, d2 + 3] += ResultsOfIntegration[l, 0]; break; } } } ).Execute(); } } } if (levelSetTracker.GridDat.SpatialDimension == 2) { return(ModifyDampingTensor2D(addedDampingTensor)); } else { throw new NotImplementedException("Currently the calculation of the Damping tensors is only available for 2D"); } }
/// <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]); } }