public static double SecondDerivative(SinglePhaseField field, int localCellIndex, NodeSet nodeSet)
        {
            // Evaluate gradient
            int length    = 1;
            int noOfNodes = 1;
            int D         = 2;
            MultidimensionalArray gradient = MultidimensionalArray.Create(length, noOfNodes, D);

            field.EvaluateGradient(localCellIndex, 1, nodeSet, gradient, ResultCellindexOffset: 0, ResultPreScale: 1.0);

            // Evalaute Hessian matrix
            MultidimensionalArray hessian = MultidimensionalArray.Create(length, noOfNodes, D, D);

            field.EvaluateHessian(localCellIndex, 1, nodeSet, hessian);

            // Compute second derivative along curve
            double g_alpha_alpha = 2 * ((hessian[0, 0, 0, 0] * gradient[0, 0, 0]
                                         + hessian[0, 0, 0, 1] * gradient[0, 0, 1])
                                        * gradient[0, 0, 0]
                                        + (hessian[0, 0, 1, 0] * gradient[0, 0, 0]
                                           + hessian[0, 0, 1, 1] * gradient[0, 0, 1])
                                        * gradient[0, 0, 1]);

            if (g_alpha_alpha == 0.0 || g_alpha_alpha.IsNaN())
            {
                throw new NotSupportedException("Second derivative is zero");
            }

            return(g_alpha_alpha);
        }
        public static double[] NormalizedGradient(SinglePhaseField field, int localCellIndex, NodeSet nodeSet)
        {
            // Evaluate gradient
            int length    = 1;
            int noOfNodes = 1;
            int D         = 2;
            MultidimensionalArray gradient = MultidimensionalArray.Create(length, noOfNodes, D);

            field.EvaluateGradient(localCellIndex, 1, nodeSet, gradient, ResultCellindexOffset: 0, ResultPreScale: 1.0);

            // Normalize gradient
            double[] tmp = gradient.ExtractSubArrayShallow(0, 0, -1).To1DArray();
            tmp.Normalize();
            return(tmp);
        }
        /// <summary>
        /// Evaluates the divergence of the modified integrand
        /// \f$
        /// \nabla \cdot \vec{g} = \nabla \cdot (g \frac{\nabla \Phi}{|\nabla \Phi|})
        /// \f$
        /// which can be expanded to
        /// \f$
        /// \nabla \cdot \vec{g} = \nabla g \frac{\nabla \Phi}{|\nabla \Phi|} + g (
        /// \frac{\Delta \Phi}{|\nabla \Phi|}
        /// - \frac{\nabla \Phi}{|\nabla \Phi|} \frac{H(\Phi)}{|\nabla \Phi|} \frac{\nabla \Phi}{|\nabla \Phi|})
        /// \f$
        /// using the chain rule. HEre, \f$ H(\Phi)\f$
        /// denotes the Hessian of the level set (i.e., the second derivatives)
        /// </summary>
        /// <param name="j0">
        /// <see cref="LevelSetIntegrator.EvaluateDivergenceOfIntegrand"/>
        /// </param>
        /// <param name="Length">
        /// <see cref="LevelSetIntegrator.EvaluateDivergenceOfIntegrand"/>
        /// </param>
        /// <param name="EvalResult">
        /// <see cref="LevelSetIntegrator.EvaluateDivergenceOfIntegrand"/>
        /// </param>
        public override void EvaluateDivergenceOfIntegrand(NodeSet nodes, int j0, int Length, MultidimensionalArray EvalResult)
        {
            using (new FuncTrace()) {
                int D         = base.m_LevSetTrk.GridDat.SpatialDimension; // spatial dimension
                int noOfNodes = EvalResult.GetLength(1);                   // number of nodes

                if (m_WeighFunctionBuffer.GetLength(0) != Length || m_WeighFunctionBuffer.GetLength(1) != noOfNodes)
                {
                    m_IntegrandBuffer.Allocate(Length, noOfNodes);
                    m_IntegrandGradientBuffer.Allocate(Length, noOfNodes, D);
                    m_WeighFunctionBuffer.Allocate(Length, noOfNodes);
                    m_LevelSetGradientBuffer.Allocate(Length, noOfNodes, D);
                    m_LevelSetHessianBuffer.Allocate(Length, noOfNodes, D, D);
                }

                m_Field.Evaluate(j0, Length, nodes, m_IntegrandBuffer);
                m_Field.EvaluateGradient(j0, Length, nodes, m_IntegrandGradientBuffer, 0, 0.0);
                m_levSet.EvaluateGradient(j0, Length, nodes, m_LevelSetGradientBuffer);
                m_levSet.EvaluateHessian(j0, Length, nodes, m_LevelSetHessianBuffer);

                EvaluateWeightFunction(nodes, j0, Length, m_WeighFunctionBuffer);

                double[] Buf = new double[D];

                for (int i = 0; i < Length; i++)
                {
                    for (int j = 0; j < noOfNodes; j++)
                    {
                        if (m_WeighFunctionBuffer[i, j] == 0.0)
                        {
                            continue;
                        }

                        double AbsGradPhi = 0.0;

                        for (int d = 0; d < D; d++)
                        {
                            double GradPhi_d = m_LevelSetGradientBuffer[i, j, d];
                            AbsGradPhi += GradPhi_d * GradPhi_d;
                        }
                        AbsGradPhi = Math.Sqrt(AbsGradPhi);
                        if (AbsGradPhi < 1e-11)
                        {
                            // Assume zero since gradient is nearly zero
                            continue;
                        }

                        double ooAbsGradPhi = 1.0 / AbsGradPhi;

                        double term1 = 0.0;
                        for (int d = 0; d < D; d++)
                        {
                            term1 += m_IntegrandGradientBuffer[i, j, d] * m_LevelSetGradientBuffer[i, j, d];
                        }
                        term1 *= ooAbsGradPhi;

                        double term2 = 0;
                        for (int d = 0; d < D; d++)
                        {
                            term2 += m_LevelSetHessianBuffer[i, j, d, d];
                        }
                        term2 *= ooAbsGradPhi;

                        double term3 = 0;
                        {
                            for (int d1 = 0; d1 < D; d1++)
                            {
                                double a = 0;
                                for (int d2 = 0; d2 < D; d2++)
                                {
                                    a += m_LevelSetHessianBuffer[i, j, d1, d2] * m_LevelSetGradientBuffer[i, j, d2];
                                }
                                Buf[d1] = a;
                            }

                            for (int d = 0; d < D; d++)
                            {
                                term3 += Buf[d] * m_LevelSetGradientBuffer[i, j, d];
                            }

                            term3 *= (ooAbsGradPhi * ooAbsGradPhi * ooAbsGradPhi);
                        }

                        EvalResult[i, j, 0] = term1 + m_IntegrandBuffer[i, j] * (term2 - term3);
                    }
                }
            }
        }