/// <summary> /// <see cref="Quadrature{U,V}.CreateNodeSetFamily"/> /// </summary> /// <param name="NoOfItems"></param> /// <param name="rule"></param> protected override void AllocateBuffers(int NoOfItems, NodeSet rule) { base.AllocateBuffers(NoOfItems, rule); int NoOfNodes = rule.GetLength(0); int D = m_phi.GridDat.SpatialDimension; m_gradPhi.Allocate(NoOfItems, NoOfNodes, D); }
protected override void AllocateBuffers(int NoOfItems, NodeSet rule) { base.AllocateBuffers(NoOfItems, rule); int NoOfNodes = rule.GetLength(0); if (m_func != null || m_Map != null) { m_NodesTransformed.Allocate(new int[] { NoOfItems, NoOfNodes, GridDat.SpatialDimension }); } }
/// <summary> /// Evaluates the modified integrand which is /// \f$ /// \vec{g} = g \frac{\nabla \Phi}{|\nabla \Phi|} /// \f$ /// where g represents <see cref="m_Field"/>. /// </summary> /// <param name="j0"> /// <see cref="LevelSetIntegrator.EvaluateIntegrand"/> /// </param> /// <param name="Length"> /// <see cref="LevelSetIntegrator.EvaluateIntegrand"/> /// </param> /// <param name="EvalResult"> /// <see cref="LevelSetIntegrator.EvaluateIntegrand"/> /// </param> public override void EvaluateIntegrand(NodeSet N, int j0, int Length, MultidimensionalArray EvalResult) { using (new FuncTrace()) { int D = base.m_LevSetTrk.GridDat.SpatialDimension; // spatial dimension int noOfNodes = EvalResult.GetLength(1); // number of nodes if (m_LevelSetGradientBuffer.GetLength(0) != Length || m_LevelSetGradientBuffer.GetLength(1) != noOfNodes) { m_IntegrandBuffer.Allocate(Length, noOfNodes); m_LevelSetGradientBuffer.Allocate(Length, noOfNodes, D); } m_Field.Evaluate(j0, Length, N, m_IntegrandBuffer, 0.0); m_levSet.EvaluateGradient(j0, Length, N, m_LevelSetGradientBuffer); for (int i = 0; i < Length; i++) { for (int j = 0; j < noOfNodes; j++) { double AbsGradPhi = 0; for (int d = 0; d < D; d++) { double GradPhi_d = m_LevelSetGradientBuffer[i, j, d]; AbsGradPhi += GradPhi_d * GradPhi_d; } AbsGradPhi = Math.Sqrt(AbsGradPhi); double ooAbsGradPhi = 1.0 / AbsGradPhi; for (int d = 0; d < D; d++) { EvalResult[i, j, 0, d] = ooAbsGradPhi * m_LevelSetGradientBuffer[i, j, d] * m_IntegrandBuffer[i, j]; } } } } }
/// <summary> /// Ctr /// </summary> public PlanarFourierLevSet(FourierLevSetControl Control) : base(Control) { setProjectingFourierModes(); // set the material sample points current_interfaceP = new MultidimensionalArray(2); current_interfaceP.Allocate(numFp, 2); for (int sp = 0; sp < numFp; sp++) { current_interfaceP[sp, 0] = FourierP[sp]; current_interfaceP[sp, 1] = current_samplP[sp]; } setInterfaceLength(current_interfaceP); InterfaceResolution = interfaceLength / numFp; }
protected override SayeQuadRule BuildSurfaceQuadRule(MultidimensionalArray X, double X_weight, int heightDirection, int cell) { double weight = X_weight; NodeSet node = new NodeSet(RefElement, X.To2DArray()); MultidimensionalArray gradient = lsData.GetLevelSetGradients(node, cell, 1); gradient = gradient.ExtractSubArrayShallow(new int[] { 0, 0, -1 }); MultidimensionalArray jacobian = grid.Jacobian.GetValue_Cell(node, cell, 1).ExtractSubArrayShallow(0, 0, -1, -1); //Scale weight weight *= gradient.L2Norm() / Math.Abs(gradient[heightDirection]); weight /= jacobian[heightDirection, heightDirection]; MultidimensionalArray weightArr = new MultidimensionalArray(1); weightArr.Allocate(1); weightArr[0] = weight; return(new SayeQuadRule(node, weightArr)); }
public void Evaluate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { // Del_Evaluate // ~~~~~~~~~~~~~ NodeSet NS = QR.Nodes; int NoOfNodes = NS.NoOfNodes; var BasisVal = b.CellEval(NS, i0, Length); EvalResult.ExtractSubArrayShallow(new int[] { 0, 0, 0, 0 }, new int[] { Length - 1, NoOfNodes - 1, Nnx - 1, Nnx - 1 }) .Multiply(1.0, BasisVal, BasisVal, 0.0, "ikmn", "ikm", "ikn"); if (UevalBuf == null) { UevalBuf = MultidimensionalArray.Create(Length, NoOfNodes); } if (UevalBuf.GetLength(0) < Length || UevalBuf.GetLength(1) != NoOfNodes) { UevalBuf.Allocate(Length, NoOfNodes); } MultidimensionalArray _UevalBuf; if (UevalBuf.GetLength(0) > Length) { _UevalBuf = UevalBuf.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { Length - 1, NoOfNodes - 1 }); } else { Debug.Assert(UevalBuf.GetLength(0) == Length); _UevalBuf = UevalBuf; } for (int d = 0; d < D; d++) { _UevalBuf.Clear(); Uin[d].Evaluate(i0, Length, NS, _UevalBuf); EvalResult.ExtractSubArrayShallow(new int[] { 0, 0, Nnx + d, 0 }, new int[] { Length - 1, NoOfNodes - 1, Nnx + d - 1, Nnx - 1 }) .Multiply(1.0, BasisVal, _UevalBuf, 0.0, "ikm", "ikm", "ik"); } }
/// <summary> /// /// </summary> /// <param name="ctrl"></param> public PolarFourierLevSet(FourierLevSetControl ctrl) : base(ctrl) { this.DomainSize = 2 * Math.PI; this.center = new MultidimensionalArray(2); this.center.Allocate(1, 2); this.center[0, 0] = ctrl.center[0]; this.center[0, 1] = ctrl.center[1]; this.CenterMove = ctrl.centerMove; this.LevSetForm = ctrl.PLevSetForm; this.curvComp_extended = ctrl.curvComp_extended; // set material polar coordinates interfaceP_polar = new MultidimensionalArray(2); interfaceP_polar.Allocate(numFp, 2); for (int sp = 0; sp < numFp; sp++) { interfaceP_polar[sp, 0] = FourierP[sp]; interfaceP_polar[sp, 1] = current_samplP[sp]; } setProjectingFourierModes(); // set the material sample points (cartesian) current_interfaceP = new MultidimensionalArray(2); current_interfaceP.Allocate(numFp, 2); for (int sp = 0; sp < numFp; sp++) { current_interfaceP[sp, 0] = center[0, 0] + (interfaceP_polar[sp, 1] * Math.Cos(interfaceP_polar[sp, 0])); current_interfaceP[sp, 1] = center[0, 1] + (interfaceP_polar[sp, 1] * Math.Sin(interfaceP_polar[sp, 0])); } setInterfaceLength(current_interfaceP); InterfaceResolution = interfaceLength / numFp; }
void ExtractMatrices() { // dispose old solver, if required // =============================== if (this.m_PressureSolver != null) { this.m_PressureSolver.Dispose(); this.m_PressureSolver = null; } // sub-matrices for the Potential Solver // ===================================== int VelocityLength = this.USubMatrixIdx_Row.Length; int PressureLength = this.PSubMatrixIdx_Row.Length; this.PressureGrad = new MsrMatrix(VelocityLength, PressureLength, 1, 1); this.VelocityDiv = new MsrMatrix(PressureLength, VelocityLength, 1, 1); this.Stab = new MsrMatrix(PressureLength, PressureLength, 1, 1); var WholeSystemMatrix = this.m_MgOp.OperatorMatrix; WholeSystemMatrix.WriteSubMatrixTo(PressureGrad, USubMatrixIdx_Row, default(int[]), PSubMatrixIdx_Row, default(int[])); WholeSystemMatrix.WriteSubMatrixTo(VelocityDiv, PSubMatrixIdx_Row, default(int[]), USubMatrixIdx_Row, default(int[])); WholeSystemMatrix.WriteSubMatrixTo(Stab, PSubMatrixIdx_Row, default(int[]), PSubMatrixIdx_Row, default(int[])); // inverse mass matrix // =================== if (this.m_SIMPLEOptions.PotentialSolver_UseMassMatrix) { // extract the mass-matrix block for the velocity part // --------------------------------------------------- MsrMatrix MM = new MsrMatrix(this.PressureGrad.RowPartitioning, this.VelocityDiv.ColPartition); this.m_MgOp.MassMatrix.WriteSubMatrixTo(MM, this.USubMatrixIdx_Row, default(int[]), this.USubMatrixIdx_Row, default(int[])); // invert mass matrix // ------------------ int D = this.LsTrk.GridDat.SpatialDimension; this.invMM = new MsrMatrix(MM.RowPartitioning, MM.ColPartition); MultidimensionalArray Block = new MultidimensionalArray(2); MultidimensionalArray InvBlock = new MultidimensionalArray(2); int iRow0 = MM.RowPartitioning.i0; int JAGG = this.m_MgOp.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; int[] DegreeS = this.m_MgOp.Mapping.DgDegree; for (int jagg = 0; jagg < JAGG; jagg++) // loop over aggregate cells... { for (int d = 0; d < D; d++) // loop over velocity components... { int N = this.m_MgOp.Mapping.AggBasis[d].GetLength(jagg, DegreeS[d]); if (Block.GetLength(0) != N) { Block.Allocate(N, N); InvBlock.Allocate(N, N); } for (int n = 0; n < N; n++) { CheckMatrix(MM, iRow0, N, iRow0 + n); for (int m = 0; m < N; m++) { Block[n, m] = MM[iRow0 + n, iRow0 + m]; } } Block.InvertTo(InvBlock); for (int n = 0; n < N; n++) { for (int m = 0; m < N; m++) { this.invMM[iRow0 + n, iRow0 + m] = InvBlock[n, m]; } } iRow0 += N; } } Debug.Assert(iRow0 == MM.RowPartitioning.iE); #if DEBUG var CheckMX = MM * invMM; double TRESH = Math.Max(MM.InfNorm(), invMM.InfNorm()) * 1.0e-10; for (int iRow = CheckMX.RowPartitioning.i0; iRow < CheckMX.RowPartitioning.iE; iRow++) { if (Math.Abs(CheckMX.GetDiagonalElement(iRow) - 1.0) > TRESH) { throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix"); } } #endif } }
/// <summary> /// /// </summary> /// <param name="Flds"> /// a list of <em>M</em> DG fields. /// </param> /// <param name="Points"> /// 2-dimensional: <br/> /// - 1st index: point index, from 0 (including) to <em>N</em> (excluding)<br/> /// - 2nd index: spatial dimension/direction /// </param> /// <param name="Result"> /// result of the evaluation of the DG fields <paramref name="Flds"/> at points <paramref name="Points"/>. /// - 1st index: point index, from 0 (including) to <em>N</em> (excluding) /// - 2nd index: DG field, from 0 (including) to <em>M</em> (excluding). /// the result will be accumulated. /// </param> /// <param name="UnlocatedPoints"> /// Optional, can be null; otherwise, an array of length <em>N</em>. /// On exit, in the latter case, true for every point that is not within the grid. /// </param> /// <param name="LocalCellIndices"> /// Optional, can be null; otherwise, an array of length <em>N</em>. /// On exit, in the latter case, the <em>n</em>-th entry contains the local index of the cell /// where the <em>n</em>-th point is found. /// </param> /// <param name="beta"> /// pre-scaling of <paramref name="Result"/> on entry, i.e. before accumulation /// </param> /// <param name="alpha"> /// scaling of <paramref name="Flds"/> for evaluation /// </param> /// <returns> /// the number of points that are not within the grid; /// </returns> public int Evaluate(double alpha, IEnumerable <DGField> Flds, MultidimensionalArray Points, double beta, MultidimensionalArray Result, BitArray UnlocatedPoints = null, int[] LocalCellIndices = null) { // init / check args // ================= int D = m_Context.Grid.SpatialDimension; int J = m_Context.Grid.NoOfUpdateCells; if (Points.Dimension != 2) { throw new ArgumentException("must be 2-dimensional", "Points"); } int N = Points.GetLength(0); if (Result.Dimension != 2) { throw new ArgumentException("must be 2-dimensional", "Result"); } if (Result.GetLength(0) != N) { throw new ArgumentException("mismatch in 1st dimension", "Points,Result"); } DGField[] Fields = Flds.ToArray(); int M = Fields.Length; for (int m = 0; m < M; m++) { if (!object.ReferenceEquals(this.m_Context, Fields[m].GridDat)) { throw new ArgumentException($"Mismatch in grid: field #{m} is defined on a different grid."); } } if (Result.GetLength(1) != Fields.Length) { throw new ArgumentException("2nd dimension of 'Result' and length of 'Flds' must be equal"); } if (UnlocatedPoints == null) { UnlocatedPoints = new BitArray(N, false); } else { UnlocatedPoints.SetAll(false); } if (LocalCellIndices != null) { if (LocalCellIndices.Length != N) { throw new ArgumentException("2nd dimension of 'Result' and length of 'LocalCellIndices' must be equal"); } for (int n = 0; n < N; n++) { LocalCellIndices[n] = int.MinValue; } } if (UnlocatedPoints.Length != N) { throw new ArgumentException("2nd dimension of 'Result' and length of 'UnlocatedPoints' must be equal"); } double[] pt = new double[D]; Result.Scale(beta); // build point localization // ======================== // filter points that are outside the grid bounding box int[] Perm2 = new int[N]; { int cnt = 0; var bb = CellLoc.GridBB; for (int n = 0; n < N; n++) { for (int d = 0; d < D; d++) { pt[d] = Points[n, d]; } if (!bb.Contains(pt)) { UnlocatedPoints[n] = true; } else { Perm2[cnt] = n; cnt++; } } Array.Resize(ref Perm2, cnt); } if (Perm2.Length <= 0) { UnlocatedPoints.SetAll(true); return(N); // we are done } int _cnt = 0; MultidimensionalArray pts = MultidimensionalArray.Create(Perm2.Length, D); for (int n = 0; n < N; n++) { if (!UnlocatedPoints[n]) { for (int d = 0; d < D; d++) { pts[_cnt, d] = Points[n, d]; } _cnt++; } } int NU = N - Perm2.Length; UnlocatedPoints.SetAll(true); N = Perm2.Length; int[] Perm = new int[N]; int NoOfUnassignedNodes = N; PointLocalization pl = new PointLocalization(pts, CellLoc.GridBB, Perm); pts = null; // not required anymore // localize Points / evaluate at // ============================= MultidimensionalArray vertGlobalSupect1 = new MultidimensionalArray(2); MultidimensionalArray vertGlobalSupect = new MultidimensionalArray(2); MultidimensionalArray vertLocalSuspect = new MultidimensionalArray(3); NodeSet vertLocal = null; MultidimensionalArray[] fieldVal = new MultidimensionalArray[M]; for (int m = 0; m < M; m++) { fieldVal[m] = new MultidimensionalArray(2); } //Console.WriteLine("debgcode akt."); //int[] bbsfound = new int[Points.GetLength(0)]; BoundingBox CellTreeBB = new BoundingBox(D); BoundingBox CellBB = new BoundingBox(D); // loop over cells ... for (int j = 0; j < J; j++) { // code of the cell: all bounding boxes in the tree that // share a point with the cell GeomBinTreeBranchCode bbcode; int bbBits; { BoundingBoxCode __b = CellLoc.GetCellBoundingBoxCode(j); bbcode = __b.Branch; bbBits = (int)__b.SignificantBits; CellLoc.GridBB.SubBoxFromCode(CellTreeBB, __b); } // cell bounding box is smaller than the bounding box in the tree m_Context.Cells.GetCellBoundingBox(j, CellBB); if (!CellTreeBB.Contains(CellBB)) // test { throw new ApplicationException("internal error: should not happen"); } CellBB.ExtendByFactor(0.001); // safety factor // determine all points in cell int iP0, Len; pl.GetPointsInBranch(bbcode, bbBits, out iP0, out Len); if (Len <= 0) { // no points in cell j continue; } // transform points to cell-local coordinates vertGlobalSupect1.Allocate(Len, D); double[] tempPt = new double[D]; int tempLen = 0; int[] nPts = new int[Len]; for (int n = 0; n < Len; n++) { int nPt = Perm2[Perm[n + iP0]]; if (!UnlocatedPoints[nPt]) { continue; } for (int d = 0; d < D; d++) { tempPt[d] = pl.Points[n + iP0, d]; } if (CellBB.Contains(tempPt)) { for (int d = 0; d < D; d++) { vertGlobalSupect1[tempLen, d] = tempPt[d]; } nPts[tempLen] = nPt; tempLen++; } } Len = tempLen; if (Len <= 0) { // no points in cell j continue; } vertGlobalSupect.Allocate(Len, D); vertGlobalSupect.Set(vertGlobalSupect1.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { Len - 1, D - 1 })); vertLocalSuspect.Allocate(1, Len, D); CellLoc.GrdDat.TransformGlobal2Local(vertGlobalSupect, vertLocalSuspect, j, 1, 0); // test //for (int n = 0; n < Len; n++) { // for (int d = 0; d < D; d++) // pt[d] = vertGlobalSupect[n, d]; // if (!CellBB.Contains(pt)) // Console.WriteLine("Huramnet"); //} var splx = m_Context.Cells.GetRefElement(j); // test whether the points in the bounding box of cell j // are also in cell j bool[] tatsaechlich = new bool[Len]; int Z = 0; for (int n = 0; n < Len; n++) { int nPt = nPts[n]; if (!UnlocatedPoints[nPt]) { // point was already located in/assigned to another cell continue; } for (int d = 0; d < D; d++) { pt[d] = vertGlobalSupect[n, d]; } if (!CellBB.Contains(pt)) { continue; // cell bounding box is usually smaller than the bounding box in the tree ('bbcode') } for (int d = 0; d < D; d++) { pt[d] = vertLocalSuspect[0, n, d]; } if (splx.IsWithin(pt, 1.0e-8)) { UnlocatedPoints[nPt] = false; NoOfUnassignedNodes--; if (LocalCellIndices != null) { LocalCellIndices[nPt] = j; } Z++; tatsaechlich[n] = true; } } if (Z <= 0) { // no points in bb continue; } // collect all vertices that are really in cell j vertLocal = new NodeSet(m_Context.Cells.GetRefElement(j), Z, D); int z = 0; for (int n = 0; n < Len; n++) { if (!tatsaechlich[n]) { continue; } for (int d = 0; d < D; d++) { vertLocal[z, d] = vertLocalSuspect[0, n, d]; } z++; } vertLocal.LockForever(); // evaluate Velocity Field there for (int m = 0; m < M; m++) { fieldVal[m].Allocate(1, Z); } for (int m = 0; m < M; m++) { Fields[m].Evaluate(j, 1, vertLocal, fieldVal[m]); } // store result of evaluation z = 0; for (int n = 0; n < Len; n++) { //int nPt = Perm2[Perm[n + iP0]]; int nPt = nPts[n]; if (!tatsaechlich[n]) { continue; } for (int m = 0; m < M; m++) { Result[nPt, m] += alpha * fieldVal[m][0, z]; } z++; } } // return // ====== return(NoOfUnassignedNodes + NU); }
private void ApproximationMatrix() { this.Aapprox = null; this.AapproxInverse = null; //MsrMatrix AapproxComp = null; /* * switch(m_SIMPLEOptions.Option_Approximation_Predictor) { * case ApproxPredictor.MassMatrix: * case ApproxPredictor.LocalizedOperator: { break; } * default: { * Aapprox = ConvDiff.CloneAs(); * //switch (m_SIMPLEOptions.Option_Timestepper) { * // case Timestepper.Steady: break; * // case Timestepper.ImplicitEuler: { * // Aapprox.Acc(1.0 / dt, MassMatrix); * // break; * // } * // default: { * // throw new NotImplementedException("Unknown Timestepper"); * // } * //} * AapproxComp = new MsrMatrix(USubMatrixIdx.Length, USubMatrixIdx.Length, MassMatrix.RowPartitioning.BlockSize / (2 * D), MassMatrix.ColPartition.BlockSize / (2 * D)); * Aapprox.WriteSubMatrixTo(AapproxComp, USubMatrixIdx, default(int[]), USubMatrixIdx, default(int[])); * break; * } * } */ switch (m_SIMPLEOptions.Option_Approximation_Predictor) { case ApproxPredictor.MassMatrix: { BlockMsrMatrix MM; if (!double.IsPositiveInfinity(this.m_SIMPLEOptions.dt)) { // instationary SIMPLE //MM = this.m_MgOp.MassMatrix.CloneAs(); // hier muss ich mir nochmal was überlegen -- // für einige Präkond.-Optionen // (genau jene, welche die XDG-Basen für beide Phasen in Cut-Zellen mischen), // wie etwa // MultigridOperator.Mode.SymPart_DiagBlockEquilib // ist eine Block-Skalierung mit rho_A und rho_B // inkonsistent! // throw new NotImplementedException("todo"); } else { MM = this.m_MgOp.MassMatrix; } Aapprox = new MsrMatrix(this.ConvDiff.RowPartitioning); this.m_MgOp.MassMatrix.WriteSubMatrixTo(Aapprox, this.USubMatrixIdx_Row, default(int[]), this.USubMatrixIdx_Row, default(int[])); //AapproxInverse = MassMatrixInv._ToMsrMatrix();// Aapprox.Invert(); //switch(m_SIMPLEOptions.Option_Timestepper) { // case Timestepper.Steady: break; // case Timestepper.ImplicitEuler: { // Aapprox.Scale(1 + 1.0 / dt); // AapproxInverse.Scale(1 / (1 + 1.0 / dt)); // /*#if DEBUG // var CheckMX = AapproxInverse * Aapprox; // foreach (int i in USubMatrixIdx) { // if (Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-10) throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix"); // } // #endif*/ // break; // } // default: { // throw new NotImplementedException("Unknown Timestepper"); // } //} break; } case ApproxPredictor.Exact: { if (this.LsTrk.GridDat.CellPartitioning.MpiSize > 1) { throw new NotSupportedException("Not implemented for MPI-parallel runs."); } //RowIdx = VelocityMapping.GetSubvectorIndices(this.LsTrk, D.ForLoop(d => d), _SpcIds: this.LsTrk.SpeciesIdS, drk: this.TransportAgglomerator); //ColIdx = RowIdx; if (USubMatrixIdx_Row.Length > 4500) { Console.WriteLine(string.Format("WARNING: you don't really want to invert a {0}x{0} matrix.", USubMatrixIdx_Row.Length)); } this.Aapprox = this.ConvDiff; MultidimensionalArray AapproxFull = Aapprox.ToFullMatrixOnProc0(); MultidimensionalArray AapproxInverseFull = AapproxFull.GetInverse(); this.AapproxInverse = new MsrMatrix(new Partitioning(USubMatrixIdx_Row.Length)); this.AapproxInverse.AccDenseMatrix(1.0, AapproxInverseFull); break; } case ApproxPredictor.Diagonal: { /* * Aapprox = new MsrMatrix(ConvDiff.RowPartitioning, ConvDiff.ColPartition); * AapproxInverse = new MsrMatrix(ConvDiff.RowPartitioning, ConvDiff.ColPartition); * foreach(int i in USubMatrixIdx) { * int[] j = new int[] { i }; * double Value = ConvDiff.GetValues(i, j)[0]; * //Value += MassMatrix.GetValues(i, j)[0]; * Aapprox.SetDiagonalElement(i, Value); * if(Value == 0) { * AapproxInverse.SetDiagonalElement(i, 0); * } else { * AapproxInverse.SetDiagonalElement(i, 1 / Value); * } * } #if DEBUG * Aapprox.VerifyDataStructure(); * AapproxInverse.VerifyDataStructure(); * var CheckMX = AapproxInverse * Aapprox; * foreach(int i in USubMatrixIdx) { * if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-13) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix"); * } #endif * break; */ throw new NotImplementedException("todo"); } case ApproxPredictor.BlockDiagonal: { /* * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp); * var AapproxCompInvBD = AapproxCompBD.Invert(); * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(Aapprox, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); * //#if DEBUG * Aapprox.VerifyDataStructure(); * AapproxInverse.VerifyDataStructure(); * var CheckMX = AapproxInverse * Aapprox; * foreach(int i in USubMatrixIdx) { * if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix"); * } * //#endif * * break; */ throw new NotImplementedException("todo"); } case ApproxPredictor.BlockSum: { /* * Console.WriteLine("BlockSum is not properly tested yet and did not work in previous tests"); * int AccdBlockSize = ConvDiff.RowPartitioning.BlockSize / (2 * D); * var AapproxBD = new BlockDiagonalMatrix(ConvDiff.RowPartitioning); * var Aapprox = new MsrMatrix(ConvDiff.RowPartitioning); * int[] indexer = new int[AccdBlockSize]; * for(int i = 0; i < indexer.Length; i++) { * indexer[i] = i; * } * int[] rowindexer = indexer.CloneAs(); * * * for(int i = 0; i < ConvDiff.NoOfRows / AccdBlockSize; i++) { * int[] colindexer = indexer.CloneAs(); * for(int j = 0; j < ConvDiff.NoOfCols / AccdBlockSize; j++) { * ConvDiff.AccSubMatrixTo(1.0, Aapprox, rowindexer, rowindexer, colindexer, rowindexer); * for(int r = 0; r < indexer.Length; r++) { * colindexer[r] += AccdBlockSize; * } * } * for(int r = 0; r < indexer.Length; r++) { * rowindexer[r] += AccdBlockSize; * } * } * //if (m_SIMPLEOptions.Option_Timestepper == Timestepper.ImplicitEuler) { * // Aapprox.Acc(1 / dt, MassMatrix); * //} * AapproxComp = new MsrMatrix(USubMatrixIdx.Length, USubMatrixIdx.Length, AccdBlockSize, AccdBlockSize); * Aapprox.WriteSubMatrixTo(AapproxComp, USubMatrixIdx, default(int[]), USubMatrixIdx, default(int[])); * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp); * var AapproxCompInvBD = AapproxCompBD.Invert(); * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); #if DEBUG * Aapprox.VerifyDataStructure(); * AapproxInverse.VerifyDataStructure(); * * // Check copying back and forth * var CheckAapproxComp = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * AapproxComp.WriteSubMatrixTo(CheckAapproxComp, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); * CheckAapproxComp.Acc(-1.0, Aapprox); * if(CheckAapproxComp.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix"); * * //Check Transformation to BlockdiagonalMatrix * var CheckAapproxCompBD = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(CheckAapproxCompBD, default(int[]), USubMatrixIdx, default(int[]), USubMatrixIdx); * CheckAapproxCompBD.Acc(-1.0, Aapprox); * if(CheckAapproxCompBD.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix"); * * //Check Matrix Inversion * var CheckMX = AapproxInverse * Aapprox; * foreach(int i in USubMatrixIdx) { * if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix"); * } #endif * break; */ throw new NotImplementedException("todo"); } case ApproxPredictor.Neumann: { /* * Console.WriteLine("Neumann did not work in previous Tests, Series does typically not converge"); * int serieslength = 10; * * Aapprox = ConvDiff.CloneAs(); * //if (m_SIMPLEOptions.Option_Timestepper != Timestepper.Steady) { * // Aapprox.Acc(1.0 / dt, MassMatrix); * //} * var B = Aapprox.CloneAs(); * double ScalingFactor = Aapprox.InfNorm(); * B.Scale((-1.0 / ScalingFactor.Pow(0))); //Scaling Power up to 4 tried * B.AccEyeSp(1.0); * AapproxInverse = B; * AapproxInverse.AccEyeSp(1.0); * MsrMatrix OldMoment = B; * for(int i = 0; i <= serieslength; i++) { * var NewMoment = OldMoment * B; * AapproxInverse.Acc(1.0, NewMoment); * //Debug * Console.WriteLine("MomentNumber #{0}, InfNormOf Inverse #{1}", i, NewMoment.InfNorm()); * OldMoment = NewMoment; * } * AapproxInverse.Scale((1.0 / ScalingFactor.Pow(0))); //Scaling Power up to 4 tried * break; */ throw new NotImplementedException("todo"); } case ApproxPredictor.LocalizedOperator: { /* * Console.WriteLine("Localized Operator did not work in previous Tests"); * double[] LocalizedOpAffine; * MultiphaseCellAgglomerator LocalizedAgglomerator; * Aapprox = new MsrMatrix(MassMatrix.RowPartitioning, MassMatrix.ColPartition); * TransportOpLocalized.AssembleMatrix( * out Aapprox, out LocalizedOpAffine, * out LocalizedAgglomerator, out TransportMassFact, * this.Velocity.Current, null, * this.LevSet, null, Curv, * VelocityMapping, VelocityMapping); * if(Option_Timestepper == Timestepper.ImplicitEuler) { * Aapprox.Acc(1 / dt, MassMatrix); * } * * var DiagAverage = Aapprox.GetDiagVector().Average(); * foreach(int i in RowIdx) { * if(Aapprox.GetDiagonalElement(i) == 0.0) { * //Aapprox.SetDiagonalElement(i, MassMatrix.GetDiagonalElement(i)); * Aapprox.SetDiagonalElement(i, DiagAverage); * } * } * AapproxComp = new MsrMatrix(RowIdx.Length, RowIdx.Length, MassMatrix.RowPartitioning.BlockSize / (2 * D), MassMatrix.ColPartition.BlockSize / (2 * D)); * Aapprox.WriteSubMatrixTo(AapproxComp, RowIdx, default(int[]), ColIdx, default(int[])); * AapproxInverse = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * var AapproxCompBD = new BlockDiagonalMatrix(AapproxComp); * var AapproxCompInvBD = AapproxCompBD.Invert(); * AapproxCompInvBD._ToMsrMatrix().WriteSubMatrixTo(AapproxInverse, default(int[]), RowIdx, default(int[]), ColIdx); * //AapproxComp._ToMsrMatrix().WriteSubMatrixTo(Aapprox, default(int[]), RowIdx, default(int[]), ColIdx); * * #if DEBUG * Aapprox.VerifyDataStructure(); * AapproxInverse.VerifyDataStructure(); * var CheckAapproxCompBD = new MsrMatrix(Aapprox.RowPartitioning, Aapprox.ColPartition); * AapproxCompBD._ToMsrMatrix().WriteSubMatrixTo(CheckAapproxCompBD, default(int[]), RowIdx, default(int[]), ColIdx); * CheckAapproxCompBD.Acc(-1.0, Aapprox); * if(CheckAapproxCompBD.InfNorm() > 1e-14) throw new ArithmeticException("Something went wrong while copying the Aapprox Matrix"); * var CheckMX = AapproxInverse * Aapprox; * foreach(int i in RowIdx) { * if(Math.Abs(CheckMX.GetDiagonalElement(i) - 1.0) > 1e-12) throw new ArithmeticException("AapproxInverse is not the Inverse of the Operator Matrix"); * } #endif * break; */ throw new NotImplementedException("todo"); } default: throw new NotImplementedException("todo"); } if (this.AapproxInverse == null) { // block-inversion is required. // ++++++++++++++++++++++++++++ int D = this.LsTrk.GridDat.SpatialDimension; this.AapproxInverse = new MsrMatrix(this.Aapprox.RowPartitioning, this.Aapprox.ColPartition); //int N = this.m_MgOp.Mapping.AggBasis.GetMinimalLength(this.m_MgOp.Mapping.DgDegree[0]); //Debug.Assert(this.Aapprox.RowPartitioning.LocalLength % N == 0); MultidimensionalArray Block = new MultidimensionalArray(2); MultidimensionalArray InvBlock = new MultidimensionalArray(2); int iRow0 = this.Aapprox.RowPartitioning.i0; int JAGG = this.m_MgOp.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; int[] DegreeS = this.m_MgOp.Mapping.DgDegree; for (int jagg = 0; jagg < JAGG; jagg++) // loop over aggregate cells... { for (int d = 0; d < D; d++) // loop over velocity components... { int N = this.m_MgOp.Mapping.AggBasis[d].GetLength(jagg, DegreeS[d]); if (Block.GetLength(0) != N) { Block.Allocate(N, N); InvBlock.Allocate(N, N); } for (int n = 0; n < N; n++) { #if DEBUG int iRow = iRow0 + n; { int[] Cols = null; double[] Vals = null; int LR = Aapprox.GetRow(iRow, ref Cols, ref Vals); int cMin = int.MaxValue; int cMax = int.MinValue; for (int lr = 0; lr < LR; lr++) { if (Vals[lr] != 0.0) { cMin = Math.Min(cMin, Cols[lr]); cMax = Math.Max(cMax, Cols[lr]); } } Debug.Assert(cMin >= iRow0); Debug.Assert(cMax < iRow0 + N); } #endif for (int m = 0; m < N; m++) { Block[n, m] = this.Aapprox[iRow0 + n, iRow0 + m]; } } Block.InvertTo(InvBlock); for (int n = 0; n < N; n++) { for (int m = 0; m < N; m++) { this.AapproxInverse[iRow0 + n, iRow0 + m] = InvBlock[n, m]; } } iRow0 += N; } } Debug.Assert(iRow0 == this.Aapprox.RowPartitioning.iE); } #if DEBUG var CheckMX = AapproxInverse * Aapprox; double TRESH = Math.Max(AapproxInverse.InfNorm(), Aapprox.InfNorm()) * 1.0e-10; for (int iRow = CheckMX.RowPartitioning.i0; iRow < CheckMX.RowPartitioning.iE; iRow++) { if (Math.Abs(CheckMX.GetDiagonalElement(iRow) - 1.0) > TRESH) { throw new ArithmeticException("AapproxInverse is not the Inverse of the Aapprox-Matrix"); } } #endif }
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> /// Allocates memory for <see cref="m_WeightBuffer"/>. /// </summary> protected override void AllocateBuffers(int NoOfItems, NodeSet ruleNodes) { base.AllocateBuffers(NoOfItems, ruleNodes); m_WeightBuffer.Allocate(NoOfItems, ruleNodes.GetLength(0)); }
/// <summary> /// for a cloud of points, this method finds the cells which contain the points /// </summary> /// <param name="_pts"> /// Input: a cloud of points; 1st index: point index, 2nd index: spatial dimension; /// </param> /// <param name="LocalCellIdx"> /// Output: for each point in <paramref name="_pts"/>, the the (local) index of the cell which contains the specific point /// </param> /// <param name="NoOfUnassigned"> /// on exit, the number of points which cannot be assigned to one cell /// </param> public void LocalizePointsWithinGrid <T>(MultidimensionalArray _pts, T LocalCellIdx, out int NoOfUnassigned) where T : IList <int> { using (new FuncTrace()) { // init and check // ============== NoOfUnassigned = 0; GridData grd = this.GrdDat; var CellLoc = this; var splxS = grd.Grid.RefElements; int D = grd.SpatialDimension; int N = _pts.GetLength(0); if (_pts.Dimension != 2) { throw new ArgumentException(); } if (_pts.GetLength(0) != LocalCellIdx.Count) { throw new ArgumentException(); } if (_pts.GetLength(1) != D) { throw new ArgumentException(); } var UnlocatedPoints = new BitArray(N, false); int J = grd.Cells.NoOfLocalUpdatedCells; double[] pt = new double[D]; // build point localization // ======================== // filter points that are outside the grid bounding box int[] Perm2 = new int[N]; { int cnt = 0; var bb = CellLoc.GridBB; for (int n = 0; n < N; n++) { _pts.ExtractVector(pt, 1, 0, D, n, 0); //for (int d = 0; d < D; d++) // pt[d] = Points[n, d]; if (!bb.Contains(pt)) { UnlocatedPoints[n] = true; NoOfUnassigned++; } else { Perm2[cnt] = n; cnt++; } } Array.Resize(ref Perm2, cnt); } if (Perm2.Length <= 0) { // all points are outside the bounding box of the grid ! LocalCellIdx.SetAll(int.MinValue); return; // we are done } int _cnt = 0; MultidimensionalArray pts = MultidimensionalArray.Create(Perm2.Length, D); for (int n = 0; n < N; n++) { if (!UnlocatedPoints[n]) { for (int d = 0; d < D; d++) { pts[_cnt, d] = _pts[n, d]; } _cnt++; } } int NU = N - Perm2.Length; UnlocatedPoints.SetAll(true); N = Perm2.Length; int[] Perm = new int[N]; int NoOfUnassignedNodes = N; PointLocalization pl = new PointLocalization(pts, CellLoc.GridBB, Perm); pts = null; // not required anymore // localize Points / evaluate at // ============================= MultidimensionalArray vertGlobalSupect = new MultidimensionalArray(2); MultidimensionalArray vertLocalSuspect = new MultidimensionalArray(3); BoundingBox CellTreeBB = new BoundingBox(D); BoundingBox CellBB = new BoundingBox(D); // loop over cells ... for (int j = 0; j < J; j++) { // code of the cell: all bounding boxes in the tree that // share a point with the cell GeomBinTreeBranchCode bbcode; int bbBits; { BoundingBoxCode __b = CellLoc.GetCellBoundingBoxCode(j); bbcode = __b.Branch; bbBits = (int)__b.SignificantBits; CellLoc.GridBB.SubBoxFromCode(CellTreeBB, __b); } // cell bounding box is smaller than the bounding box in the tree grd.Cells.GetCellBoundingBox(j, CellBB); if (!CellTreeBB.Contains(CellBB)) // test { throw new ApplicationException("internal error: should not happen"); } CellBB.ExtendByFactor(0.001); // safety factor // determine all points in cell int iP0, Len; pl.GetPointsInBranch(bbcode, bbBits, out iP0, out Len); if (Len <= 0) { // no points in cell j continue; } // transform points to cell-local coordinates vertGlobalSupect.Allocate(Len, D); vertLocalSuspect.Allocate(1, Len, D); for (int n = 0; n < Len; n++) { for (int d = 0; d < D; d++) { vertGlobalSupect[n, d] = pl.Points[n + iP0, d]; } } CellLoc.GrdDat.TransformGlobal2Local(vertGlobalSupect, vertLocalSuspect, j, 1, 0); var Kref = grd.Cells.GetRefElement(j); // test whether the points in the bounding box of cell j // are also in cell j for (int n = 0; n < Len; n++) { int nPt = Perm2[Perm[n + iP0]]; if (!UnlocatedPoints[nPt]) { // point was already located in/assigned to another cell continue; } for (int d = 0; d < D; d++) { pt[d] = vertGlobalSupect[n, d]; } if (!CellBB.Contains(pt)) { continue; // cell bounding box is usually smaller than the bounding box in the tree ('bbcode') } for (int d = 0; d < D; d++) { pt[d] = vertLocalSuspect[0, n, d]; } if (Kref.IsWithin(pt)) { UnlocatedPoints[nPt] = false; NoOfUnassignedNodes--; LocalCellIdx[nPt] = j; } } } // return NoOfUnassigned += NoOfUnassignedNodes; } }
/// <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); } } } }
/// <summary> /// Evaluates the divergence of the modified integrand /// \f$ /// \nabla \cdot \vec{g} = \nabla \cdot (g \frac{\nabla \Phi}{|\nabla \Phi|}) /// \f$ /// which can be expanded to /// \f$ /// \nabla \cdot \vec{g} = \nabla g \frac{\nabla \Phi}{|\nabla \Phi|} + g ( /// \frac{\Delta \Phi}{|\nabla \Phi|} /// - \frac{\nabla \Phi}{|\nabla \Phi|} \frac{H(\Phi)}{|\nabla \Phi|} \frac{\nabla \Phi}{|\nabla \Phi|}) /// \f$ /// using the chain rule. HEre, \f$ H(\Phi)\f$ /// denotes the Hessian of the level set (i.e., the second derivatives) /// </summary> /// <param name="j0"> /// <see cref="LevelSetIntegrator.EvaluateDivergenceOfIntegrand"/> /// </param> /// <param name="Length"> /// <see cref="LevelSetIntegrator.EvaluateDivergenceOfIntegrand"/> /// </param> /// <param name="EvalResult"> /// <see cref="LevelSetIntegrator.EvaluateDivergenceOfIntegrand"/> /// </param> public override void EvaluateDivergenceOfIntegrand(NodeSet nodes, int j0, int Length, MultidimensionalArray EvalResult) { using (new FuncTrace()) { int D = base.m_LevSetTrk.GridDat.SpatialDimension; // spatial dimension int noOfNodes = EvalResult.GetLength(1); // number of nodes if (m_WeighFunctionBuffer.GetLength(0) != Length || m_WeighFunctionBuffer.GetLength(1) != noOfNodes) { m_IntegrandBuffer.Allocate(Length, noOfNodes); m_IntegrandGradientBuffer.Allocate(Length, noOfNodes, D); m_WeighFunctionBuffer.Allocate(Length, noOfNodes); m_LevelSetGradientBuffer.Allocate(Length, noOfNodes, D); m_LevelSetHessianBuffer.Allocate(Length, noOfNodes, D, D); } m_Field.Evaluate(j0, Length, nodes, m_IntegrandBuffer); m_Field.EvaluateGradient(j0, Length, nodes, m_IntegrandGradientBuffer, 0, 0.0); m_levSet.EvaluateGradient(j0, Length, nodes, m_LevelSetGradientBuffer); m_levSet.EvaluateHessian(j0, Length, nodes, m_LevelSetHessianBuffer); EvaluateWeightFunction(nodes, j0, Length, m_WeighFunctionBuffer); double[] Buf = new double[D]; for (int i = 0; i < Length; i++) { for (int j = 0; j < noOfNodes; j++) { if (m_WeighFunctionBuffer[i, j] == 0.0) { continue; } double AbsGradPhi = 0.0; for (int d = 0; d < D; d++) { double GradPhi_d = m_LevelSetGradientBuffer[i, j, d]; AbsGradPhi += GradPhi_d * GradPhi_d; } AbsGradPhi = Math.Sqrt(AbsGradPhi); if (AbsGradPhi < 1e-11) { // Assume zero since gradient is nearly zero continue; } double ooAbsGradPhi = 1.0 / AbsGradPhi; double term1 = 0.0; for (int d = 0; d < D; d++) { term1 += m_IntegrandGradientBuffer[i, j, d] * m_LevelSetGradientBuffer[i, j, d]; } term1 *= ooAbsGradPhi; double term2 = 0; for (int d = 0; d < D; d++) { term2 += m_LevelSetHessianBuffer[i, j, d, d]; } term2 *= ooAbsGradPhi; double term3 = 0; { for (int d1 = 0; d1 < D; d1++) { double a = 0; for (int d2 = 0; d2 < D; d2++) { a += m_LevelSetHessianBuffer[i, j, d1, d2] * m_LevelSetGradientBuffer[i, j, d2]; } Buf[d1] = a; } for (int d = 0; d < D; d++) { term3 += Buf[d] * m_LevelSetGradientBuffer[i, j, d]; } term3 *= (ooAbsGradPhi * ooAbsGradPhi * ooAbsGradPhi); } EvalResult[i, j, 0] = term1 + m_IntegrandBuffer[i, j] * (term2 - term3); } } } }
/// <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) ); } }
/// <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> /// ctor /// </summary> /// <param name="loc"></param> /// <param name="QuadNodes"> /// quad nodes outside the grid are ignored, i.e. the integrand is assumed to be 0 /// </param> /// <param name="quadweights"> /// </param> public Integrator(CellLocalization loc, double[,] QuadNodes, double[] quadweights) { int N = QuadNodes.GetLength(0); if (N != quadweights.Length) { throw new ArgumentException("length of 0-th dimension of arrays must match."); } int D = QuadNodes.GetLength(1); if (D != loc.GridBB.D) { throw new ArgumentException("mismatch in spatial dimension."); } int J = loc.GrdDat.Cells.NoOfLocalUpdatedCells; GridData gdat = loc.GrdDat; grdDat = gdat; // filter quad nodes outside of the bounding box // ============================================= MultidimensionalArray QuadNodes2; double[] quadweights2; int[] orgindex; { double[] pt = new double[D]; BitArray inside = new BitArray(N); int Found = 0; for (int n = 0; n < N; n++) { for (int d = 0; d < D; d++) { pt[d] = QuadNodes[n, d]; } bool ins = loc.GridBB.Contains(pt); inside[n] = ins; if (ins) { Found++; } } QuadNodes2 = MultidimensionalArray.Create(Found, D); quadweights2 = new double[Found]; orgindex = new int[Found]; int cnt = 0; for (int n = 0; n < N; n++) { if (inside[n]) { for (int d = 0; d < D; d++) { QuadNodes2[cnt, d] = QuadNodes[n, d]; } quadweights2[cnt] = quadweights[cnt]; orgindex[cnt] = n; cnt++; } } QuadNodes = null; quadweights = null; N = Found; } // build tree of quad nodes // ======================== int[] Perm = new int[N]; PointLocalization qn = new PointLocalization(QuadNodes2, loc.GridBB, Perm); double[] quadwegtNew = new double[N]; int[] origindexNew = new int[N]; for (int n = 0; n < N; n++) { quadwegtNew[n] = quadweights2[Perm[n]]; origindexNew[n] = orgindex[Perm[n]]; } quadweights2 = null; // 1st index: cell index // 2nd index: quad node index within cell // 3rd index: spatial coordinate List <List <double[]> > QuadNodesPerCell = new List <List <double[]> >(); // 1st index: cell index // 2nd index: quad node index within cell List <List <double> > QuadWeightsPerCell = new List <List <double> >(); // 1st index: cell index // 2nd index: quad node index within cell List <List <int> > OrigIndexPerCell = new List <List <int> >(); for (int j = 0; j < J; j++) { QuadNodesPerCell.Add(new List <double[]>()); QuadWeightsPerCell.Add(new List <double>()); OrigIndexPerCell.Add(new List <int>()); } // try to assign the quad nodes to cells // ===================================== BitArray PointsLocatedMarker = new BitArray(N); // mark every node, that we assign to a cell with int NoOfUnassignedNodes = N; //int[] Cell4Quadnodes = new int[N]; // loop over cells ... MultidimensionalArray vertGlobal = new MultidimensionalArray(2); MultidimensionalArray vertLocal = new MultidimensionalArray(3); for (int j = 0; j < J; j++) { //if (loc.CellMaxCode[j] < Locations[0]) // continue; // skip the cell: contains none of the searched points //if (loc.CellMinCode[j] > Locations[N - 1]) // continue; // skip the cell: contains none of the searched points GeomBinTreeBranchCode bbcode; int bbBits; { BoundingBoxCode __b = loc.GetCellBoundingBoxCode(j); bbcode = __b.Branch; bbBits = (int)__b.SignificantBits; } int iP0, Len; qn.GetPointsInBranch(bbcode, bbBits, out iP0, out Len); if (Len <= 0) { continue; } vertGlobal.Allocate(Len, D); vertLocal.Allocate(1, Len, D); for (int n = 0; n < Len; n++) { for (int d = 0; d < D; d++) { vertGlobal[n, d] = qn.Points[n + iP0, d]; } } gdat.TransformGlobal2Local(vertGlobal, vertLocal, j, 1, 0); var splx = gdat.Cells.GetRefElement(j); for (int n = 0; n < Len; n++) { int nPt = n + iP0; if (PointsLocatedMarker[nPt]) { continue; } double[] pt = new double[D]; for (int d = 0; d < D; d++) { pt[d] = vertLocal[0, n, d]; } if (splx.IsWithin(pt)) { PointsLocatedMarker[nPt] = true; NoOfUnassignedNodes--; //Cell4Quadnodes[nPt] = j; QuadNodesPerCell[j].Add(pt); QuadWeightsPerCell[j].Add(quadwegtNew[nPt]); OrigIndexPerCell[j].Add(origindexNew[nPt]); } } } // record final data structures // ============================ //m_QuadNodesPerCell = new MultidimensionalArray[J]; m_QuadNodesPerCell = new NodeSet[J]; m_QuadWeightsPerCell = new double[J][]; m_OriginalQuadNodesIndex = new int[J][]; MaxNumberOfNodes = 0; for (int j = 0; j < J; j++) { List <double[]> NodesInCellj = QuadNodesPerCell[j]; m_QuadWeightsPerCell[j] = QuadWeightsPerCell[j].ToArray(); m_OriginalQuadNodesIndex[j] = OrigIndexPerCell[j].ToArray(); int NJ = NodesInCellj.Count; if (NJ > 0) { var _QuadNodesPerCell_j = new NodeSet(grdDat.Cells.GetRefElement(j), NJ, D); MaxNumberOfNodes = Math.Max(MaxNumberOfNodes, NJ); for (int nn = 0; nn < NJ; nn++) { for (int d = 0; d < D; d++) { _QuadNodesPerCell_j[nn, d] = NodesInCellj[nn][d]; } } _QuadNodesPerCell_j.LockForever(); m_QuadNodesPerCell[j] = _QuadNodesPerCell_j; } else { m_QuadNodesPerCell[j] = null; } } }