/// <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); } }