protected override void ComputeValues(NodeSet NS, int j0, int Len, MultidimensionalArray output) { MultidimensionalArray Phi = m_owner.GetLevSetValues(NS, j0, Len); MultidimensionalArray GradPhi = m_owner.GetLevelSetReferenceGradients(NS, j0, Len); MultidimensionalArray HessPhi = m_owner.GetLevelSetReferenceHessian(NS, j0, Len); MultidimensionalArray ooNormGrad = new MultidimensionalArray(2); MultidimensionalArray Laplace = new MultidimensionalArray(2); MultidimensionalArray Q = new MultidimensionalArray(3); int K = output.GetLength(1); int D = GradPhi.GetLength(2); Debug.Assert(D == this.m_owner.m_owner.GridDat.SpatialDimension); ooNormGrad.Allocate(Len, K); Laplace.Allocate(Len, K); Q.Allocate(Len, K, D); // compute the monstrous formula // ----------------------------- // norm of Gradient: for (int d = 0; d < D; d++) { var GradPhi_d = GradPhi.ExtractSubArrayShallow(-1, -1, d); ooNormGrad.Multiply(1.0, GradPhi_d, GradPhi_d, 1.0, "ik", "ik", "ik"); } ooNormGrad.ApplyAll(x => 1.0 / Math.Sqrt(x)); // laplacian of phi: for (int d = 0; d < D; d++) { var HessPhi_d_d = HessPhi.ExtractSubArrayShallow(-1, -1, d, d); Laplace.Acc(1.0, HessPhi_d_d); } // result = Laplacian(phi)/|Grad phi| output.Multiply(1.0, Laplace, ooNormGrad, 0.0, "ik", "ik", "ik"); // result = Grad(1/|Grad(phi)|) for (int d1 = 0; d1 < D; d1++) { var Qd = Q.ExtractSubArrayShallow(-1, -1, d1); for (int d2 = 0; d2 < D; d2++) { var Grad_d2 = GradPhi.ExtractSubArrayShallow(-1, -1, d2); var Hess_d2_d1 = HessPhi.ExtractSubArrayShallow(-1, -1, d2, d1); Qd.Multiply(-1.0, Grad_d2, Hess_d2_d1, 1.0, "ik", "ik", "ik"); } } ooNormGrad.ApplyAll(x => x * x * x); output.Multiply(1.0, GradPhi, Q, ooNormGrad, 1.0, "ik", "ikd", "ikd", "ik"); }
/// <summary> /// Constructs a new flux builder. /// </summary> /// <param name="control"></param> /// <param name="boundaryMap"></param> /// <param name="speciesMap"></param> /// <param name="gridData"></param> public OptimizedSIPGFluxBuilder(CNSControl control, IBoundaryConditionMap boundaryMap, ISpeciesMap speciesMap, GridData gridData) : base(control, boundaryMap, speciesMap) { this.gridData = gridData; //Create Functions for calculation the cell metric, needed as Func<> because //LevelSet field and HMF options are not known at this point if (speciesMap is IBM.ImmersedSpeciesMap) { // IBM case ImmersedSpeciesMap IBMspeciesMap = speciesMap as ImmersedSpeciesMap; cellMetricFunc = delegate() { SpeciesId species = IBMspeciesMap.Tracker.GetSpeciesId(IBMspeciesMap.Control.FluidSpeciesName); MultidimensionalArray cellMetric = IBMspeciesMap.CellAgglomeration.CellLengthScales[species].CloneAs(); cellMetric.ApplyAll(x => 1 / x); // Needed, because 1/x produces NaN in void cells and can happen that penalty factor leads then to NaN cellMetric.ApplyAll(delegate(double x) { if (double.IsNaN(x) || double.IsInfinity(x)) { return(0); } else { return(x); } }); return(cellMetric); }; } else { // Non-IBM cellMetricFunc = () => gridData.Cells.cj; } }
internal void Tf(int j0, int Len, NodeSet N, MultidimensionalArray result) { f(j0, Len, N, result); Debug.Assert(Len == result.GetLength(0)); Debug.Assert(result.Dimension == 2); result.ApplyAll(this.T); }
/// <summary> /// First order approximation of delta >= sup_x|psi(x) - psi(x_center)| /// </summary> /// <param name="Arg"></param> /// <param name="psi"></param> /// <param name="x_center"></param> /// <param name="cell"></param> /// <returns></returns> protected override double EvaluateBounds(LinearSayeSpace <Cube> Arg, LinearPSI <Cube> psi, NodeSet x_center, int cell) { double[] arr = new double[RefElement.SpatialDimension]; Arg.Diameters.CopyTo(arr, 0); psi.SetInactiveDimsToZero(arr); MultidimensionalArray diameters = MultidimensionalArray.CreateWrapper(arr, 3); NodeSet nodeOnPsi = psi.ProjectOnto(x_center); MultidimensionalArray grad = ReferenceGradient(nodeOnPsi, cell); grad.ApplyAll(x => Math.Abs(x)); double delta = grad.InnerProduct(diameters); return(delta); }
protected override bool HeightDirectionIsSuitable(SayeSquare arg, LinearPSI <Square> psi, NodeSet x_center, int heightDirection, MultidimensionalArray gradient, int cell) { //Determine bounds //----------------------------------------------------------------------------------------------------------------- double[] arr = arg.Diameters; psi.SetInactiveDimsToZero(arr); MultidimensionalArray diameters = MultidimensionalArray.CreateWrapper(arr, new int[] { 2, 1 }); NodeSet nodeOnPsi = psi.ProjectOnto(x_center); MultidimensionalArray hessian = lsData.GetLevelSetReferenceHessian(nodeOnPsi, cell, 1); hessian = hessian.ExtractSubArrayShallow(new int[] { 0, 0, -1, -1 }); MultidimensionalArray jacobian = grid.InverseJacobian.GetValue_Cell(nodeOnPsi, cell, 1); jacobian = jacobian.ExtractSubArrayShallow(new int[] { 0, 0, -1, -1 }); hessian = jacobian * hessian; hessian.ApplyAll(x => Math.Abs(x)); //abs(Hessian) * diameters = delta MultidimensionalArray delta = hessian * diameters; delta = delta.ExtractSubArrayShallow(new int[] { -1, 0 }); //Check if suitable //----------------------------------------------------------------------------------------------------------------- //|gk| > δk if (Math.Abs(gradient[heightDirection]) > delta[heightDirection]) { bool suitable = true; // Sum_j( g_j + delta_j)^2 / (g_k - delta_k)^2 < 20 double sum = 0; for (int j = 0; j < delta.Length; ++j) { sum += Math.Pow(gradient[j] + delta[j], 2); } sum /= Math.Pow(gradient[heightDirection] - delta[heightDirection], 2); suitable &= sum < 20; return(suitable); } return(false); }
/// <summary> /// First order approximation of delta >= sup_x|psi(x) - psi(x_center)| /// </summary> /// <param name="Arg"></param> /// <param name="psi"></param> /// <param name="x_center"></param> /// <param name="cell"></param> /// <returns></returns> protected override double EvaluateBounds(SayeSquare Arg, LinearPSI <Square> psi, NodeSet x_center, int cell) { double[] arr = new double[Arg.Dimension]; Arg.Diameters.CopyTo(arr, 0); psi.SetInactiveDimsToZero(arr); MultidimensionalArray diameters = MultidimensionalArray.CreateWrapper(arr, new int[] { 2 }); NodeSet nodeOnPsi = psi.ProjectOnto(x_center); MultidimensionalArray grad = ScaledReferenceGradient(nodeOnPsi, cell); grad.ApplyAll(x => Math.Abs(x)); double delta = grad.InnerProduct(diameters) * sqrt_2; return(delta); }
/// <summary> /// curvature computation according to Bonnet's formula /// Copy-Paste from <see cref="LevelSet.EvaluatetotalCurvature"/>, since there is no analytic formula for the curvature of an ellipse /// </summary> public void EvaluateTotalCurvature(int j0, int Len, NodeSet NodeSet, MultidimensionalArray result) { // (siehe FK, persoenliche Notizen, 08mar13) // checks // ------ int K = NodeSet.NoOfNodes; if (result.Dimension != 2) { throw new ArgumentException(); } if (result.GetLength(0) != Len) { throw new ArgumentException(); } if (result.GetLength(1) != K) { throw new ArgumentException(); } int D = NodeSet.SpatialDimension; //Debug.Assert(D == this.GridDat.SpatialDimension); // buffers: // -------- //MultidimensionalArray Phi = new MultidimensionalArray(2); MultidimensionalArray GradPhi = new MultidimensionalArray(3); MultidimensionalArray HessPhi = new MultidimensionalArray(4); MultidimensionalArray ooNormGrad = new MultidimensionalArray(2); MultidimensionalArray Laplace = new MultidimensionalArray(2); MultidimensionalArray Q = new MultidimensionalArray(3); //Phi.Allocate(Len, K); GradPhi.Allocate(Len, K, D); HessPhi.Allocate(Len, K, D, D); ooNormGrad.Allocate(Len, K); Laplace.Allocate(Len, K); Q.Allocate(Len, K, D); // derivatives // ----------- // evaluate gradient this.EvaluateGradient(j0, Len, NodeSet, GradPhi); // evaluate Hessian this.EvaluateHessian(j0, Len, NodeSet, HessPhi); // compute the monstrous formula // ----------------------------- // norm of Gradient: for (int d = 0; d < D; d++) { var GradPhi_d = GradPhi.ExtractSubArrayShallow(-1, -1, d); ooNormGrad.Multiply(1.0, GradPhi_d, GradPhi_d, 1.0, "ik", "ik", "ik"); } ooNormGrad.ApplyAll(x => 1.0 / Math.Sqrt(x)); // laplacian of phi: for (int d = 0; d < D; d++) { var HessPhi_d_d = HessPhi.ExtractSubArrayShallow(-1, -1, d, d); Laplace.Acc(1.0, HessPhi_d_d); } // result = Laplacian(phi)/|Grad phi| result.Multiply(1.0, Laplace, ooNormGrad, 0.0, "ik", "ik", "ik"); // result += Grad(1/|Grad(phi)|) for (int d1 = 0; d1 < D; d1++) { var Qd = Q.ExtractSubArrayShallow(-1, -1, d1); for (int d2 = 0; d2 < D; d2++) { var Grad_d2 = GradPhi.ExtractSubArrayShallow(-1, -1, d2); var Hess_d2_d1 = HessPhi.ExtractSubArrayShallow(-1, -1, d2, d1); Qd.Multiply(-1.0, Grad_d2, Hess_d2_d1, 1.0, "ik", "ik", "ik"); } } ooNormGrad.ApplyAll(x => x * x * x); result.Multiply(1.0, GradPhi, Q, ooNormGrad, 1.0, "ik", "ikd", "ikd", "ik"); }
/// <summary> /// Computation of mean curvature according to Bonnet's formula. /// </summary> /// <param name="scale"></param> /// <param name="Output"> /// output. /// </param> /// <param name="quadScheme"></param> /// <param name="UseCenDiffUpTo"> /// Either 0, 1, or 2: /// If 0, all derivatives are computed locally (broken derivative); /// if 1, the first order derivatives are computed by central /// differences, while the second order ones are computed locally, /// based on the first order ones; /// if 2, all derivatives are computed by central differences. /// </param> /// <param name="_1stDerivDegree"> /// Relative DG polynomial degree for the 1st order derivatives, i.e. /// degree is <paramref name="_1stDerivDegree"/>+<em>p</em>, where /// <em>p</em> is the degree of this field. /// Only active if <paramref name="UseCenDiffUpTo"/> is greater than 0. /// </param> /// <param name="_2ndDerivDegree"> /// Relative DG polynomial degree for the 2nd order derivatives, i.e. /// degree is <paramref name="_2ndDerivDegree"/>+<em>p</em>, where /// <em>p</em> is the degree of this field. Only active if /// <paramref name="UseCenDiffUpTo"/> is greater than 1. /// </param> /// <remarks> /// using central differences causes memory allocation: <em>D</em> /// fields for <paramref name="UseCenDiffUpTo"/>=1, and /// <em>D</em>*(<em>D</em>+1) for <paramref name="UseCenDiffUpTo"/>=2, /// where <em>D</em> notates the spatial dimension. /// </remarks> public void ProjectTotalcurvature2( double scale, SinglePhaseField Output, int UseCenDiffUpTo, int _1stDerivDegree = 0, int _2ndDerivDegree = 0, CellQuadratureScheme quadScheme = null) { using (new FuncTrace()) { if (UseCenDiffUpTo < 0 || UseCenDiffUpTo > 2) { throw new ArgumentOutOfRangeException(); } //int M = Output.Basis.Length; //int N = this.Basis.Length; int D = this.GridDat.SpatialDimension; //var NSC = m_context.NSC; SubGrid sgrd = null; SpatialOperator.SubGridBoundaryModes bndMode = SpatialOperator.SubGridBoundaryModes.InnerEdge; if (UseCenDiffUpTo >= 1 && quadScheme != null && quadScheme.Domain != null) { sgrd = new SubGrid(quadScheme.Domain); bndMode = SpatialOperator.SubGridBoundaryModes.OpenBoundary; } // compute 1st order derivatives by central differences, if desired // ================================================================ Basis B2 = new Basis(this.GridDat, this.Basis.Degree + _1stDerivDegree); SinglePhaseField[] GradientVector = null; if (UseCenDiffUpTo >= 1) { GradientVector = new SinglePhaseField[D]; for (int d = 0; d < D; d++) { GradientVector[d] = new SinglePhaseField(B2); GradientVector[d].DerivativeByFlux(1.0, this, d, sgrd, bndMode); } } // compute 2nd order derivatives by central differences, if desired // =============================================================== Basis B3 = new Basis(this.GridDat, this.Basis.Degree + _2ndDerivDegree); SinglePhaseField[,] HessianTensor = null; if (UseCenDiffUpTo >= 2) { HessianTensor = new SinglePhaseField[D, D]; for (int d1 = 0; d1 < D; d1++) { for (int d2 = 0; d2 < D; d2++) { HessianTensor[d1, d2] = new SinglePhaseField(B3); HessianTensor[d1, d2].DerivativeByFlux(1.0, GradientVector[d1], d2, sgrd, bndMode); } } } // compute and project // =================== // buffers: MultidimensionalArray Phi = new MultidimensionalArray(2); MultidimensionalArray GradPhi = new MultidimensionalArray(3); MultidimensionalArray HessPhi = new MultidimensionalArray(4); MultidimensionalArray ooNormGrad = new MultidimensionalArray(2); MultidimensionalArray Laplace = new MultidimensionalArray(2); MultidimensionalArray Q = new MultidimensionalArray(3); // evaluate/project: //double Erracc = 0; Output.ProjectField(scale, (ScalarFunctionEx) delegate(int j0, int Len, NodeSet NodeSet, MultidimensionalArray result) { // ScalarFunction2 Debug.Assert(result.Dimension == 2); Debug.Assert(Len == result.GetLength(0)); int K = result.GetLength(1); // number of nodes // alloc buffers // ------------- if (Phi.GetLength(0) != Len || Phi.GetLength(1) != K) { Phi.Allocate(Len, K); GradPhi.Allocate(Len, K, D); HessPhi.Allocate(Len, K, D, D); ooNormGrad.Allocate(Len, K); Laplace.Allocate(Len, K); Q.Allocate(Len, K, D); } else { Phi.Clear(); GradPhi.Clear(); HessPhi.Clear(); ooNormGrad.Clear(); Laplace.Clear(); Q.Clear(); } // evaluate Gradient and Hessian // ----------------------------- if (UseCenDiffUpTo >= 1) { for (int d = 0; d < D; d++) { GradientVector[d].Evaluate(j0, Len, NodeSet, GradPhi.ExtractSubArrayShallow(-1, -1, d)); } } else { this.EvaluateGradient(j0, Len, NodeSet, GradPhi); } if (UseCenDiffUpTo == 2) { for (int d1 = 0; d1 < D; d1++) { for (int d2 = 0; d2 < D; d2++) { HessianTensor[d1, d2].Evaluate(j0, Len, NodeSet, HessPhi.ExtractSubArrayShallow(-1, -1, d1, d2)); } } } else if (UseCenDiffUpTo == 1) { for (int d = 0; d < D; d++) { var GradientVector_d = GradientVector[d]; GradientVector_d.EvaluateGradient(j0, Len, NodeSet, HessPhi.ExtractSubArrayShallow(-1, -1, d, -1), 0, 0.0); } } else if (UseCenDiffUpTo == 0) { this.EvaluateHessian(j0, Len, NodeSet, HessPhi); } else { Debug.Assert(false); } // compute the monstrous formula // ----------------------------- // norm of Gradient: for (int d = 0; d < D; d++) { var GradPhi_d = GradPhi.ExtractSubArrayShallow(-1, -1, d); ooNormGrad.Multiply(1.0, GradPhi_d, GradPhi_d, 1.0, "ik", "ik", "ik"); } ooNormGrad.ApplyAll(x => 1.0 / Math.Sqrt(x)); // laplacian of phi: for (int d = 0; d < D; d++) { var HessPhi_d_d = HessPhi.ExtractSubArrayShallow(-1, -1, d, d); Laplace.Acc(1.0, HessPhi_d_d); } // result = Laplacian(phi)/|Grad phi| result.Multiply(1.0, Laplace, ooNormGrad, 0.0, "ik", "ik", "ik"); // result = Grad(1/|Grad(phi)|) for (int d1 = 0; d1 < D; d1++) { var Qd = Q.ExtractSubArrayShallow(-1, -1, d1); for (int d2 = 0; d2 < D; d2++) { var Grad_d2 = GradPhi.ExtractSubArrayShallow(-1, -1, d2); var Hess_d2_d1 = HessPhi.ExtractSubArrayShallow(-1, -1, d2, d1); Qd.Multiply(-1.0, Grad_d2, Hess_d2_d1, 1.0, "ik", "ik", "ik"); } } ooNormGrad.ApplyAll(x => x * x * x); result.Multiply(1.0, GradPhi, Q, ooNormGrad, 1.0, "ik", "ikd", "ikd", "ik"); //for (int i = 0; i < Len; i++) { // for (int k = 0; k < K; k++) { // double acc = 0; // for (int d = 0; d < D; d++) { // acc += GradPhi[i,k,d]*Q[i,k,d]*ooNormGrad[i,k]; // } // Erracc += (acc - result[i,k]).Abs(); // } //} }, quadScheme.SaveCompile(this.GridDat, (Output.Basis.Degree + this.m_Basis.Degree * (this.m_Basis.Degree - 1) * D) * 2) ); } }
public void WriteTrendToTable(bool ErrorOrResidual, bool SepPoly, bool SepLev, out string[] Titels, out MultidimensionalArray ConvTrendData) { Dictionary <Tuple <int, int, int>, List <double> > data = ErrorOrResidual ? ErrNormTrend : ResNormTrend; List <string> titleS = new List <string>(); int iCol = 0; Dictionary <Tuple <int, int, int>, int> ColumnIndex = new Dictionary <Tuple <int, int, int>, int>(); foreach (var kv in data) { int iLevel = kv.Key.Item1; int pDG = kv.Key.Item3; int iVar = kv.Key.Item2; string title; if (SepPoly == false && SepLev == false) { title = string.Format("(var#{0})", iVar); } else if (SepPoly == false && SepLev == true) { title = string.Format("(var#{0},mg.lev.{1})", iVar, iLevel); } else if (SepPoly == true && SepLev == false) { title = string.Format("(var#{0},p={2})", iVar, pDG); } else if (SepPoly == true && SepLev == true) { title = string.Format("(var#{0},mg.lev.{1},p={2})", iVar, iLevel, pDG); } else { throw new ApplicationException(); } int iColKv = titleS.IndexOf(title); if (iColKv < 0) { titleS.Add(title); iColKv = iCol; iCol++; } ColumnIndex.Add(kv.Key, iColKv); } Titels = titleS.ToArray(); ConvTrendData = MultidimensionalArray.Create(data.First().Value.Count, titleS.Count); foreach (var kv in data) { double[] Column = kv.Value.ToArray(); for (int l = 0; l < Column.Length; l++) { Column[l] = Column[l].Pow2(); } if (ConvTrendData.GetLength(0) != Column.Length) { throw new ApplicationException(); } int iColkv = ColumnIndex[kv.Key]; ConvTrendData.ExtractSubArrayShallow(-1, iColkv).AccVector(1.0, Column); } ConvTrendData.ApplyAll(x => Math.Sqrt(x)); }
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> /// provides data collected during a solver run in tabular form /// </summary> /// <param name="ErrorOrResidual"> /// - true: output is error against exact solution (if provided) during each iteration /// - false: output is residual against exact solution (if provided) during each iteration /// </param> /// <param name="SepVars"> /// - true: separate column for each variable /// - false: l2-norm over all variables /// </param> /// <param name="SepPoly"> /// - true: separate column for each polynomial degree /// - false: l2-norm over all polynomial degrees /// </param> /// <param name="SepLev"> /// - true: separate column for each multi-grid level /// - false: l2-norm over all multi-grid levels /// </param> /// <param name="Titels"> /// Column names/titles /// </param> /// <param name="ConvTrendData"> /// data table: /// - columns: correspond to <paramref name="Titels"/> /// - rows: solver iterations /// </param> public void WriteTrendToTable(bool ErrorOrResidual, bool SepVars, bool SepPoly, bool SepLev, out string[] Titels, out MultidimensionalArray ConvTrendData) { var data = ErrorOrResidual ? ErrNormTrend : ResNormTrend; List <string> titleS = new List <string>(); int iCol = 0; Dictionary <(int MGlevel, int iVar, int deg), int> ColumnIndex = new Dictionary <(int, int, int), int>(); foreach (var kv in data) { int iLevel = kv.Key.Item1; int pDG = kv.Key.Item3; int iVar = kv.Key.Item2; string title; { if (SepVars) { title = $"Var{iVar}"; } else { title = ""; } if (SepLev) { if (title.Length > 0) { title = title + ","; } title = title + $"Mglv{iLevel}"; } if (SepPoly) { if (title.Length > 0) { title = title + ","; } title = title + $"p={pDG}"; } if (title.Length > 0) { title = "_" + title; } if (ErrorOrResidual) { title = "Err" + title; } else { title = "Res" + title; } } /* * if (SepPoly == false && SepLev == false) { * title = string.Format("(var#{0})", iVar); * } else if (SepPoly == false && SepLev == true) { * title = string.Format("(var#{0},mg.lev.{1})", iVar, iLevel); * } else if (SepPoly == true && SepLev == false) { * title = string.Format("(var#{0},p={1})", iVar, pDG); * } else if (SepPoly == true && SepLev == true) { * title = string.Format("(var#{0},mg.lev.{1},p={2})", iVar, iLevel, pDG); * } else { * throw new ApplicationException(); * } */ int iColKv = titleS.IndexOf(title); if (iColKv < 0) { titleS.Add(title); iColKv = iCol; iCol++; } ColumnIndex.Add(kv.Key, iColKv); } Titels = titleS.ToArray(); ConvTrendData = MultidimensionalArray.Create(data.First().Value.Count, titleS.Count); foreach (var kv in data) // over all data columns { double[] ColumnSquared = kv.Value.Select(val => val.Pow2()).ToArray(); if (ConvTrendData.GetLength(0) != ColumnSquared.Length) { throw new ApplicationException(); } int iColkv = ColumnIndex[kv.Key]; // output column index in which we sum up the column ConvTrendData.ExtractSubArrayShallow(-1, iColkv).AccVector(1.0, ColumnSquared); } ConvTrendData.ApplyAll(x => Math.Sqrt(x)); }
protected override bool HeightDirectionIsSuitable( LinearSayeSpace <Cube> arg, LinearPSI <Cube> psi, NodeSet x_center, int heightDirection, MultidimensionalArray agradient, int cell) { //throw new NotImplementedException(); //Determine bounds //----------------------------------------------------------------------------------------------------------------- NodeSet nodeOnPsi = psi.ProjectOnto(x_center); MultidimensionalArray jacobian = grid.Jacobian.GetValue_Cell(nodeOnPsi, cell, 1); jacobian = jacobian.ExtractSubArrayShallow(new int[] { 0, 0, -1, -1 }); LevelSet levelSet = lsData.LevelSet as LevelSet; MultidimensionalArray hessian = MultidimensionalArray.Create(1, 1, 3, 3); levelSet.EvaluateHessian(cell, 1, nodeOnPsi, hessian); hessian = hessian.ExtractSubArrayShallow(new int[] { 0, 0, -1, -1 }).CloneAs(); //hessian = jacobian * hessian; hessian.ApplyAll(x => Math.Abs(x)); MultidimensionalArray gradient = lsData.GetLevelSetGradients(nodeOnPsi, cell, 1); gradient = gradient.ExtractSubArrayShallow(0, 0, -1).CloneAs(); //abs(Hessian) * 0,5 * diameters.^2 = delta ,( square each entry of diameters) , //this bounds the second error term from taylor series //+ + + + double[] arr = arg.Diameters.CloneAs(); psi.SetInactiveDimsToZero(arr); MultidimensionalArray diameters = MultidimensionalArray.CreateWrapper(arr, 3, 1); diameters = jacobian * diameters; diameters.ApplyAll(x => 0.5 * x * x); MultidimensionalArray delta = hessian * diameters; delta = delta.ExtractSubArrayShallow(-1, 0); //Check if suitable //----------------------------------------------------------------------------------------------------------------- //|gk| > δk //Gradient should be able to turn arround psi.SetInactiveDimsToZero(gradient.Storage); if (Math.Abs(gradient[heightDirection]) > delta[heightDirection]) { bool suitable = true; // ||Grad + maxChange|| should be smaller than 20 * // Sum_j( g_j + delta_j)^2 / (g_k - delta_k)^2 < 20 double sum = 0; for (int j = 0; j < delta.Length; ++j) { sum += Math.Pow(Math.Abs(gradient[j]) + delta[j], 2); } sum /= Math.Pow(Math.Abs(gradient[heightDirection]) - delta[heightDirection], 2); suitable &= sum < 20; return(suitable); } return(false); }