Skip to content

Commit

Permalink
Test workflow + custom metric docs (#28)
Browse files Browse the repository at this point in the history
* custom metric documentation

* re-enable test workflow

* some referencing fixes

* compat version for VoronoiCells

* print manifest to terminal

* add GeometricalPredicates to Project

* cat the manifest in the right place

* pin an older version of GeometricalPredicates

* change matrix of machines

* remove compat

* tweak tolerances

* debug show and lower tolerances again

* actually print the right thing this time

* no fast math during tests and check bounds

* julia formatting

* test environment flags

* fix yaml syntax

* don't test on macOS
  • Loading branch information
fjebaker authored Jun 4, 2022
1 parent b5b0698 commit a54e037
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 64 deletions.
93 changes: 49 additions & 44 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,48 +1,53 @@
# name: Test
name: Test

# on:
# pull_request:
# branches:
# - main
# paths:
# - '**.jl'
# push:
# branches:
# - main
# paths:
# - '**.jl'
on:
pull_request:
branches:
- main
paths:
- '**.jl'
push:
branches:
- main
paths:
- '**.jl'

# jobs:
jobs:

# smoke-test:
# runs-on: ${{ matrix.os }}
# strategy:
# matrix:
# julia-version: ['1.7']
# julia-arch: [x86]
# os: [ubuntu-latest]
smoke-test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: ['1.7']
os: [ubuntu-latest]

# steps:
# - uses: actions/checkout@v2
# - uses: julia-actions/setup-julia@v1
# with:
# version: ${{ matrix.julia-version }}
# arch: ${{ matrix.julia-arch }}
# - uses: actions/cache@v1
# env:
# cache-name: cache-artifacts
# with:
# path: ~/.julia/artifacts
# key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
# restore-keys: |
# ${{ runner.os }}-test-${{ env.cache-name }}-
# ${{ runner.os }}-test-
# ${{ runner.os }}-
# - uses: julia-actions/julia-buildpkg@v1
# - uses: julia-actions/julia-runtest@v1
# - uses: julia-actions/julia-processcoverage@v1
# with:
# directories: src
# - uses: codecov/codecov-action@v2
# with:
# files: lcov.info
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.julia-version }}
- uses: actions/cache@v1
env:
cache-name: cache-artifacts
with:
path: ~/.julia/artifacts
key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }}
restore-keys: |
${{ runner.os }}-test-${{ env.cache-name }}-
${{ runner.os }}-test-
${{ runner.os }}-
- uses: julia-actions/julia-buildpkg@v1
- run: cat Manifest.toml
#- uses: julia-actions/julia-runtest@v1
- run: |
julia --color=yes --math-mode=ieee --check-bounds=yes --project=. -e '
import Pkg
Pkg.test(; coverage=true, force_latest_compatible_version=true)
'
- uses: julia-actions/julia-processcoverage@v1
with:
directories: src
- uses: codecov/codecov-action@v2
with:
files: lcov.info
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
ThreadsX = "ac1d9e8a-700a-412c-b207-f0111f4b6c0d"
Tullio = "bc48ee85-29a4-5162-ae0b-a64e1601d4bc"
VoronoiCells = "e3e34ffb-84e9-5012-9490-92c94d0c60a4"
VoronoiCells = "e3e34ffb-84e9-5012-9490-92c94d0c60a4"
11 changes: 8 additions & 3 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ makedocs(
"Home" => "index.md",
"Overview" => [
# "Examples"
"Geodesic integration" => "overview/geodesic-integration.md"
"Implemented metrics" => "overview/metrics.md"
# "Tracing"
# "Rendering"
"Point Functions" => "overview/point-functions.md",
# "Callbacks"
"Available metrics" => "overview/metrics.md"
],
# "Reverberation Lags"
"Internals" => [
"Custom metrics" => "internals/custom-metrics.md"
"Geodesic integration" => "overview/geodesic-integration.md",
"Implementing new metrics" => "internals/custom-metrics.md",
],
"Module API" => [
"Gradus" => "api-documentation/Gradus.md",
Expand Down
62 changes: 58 additions & 4 deletions docs/src/internals/custom-metrics.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,67 @@
# Defining a new metric
# Implementing a new metric

```@meta
CurrentModule = Gradus
```

Gradus.jl is able to integrate any 3+1 dimensional metric, however provides a few derivative abstract types to implement to ensure the most efficient code is executed for a given metric. Currently, Gradus differentiates the following specializations:
Gradus.jl is able to integrate any 3+1 dimensional metric. A new metric may be defined by implementing one of the abstract types with a concrete type, and defining a number of methods. Depending on what you want to be able to do with a metric, different functions need to be implemented.

Gradus also provides a few derivative abstract types to implement to ensure the most efficient code is executed for a given metric (see [Metric parameter types](@ref) below).

## First-Order
## Example: Schwarzschild

As a minimal example, here is how the Schwarzschild metric may be implemented. First, we must define what the _metric parameters_ for this metric are. These are effectively constants of the spacetime, representing physical quantities that appear in the metric expression. For the Schwarzschild metric, this is only the black hole mass ``M``, but e.g. the Kerr metric also has the black hole spin ``a``.

We can choose the integration strategy by sub-typing an abstract type representing different classes of spacetimes. For the Schwarzschild metric, we will use the static, axis-symmetric class, with the automatic differentiation (AD) backend. With AD, we only need to specify the non-zero components of the metric as Julia functions, and the rest is done for us.

For ease, we choose the [Eddington-Finkelstein coordinates](https://en.wikipedia.org/wiki/Eddington%E2%80%93Finkelstein_coordinates) of the Schwarzschild solution, which may be written

```math
\text{d}s^2 =
- \left( 1 - \frac{2 M}{r} \right) \text{d}t^2
+ \left( 1 - \frac{2 M}{r} \right)^{-1} \text{d}r^2
+ r^2 \text{d}\theta^2
+ r^2 \sin^2(\theta) \text{d}\phi^2.
```

Here is a possible implementation for Gradus.jl:
```julia
using Gradus

@with_kw struct EddingtonFinkelsteinAD{T} <: AbstractAutoDiffStaticAxisSymmetricParams{T}
M = 1.0
end

function GeodesicTracer.metric_components(m::EddingtonFinkelsteinAD{T}, rθ) where {T}
(r, θ) =
M = m.M

tt = 1 - (2M / r)
rr = inv(tt)
θθ = r^2
ϕϕ = r^2 * sin(θ)^2

(tt, rr, θθ, ϕϕ, T(0.0))
end

GradusBase.inner_radius(m::BoyerLindquistAD{T}) where {T} = 2 * m.M
```
A few notes:
- We use `@with_kw` from [Parameters.jl](https://github.com/mauro3/Parameters.jl) to define various utility constructors for us.
- [`GeodesicTracer.metric_components`](@ref) must return five elements for [`AbstractAutoDiffStaticAxisSymmetricParams`](@ref), where the last element is the off-axis ``g_{t \phi}`` matrix element, which in this case is always 0.
- The [`GradusBase.inner_radius`](@ref) function defines the inner-radius of integration chart. This defines where the integration should terminate to avoid running indefinitely, and is, in this case, set to the event-horizon of our metric.

That's all we need! This metric is now ready to be traced in the usual way.

!!! note
For more examples of how to implement different metrics, click on the "source" button of a metric in [Implemented Metrics](@ref). Alternatively, view the source code directly [here](https://github.com/astro-group-bristol/Gradus.jl/tree/main/src/metrics).


## Metric parameter types

The following types may be implemented to add new metrics. Each type has different requirements for its interface.

### First-Order

```@docs
FirstOrderMethods.AbstractFirstOrderMetricParams
Expand All @@ -17,7 +71,7 @@ FirstOrderMethods.Vr
FirstOrderMethods.Vθ
```

## Second-Order
### Second-Order

```@docs
GeodesicTracer.AbstractAutoDiffMetricParams
Expand Down
6 changes: 6 additions & 0 deletions docs/src/overview/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
CurrentModule = Gradus
```

Gradus.jl implements a library of metrics ready to use for integrations and rendering.


!!! note
To implement your own custom metrics, please see [Implementing a new metric](@ref).

## First-Order
```@docs
BoyerLindquistFO
Expand Down
1 change: 1 addition & 0 deletions docs/src/overview/point-functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Point functions
3 changes: 1 addition & 2 deletions src/GeodesicTracer/GeodesicTracer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ using StaticArrays
using DocStringExtensions
using Parameters

import ..GradusBase:
AbstractMetricParams, geodesic_eq, constrain, inner_radius, metric
import ..GradusBase: AbstractMetricParams, geodesic_eq, constrain, inner_radius, metric

import ForwardDiff

Expand Down
4 changes: 2 additions & 2 deletions test/smoke-tests/disc-profiles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
352.20220398142754,
]

@test all(isapprox.(areas1, expected_areas))
@test all(isapprox.(areas2, expected_areas))
@test all(isapprox.(areas1, expected_areas, atol = 1e-3))
@test all(isapprox.(areas2, expected_areas, atol = 1e-3))

end
end
12 changes: 6 additions & 6 deletions test/smoke-tests/rendergeodesics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
for (m, expectation) in zip(
[BoyerLindquistAD(), JohannsenAD(), BoyerLindquistFO(), MorrisThorneAD()],
# expectation values for the sum of the image
# last computed 29/04/2022: corrected impact parameter mapping
[8966.172562862197, 8966.172929103566, 8977.500037031317, 413.49944125849277],
# last computed 04/06/2022: tests with --math-mode=ieee
[8969.1564582409967, 8969.15634220181, 8977.502920124776, 413.49634341337264],
)
img = rendergeodesics(
m,
Expand All @@ -22,7 +22,7 @@
image_fingerprint = sum(filter(!isnan, img))
# have to be really coarse cus the first order method is so variable???
# the rest are very resolute
@test isapprox(expectation, image_fingerprint; atol = 3.0, rtol = 0.0)
@test isapprox(expectation, image_fingerprint; atol = 1e-3, rtol = 0.0)
end
end

Expand All @@ -32,8 +32,8 @@
for (m, expectation) in zip(
[BoyerLindquistAD(), JohannsenAD(), BoyerLindquistFO(), MorrisThorneAD()],
# expectation values for the sum of the image
# last computed 29/04/2022: corrected impact parameter mapping
[86114.71461584378, 86233.47133294535, 81500.87198429636, 36043.4795182386],
# last computed 04/06/2022: tests with --math-mode=ieee
[86114.71322445248, 86233.47268379868, 81502.90270571726, 36043.47569730063],
)
img = rendergeodesics(
m,
Expand All @@ -46,7 +46,7 @@
verbose = false,
)
image_fingerprint = sum(filter(!isnan, img))
@test isapprox(expectation, image_fingerprint; atol = 3.0, rtol = 0.0)
@test isapprox(expectation, image_fingerprint; atol = 1e-3, rtol = 0.0)
end
end

Expand Down
17 changes: 15 additions & 2 deletions test/smoke-tests/special-radii.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,21 @@
)

@testset "iscos" begin
for m in all_metrics
@test 100 > Gradus.isco(m) > 0.1
# last computed 04/06/2022: tests with --math-mode=ieee
for (m, expected) in zip(
all_metrics,
[
1.2369706551751847,
8.99437445480357,
1.2369706551751847,
8.99437445480357,
2.8482863127671534,
1.1306596884484472,
6.880202293032178,
],
)
isco_r = Gradus.isco(m)
@test isapprox(expected, isco_r; atol = 1e-5, rtol = 0.0)
end
end
end

0 comments on commit a54e037

Please sign in to comment.