Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw error in trixi_include when assignment is not found #1737

Merged
merged 21 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/p4est_2d_dgsem/elixir_advection_restart.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ save_solution.condition.save_initial_solution = false

integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false),
dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks);
save_everystep = false, callback = callbacks, maxiters = 100_000);

# Get the last time index and work with that.
load_timestep!(integrator, restart_filename)
Expand Down
2 changes: 1 addition & 1 deletion examples/p4est_3d_dgsem/elixir_advection_restart.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ save_solution.condition.save_initial_solution = false

integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false),
dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks);
save_everystep = false, callback = callbacks, maxiters = 100_000);

# Get the last time index and work with that.
load_timestep!(integrator, restart_filename)
Expand Down
2 changes: 1 addition & 1 deletion examples/structured_2d_dgsem/elixir_advection_restart.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ save_solution.condition.save_initial_solution = false

integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false),
dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks);
save_everystep = false, callback = callbacks, maxiters = 100_000);

# Get the last time index and work with that.
load_timestep!(integrator, restart_filename)
Expand Down
2 changes: 1 addition & 1 deletion examples/structured_3d_dgsem/elixir_advection_restart.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ save_solution.condition.save_initial_solution = false

integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false),
dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks);
save_everystep = false, callback = callbacks, maxiters = 100_000);

# Get the last time index and work with that.
load_timestep!(integrator, restart_filename)
Expand Down
2 changes: 1 addition & 1 deletion examples/tree_2d_dgsem/elixir_advection_restart.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ save_solution.condition.save_initial_solution = false

integrator = init(ode, alg,
dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks; ode_default_options()...)
callback = callbacks, maxiters = 100_000; ode_default_options()...)
ranocha marked this conversation as resolved.
Show resolved Hide resolved

# Load saved context for adaptive time integrator
if integrator.opts.adaptive
Expand Down
2 changes: 1 addition & 1 deletion examples/tree_3d_dgsem/elixir_advection_restart.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ save_solution.condition.save_initial_solution = false

integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false),
dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks);
save_everystep = false, callback = callbacks, maxiters=100_000);

# Get the last time index and work with that.
load_timestep!(integrator, restart_filename)
Expand Down
2 changes: 1 addition & 1 deletion examples/unstructured_2d_dgsem/elixir_euler_restart.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ save_solution.condition.save_initial_solution = false

integrator = init(ode, CarpenterKennedy2N54(williamson_condition = false),
dt = dt, # solve needs some value here but it will be overwritten by the stepsize_callback
save_everystep = false, callback = callbacks);
save_everystep = false, callback = callbacks, maxiters = 100_000);

# Get the last time index and work with that.
load_timestep!(integrator, restart_filename)
Expand Down
20 changes: 18 additions & 2 deletions src/auxiliary/special_elixirs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ providing examples with sensible default values for users.

Before replacing assignments in `elixir`, the keyword argument `maxiters` is inserted
into calls to `solve` and `Trixi.solve` with it's default value used in the SciML ecosystem
for ODEs, see the "Miscellaneous" section of the
for ODEs, see the "Miscellaneous" section of the
[documentation](https://docs.sciml.ai/DiffEqDocs/stable/basics/common_solver_opts/).

# Examples
Expand All @@ -36,6 +36,16 @@ julia> redirect_stdout(devnull) do
```
"""
function trixi_include(mod::Module, elixir::AbstractString; kwargs...)
# Check that all kwargs exist as assignments
code = read(elixir, String)
expr = Meta.parse("begin \n$code \nend")
ranocha marked this conversation as resolved.
Show resolved Hide resolved
expr = insert_maxiters(expr)
ranocha marked this conversation as resolved.
Show resolved Hide resolved

for (key, val) in kwargs
# This will throw an error when `key` is not found
find_assignment(expr, key)
end
ranocha marked this conversation as resolved.
Show resolved Hide resolved
ranocha marked this conversation as resolved.
Show resolved Hide resolved

# Print information on potential wait time only in non-parallel case
if !mpi_isparallel()
@info "You just called `trixi_include`. Julia may now compile the code, please be patient."
Expand Down Expand Up @@ -243,19 +253,25 @@ end
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

Expand All @@ -274,7 +290,7 @@ function extract_initial_resolution(elixir, kwargs)
return initial_refinement_level
end
catch e
if isa(e, UndefVarError)
if isa(e, ArgumentError)
# get cells_per_dimension from the elixir
ranocha marked this conversation as resolved.
Show resolved Hide resolved
cells_per_dimension = eval(find_assignment(expr, :cells_per_dimension))

Expand Down
5 changes: 4 additions & 1 deletion test/test_mpi_p4est_2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_2d_dgsem")
@trixi_testset "elixir_advection_restart.jl" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
l2=[4.507575525876275e-6],
linf=[6.21489667023134e-5])
linf=[6.21489667023134e-5],
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
ranocha marked this conversation as resolved.
Show resolved Hide resolved
end

@trixi_testset "elixir_euler_source_terms_nonconforming_unstructured_flag.jl" begin
Expand Down
5 changes: 4 additions & 1 deletion test/test_mpi_p4est_3d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ const EXAMPLES_DIR = pkgdir(Trixi, "examples", "p4est_3d_dgsem")
@trixi_testset "elixir_advection_restart.jl" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
l2=[0.002590388934758452],
linf=[0.01840757696885409])
linf=[0.01840757696885409],
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
end

@trixi_testset "elixir_advection_cubed_sphere.jl" begin
Expand Down
9 changes: 6 additions & 3 deletions test/test_p4est_2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ end
@trixi_testset "elixir_advection_restart.jl" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
l2=[4.507575525876275e-6],
linf=[6.21489667023134e-5])
linf=[6.21489667023134e-5],
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
Expand Down Expand Up @@ -216,8 +219,8 @@ end
],
surface_flux=flux_hlle,
tspan=(0.0, 0.3))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
t = sol.t[end]
u_ode = sol.u[end]
Expand Down
9 changes: 6 additions & 3 deletions test/test_p4est_3d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@ end
@trixi_testset "elixir_advection_restart.jl" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
l2=[0.002590388934758452],
linf=[0.01840757696885409])
linf=[0.01840757696885409],
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
Expand Down Expand Up @@ -305,8 +308,8 @@ end
],
tspan=(0.0, 0.3),
surface_flux=flux_hlle)
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
t = sol.t[end]
u_ode = sol.u[end]
Expand Down
15 changes: 12 additions & 3 deletions test/test_structured_2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ end
@trixi_testset "elixir_advection_restart.jl" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
l2=[4.219208035582454e-6],
linf=[3.438434404412494e-5])
linf=[3.438434404412494e-5],
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
Expand All @@ -211,7 +214,10 @@ end
linf=[0.0015194252169410394],
rtol=5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS)
elixir_file="elixir_advection_waving_flag.jl",
restart_file="restart_000021.h5")
restart_file="restart_000021.h5",
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
Expand All @@ -227,7 +233,10 @@ end
l2=[7.841217436552029e-15],
linf=[1.0857981180834031e-13],
elixir_file="elixir_advection_free_stream.jl",
restart_file="restart_000036.h5")
restart_file="restart_000036.h5",
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
Expand Down
5 changes: 4 additions & 1 deletion test/test_structured_3d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ end
@trixi_testset "elixir_advection_restart.jl" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
l2=[0.0025903889347585777],
linf=[0.018407576968841655])
linf=[0.018407576968841655],
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
Expand Down
5 changes: 4 additions & 1 deletion test/test_threaded.jl
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,10 @@ end
linf=[0.0015194252169410394],
rtol=5.0e-5, # Higher tolerance to make tests pass in CI (in particular with macOS)
elixir_file="elixir_advection_waving_flag.jl",
restart_file="restart_000021.h5")
restart_file="restart_000021.h5",
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))

# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
Expand Down
5 changes: 4 additions & 1 deletion test/test_tree_3d_advection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ end
@trixi_testset "elixir_advection_restart.jl" begin
@test_trixi_include(joinpath(EXAMPLES_DIR, "elixir_advection_restart.jl"),
l2=[0.00016017848135651983],
linf=[0.0014175368788298393])
linf=[0.0014175368788298393],
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
Expand Down
2 changes: 1 addition & 1 deletion test/test_trixi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ macro test_trixi_include(elixir, args...)
local kwargs = Pair{Symbol, Any}[]
for arg in args
if (arg.head == :(=) &&
!(arg.args[1] in (:l2, :linf, :atol, :rtol, :coverage_override))
!(arg.args[1] in (:l2, :linf, :atol, :rtol, :coverage_override, :skip_coverage))
&& !(coverage && arg.args[1] in keys(coverage_override)))
push!(kwargs, Pair(arg.args...))
end
Expand Down
97 changes: 97 additions & 0 deletions test/test_unit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1325,6 +1325,103 @@ end

@test mesh.boundary_faces[:entire_boundary] == [1, 2]
end

@testset "trixi_include" begin
@trixi_testset "Basic" begin
example = """
x = 4
"""

filename = tempname()
try
open(filename, "w") do file
write(file, example)
end

# Use `@trixi_testset`, which wraps code in a temporary module, and call
# `trixi_include` with `@__MODULE__` in order to isolate this test.
@test_warn "You just called" trixi_include(@__MODULE__, filename)
@test @isdefined x
@test x == 4

@test_warn "You just called" trixi_include(@__MODULE__, filename, x = 7)
@test x == 7

@test_throws "assignment `y` not found in expression" trixi_include(@__MODULE__,
filename,
y = 3)
finally
rm(filename, force = true)
end
end

@trixi_testset "With `solve` Without `maxiters`" begin
# `trixi_include` assumes this to be the `solve` function of OrdinaryDiffEq,
# and therefore tries to insert the kwarg `maxiters`, which will fail here.
example = """
solve() = 0
x = solve()
"""

filename = tempname()
try
open(filename, "w") do file
write(file, example)
end

# Use `@trixi_testset`, which wraps code in a temporary module, and call
# `trixi_include` with `@__MODULE__` in order to isolate this test.
@test_throws "no method matching solve(; maxiters::Int64)" trixi_include(@__MODULE__,
filename)

@test_throws "no method matching solve(; maxiters::Int64)" trixi_include(@__MODULE__,
filename,
maxiters = 3)
finally
rm(filename, force = true)
end
end

@trixi_testset "With `solve` with `maxiters`" begin
# We need another example file that we include with `Base.include` first, in order to
# define the `solve` method without `trixi_include` trying to insert `maxiters` kwargs.
# Then, we can test that `trixi_include` inserts the kwarg in the `solve()` call.
example1 = """
solve(; maxiters=0) = maxiters
"""

example2 = """
x = solve()
"""

filename1 = tempname()
filename2 = tempname()
try
open(filename1, "w") do file
write(file, example1)
end
open(filename2, "w") do file
write(file, example2)
end

# Use `@trixi_testset`, which wraps code in a temporary module, and call
# `Base.include` and `trixi_include` with `@__MODULE__` in order to isolate this test.
Base.include(@__MODULE__, filename1)
@test_warn "You just called" trixi_include(@__MODULE__, filename2)
@test @isdefined x
# This is the default `maxiters` inserted by `trixi_include`
@test x == 10^5

@test_warn "You just called" trixi_include(@__MODULE__, filename2,
maxiters = 7)
# Test that `maxiters` got overwritten
@test x == 7
finally
rm(filename1, force = true)
rm(filename2, force = true)
end
end
end
end

end #module
5 changes: 4 additions & 1 deletion test/test_unstructured_2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ end
0.005243995459478956,
0.004685630332338153,
0.01750217718347713,
])
],
# With the default `maxiters = 1` in coverage tests,
# there would be no time steps after the restart.
coverage_override = (maxiters = 100_000,))
# Ensure that we do not have excessive memory allocations
# (e.g., from type instabilities)
let
Expand Down
Loading
Loading