From a54e0377e4cc8493b443b9e0771569b66eb721e2 Mon Sep 17 00:00:00 2001 From: Fergus Baker Date: Sat, 4 Jun 2022 12:16:24 +0200 Subject: [PATCH] Test workflow + custom metric docs (#28) * 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 --- .github/workflows/test.yml | 93 +++++++++++++++------------- Project.toml | 2 +- docs/make.jl | 11 +++- docs/src/internals/custom-metrics.md | 62 +++++++++++++++++-- docs/src/overview/metrics.md | 6 ++ docs/src/overview/point-functions.md | 1 + src/GeodesicTracer/GeodesicTracer.jl | 3 +- test/smoke-tests/disc-profiles.jl | 4 +- test/smoke-tests/rendergeodesics.jl | 12 ++-- test/smoke-tests/special-radii.jl | 17 ++++- 10 files changed, 147 insertions(+), 64 deletions(-) create mode 100644 docs/src/overview/point-functions.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d1ead1cb..ed93880c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 \ No newline at end of file + 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 \ No newline at end of file diff --git a/Project.toml b/Project.toml index 3e2f2122..67f6e7cc 100644 --- a/Project.toml +++ b/Project.toml @@ -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" \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index 41a95a27..90dd1bac 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -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", diff --git a/docs/src/internals/custom-metrics.md b/docs/src/internals/custom-metrics.md index bf3a2dc6..fa0c7c4f 100644 --- a/docs/src/internals/custom-metrics.md +++ b/docs/src/internals/custom-metrics.md @@ -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, θ) = 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 @@ -17,7 +71,7 @@ FirstOrderMethods.Vr FirstOrderMethods.Vθ ``` -## Second-Order +### Second-Order ```@docs GeodesicTracer.AbstractAutoDiffMetricParams diff --git a/docs/src/overview/metrics.md b/docs/src/overview/metrics.md index a3786666..af668519 100644 --- a/docs/src/overview/metrics.md +++ b/docs/src/overview/metrics.md @@ -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 diff --git a/docs/src/overview/point-functions.md b/docs/src/overview/point-functions.md new file mode 100644 index 00000000..a9f9bb50 --- /dev/null +++ b/docs/src/overview/point-functions.md @@ -0,0 +1 @@ +# Point functions \ No newline at end of file diff --git a/src/GeodesicTracer/GeodesicTracer.jl b/src/GeodesicTracer/GeodesicTracer.jl index ca128bd1..bbfd0d0f 100644 --- a/src/GeodesicTracer/GeodesicTracer.jl +++ b/src/GeodesicTracer/GeodesicTracer.jl @@ -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 diff --git a/test/smoke-tests/disc-profiles.jl b/test/smoke-tests/disc-profiles.jl index 5dea16b4..67c94d20 100644 --- a/test/smoke-tests/disc-profiles.jl +++ b/test/smoke-tests/disc-profiles.jl @@ -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 diff --git a/test/smoke-tests/rendergeodesics.jl b/test/smoke-tests/rendergeodesics.jl index c30d62e4..3f69effe 100644 --- a/test/smoke-tests/rendergeodesics.jl +++ b/test/smoke-tests/rendergeodesics.jl @@ -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, @@ -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 @@ -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, @@ -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 diff --git a/test/smoke-tests/special-radii.jl b/test/smoke-tests/special-radii.jl index 1cde93d1..4c6822c8 100644 --- a/test/smoke-tests/special-radii.jl +++ b/test/smoke-tests/special-radii.jl @@ -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