Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 0 additions & 3 deletions .JuliaFormatter.toml

This file was deleted.

19 changes: 19 additions & 0 deletions .github/workflows/FormatCheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: format-check

on:
push:
branches:
- 'master'
- 'main'
- 'release-'
tags: '*'
pull_request:

jobs:
runic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: fredrikekre/runic-action@v1
with:
version: '1'
5 changes: 3 additions & 2 deletions docs/liveserver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ withenv("LIVESERVER_ACTIVE" => "true") do
launch_browser = true,
foldername = joinpath(repo_root, "docs"),
include_dirs = [joinpath(repo_root, "src")],
skip_dirs = [joinpath(repo_root, "docs/src/tutorials"),
skip_dirs = [
joinpath(repo_root, "docs/src/tutorials"),
joinpath(repo_root, "docs/src/wyos"),
joinpath(repo_root, "docs/src/figures")
joinpath(repo_root, "docs/src/figures"),
]
)
end
58 changes: 35 additions & 23 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,22 @@ if RUN_EXAMPLES
using CairoMakie
CairoMakie.activate!()

# When running docs locally, the EditURL is incorrect. For example, we might get
# When running docs locally, the EditURL is incorrect. For example, we might get
# ```@meta
# EditURL = "<unknown>/docs/src/literate_tutorials/name.jl"
# ```
# We need to replace this EditURL if we are running the docs locally. The last case is more complicated because,
# We need to replace this EditURL if we are running the docs locally. The last case is more complicated because,
# after changing to use temporary directories, it can now look like...
# ```@meta
# EditURL = "../../../../../../../AppData/Local/Temp/jl_8nsMGu/name_just_the_code.jl"
# ```
function update_edit_url(content, file, folder)
content = replace(content, "<unknown>" => "https://github.com/SciML/FiniteVolumeMethod.jl/tree/main")
content = replace(content, "temp/" => "") # as of Literate 2.14.1
content = replace(content,
r"EditURL\s*=\s*\"[^\"]*\"" => "EditURL = \"https://github.com/SciML/FiniteVolumeMethod.jl/tree/main/docs/src/literate_$(folder)/$file\"")
content = replace(
content,
r"EditURL\s*=\s*\"[^\"]*\"" => "EditURL = \"https://github.com/SciML/FiniteVolumeMethod.jl/tree/main/docs/src/literate_$(folder)/$file\""
)
return content
end
# We can add the code to the end of each file in its uncommented form programatically.
Expand All @@ -37,8 +39,10 @@ if RUN_EXAMPLES
write(io, "\n")
write(io, "# ## Just the code\n")
write(io, "# An uncommented version of this example is given below.\n")
write(io,
"# You can view the source code for this file [here](<unknown>/docs/src/$folder/@__NAME__.jl).\n")
write(
io,
"# You can view the source code for this file [here](<unknown>/docs/src/$folder/@__NAME__.jl).\n"
)
write(io, "\n")
write(io, "# ```julia\n")
write(io, "# @__CODE__\n")
Expand All @@ -61,14 +65,14 @@ if RUN_EXAMPLES
"tutorials/piecewise_linear_and_natural_neighbour_interpolation_for_an_advection_diffusion_equation.jl",
"tutorials/helmholtz_equation_with_inhomogeneous_boundary_conditions.jl",
"tutorials/laplaces_equation_with_internal_dirichlet_conditions.jl",
"tutorials/diffusion_equation_on_an_annulus.jl"
"tutorials/diffusion_equation_on_an_annulus.jl",
]
wyos_files = [
"wyos/diffusion_equations.jl",
"wyos/laplaces_equation.jl",
"wyos/mean_exit_time.jl",
"wyos/poissons_equation.jl",
"wyos/linear_reaction_diffusion_equations.jl"
"wyos/linear_reaction_diffusion_equations.jl",
]
example_files = vcat(tutorial_files, wyos_files)
session_tmp = mktempdir()
Expand All @@ -81,8 +85,10 @@ if RUN_EXAMPLES
file_path = joinpath(dir, file)
# See also https://github.com/Ferrite-FEM/Ferrite.jl/blob/d474caf357c696cdb80d7c5e1edcbc7b4c91af6b/docs/generate.jl for some of this
new_file_path = add_just_the_code_section(dir, file)
script = Literate.script(file_path, session_tmp, name = splitext(file)[1] *
"_just_the_code_cleaned")
script = Literate.script(
file_path, session_tmp, name = splitext(file)[1] *
"_just_the_code_cleaned"
)
code = strip(read(script, String))
@info "[$(ct())] Processing $file: Converting markdown script"
line_ending_symbol = occursin(code, "\r\n") ? "\r\n" : "\n"
Expand Down Expand Up @@ -130,17 +136,17 @@ _PAGES = [
"Diffusion Equation on an Annulus" => "tutorials/diffusion_equation_on_an_annulus.md",
"Mean Exit Time" => "tutorials/mean_exit_time.md",
"Solving Mazes with Laplace's Equation" => "tutorials/solving_mazes_with_laplaces_equation.md",
"Keller-Segel Model of Chemotaxis" => "tutorials/keller_segel_chemotaxis.md"
"Keller-Segel Model of Chemotaxis" => "tutorials/keller_segel_chemotaxis.md",
],
"Solvers for Specific Problems, and Writing Your Own" => [
"Section Overview" => "wyos/overview.md",
"Diffusion Equations" => "wyos/diffusion_equations.md",
"Mean Exit Time Problems" => "wyos/mean_exit_time.md",
"Linear Reaction-Diffusion Equations" => "wyos/linear_reaction_diffusion_equations.md",
"Poisson's Equation" => "wyos/poissons_equation.md",
"Laplace's Equation" => "wyos/laplaces_equation.md"
"Laplace's Equation" => "wyos/laplaces_equation.md",
],
"Mathematical and Implementation Details" => "math.md"
"Mathematical and Implementation Details" => "math.md",
]

# Make sure we haven't forgotten any files
Expand Down Expand Up @@ -173,8 +179,10 @@ end
!isempty(missing_set) && error("Missing files: $missing_set")

# Make and deploy
DocMeta.setdocmeta!(FiniteVolumeMethod, :DocTestSetup, :(using FiniteVolumeMethod, Test);
recursive = true)
DocMeta.setdocmeta!(
FiniteVolumeMethod, :DocTestSetup, :(using FiniteVolumeMethod, Test);
recursive = true
)
IS_LIVESERVER = get(ENV, "LIVESERVER_ACTIVE", "false") == "true"
IS_CI = get(ENV, "CI", "false") == "true"
makedocs(;
Expand All @@ -186,14 +194,17 @@ makedocs(;
edit_link = "main",
collapselevel = 1,
assets = String[],
mathengine = MathJax3(Dict(
:loader => Dict("load" => ["[tex]/physics"]),
:tex => Dict(
"inlineMath" => [["\$", "\$"], ["\\(", "\\)"]],
"tags" => "ams",
"packages" => ["base", "ams", "autoload", "physics"]
mathengine = MathJax3(
Dict(
:loader => Dict("load" => ["[tex]/physics"]),
:tex => Dict(
"inlineMath" => [["\$", "\$"], ["\\(", "\\)"]],
"tags" => "ams",
"packages" => ["base", "ams", "autoload", "physics"]
)
)
))),
)
),
draft = IS_LIVESERVER,
pages = _PAGES,
warnonly = true
Expand All @@ -202,4 +213,5 @@ makedocs(;
deploydocs(;
repo = "github.com/SciML/FiniteVolumeMethod.jl",
devbranch = "main",
push_preview = true)
push_preview = true
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using DisplayAs #hide
tc = DisplayAs.withcontext(:displaysize => (15, 80), :limit => true); #hide
# # Diffusion Equation in a Wedge with Mixed Boundary Conditions
# In this example, we consider a diffusion equation on a wedge
# # Diffusion Equation in a Wedge with Mixed Boundary Conditions
# In this example, we consider a diffusion equation on a wedge
# with angle $\alpha$ and mixed boundary conditions:
# ```math
# \begin{equation*}
Expand All @@ -16,21 +16,21 @@ tc = DisplayAs.withcontext(:displaysize => (15, 80), :limit => true); #hide
# ```
# where we take $f(r,\theta) = 1-r$ and $\alpha=\pi/4$.
#
# Note that the PDE is provided in polar form, but Cartesian coordinates
# are assumed for the operators in our code. The conversion is easy, noting
# Note that the PDE is provided in polar form, but Cartesian coordinates
# are assumed for the operators in our code. The conversion is easy, noting
# that the two Neumann conditions are just equations of the form $\grad u \vdot \vu n = 0$.
# Moreover, although the right-hand side of the PDE is given as a Laplacian,
# Moreover, although the right-hand side of the PDE is given as a Laplacian,
# recall that $\grad^2 = \div\grad$, so we can write the PDE as $\partial u/\partial t + \div \vb q = 0$,
# where $\vb q = -\grad u$.
#
# Let us now setup the problem. To define the geometry,
# we need to be careful that the `Triangulation` recognises
# Let us now setup the problem. To define the geometry,
# we need to be careful that the `Triangulation` recognises
# that we need to split the boundary into three parts,
# one part for each boundary condition. This is accomplished
# one part for each boundary condition. This is accomplished
# by providing a single vector for each part of the boundary as follows
# (and as described in DelaunayTriangulation.jl's documentation),
# where we also `refine!` the mesh to get a better mesh. For the arc,
# we use the `CircularArc` so that the mesh knows that it is triangulating
# where we also `refine!` the mesh to get a better mesh. For the arc,
# we use the `CircularArc` so that the mesh knows that it is triangulating
# a certain arc in that area.
using DelaunayTriangulation, FiniteVolumeMethod, ElasticArrays
using ReferenceTests, Bessels, FastGaussQuadrature, Cubature #src
Expand All @@ -43,7 +43,7 @@ upper_edge = [3, 1]
boundary_nodes = [bottom_edge, [arc], upper_edge]
tri = triangulate(points; boundary_nodes)
A = get_area(tri)
refine!(tri; max_area = 1e-4A)
refine!(tri; max_area = 1.0e-4A)
mesh = FVMGeometry(tri)

# This is the mesh we've constructed.
Expand All @@ -54,30 +54,30 @@ fig
# To confirm that the boundary is now in three parts, see:
get_boundary_nodes(tri)

# We now need to define the boundary conditions. For this,
# we need to provide `Tuple`s, where the `i`th element of the
# `Tuple`s refers to the `i`th part of the boundary. The boundary
# We now need to define the boundary conditions. For this,
# we need to provide `Tuple`s, where the `i`th element of the
# `Tuple`s refers to the `i`th part of the boundary. The boundary
# conditions are thus:
lower_bc = arc_bc = upper_bc = (x, y, t, u, p) -> zero(u)
types = (Neumann, Dirichlet, Neumann)
BCs = BoundaryConditions(mesh, (lower_bc, arc_bc, upper_bc), types)

# Now we can define the PDE. We use the reaction-diffusion formulation,
# specifying the diffusion function as a constant.
# Now we can define the PDE. We use the reaction-diffusion formulation,
# specifying the diffusion function as a constant.
f = (x, y) -> 1 - sqrt(x^2 + y^2)
D = (x, y, t, u, p) -> one(u)
initial_condition = [f(x, y) for (x, y) in DelaunayTriangulation.each_point(tri)]
final_time = 0.1
prob = FVMProblem(mesh, BCs; diffusion_function = D, initial_condition, final_time)

# If you did want to use the flux formulation, you would need to provide
# If you did want to use the flux formulation, you would need to provide
flux = (x, y, t, α, β, γ, p) -> (-α, -β)

# which replaces `u` with `αx + βy + γ` so that we approximate $\grad u$ by $(\alpha,\beta)^{\mkern-1.5mu\mathsf{T}}$,
# and the negative is needed since $\vb q = -\grad u$.

# We now solve the problem. We provide the solver for this problem.
# In my experience, I've found that `TRBDF2(linsolve=KLUFactorization())` typically
# In my experience, I've found that `TRBDF2(linsolve=KLUFactorization())` typically
# has the best performance for these problems.
using OrdinaryDiffEq, LinearSolve
sol = solve(prob, TRBDF2(linsolve = KLUFactorization()), saveat = 0.01, parallel = Val(false))
Expand All @@ -93,17 +93,20 @@ using CairoMakie
fig = Figure(fontsize = 38)
for (i, j) in zip(1:3, (1, 6, 11))
local ax
ax = Axis(fig[1, i], width = 600, height = 600,
ax = Axis(
fig[1, i], width = 600, height = 600,
xlabel = "x", ylabel = "y",
title = "t = $(sol.t[j])",
titlealign = :left)
titlealign = :left
)
tricontourf!(ax, tri, sol.u[j], levels = 0:0.01:1, colormap = :matter)
tightlimits!(ax)
end
resize_to_layout!(fig)
fig
@test_reference joinpath(
@__DIR__, "../figures", "diffusion_equation_in_a_wedge_with_mixed_boundary_conditions.png") fig #src
@__DIR__, "../figures", "diffusion_equation_in_a_wedge_with_mixed_boundary_conditions.png"
) fig #src

function get_ζ_terms(M, N, α) #src
ζ = zeros(M, N + 2) #src
Expand All @@ -120,9 +123,9 @@ function get_sum_coefficients(M, N, α, ζ) #src
order = n * π / α #src
for m in 1:M #src
integrand = rθ -> _f(rθ[2], rθ[1]) * besselj(order, ζ[m, n + 1] * rθ[2]) *
cos(order * rθ[1]) * rθ[2] #src
cos(order * rθ[1]) * rθ[2] #src
A[m, n + 1] = 4.0 / (α * besselj(order + 1, ζ[m, n + 1])^2) *
hcubature(integrand, [0.0, 0.0], [α, 1.0]; abstol = 1e-8)[1] #src
hcubature(integrand, [0.0, 0.0], [α, 1.0]; abstol = 1.0e-8)[1] #src
end #src
end #src
return A #src
Expand All @@ -141,7 +144,7 @@ function exact_solution(x, y, t, A, ζ, f, α) #src
order = n * π / α #src
for m in 1:M #src
s += +A[m, n + 1] * exp(-ζ[m, n + 1]^2 * t) * besselj(order, ζ[m, n + 1] * r) *
cos(order * θ) #src
cos(order * θ) #src
end #src
end #src
return s #src
Expand Down Expand Up @@ -172,5 +175,7 @@ for i in eachindex(sol) #src
end #src
resize_to_layout!(fig) #src
fig #src
@test_reference joinpath(@__DIR__, "../figures",
"diffusion_equation_in_a_wedge_with_mixed_boundary_conditions_exact_comparisons.png") fig #src
@test_reference joinpath(
@__DIR__, "../figures",
"diffusion_equation_in_a_wedge_with_mixed_boundary_conditions_exact_comparisons.png"
) fig #src
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fig
bc = (x, y, t, u, p) -> zero(u)
BCs = BoundaryConditions(mesh, bc, Dirichlet)

# We can now define the actual PDE. We start by defining the initial condition and the diffusion function.
# We can now define the actual PDE. We start by defining the initial condition and the diffusion function.
f = (x, y) -> y ≤ 1.0 ? 50.0 : 0.0
initial_condition = [f(x, y) for (x, y) in DelaunayTriangulation.each_point(tri)]
D = (x, y, t, u, p) -> 1 / 9
Expand All @@ -47,26 +47,28 @@ prob = FVMProblem(mesh, BCs; diffusion_function = D, initial_condition, final_ti
prob.flux_function

# When providing `diffusion_function`, the flux is given by $\vb q(\vb x, t, \alpha,\beta,\gamma) = (-\alpha/9, -\beta/9)^{\mkern-1.5mu\mathsf{T}}$,
# where $(\alpha, \beta, \gamma)$ defines the approximation to $u$ via $u(x, y) = \alpha x + \beta y + \gamma$ so that
# where $(\alpha, \beta, \gamma)$ defines the approximation to $u$ via $u(x, y) = \alpha x + \beta y + \gamma$ so that
# $\grad u(\vb x, t) = (\alpha,\beta)^{\mkern-1.5mu\mathsf{T}}$.

# To now solve the problem, we simply use `solve`. Note that,
# To now solve the problem, we simply use `solve`. Note that,
# in the `solve` call below, multithreading is enabled by default.
# (If you don't know what algorithm to consider, do `using DifferentialEquations` instead
# and simply call `solve(prob, saveat=0.05)` so that the algorithm is chosen automatically instead
# (If you don't know what algorithm to consider, do `using DifferentialEquations` instead
# and simply call `solve(prob, saveat=0.05)` so that the algorithm is chosen automatically instead
# of using `Tsit5()`.)
using OrdinaryDiffEq
sol = solve(prob, Tsit5(), saveat = 0.05)
sol |> tc #hide

# To visualise the solution, we can use `tricontourf!` from Makie.jl.
# To visualise the solution, we can use `tricontourf!` from Makie.jl.
fig = Figure(fontsize = 38)
for (i, j) in zip(1:3, (1, 6, 11))
local ax
ax = Axis(fig[1, i], width = 600, height = 600,
ax = Axis(
fig[1, i], width = 600, height = 600,
xlabel = "x", ylabel = "y",
title = "t = $(sol.t[j])",
titlealign = :left)
titlealign = :left
)
tricontourf!(ax, tri, sol.u[j], levels = 0:5:50, colormap = :matter)
tightlimits!(ax)
end
Expand All @@ -81,7 +83,7 @@ function exact_solution(x, y, t) #src
mterm = 2 / m * sin(m * π * x / 2) * exp(-π^2 * m^2 * t / 36) #src
for n in 1:50 #src
nterm = (1 - cos(n * π / 2)) / n * sin(n * π * y / 2) *
exp(-π^2 * n^2 * t / 36) #src
exp(-π^2 * n^2 * t / 36) #src
s += mterm * nterm #src
end #src
end #src
Expand Down
Loading
Loading