Ejemplo n.º 1
0
        /// <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);
            }
        }