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