/// <summary> /// evaluation of DG field; may be used in derived classes to implement <see cref="DGField.Evaluate(int,int,NodeSet,MultidimensionalArray,int,double)"/>. /// </summary> protected static void EvaluateInternal(int j0, int L, NodeSet NS, Basis basis, MultidimensionalArray Coördinates, int coördOffset, MultidimensionalArray ResultAcc, double ResultPreScale) { int D, N, NumNodes; bool AffineLinear; CheckArgs(j0, L, NS, basis, Coördinates, ResultAcc, out D, out N, out NumNodes, out AffineLinear); Debug.Assert(ResultAcc.Dimension == 2); Debug.Assert(L == ResultAcc.GetLength(0)); Debug.Assert(NumNodes == ResultAcc.GetLength(1)); /* * MultidimensionalArray BasisValues; * BasisValues = basis.CellEval(NS, j0, L); * Debug.Assert(BasisValues.GetLength(0) == L, "No. of. cells mismatch"); * Debug.Assert(BasisValues.GetLength(1) == M, "No. of. nodes mismatch"); * Debug.Assert(BasisValues.GetLength(2) == N, "No. of. basis elements mismatch"); * * ResultAcc.Multiply(1.0, Coördinates, BasisValues, ResultPreScale, "jm", "jn", "jmn"); */ //int[] geom2log = basis.GridDat.iGeomCells.GeomCell2LogicalCell; MultidimensionalArray BasisValues = basis.Evaluate(NS); if (L == 1 && AffineLinear) { // Special optimization for single-cell evaluation: // this happens very often for edge quadrature, so it is quite relevant. double scale0 = basis.GridDat.ChefBasis.Scaling[j0]; Debug.Assert(basis.GridDat.iGeomCells.GeomCell2LogicalCell == null || basis.GridDat.iGeomCells.GeomCell2LogicalCell[j0] == j0); MultidimensionalArray Coördinates_j; if (coördOffset == 0 && Coördinates.GetLength(0) == 1) { Coördinates_j = Coördinates; } else { Coördinates_j = Coördinates.ExtractSubArrayShallow(new int[] { coördOffset, 0 }, new int[] { coördOffset, N - 1 }); } ResultAcc.Multiply(scale0, Coördinates_j, BasisValues, ResultPreScale, ref mp_jk_jm_km); //"jk", "jm", "km"); } else { int iBuf; MultidimensionalArray trfCoördinates = TempBuffer.GetTempMultidimensionalarray(out iBuf, L, N); TransformCoördinates(j0, L, basis, Coördinates, coördOffset, N, AffineLinear, trfCoördinates); if (ResultAcc.IsContinious && trfCoördinates.IsContinious && BasisValues.IsContinious) { unsafe { fixed(double *_pResultAcc = ResultAcc.Storage, _ptrfCoördinates = trfCoördinates.Storage, _pBasisValues = BasisValues.Storage) { double *pResultAcc = _pResultAcc + ResultAcc.Index(0, 0); double *ptrfCoördinates = _ptrfCoördinates + trfCoördinates.Index(0, 0); double *pBasisValues = _pBasisValues + BasisValues.Index(0, 0); //#if DEBUG // MultidimensionalArray check = ResultAcc.CloneAs(); //#endif int _M = ResultAcc.GetLength(1); // entspricht k (node index) int _N = ResultAcc.GetLength(0); // entspricht j (cell index) int _K = BasisValues.GetLength(1); // entspricht m (DG mode index) // NOTE: dimensions in FORTRAN order: // pBasisValues : _K x _M // ptrfCoördinates : _K x _N // pResultAcc : _M x _N // // => FORTRAN GEMM // pResultAcc = pBasisValues^T * ptrfCoördinates int TRANSA = 'T'; int TRANSB = 'N'; BLAS.dgemm(TRANSA, TRANSB, _M, _N, _K, 1.0, pBasisValues, _K, ptrfCoördinates, _K, ResultPreScale, pResultAcc, _M); //#if DEBUG // check.Multiply(1.0, trfCoördinates, BasisValues, ResultPreScale, ref mp_jk_jm_km); // check.Acc(-1.0, ResultAcc); // double error = check.L2Norm(); // Console.WriteLine("GEMM error: " + error); // Debug.Assert(error < 1.0); //#endif } } } else { ResultAcc.Multiply(1.0, trfCoördinates, BasisValues, ResultPreScale, ref mp_jk_jm_km); //"jk", "jm", "km"); } TempBuffer.FreeTempBuffer(iBuf); } }
protected static void EvaluateEdgeInternal(int e0, int Len, NodeSet NS, Basis _Basis, MultidimensionalArray Coord, MultidimensionalArray valIN, MultidimensionalArray valOT, MultidimensionalArray meanValIN, MultidimensionalArray meanValOT, MultidimensionalArray gradIN, MultidimensionalArray gradOT, double ResultPreScale) { // checks and init // =============== var grd = _Basis.GridDat; int NoOfNodes = NS.NoOfNodes; bool AffineLinear = grd.iGeomEdges.IsEdgeAffineLinear(e0); Debug.Assert(NS.GetNodeCoordinateSystem(grd) == NodeCoordinateSystem.EdgeCoord); Debug.Assert(valIN == null || valIN.Dimension == 2); Debug.Assert(valOT == null || valOT.Dimension == 2); Debug.Assert(valIN == null || valIN.GetLength(0) == Len); Debug.Assert(valOT == null || valOT.GetLength(0) == Len); Debug.Assert(valIN == null || valIN.GetLength(1) == NoOfNodes); Debug.Assert(valOT == null || valOT.GetLength(1) == NoOfNodes); int[,] trfIdx = grd.iGeomEdges.Edge2CellTrafoIndex; int[,] E2Cl = grd.iGeomEdges.LogicalCellIndices; int[,] E2Cg = grd.iGeomEdges.CellIndices; // transform DG coördinates // ======================== int Nin = _Basis.GetLength(E2Cl[e0, 0]); int Not = Nin; #if DEBUG for (int e = 0; e < Len; e++) { int iEdge = e + e0; int jCellIN = E2Cl[iEdge, 0]; int jCellOT = E2Cl[iEdge, 1]; Debug.Assert(_Basis.GetLength(jCellIN) == Nin); if (jCellOT >= 0) { Debug.Assert(_Basis.GetLength(jCellOT) == Not); } } #endif int iBufIN, iBufOT = 0; MultidimensionalArray trfCoördinatesIN = TempBuffer.GetTempMultidimensionalarray(out iBufIN, Len, Nin); MultidimensionalArray trfCoördinatesOT = Not > 0 ? TempBuffer.GetTempMultidimensionalarray(out iBufOT, Len, Not) : null; TransformCoördinatesEdge(e0, Len, grd, Coord, Nin, Not, _Basis.Degree, AffineLinear, trfCoördinatesIN, trfCoördinatesOT); // Evaluate // ======== unsafe { fixed(int *pTrfIndex = trfIdx) { MultidimensionalArray BasisValues = null; Debug.Assert((valIN != null) == (valOT != null)); if (valIN != null) { // compute the values // ------------------- BasisValues = grd.ChefBasis.EdgeEval.GetValues(NS, e0, Len, _Basis.Degree); Debug.Assert(BasisValues.Dimension == 3); MultidimensionalArray BasisValuesIN, BasisValuesOT; if (BasisValues.GetLength(2) > Nin) { BasisValuesIN = BasisValues.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { BasisValues.GetLength(0) - 1, NoOfNodes - 1, Nin - 1 }); } else { BasisValuesIN = BasisValues; } if (BasisValues.GetLength(2) > Not) { if (Nin == Not) { BasisValuesOT = BasisValuesIN; } else { BasisValuesOT = BasisValues.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { BasisValues.GetLength(0) - 1, NoOfNodes - 1, Nin - 1 }); } } else { BasisValuesOT = BasisValues; } { valIN.Multiply(1.0, trfCoördinatesIN, BasisValuesIN, ResultPreScale, ref mp_ik_im_Tikm, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0), trfCycle_B: 2, trfPostOffset_B: 0); } if (Not > 0) { valOT.Multiply(1.0, trfCoördinatesOT, BasisValuesOT, ResultPreScale, ref mp_ik_im_Tikm, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0 + 1), trfCycle_B: 2, trfPostOffset_B: 0); } } Debug.Assert((meanValIN != null) == (meanValOT != null)); if (meanValIN != null) { // compute the mean values // ----------------------- var _Basis0Values = BasisValues; if (_Basis0Values == null) { _Basis0Values = grd.ChefBasis.EdgeEval.GetValues(NS, e0, Len, 0); } // assume the 0-th basis polynomial \f$ \phi_0 \f$ is constant! _Basis0Values = _Basis0Values.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { BasisValues.GetLength(0) - 1, -1, -1 }); // DG coördinates for the 0-th mode: var _trfCoördinatesIN = trfCoördinatesIN.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { Len - 1, -1 }); var _trfCoördinatesOT = trfCoördinatesOT.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { Len - 1, -1 }); { meanValIN.Multiply(1.0, _trfCoördinatesIN, _Basis0Values, ResultPreScale, ref mp_i_i_Ti, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0), trfCycle_B: 2, trfPostOffset_B: 0); } if (Not > 0) { meanValOT.Multiply(1.0, _trfCoördinatesOT, _Basis0Values, ResultPreScale, ref mp_i_i_Ti, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0 + 1), trfCycle_B: 2, trfPostOffset_B: 0); } } Debug.Assert((gradIN != null) == (gradOT != null)); if (gradIN != null) { // compute gradient values // ----------------------- int D = grd.SpatialDimension; int iBuf2; MultidimensionalArray GradientRef = TempBuffer.GetTempMultidimensionalarray(out iBuf2, Len, NoOfNodes, D); MultidimensionalArray BasisGradValues = grd.ChefBasis.EdgeGradientEval.GetValues(NS, e0, Len, _Basis.Degree); Debug.Assert(BasisGradValues.Dimension == 4); MultidimensionalArray BasisGradValuesIN, BasisGradValuesOT; if (BasisGradValues.GetLength(2) > Nin) { BasisGradValuesIN = BasisGradValues.ExtractSubArrayShallow(new int[] { 0, 0, 0, 0 }, new int[] { BasisGradValues.GetLength(0) - 1, NoOfNodes - 1, Nin - 1, D - 1 }); } else { BasisGradValuesIN = BasisGradValues; } if (BasisGradValues.GetLength(2) > Not) { if (Nin == Not) { BasisGradValuesOT = BasisGradValuesIN; } else { BasisGradValuesOT = BasisGradValues.ExtractSubArrayShallow(new int[] { 0, 0, 0, 0 }, new int[] { BasisGradValues.GetLength(0) - 1, NoOfNodes - 1, Nin - 1, D - 1 }); } } else { BasisGradValuesOT = BasisGradValues; } if (AffineLinear) { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // affine-linear-cell: // Inverse Jacobian different for each cell, but constant among nodes // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ var InvJacobi = grd.iGeomCells.InverseTransformation; Debug.Assert(grd is Grid.Classic.GridData, "implementation only valid for classic grid"); Debug.Assert(object.ReferenceEquals(E2Cg, E2Cl)); fixed(int *pE2Cl = E2Cl) { { GradientRef.Multiply(1.0, trfCoördinatesIN, BasisGradValuesIN, 0.0, ref mp_ike_im_Tikme, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0), trfCycle_B: 2, trfPostOffset_B: 0); // gradient in reference coördinates gradIN.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_ikd_Tied_ike, pE2Cl, pE2Cl, trfPreOffset_A: (2 * e0), trfCycle_A: 2, trfPostOffset_A: 0, trfPreOffset_B: 0, trfCycle_B: 0, trfPostOffset_B: 0); } if (Not > 0) { GradientRef.Multiply(1.0, trfCoördinatesOT, BasisGradValuesOT, 0.0, ref mp_ike_im_Tikme, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0 + 1), trfCycle_B: 2, trfPostOffset_B: 0); // gradient in reference coördinates gradOT.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_ikd_Tied_ike, pE2Cl, pE2Cl, trfPreOffset_A: (2 * e0 + 1), trfCycle_A: 2, trfPostOffset_A: 0, trfPreOffset_B: 0, trfCycle_B: 0, trfPostOffset_B: 0); } } } else { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++ // curved-cell: // Inverse Jacobian different for each node and each cell // ++++++++++++++++++++++++++++++++++++++++++++++++++++++ MultidimensionalArray invJacobiIN, invJacobiOT; var TiJ = grd.InverseJacobian.GetValue_EdgeDV(NS, e0, Len); invJacobiIN = TiJ.Item1; invJacobiOT = TiJ.Item2; { GradientRef.Multiply(1.0, trfCoördinatesIN, BasisGradValuesIN, 0.0, ref mp_ike_im_Tikme, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0), trfCycle_B: 2, trfPostOffset_B: 0); // gradient in reference coördinates, i.e. \f$ \nabla_{\vec{xi}} \f$ gradIN.Multiply(1.0, invJacobiIN, GradientRef, ResultPreScale, ref mp_ikd_iked_ike); // gradient in physical coördinates, i.e. \f$ \nabla_{\vec{x}}n \f$ } if (Not > 0) { GradientRef.Multiply(1.0, trfCoördinatesOT, BasisGradValuesOT, 0.0, ref mp_ike_im_Tikme, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0 + 1), trfCycle_B: 2, trfPostOffset_B: 0); // gradient in reference coördinates, i.e. \f$ \nabla_{\vec{xi}} \f$ gradOT.Multiply(1.0, invJacobiOT, GradientRef, ResultPreScale, ref mp_ikd_iked_ike); // gradient in physical coördinates, i.e. \f$ \nabla_{\vec{x}} \f$ } } TempBuffer.FreeTempBuffer(iBuf2); } } } TempBuffer.FreeTempBuffer(iBufIN); if (Not > 0) { TempBuffer.FreeTempBuffer(iBufOT); } /* * { * var _BasisValues = grd.ChefBasis.EdgeEval.GetValues(NS, e0, Len, _Basis.Degree); * * * var resultINAccCheck = valIN.CloneAs(); * var resultOTAccCheck = valOT.CloneAs(); * * for(int e = 0; e < Len; e++) { * int iEdge = e + e0; * int jCellIN = E2C[iEdge, 0]; * int jCellOT = E2C[iEdge, 1]; * int iTrfIN = trfIdx[iEdge, 0]; * int iTrfOT = trfIdx[iEdge, 1]; * * for(int k = 0; k < NoOfNodes; k++) { * int BN = _Basis.GetLength(jCellIN); * * resultINAccCheck[e, k] *= ResultPreScale; * resultOTAccCheck[e, k] *= ResultPreScale; * * for(int n = 0; n < BN; n++) { * double Cinerr = trfCoördinatesIN[e, n] - Coord[jCellIN, n]; * double Coterr = jCellOT >= 0 ? trfCoördinatesOT[e, n] - Coord[jCellOT, n] : 0.0; * * if(Math.Abs(Cinerr) > 1.0e-5) * Console.WriteLine("44fuckIN" + e); * if(Math.Abs(Coterr) > 1.0e-5) * Console.WriteLine("44fuckOT" + e); * * * resultINAccCheck[e, k] += Coord[jCellIN, n] * _BasisValues[iTrfIN, k, n]; * if(jCellOT >= 0) * resultOTAccCheck[e, k] += Coord[jCellOT, n] * _BasisValues[iTrfOT, k, n]; * * } * * double Vinerr = resultINAccCheck[e, k] - valIN[e, k]; * double Voterr = jCellOT >= 0 ? resultOTAccCheck[e, k] - valOT[e, k] : 0.0; * * * * if(Math.Abs(Vinerr) > 1.0e-5) * Console.WriteLine("44fuckIN" + e); * if(Math.Abs(Voterr) > 1.0e-5) * Console.WriteLine("44fuckOT" + e); * } * * } * * //resultINAcc.Set(resultINAccCheck); * //resultOTAcc.Set(resultOTAccCheck); * } */ }
/// <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> /// evaluation of DG field gradient; may be used in derived classes to implement <see cref="EvaluateGradient"/>. /// </summary> protected static void EvaluateGradientInternal(int j0, int L, NodeSet NS, Basis basis, MultidimensionalArray Coördinates, int coördOffset, MultidimensionalArray ResultAcc, double ResultPreScale) { int D, N, K; bool AffineLinear; CheckArgs(j0, L, NS, basis, Coördinates, ResultAcc, out D, out N, out K, out AffineLinear); Debug.Assert(ResultAcc.Dimension == 3); Debug.Assert(L == ResultAcc.GetLength(0)); Debug.Assert(K == ResultAcc.GetLength(1)); Debug.Assert(D == ResultAcc.GetLength(2)); /* * MultidimensionalArray BasisGradValues; * BasisGradValues = basis.CellEvalGradient(NS, j0, L); * * ResultAcc.Multiply(1.0, Coördinates, BasisGradValues, ResultPreScale, "jmd", "jn", "jmnd"); */ MultidimensionalArray BasisGradValues = basis.EvaluateGradient(NS); int iBuf1, iBuf2; if (AffineLinear) { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // affine-linear-cell: // Inverse Jacobian different for each cell, but constant among nodes // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (L == 1) { // Special optimization for single-cell evaluation: // this happens very often for edge quadrature, so it is quite relevant. double scale0 = basis.GridDat.ChefBasis.Scaling[j0]; MultidimensionalArray GradientRef = TempBuffer.GetTempMultidimensionalarray(out iBuf2, L, K, D); MultidimensionalArray InvJacobi = basis.GridDat.iGeomCells.InverseTransformation.ExtractSubArrayShallow(j0, -1, -1); Debug.Assert(basis.GridDat.iGeomCells.GeomCell2LogicalCell == null || basis.GridDat.iGeomCells.GeomCell2LogicalCell[j0] == j0); MultidimensionalArray Coördinates_j; if (coördOffset == 0 && Coördinates.GetLength(0) == 1) { Coördinates_j = Coördinates; } else { Coördinates_j = Coördinates.ExtractSubArrayShallow(new int[] { coördOffset, 0 }, new int[] { coördOffset, N - 1 }); } GradientRef.Multiply(scale0, Coördinates_j, BasisGradValues, 0.0, ref mp_jke_jm_kme); // gradient in reference coördinates ResultAcc.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_jkd_ed_jke); TempBuffer.FreeTempBuffer(iBuf2); } else { MultidimensionalArray trfCoördinates = TempBuffer.GetTempMultidimensionalarray(out iBuf1, L, N); MultidimensionalArray GradientRef = TempBuffer.GetTempMultidimensionalarray(out iBuf2, L, K, D); MultidimensionalArray InvJacobi = basis.GridDat.iGeomCells.InverseTransformation.ExtractSubArrayShallow(new int[] { j0, 0, 0 }, new int[] { j0 + L - 1, D - 1, D - 1 }); TransformCoördinates(j0, L, basis, Coördinates, coördOffset, N, AffineLinear, trfCoördinates); GradientRef.Multiply(1.0, trfCoördinates, BasisGradValues, 0.0, ref mp_jke_jm_kme); // gradient in reference coördinates ResultAcc.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_jkd_jed_jke); TempBuffer.FreeTempBuffer(iBuf1); TempBuffer.FreeTempBuffer(iBuf2); } } else { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++ // curved-cell: // Inverse Jacobian different for each node and each cell // ++++++++++++++++++++++++++++++++++++++++++++++++++++++ MultidimensionalArray trfCoördinates = TempBuffer.GetTempMultidimensionalarray(out iBuf1, L, N); MultidimensionalArray GradientRef = TempBuffer.GetTempMultidimensionalarray(out iBuf2, L, K, D); MultidimensionalArray InvJacobi = basis.GridDat.InverseJacobian.GetValue_Cell(NS, j0, L); TransformCoördinates(j0, L, basis, Coördinates, coördOffset, N, AffineLinear, trfCoördinates); GradientRef.Multiply(1.0, trfCoördinates, BasisGradValues, 0.0, ref mp_jke_jm_kme); // gradient in reference coördinates ResultAcc.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_jkd_jked_jke); TempBuffer.FreeTempBuffer(iBuf1); TempBuffer.FreeTempBuffer(iBuf2); } }
/// <summary> /// Integrand evaluation. /// </summary> protected override void Evaluate(int i0, int Length, QuadRule rule, MultidimensionalArray EvalResult) { NodeSet NodesUntransformed = rule.Nodes; int M = NodesUntransformed.GetLength(0); int D = NodesUntransformed.GetLength(1); // evaluate scalar function ans store result in 'EvalResult' // ========================================================= Debug.Assert(!((m_func != null) && (m_funcEx != null))); if (m_func != null || m_Map != null) { GridDat.TransformLocal2Global(NodesUntransformed, i0, Length, m_NodesTransformed, 0); } if (m_func != null) { MultidimensionalArray inp = m_NodesTransformed.ResizeShallow(new int[] { Length *M, D }); MultidimensionalArray outp = EvalResult.ResizeShallow(new int[] { Length *M }); m_func(inp, outp); Debug.Assert(m_funcEx == null); } if (m_funcEx != null) { m_funcEx(i0, Length, NodesUntransformed, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); Debug.Assert(m_func == null); } if (m_Map == null) { // L2 error branch // +++++++++++++++ MultidimensionalArray fieldvals = EvalResult.ResizeShallow(new int[] { Length, NodesUntransformed.GetLength(0) }); m_Owner.Evaluate(i0, Length, NodesUntransformed, fieldvals, -1.0); for (int j = 0; j < Length; j++) { for (int m = 0; m < M; m++) { double e; e = EvalResult[j, m, 0]; EvalResult[j, m, 0] = e * e; } } } else { // arbitrary mapping branch // ++++++++++++++++++++++++ MultidimensionalArray fieldvals = MultidimensionalArray.Create(new int[] { Length, NodesUntransformed.GetLength(0) }); m_Owner.Evaluate(i0, Length, NodesUntransformed, fieldvals, -1.0); double[] X = new double[D]; for (int j = 0; j < Length; j++) { for (int m = 0; m < M; m++) { double e; e = EvalResult[j, m, 0]; for (int d = 0; d < D; d++) { X[d] = m_NodesTransformed[j, m, d]; } EvalResult[j, m, 0] = this.m_Map(X, fieldvals[j, m], e); } } } }
/// <summary> /// Returns the minimum and the maximum value of <paramref name="mod"/>(this DG field), for each cell; /// </summary> /// <param name="max"> /// Vector, with the same number of entries as the cell mask <paramref name="cm"/>; /// On exit, the approximate local maximum within the cell. /// </param> /// <param name="min"> /// Vector, with the same number of entries as the cell mask <paramref name="cm"/>; /// On exit, the approximate local minimum within the cell. /// </param> /// <param name="cm"> /// optional domain restriction /// </param> /// <param name="mod"> /// optimal modifier, which e.g. may select the absolute value; if null, the identity function; /// </param> public void GetCellwiseExtremalValues <T1, T2>(T1 min, T2 max, CellMask cm = null, Func <double, double> mod = null) where T1 : IList <double> where T2 : IList <double> // { using (new FuncTrace()) { int J = Basis.GridDat.iLogicalCells.NoOfLocalUpdatedCells; int Jcm = cm == null ? J : cm.NoOfItemsLocally; if (min.Count != Jcm) { throw new ArgumentException("wrong length of output vector", "min"); } if (max.Count != Jcm) { throw new ArgumentException("wrong length of output vector", "max"); } min.SetAll(double.MaxValue); max.SetAll(double.MinValue); if (mod == null) { mod = (x => x); } //int N = m_context.Grid.GridSimplex.NoOfVertices + 1; // find maximum on this processor // ------------------------------ // create node set if (m_ExtremalProbeNS == null) { // nodes for the evaluation of the velocity vector // (all vertices an 0) int D = Basis.GridDat.SpatialDimension; var KrefS = Basis.GridDat.iGeomCells.RefElements; m_ExtremalProbeNS = new NodeSet[KrefS.Length]; for (int i = 0; i < KrefS.Length; i++) { m_ExtremalProbeNS[i] = new NodeSet(KrefS[i], KrefS[i].Vertices); } } // vectorisation of this method int VectorSize = -1; int N0 = m_ExtremalProbeNS[0].NoOfNodes; // number of nodes MultidimensionalArray fieldValues = new MultidimensionalArray(2); IEnumerable <Chunk> all_chunks; if (cm == null) { var _ch = new Chunk[1]; _ch[0].i0 = 0; _ch[0].Len = J; all_chunks = _ch; } else { all_chunks = cm; } int jSub = 0; foreach (Chunk chk in all_chunks) { VectorSize = this.GridDat.iGeomCells.GetNoOfSimilarConsecutiveCells(CellInfo.RefElementIndex_Mask, chk.i0, Math.Min(100, chk.Len)); // try to be a little vectorized; int _J = chk.Len + chk.i0; for (int j0 = chk.i0; j0 < _J; j0 += VectorSize) { if (j0 + VectorSize > _J) { VectorSize = _J - j0; } int iKref = Basis.GridDat.iGeomCells.GetRefElementIndex(j0); int N = m_ExtremalProbeNS[iKref].NoOfNodes; if (fieldValues.GetLength(0) != VectorSize || fieldValues.GetLength(1) != N) { fieldValues = MultidimensionalArray.Create(VectorSize, N); } this.Evaluate(j0, VectorSize, m_ExtremalProbeNS[iKref], fieldValues, 0.0); // loop over cells ... for (int jCell = j0; jCell < j0 + VectorSize; jCell++) { // loop over nodes ... for (int n = 0; n < N; n++) { double vel = 0; vel = mod(fieldValues[jCell - j0, n]); min[jSub] = Math.Min(min[jSub], vel); max[jSub] = Math.Max(max[jSub], vel); } jSub++; } } } } }
/// <summary> /// Evaluates all 2nd derivatives (by cell-local analytic derivation of /// the basis polynomials) of this field; /// </summary> /// <param name="j0"></param> /// <param name="Len"></param> /// <param name="NS"></param> /// <param name="result"> /// <list type="bullet"> /// <item>1st index: cell index <em>j</em></item> /// <item>2nd index: node index <em>m</em> into nodeset #<paramref name="NodeSetIndex"/></item> /// <item>3rd index: spatial direction of 1st derivation, <em>k</em></item> /// <item>4th index: spatial direction of 2nd derivation, <em>l</em></item> /// </list> /// So, the entry [j,m,k,l] = \f$ \frac{\partial}{\partial x_k} \frac{\partial}{\partial x_l} \varphi (\vec{\xi}_m)\f$ /// where \f$ \vec{xi}_m\f$ is the <em>m</em>-th /// vector in the node set #<paramref name="NodeSetIndex"/>, in the /// <em>j</em>-th cell. /// </param> /// <remarks> /// Because of 2 derivatives taken, this field needs to be at least of /// DG degree 2 to get a non-zero result from this method. /// </remarks> public void EvaluateHessian(int j0, int Len, NodeSet NS, MultidimensionalArray result) { int D = this.GridDat.SpatialDimension; // spatial dimension int N = m_Basis.GetLength(j0); // number of coordinates per cell if (result.Dimension != 4) { throw new ArgumentException("dimension must be 4", "result"); } if (Len > result.GetLength(0)) { throw new ArgumentOutOfRangeException("mismatch between Len and 0-th length of result"); } if (result.GetLength(2) != D || result.GetLength(3) != D) { throw new ArgumentOutOfRangeException("3rd and 4th length of result must be " + D + "x" + D + ";"); } // not very optimized.... MultidimensionalArray BasisHessian = this.Basis.CellEval2ndDeriv(NS, j0, Len); result.Multiply(1.0, this.m_Mda_Coordinates.ExtractSubArrayShallow(new int[] { j0, 0 }, new int[] { j0 + Len - 1, N - 1 }), BasisHessian, 0.0, "jkde", "jn", "jknde"); /* * var scales = this.GridDat.ChefBasis.Scaling; * var Tinv = this.GridDat.Cells.InverseTransformation; * * MultidimensionalArray gbv = Basis.Evaluate2ndDeriv(NS); * int M = gbv.GetLength(0); // number of nodes per cell * if (result.GetLength(1) != M) * throw new ArgumentException("length of dimension 1 must be " + M, "result"); * * var Coordinates = (MultidimensionalArray)this.Coordinates; * * double[,] acc = new double[D, D]; * double[,] Tinv_j = new double[D, D]; * * // loop over cells... * for (int j = 0; j < Len; j++) { * double sc = scales[j0 + j]; * * if (this.GridDat.Cells.IsCellAffineLinear(j0 + j)) { * * // load transformation matrix for easier access * for (int d1 = 0; d1 < D; d1++) * for (int d2 = 0; d2 < D; d2++) * Tinv_j[d1, d2] = Tinv[j + j0, d1, d2]; * * // loop over nodes ... * for (int m = 0; m < M; m++) { * * Array.Clear(acc, 0, D * D); * * // sum up... * for (int n = 0; n < N; n++) { // loop over basis functions * * double coord = Coordinates[j + j0, n]; * for (int d1 = 0; d1 < D; d1++) { // 1st loop over spatial dimension * for (int d2 = 0; d2 < D; d2++) { // 1st loop over spatial dimension * acc[d1, d2] += gbv[m, n, d1, d2] * coord; * } * } * } * * // transform... * for (int d1 = 0; d1 < D; d1++) { * for (int d2 = 0; d2 < D; d2++) { * double r = 0.0; * for (int k1 = 0; k1 < D; k1++) { * double rr = 0; * for (int k2 = 0; k2 < D; k2++) { * rr += acc[k1, k2] * Tinv_j[k2, d1]; * } * r += rr * Tinv_j[k1, d2]; * } * result[j, m, d1, d2] = r * sc; * } * } * } * } else { * throw new NotImplementedException("nonlinear cell: todo"); * } */ /* * * //Test code; * * var HessBasis = this.Basis.CellEval2ndDeriv(NodeSetIndex, j0, Len); * var CheckResult = result.CloneAs(); * * * for (int j = 0; j < Len; j++) { * * // loop over nodes ... * for (int m = 0; m < M; m++) { * * for (int d1 = 0; d1 < D; d1++) { * for (int d2 = 0; d2 < D; d2++) { * double accu = 0; * * for (int n = 0; n < N; n++) { * accu += HessBasis[j, m, n, d1, d2]*Coordinates[j + j0, n]; * } * * CheckResult[j, m, d1, d2] = accu; * } * } * * } * } * * CheckResult.Acc(-1.0, result); * if (CheckResult.L2Norm() > 1.0e-8) * throw new Exception(); */ }
/// <summary> /// Evaluates the field along edges. /// </summary> /// <param name="ResultIndexOffset"> /// An offset for the first index of <paramref name="ValueIN"/> resp. <paramref name="ValueOT"/>, /// i.e. the first result will be written to /// <paramref name="ValueIN"/>[<paramref name="ResultIndexOffset"/>,*]. /// </param> /// <param name="e0">Index of the first edge to evaluate.</param> /// <param name="Len">Number of edges to evaluate</param> /// <param name="NS"> /// nodes to evaluate at /// </param> /// <param name="ValueIN"> /// If not null, contains the following output: /// On exit, the value of the DG field at the given nodes are /// <em>accumulated</em> (!) there. Before the values are added, /// the original content is scaled by <paramref name="ResultPreScale"/>.<br/> /// The array is 2-dimensional: /// <list type="bullet"> /// <item> /// 1st index: edge index <i>j</i> - <paramref name="e0"/>; /// </item> /// <item> /// 2nd index: node index <i>k</i>, corresponds with 1st index of /// the node set <paramref name="NS"/>; /// </item> /// </list> /// </param> /// <param name="ValueOUT"> /// Same as <paramref name="ValueIN"/>. /// </param> /// <param name="MeanValueIN"> /// If not null, contains the following output: /// On exit, the mean values of the DG field at the given edges are /// <em>accumulated</em> (!) there. Before the values are added, /// the original content is scaled by <paramref name="ResultPreScale"/>.<br/> /// The array is 2-dimensional: /// <list type="bullet"> /// <item> /// 1st index: edge index <i>j</i> - <paramref name="e0"/>; /// </item> /// <item> /// 2nd index: node index <i>k</i>, corresponds with 1st index of /// the node set <paramref name="NS"/>; /// </item> /// </list> /// </param> /// <param name="MeanValueOT"> /// Same as <paramref name="MeanValueIN"/>. /// </param> /// <param name="GradientIN"> /// If not null, contains the following output: /// On exit, the value of the gradient of DG field at the given nodes /// are <em>accumulated</em> (!) there. Before the values are added, /// the original content is scaled by <paramref name="ResultPreScale"/>.<br/> /// The array is 3-dimensional: /// <list type="bullet"> /// <item> /// 1st index: edge index <i>j</i> - <paramref name="e0"/>; /// </item> /// <item> /// 2nd index: node index <i>k</i>, corresponds with 1st index of /// the node set <paramref name="NS"/>; /// </item> /// <item> /// 2rd index: spatial dimension; /// </item> /// </list> /// </param> /// <param name="GradientOT"> /// Same as <paramref name="GradientIN"/>. /// </param> /// <param name="ResultPreScale"> /// Scaling that is applied to <paramref name="ValueIN"/> and <paramref name="ValueOUT"/> before /// the field evaluation is added /// </param> public override void EvaluateEdge(int e0, int Len, NodeSet NS, MultidimensionalArray ValueIN, MultidimensionalArray ValueOT, MultidimensionalArray MeanValueIN = null, MultidimensionalArray MeanValueOT = null, MultidimensionalArray GradientIN = null, MultidimensionalArray GradientOT = null, int ResultIndexOffset = 0, double ResultPreScale = 0.0) // { int D = GridDat.SpatialDimension; // spatial dimension int N = m_Basis.Length; // number of coordinates per cell int K = NS.NoOfNodes; // number of nodes if ((ValueIN != null) != (ValueOT != null)) { throw new ArgumentException(); } if ((MeanValueIN != null) != (MeanValueOT != null)) { throw new ArgumentException(); } if ((GradientIN != null) != (GradientOT != null)) { throw new ArgumentException(); } if (ValueIN != null) { if (ValueIN.Dimension != 2) { throw new ArgumentException("result", "dimension of result array must be 2"); } if (Len > ValueIN.GetLength(0) + ResultIndexOffset) { throw new ArgumentException("mismatch between Len and 0-th length of result"); } if (ValueIN.GetLength(1) != K) { throw new ArgumentException(); } if (ValueOT.Dimension != 2) { throw new ArgumentException("result", "dimension of result array must be 2"); } if (Len > ValueOT.GetLength(0) + ResultIndexOffset) { throw new ArgumentException("mismatch between Len and 0-th length of result"); } if (ValueOT.GetLength(1) != K) { throw new ArgumentException(); } if (!(ResultIndexOffset == 0 && Len == ValueIN.GetLength(0))) { ValueIN = ValueIN.ExtractSubArrayShallow(new int[] { ResultIndexOffset, 0 }, new int[] { ResultIndexOffset + Len - 1, K - 1 }); } if (!(ResultIndexOffset == 0 && Len == ValueOT.GetLength(0))) { ValueOT = ValueOT.ExtractSubArrayShallow(new int[] { ResultIndexOffset, 0 }, new int[] { ResultIndexOffset + Len - 1, K - 1 }); } } if (MeanValueIN != null) { if (MeanValueIN.Dimension != 1) { throw new ArgumentException("Dimension of mean-value result array must be 1."); } if (Len > MeanValueIN.GetLength(0) + ResultIndexOffset) { throw new ArgumentException("mismatch between Len and 0-th length of result"); } if (MeanValueOT.Dimension != 1) { throw new ArgumentException("Dimension of mean-value result array must be 1."); } if (Len > MeanValueOT.GetLength(0) + ResultIndexOffset) { throw new ArgumentException("mismatch between Len and 0-th length of result"); } if (!(ResultIndexOffset == 0 && Len == MeanValueIN.GetLength(0))) { MeanValueIN = MeanValueIN.ExtractSubArrayShallow(new int[] { ResultIndexOffset }, new int[] { ResultIndexOffset + Len - 1 }); } if (!(ResultIndexOffset == 0 && Len == MeanValueOT.GetLength(0))) { MeanValueOT = MeanValueOT.ExtractSubArrayShallow(new int[] { ResultIndexOffset }, new int[] { ResultIndexOffset + Len - 1 }); } } if (GradientIN != null) { if (GradientIN.Dimension != 3) { throw new ArgumentException("Dimension of gradient result array must be 3."); } if (Len > GradientIN.GetLength(0) + ResultIndexOffset) { throw new ArgumentException("mismatch between Len and 0-th length of result"); } if (GradientIN.GetLength(1) != K) { throw new ArgumentException(); } if (GradientIN.GetLength(2) != D) { throw new ArgumentException(); } if (GradientOT.Dimension != 3) { throw new ArgumentException("Dimension of gradient result array must be 3."); } if (Len > GradientOT.GetLength(0) + ResultIndexOffset) { throw new ArgumentException("mismatch between Len and 0-th length of result"); } if (GradientOT.GetLength(1) != K) { throw new ArgumentException(); } if (GradientOT.GetLength(2) != D) { throw new ArgumentException(); } if (!(ResultIndexOffset == 0 && Len == GradientIN.GetLength(0))) { GradientIN = GradientIN.ExtractSubArrayShallow(new int[] { ResultIndexOffset, 0, 0 }, new int[] { ResultIndexOffset + Len - 1, K - 1, D - 1 }); } if (!(ResultIndexOffset == 0 && Len == GradientOT.GetLength(0))) { GradientOT = GradientOT.ExtractSubArrayShallow(new int[] { ResultIndexOffset, 0, 0 }, new int[] { ResultIndexOffset + Len - 1, K - 1, D - 1 }); } } var coöSys = NS.GetNodeCoordinateSystem(this.GridDat); if (coöSys != NodeCoordinateSystem.EdgeCoord) { throw new ArgumentOutOfRangeException(); } DGField.EvaluateEdgeInternal(e0, Len, NS, this.m_Basis, this.m_Mda_Coordinates, ValueIN, ValueOT, MeanValueIN, MeanValueOT, GradientIN, GradientOT, ResultPreScale); }
/// <summary> /// Evaluates the gradient of all polynomials in this basis (see <see cref="Polynomials"/>) at specified edges. /// </summary> /// <param name="NS"></param> /// <param name="j0">index of first edge to evaluate</param> /// <param name="Len">number of cells to evaluate</param> /// <returns> /// For each 'in'- and 'out'-cell, arrays;<br/> /// <list type="bullet"> /// <item>1st index: cell index</item> /// <item>2nd index: node index</item> /// <item>3rd index: polynomial index</item> /// <item>4th index: spatial dimension</item> /// </list> /// </returns> public virtual Tuple <MultidimensionalArray, MultidimensionalArray> EdgeEvalGradient(NodeSet NS, int j0, int Len) { var ret = this.GridDat.ChefBasis.CellBasisGradientValues.GetValue_EdgeDV(NS, j0, Len, this.Degree); if (ret.Item1.GetLength(0) != Len) { int M = ret.Item1.GetLength(1); int N = ret.Item1.GetLength(2); int D = ret.Item1.GetLength(3); ret = new Tuple <MultidimensionalArray, MultidimensionalArray>( ret.Item1.ExtractSubArrayShallow(new int[] { 0, 0, 0, 0 }, new int[] { Len - 1, M - 1, N - 1, D - 1 }), ret.Item2.ExtractSubArrayShallow(new int[] { 0, 0, 0, 0 }, new int[] { Len - 1, M - 1, N - 1, D - 1 })); } return(ret); }