Skip to content

Commit 38893e7

Browse files
Improve documentation (#165)
* Remove current docs index.md * New index.md as symlink to README * Update example/demo * Rearrange and relabel the Support Matrix, update notes * Change naming of Support Status * Overhaul usage into new Tutorial page * Apply suggestions from code review Co-authored-by: Joshua Lampert <[email protected]> * Add a link to juliadocs for do syntax * Convert to example blocks Co-authored-by: Joshua Lampert <[email protected]> * Add Meshes and Unitful to docs Project * Convert another block * Try a jldoctest * Add repl prompts * Revert to static code block * Reorganize files * Add a placeholder page for integration rules * Add some draft contents * Add some more notes * Remove unneeded comment * Add a Tips page * Add links to sections * fix typo * Apply suggestion Co-authored-by: Joshua Lampert <[email protected]> * Change page order * Clarify that atol tip affects both adaptive solvers * Add more notes to tip * Update language * Add a tip for AutoEnzyme * Update docs/src/tips.md Co-authored-by: Joshua Lampert <[email protected]> * Convert code blocks to repl blocks * Add compats * Update docs/Project.toml Co-authored-by: Joshua Lampert <[email protected]> --------- Co-authored-by: Joshua Lampert <[email protected]>
1 parent 29c87ef commit 38893e7

14 files changed

+328
-158
lines changed

README.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Performs a numerical integration of some integrand function `f` over the domain
3030
```julia
3131
integral(f, geometry, rule)
3232
```
33-
Performs a numerical integration of some integrand function `f` over the domain specified by `geometry` using the specified integration rule, e.g. `GaussKronrod()`. The integrand function can be anything callable with a method `f(::Meshes.Point)`.
33+
Performs a numerical integration of some integrand function `f` over the domain specified by `geometry` using the specified integration rule, e.g. `GaussKronrod()`. The integrand function can be anything callable with a method `f(::Meshes.Point)`.
3434

3535
Additionally, several optional keyword arguments are defined in [the API](https://juliageometry.github.io/MeshIntegrals.jl/stable/api/) to provide additional control over the integration mechanics.
3636

@@ -46,24 +46,30 @@ Alias functions are provided for convenience. These are simply wrappers for `int
4646
- `surfaceintegral` is used for surfaces (e.g. `Disk`, `Sphere`, `CylinderSurface`, etc)
4747
- `volumeintegral` is used for (3D) volumes (e.g. `Ball`, `Cone`, `Torus`, etc)
4848

49-
# Demo
49+
### Example
5050

5151
```julia
5252
using Meshes
5353
using MeshIntegrals
5454
using Unitful
5555

56-
# Define a path that approximates a sine-wave on the xy-plane
57-
mypath = BezierCurve(
58-
[Point(t*u"m", sin(t)*u"m", 0.0u"m") for t in range(-pi, pi, length=361)]
59-
)
56+
# Define a Bezier curve whose path approximates a sine-wave on the xy-plane
57+
N = 361
58+
curve = BezierCurve([Point(t*u"m", sin(t)*u"m", 0.0u"m") for t in range(-π, π, length=N)])
6059

61-
# Map f(::Point) -> f(x, y, z) in unitless coordinates
62-
f(p::Meshes.Point) = f(ustrip(to(p))...)
60+
# Integrand function that outputs in units of Ohms/meter
61+
function f(p::Point)
62+
x, y, z = to(p)
63+
return (1 / sqrt(1 + cos(x / u"m")^2)) * u"Ω/m"
64+
end
6365

64-
# Integrand function in units of Ohms/meter
65-
f(x, y, z) = (1 / sqrt(1 + cos(x)^2)) * u"Ω/m"
66+
# Use recommended defaults
67+
integral(f, curve) # -> Approximately 2π Ω
6668

67-
integral(f, mypath)
68-
# -> Approximately 2*Pi Ω
69+
# Using aliases
70+
lineintegral(f, curve) # -> Approximately 2π Ω
71+
surfaceintegral(f, curve) # -> throws ArgumentError
72+
73+
# Specifying an integration rule and settings (loosened absolute tolerance)
74+
integral(f, curve, GaussKronrod(atol = 1e-4u"Ω")) # -> Approximately (2π ± 1e-4) Ω
6975
```

docs/Project.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
[deps]
2+
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
23
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
4+
Meshes = "eacbb407-ea5a-433e-ab97-5258b1ca43fa"
35
MeshIntegrals = "dadec2fd-bbe0-4da4-9dbe-476c782c8e47"
6+
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
7+
8+
[compat]
9+
BenchmarkTools = "1"
10+
Documenter = "1"
11+
Meshes = "0.51.20, 0.52"
12+
Unitful = "1.19"
13+
julia = "1.9"

docs/make.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ makedocs(
1111
pages = [
1212
"Home" => [
1313
"About" => "index.md",
14-
"Support Matrix" => "supportmatrix.md",
15-
"Example Usage" => "usage.md"
14+
"Tutorial" => "tutorial.md",
15+
"Integration Rules" => "integration_rules.md",
16+
"Support Status" => "support.md",
17+
"Tips" => "tips.md"
1618
],
1719
"Developer Notes" => [
18-
"Changelog" => "CHANGELOG.md",
19-
"How it Works" => "how_it_works.md",
20-
"Specializations" => "specializations.md"
20+
"Changelog" => "developer/CHANGELOG.md",
21+
"How it Works" => "developer/how_it_works.md",
22+
"Specializations" => "developer/specializations.md"
2123
],
2224
"Public API" => "api.md"
2325
]

docs/src/CHANGELOG.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/src/developer/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../CHANGELOG.md

docs/src/how_it_works.md renamed to docs/src/developer/how_it_works.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# How it Works (By Example)
1+
# [How it Works](@id howitworks)
22

33
## Example Problem
44

File renamed without changes.

docs/src/index.md

Lines changed: 0 additions & 47 deletions
This file was deleted.

docs/src/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../README.md

docs/src/integration_rules.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Integration Rules
2+
3+
An **integration rule** is a method or algorithm used to numerically calculate the value of an integral. When an integral is calculated using the two-argument form `integral(f, geometry)`, **MeshIntegrals.jl** will automatically select an integration rule. Default rules are generally well-behaved, but may not be optimal for every problem.
4+
5+
**MeshIntegrals.jl** defines an abstract type `IntegrationRule` with sub-types representing the various integration rules supported by this package. These rules can be specified when calculating an integral using the three-argument form `integral(f, geometry, rule)`. Currently, the following rule types are implemented:
6+
- [`GaussKronrod`](@ref gausskronrod) for adaptive Gauss-Kronrod quadrature rules
7+
- [`GaussLegendre`](@ref gausslegendre) for Gauss-Legendre quadrature rules
8+
- [`HAdaptiveCubature`](@ref hadaptivecubature) for h-adaptive cubature rules
9+
10+
## [Gauss-Kronrod](@id gausskronrod)
11+
12+
The `GaussKronrod` type is used to specify an adaptive Gauss-Kronrod quadrature rule, as implemented by [QuadGK.jl](https://github.com/JuliaMath/QuadGK.jl).
13+
14+
```julia
15+
rule = GaussKronrod()
16+
```
17+
18+
All standard `QuadGK.quadgk` keyword-argument options are supported. These can be specified when constructing the rule, where the `kwargs` in `GaussKronrod(kwargs...)` is equivalent to `quadgk(f, a, b; kwargs...)`, e.g.:
19+
```julia
20+
rule = GaussKronrod(order = 5, rtol = 1e-4)
21+
```
22+
23+
## [Gauss-Legendre](@id gausslegendre)
24+
25+
The `GaussLegendre` type is used to specify a [Gauss-Legendre quadrature](https://en.wikipedia.org/wiki/Gauss%E2%80%93Legendre_quadrature) rule. Gauss-Legendre quadrature rules of order $N$ are used to approximate definite integrals by sampling the integrand on a fixed grid with corresponding nodes $x_i$ and weights $w_i$.
26+
```math
27+
\int_{-1}^1 f(x) ~\text{d}x \approx \sum_{i=1}^N w_i \, f(x_i)
28+
```
29+
30+
These nodes and weights are purely a function of $N$ as they are derived from the roots of $N$-th order Legendre polynomials. This has the effect of providing exact solutions for integrand functions $f$ that can be represented as degree $2N-1$ polynomials.
31+
32+
This integration process can also be extended into multiple dimensions, for example:
33+
```math
34+
\int_{-1}^1 \int_{-1}^1 \int_{-1}^1 f(x, y, z) ~\text{d}x ~\text{d}y ~\text{d}z \approx \sum_{i=1}^N \sum_{j=1}^N \sum_{k=1}^N w_i\,w_j\,w_k \, f(x_i, y_i, z_i)
35+
```
36+
37+
MeshIntegrals.jl uses [FastGaussQuadrature.jl](https://github.com/JuliaApproximation/FastGaussQuadrature.jl) to efficiently compute Gauss-Legendre quadrature nodes and weights at the time a `GaussLegendre` rule is constructed. Once constructed, these rules can be re-used to calculate multiple integrals to improve performance. Additionally, MeshIntegrals.jl uses an allocation-free summation routine that further improves performance by avoiding storing intermediate results.
38+
```julia
39+
rule = GaussLegendre(N)
40+
```
41+
42+
By contrast to adaptive integration rules where compute times can sometimes vary significantly, this technique has the advantage that compute times are much more predictable. For example, calculating a one-dimensional integral whose integrand $f$ can be computed in 10 microseconds using a `GaussLegendre(100)` can be expected to take approximately 1 millisecond. However, this lacks many of the guard-rails present in adaptive routines: results are not automatically checked to ensure convergence, so care must be taken to ensure that an appropriate rule and order are chosen.
43+
44+
## [H-Adaptive Cubature](@id hadaptivecubature)
45+
46+
The `HAdaptiveCubature` type is used to specify an h-adaptive cubature rule, as implemented by [HCubature.jl](https://github.com/JuliaMath/HCubature.jl).
47+
48+
```julia
49+
rule = HAdaptiveCubature()
50+
```
51+
52+
All standard `HCubature.hcubature` keyword-argument options are supported. These can be specified when constructing the rule, where the `kwargs` in `HAdaptiveCubature(kwargs...)` is equivalent to `hcubature(f, a, b; kwargs...)`, e.g.:
53+
```julia
54+
rule = HAdaptiveCubature(order = 5, rtol = 1e-4)
55+
```

0 commit comments

Comments
 (0)