/// <summary>
        /// Approximates a 2-dimensional definite integral using an Nth order Gauss-Legendre rule over the rectangle [a,b] x [c,d].
        /// </summary>
        /// <param name="f">The 2-dimensional analytic smooth function to integrate.</param>
        /// <param name="invervalBeginA">Where the interval starts for the first (inside) integral, exclusive and finite.</param>
        /// <param name="invervalEndA">Where the interval ends for the first (inside) integral, exclusive and finite.</param>
        /// <param name="invervalBeginB">Where the interval starts for the second (outside) integral, exclusive and finite.</param>
        /// /// <param name="invervalEndB">Where the interval ends for the second (outside) integral, exclusive and finite.</param>
        /// <param name="order">Defines an Nth order Gauss-Legendre rule. The order also defines the number of abscissas and weights for the rule. Precomputed Gauss-Legendre abscissas/weights for orders 2-20, 32, 64, 96, 100, 128, 256, 512, 1024 are used, otherwise they're calculated on the fly.</param>
        /// <returns>Approximation of the finite integral in the given interval.</returns>
        public static double Integrate(Func <double, double, double> f, double invervalBeginA, double invervalEndA, double invervalBeginB, double invervalEndB, int order)
        {
            GaussPoint gaussLegendrePoint = GaussLegendrePointFactory.GetGaussPoint(order);

            double ax, cy, sum;
            int    i, j;
            int    m = (order + 1) >> 1;

            double a = 0.5 * (invervalEndA - invervalBeginA);
            double b = 0.5 * (invervalEndA + invervalBeginA);
            double c = 0.5 * (invervalEndB - invervalBeginB);
            double d = 0.5 * (invervalEndB + invervalBeginB);

            if (order.IsOdd())
            {
                sum = gaussLegendrePoint.Weights[0] * gaussLegendrePoint.Weights[0] * f(b, d);

                double t;
                for (j = 1, t = 0.0; j < m; j++)
                {
                    cy = c * gaussLegendrePoint.Abscissas[j];
                    t += gaussLegendrePoint.Weights[j] * (f(b, d + cy) + f(b, d - cy));
                }

                sum += gaussLegendrePoint.Weights[0] * t;

                for (i = 1, t = 0.0; i < m; i++)
                {
                    ax = a * gaussLegendrePoint.Abscissas[i];
                    t += gaussLegendrePoint.Weights[i] * (f(b + ax, d) + f(b - ax, d));
                }

                sum += gaussLegendrePoint.Weights[0] * t;

                for (i = 1; i < m; i++)
                {
                    ax = a * gaussLegendrePoint.Abscissas[i];
                    for (j = 1; j < m; j++)
                    {
                        cy   = c * gaussLegendrePoint.Abscissas[j];
                        sum += gaussLegendrePoint.Weights[i] * gaussLegendrePoint.Weights[j] * (f(b + ax, d + cy) + f(ax + b, d - cy) + f(b - ax, d + cy) + f(b - ax, d - cy));
                    }
                }
            }
            else
            {
                sum = 0.0;
                for (i = 0; i < m; i++)
                {
                    ax = a * gaussLegendrePoint.Abscissas[i];
                    for (j = 0; j < m; j++)
                    {
                        cy   = c * gaussLegendrePoint.Abscissas[j];
                        sum += gaussLegendrePoint.Weights[i] * gaussLegendrePoint.Weights[j] * (f(b + ax, d + cy) + f(ax + b, d - cy) + f(b - ax, d + cy) + f(b - ax, d - cy));
                    }
                }
            }

            return(c * a * sum);
        }
        /// <summary>
        /// Approximates a definite integral using an Nth order Gauss-Legendre rule.
        /// </summary>
        /// <param name="f">The analytic smooth complex function to integrate, defined on the real domain.</param>
        /// <param name="invervalBegin">Where the interval starts, exclusive and finite.</param>
        /// <param name="invervalEnd">Where the interval ends, exclusive and finite.</param>
        /// <param name="order">Defines an Nth order Gauss-Legendre rule. The order also defines the number of abscissas and weights for the rule. Precomputed Gauss-Legendre abscissas/weights for orders 2-20, 32, 64, 96, 100, 128, 256, 512, 1024 are used, otherwise they're calculated on the fly.</param>
        /// <returns>Approximation of the finite integral in the given interval.</returns>
        public static Complex ContourIntegrate(Func <double, Complex> f, double invervalBegin, double invervalEnd, int order)
        {
            GaussPoint gaussLegendrePoint = GaussLegendrePointFactory.GetGaussPoint(order);

            Complex sum;
            double  ax;
            int     i;
            int     m = (order + 1) >> 1;

            double a = 0.5 * (invervalEnd - invervalBegin);
            double b = 0.5 * (invervalEnd + invervalBegin);

            if (order.IsOdd())
            {
                sum = gaussLegendrePoint.Weights[0] * f(b);
                for (i = 1; i < m; i++)
                {
                    ax   = a * gaussLegendrePoint.Abscissas[i];
                    sum += gaussLegendrePoint.Weights[i] * (f(b + ax) + f(b - ax));
                }
            }
            else
            {
                sum = 0.0;
                for (i = 0; i < m; i++)
                {
                    ax   = a * gaussLegendrePoint.Abscissas[i];
                    sum += gaussLegendrePoint.Weights[i] * (f(b + ax) + f(b - ax));
                }
            }

            return(a * sum);
        }
Пример #3
0
        /// <summary>
        /// Maps the non-negative abscissas/weights from the interval [-1, 1] to the interval [intervalBegin, intervalEnd].
        /// </summary>
        /// <param name="gaussPoint">Object containing the non-negative abscissas/weights, order, and intervalBegin/intervalEnd. The non-negative abscissas/weights are generated over the interval [-1,1] for the given order.</param>
        /// <param name="intervalBegin">Where the interval starts, inclusive and finite.</param>
        /// <param name="intervalEnd">Where the interval stops, inclusive and finite.</param>
        /// <returns>Object containing the abscissas/weights, order, and intervalBegin/intervalEnd.</returns>
        private static GaussPoint Map(GaussPoint gaussPoint, double intervalBegin, double intervalEnd)
        {
            double[] abscissas = new double[gaussPoint.Order];
            double[] weights   = new double[gaussPoint.Order];

            double a = 0.5 * (intervalEnd - intervalBegin);
            double b = 0.5 * (intervalEnd + intervalBegin);

            int m = (gaussPoint.Order + 1) >> 1;

            for (int i = 1; i <= m; i++)
            {
                int index1 = gaussPoint.Order - i;
                int index2 = i - 1;
                int index3 = m - i;

                abscissas[index1] = gaussPoint.Abscissas[index3] * a + b;
                abscissas[index2] = -gaussPoint.Abscissas[index3] * a + b;

                weights[index1] = gaussPoint.Weights[index3] * a;
                weights[index2] = gaussPoint.Weights[index3] * a;
            }

            return(new GaussPoint(intervalBegin, intervalEnd, gaussPoint.Order, abscissas, weights));
        }
        // These triangles are output by the delauny triangulation and the order of their nodes might be
        // counter-clockwise or clockwise. In the second case the jacobian will be negative,
        // but it doesn't matter otherwise.
        private IReadOnlyList <GaussPoint> GenerateIntegrationPointsOfTriangle(Triangle2D <NaturalPoint> triangle)
        {
            // Coordinates of the triangle's nodes in the natural system of the element
            double xi1  = triangle.Vertices[0].Xi;
            double eta1 = triangle.Vertices[0].Eta;
            double xi2  = triangle.Vertices[1].Xi;
            double eta2 = triangle.Vertices[1].Eta;
            double xi3  = triangle.Vertices[2].Xi;
            double eta3 = triangle.Vertices[2].Eta;

            // Determinant of the Jacobian of the linear mapping from the natural system of the triangle  to the
            // natural system of the element. If the triangle's nodes are in clockwise order, the determinant will be
            // negative. It doesn't matter since its absolute value is used for integration with change of variables.
            double jacobian = Math.Abs(xi1 * (eta2 - eta3) + xi2 * (eta3 - eta1) + xi3 * (eta1 - eta2));

            var triangleGaussPoints = triangleIntegrationRule.IntegrationPoints;
            var elementGaussPoints  = new GaussPoint[triangleGaussPoints.Count];

            for (int i = 0; i < triangleGaussPoints.Count; ++i)
            {
                GaussPoint triangleGP = triangleGaussPoints[i];

                // Linear shape functions evaluated at the Gauss point's coordinates in the triangle's natural system.
                double N1 = 1.0 - triangleGP.Xi - triangleGP.Eta;
                double N2 = triangleGP.Xi;
                double N3 = triangleGP.Eta;

                // Coordinates of the same gauss point in the element's natural system
                double elementXi  = N1 * xi1 + N2 * xi2 + N3 * xi3;
                double elementEta = N1 * eta1 + N2 * eta2 + N3 * eta3;

                // The integral would need to be multiplicated with |detJ|.
                // It is simpler for the caller to have it already included in the weight.
                double elementWeight = triangleGP.Weight * jacobian;

                elementGaussPoints[i] = new GaussPoint(elementXi, elementEta, elementWeight);
            }

            return(elementGaussPoints);
        }
        private IReadOnlyList <Matrix> EvaluateNaturalGradientsAtGaussPoints(IQuadrature1D quadrature)
        {
            bool isCached = cachedNaturalGradientsAtGPs.TryGetValue(quadrature,
                                                                    out IReadOnlyList <Matrix> naturalGradientsAtGPs);

            if (isCached)
            {
                return(naturalGradientsAtGPs);
            }
            else
            {
                int numGPs = quadrature.IntegrationPoints.Count;
                var naturalGradientsAtGPsArray = new Matrix[numGPs];
                for (int gp = 0; gp < numGPs; ++gp)
                {
                    GaussPoint gaussPoint = quadrature.IntegrationPoints[gp];
                    naturalGradientsAtGPsArray[gp] = EvaluateGradientsAt();
                }
                cachedNaturalGradientsAtGPs.Add(quadrature, naturalGradientsAtGPsArray);
                return(naturalGradientsAtGPsArray);
            }
        }
        public IReadOnlyList <Vector> EvaluateFunctionsAtGaussPoints(IQuadrature1D quadrature)
        {
            bool isCached = cachedFunctionsAtGPs.TryGetValue(quadrature,
                                                             out IReadOnlyList <Vector> shapeFunctionsAtGPs);

            if (isCached)
            {
                return(shapeFunctionsAtGPs);
            }
            else
            {
                int numGPs = quadrature.IntegrationPoints.Count;
                var shapeFunctionsAtGPsArray = new Vector[numGPs];
                for (int gp = 0; gp < numGPs; ++gp)
                {
                    GaussPoint gaussPoint = quadrature.IntegrationPoints[gp];
                    shapeFunctionsAtGPsArray[gp] = Vector.CreateFromArray(EvaluateAt(gaussPoint.Xi));
                }
                cachedFunctionsAtGPs.Add(quadrature, shapeFunctionsAtGPsArray);
                return(shapeFunctionsAtGPsArray);
            }
        }
Пример #7
0
        /// <summary>
        /// See <see cref="IIsoparametricInterpolation2D.EvaluateFunctionsAtGaussPoints(IQuadrature2D)"/>.
        /// </summary>
        public IReadOnlyList <double[]> EvaluateFunctionsAtGaussPoints(IQuadrature2D quadrature)
        {
            bool isCached = cachedFunctionsAtGPs.TryGetValue(quadrature,
                                                             out IReadOnlyList <double[]> shapeFunctionsAtGPs);

            if (isCached)
            {
                return(shapeFunctionsAtGPs);
            }
            else
            {
                int numGPs = quadrature.IntegrationPoints.Count;
                var shapeFunctionsAtGPsArray = new double[numGPs][];
                for (int gp = 0; gp < numGPs; ++gp)
                {
                    GaussPoint gaussPoint = quadrature.IntegrationPoints[gp];
                    shapeFunctionsAtGPsArray[gp] = EvaluateAt(gaussPoint.Xi, gaussPoint.Eta);
                }
                cachedFunctionsAtGPs.Add(quadrature, shapeFunctionsAtGPsArray);
                return(shapeFunctionsAtGPsArray);
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="GaussLegendreRule"/> class.
 /// </summary>
 /// <param name="intervalBegin">Where the interval starts, inclusive and finite.</param>
 /// <param name="intervalEnd">Where the interval stops, inclusive and finite.</param>
 /// <param name="order">Defines an Nth order Gauss-Legendre rule. The order also defines the number of abscissas and weights for the rule. Precomputed Gauss-Legendre abscissas/weights for orders 2-20, 32, 64, 96, 100, 128, 256, 512, 1024 are used, otherwise they're calculated on the fly.</param>
 public GaussLegendreRule(double intervalBegin, double intervalEnd, int order)
 {
     _gaussLegendrePoint = GaussLegendrePointFactory.GetGaussPoint(intervalBegin, intervalEnd, order);
 }