public static double EnergyBalanceNormAtInterface(XDGField P, VectorField <XDGField> U, ConventionalDGField[] Umean, SinglePhaseField C, double muA, double muB, double sigma, int momentFittingOrder) { LevelSetTracker LsTrk = P.Basis.Tracker; double energyBal_Norm = 0.0; ScalarFunctionEx energyBalFunc = GetEnergyBalanceFunc(P, U, Umean, C, muA, muB, sigma, true); var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, momentFittingOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, momentFittingOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { energyBalFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { energyBal_Norm += ResultsOfIntegration[i, 0]; } } ).Execute(); return(energyBal_Norm.Sqrt()); }
public static double CurvatureEnergy(LevelSetTracker LsTrk, SinglePhaseField Curvature, double sigma, ConventionalDGField[] uI, bool ExtVel, bool Norm, int momentFittingorder) { double EnergyCurv = 0.0; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, momentFittingorder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); ScalarFunctionEx CurvEnergyFunc = GetCurvatureEnergyFunc(LsTrk, Curvature, sigma, uI, ExtVel, Norm); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, momentFittingorder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { CurvEnergyFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { EnergyCurv += ResultsOfIntegration[i, 0]; } } ).Execute(); if (Norm) { EnergyCurv.Sqrt(); } return(EnergyCurv); }
public static double EnergyJumpAtInterface(LevelSetTracker LsTrk, VectorField <XDGField> Velocity, XDGField Pressure, double muA, double muB, bool Norm, int momentFittingorder) { double EnergyJump = 0.0; ScalarFunctionEx EnergyJumpFunc = GetEnergyJumpFunc(LsTrk, Velocity, Pressure, muA, muB, Norm); var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, momentFittingorder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, momentFittingorder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { EnergyJumpFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { EnergyJump += ResultsOfIntegration[i, 0]; } } ).Execute(); if (Norm) { EnergyJump.Sqrt(); } return(EnergyJump); }
public static double SurfaceEnergyChangerate(LevelSetTracker LsTrk, ConventionalDGField[] uI, double sigma, bool Norm, int momentFittingorder) { double Changerate_Surface = 0.0; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, momentFittingorder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); ScalarFunctionEx SurfaceChangerate = GetInterfaceDivergenceFunc(LsTrk, uI, Norm); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, momentFittingorder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { SurfaceChangerate(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { Changerate_Surface += ResultsOfIntegration[i, 0]; } } ).Execute(); double Changerate_Esurf; if (Norm) { Changerate_Esurf = sigma * Changerate_Surface.Sqrt(); } else { Changerate_Esurf = sigma * Changerate_Surface; } return(Changerate_Esurf); }
/// <summary> /// Change-of-basis, in cell 0 /// </summary> /// <param name="jCell"></param> /// <param name="pl"></param> public MultidimensionalArray GetChangeofBasisMatrix(int jCell, PolynomialList pl) { var m_Context = this.GridDat; int N = this.Length; int M = pl.Count; int J = this.GridDat.iLogicalCells.NoOfLocalUpdatedCells; if (jCell < 0 || jCell >= J) { throw new ArgumentOutOfRangeException("cell index out of range"); } MultidimensionalArray Mtx = MultidimensionalArray.Create(N, M); var cellMask = new CellMask(m_Context, new[] { new Chunk() { i0 = jCell, Len = 1 } }, MaskType.Geometrical); // we project the basis function from 'jCell1' onto 'jCell0' CellQuadrature.GetQuadrature(new int[2] { N, M }, m_Context, (new CellQuadratureScheme(true, cellMask)).Compile(m_Context, this.Degree + pl.MaxAbsoluteDegree), // integrate over target cell delegate(int i0, int Length, QuadRule QR, MultidimensionalArray _EvalResult) { NodeSet nodes_Cell0 = QR.Nodes; Debug.Assert(Length == 1); //NodesGlobal.Allocate(1, nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1)); //m_Context.TransformLocal2Global(nodes_Cell0, jCell0, 1, NodesGlobal, 0); //var nodes_Cell1 = new NodeSet(GridDat.iGeomCells.GetRefElement(jCell1), nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1)); //m_Context.TransformGlobal2Local(NodesGlobal.ExtractSubArrayShallow(0, -1, -1), nodes_Cell1, jCell1, null); //nodes_Cell1.LockForever(); var phi_0 = this.CellEval(nodes_Cell0, jCell, 1).ExtractSubArrayShallow(0, -1, -1); MultidimensionalArray R = MultidimensionalArray.Create(QR.NoOfNodes, pl.Count); pl.Evaluate(nodes_Cell0, R); var EvalResult = _EvalResult.ExtractSubArrayShallow(0, -1, -1, -1); EvalResult.Multiply(1.0, R, phi_0, 0.0, "knm", "km", "kn"); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { Debug.Assert(Length == 1); var res = ResultsOfIntegration.ExtractSubArrayShallow(0, -1, -1); Mtx.Clear(); Mtx.Acc(1.0, res); }).Execute(); return(Mtx); }
/// <summary> /// Computes the Integral of a given function over the zero iso-contour of the Level-Set /// </summary> /// <param name="LsTrk">Level-Set tracker</param> /// <param name="func">function which is integrated</param> /// <param name="HMForder"></param> /// <param name="spc">species, over whose surface is integrated</param> /// <returns>Integral of <param name="func">func</param> over all MPI processors</returns> static public double GetIntegralOverZeroLevelSet(LevelSetTracker LsTrk, ScalarFunctionEx func, int HMForder, SpeciesId spc) { using (new FuncTrace()) { if (LsTrk.LevelSets.Count != 1) { throw new NotImplementedException(); } var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new SpeciesId[] { spc }, HMForder, 1).XQuadSchemeHelper; // new XQuadSchemeHelper(LsTrk, momentFittingVariant); // Classic HMF uses order+1 for Surface Integrals and additionally 1 order higher for the HMF system // e.g order-2 is the cached quad rule if (SchemeHelper.MomentFittingVariant == XQuadFactoryHelper.MomentFittingVariants.Classic) { HMForder -= 2; } CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); double force = 0; CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, HMForder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { func(i0, Length, QR.Nodes, EvalResult); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { force += ResultsOfIntegration[i, 0]; } } ).Execute(); double localForce = force; double globalForce; unsafe { csMPI.Raw.Allreduce( (IntPtr)(&localForce), (IntPtr)(&globalForce), 1, csMPI.Raw._DATATYPE.DOUBLE, csMPI.Raw._OP.SUM, csMPI.Raw._COMM.WORLD); } return(globalForce); } }
/// <summary> /// Calculate Forces acting from fluid onto the particle /// </summary> internal double[] Forces(out List <double[]>[] stressToPrintOut, CellMask cutCells) { double[] tempForces = new double[m_SpatialDim]; double[] IntegrationForces = tempForces.CloneAs(); List <double[]>[] stressToPrint = new List <double[]> [m_SpatialDim]; stressToPrint[0] = new List <double[]>(); stressToPrint[1] = new List <double[]>(); for (int d = 0; d < m_SpatialDim; d++) { void ErrFunc(int CurrentCellID, int Length, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Length, K, m_SpatialDim, m_SpatialDim); MultidimensionalArray pARes = MultidimensionalArray.Create(Length, K); MultidimensionalArray Normals = m_LevelSetTracker.DataHistories[0].Current.GetLevelSetNormals(Ns, CurrentCellID, Length); for (int i = 0; i < m_SpatialDim; i++) { m_U[i].EvaluateGradient(CurrentCellID, Length, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } m_P.Evaluate(CurrentCellID, Length, Ns, pARes); for (int j = 0; j < Length; j++) { for (int k = 0; k < K; k++) { result[j, k] = StressTensor(Grad_UARes, pARes, Normals, m_FluidViscosity, k, j, m_SpatialDim, d); double t = Math.PI * (1 - Math.Sign(Normals[j, k, 1])) / 2 + Math.Acos(Normals[j, k, 0]); stressToPrint[d].Add(new double[] { t, result[j, k] }); } } } int[] noOfIntegrals = new int[] { 1 }; XQuadSchemeHelper SchemeHelper = m_LevelSetTracker.GetXDGSpaceMetrics(new[] { m_LevelSetTracker.GetSpeciesId("A") }, m_RequiredOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, cutCells); ICompositeQuadRule <QuadRule> surfaceRule = cqs.Compile(m_LevelSetTracker.GridDat, m_RequiredOrder); CellQuadrature.GetQuadrature(noOfIntegrals, m_GridData, surfaceRule, 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) { IntegrationForces[d] = ForceTorqueSummationWithNeumaierArray(IntegrationForces[d], ResultsOfIntegration, Length); } ).Execute(); } stressToPrintOut = stressToPrint.CloneAs(); return(tempForces = IntegrationForces.CloneAs()); }
void OrthonormalityTest() { Basis B = f1.Basis; int N = B.Length; var Mtx = new FullMatrix(N, N); double TotErrSum = 0.0; CellQuadrature.GetQuadrature(new int[] { N, N }, this.GridDat, (new CellQuadratureScheme(true)).Compile(GridDat, Math.Min(B.Degree * 2, 16)), delegate(MultidimensionalArray NodesUntransformed, int iKref) { var ret = new NodeSetController.NodeSetContainer[] { GridDat.NSC.CreateContainer(NodesUntransformed, iKref) }; return(ret); }, delegate(int i0, int Length, int NoOfNodes, MultidimensionalArray EvalResult) { // void Del_Evaluate var BasisVal = B.CellEval(0, i0, Length); EvalResult.Multiply(1.0, BasisVal, BasisVal, 0.0, "jknm", "jkn", "jkm"); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { // SaveIntegrationResults for (int i = 0; i < Length; i++) { var MassMtx = ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1); double errsum = 0; for (int n = 0; n < N; n++) { for (int m = 0; m < N; m++) { double soll = (n == m) ? 1.0 : 0.0; errsum += Math.Abs(MassMtx[m, n] - soll); } } TotErrSum += errsum; } }).Execute(); Console.WriteLine("orthonormality error sum:" + TotErrSum); }
public static double GetKineticDissipation(LevelSetTracker LsTrk, DGField[] Velocity, double[] mu, int momentFittingOrder, int HistInd = 1) { using (new FuncTrace()) { int D = LsTrk.GridDat.SpatialDimension; if (Velocity.Count() != D) { throw new ArgumentException(); } if (LsTrk.SpeciesIdS.Count != mu.Length) { throw new ArgumentException(); } double dE = 0.0; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(LsTrk.SpeciesIdS.ToArray(), momentFittingOrder, HistInd).XQuadSchemeHelper; for (int iSpc = 0; iSpc < LsTrk.SpeciesIdS.Count; iSpc++) { SpeciesId spcId = LsTrk.SpeciesIdS[iSpc]; double _mu = mu[iSpc]; var Uspc = Velocity.Select(u => (u as XDGField).GetSpeciesShadowField(spcId)).ToArray(); ScalarFunctionEx changerate_dEspc = GetSpeciesKineticDissipationFunc(Uspc, _mu); CellQuadratureScheme vqs = SchemeHelper.GetVolumeQuadScheme(spcId); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, vqs.Compile(LsTrk.GridDat, momentFittingOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { changerate_dEspc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { dE += ResultsOfIntegration[i, 0]; } } ).Execute(); } return(dE); } }
/// <summary> /// Computes the energy stored in the fluid interface of a two-phase flow. /// </summary> /// <param name="LsTrk"></param> /// <param name="sigma"></param> public static double GetSurfaceEnergy(LevelSetTracker LsTrk, double sigma) { using (new FuncTrace()) { if (LsTrk.LevelSets.Count != 1) { throw new NotImplementedException(); } double totSurface = 0; int order = 0; if (LsTrk.GetCachedOrders().Count > 0) { order = LsTrk.GetCachedOrders().Max(); } else { order = 1; } var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, order, 1).XQuadSchemeHelper; //var SchemeHelper = new XQuadSchemeHelper(LsTrk, momentFittingVariant, LsTrk.GetSpeciesId("A")); CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, order), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { EvalResult.SetAll(1.0); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { totSurface += ResultsOfIntegration[i, 0]; } } ).Execute(); return(totSurface * sigma); } }
/// <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); }
public static void ProjectEnergyBalanceNorm(this SinglePhaseField err, double alpha, XDGField P, VectorField <XDGField> U, ConventionalDGField[] Umean, SinglePhaseField C, double muA, double muB, double sigma, int momentFittingOrder) { var LsTrk = U[0].Basis.Tracker; int D = LsTrk.GridDat.SpatialDimension; ScalarFunctionEx ErrFunc = GetEnergyBalanceFunc(P, U, Umean, C, muA, muB, sigma, true); var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, momentFittingOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, momentFittingOrder), 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++) { err.SetMeanValue(i0 + i, ResultsOfIntegration[i, 0].Sqrt()); } } ).Execute(); }
public static double GetInterfaceShearViscosityEnergyCR(LevelSetTracker LsTrk, ConventionalDGField[] uI, double muI, int momentFittingOrder) { double shearViscEnergy = 0.0; ScalarFunctionEx shearViscEnergyFunc = GetInterfaceShearViscosityEnergyCRFunc(LsTrk, uI, false); var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, momentFittingOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, momentFittingOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { shearViscEnergyFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { shearViscEnergy += ResultsOfIntegration[i, 0]; } } ).Execute(); return(muI * shearViscEnergy); }
void SpecialProjection(LevelSetTracker LsTrk, int order, DGField[] Uin, VectorField <SinglePhaseField> Uout) { var CC = LsTrk.Regions.GetCutCellMask(); var gDat = LsTrk.GridDat; // get quadrature rules // ==================== //XQuadSchemeHelper H = new XQuadSchemeHelper(LsTrk, MomentFittingVariant); var H = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, order, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = H.GetLevelSetquadScheme(0, CC); ICompositeQuadRule <QuadRule> surfRule = cqs.Compile(gDat, order); ICompositeQuadRule <CellBoundaryQuadRule> bndyRule = (new CellBoundaryQuadratureScheme(true, CC)).Compile(gDat, order); // Compute Mass matrix and RHS for the 'strange' projection // ======================================================== int L = CC.NoOfItemsLocally; var Q = new QuadratureKernels(Uin, L); Q.BlockCnt = 0; CellQuadrature.GetQuadrature( new int[] { Q.Nnx + Q.D, Q.Nnx }, gDat, surfRule, Q.Evaluate, Q.SaveIntegrationResults_surf).Execute(); Debug.Assert(Q.BlockCnt == L); Q.BlockCnt = 0; CellBoundaryQuadrature <CellBoundaryQuadRule> .GetQuadrature( new int[] { Q.Nnx + Q.D, Q.Nnx }, gDat, bndyRule, Q.Evaluate, Q.SaveIntegrationResults_bndy).Execute(); Debug.Assert(Q.BlockCnt == L); // solve the non-diagonal mass matrix systems // ========================================== int BlkCnt = 0; foreach (int jCell in CC.ItemEnum) { var MassMatrix = Q.MassMatrix.ExtractSubArrayShallow(BlkCnt, -1, -1); var RHS = Q.RHS.ExtractSubArrayShallow(BlkCnt, -1, -1); // Die "Massenmatrix" muss nicht unbedingt invbar sein, daher: Least-Squares solve MassMatrix.LeastSquareSolve(RHS); for (int d = 0; d < Q.D; d++) { for (int n = 0; n < Q.Nnx; n++) { Uout[d].Coordinates[jCell, n] = RHS[n, d]; } } BlkCnt++; } }
/// <summary> /// Calculates the Torque around the center of mass /// </summary> /// <param name="U"></param> /// <param name="P"></param> /// <param name="momentFittingVariant"></param> /// <param name="muA"></param> /// <param name="particleRadius"></param> /// <returns></returns> static public void GetCellValues(VectorField <XDGField> U, XDGField P, double muA, double particleRadius, SinglePhaseField P_atIB, SinglePhaseField gradU_atIB, SinglePhaseField gradUT_atIB) { var LsTrk = U[0].Basis.Tracker; int D = LsTrk.GridDat.SpatialDimension; var UA = U.Select(u => u.GetSpeciesShadowField("A")).ToArray(); if (D > 2) { throw new NotImplementedException("Currently only 2D cases supported"); } int RequiredOrder = U[0].Basis.Degree * 3 + 2; //if (RequiredOrder > agg.HMForder) // throw new ArgumentException(); Console.WriteLine("Cell values calculated by: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); ConventionalDGField pA = null; double circumference = new double(); pA = P.GetSpeciesShadowField("A"); for (int n = 0; n < 4; n++) { ScalarFunctionEx ErrFunc_CellVal = 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)); } 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; switch (n) { case 0: // Pressure part acc += pARes[j, k] * Normals[j, k, 0]; acc *= -Normals[j, k, 1] * particleRadius; acc2 += pARes[j, k] * Normals[j, k, 1]; acc2 *= Normals[j, k, 0] * particleRadius; result[j, k] = acc + acc2; break; case 1: // GradU part acc -= (1 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; // Attention was 2 times acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc *= -Normals[j, k, 1] * particleRadius; acc2 -= (1 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc2 -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc2 *= Normals[j, k, 0] * particleRadius; result[j, k] = acc + acc2; break; case 2: // GradU_T part acc -= (1 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; // Attention was 2 times acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; acc *= -Normals[j, k, 1] * particleRadius; acc2 -= (1 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; // Attention was 2 times acc2 -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; acc2 *= Normals[j, k, 0] * particleRadius; result[j, k] = acc + acc2; break; case 3: // Standardization with radians result[j, k] = 1; break; default: throw new NotImplementedException(); } } } }; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; // new XQuadSchemeHelper(LsTrk, momentFittingVariant, ); CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc_CellVal(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { switch (n) { case 0: P_atIB.SetMeanValue(i0, ResultsOfIntegration[i, 0]); break; case 1: gradU_atIB.SetMeanValue(i0, ResultsOfIntegration[i, 0]); break; case 2: gradUT_atIB.SetMeanValue(i0, ResultsOfIntegration[i, 0]); break; case 3: circumference += ResultsOfIntegration[i, 0]; P_atIB.SetMeanValue(i0, P_atIB.GetMeanValue(i0) / ResultsOfIntegration[i, 0]); gradU_atIB.SetMeanValue(i0, gradU_atIB.GetMeanValue(i0) / ResultsOfIntegration[i, 0]); gradUT_atIB.SetMeanValue(i0, gradUT_atIB.GetMeanValue(i0) / ResultsOfIntegration[i, 0]); break; default: throw new NotImplementedException(); } } } ).Execute(); } Console.WriteLine("Circle circumference: " + circumference); }
/// <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> /// /// </summary> /// <param name="CellPairs"> /// 1st index: list of cells <br/> /// 2nd index: in {0, 1} /// </param> /// <param name="M"> /// 1st index: corresponds with 1st index of <paramref name="CellPairs"/><br/> /// 2nd index: matrix row index <br/> /// 3rd index: matrix column index /// </param> /// <param name="Minv">the inverse of <paramref name="M"/></param> /// <remarks> /// Let \f$ K_j \f$ and \f$ K_i \f$ be two different cells with a linear-affine /// transformation to the reference element. /// Here, \f$ j \f$=<paramref name="CellPairs"/>[a,0] and \f$ i \f$=<paramref name="CellPairs"/>[a,1]. /// The DG-basis in these cells can uniquely be represented as /// \f[ /// \phi_{j n} (\vec{x}) = p_n (\vec{x}) \vec{1}_{K_j} (\vec{x}) /// \textrm{ and } /// \phi_{i m} (\vec{x}) = q_m (\vec{x}) \vec{1}_{K_i} (\vec{x}) /// \f] /// where \f$ \vec{1}_X \f$ denotes the characteristic function for set \f$ X \f$ /// and \f$ p_n\f$ and \f$ p_m\f$ are polynomials. /// Then, for the output \f$ M \f$ =<paramref name="M"/>[a,-,-] fulfills /// \f[ /// \phi_{j n} + \sum_{m} M_{m n} \phi_{i m} /// = /// p_n \vec{1}_{K_j \cup K_i} /// \f] /// </remarks> public void GetExtrapolationMatrices(int[,] CellPairs, MultidimensionalArray M, MultidimensionalArray Minv = null) { var m_Context = this.GridDat; int N = this.Length; int Esub = CellPairs.GetLength(0); int JE = this.GridDat.iLogicalCells.Count; int J = this.GridDat.iLogicalCells.NoOfLocalUpdatedCells; if (CellPairs.GetLength(1) != 2) { throw new ArgumentOutOfRangeException("second dimension is expected to be 2!"); } if (M.Dimension != 3) { throw new ArgumentException(); } if (M.GetLength(0) != Esub) { throw new ArgumentException(); } if (M.GetLength(1) != N || M.GetLength(2) != N) { throw new ArgumentException(); } if (Minv != null) { if (Minv.GetLength(0) != Esub) { throw new ArgumentException(); } if (Minv.GetLength(1) != N || Minv.GetLength(2) != N) { throw new ArgumentException(); } } MultidimensionalArray NodesGlobal = new MultidimensionalArray(3); MultidimensionalArray Minv_tmp = MultidimensionalArray.Create(N, N); MultidimensionalArray M_tmp = MultidimensionalArray.Create(N, N); for (int esub = 0; esub < Esub; esub++) // loop over the cell pairs... { int jCell0 = CellPairs[esub, 0]; int jCell1 = CellPairs[esub, 1]; if (jCell0 < 0 || jCell0 >= JE) { throw new ArgumentOutOfRangeException("Cell index out of range."); } if (jCell1 < 0 || jCell1 >= JE) { throw new ArgumentOutOfRangeException("Cell index out of range."); } bool swap; if (jCell0 >= J) { //if(true) { swap = true; int a = jCell0; jCell0 = jCell1; jCell1 = a; } else { swap = false; } if (!m_Context.iGeomCells.IsCellAffineLinear(jCell0)) { throw new NotSupportedException("Currently not supported for curved cells."); } if (!m_Context.iGeomCells.IsCellAffineLinear(jCell1)) { throw new NotSupportedException("Currently not supported for curved cells."); } Debug.Assert(jCell0 < J); var cellMask = new CellMask(m_Context, new[] { new Chunk() { i0 = jCell0, Len = 1 } }, MaskType.Geometrical); // we project the basis function from 'jCell1' onto 'jCell0' CellQuadrature.GetQuadrature(new int[2] { N, N }, m_Context, (new CellQuadratureScheme(true, cellMask)).Compile(m_Context, this.Degree * 2), // integrate over target cell delegate(int i0, int Length, QuadRule QR, MultidimensionalArray _EvalResult) { NodeSet nodes_Cell0 = QR.Nodes; Debug.Assert(Length == 1); NodesGlobal.Allocate(1, nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1)); m_Context.TransformLocal2Global(nodes_Cell0, jCell0, 1, NodesGlobal, 0); var nodes_Cell1 = new NodeSet(GridDat.iGeomCells.GetRefElement(jCell1), nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1)); m_Context.TransformGlobal2Local(NodesGlobal.ExtractSubArrayShallow(0, -1, -1), nodes_Cell1, jCell1, null); nodes_Cell1.LockForever(); var phi_0 = this.CellEval(nodes_Cell0, jCell0, 1).ExtractSubArrayShallow(0, -1, -1); var phi_1 = this.CellEval(nodes_Cell1, jCell1, 1).ExtractSubArrayShallow(0, -1, -1); var EvalResult = _EvalResult.ExtractSubArrayShallow(0, -1, -1, -1); EvalResult.Multiply(1.0, phi_1, phi_0, 0.0, "kmn", "kn", "km"); }, /*_SaveIntegrationResults:*/ delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { Debug.Assert(Length == 1); var res = ResultsOfIntegration.ExtractSubArrayShallow(0, -1, -1); Minv_tmp.Clear(); Minv_tmp.Acc(1.0, res); }).Execute(); // compute the inverse Minv_tmp.InvertTo(M_tmp); // store if (!swap) { M.ExtractSubArrayShallow(esub, -1, -1).AccMatrix(1.0, M_tmp); if (Minv != null) { Minv.ExtractSubArrayShallow(esub, -1, -1).AccMatrix(1.0, Minv_tmp); } } else { M.ExtractSubArrayShallow(esub, -1, -1).AccMatrix(1.0, Minv_tmp); if (Minv != null) { Minv.ExtractSubArrayShallow(esub, -1, -1).AccMatrix(1.0, M_tmp); } } } }
static internal void ComputeMassMatrixBlocks( IEnumerable <SpeciesId> _SpeciesIds, out Dictionary <SpeciesId, MassMatrixBlockContainer> Result, Basis b, XDGSpaceMetrics homie) { using (var tracer = new FuncTrace()) { if (b is XDGBasis) { throw new ArgumentException(); } var ctx = homie.GridDat; Result = new Dictionary <SpeciesId, MassMatrixBlockContainer>(); var schemeHelper = homie.XQuadSchemeHelper; int Nnx = b.Length; int quadorder = homie.CutCellQuadOrder; // define domains and allocate memory // ================================== foreach (var Species in _SpeciesIds) // loop over species... // interation dom { var _IntegrationDomain = homie.LevelSetRegions.GetSpeciesMask(Species).Intersect(homie.LevelSetRegions.GetCutCellMask()); // domain for mass-matrix blocks (include agglomeration targets) var _BlockDomain = _IntegrationDomain; //.Union(Agg.GetAgglomerator(Species).AggInfo.AllAffectedCells); // alloc mem for blocks var _MassMatrixBlocksSpc = MultidimensionalArray.Create(_BlockDomain.NoOfItemsLocally, Nnx, Nnx); // Subgrid index to cell index int[] _jSub2jCell = _BlockDomain.ItemEnum.ToArray(); // cell to subgrid index //Dictionary<int, int> _jCell2jSub; //if (Agg.GetAgglomerator(Species).AggInfo.AgglomerationPairs.Length > 0) { // _jCell2jSub = new Dictionary<int, int>(); // for (int i = 0; i < _jSub2jCell.Length; i++) { // _jCell2jSub.Add(_jSub2jCell[i], i); // } //} else { // _jCell2jSub = null; //} Result.Add(Species, new MassMatrixBlockContainer() { IntegrationDomain = _IntegrationDomain, MassMatrixBlocks = _MassMatrixBlocksSpc, //jCell2jSub = _jCell2jSub, jSub2jCell = _jSub2jCell }); } // compute blocks // ============== foreach (var Species in _SpeciesIds) { // get quad scheme CellQuadratureScheme scheme = schemeHelper.GetVolumeQuadScheme(Species, IntegrationDomain: Result[Species].IntegrationDomain); // result storage var MassMatrixBlocksSpc = Result[Species].MassMatrixBlocks; tracer.Info("mass matrix quad order: " + quadorder); // compute the products of the basis functions: int BlockCnt = -1; int[] BlockCell = Result[Species].jSub2jCell; CellMask speciesCells = homie.LevelSetRegions.GetSpeciesMask(Species); CellQuadrature.GetQuadrature( new int[] { Nnx, Nnx }, ctx, scheme.Compile(ctx, quadorder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { // Del_Evaluate // ~~~~~~~~~~~~~ var BasisVal = b.CellEval(QR.Nodes, i0, Length); EvalResult.Multiply(1.0, BasisVal, BasisVal, 0.0, "ikmn", "ikm", "ikn"); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { // Del_SaveIntegrationResults // ~~~~~~~~~~~~~~~~~~~~~~~~~~ for (int i = 0; i < Length; i++) { int jCell = i0 + i; BlockCnt++; // insert ID block in agglomeration target cells (if necessary): // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - var Block = MassMatrixBlocksSpc.ExtractSubArrayShallow(BlockCnt, -1, -1); while (BlockCell[BlockCnt] < jCell) { // agglomeration source/target cell that is not cut // mass matrix is identity (full) or zero (void) Block.Clear(); if (speciesCells.Contains(BlockCell[BlockCnt])) { // cell is full for (int nn = 0; nn < Nnx; nn++) { Block[nn, nn] = 1.0; } } BlockCnt++; Block = MassMatrixBlocksSpc.ExtractSubArrayShallow(BlockCnt, -1, -1); } // store computed block // - - - - - - - - - - - Debug.Assert(BlockCell[BlockCnt] == jCell); MassMatrixBlocksSpc.ExtractSubArrayShallow(BlockCnt, -1, -1) .Set(ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1)); #if DEBUG for (int n = 0; n < Nnx; n++) { for (int m = 0; m < Nnx; m++) { Debug.Assert(Block[n, m] == Block[m, n]); } } #endif } }).Execute(); // ------------------------------------ quadrature end. BlockCnt++; while (BlockCnt < MassMatrixBlocksSpc.GetLength(0)) { // agglomeration source/target cell that is not cut // mass matrix is identity (full) or zero (void) var Block = MassMatrixBlocksSpc.ExtractSubArrayShallow(BlockCnt, -1, -1); Block.Clear(); if (speciesCells.Contains(BlockCell[BlockCnt])) { // cell is full for (int nn = 0; nn < Nnx; nn++) { Block[nn, nn] = 1.0; } } BlockCnt++; } /* * // test mass matrix for positive definiteness * { * int JSUB = MassMatrixBlocksSpc.GetLength(0); * SubGrid Idom = null; * * int failCount = 0; * var PosDefiniteTest = new FullMatrix(Nnx, Nnx); * * for (int jsub = 0; jsub < JSUB; jsub++) { * PosDefiniteTest.Clear(); * PosDefiniteTest.Acc(MassMatrixBlocksSpc.ExtractSubArrayShallow(jsub, -1, -1), 1.0); * * try { * PosDefiniteTest.Clear(); * PosDefiniteTest.Acc(MassMatrixBlocksSpc.ExtractSubArrayShallow(jsub, -1, -1), 1.0); * PosDefiniteTest.InvertSymmetrical(); * * //PosDefiniteTest.Clear(); * //PosDefiniteTest.AccEye(1.0); * //PosDefiniteTest.Acc(MassMatrixBlocksSpc.ExtractSubArrayShallow(jsub, -1, -1), -1.0); * //PosDefiniteTest.InvertSymmetrical(); * } catch (ArithmeticException ae) { * if (Idom == null) * Idom = new SubGrid(scheme.Domain); * * int jCell = Idom.SubgridIndex2LocalCellIndex[jsub]; * long Gid = Tracker.GridDat.Cells.GetCell(jCell).GlobalID; * * * double volFrac = Tracker.GetSpeciesVolume(jCell, Species)/ctx.Cells.GetCellVolume(jCell); * * var errString = string.Format("Indefinite mass matrix in cell: globalId = {0}, local index = {1}, species {2}; \n cell volume fraction: {3};\n [{4}]", Gid, jCell, Tracker.GetSpeciesName(Species), volFrac, ae.Message); * tracer.Logger.Error(errString); * //Console.WriteLine(errString); * failCount++; * } * } * * if (failCount > 0) { * var errString = string.Format("Indefinite mass matrix in {0} of {1} cut cells", failCount, JSUB); * tracer.Logger.Error(errString); * Console.WriteLine(errString); * } else { * Console.WriteLine("No indefinite mass matrix blocks"); * } * * } * // */ // backup before agglomeration (required if we wanna treat e.g. velocity in DG and pressure in XDG) //MultidimensionalArray[] massMatrixBlocksB4Agglom = new MultidimensionalArray[Result[Species].jSub2jCell.Length]; //Result[Species].MassMatrixBlocks_B4Agglom = massMatrixBlocksB4Agglom; //var _jCell2jSub = Result[Species].jCell2jSub; //int J = ctx.Cells.NoOfLocalUpdatedCells; //foreach (var pair in Agg.GetAgglomerator(Species).AggInfo.AgglomerationPairs) { // foreach (int jCell in new int[] { pair.jCellSource, pair.jCellTarget }) { // create a backup of source and target cell // if (jCell >= J) // continue; // int jSub = _jCell2jSub[jCell]; // if (massMatrixBlocksB4Agglom[jSub] == null) { // massMatrixBlocksB4Agglom[jSub] = MassMatrixBlocksSpc.ExtractSubArrayShallow(jSub, -1, -1).CloneAs(); // } // } //} // agglomeration //Agg.GetAgglomerator(Species).ManipulateMassMatrixBlocks(MassMatrixBlocksSpc, b, Result[Species].jSub2jCell, Result[Species].jCell2jSub); //throw new NotImplementedException("todo"); } } }
/// <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]); } }
private void ComputeAverageU <T>(IEnumerable <T> U0, VectorField <XDGField> U0mean, int order, XQuadSchemeHelper qh) where T : DGField { using (FuncTrace ft = new FuncTrace()) { var CC = this.LsTrk.Regions.GetCutCellMask(); int D = this.LsTrk.GridDat.SpatialDimension; double minvol = Math.Pow(this.LsTrk.GridDat.Cells.h_minGlobal, D); //var qh = new XQuadSchemeHelper(agg); foreach (var Spc in this.LsTrk.SpeciesIdS) // loop over species... //var Spc = this.LsTrk.GetSpeciesId("B"); { // shadow fields { DGField[] U0_Spc = U0.Select(U0_d => (U0_d is XDGField) ? ((DGField)((U0_d as XDGField).GetSpeciesShadowField(Spc))) : ((DGField)U0_d)).ToArray(); var U0mean_Spc = U0mean.Select(U0mean_d => U0mean_d.GetSpeciesShadowField(Spc)).ToArray(); // normal cells: for (int d = 0; d < D; d++) { U0mean_Spc[d].AccLaidBack(1.0, U0_Spc[d], this.LsTrk.Regions.GetSpeciesMask(Spc)); } // cut cells var scheme = qh.GetVolumeQuadScheme(Spc, IntegrationDomain: this.LsTrk.Regions.GetCutCellMask()); var rule = scheme.Compile(this.LsTrk.GridDat, order); CellQuadrature.GetQuadrature(new int[] { D + 1 }, // vector components: ( avg_vel[0], ... , avg_vel[D-1], cell_volume ) this.LsTrk.GridDat, rule, delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { EvalResult.Clear(); for (int d = 0; d < D; d++) { U0_Spc[d].Evaluate(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, d)); } var Vol = EvalResult.ExtractSubArrayShallow(-1, -1, D); Vol.SetAll(1.0); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { int jCell = i + i0; double Volume = ResultsOfIntegration[i, D]; if (Math.Abs(Volume) < minvol * 1.0e-12) { // keep current value // since the volume of species 'Spc' in cell 'jCell' is 0.0, the value in this cell should have no effect } else { for (int d = 0; d < D; d++) { double IntVal = ResultsOfIntegration[i, d]; U0mean_Spc[d].SetMeanValue(jCell, IntVal / Volume); } } } }).Execute(); } #if DEBUG { var Uncut = LsTrk.Regions.GetCutCellMask().Complement(); VectorField <SinglePhaseField> U0mean_check = new VectorField <SinglePhaseField>(D, new Basis(LsTrk.GridDat, 0), SinglePhaseField.Factory); for (int d = 0; d < D; d++) { U0mean_check[d].ProjectField(1.0, U0.ElementAt(d).Evaluate, new CellQuadratureScheme(false, Uncut).AddFixedOrderRules(LsTrk.GridDat, U0.ElementAt(d).Basis.Degree + 1)); } foreach (var _Spc in this.LsTrk.SpeciesIdS) // loop over species... { for (int d = 0; d < D; d++) { U0mean_check[d].AccLaidBack(-1.0, U0mean[d].GetSpeciesShadowField(_Spc), Uncut.Intersect(LsTrk.Regions.GetSpeciesMask(_Spc))); } } double checkNorm = U0mean_check.L2Norm(); Debug.Assert(checkNorm < 1.0e-6); } #endif U0mean.ForEach(F => F.CheckForNanOrInf(true, true, true)); } }
private double[] ComputeBenchmarkQuantities() { int order = 0; if (CorrectionLsTrk.GetCachedOrders().Count > 0) { order = CorrectionLsTrk.GetCachedOrders().Max(); } else { order = 1; } var SchemeHelper = CorrectionLsTrk.GetXDGSpaceMetrics(CorrectionLsTrk.SpeciesIdS.ToArray(), order, 1).XQuadSchemeHelper; // area of bubble double area = 0.0; SpeciesId spcId = CorrectionLsTrk.SpeciesIdS[1]; var vqs = SchemeHelper.GetVolumeQuadScheme(spcId); CellQuadrature.GetQuadrature(new int[] { 1 }, CorrectionLsTrk.GridDat, vqs.Compile(CorrectionLsTrk.GridDat, order), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { EvalResult.SetAll(1.0); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { area += ResultsOfIntegration[i, 0]; } } ).Execute(); area = area.MPISum(); // surface double surface = 0.0; //CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); var surfElemVol = SchemeHelper.Get_SurfaceElement_VolumeQuadScheme(spcId); CellQuadrature.GetQuadrature(new int[] { 1 }, CorrectionLsTrk.GridDat, surfElemVol.Compile(CorrectionLsTrk.GridDat, this.m_HMForder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { EvalResult.SetAll(1.0); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { surface += ResultsOfIntegration[i, 0]; } } ).Execute(); surface = surface.MPISum(); // circularity double diamtr_c = Math.Sqrt(4 * area / Math.PI); double perimtr_b = surface; double circ = Math.PI * diamtr_c / perimtr_b; // total concentration, careful above values are "old" when CorrectionTracker is not updated, this value is always "new" double concentration = 0.0; var tqs = new CellQuadratureScheme(); CellQuadrature.GetQuadrature(new int[] { 1 }, phi.GridDat, tqs.Compile(phi.GridDat, phi.Basis.Degree * 2 + 2), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { phi.Evaluate(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { concentration += ResultsOfIntegration[i, 0]; } } ).Execute(); concentration = concentration.MPISum(); // total mixing energy double energy = 0.0; var eqs = new CellQuadratureScheme(); int D = phi.GridDat.SpatialDimension; SinglePhaseField[] PhiGrad = new SinglePhaseField[D]; for (int d = 0; d < D; d++) { PhiGrad[d] = new SinglePhaseField(phi.Basis, string.Format("G_{0}", d)); PhiGrad[d].Derivative(1.0, phi, d); } MultidimensionalArray _Phi = new MultidimensionalArray(2); MultidimensionalArray _GradPhi = new MultidimensionalArray(3); MultidimensionalArray _NormGrad = new MultidimensionalArray(2); CellQuadrature.GetQuadrature(new int[] { 1 }, phi.GridDat, eqs.Compile(phi.GridDat, phi.Basis.Degree * 2 + 2), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { int K = EvalResult.GetLength(1); // alloc buffers // ------------- if (_Phi.GetLength(0) != Length || _Phi.GetLength(1) != K) { _Phi.Allocate(Length, K); _GradPhi.Allocate(Length, K, D); _NormGrad.Allocate(Length, K); } else { _Phi.Clear(); _GradPhi.Clear(); _NormGrad.Clear(); } // chemical potential phi.Evaluate(i0, Length, QR.Nodes, _Phi.ExtractSubArrayShallow(-1, -1)); _Phi.ApplyAll(x => 0.25 / (this.Control.cahn.Pow2()) * (x.Pow2() - 1.0).Pow2()); for (int d = 0; d < D; d++) { PhiGrad[d].Evaluate(i0, Length, QR.Nodes, _GradPhi.ExtractSubArrayShallow(-1, -1, d)); } // free surface energy for (int d = 0; d < D; d++) { var GradPhi_d = _GradPhi.ExtractSubArrayShallow(-1, -1, d); _NormGrad.Multiply(1.0, GradPhi_d, GradPhi_d, 1.0, "ik", "ik", "ik"); } _NormGrad.ApplyAll(x => 0.5 * x); EvalResult.ExtractSubArrayShallow(-1, -1, 0).Acc(1.0, _Phi); EvalResult.ExtractSubArrayShallow(-1, -1, 0).Acc(1.0, _NormGrad); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { energy += ResultsOfIntegration[i, 0]; } } ).Execute(); energy = energy.MPISum(); // replace 1.96 (RB_TC2) with actual surface tension // see Yue (2004) double lambda = this.Control.cahn.Pow2() * 1.96 * surface / energy; return(new double[] { area, surface, circ, concentration, energy, lambda, this.Control.diff }); }
/// <summary> /// Calculates the Torque around the center of mass /// </summary> /// <param name="U"></param> /// <param name="P"></param> /// <param name="muA"></param> /// <param name="particleRadius"></param> /// <returns></returns> static public double GetTorque(VectorField <SinglePhaseField> U, SinglePhaseField P, LevelSetTracker LsTrk, double muA, double particleRadius) { var _LsTrk = LsTrk; int D = _LsTrk.GridDat.SpatialDimension; var UA = U.ToArray(); //if (D > 2) throw new NotImplementedException("Currently only 2D cases supported"); int RequiredOrder = U[0].Basis.Degree * 3; //if (RequiredOrder > agg.HMForder) // throw new ArgumentException(); Console.WriteLine("Torque coeff: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); ConventionalDGField pA = null; double force = new double(); pA = P; 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); 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] * particleRadius; 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] * particleRadius; result[j, k] = acc + acc2; } } }; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; //var SchemeHelper = new XQuadSchemeHelper(_LsTrk, momentFittingVariant, _LsTrk.GetSpeciesId("A")); CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, _LsTrk.Regions.GetCutCellMask()); 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) { for (int i = 0; i < Length; i++) { force += ResultsOfIntegration[i, 0]; } } ).Execute(); return(force); }
/// <summary> /// ctor. /// </summary> public NECQuadratureVolume(IGridData context, SpatialOperator DiffOp, IList <DGField> _DomainFields, IList <DGField> _ParameterFields, UnsetteledCoordinateMapping CodomainMapping, ICompositeQuadRule <QuadRule> domNrule) : base(context, DiffOp, _DomainFields, _ParameterFields, CodomainMapping) { // ----------------- // quadrature object // ----------------- m_Quad = CellQuadrature.GetQuadrature2(new int[] { CodomainMapping.NoOfCoordinatesPerCell }, context, domNrule, this.EvaluateEx, this.SaveIntegrationResults, this.AllocateBuffers); int Gamma = _DomainFields.Count; // ------------------------ // sort equation components // ------------------------ m_NonlinSources = EquationComponentArgMapping <INonlinearSource> .GetArgMapping(DiffOp, true); m_NonlinFormV = EquationComponentArgMapping <INonlinVolumeForm_V> .GetArgMapping(DiffOp, true, eq => ((eq.VolTerms & (TermActivationFlags.V | TermActivationFlags.UxV | TermActivationFlags.GradUxV)) != 0), eq => (eq is IVolumeForm ? new NonlinVolumeFormVectorizer((IVolumeForm)eq) : null)); m_NonlinFormGradV = EquationComponentArgMapping <INonlinVolumeForm_GradV> .GetArgMapping(DiffOp, true, eq => ((eq.VolTerms & (TermActivationFlags.UxGradV | TermActivationFlags.GradV | TermActivationFlags.GradUxGradV)) != 0), eq => (eq is IVolumeForm ? new NonlinVolumeFormVectorizer((IVolumeForm)eq) : null)); Debug.Assert(base.m_DomainFields.Length >= Gamma); m_ValueRequired = new bool[base.m_DomainFields.Length]; m_GradientRequired = new bool[Gamma]; // base.m_DomainFields may also contain parameter fields: for (int i = Gamma; i < base.m_DomainFields.Length; i++) { m_ValueRequired[i] = true; } this.m_NonlinFormV.DetermineReqFields(m_GradientRequired, comp => ((comp.VolTerms & (TermActivationFlags.GradUxGradV | TermActivationFlags.GradUxV)) != 0)); this.m_NonlinFormGradV.DetermineReqFields(m_GradientRequired, comp => ((comp.VolTerms & (TermActivationFlags.GradUxGradV | TermActivationFlags.GradUxV)) != 0)); this.m_NonlinFormV.DetermineReqFields(m_ValueRequired, comp => ((comp.VolTerms & (TermActivationFlags.UxGradV | TermActivationFlags.UxV)) != 0)); this.m_NonlinFormGradV.DetermineReqFields(m_ValueRequired, comp => ((comp.VolTerms & (TermActivationFlags.UxGradV | TermActivationFlags.UxV)) != 0)); this.m_NonlinSources.DetermineReqFields(m_ValueRequired, comp => true); base.m_NonlinFluxes.DetermineReqFields(m_ValueRequired, comp => true); base.m_NonlinFluxesEx.DetermineReqFields(m_ValueRequired, comp => true); // --------- // profiling // --------- var _CustomTimers = new Stopwatch[] { new Stopwatch(), new Stopwatch(), new Stopwatch(), new Stopwatch(), new Stopwatch(), new Stopwatch() }; var _CustomTimers_Names = new string[] { "Flux-Eval", "Basis-Eval", "Field-Eval", "Loops", "ParametersAndNormals", "Flux-Trafo" }; Flux_Eval = _CustomTimers[0]; Flux_Trafo = _CustomTimers[5]; Field_Eval = _CustomTimers[2]; Basis_Eval = _CustomTimers[1]; Loops = _CustomTimers[3]; ParametersAndNormals = _CustomTimers[4]; m_Quad.CustomTimers = m_Quad.CustomTimers.Cat(_CustomTimers); m_Quad.CustomTimers_Names = m_Quad.CustomTimers_Names.Cat(_CustomTimers_Names); m_Quad.CustomTimers_RootPointer = new int[_CustomTimers_Names.Length]; ArrayTools.SetAll(m_Quad.CustomTimers_RootPointer, -1); this.m_NonlinSources_watch = this.m_NonlinSources.InitStopWatches(0, m_Quad); this.m_NonlinFormV_watch = this.m_NonlinFormV.InitStopWatches(0, m_Quad); this.m_NonlinFormGradV_watch = this.m_NonlinFormGradV.InitStopWatches(0, m_Quad); base.m_NonlinFluxesWatches = base.m_NonlinFluxes.InitStopWatches(0, m_Quad); base.m_NonlinFluxesExWatches = base.m_NonlinFluxesEx.InitStopWatches(0, m_Quad); // --------------------- // alloc multidim arrays // --------------------- m_FluxValues = new MultidimensionalArray[m_CodomainBasisS.Length]; m_FluxValuesTrf = new MultidimensionalArray[m_CodomainBasisS.Length]; for (int i = 0; i < m_FluxValues.Length; i++) { if (m_NonlinFluxes[i].m_AllComponentsOfMyType.Length > 0 || m_NonlinFluxesEx[i].m_AllComponentsOfMyType.Length > 0 || m_NonlinFormGradV[i].m_AllComponentsOfMyType.Length > 0) { m_FluxValues[i] = new MultidimensionalArray(3); m_FluxValuesTrf[i] = new MultidimensionalArray(3); Basis GradBasis = base.m_CodomainBasisS[i]; if (m_MaxCodBasis_Gradient == null || m_MaxCodBasis_Gradient.Degree < GradBasis.Degree) { m_MaxCodBasis_Gradient = GradBasis; } } } m_SourceValues = new MultidimensionalArray[m_CodomainBasisS.Length]; for (int i = 0; i < m_SourceValues.Length; i++) { if (m_NonlinSources[i].m_AllComponentsOfMyType.Length > 0 || m_NonlinFormV[i].m_AllComponentsOfMyType.Length > 0) { m_SourceValues[i] = new MultidimensionalArray(2); Basis ValBasis = base.m_CodomainBasisS[i]; if (m_MaxCodBasis == null || m_MaxCodBasis.Degree < ValBasis.Degree) { m_MaxCodBasis = ValBasis; } } } m_FieldValues = new MultidimensionalArray[m_DomainFields.Length]; m_FieldGradients = new MultidimensionalArray[Gamma]; for (int i = 0; i < m_DomainFields.Length; i++) { if (m_ValueRequired[i]) { m_FieldValues[i] = new MultidimensionalArray(2); } if (i < Gamma && m_GradientRequired[i]) { m_FieldGradients[i] = new MultidimensionalArray(3); } } m_TestFuncWeighted = new MultidimensionalArray(2); m_TestFuncGradWeighted = new MultidimensionalArray(3); }
static public double[] GetParticleForces(VectorField <SinglePhaseField> U, SinglePhaseField P, LevelSetTracker LsTrk, double muA) { 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; 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()); 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(); } for (int i = 0; i < D; i++) { forces[i] = MPI.Wrappers.MPIExtensions.MPISum(forces[i]); } return(forces); }
/// <summary> /// computes derivatives in various ways and compares them against known values. /// </summary> protected override double RunSolverOneStep(int TimestepNo, double phystime, double dt) { base.EndTime = 0.0; base.NoOfTimesteps = 0; int D = this.GridData.SpatialDimension; int J = this.GridData.iLogicalCells.NoOfLocalUpdatedCells; Console.WriteLine("DerivativeTest.exe, test case #" + GRID_CASE + " ******************************"); //var Fix = this.GridData.iGeomEdges.FaceIndices; //for(int iEdge = 0; iEdge < Fix.GetLength(0); iEdge++) { // Debug.Assert(Fix[iEdge, 0] >= 0); // Debug.Assert(Fix[iEdge, 1] >= 0); //} // sealing test // ================= if (this.GridData is Foundation.Grid.Classic.GridData) { TestSealing(this.GridData); } // cell volume and edge area check, if possible // =============================================== if (this.CellVolume > 0) { double err = 0; double Treshold = 1.0e-10; for (int j = 0; j < J; j++) { err += Math.Abs(this.GridData.iLogicalCells.GetCellVolume(j) - this.CellVolume); } bool passed = (err < Treshold); m_passed = m_passed && passed; Console.WriteLine("Cell volume error: " + err + " passed? " + passed); Console.WriteLine("--------------------------------------------"); } if (this.EdgeArea > 0) { double err = 0; double Treshold = 1.0e-10; int E = this.GridData.iLogicalEdges.Count; for (int e = 0; e < E; e++) { err += Math.Abs(this.GridData.iLogicalEdges.GetEdgeArea(e) - this.EdgeArea); } bool passed = (err < Treshold); m_passed = m_passed && passed; Console.WriteLine("Edge area error: " + err + " passed? " + passed); Console.WriteLine("--------------------------------------------"); } // Orthonormality of basis in physical coords // ========================================== { Basis Bs = this.f1.Basis; int N = Bs.Length; int degQuad = this.GridData.iLogicalCells.GetInterpolationDegree(0) * D + Bs.Degree + 3; int[] jG2jL = this.GridData.iGeomCells.GeomCell2LogicalCell; // mass matrix: should be identity! MultidimensionalArray MassMatrix = MultidimensionalArray.Create(J, N, N); // compute mass matrix by quadrature. var quad = CellQuadrature.GetQuadrature(new int[] { N, N }, base.GridData, (new CellQuadratureScheme()).Compile(base.GridData, degQuad), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { NodeSet QuadNodes = QR.Nodes; MultidimensionalArray BasisVals = Bs.CellEval(QuadNodes, i0, Length); EvalResult.Multiply(1.0, BasisVals, BasisVals, 0.0, "jknm", "jkn", "jkm"); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { if (jG2jL != null) { for (int i = 0; i < Length; i++) { int jG = i + i0; MassMatrix.ExtractSubArrayShallow(jG2jL[jG], -1, -1) .Acc(1.0, ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1)); } } else { MassMatrix.SetSubArray(ResultsOfIntegration, new int[] { i0, 0, 0 }, new int[] { i0 + Length - 1, N - 1, N - 1 }); } }, cs: CoordinateSystem.Physical); quad.Execute(); // check that mass matrix is Id. int MaxErrorCell = -1; double MaxError = -1; for (int j = 0; j < J; j++) { MultidimensionalArray MassMatrix_j = MassMatrix.ExtractSubArrayShallow(j, -1, -1); MassMatrix_j.AccEye(-1.0); double Norm_j = MassMatrix_j.InfNorm(); if (Norm_j > MaxError) { MaxError = Norm_j; MaxErrorCell = j; } } bool passed = (MaxError < 1.0e-8); m_passed = m_passed && passed; Console.WriteLine("Mass Matrix, maximum error in Cell #" + MaxErrorCell + ", mass matrix error norm: " + MaxError + " passed? " + passed); } // Broken Derivatives // ================= double totalVolume = (new SubGrid(CellMask.GetFullMask(this.GridData))).Volume; for (int d = 0; d < D; d++) { // compute f1Gradient_Numerical[d].Clear(); f1Gradient_Numerical[d].Derivative(1.0, f1, d); f2Gradient_Numerical[d].Clear(); f2Gradient_Numerical[d].Derivative(1.0, f2, d); // subtract analytical var Errfield1 = f1Gradient_Numerical[d].CloneAs(); Errfield1.Acc(-1, f1Gradient_Analytical[d]); var Errfield2 = f2Gradient_Numerical[d].CloneAs(); Errfield2.Acc(-1, f2Gradient_Analytical[d]); Console.WriteLine("Broken Derivatives: "); double Treshold = 1.0e-10; if (AltRefSol) { Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold } double err1_dx = Errfield1.L2Norm() / totalVolume; bool passed = (err1_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed)); double err2_dx = Errfield2.L2Norm() / totalVolume; passed = (err2_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed)); Console.WriteLine("--------------------------------------------"); } // Flux Derivatives // ================= for (int d = 0; d < D; d++) { // compute f1Gradient_Numerical[d].Clear(); f1Gradient_Numerical[d].DerivativeByFlux(1.0, f1, d); f2Gradient_Numerical[d].Clear(); f2Gradient_Numerical[d].DerivativeByFlux(1.0, f2, d); f1Gradient_Numerical[d].CheckForNanOrInf(true, true, true); f2Gradient_Numerical[d].CheckForNanOrInf(true, true, true); // subtract analytical var Errfield1 = f1Gradient_Numerical[d].CloneAs(); Errfield1.Acc(-1, f1Gradient_Analytical[d]); var Errfield2 = f2Gradient_Numerical[d].CloneAs(); Errfield2.Acc(-1, f2Gradient_Analytical[d]); Console.WriteLine("Flux Derivatives: "); double Treshold = 1.0e-10; if (AltRefSol) { Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold } double err1_dx = Errfield1.L2Norm() / totalVolume; bool passed = (err1_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed)); double err2_dx = Errfield2.L2Norm() / totalVolume; passed = (err2_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed)); Console.WriteLine("--------------------------------------------"); } // Linear flux Derivatives // ======================= for (int d = 0; d < D; d++) { double[] korrekto = f1Gradient_Numerical[d].CoordinateVector.ToArray(); // compute DerivativeByFluxLinear(f1, f1Gradient_Numerical[d], d, f1); DerivativeByFluxLinear(f2, f2Gradient_Numerical[d], d, f2); // subtract analytical var Errfield1 = f1Gradient_Numerical[d].CloneAs(); Errfield1.Acc(-1, f1Gradient_Analytical[d]); var Errfield2 = f2Gradient_Numerical[d].CloneAs(); Errfield2.Acc(-1, f2Gradient_Analytical[d]); Console.WriteLine("Linear Flux Derivatives: "); double Treshold = 1.0e-10; if (AltRefSol) { Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold } double err1_dx = Errfield1.L2Norm() / totalVolume; bool passed = (err1_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed)); double err2_dx = Errfield2.L2Norm() / totalVolume; passed = (err2_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed)); Console.WriteLine("--------------------------------------------"); } // Laplacian, nonlinear // ==================== if (!AltRefSol) { var Laplace = (new ipLaplace()).Operator(1); Laplace.Evaluate(new DGField[] { this.f1 }, new DGField[] { this.Laplace_f1_Numerical }); Laplace.Evaluate(new DGField[] { this.f2 }, new DGField[] { this.Laplace_f2_Numerical }); double Treshold = 1.0e-8; // subtract analytical var Errfield1 = Laplace_f1_Numerical.CloneAs(); Errfield1.Acc(-1, Laplace_f1_Analytical); var Errfield2 = Laplace_f2_Numerical.CloneAs(); Errfield2.Acc(-1, Laplace_f2_Analytical); double err_Lf1 = Errfield1.L2Norm() / totalVolume; bool passed = (err_Lf1 < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| /\\f1 Numerical - /\\f1 Analytical ||_2 = {0} (nonlinear evaluation), passed? {1}", err_Lf1, passed)); double err_Lf2 = Errfield2.L2Norm() / totalVolume; passed = (err_Lf2 < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| /\\f2 Numerical - /\\f2 Analytical ||_2 = {0} (nonlinear evaluation), passed? {1}", err_Lf2, passed)); Console.WriteLine("--------------------------------------------"); } // Laplacian, linear // ==================== if (!AltRefSol) { var Laplace = (new ipLaplace()).Operator(1); var LaplaceMtx = new BlockMsrMatrix(this.f1.Mapping, this.Laplace_f1_Numerical.Mapping); var LaplaceAffine = new double[LaplaceMtx.RowPartitioning.LocalLength]; Laplace.ComputeMatrix(this.f1.Mapping, null, this.Laplace_f1_Numerical.Mapping, LaplaceMtx, LaplaceAffine, false); this.Laplace_f1_Numerical.CoordinateVector.SetV(LaplaceAffine); LaplaceMtx.SpMV(1.0, this.f1.CoordinateVector, 1.0, this.Laplace_f1_Numerical.CoordinateVector); this.Laplace_f2_Numerical.CoordinateVector.SetV(LaplaceAffine); LaplaceMtx.SpMV(1.0, this.f2.CoordinateVector, 1.0, this.Laplace_f2_Numerical.CoordinateVector); // subtract analytical var Errfield1 = Laplace_f1_Numerical.CloneAs(); Errfield1.Acc(-1, Laplace_f1_Analytical); var Errfield2 = Laplace_f2_Numerical.CloneAs(); Errfield2.Acc(-1, Laplace_f2_Analytical); double Treshold = 1.0e-8; double err_Lf1 = Errfield1.L2Norm() / totalVolume; bool passed = (err_Lf1 < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| /\\f1 Numerical - /\\f1 Analytical ||_2 = {0} (linear evaluation), passed? {1}", err_Lf1, passed)); double err_Lf2 = Errfield2.L2Norm() / totalVolume; passed = (err_Lf2 < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| /\\f2 Numerical - /\\f2 Analytical ||_2 = {0} (linear evaluation), passed? {1}", err_Lf2, passed)); // comparison of finite difference Jacobian and Operator matrix if (TestFDJacobian) { this.f1.Clear(); var FDJbuilder = Laplace.GetFDJacobianBuilder(this.f1.Mapping.Fields, null, this.f1.Mapping, delegate(IEnumerable <DGField> U0, IEnumerable <DGField> Params) { return; }); var CheckMatrix = new BlockMsrMatrix(FDJbuilder.CodomainMapping, FDJbuilder.DomainMapping); var CheckAffine = new double[FDJbuilder.CodomainMapping.LocalLength]; FDJbuilder.ComputeMatrix(CheckMatrix, CheckAffine); var ErrMatrix = LaplaceMtx.CloneAs(); var ErrAffine = LaplaceAffine.CloneAs(); ErrMatrix.Acc(-1.0, CheckMatrix); ErrAffine.AccV(-1.0, CheckAffine); double LinfMtx = ErrMatrix.InfNorm(); double L2Aff = ErrAffine.L2NormPow2().MPISum().Sqrt(); bool passed1 = (LinfMtx < 1.0e-3); bool passed2 = (L2Aff < Treshold); Console.WriteLine("Finite Difference Jacobian: Matrix/Affine delta norm {0} {1}, passed? {2} {3}", LinfMtx, L2Aff, passed1, passed2); m_passed = m_passed && passed1; m_passed = m_passed && passed2; } Console.WriteLine("--------------------------------------------"); } // finally... // ================= if (m_passed) { Console.WriteLine("All tests passed. *****************************"); } else { Console.WriteLine("Some error above threshold. *******************"); } return(0.0); // return some artificial timestep }