Skip to content

Commit

Permalink
Use trixi_include from TrixiBase.jl (#88)
Browse files Browse the repository at this point in the history
* use trixi_include from TrixiBase.jl

* generate API for TrixiBase.jl in docs

* format

* Bump version of TrixiBase.jl

Co-authored-by: Hendrik Ranocha <[email protected]>

* bump TrixiBase to v0.1.1 in docs

---------

Co-authored-by: Hendrik Ranocha <[email protected]>
  • Loading branch information
JoshuaLampert and ranocha authored Feb 15, 2024
1 parent 7db8bb0 commit ac6f2c0
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 139 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/Format-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Install JuliaFormatter and format
run: |
julia -e 'using Pkg; Pkg.add(PackageSpec(name = "JuliaFormatter", version="1.0.45"))'
julia -e 'using JuliaFormatter; format(["src", "test", "examples"], verbose = true)'
julia -e 'using JuliaFormatter; format(["src", "test", "examples", "docs"], verbose = true)'
- name: Format check
run: |
julia -e '
Expand Down
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
SummationByPartsOperators = "9f78cca6-572e-554e-b819-917d2f1cf240"
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284"

[compat]
DiffEqBase = "6.128"
Expand All @@ -34,4 +35,5 @@ SparseArrays = "1"
StaticArrays = "1"
SummationByPartsOperators = "0.5.41"
TimerOutputs = "0.5.7"
TrixiBase = "0.1.1"
julia = "1.9"
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
SummationByPartsOperators = "9f78cca6-572e-554e-b819-917d2f1cf240"
TrixiBase = "9a0f1c46-06d5-4909-a5a3-ce25d3fa3284"

[compat]
Documenter = "1"
OrdinaryDiffEq = "6.49.1"
Plots = "1.9"
SummationByPartsOperators = "0.5.41"
TrixiBase = "0.1.1"
11 changes: 8 additions & 3 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using DispersiveShallowWater
using Documenter
using DispersiveShallowWater
using TrixiBase

# Define module-wide setups such that the respective modules are available in doctests
DocMeta.setdocmeta!(DispersiveShallowWater, :DocTestSetup, :(using DispersiveShallowWater);
recursive = true)
DocMeta.setdocmeta!(TrixiBase, :DocTestSetup, :(using TrixiBase); recursive = true)

makedocs(;
modules = [DispersiveShallowWater],
modules = [DispersiveShallowWater, TrixiBase],
authors = "Joshua Lampert <[email protected]>",
repo = Remotes.GitHub("JoshuaLampert", "DispersiveShallowWater.jl"),
sitename = "DispersiveShallowWater.jl",
Expand All @@ -18,7 +20,10 @@ makedocs(;
pages = [
"Home" => "index.md",
"Overview" => "overview.md",
"Reference" => "ref.md",
"Reference" => [
"TrixiBase" => "ref-trixibase.md",
"DispersiveShallowWater" => "ref.md",
],
"License" => "license.md",
])

Expand Down
9 changes: 9 additions & 0 deletions docs/src/ref-trixibase.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# TrixiBase.jl API

```@meta
CurrentModule = TrixiBase
```

```@autodocs
Modules = [TrixiBase]
```
3 changes: 2 additions & 1 deletion src/DispersiveShallowWater.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ using SummationByPartsOperators: AbstractDerivativeOperator,
derivative_order, integrate
import SummationByPartsOperators: grid, xmin, xmax
using TimerOutputs: TimerOutputs, TimerOutput, @timeit, print_timer, reset_timer!
@reexport using TrixiBase: TrixiBase, trixi_include

include("boundary_conditions.jl")
include("mesh.jl")
Expand All @@ -32,7 +33,7 @@ include("callbacks_step/callbacks_step.jl")
include("visualization.jl")
include("util.jl")

export examples_dir, get_examples, default_example, trixi_include, convergence_test
export examples_dir, get_examples, default_example, convergence_test

export BBMBBMEquations1D, BBMBBMVariableEquations1D, SvärdKalischEquations1D,
SvaerdKalischEquations1D
Expand Down
133 changes: 1 addition & 132 deletions src/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,53 +48,6 @@ function default_example()
"bbm_bbm_variable_bathymetry_1d_basic.jl")
end

# Note: We can't call the method below `DispersiveShallowWater.include` since that is created automatically
# inside `module DispersiveShallowWater` to `include` source files and evaluate them within the global scope
# of `DispersiveShallowWater`. However, users will want to evaluate in the global scope of `Main` or something
# similar to manage dependencies on their own.
"""
trixi_include([mod::Module=Main,] example::AbstractString; kwargs...)
`include` the file `example` and evaluate its content in the global scope of module `mod`.
You can override specific assignments in `example` by supplying keyword arguments.
It's basic purpose is to make it easier to modify some parameters while running DispersiveShallowWater from the
REPL. Additionally, this is used in tests to reduce the computational burden for CI while still
providing examples with sensible default values for users.
Before replacing assignments in `example`, the keyword argument `maxiters` is inserted
into calls to `solve` and `DispersiveShallowWater.solve` with it's default value used in the SciML ecosystem
for ODEs, see the "Miscellaneous" section of the
[documentation](https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/).
Copied from [Trixi.jl](https://github.com/trixi-framework/Trixi.jl).
# Examples
```jldoctest
julia> redirect_stdout(devnull) do
trixi_include(@__MODULE__, joinpath(examples_dir(), "bbm_bbm_1d", "bbm_bbm_1d_basic.jl"),
tspan=(0.0, 0.1))
sol.t[end]
end
0.1
```
"""
function trixi_include(mod::Module, example::AbstractString; kwargs...)
# Check that all kwargs exist as assignments
code = read(example, String)
expr = Meta.parse("begin \n$code \nend")
expr = insert_maxiters(expr)

for (key, val) in kwargs
# This will throw an error when `key` is not found
find_assignment(expr, key)
end

Base.include(ex -> replace_assignments(insert_maxiters(ex); kwargs...), mod, example)
end

trixi_include(example::AbstractString; kwargs...) = trixi_include(Main, example; kwargs...)

"""
convergence_test([mod::Module=Main,] example::AbstractString, iterations; kwargs...)
Expand Down Expand Up @@ -214,90 +167,6 @@ function convergence_test(example::AbstractString, iterations; kwargs...)
convergence_test(Main, example::AbstractString, iterations; kwargs...)
end

# Helper methods used in the functions defined above, also copied from Trixi.jl

# Apply the function `f` to `expr` and all sub-expressions recursively.
walkexpr(f, expr::Expr) = f(Expr(expr.head, (walkexpr(f, arg) for arg in expr.args)...))
walkexpr(f, x) = f(x)

# Insert the keyword argument `maxiters` into calls to `solve` and `DispersiveShallowWater.solve`
# with default value `10^5` if it is not already present.
function insert_maxiters(expr)
maxiters_default = 10^5

expr = walkexpr(expr) do x
if x isa Expr
is_plain_solve = x.head === Symbol("call") && x.args[1] === Symbol("solve")
is_trixi_solve = (x.head === Symbol("call") && x.args[1] isa Expr &&
x.args[1].head === Symbol(".") &&
x.args[1].args[1] === Symbol("DispersiveShallowWater") &&
x.args[1].args[2] isa QuoteNode &&
x.args[1].args[2].value === Symbol("solve"))

if is_plain_solve || is_trixi_solve
# Do nothing if `maxiters` is already set as keyword argument...
for arg in x.args
if arg isa Expr && arg.head === Symbol("kw") &&
arg.args[1] === Symbol("maxiters")
return x
end
end

# ...and insert it otherwise.
push!(x.args, Expr(Symbol("kw"), Symbol("maxiters"), maxiters_default))
end
end
return x
end

return expr
end

# Replace assignments to `key` in `expr` by `key = val` for all `(key,val)` in `kwargs`.
function replace_assignments(expr; kwargs...)
# replace explicit and keyword assignments
expr = walkexpr(expr) do x
if x isa Expr
for (key, val) in kwargs
if (x.head === Symbol("=") || x.head === :kw) && x.args[1] === Symbol(key)
x.args[2] = :($val)
# dump(x)
end
end
end
return x
end

return expr
end

# find a (keyword or common) assignment to `destination` in `expr`
# and return the assigned value
function find_assignment(expr, destination)
# declare result to be able to assign to it in the closure
local result
found = false

# find explicit and keyword assignments
walkexpr(expr) do x
if x isa Expr
if (x.head === Symbol("=") || x.head === :kw) &&
x.args[1] === Symbol(destination)
result = x.args[2]
found = true
# dump(x)
end
end
return x
end

if !found
throw(ArgumentError("assignment `$destination` not found in expression"))
end

result
end

function extract_initial_N(example, kwargs)
code = read(example, String)
expr = Meta.parse("begin \n$code \nend")
Expand All @@ -306,7 +175,7 @@ function extract_initial_N(example, kwargs)
return kwargs[:N]
else
# get N from the example
N = find_assignment(expr, :N)
N = TrixiBase.find_assignment(expr, :N)
return N
end
end
Expand Down
1 change: 0 additions & 1 deletion test/test_unit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ using SparseArrays: sparse, SparseMatrixCSC

@testset "util" begin
@test_nowarn get_examples()
@test_nowarn trixi_include(default_example(), tspan = (0.0, 0.1))

accuracy_orders = [2, 4, 6]
for accuracy_order in accuracy_orders
Expand Down
44 changes: 43 additions & 1 deletion test/test_util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ macro test_trixi_include(example, args...)
println($example)

# evaluate examples in the scope of the module they're called from
@test_nowarn trixi_include(@__MODULE__, $example; $kwargs...)
@test_nowarn_mod trixi_include(@__MODULE__, $example; $kwargs...)

# if present, compare l2, linf and conservation errors against reference values
if !isnothing($l2) || !isnothing($linf) || !isnothing($cons_error)
Expand Down Expand Up @@ -189,3 +189,45 @@ macro trixi_testset(name, expr)
nothing
end
end

# Copied from TrixiBase.jl. See https://github.com/trixi-framework/TrixiBase.jl/issues/9.
"""
@test_nowarn_mod expr
Modified version of `@test_nowarn expr` that prints the content of `stderr` when
it is not empty and ignores some common info statements printed in DispersiveShallowWater.jl
uses.
"""
macro test_nowarn_mod(expr, additional_ignore_content = String[])
quote
let fname = tempname()
try
ret = open(fname, "w") do f
redirect_stderr(f) do
$(esc(expr))
end
end
stderr_content = read(fname, String)
if !isempty(stderr_content)
println("Content of `stderr`:\n", stderr_content)
end

# Patterns matching the following ones will be ignored. Additional patterns
# passed as arguments can also be regular expressions, so we just use the
# type `Any` for `ignore_content`.
ignore_content = Any["[ Info: You just called `trixi_include`. Julia may now compile the code, please be patient.\n"]
append!(ignore_content, $additional_ignore_content)
for pattern in ignore_content
stderr_content = replace(stderr_content, pattern => "")
end

# We also ignore simple module redefinitions for convenience. Thus, we
# check whether every line of `stderr_content` is of the form of a
# module replacement warning.
@test occursin(r"^(WARNING: replacing module .+\.\n)*$", stderr_content)
ret
finally
rm(fname, force = true)
end
end
end
end

0 comments on commit ac6f2c0

Please sign in to comment.