|
11 | 11 | function integral( |
12 | 12 | f, |
13 | 13 | plane::Meshes.Plane, |
14 | | - rule::GaussLegendre; |
15 | | - diff_method::DM = Analytical(), |
16 | | - FP::Type{T} = Float64 |
17 | | -) where {DM <: DifferentiationMethod, T <: AbstractFloat} |
18 | | - _guarantee_analytical(Meshes.Plane, diff_method) |
19 | | - |
20 | | - # Get Gauss-Legendre nodes and weights for a 2D region [-1,1]² |
21 | | - xs, ws = _gausslegendre(FP, rule.n) |
22 | | - wws = Iterators.product(ws, ws) |
23 | | - xxs = Iterators.product(xs, xs) |
24 | | - |
25 | | - # Normalize the Plane's orthogonal vectors |
26 | | - uu = Meshes.unormalize(plane.u) |
27 | | - uv = Meshes.unormalize(plane.v) |
28 | | - uplane = Meshes.Plane(plane.p, uu, uv) |
29 | | - |
30 | | - # Domain transformation: x ∈ [-1,1] ↦ t ∈ (-∞,∞) |
31 | | - t(x) = x / (1 - x^2) |
32 | | - t′(x) = (1 + x^2) / (1 - x^2)^2 |
33 | | - |
34 | | - # Integrate f over the Plane |
35 | | - domainunits = _units(uplane(0, 0)) |
36 | | - function integrand(((wi, wj), (xi, xj))) |
37 | | - wi * wj * f(uplane(t(xi), t(xj))) * t′(xi) * t′(xj) * domainunits^2 |
38 | | - end |
39 | | - return sum(integrand, zip(wws, xxs)) |
| 14 | + rule::IntegrationRule; |
| 15 | + kwargs... |
| 16 | +) |
| 17 | + # Generate a _ParametricGeometry whose parametric function spans the domain [0, 1]² |
| 18 | + param_plane = _ParametricGeometry(_parametric(plane), Meshes.paramdim(plane)) |
| 19 | + |
| 20 | + # Integrate the _ParametricGeometry using the standard methods |
| 21 | + return _integral(f, param_plane, rule; kwargs...) |
40 | 22 | end |
41 | 23 |
|
42 | | -function integral( |
43 | | - f, |
44 | | - plane::Meshes.Plane, |
45 | | - rule::GaussKronrod; |
46 | | - diff_method::DM = Analytical(), |
47 | | - FP::Type{T} = Float64 |
48 | | -) where {DM <: DifferentiationMethod, T <: AbstractFloat} |
49 | | - _guarantee_analytical(Meshes.Plane, diff_method) |
50 | | - |
51 | | - # Normalize the Plane's orthogonal vectors |
52 | | - uu = Meshes.unormalize(plane.u) |
53 | | - uv = Meshes.unormalize(plane.v) |
54 | | - uplane = Meshes.Plane(plane.p, uu, uv) |
55 | | - |
56 | | - # Integrate f over the Plane |
57 | | - domainunits = _units(uplane(0, 0))^2 |
58 | | - integrand(u, v) = f(uplane(u, v)) * domainunits |
59 | | - inner∫(v) = QuadGK.quadgk(u -> integrand(u, v), FP(-Inf), FP(Inf); rule.kwargs...)[1] |
60 | | - return QuadGK.quadgk(inner∫, FP(-Inf), FP(Inf); rule.kwargs...)[1] |
| 24 | +############################################################################################ |
| 25 | +# Parametric |
| 26 | +############################################################################################ |
| 27 | + |
| 28 | +# Map argument domain from [0, 1]² to (-∞, ∞)² for (::Plane)(t1, t2) |
| 29 | +function _parametric(plane::Meshes.Plane) |
| 30 | + # [-1, 1] ↦ (-∞, ∞) |
| 31 | + f1(t) = t / (1 - t^2) |
| 32 | + # [0, 1] ↦ [-1, 1] |
| 33 | + f2(t) = 2t - 1 |
| 34 | + # Compose the two transforms |
| 35 | + f = f1 ∘ f2 |
| 36 | + return (t1, t2) -> plane(f(t1), f(t2)) |
61 | 37 | end |
62 | | - |
63 | | -function integral( |
64 | | - f, |
65 | | - plane::Meshes.Plane, |
66 | | - rule::HAdaptiveCubature; |
67 | | - diff_method::DM = Analytical(), |
68 | | - FP::Type{T} = Float64 |
69 | | -) where {DM <: DifferentiationMethod, T <: AbstractFloat} |
70 | | - _guarantee_analytical(Meshes.Plane, diff_method) |
71 | | - |
72 | | - # Normalize the Plane's orthogonal vectors |
73 | | - uu = Meshes.unormalize(plane.u) |
74 | | - uv = Meshes.unormalize(plane.v) |
75 | | - uplane = Meshes.Plane(plane.p, uu, uv) |
76 | | - |
77 | | - # Domain transformation: x ∈ [-1,1] ↦ t ∈ (-∞,∞) |
78 | | - t(x) = x / (1 - x^2) |
79 | | - t′(x) = (1 + x^2) / (1 - x^2)^2 |
80 | | - |
81 | | - # Integrate f over the Plane |
82 | | - domainunits = _units(uplane(0, 0)) |
83 | | - function integrand(xs) |
84 | | - f(uplane(t(xs[1]), t(xs[2]))) * t′(xs[1]) * t′(xs[2]) * domainunits^2 |
85 | | - end |
86 | | - |
87 | | - # HCubature doesn't support functions that output Unitful Quantity types |
88 | | - # Establish the units that are output by f |
89 | | - testpoint_parametriccoord = zeros(FP, 2) |
90 | | - integrandunits = Unitful.unit.(integrand(testpoint_parametriccoord)) |
91 | | - # Create a wrapper that returns only the value component in those units |
92 | | - uintegrand(uv) = Unitful.ustrip.(integrandunits, integrand(uv)) |
93 | | - # Integrate only the unitless values |
94 | | - a = .-_ones(FP, 2) |
95 | | - b = _ones(FP, 2) |
96 | | - value = HCubature.hcubature(uintegrand, a, b; rule.kwargs...)[1] |
97 | | - |
98 | | - # Reapply units |
99 | | - return value .* integrandunits |
100 | | -end |
101 | | - |
102 | | -################################################################################ |
103 | | -# jacobian |
104 | | -################################################################################ |
105 | | - |
106 | | -_has_analytical(::Type{T}) where {T <: Meshes.Plane} = true |
0 commit comments