/// <summary>
        ///
        /// </summary>
        protected void EvaluateEx(int i0, int Length, QuadRule QR, MultidimensionalArray QuadResult)
        {
            NodeSet   NodesUntransformed = QR.Nodes;
            IGridData grid          = this.GridDat;
            int       D             = grid.SpatialDimension;
            int       NoOfEquations = m_CodomainBasisS.Length;
            int       NoOfNodes     = NodesUntransformed.NoOfNodes;
            bool      isAffine      = grid.iGeomCells.IsCellAffineLinear(i0);

            int[] geom2log = grid.iGeomCells.GeomCell2LogicalCell;
#if DEBUG
            for (int i = 1; i < Length; i++)
            {
                Debug.Assert(grid.iGeomCells.IsCellAffineLinear(i + i0) == isAffine);

                if (geom2log == null)
                {
                    for (int e = 0; e < base.m_CodomainBasisS.Length; e++)
                    {
                        Debug.Assert(base.m_CodomainBasisS[e].GetLength(i + i0) == base.m_CodomainBasisS[e].GetLength(i0));
                    }
                }
                else
                {
                    for (int e = 0; e < base.m_CodomainBasisS.Length; e++)
                    {
                        Debug.Assert(base.m_CodomainBasisS[e].GetLength(geom2log[i + i0]) == base.m_CodomainBasisS[e].GetLength(geom2log[i0]));
                    }
                }
            }
#endif

            // this is an EvaluateEx: we are also responsible for multiplying with quadrature weights and summing up!
            Debug.Assert(QuadResult.Dimension == 2);
            Debug.Assert(QuadResult.GetLength(0) == Length);
            Debug.Assert(QuadResult.GetLength(1) == base.m_CodomainMapping.BasisS.Sum(basis => basis.Length));

            // ===================
            // Evaluate all fields
            // ===================

            this.Field_Eval.Start();

            for (int f = 0; f < m_DomainFields.Length; f++)
            {
                if (m_ValueRequired[f])
                {
                    Debug.Assert(m_FieldValues[f] != null);
                    if (m_DomainFields[f] != null)
                    {
                        m_DomainFields[f].Evaluate(i0, Length, NodesUntransformed, m_FieldValues[f]);
                    }
                    else
                    {
                        // field is null => set to 0.0
                        m_FieldValues[f].Clear();
                    }
                }
            }

            for (int f = 0; f < m_GradientRequired.Length; f++)
            {
                if (m_GradientRequired[f])
                {
                    Debug.Assert(m_FieldGradients[f] != null);
                    if (m_DomainFields[f] != null)
                    {
                        m_DomainFields[f].EvaluateGradient(i0, Length, NodesUntransformed, m_FieldGradients[f]);
                    }
                    else
                    {
                        // field is null => set to 0.0
                        m_FieldValues[f].Clear();
                    }
                }
            }

            this.Field_Eval.Stop();



            // =====================================
            // Transform Nodes to global coordinates
            // =====================================

            this.ParametersAndNormals.Start();

            var NodesGlobalCoords = grid.GlobalNodes.GetValue_Cell(NodesUntransformed, i0, Length);
            //var NodesGlobalCoords = MultidimensionalArray.Create(Length, NoOfNodes, D);

            this.ParametersAndNormals.Stop();

            // =======================
            // Evaluate Flux functions
            // =======================


            bool[] RequireTestFunctionGradient = new bool[NoOfEquations];
            bool[] Cleared_m_FluxValues        = new bool[NoOfEquations];

            this.Flux_Eval.Start();

            // loop over all equations ...
            for (int e = 0; e < NoOfEquations; e++)
            {
                //                Field fld = m_CodomainFields[e];

                if (m_NonlinFluxes[e].m_AllComponentsOfMyType.Length + m_NonlinFluxesEx[e].m_AllComponentsOfMyType.Length > 0)
                {
                    m_FluxValues[e].Clear();
                    Cleared_m_FluxValues[e] = true;

                    RequireTestFunctionGradient[e] = true;

                    // sum up all INonlinearFlux - objects
                    int jjj = 0;
                    foreach (INonlinearFlux nonlinFlx in m_NonlinFluxes[e].m_AllComponentsOfMyType)
                    {
                        m_NonlinFluxesWatches[e][jjj].Start();
                        nonlinFlx.Flux(m_Time,
                                       NodesGlobalCoords,
                                       m_NonlinFluxes[e].MapArguments(m_FieldValues, nonlinFlx),
                                       0, Length,
                                       m_FluxValues[e]);
                        m_NonlinFluxesWatches[e][jjj].Stop();
                        jjj++;
                    }

                    // sum up all INonlinearFluxEx - objects
                    jjj = 0;
                    foreach (INonlinearFluxEx nonlinFlxEx in m_NonlinFluxesEx[e].m_AllComponentsOfMyType)
                    {
                        m_NonlinFluxesExWatches[e][jjj].Start();
                        nonlinFlxEx.Flux(m_Time,
                                         NodesGlobalCoords,
                                         m_NonlinFluxesEx[e].MapArguments(m_FieldValues, nonlinFlxEx),
                                         0, Length,
                                         m_FluxValues[e],
                                         i0);
                        m_NonlinFluxesExWatches[e][jjj].Stop();
                        jjj++;
                    }

                    m_FluxValues[e].Scale(-1.0);
                }
            }



            // =========================
            // Evaluate Source functions
            // =========================

            bool[] RequireTestfunction    = new bool[NoOfEquations];
            bool[] Cleared_m_SourceValues = new bool[NoOfEquations];

            for (int e = 0; e < NoOfEquations; e++)
            {
                //                Equation eq = m_Equations[e];
                //                Field fld = eq.MyField;

                if (m_NonlinSources[e].m_AllComponentsOfMyType.Length > 0)
                {
                    m_SourceValues[e].Clear();
                    Cleared_m_SourceValues[e] = true;

                    RequireTestfunction[e] = true;

                    // sum up all sources
                    int jjj = 0;
                    foreach (INonlinearSource nonlinSrc in m_NonlinSources[e].m_AllComponentsOfMyType)
                    {
                        m_NonlinSources_watch[e][jjj].Start();
                        nonlinSrc.Source(m_Time,
                                         NodesGlobalCoords,
                                         m_NonlinSources[e].MapArguments(m_FieldValues, nonlinSrc),
                                         0, i0, Length,
                                         m_SourceValues[e]);
                        m_NonlinSources_watch[e][jjj].Stop();
                        jjj++;
                    }
                }
            }

            // ==============
            // Evaluate Forms
            // ==============

            for (int e = 0; e < NoOfEquations; e++)
            {
                if (m_NonlinFormV[e].m_AllComponentsOfMyType.Length > 0)
                {
                    for (int icomp = 0; icomp < m_NonlinFormV[e].m_AllComponentsOfMyType.Length; icomp++)
                    {
                        INonlinVolumeForm_V nonlinform = m_NonlinFormV[e].m_AllComponentsOfMyType[icomp];

                        if ((nonlinform.VolTerms & (TermActivationFlags.UxV | TermActivationFlags.V | TermActivationFlags.GradUxV)) == 0)
                        {
                            continue;
                        }
                        else
                        {
                            m_NonlinFormV_watch[e][icomp].Start();
                            RequireTestfunction[e] = true;

                            if (!Cleared_m_SourceValues[e])
                            {
                                m_SourceValues[e].Clear();
                                Cleared_m_SourceValues[e] = true;
                            }

                            VolumFormParams vfp;
                            vfp.GridDat = base.GridDat;
                            vfp.j0      = i0;
                            vfp.Len     = Length;
                            vfp.Xglobal = NodesGlobalCoords;
                            vfp.time    = this.m_Time;
                            int NoArgs              = m_NonlinFormV[e].NoOfArguments[icomp];
                            int NoParams            = m_NonlinFormV[e].NoOfParameters[icomp];
                            var MappedArgsAndParams = m_NonlinFormV[e].MapArguments(this.m_FieldValues, nonlinform);
                            vfp.ParameterVars = MappedArgsAndParams.GetSubVector(NoArgs, NoParams);
                            var MappedArgs = MappedArgsAndParams.GetSubVector(0, NoArgs);

                            var MappedGradients = m_NonlinFormV[e].MapArguments(this.m_FieldGradients, nonlinform, true);

                            nonlinform.Form(ref vfp, MappedArgs, MappedGradients, this.m_SourceValues[e]);
                            m_NonlinFormV_watch[e][icomp].Stop();
                        }
                    }
                }
            }

            for (int e = 0; e < NoOfEquations; e++)
            {
                if (m_NonlinFormGradV[e].m_AllComponentsOfMyType.Length > 0)
                {
                    for (int icomp = 0; icomp < m_NonlinFormGradV[e].m_AllComponentsOfMyType.Length; icomp++)
                    {
                        INonlinVolumeForm_GradV nonlinform = m_NonlinFormGradV[e].m_AllComponentsOfMyType[icomp];

                        if ((nonlinform.VolTerms & (TermActivationFlags.GradUxGradV | TermActivationFlags.UxGradV | TermActivationFlags.GradV)) == 0)
                        {
                            continue;
                        }
                        else
                        {
                            m_NonlinFormGradV_watch[e][icomp].Start();
                            RequireTestFunctionGradient[e] = true;

                            if (!Cleared_m_FluxValues[e])
                            {
                                this.m_FluxValues[e].Clear();
                                Cleared_m_FluxValues[e] = true;
                            }

                            VolumFormParams vfp;
                            vfp.GridDat = base.GridDat;
                            vfp.j0      = i0;
                            vfp.Len     = Length;
                            vfp.Xglobal = NodesGlobalCoords;
                            vfp.time    = this.m_Time;
                            int NoArgs              = m_NonlinFormGradV[e].NoOfArguments[icomp];
                            int NoParams            = m_NonlinFormGradV[e].NoOfParameters[icomp];
                            var MappedArgsAndParams = m_NonlinFormGradV[e].MapArguments(this.m_FieldValues, nonlinform);
                            vfp.ParameterVars = MappedArgsAndParams.GetSubVector(NoArgs, NoParams);
                            var MappedArgs = MappedArgsAndParams.GetSubVector(0, NoArgs);

                            var MappedGradients = m_NonlinFormGradV[e].MapArguments(this.m_FieldGradients, nonlinform, true);

                            nonlinform.Form(ref vfp, MappedArgs, MappedGradients, this.m_FluxValues[e]);
                            m_NonlinFormGradV_watch[e][icomp].Stop();
                        }
                    }
                }
            }
            this.Flux_Eval.Stop();



            // ================
            // Transform fluxes
            // ================

            // its less work to multiply the fluxes by the inverse Jacobi,
            // than each test function gradient by inverse Jacobi.
            // Could be interpreted as transforming fluxes to Refelem, i think....

            this.Flux_Trafo.Start();

            MultidimensionalArray InverseJacobi = null, JacobiDet = null;
            for (int e = 0; e < NoOfEquations; e++)
            {
                Debug.Assert((m_FluxValues[e] != null) == (m_FluxValuesTrf[e] != null));

                if (m_FluxValues[e] != null)
                {
                    if (InverseJacobi == null)
                    {
                        if (isAffine)
                        {
                            InverseJacobi = grid.iGeomCells.InverseTransformation.ExtractSubArrayShallow(new int[] { i0, 0, 0 }, new int[] { i0 + Length - 1, D - 1, D - 1 });
                        }
                        else
                        {
                            InverseJacobi = grid.InverseJacobian.GetValue_Cell(QR.Nodes, i0, Length);
                            //InverseJacobi = MultidimensionalArray.Create(Length, NoOfNodes, D, D);
                        }
                    }

                    if (JacobiDet == null && !isAffine)
                    {
                        JacobiDet = grid.JacobianDeterminat.GetValue_Cell(QR.Nodes, i0, Length);
                    }

                    if (isAffine)
                    {
                        m_FluxValuesTrf[e].Multiply(1.0, m_FluxValues[e], InverseJacobi, 0.0, "jke", "jkd", "jed");
                        // for affine-linear cells the multiplication with Jacobi determinant is done AFTER quadrature, since it is constant per cell.
                    }
                    else
                    {
                        m_FluxValuesTrf[e].Multiply(1.0, m_FluxValues[e], InverseJacobi, 0.0, "jke", "jkd", "jked");
                        m_FluxValuesTrf[e].Multiply(1.0, m_FluxValuesTrf[e], JacobiDet, 0.0, "jke", "jke", "jk"); // apply scaling with Jacobi determinant, for integral transformation
                    }
                }

                if (m_SourceValues[e] != null)
                {
                    if (JacobiDet == null && !isAffine)
                    {
                        JacobiDet = grid.JacobianDeterminat.GetValue_Cell(QR.Nodes, i0, Length);
                    }
                    //JacobiDet = MultidimensionalArray.Create(Length, NoOfNodes);

                    // apply scaling with Jacobi determinant, for integral transformation
                    if (isAffine)
                    {
                        // nop: for affine-linear cells the multiplication with Jacobi determinant is done AFTER quadrature, since it is constant per cell.
                    }
                    else
                    {
                        m_SourceValues[e].Multiply(1.0, m_SourceValues[e], JacobiDet, 0.0, "jk", "jk", "jk");
                    }
                }
            }

            this.Flux_Trafo.Stop();



            // =======================
            // evaluate test functions
            // =======================

            this.Basis_Eval.Start();

            if (this.m_MaxCodBasis != null && QR.NoOfNodes != this.m_TestFuncWeighted.GetLength(0))
            {
                this.m_TestFuncWeighted.Allocate(QR.NoOfNodes, m_MaxCodBasis.GetLength(i0));
            }
            if (this.m_MaxCodBasis_Gradient != null && QR.NoOfNodes != this.m_TestFuncGradWeighted.GetLength(0))
            {
                this.m_TestFuncGradWeighted.Allocate(QR.NoOfNodes, m_MaxCodBasis_Gradient.GetLength(i0), D);
            }

            if (m_MaxCodBasis != null)
            {
                var testFunc = m_MaxCodBasis.Evaluate(QR.Nodes);
                m_TestFuncWeighted.Multiply(1.0, QR.Weights, testFunc, 0.0, "kn", "k", "kn");
            }

            if (m_MaxCodBasis_Gradient != null)
            {
                var testFuncGrad = m_MaxCodBasis_Gradient.EvaluateGradient(QR.Nodes);
                m_TestFuncGradWeighted.Multiply(1.0, QR.Weights, testFuncGrad, 0.0, "knd", "k", "knd");
            }
            this.Basis_Eval.Stop();

            // ==========================================
            // multiply with test functions / save result
            // ==========================================

            MultidimensionalArray OrthoTrf = null; // to transform back to ONB on physical space...
            int iBufOrthoTrf;
            if (isAffine)
            {
                OrthoTrf = TempBuffer.GetTempMultidimensionalarray(out iBufOrthoTrf, Length);
                OrthoTrf.Multiply(1.0,
                                  grid.iGeomCells.JacobiDet.ExtractSubArrayShallow(new int[] { i0 }, new int[] { i0 + Length - 1 }),
                                  grid.ChefBasis.Scaling.ExtractSubArrayShallow(new int[] { i0 }, new int[] { i0 + Length - 1 }),
                                  0.0,
                                  "j", "j", "j");
            }
            else
            {
                int MaxDegree = Math.Max(this.m_MaxCodBasis != null ? m_MaxCodBasis.Degree : 0, this.m_MaxCodBasis_Gradient != null ? m_MaxCodBasis_Gradient.Degree : 0);
                OrthoTrf     = grid.ChefBasis.OrthonormalizationTrafo.GetValue_Cell(i0, Length, MaxDegree);
                iBufOrthoTrf = int.MinValue;
            }

            this.Loops.Start();
            int N0, N;
            N0 = 0;
            for (int e = 0; e < NoOfEquations; e++)   // loop over equations...

            {
                if (geom2log != null)
                {
                    N = m_CodomainBasisS[e].GetLength(geom2log[i0]);
                }
                else
                {
                    N = m_CodomainBasisS[e].GetLength(i0);
                }

                int iBuf;
                MultidimensionalArray QuadResult_e = TempBuffer.GetTempMultidimensionalarray(out iBuf, Length, N);

                // fluxes
                // ------
                if (RequireTestFunctionGradient[e])
                {
                    MultidimensionalArray
                        Fluxes_e       = m_FluxValuesTrf[e],
                        testFuncGrad_e = null;
                    if (m_TestFuncGradWeighted.GetLength(1) == N)
                    {
                        testFuncGrad_e = m_TestFuncGradWeighted;
                    }
                    else
                    {
                        testFuncGrad_e = m_TestFuncGradWeighted.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { NoOfNodes - 1, N - 1, D - 1 });
                    }

                    QuadResult_e.Multiply(1.0, Fluxes_e, testFuncGrad_e, 0.0, "jn", "jke", "kne");
                }

                // sources
                // -------

                if (RequireTestfunction[e])
                {
                    MultidimensionalArray
                        SourceValues_e = m_SourceValues[e],
                        testFunc_e     = null;
                    if (m_TestFuncWeighted.GetLength(1) == N)
                    {
                        testFunc_e = m_TestFuncWeighted;
                    }
                    else
                    {
                        testFunc_e = m_TestFuncWeighted.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { NoOfNodes - 1, N - 1 });
                    }


                    QuadResult_e.Multiply(1.0, SourceValues_e, testFunc_e, 1.0, "jn", "jk", "kn");
                }

                // final transformations
                // ---------------------
                MultidimensionalArray trfQuadResult_e = QuadResult.ExtractSubArrayShallow(new int[] { 0, N0 }, new int[] { Length - 1, N0 + N - 1 });

                if (isAffine)
                {
                    trfQuadResult_e.Multiply(1.0, OrthoTrf, QuadResult_e, 0.0, "jn", "j", "jn");
                }
                else
                {
                    MultidimensionalArray _OrthoTrf;
                    if (OrthoTrf.GetLength(1) == N)
                    {
                        _OrthoTrf = OrthoTrf;
                    }
                    else
                    {
                        _OrthoTrf = OrthoTrf.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { Length - 1, N - 1, N - 1 });
                    }

                    trfQuadResult_e.Multiply(1.0, _OrthoTrf, QuadResult_e, 0.0, "jn", "jmn", "jm");
                }

                // next
                // ----

                TempBuffer.FreeTempBuffer(iBuf);
                N0 += N;
            }

            if (isAffine)
            {
                TempBuffer.FreeTempBuffer(iBufOrthoTrf);
            }

            this.Loops.Stop();

#if DEBUG
            QuadResult.CheckForNanOrInf(true, true, true);
#endif
        }
Example #2
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);
            }
        }
Example #3
0
        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);
             * }  */
        }
Example #4
0
        /// <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);
            }
        }