From 2ea9d10e5042903a76e8a81d777f883e9b565b64 Mon Sep 17 00:00:00 2001 From: gregoirepourtier Date: Sat, 5 Oct 2024 12:36:55 +0200 Subject: [PATCH 1/6] fix crossrefs by avoiding use of \ref macro --- docs/make.jl | 27 +---- .../pluto-examples/helmholtz_scattering.jl | 114 +++++++++--------- docs/src/pluto-examples/poisson.jl | 54 +++++---- docs/src/pluto-examples/toy_example.jl | 2 +- 4 files changed, 91 insertions(+), 106 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 53c7b2f5..c9f847cd 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -11,24 +11,6 @@ using GLMakie using FMM2D using FMM3D -# Function to remove "begin #hide" and "end #hide" from a markdown file -function formatting_pluto(input_file::String, output_file::String) - # Read the contents of the file - file_content = read(input_file, String) - - # Replace the "begin #hide" and "end #hide" with an empty string - cleaned_content = replace(file_content, r"\b(end #hide)\b" => "") - cleaned_content = replace(cleaned_content, r"\b(end; #hide)\b" => "") - cleaned_content = replace(cleaned_content, r"\b(end;#hide)\b" => "") - cleaned_content = replace(cleaned_content, r"begin #hide\s*" => "") - cleaned_content = replace(cleaned_content, r"let #hide\s*" => "") - - # Write the modified content back to a new file - open(output_file, "w") do f - return write(f, cleaned_content) - end -end - # Function to format the terminal output for the documentation function formatting_terminal_output(input_file::String, output_file::String) # Read the contents of the file @@ -53,14 +35,14 @@ function formatting_terminal_output(input_file::String, output_file::String) end # Function to format the note sections in the markdown file -function formatting_note_tip_md(input_file::String, output_file::String) +function formatting_admonitions(input_file::String, output_file::String) # Read the contents of the file file_content = read(input_file, String) cleaned_content = - replace(file_content, r"\badmonition is-note\b" => "admonition is-info") + replace(file_content, r"admonition is-note" => "admonition is-info") cleaned_content = - replace(cleaned_content, r"\badmonition is-tip\b" => "admonition is-success") + replace(cleaned_content, r"admonition is-tip" => "admonition is-success") # Write the modified content back to a new file open(output_file, "w") do f @@ -146,9 +128,8 @@ for notebook in notebooks get_md_files = replace(notebook[2], ".jl" => ".md") file = joinpath(Inti.PROJECT_ROOT, "docs", "src", "plutostatichtml_examples", get_md_files) - formatting_pluto(file, file) formatting_terminal_output(file, file) - formatting_note_tip_md(file, file) + formatting_admonitions(file, file) end # Generate HTML versions of the notebooks using PlutoSliderServer.jl diff --git a/docs/src/pluto-examples/helmholtz_scattering.jl b/docs/src/pluto-examples/helmholtz_scattering.jl index 82f507ab..08c117de 100644 --- a/docs/src/pluto-examples/helmholtz_scattering.jl +++ b/docs/src/pluto-examples/helmholtz_scattering.jl @@ -12,7 +12,7 @@ begin end ; # ╔═╡ ef067551-aa44-4099-b32a-08debb81ee79 -begin #hide +begin # hide using Inti using LinearAlgebra using StaticArrays @@ -23,13 +23,13 @@ using SpecialFunctions using GSL using IterativeSolvers using LinearMaps -end #hide +end # hide # ╔═╡ a6c80f87-ff47-496f-8925-1275b58b02e1 md""" # Helmholtz scattering -[![Pluto notebook](https://img.shields.io/badge/download-Pluto_notebook-blue)](../../pluto_examples/helmholtz_scattering.jl) $\hspace{0.2cm}$ [![nbviewer](https://img.shields.io/badge/show-nbviewer-blue.svg)](../../pluto_examples/helmholtz_scattering.html) +[![Pluto notebook](https://img.shields.io/badge/download-Pluto_notebook-blue)](../../pluto_examples/helmholtz_scattering.jl)$\hspace{5pt}$[![nbviewer](https://img.shields.io/badge/show-nbviewer-blue.svg)](../../pluto_examples/helmholtz_scattering.html) """ # ╔═╡ 1715d794-a33d-4faf-953c-b706a9ceea23 @@ -46,7 +46,7 @@ md""" md""" In this tutorial we will show how to solve an acoustic scattering problem in the context of Helmholtz equation. We will focus on a *smooth* sound-soft obstacle for simplicity, and introduce along the way the necessary techniques used to handle some difficulties encountered. We will use various packages throughout this example (including of course `Inti.jl`); if they are not on your environment, you can install them using `] add ` in the REPL. -In the [following section](@ref helmholtz-soundsoft), we will provide a brief mathematical description of the problem (valid in both $2$ and $3$ dimensions). We will tackle the [two-dimensional problem](@ref helmholtz-scattering-2d) first, for which we do not need to worry much about performance issues (e.g. compressing the integral operators). Finally, we present a [three-dimensional example](@ref helmholtz-scattering-3d), where we will use [`HMatrices.jl`](https://github.com/IntegralEquatins/HMatrices.jl) to compress the underlying integral operators. +In the [following section](#Sound-soft-problem), we will provide a brief mathematical description of the problem (valid in both $2$ and $3$ dimensions). We will tackle the [two-dimensional problem](#Two-dimensional-scattering) first, for which we do not need to worry much about performance issues (e.g. compressing the integral operators). Finally, we present a [three-dimensional example](#Three-dimensional-scattering), where we will use [`HMatrices.jl`](https://github.com/IntegralEquations/HMatrices.jl) to compress the underlying integral operators. """ # ╔═╡ 643919c5-762f-4fa6-ac26-6bf0abd94558 @@ -121,18 +121,18 @@ and setup some of the (global) problem parameters: """ # ╔═╡ 4cabe108-93c6-4fbf-b8ec-37277abbbda1 -begin #hide +begin # hide k = 4π λ = 2π / k qorder = 4 # quadrature order gorder = 2 # order of geometrical approximation -end; #hide +end; # hide # ╔═╡ a33f066e-307c-42c4-836b-5b7d8236a893 md""" ## Two-dimensional scattering -We will use [Gmsh API](https://gmsh.info/doc/texinfo/gmsh.htmlGmsh-application-programming-interface) for creating `.msh` file containing the desired geometry and mesh. Here is a function to mesh the circle: +We will use [Gmsh API](https://gmsh.info/doc/texinfo/gmsh.html#Gmsh-application-programming-interface) for creating `.msh` file containing the desired geometry and mesh. Here is a function to mesh the circle: """ # ╔═╡ cb736b4d-bbd6-456c-9041-f69b2155a470 @@ -159,11 +159,11 @@ Let us now use `gmsh_circle` to create a `circle.msh` file. As customary in wave # ╔═╡ 12e20620-042c-4040-bd64-af01bd0f2ad9 # ╠═╡ show_logs = false -begin #hide +begin # hide name = joinpath(@__DIR__, "circle.msh") meshsize = λ / 5 gmsh_circle(; meshsize, order = gorder, name) -end #hide +end # hide # ╔═╡ 867186cf-fd4c-484b-9ded-344573ccda4f let # to render terminal output in the documentation @@ -176,14 +176,14 @@ end # ╔═╡ 24454bd5-00cf-4282-926f-f1324141fe26 md""" -We can now import the file and parse the mesh and domain information into `Inti.jl` using the [`import_mesh`](@ref Inti.import_mesh) function: +We can now import the file and parse the mesh and domain information into `Inti.jl` using the [`import_mesh`](../docstrings/#Inti.import_mesh-Tuple) function: """ # ╔═╡ ff73663c-7cf4-4b23-83b5-095dc66f711f -begin #hide +begin # hide Inti.clear_entities!() # empty the entity cache msh = Inti.import_mesh(name; dim = 2) -end #hide +end # hide # ╔═╡ 176f1fef-f761-4ad0-8fea-982eab4fe24d md""" @@ -195,16 +195,16 @@ The code above will import the mesh with all of its geometrical entities. The `d # ╔═╡ 3251d71a-b84c-48d8-9dff-01b2457e610b md""" -To solve our boundary integral equation usign a Nyström method, we actually need a quadrature of our curve/surface (and possibly the normal vectors at the quadrature nodes). Once a mesh is available, creating a quadrature object can be done via the [`Quadrature`](@ref Inti.Quadrature) constructor, which requires passing a mesh of the domain that one wishes to generate a quadrature +To solve our boundary integral equation usign a Nyström method, we actually need a quadrature of our curve/surface (and possibly the normal vectors at the quadrature nodes). Once a mesh is available, creating a quadrature object can be done via the [`Quadrature`](../docstrings/#Inti.Quadrature) constructor, which requires passing a mesh of the domain that one wishes to generate a quadrature for: """ # ╔═╡ 09a785ae-7286-4a47-b103-1e90efa20167 -begin #hide +begin # hide Γ = Inti.boundary(Ω) Γ_msh = view(msh, Γ) Q = Inti.Quadrature(Γ_msh; qorder) -end; #hide +end; # hide # ╔═╡ 593216db-810e-47db-b6cb-aa6cf53e8590 md""" @@ -230,11 +230,11 @@ abs(Inti.integrate(x -> 1, Q) - 2π) # ╔═╡ 78ac2790-60d4-40da-bf5d-09617f1445a2 md""" -With the [`Quadrature`](@ref Inti.Quadrature) constructed, we now can define discrete approximation to the integral operators ``\mathrm{S}`` and ``\mathrm{D}`` as follows: +With the [`Quadrature`](../docstrings/#Inti.Quadrature) constructed, we now can define discrete approximation to the integral operators ``\mathrm{S}`` and ``\mathrm{D}`` as follows: """ # ╔═╡ 9b37d163-15ca-44af-9e00-7410956fc16c -begin #hide +begin # hide pde = Inti.Helmholtz(; k, dim = 2) S, D = Inti.single_double_layer(; pde, @@ -243,7 +243,7 @@ S, D = Inti.single_double_layer(; compression = (method = :none,), correction = (method = :dim,), ) -end; #hide +end; # hide # ╔═╡ 061b7503-bad0-411e-b126-eea4b89feb03 md""" @@ -251,7 +251,7 @@ There are two well-known difficulties related to the discretization of the bound - The kernel of the integral operator is not smooth, and thus specialized quadrature rules are required to accurately approximate the matrix entries for which the target and source point lie *close* (relative to some scale) to each other. - The underlying matrix is dense, and thus the storage and computational cost of the operator is prohibitive for large problems unless acceleration techniques such as *Fast Multipole Methods* or *Hierarchical Matrices* are employed. -`Inti.jl` tries to provide a modular and transparent interface for dealing with both of these difficulties, where the general approach for solving a BIE will be to first construct a (possible compressed) naive representation of the integral operator where singular and nearly-singular integrals are ignored, followed by a the creation of a (sparse) correction intended to account for such singular interactions. See [`single_double_layer`](@ref Inti.single_double_layer) for more details on the various options available. +`Inti.jl` tries to provide a modular and transparent interface for dealing with both of these difficulties, where the general approach for solving a BIE will be to first construct a (possible compressed) naive representation of the integral operator where singular and nearly-singular integrals are ignored, followed by a the creation of a (sparse) correction intended to account for such singular interactions. See [`single_double_layer`](../docstrings/#Inti.single_double_layer-Tuple{}) for more details on the various options available. We can now combine `S` and `D` to form the combined-field operator: """ @@ -265,18 +265,18 @@ where `I` is the identity matrix. Assuming an incident field along the $x_1$ dir """ # ╔═╡ eaf2025e-1135-4ee6-9dea-25e2c0c09ec8 -begin #hide +begin # hide uᵢ = x -> exp(im * k * x[1]) # plane-wave incident field rhs = map(Q) do q x = q.coords return -uᵢ(x) end -end; #hide +end; # hide # ╔═╡ 7fcd47c1-9d65-41e2-9363-141d53f0dbca md""" !!! note "Iterating over a quadrature" - In computing `rhs` above, we used `map` to evaluate the incident field at all quadrature nodes. When iterating over `Q`, the iterator returns a [`QuadratureNode`](@ref Inti.QuadratureNode), and not simply the *coordinate* of the quadrature node. This is so that you can access additional information, such as the `normal` vector, at the quadrature node. + In computing `rhs` above, we used `map` to evaluate the incident field at all quadrature nodes. When iterating over `Q`, the iterator returns a [`QuadratureNode`](../docstrings/#Inti.QuadratureNode), and not simply the *coordinate* of the quadrature node. This is so that you can access additional information, such as the `normal` vector, at the quadrature node. """ # ╔═╡ 4cdf0551-1d13-4060-88e6-cf86ad180938 @@ -289,14 +289,14 @@ We can now solve the integral equation using e.g. the backslash operator: # ╔═╡ b26e0c64-b3f1-4b18-a6f5-8f789407a744 md""" -The variable `σ` contains the value of the approximate density at the quadrature nodes. To reconstruct a continuous approximation to the solution, we can use [`single_double_layer_potential`](@ref Inti.single_double_layer_potential) to obtain the single- and double-layer potentials, and then combine them as follows: +The variable `σ` contains the value of the approximate density at the quadrature nodes. To reconstruct a continuous approximation to the solution, we can use [`single_double_layer_potential`](../docstrings/#Inti.single_double_layer_potential-Tuple{}) to obtain the single- and double-layer potentials, and then combine them as follows: """ # ╔═╡ fd0f2cf4-1b18-4c56-84a9-2339b3dfc10a -begin #hide +begin # hide 𝒮, 𝒟 = Inti.single_double_layer_potential(; pde, source = Q) uₛ = x -> 𝒟[σ](x) - im * k * 𝒮[σ](x) -end; #hide +end; # hide # ╔═╡ 12b3c26a-96b3-440b-9771-4a945fe14ce7 md""" @@ -332,7 +332,7 @@ Here is the maximum error on some points located on a circle of radius `2`: # ╔═╡ 1daa0518-a98b-448c-bddd-1147a0f7ed4d # ╠═╡ show_logs = false -begin #hide +begin # hide uₑ = x -> circle_helmholtz_soundsoft(x; k, radius = 1, θin = 0) # exact solution er = maximum(0:0.01:2π) do θ R = 2 @@ -340,7 +340,7 @@ er = maximum(0:0.01:2π) do θ return abs(uₛ(x) - uₑ(x)) end @info "maximum error = $er" -end #hide +end # hide # ╔═╡ 3557cd23-43b2-4c79-a0e9-53c0d9650851 let @@ -356,7 +356,7 @@ As we can see, the error is quite small! Let's use `Makie` to visualize the solu """ # ╔═╡ 56350a37-b2d8-463e-934f-e8a4fbf72c67 -begin #hide +begin # hide xx = yy = range(-4; stop = 4, length = 200) vals = map(pt -> Inti.isinside(pt, Q) ? NaN : real(uₛ(pt) + uᵢ(pt)), Iterators.product(xx, yy)) @@ -371,7 +371,7 @@ fig, ax, hm = heatmap( viz!(Γ_msh; color = :white, segmentsize = 5) Colorbar(fig[1, 2], hm) fig -end #hide +end # hide # ╔═╡ 471a5475-1ef5-4f40-bb45-a3e29ae5c0a8 md""" @@ -381,7 +381,7 @@ Before moving on to the 3D example let us simply mention that, besides the fact """ # ╔═╡ 3f3f4794-f2bf-4171-a1b4-70fd38c01fc3 -let #hide +let # hide # vertices of an equilateral triangle centered at the origin with a vertex at (0,1) a, b, c = SVector(0, 1), SVector(sqrt(3) / 2, -1 / 2), SVector(-sqrt(3) / 2, -1 / 2) circle_f(center, radius) = s -> center + radius * SVector(cospi(2 * s[1]), sinpi(2 * s[1])) @@ -419,12 +419,12 @@ fig, ax, hm = heatmap( viz!(Γ_msh; color = :black, segmentsize = 4) Colorbar(fig[1, 2], hm) fig -end #hide +end # hide # ╔═╡ b8fd284a-3865-4762-9602-6bc1eba464a4 md""" !!! note "Near-field evaluation" - In the example above we employed a naive evaluation of the integral potentials, and therefore the computed solution is expected to become innacurate near the obstacles. See the [layer potential tutorial](@ref "Layer potentials") for more information on how to correct for this. + In the example above we employed a naive evaluation of the integral potentials, and therefore the computed solution is expected to become innacurate near the obstacles. See the [layer potential tutorial](../tutorials/layer_potentials/#Layer-potentials) for more information on how to correct for this. """ # ╔═╡ 8b7fc104-324d-42c7-98b7-dff0df561ce2 @@ -465,11 +465,11 @@ As before, lets write a file with our mesh, and import it into `Inti.jl`: """ # ╔═╡ a18b8726-fa97-4388-bb8b-53965a5d433b -begin #hide +begin # hide name_sphere = joinpath(@__DIR__, "sphere.msh") gmsh_sphere(; meshsize=(λ / 5), order = gorder, name=name_sphere, visualize = false) msh_3d = Inti.import_mesh(name_sphere; dim = 3) -end #hide +end # hide # ╔═╡ 063e3185-8714-4955-b985-5413420a889b md""" @@ -483,11 +483,11 @@ Since we created physical groups in `Gmsh`, we can use them to extract the relev """ # ╔═╡ 631328d5-c961-41e1-ac0e-181c3bb75112 -begin #hide +begin # hide Ω_3d = Inti.Domain(e -> "omega" ∈ Inti.labels(e), Inti.entities(msh_3d)) Σ_3d = Inti.Domain(e -> "sigma" ∈ Inti.labels(e), Inti.entities(msh_3d)) Γ_3d = Inti.boundary(Ω_3d) -end; #hide +end; # hide # ╔═╡ dbd6d298-0fbf-420f-9622-d1db1d550cc5 md""" @@ -495,13 +495,13 @@ We can now create a quadrature as before """ # ╔═╡ 6096328b-e1af-4ec5-b72b-cd381c166cb7 -begin #hide +begin # hide Γ_msh_3d = view(msh_3d, Γ_3d) Q_3d = Inti.Quadrature(Γ_msh_3d; qorder) -end; #hide +end; # hide # ╔═╡ 498fa575-5cf7-4a7e-8d3b-c50d605aa57c -begin #hide +begin # hide using HMatrices pde_3d = Inti.Helmholtz(; k, dim = 3) S_3d, D_3d = Inti.single_double_layer(; @@ -511,12 +511,12 @@ S_3d, D_3d = Inti.single_double_layer(; compression = (method = :hmatrix, tol = 1e-4), correction = (method = :dim,), ) -end; #hide +end; # hide # ╔═╡ b6cad085-eb74-4152-8850-226ed837febd md""" !!! tip "Writing/reading a mesh from disk" - Writing and reading a mesh to/from disk can be time consuming. You can avoid doing so by using [`import_mesh`](@ref Inti.import_mesh) without a file name to import the mesh from the current `gmsh` session without the need to write it to disk. + Writing and reading a mesh to/from disk can be time consuming. You can avoid doing so by using [`import_mesh`](../docstrings/#Inti.import_mesh-Tuple) without a file name to import the mesh from the current `gmsh` session without the need to write it to disk. """ # ╔═╡ f5d990e9-8d05-41e6-b6b3-c737692de37a @@ -531,10 +531,10 @@ Here is how much memory it would take to store the dense representation of these # ╔═╡ 54f07c21-339b-44c3-9ac2-22af163d55ae # ╠═╡ show_logs = false -begin #hide +begin # hide mem = 2 * length(S_3d) * 16 / 1e9 # 16 bytes per complex number, 1e9 bytes per GB, two matrices println("memory required to store S and D: $(mem) GB") -end #hide +end # hide # ╔═╡ baea69b3-028b-4617-83f1-1ab9e2ca7115 let # to render terminal output in the documentation @@ -551,7 +551,7 @@ Even for this simple example, the dense representation of the integral operators # ╔═╡ bc09986a-5378-4d0b-a2b2-df9245f3f9cf md""" !!! note "Compression methods" - It is worth mentioning that hierchical matrices are not the only way to compress such integral operators, and may in fact not even be the best for the problem at hand. For example, one could use a fast multipole method (FMM), which has a much lighter memory footprint. See the the [tutorial on compression methods](@ref "Compression methods") for more information. + It is worth mentioning that hierchical matrices are not the only way to compress such integral operators, and may in fact not even be the best for the problem at hand. For example, one could use a fast multipole method (FMM), which has a much lighter memory footprint. See the the [tutorial on compression methods](../tutorials/compression_methods/#Compression-methods) for more information. """ # ╔═╡ b9e36a69-a3d1-41c8-8951-01f92acf0806 @@ -569,7 +569,7 @@ We can now solve the linear system using GMRES solver: # ╔═╡ dcf006a3-5332-442a-9771-f427cd7189a5 # ╠═╡ show_logs = false -begin #hide +begin # hide rhs_3d = map(Q_3d) do q x = q.coords return -uᵢ(x) @@ -577,7 +577,7 @@ end σ_3d, hist = gmres(L_3d, rhs_3d; log = true, abstol = 1e-6, verbose = false, restart = 100, maxiter = 100) @show hist -end #hide +end # hide # ╔═╡ 215677a6-af7b-4e5d-863f-aabdfb4a1400 md""" @@ -585,10 +585,10 @@ As before, let us represent the solution using `IntegralPotential`s: """ # ╔═╡ 14a549ad-e23f-40a4-b7fa-ef31354805a9 -begin #hide +begin # hide 𝒮_3d, 𝒟_3d = Inti.single_double_layer_potential(; pde=pde_3d, source = Q_3d) uₛ_3d = x -> 𝒟_3d[σ_3d](x) - im * k * 𝒮_3d[σ_3d](x) -end; #hide +end; # hide # ╔═╡ 832858dc-2475-4f6a-a820-a557b2883f0c md""" @@ -596,7 +596,7 @@ To check the result, we compare against the exact solution obtained through a se """ # ╔═╡ e00c4d90-aa3b-41f9-b65e-7e9ace89a295 -begin #hide +begin # hide sphbesselj(l, r) = sqrt(π / (2r)) * besselj(l + 1 / 2, r) sphbesselh(l, r) = sqrt(π / (2r)) * besselh(l + 1 / 2, r) sphharmonic(l, m, θ, ϕ) = GSL.sf_legendre_sphPlm(l, abs(m), cos(θ)) * exp(im * m * ϕ) @@ -621,7 +621,7 @@ function sphere_helmholtz_soundsoft(xobs; radius = 1, k = 1, θin = 0, ϕin = 0) end return u end -end; #hide +end; # hide # ╔═╡ bb87f66d-5e68-49c5-9167-bdbab60109e5 md""" @@ -630,7 +630,7 @@ We will compute the error on some point on the sphere of radius `2`: # ╔═╡ 3848717e-0c30-4c0b-82ec-b504c9210483 # ╠═╡ show_logs = false -begin #hide +begin # hide uₑ_3d = (x) -> sphere_helmholtz_soundsoft(x; radius = 1, k = k, θin = π / 2, ϕin = 0) er_3d = maximum(1:100) do _ x̂ = rand(Inti.Point3D) |> normalize # an SVector of unit norm @@ -638,7 +638,7 @@ er_3d = maximum(1:100) do _ return abs(uₛ_3d(x) - uₑ_3d(x)) end @info "error with correction = $er_3d" -end #hide +end # hide # ╔═╡ 36ddb3be-7103-429f-9011-99c27c655de5 let # Render terminal output in documentation @@ -654,7 +654,7 @@ We see that, once again, the approximation is quite accurate. Let us now visuali """ # ╔═╡ b2b31b38-4c2f-4763-9273-971749c40d5c -begin #hide +begin # hide Σ_msh = view(msh_3d, Σ_3d) target = Inti.nodes(Σ_msh) @@ -670,15 +670,15 @@ S_viz, D_viz = Inti.single_double_layer(; ui_eval_msh = uᵢ.(target) us_eval_msh = D_viz * σ_3d - im * k * S_viz * σ_3d u_eval_msh = ui_eval_msh + us_eval_msh -end; #hide +end; # hide # ╔═╡ 0cec09b1-8806-4aee-970d-cc0b1e4b841c md""" -Finalize, we use [`Meshes.viz`](@extref) to visualize the scattered field: +Finalize, we use [`Meshes.viz`](https://juliageometry.github.io/MeshesDocs/dev/visualization/#Meshes.viz) to visualize the scattered field: """ # ╔═╡ dab9a19c-977e-4ab1-a3d9-f9970af69642 -begin #hide +begin # hide nv = length(Inti.nodes(Γ_msh_3d)) colorrange = extrema(real(u_eval_msh)) colormap = :inferno @@ -687,7 +687,7 @@ ax_3d = Axis3(fig_3d[1, 1]; aspect = :data) viz!(Γ_msh_3d; colorrange, colormap, color = zeros(nv), interpolate = true) viz!(Σ_msh; colorrange, colormap, color = real(u_eval_msh)) cb = Colorbar(fig_3d[1, 2]; label = "real(u)", colormap, colorrange) -end; #hide +end; # hide # ╔═╡ 0c1114d1-256c-44e3-bbd4-9b5077fc7ee8 fig_3d diff --git a/docs/src/pluto-examples/poisson.jl b/docs/src/pluto-examples/poisson.jl index 62bb262a..fbfaa07f 100644 --- a/docs/src/pluto-examples/poisson.jl +++ b/docs/src/pluto-examples/poisson.jl @@ -8,12 +8,12 @@ using InteractiveUtils begin import Pkg as _Pkg haskey(ENV, "PLUTO_PROJECT") && _Pkg.activate(ENV["PLUTO_PROJECT"]) - using PlutoUI: with_terminal + using PlutoUI: with_terminal, TableOfContents end ; # ╔═╡ 332bd3bb-c720-454e-80af-89ad65041773 # ╠═╡ show_logs = false -begin #hide +begin # hide using Inti, Gmsh meshsize = 0.1 gmsh.initialize() @@ -29,13 +29,13 @@ gmsh.model.mesh.generate(2) gmsh.model.mesh.setOrder(2) msh = Inti.import_mesh(; dim = 2) gmsh.finalize() -end #hide +end # hide # ╔═╡ aca57c74-d084-40e7-9760-edf988a64915 md""" # Poisson Problem -[![Pluto notebook](https://img.shields.io/badge/download-Pluto_notebook-blue)](../../pluto_examples/poisson.jl) $\hspace{0.2cm}$ [![nbviewer](https://img.shields.io/badge/show-nbviewer-blue.svg)](../../pluto_examples/poisson.html) +[![Pluto notebook](https://img.shields.io/badge/download-Pluto_notebook-blue)](../../pluto_examples/poisson.jl)$\hspace{5pt}$[![nbviewer](https://img.shields.io/badge/show-nbviewer-blue.svg)](../../pluto_examples/poisson.html) """ # ╔═╡ 4160cbc1-3e98-4919-a8b5-bfbc65077b53 @@ -137,19 +137,19 @@ We can now extract components of the mesh corresponding to the ``\Omega`` and """ # ╔═╡ 4e580f9f-6e22-4160-b262-ca941b6bfb8f -begin #hide +begin # hide Ω = Inti.Domain(e -> Inti.geometric_dimension(e) == 2, msh) Γ = Inti.boundary(Ω) Ω_msh = view(msh, Ω) Γ_msh = view(msh, Γ) -end; #hide +end; # hide # ╔═╡ 2c4bace3-ef35-4500-829f-2f5ae6725249 -begin #hide +begin # hide using Meshes, GLMakie viz(Ω_msh; showsegments=true) viz!(Γ_msh; color=:red) -end; #hide +end; # hide # ╔═╡ 901578c3-b7aa-4023-bb99-769cf5805f57 md""" @@ -166,13 +166,13 @@ boundary: """ # ╔═╡ 85ce61fc-086d-4661-8f03-6a6ae4d55511 -begin #hide +begin # hide Ω_quad = Inti.Quadrature(Ω_msh; qorder = 4) Γ_quad = Inti.Quadrature(Γ_msh; qorder = 6) -end; #hide +end; # hide # ╔═╡ 6e3ea607-2b70-485d-94f0-5626bab4f832 -begin #hide +begin # hide using FMM2D #to accelerate the maps pde = Inti.Laplace(; dim = 2) # Newtonian potential mapping domain to boundary @@ -187,7 +187,7 @@ V_d2b = Inti.volume_potential(; target_location = :on, ), ) -end #hide +end # hide # ╔═╡ 731d9ae8-33a8-4f03-8cbc-5e40972996a2 md""" @@ -234,13 +234,13 @@ instead a manufactured solution ``u_e`` from which we will derive the functions """ # ╔═╡ 975b7c01-8147-44f8-a693-1185e7b8d63b -begin #hide +begin # hide # Create a manufactured solution uₑ = (x) -> cos(2 * x[1]) * sin(2 * x[2]) fₑ = (x) -> 8 * cos(2 * x[1]) * sin(2 * x[2]) # -Δuₑ g = map(q -> uₑ(q.coords), Γ_quad) f = map(q -> fₑ(q.coords), Ω_quad) -end; #hide +end; # hide # ╔═╡ 700cfbbc-970a-466b-9f8c-748f7ff0bc6e md""" @@ -253,10 +253,10 @@ rhs = g - V_d2b*f ; # ╔═╡ 6eb1d813-e792-4148-8d30-975c49e9dbc6 # ╠═╡ show_logs = false -begin #hide +begin # hide using IterativeSolvers, LinearAlgebra σ = gmres(-I/2 + D_b2b, rhs; abstol = 1e-8, verbose = true, restart = 1000) -end; #hide +end; # hide # ╔═╡ b21911c7-7276-44cb-a15f-64db3430a896 md""" @@ -277,13 +277,13 @@ With the density function at hand, we can now reconstruct our approximate soluti """ # ╔═╡ e0e1fa9c-7a43-45b1-ad45-2510533e1aed -begin #hide +begin # hide G = Inti.SingleLayerKernel(pde) dG = Inti.DoubleLayerKernel(pde) 𝒱 = Inti.IntegralPotential(G, Ω_quad) 𝒟 = Inti.IntegralPotential(dG, Γ_quad) u = (x) -> 𝒱[f](x) + 𝒟[σ](x) -end #hide +end # hide # ╔═╡ 2c2c943b-30ed-4244-a40c-f061050ca7b8 md""" @@ -292,10 +292,10 @@ and evaluate it at any point in the domain: # ╔═╡ 2faa4311-59d9-4b85-b585-937391e94568 # ╠═╡ show_logs = false -begin #hide +begin # hide x = Inti.Point2D(0.1,0.4) println("error at $x: ", u(x)-uₑ(x)) -end #hide +end # hide # ╔═╡ f3495025-ac97-415d-a398-ee5280c2d714 let # Render for Documentation @@ -353,11 +353,11 @@ manufactured: # ╔═╡ 5be59f68-cf21-4e7e-ac23-7bffd690dc03 # ╠═╡ show_logs = false -begin #hide +begin # hide u_quad = V_d2d*f + D_b2d*σ er_quad = u_quad - map(q -> uₑ(q.coords), Ω_quad) println("maximum error at all quadrature nodes: ", norm(er_quad, Inf)) -end; #hide +end; # hide # ╔═╡ 41f97844-3c86-46b8-9fbb-0632bdcee0f6 let # render for documentation @@ -368,11 +368,11 @@ end # ╔═╡ a61f336e-15ee-4bb3-a071-1115ac6f1be1 md""" -Lastly, let us visualize the solution and the error on the mesh nodes using [`quadrature_to_node_vals`](@ref): +Lastly, let us visualize the solution and the error on the mesh nodes using [`quadrature_to_node_vals`](../docstrings/#Inti.quadrature_to_node_vals-Tuple{Inti.Quadrature,%20AbstractVector}): """ # ╔═╡ ce03f9b7-c91c-4f53-bcda-49261a4bdcc2 -begin #hide +begin # hide nodes = Inti.nodes(Ω_msh) u_nodes = Inti.quadrature_to_node_vals(Ω_quad, u_quad) er = u_nodes - map(uₑ, nodes) @@ -388,11 +388,14 @@ colormap = :inferno ax = Axis(fig[1, 3]; aspect = DataAspect()) viz!(Ω_msh; colorrange, colormap, color = log_er, interpolate = true) cb = Colorbar(fig[1, 4]; label = "log₁₀|u - uₑ|", colormap, colorrange) -end; #hide +end; # hide # ╔═╡ e46f76d5-074b-49ac-b976-9f782df9307d fig +# ╔═╡ e63c776b-6b52-4e6e-aca8-3d67cd9a9c3f +TableOfContents() + # ╔═╡ 00000000-0000-0000-0000-000000000001 PLUTO_PROJECT_TOML_CONTENTS = """ [deps] @@ -2478,5 +2481,6 @@ version = "1.4.1+1" # ╟─a61f336e-15ee-4bb3-a071-1115ac6f1be1 # ╠═ce03f9b7-c91c-4f53-bcda-49261a4bdcc2 # ╟─e46f76d5-074b-49ac-b976-9f782df9307d +# ╟─e63c776b-6b52-4e6e-aca8-3d67cd9a9c3f # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002 diff --git a/docs/src/pluto-examples/toy_example.jl b/docs/src/pluto-examples/toy_example.jl index e9acae6f..8e35052e 100644 --- a/docs/src/pluto-examples/toy_example.jl +++ b/docs/src/pluto-examples/toy_example.jl @@ -18,7 +18,7 @@ using Inti md""" # Toy example -[![Pluto notebook](https://img.shields.io/badge/download-Pluto_notebook-blue)](../../pluto_examples/toy_example.jl) $\hspace{0.2cm}$ [![nbviewer](https://img.shields.io/badge/show-nbviewer-blue.svg)](../../pluto_examples/toy_example.html) +[![Pluto notebook](https://img.shields.io/badge/download-Pluto_notebook-blue)](../../pluto_examples/toy_example.jl)$\hspace{5pt}$[![nbviewer](https://img.shields.io/badge/show-nbviewer-blue.svg)](../../pluto_examples/toy_example.html) """ # ╔═╡ 09c0bfc0-1c65-4fad-b486-b6a61ca580e8 From bef60682f737f9cd5fd913d9c68eb38f5393ac34 Mon Sep 17 00:00:00 2001 From: gregoirepourtier Date: Sat, 5 Oct 2024 13:10:39 +0200 Subject: [PATCH 2/6] fix path ... --- docs/src/pluto-examples/helmholtz_scattering.jl | 16 ++++++++-------- docs/src/pluto-examples/poisson.jl | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/src/pluto-examples/helmholtz_scattering.jl b/docs/src/pluto-examples/helmholtz_scattering.jl index 08c117de..b14636eb 100644 --- a/docs/src/pluto-examples/helmholtz_scattering.jl +++ b/docs/src/pluto-examples/helmholtz_scattering.jl @@ -176,7 +176,7 @@ end # ╔═╡ 24454bd5-00cf-4282-926f-f1324141fe26 md""" -We can now import the file and parse the mesh and domain information into `Inti.jl` using the [`import_mesh`](../docstrings/#Inti.import_mesh-Tuple) function: +We can now import the file and parse the mesh and domain information into `Inti.jl` using the [`import_mesh`](../../docstrings/#Inti.import_mesh-Tuple) function: """ # ╔═╡ ff73663c-7cf4-4b23-83b5-095dc66f711f @@ -195,7 +195,7 @@ The code above will import the mesh with all of its geometrical entities. The `d # ╔═╡ 3251d71a-b84c-48d8-9dff-01b2457e610b md""" -To solve our boundary integral equation usign a Nyström method, we actually need a quadrature of our curve/surface (and possibly the normal vectors at the quadrature nodes). Once a mesh is available, creating a quadrature object can be done via the [`Quadrature`](../docstrings/#Inti.Quadrature) constructor, which requires passing a mesh of the domain that one wishes to generate a quadrature +To solve our boundary integral equation usign a Nyström method, we actually need a quadrature of our curve/surface (and possibly the normal vectors at the quadrature nodes). Once a mesh is available, creating a quadrature object can be done via the [`Quadrature`](../../docstrings/#Inti.Quadrature) constructor, which requires passing a mesh of the domain that one wishes to generate a quadrature for: """ @@ -230,7 +230,7 @@ abs(Inti.integrate(x -> 1, Q) - 2π) # ╔═╡ 78ac2790-60d4-40da-bf5d-09617f1445a2 md""" -With the [`Quadrature`](../docstrings/#Inti.Quadrature) constructed, we now can define discrete approximation to the integral operators ``\mathrm{S}`` and ``\mathrm{D}`` as follows: +With the [`Quadrature`](../../docstrings/#Inti.Quadrature) constructed, we now can define discrete approximation to the integral operators ``\mathrm{S}`` and ``\mathrm{D}`` as follows: """ # ╔═╡ 9b37d163-15ca-44af-9e00-7410956fc16c @@ -251,7 +251,7 @@ There are two well-known difficulties related to the discretization of the bound - The kernel of the integral operator is not smooth, and thus specialized quadrature rules are required to accurately approximate the matrix entries for which the target and source point lie *close* (relative to some scale) to each other. - The underlying matrix is dense, and thus the storage and computational cost of the operator is prohibitive for large problems unless acceleration techniques such as *Fast Multipole Methods* or *Hierarchical Matrices* are employed. -`Inti.jl` tries to provide a modular and transparent interface for dealing with both of these difficulties, where the general approach for solving a BIE will be to first construct a (possible compressed) naive representation of the integral operator where singular and nearly-singular integrals are ignored, followed by a the creation of a (sparse) correction intended to account for such singular interactions. See [`single_double_layer`](../docstrings/#Inti.single_double_layer-Tuple{}) for more details on the various options available. +`Inti.jl` tries to provide a modular and transparent interface for dealing with both of these difficulties, where the general approach for solving a BIE will be to first construct a (possible compressed) naive representation of the integral operator where singular and nearly-singular integrals are ignored, followed by a the creation of a (sparse) correction intended to account for such singular interactions. See [`single_double_layer`](../../docstrings/#Inti.single_double_layer-Tuple{}) for more details on the various options available. We can now combine `S` and `D` to form the combined-field operator: """ @@ -289,7 +289,7 @@ We can now solve the integral equation using e.g. the backslash operator: # ╔═╡ b26e0c64-b3f1-4b18-a6f5-8f789407a744 md""" -The variable `σ` contains the value of the approximate density at the quadrature nodes. To reconstruct a continuous approximation to the solution, we can use [`single_double_layer_potential`](../docstrings/#Inti.single_double_layer_potential-Tuple{}) to obtain the single- and double-layer potentials, and then combine them as follows: +The variable `σ` contains the value of the approximate density at the quadrature nodes. To reconstruct a continuous approximation to the solution, we can use [`single_double_layer_potential`](../../docstrings/#Inti.single_double_layer_potential-Tuple{}) to obtain the single- and double-layer potentials, and then combine them as follows: """ # ╔═╡ fd0f2cf4-1b18-4c56-84a9-2339b3dfc10a @@ -424,7 +424,7 @@ end # hide # ╔═╡ b8fd284a-3865-4762-9602-6bc1eba464a4 md""" !!! note "Near-field evaluation" - In the example above we employed a naive evaluation of the integral potentials, and therefore the computed solution is expected to become innacurate near the obstacles. See the [layer potential tutorial](../tutorials/layer_potentials/#Layer-potentials) for more information on how to correct for this. + In the example above we employed a naive evaluation of the integral potentials, and therefore the computed solution is expected to become innacurate near the obstacles. See the [layer potential tutorial](../../tutorials/layer_potentials/#Layer-potentials) for more information on how to correct for this. """ # ╔═╡ 8b7fc104-324d-42c7-98b7-dff0df561ce2 @@ -516,7 +516,7 @@ end; # hide # ╔═╡ b6cad085-eb74-4152-8850-226ed837febd md""" !!! tip "Writing/reading a mesh from disk" - Writing and reading a mesh to/from disk can be time consuming. You can avoid doing so by using [`import_mesh`](../docstrings/#Inti.import_mesh-Tuple) without a file name to import the mesh from the current `gmsh` session without the need to write it to disk. + Writing and reading a mesh to/from disk can be time consuming. You can avoid doing so by using [`import_mesh`](../../docstrings/#Inti.import_mesh-Tuple) without a file name to import the mesh from the current `gmsh` session without the need to write it to disk. """ # ╔═╡ f5d990e9-8d05-41e6-b6b3-c737692de37a @@ -551,7 +551,7 @@ Even for this simple example, the dense representation of the integral operators # ╔═╡ bc09986a-5378-4d0b-a2b2-df9245f3f9cf md""" !!! note "Compression methods" - It is worth mentioning that hierchical matrices are not the only way to compress such integral operators, and may in fact not even be the best for the problem at hand. For example, one could use a fast multipole method (FMM), which has a much lighter memory footprint. See the the [tutorial on compression methods](../tutorials/compression_methods/#Compression-methods) for more information. + It is worth mentioning that hierchical matrices are not the only way to compress such integral operators, and may in fact not even be the best for the problem at hand. For example, one could use a fast multipole method (FMM), which has a much lighter memory footprint. See the the [tutorial on compression methods](../../tutorials/compression_methods/#Compression-methods) for more information. """ # ╔═╡ b9e36a69-a3d1-41c8-8951-01f92acf0806 diff --git a/docs/src/pluto-examples/poisson.jl b/docs/src/pluto-examples/poisson.jl index fbfaa07f..1667383a 100644 --- a/docs/src/pluto-examples/poisson.jl +++ b/docs/src/pluto-examples/poisson.jl @@ -368,7 +368,7 @@ end # ╔═╡ a61f336e-15ee-4bb3-a071-1115ac6f1be1 md""" -Lastly, let us visualize the solution and the error on the mesh nodes using [`quadrature_to_node_vals`](../docstrings/#Inti.quadrature_to_node_vals-Tuple{Inti.Quadrature,%20AbstractVector}): +Lastly, let us visualize the solution and the error on the mesh nodes using [`quadrature_to_node_vals`](../../docstrings/#Inti.quadrature_to_node_vals-Tuple{Inti.Quadrature,%20AbstractVector}): """ # ╔═╡ ce03f9b7-c91c-4f53-bcda-49261a4bdcc2 From 28d90888b8a8609912c27befca96ffd021d501bb Mon Sep 17 00:00:00 2001 From: gregoirepourtier Date: Wed, 9 Oct 2024 16:22:58 +0200 Subject: [PATCH 3/6] pipeline based on generate_md from Pluto notebook --- docs/Project.toml | 3 +- docs/make.jl | 130 ++-- .../pluto-examples/helmholtz_scattering.jl | 636 +++++++++--------- docs/src/pluto-examples/poisson.jl | 252 +++---- docs/src/pluto-examples/toy_example.jl | 96 +-- 5 files changed, 511 insertions(+), 606 deletions(-) diff --git a/docs/Project.toml b/docs/Project.toml index 7cb65c49..efb87802 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -11,11 +11,12 @@ GSL = "92c85e6c-cbff-5e0c-80f7-495c94daaecd" Gmsh = "705231aa-382f-11e9-3f0c-b7cb4346fdeb" HMatrices = "8646bddf-ab1c-4fa7-9c51-ba187d647618" IterativeSolvers = "42fd0dbc-a981-5370-80f2-aaf504508153" +JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899" LinearMaps = "7a12625a-238d-50fd-b39a-03d52299707e" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" Meshes = "eacbb407-ea5a-433e-ab97-5258b1ca43fa" +Pluto = "c3e4b0f8-55cb-11ea-2926-15256bba5781" PlutoSliderServer = "2fc8631c-6f24-4c5b-bca7-cbb509c42db4" -PlutoStaticHTML = "359b1769-a58e-495b-9770-312e911026ad" PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" diff --git a/docs/make.jl b/docs/make.jl index c9f847cd..a9a2ff5f 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -2,7 +2,8 @@ using Inti using Documenter using DocumenterCitations using DocumenterInterLinks -using ExampleJuggler, Literate, PlutoStaticHTML, PlutoSliderServer +using ExampleJuggler, Literate, PlutoSliderServer +using Pluto, JuliaFormatter # packages needed for extensions using Gmsh using HMatrices @@ -11,47 +12,85 @@ using GLMakie using FMM2D using FMM3D -# Function to format the terminal output for the documentation -function formatting_terminal_output(input_file::String, output_file::String) - # Read the contents of the file - file_content = read(input_file, String) - - # Replace the plutouiterminal in the md file by plutouiterminal with padding and background color - cleaned_content = replace( - file_content, - r"\bplutouiterminal\b" => "plutouiterminal\" style=\"padding: 10px; background-color: white;", - ) - - # replace info macro (to keep?? or not use the macro) - cleaned_content = replace( - cleaned_content, - r"�\[36m�\[1m\[ �\[22m�\[39m�\[36m�\[1mInfo: �\[22m�\[39m" => "[ Info: ", - ) +cleanexamples() - # Write the modified content back to a new file - open(output_file, "w") do f - return write(f, cleaned_content) +# from https://github.com/fonsp/Pluto.jl/pull/2471 +function generate_plaintext( + notebook, + strmacrotrim::Union{String,Nothing} = nothing; + header::Function = _ -> nothing, + footer::Function = _ -> nothing, + textcomment::Function = identity, + codewrapper::Function, +) + cell_strings = String[] + header_content = header(notebook) + isnothing(header_content) || push!(cell_strings, header_content) + for cell_id in notebook.cell_order + cell = notebook.cells_dict[cell_id] + scode = strip(cell.code) + (raw, ltrim, rtrim) = if isnothing(strmacrotrim) + false, 0, 0 + elseif startswith(scode, string(strmacrotrim, '"'^3)) + true, length(strmacrotrim) + 3, 3 + elseif startswith(scode, string(strmacrotrim, '"')) + true, length(strmacrotrim) + 1, 1 + else + false, 0, 0 + end + push!( + cell_strings, + if raw + text = strip( + scode[nextind(scode, 1, ltrim):prevind(scode, end, rtrim)], + ['\n'], + ) + ifelse(Pluto.is_disabled(cell), textcomment, identity)(text) + else + codewrapper(cell, Pluto.is_disabled(cell)) + end, + ) end + footer_content = footer(notebook) + isnothing(footer_content) || push!(cell_strings, footer_content) + return join(cell_strings, "\n\n") end -# Function to format the note sections in the markdown file -function formatting_admonitions(input_file::String, output_file::String) - # Read the contents of the file - file_content = read(input_file, String) - - cleaned_content = - replace(file_content, r"admonition is-note" => "admonition is-info") - cleaned_content = - replace(cleaned_content, r"admonition is-tip" => "admonition is-success") - - # Write the modified content back to a new file - open(output_file, "w") do f - return write(f, cleaned_content) +function generate_md( + input; + output = replace(replace(input, r"..$" => "md"), "pluto-examples" => "module_examples"), +) + notebook = Pluto.load_notebook(input) + header = _ -> "" + fname = basename(input) + function codewrapper(cell, _) + # 1. Strips begin/end block + # 2. Reformats code using JuliaFormatter + # 3. Wraps all code in same ```@example``` block for documenter + code = strip(cell.code) + if startswith(code, "begin") && endswith(code, "end") + code = strip(code[6:end-4]) # Remove "begin" and "end" and strip spaces + # reformat code using JuliaFormatter + code = format_text(String(code)) + elseif startswith(code, "let") && endswith(code, "end") + code = strip(code[4:end-4]) # Remove "let" and "end" and strip spaces + # reformat code using JuliaFormatter + code = format_text(String(code)) + end + return if cell.code_folded + string("```@setup $fname\n", code, "\n```") + else + string("```@example $fname\n", code, "\n```") + end + end + textcomment(text) = string("") + str = generate_plaintext(notebook, "md"; header, codewrapper, textcomment) + open(output, "w") do io + return write(io, str) end + return output end -cleanexamples() - links = InterLinks( "Meshes" => "https://juliageometry.github.io/MeshesDocs/dev/objects.inv", "HMatrices" => "https://integralequations.github.io/HMatrices.jl/stable/objects.inv", @@ -119,18 +158,19 @@ notebooks = [ "Poisson problem" => "poisson.jl", ] -# Generate markdown versions of the notebooks for documentation using PlutoStaticHTML.jl -notebook_examples = @docplutonotebooks(notebook_dir, notebooks, iframe = false) -size_threshold_ignore = last.(notebook_examples) +mkdir(joinpath(Inti.PROJECT_ROOT, "docs", "src", "module_examples")) -# Formatting the markdown files +notebook_examples = Pair{String,String}[] for notebook in notebooks - get_md_files = replace(notebook[2], ".jl" => ".md") - file = - joinpath(Inti.PROJECT_ROOT, "docs", "src", "plutostatichtml_examples", get_md_files) - formatting_terminal_output(file, file) - formatting_admonitions(file, file) + name, file = notebook + file_in = joinpath(notebook_dir, file) + file_out = generate_md(file_in) + push!( + notebook_examples, + name => joinpath("module_examples", replace(file, ".jl" => ".md")), + ) end +size_threshold_ignore = last.(notebook_examples) # Generate HTML versions of the notebooks using PlutoSliderServer.jl notebook_examples_html = @docplutonotebooks(notebook_dir, notebooks, iframe = true) @@ -175,7 +215,7 @@ makedocs(; # warnonly = true, pagesonly = true, checkdocs = :none, - clean=false, + clean = false, draft, plugins = [bib, links], ) diff --git a/docs/src/pluto-examples/helmholtz_scattering.jl b/docs/src/pluto-examples/helmholtz_scattering.jl index b14636eb..c2c1b554 100644 --- a/docs/src/pluto-examples/helmholtz_scattering.jl +++ b/docs/src/pluto-examples/helmholtz_scattering.jl @@ -8,22 +8,22 @@ using InteractiveUtils begin import Pkg as _Pkg haskey(ENV, "PLUTO_PROJECT") && _Pkg.activate(ENV["PLUTO_PROJECT"]) - using PlutoUI: with_terminal, TableOfContents + using PlutoUI: TableOfContents end ; # ╔═╡ ef067551-aa44-4099-b32a-08debb81ee79 -begin # hide -using Inti -using LinearAlgebra -using StaticArrays -using Gmsh -using Meshes -using GLMakie -using SpecialFunctions -using GSL -using IterativeSolvers -using LinearMaps -end # hide +begin + using Inti + using LinearAlgebra + using StaticArrays + using Gmsh + using Meshes + using GLMakie + using SpecialFunctions + using GSL + using IterativeSolvers + using LinearMaps +end # ╔═╡ a6c80f87-ff47-496f-8925-1275b58b02e1 md""" @@ -121,12 +121,13 @@ and setup some of the (global) problem parameters: """ # ╔═╡ 4cabe108-93c6-4fbf-b8ec-37277abbbda1 -begin # hide -k = 4π -λ = 2π / k -qorder = 4 # quadrature order -gorder = 2 # order of geometrical approximation -end; # hide +begin + k = 4π + λ = 2π / k + qorder = 4 # quadrature order + gorder = 2 # order of geometrical approximation + nothing #hide +end # ╔═╡ a33f066e-307c-42c4-836b-5b7d8236a893 md""" @@ -136,21 +137,24 @@ We will use [Gmsh API](https://gmsh.info/doc/texinfo/gmsh.html#Gmsh-application- """ # ╔═╡ cb736b4d-bbd6-456c-9041-f69b2155a470 -function gmsh_circle(; name, meshsize, order = 1, radius = 1, center = (0, 0)) - try - gmsh.initialize() - gmsh.model.add("circle-mesh") - gmsh.option.setNumber("Mesh.MeshSizeMax", meshsize) - gmsh.option.setNumber("Mesh.MeshSizeMin", meshsize) - gmsh.model.occ.addDisk(center[1], center[2], 0, radius, radius) - gmsh.model.occ.synchronize() - gmsh.model.mesh.generate(1) - gmsh.model.mesh.setOrder(order) - gmsh.write(name) - finally - gmsh.finalize() - end -end; +begin + function gmsh_circle(; name, meshsize, order = 1, radius = 1, center = (0, 0)) + try + gmsh.initialize() + gmsh.model.add("circle-mesh") + gmsh.option.setNumber("Mesh.MeshSizeMax", meshsize) + gmsh.option.setNumber("Mesh.MeshSizeMin", meshsize) + gmsh.model.occ.addDisk(center[1], center[2], 0, radius, radius) + gmsh.model.occ.synchronize() + gmsh.model.mesh.generate(1) + gmsh.model.mesh.setOrder(order) + gmsh.write(name) + finally + gmsh.finalize() + end + end + nothing #hide +end # ╔═╡ 2ed4fd2d-b3c2-4211-bf3f-c551923e65cf md""" @@ -158,32 +162,23 @@ Let us now use `gmsh_circle` to create a `circle.msh` file. As customary in wave """ # ╔═╡ 12e20620-042c-4040-bd64-af01bd0f2ad9 -# ╠═╡ show_logs = false -begin # hide -name = joinpath(@__DIR__, "circle.msh") -meshsize = λ / 5 -gmsh_circle(; meshsize, order = gorder, name) -end # hide - -# ╔═╡ 867186cf-fd4c-484b-9ded-344573ccda4f -let # to render terminal output in the documentation - with_terminal() do - name = joinpath(@__DIR__, "circle.msh") - meshsize = λ / 5 - gmsh_circle(; meshsize, order = gorder, name) - end +begin + name = joinpath(@__DIR__, "circle.msh") + meshsize = λ / 5 + gmsh_circle(; meshsize, order = gorder, name) end # ╔═╡ 24454bd5-00cf-4282-926f-f1324141fe26 md""" -We can now import the file and parse the mesh and domain information into `Inti.jl` using the [`import_mesh`](../../docstrings/#Inti.import_mesh-Tuple) function: +We can now import the file and parse the mesh and domain information into `Inti.jl` using the [`import_mesh`](@ref Inti.import_mesh) function: """ # ╔═╡ ff73663c-7cf4-4b23-83b5-095dc66f711f -begin # hide -Inti.clear_entities!() # empty the entity cache -msh = Inti.import_mesh(name; dim = 2) -end # hide +# ╠═╡ show_logs = false +begin + Inti.clear_entities!() # empty the entity cache + msh = Inti.import_mesh(name; dim = 2) +end # ╔═╡ 176f1fef-f761-4ad0-8fea-982eab4fe24d md""" @@ -195,16 +190,17 @@ The code above will import the mesh with all of its geometrical entities. The `d # ╔═╡ 3251d71a-b84c-48d8-9dff-01b2457e610b md""" -To solve our boundary integral equation usign a Nyström method, we actually need a quadrature of our curve/surface (and possibly the normal vectors at the quadrature nodes). Once a mesh is available, creating a quadrature object can be done via the [`Quadrature`](../../docstrings/#Inti.Quadrature) constructor, which requires passing a mesh of the domain that one wishes to generate a quadrature +To solve our boundary integral equation usign a Nyström method, we actually need a quadrature of our curve/surface (and possibly the normal vectors at the quadrature nodes). Once a mesh is available, creating a quadrature object can be done via the [`Quadrature`](@ref Inti.Quadrature) constructor, which requires passing a mesh of the domain that one wishes to generate a quadrature for: """ # ╔═╡ 09a785ae-7286-4a47-b103-1e90efa20167 -begin # hide -Γ = Inti.boundary(Ω) -Γ_msh = view(msh, Γ) -Q = Inti.Quadrature(Γ_msh; qorder) -end; # hide +begin + Γ = Inti.boundary(Ω) + Γ_msh = view(msh, Γ) + Q = Inti.Quadrature(Γ_msh; qorder) + nothing #hide +end # ╔═╡ 593216db-810e-47db-b6cb-aa6cf53e8590 md""" @@ -230,20 +226,21 @@ abs(Inti.integrate(x -> 1, Q) - 2π) # ╔═╡ 78ac2790-60d4-40da-bf5d-09617f1445a2 md""" -With the [`Quadrature`](../../docstrings/#Inti.Quadrature) constructed, we now can define discrete approximation to the integral operators ``\mathrm{S}`` and ``\mathrm{D}`` as follows: +With the [`Quadrature`](@ref Inti.Quadrature) constructed, we now can define discrete approximation to the integral operators ``\mathrm{S}`` and ``\mathrm{D}`` as follows: """ # ╔═╡ 9b37d163-15ca-44af-9e00-7410956fc16c -begin # hide -pde = Inti.Helmholtz(; k, dim = 2) -S, D = Inti.single_double_layer(; - pde, - target = Q, - source = Q, - compression = (method = :none,), - correction = (method = :dim,), -) -end; # hide +begin + pde = Inti.Helmholtz(; k, dim = 2) + S, D = Inti.single_double_layer(; + pde, + target = Q, + source = Q, + compression = (method = :none,), + correction = (method = :dim,), + ) + nothing #hide +end # ╔═╡ 061b7503-bad0-411e-b126-eea4b89feb03 md""" @@ -251,13 +248,16 @@ There are two well-known difficulties related to the discretization of the bound - The kernel of the integral operator is not smooth, and thus specialized quadrature rules are required to accurately approximate the matrix entries for which the target and source point lie *close* (relative to some scale) to each other. - The underlying matrix is dense, and thus the storage and computational cost of the operator is prohibitive for large problems unless acceleration techniques such as *Fast Multipole Methods* or *Hierarchical Matrices* are employed. -`Inti.jl` tries to provide a modular and transparent interface for dealing with both of these difficulties, where the general approach for solving a BIE will be to first construct a (possible compressed) naive representation of the integral operator where singular and nearly-singular integrals are ignored, followed by a the creation of a (sparse) correction intended to account for such singular interactions. See [`single_double_layer`](../../docstrings/#Inti.single_double_layer-Tuple{}) for more details on the various options available. +`Inti.jl` tries to provide a modular and transparent interface for dealing with both of these difficulties, where the general approach for solving a BIE will be to first construct a (possible compressed) naive representation of the integral operator where singular and nearly-singular integrals are ignored, followed by a the creation of a (sparse) correction intended to account for such singular interactions. See [`single_double_layer`](@ref Inti.single_double_layer) for more details on the various options available. We can now combine `S` and `D` to form the combined-field operator: """ # ╔═╡ ebaf6ed5-8e01-4c5f-9d7f-8cdc32a68022 -L = I / 2 + D - im * k * S ; +begin + L = I / 2 + D - im * k * S + nothing #hide +end # ╔═╡ 8ba9aadc-5b34-41cb-adba-1ebdc65a741d md""" @@ -265,18 +265,19 @@ where `I` is the identity matrix. Assuming an incident field along the $x_1$ dir """ # ╔═╡ eaf2025e-1135-4ee6-9dea-25e2c0c09ec8 -begin # hide -uᵢ = x -> exp(im * k * x[1]) # plane-wave incident field -rhs = map(Q) do q - x = q.coords - return -uᵢ(x) +begin + uᵢ = x -> exp(im * k * x[1]) # plane-wave incident field + rhs = map(Q) do q + x = q.coords + return -uᵢ(x) + end + nothing #hide end -end; # hide # ╔═╡ 7fcd47c1-9d65-41e2-9363-141d53f0dbca md""" !!! note "Iterating over a quadrature" - In computing `rhs` above, we used `map` to evaluate the incident field at all quadrature nodes. When iterating over `Q`, the iterator returns a [`QuadratureNode`](../docstrings/#Inti.QuadratureNode), and not simply the *coordinate* of the quadrature node. This is so that you can access additional information, such as the `normal` vector, at the quadrature node. + In computing `rhs` above, we used `map` to evaluate the incident field at all quadrature nodes. When iterating over `Q`, the iterator returns a [`QuadratureNode`](@ref Inti.QuadratureNode), and not simply the *coordinate* of the quadrature node. This is so that you can access additional information, such as the `normal` vector, at the quadrature node. """ # ╔═╡ 4cdf0551-1d13-4060-88e6-cf86ad180938 @@ -285,18 +286,22 @@ We can now solve the integral equation using e.g. the backslash operator: """ # ╔═╡ 2925e1a3-1051-4b09-bbd9-461c6a76a1e3 -σ = L \ rhs ; +begin + σ = L \ rhs + nothing #hide +end # ╔═╡ b26e0c64-b3f1-4b18-a6f5-8f789407a744 md""" -The variable `σ` contains the value of the approximate density at the quadrature nodes. To reconstruct a continuous approximation to the solution, we can use [`single_double_layer_potential`](../../docstrings/#Inti.single_double_layer_potential-Tuple{}) to obtain the single- and double-layer potentials, and then combine them as follows: +The variable `σ` contains the value of the approximate density at the quadrature nodes. To reconstruct a continuous approximation to the solution, we can use [`single_double_layer_potential`](@ref Inti.single_double_layer_potential) to obtain the single- and double-layer potentials, and then combine them as follows: """ # ╔═╡ fd0f2cf4-1b18-4c56-84a9-2339b3dfc10a -begin # hide -𝒮, 𝒟 = Inti.single_double_layer_potential(; pde, source = Q) -uₛ = x -> 𝒟[σ](x) - im * k * 𝒮[σ](x) -end; # hide +begin + 𝒮, 𝒟 = Inti.single_double_layer_potential(; pde, source = Q) + uₛ = x -> 𝒟[σ](x) - im * k * 𝒮[σ](x) + nothing #hide +end # ╔═╡ 12b3c26a-96b3-440b-9771-4a945fe14ce7 md""" @@ -306,24 +311,27 @@ To assess the accuracy of the solution, we can compare it to the exact solution """ # ╔═╡ 185cfa1e-7c87-4243-8f5e-c5983932e135 -function circle_helmholtz_soundsoft(pt; radius = 1, k, θin) - x = pt[1] - y = pt[2] - r = sqrt(x^2 + y^2) - θ = atan(y, x) - u = 0.0 - r < radius && return u - c(n) = -exp(im * n * (π / 2 - θin)) * besselj(n, k * radius) / besselh(n, k * radius) - u = c(0) * besselh(0, k * r) - n = 1 - while (abs(c(n)) > 1e-12) - u += - c(n) * besselh(n, k * r) * exp(im * n * θ) + - c(-n) * besselh(-n, k * r) * exp(-im * n * θ) - n += 1 - end - return u -end; +begin + function circle_helmholtz_soundsoft(pt; radius = 1, k, θin) + x = pt[1] + y = pt[2] + r = sqrt(x^2 + y^2) + θ = atan(y, x) + u = 0.0 + r < radius && return u + c(n) = -exp(im * n * (π / 2 - θin)) * besselj(n, k * radius) / besselh(n, k * radius) + u = c(0) * besselh(0, k * r) + n = 1 + while (abs(c(n)) > 1e-12) + u += + c(n) * besselh(n, k * r) * exp(im * n * θ) + + c(-n) * besselh(-n, k * r) * exp(-im * n * θ) + n += 1 + end + return u + end + nothing #hide +end # ╔═╡ 4c37081c-4f68-48fe-be5b-bebf35f0c35e md""" @@ -331,24 +339,18 @@ Here is the maximum error on some points located on a circle of radius `2`: """ # ╔═╡ 1daa0518-a98b-448c-bddd-1147a0f7ed4d -# ╠═╡ show_logs = false -begin # hide -uₑ = x -> circle_helmholtz_soundsoft(x; k, radius = 1, θin = 0) # exact solution -er = maximum(0:0.01:2π) do θ - R = 2 - x = (R * cos(θ), R * sin(θ)) - return abs(uₛ(x) - uₑ(x)) +begin + uₑ = x -> circle_helmholtz_soundsoft(x; k, radius = 1, θin = 0) # exact solution + er = maximum(0:0.01:2π) do θ + R = 2 + x = (R * cos(θ), R * sin(θ)) + return abs(uₛ(x) - uₑ(x)) + end + @info "maximum error = $er" end -@info "maximum error = $er" -end # hide # ╔═╡ 3557cd23-43b2-4c79-a0e9-53c0d9650851 -let - @assert er < 1e-3 - with_terminal() do - @info "maximum error = $er" - end -end +@assert er < 1e-3 # ╔═╡ 42a42555-0c97-4a40-8865-38966983a9e7 md""" @@ -356,22 +358,22 @@ As we can see, the error is quite small! Let's use `Makie` to visualize the solu """ # ╔═╡ 56350a37-b2d8-463e-934f-e8a4fbf72c67 -begin # hide -xx = yy = range(-4; stop = 4, length = 200) -vals = - map(pt -> Inti.isinside(pt, Q) ? NaN : real(uₛ(pt) + uᵢ(pt)), Iterators.product(xx, yy)) -fig, ax, hm = heatmap( - xx, - yy, - vals; - colormap = :inferno, - interpolate = true, - axis = (aspect = DataAspect(), xgridvisible = false, ygridvisible = false), -) -viz!(Γ_msh; color = :white, segmentsize = 5) -Colorbar(fig[1, 2], hm) -fig -end # hide +begin + xx = yy = range(-4; stop = 4, length = 200) + vals = + map(pt -> Inti.isinside(pt, Q) ? NaN : real(uₛ(pt) + uᵢ(pt)), Iterators.product(xx, yy)) + fig, ax, hm = heatmap( + xx, + yy, + vals; + colormap = :inferno, + interpolate = true, + axis = (aspect = DataAspect(), xgridvisible = false, ygridvisible = false), + ) + viz!(Γ_msh; color = :white, segmentsize = 5) + Colorbar(fig[1, 2], hm) + fig +end # ╔═╡ 471a5475-1ef5-4f40-bb45-a3e29ae5c0a8 md""" @@ -381,50 +383,50 @@ Before moving on to the 3D example let us simply mention that, besides the fact """ # ╔═╡ 3f3f4794-f2bf-4171-a1b4-70fd38c01fc3 -let # hide -# vertices of an equilateral triangle centered at the origin with a vertex at (0,1) -a, b, c = SVector(0, 1), SVector(sqrt(3) / 2, -1 / 2), SVector(-sqrt(3) / 2, -1 / 2) -circle_f(center, radius) = s -> center + radius * SVector(cospi(2 * s[1]), sinpi(2 * s[1])) -disk1 = Inti.parametric_curve(circle_f(a, 1 / 2), 0, 1) -disk2 = Inti.parametric_curve(circle_f(b, 1 / 2), 0, 1) -disk3 = Inti.parametric_curve(circle_f(c, 1 / 2), 0, 1) -Γ = disk1 ∪ disk2 ∪ disk3 -msh = Inti.meshgen(Γ; meshsize) -Γ_msh = view(msh, Γ) -Q = Inti.Quadrature(Γ_msh; qorder) -S, D = Inti.single_double_layer(; - pde, - target = Q, - source = Q, - compression = (method = :none,), - correction = (method = :dim,), -) -L = I / 2 + D - im * k * S -rhs = map(q -> -uᵢ(q.coords), Q) -σ = L \ rhs -𝒮, 𝒟 = Inti.single_double_layer_potential(; pde, source = Q) -uₛ = x -> 𝒟[σ](x) - im * k * 𝒮[σ](x) -vals = - map(pt -> Inti.isinside(pt, Q) ? NaN : real(uₛ(pt) + uᵢ(pt)), Iterators.product(xx, yy)) -colorrange = (-2, 2) -fig, ax, hm = heatmap( - xx, - yy, - vals; - colormap = :inferno, - colorrange, - interpolate = true, - axis = (aspect = DataAspect(), xgridvisible = false, ygridvisible = false), -) -viz!(Γ_msh; color = :black, segmentsize = 4) -Colorbar(fig[1, 2], hm) -fig -end # hide +let + # vertices of an equilateral triangle centered at the origin with a vertex at (0,1) + a, b, c = SVector(0, 1), SVector(sqrt(3) / 2, -1 / 2), SVector(-sqrt(3) / 2, -1 / 2) + circle_f(center, radius) = s -> center + radius * SVector(cospi(2 * s[1]), sinpi(2 * s[1])) + disk1 = Inti.parametric_curve(circle_f(a, 1 / 2), 0, 1) + disk2 = Inti.parametric_curve(circle_f(b, 1 / 2), 0, 1) + disk3 = Inti.parametric_curve(circle_f(c, 1 / 2), 0, 1) + Γ = disk1 ∪ disk2 ∪ disk3 + msh = Inti.meshgen(Γ; meshsize) + Γ_msh = view(msh, Γ) + Q = Inti.Quadrature(Γ_msh; qorder) + S, D = Inti.single_double_layer(; + pde, + target = Q, + source = Q, + compression = (method = :none,), + correction = (method = :dim,), + ) + L = I / 2 + D - im * k * S + rhs = map(q -> -uᵢ(q.coords), Q) + σ = L \ rhs + 𝒮, 𝒟 = Inti.single_double_layer_potential(; pde, source = Q) + uₛ = x -> 𝒟[σ](x) - im * k * 𝒮[σ](x) + vals = + map(pt -> Inti.isinside(pt, Q) ? NaN : real(uₛ(pt) + uᵢ(pt)), Iterators.product(xx, yy)) + colorrange = (-2, 2) + fig, ax, hm = heatmap( + xx, + yy, + vals; + colormap = :inferno, + colorrange, + interpolate = true, + axis = (aspect = DataAspect(), xgridvisible = false, ygridvisible = false), + ) + viz!(Γ_msh; color = :black, segmentsize = 4) + Colorbar(fig[1, 2], hm) + fig +end # ╔═╡ b8fd284a-3865-4762-9602-6bc1eba464a4 md""" !!! note "Near-field evaluation" - In the example above we employed a naive evaluation of the integral potentials, and therefore the computed solution is expected to become innacurate near the obstacles. See the [layer potential tutorial](../../tutorials/layer_potentials/#Layer-potentials) for more information on how to correct for this. + In the example above we employed a naive evaluation of the integral potentials, and therefore the computed solution is expected to become innacurate near the obstacles. See the [layer potential tutorial](@ref "Layer potentials") for more information on how to correct for this. """ # ╔═╡ 8b7fc104-324d-42c7-98b7-dff0df561ce2 @@ -437,27 +439,30 @@ The visualization is also more involved, and we will use the `Gmsh` API to creat """ # ╔═╡ b02fbb5b-ce97-48e7-ab2b-a8db6ca7c8d3 -function gmsh_sphere(; meshsize, order = gorder, radius = 1, visualize = false, name) - gmsh.initialize() - gmsh.model.add("sphere-scattering") - gmsh.option.setNumber("Mesh.MeshSizeMax", meshsize) - gmsh.option.setNumber("Mesh.MeshSizeMin", meshsize) - sphere_tag = gmsh.model.occ.addSphere(0, 0, 0, radius) - xl, yl, zl = -2 * radius, -2 * radius, 0 - Δx, Δy = 4 * radius, 4 * radius - rectangle_tag = gmsh.model.occ.addRectangle(xl, yl, zl, Δx, Δy) - outDimTags, _ = - gmsh.model.occ.cut([(2, rectangle_tag)], [(3, sphere_tag)], -1, true, false) - gmsh.model.occ.synchronize() - gmsh.model.addPhysicalGroup(3, [sphere_tag], -1, "omega") - gmsh.model.addPhysicalGroup(2, [dt[2] for dt in outDimTags], -1, "sigma") - gmsh.model.mesh.generate(2) - gmsh.model.mesh.setOrder(order) - visualize && gmsh.fltk.run() - gmsh.option.setNumber("Mesh.SaveAll", 1) # otherwise only the physical groups are saved - gmsh.write(name) - return gmsh.finalize() -end; +begin + function gmsh_sphere(; meshsize, order = gorder, radius = 1, visualize = false, name) + gmsh.initialize() + gmsh.model.add("sphere-scattering") + gmsh.option.setNumber("Mesh.MeshSizeMax", meshsize) + gmsh.option.setNumber("Mesh.MeshSizeMin", meshsize) + sphere_tag = gmsh.model.occ.addSphere(0, 0, 0, radius) + xl, yl, zl = -2 * radius, -2 * radius, 0 + Δx, Δy = 4 * radius, 4 * radius + rectangle_tag = gmsh.model.occ.addRectangle(xl, yl, zl, Δx, Δy) + outDimTags, _ = + gmsh.model.occ.cut([(2, rectangle_tag)], [(3, sphere_tag)], -1, true, false) + gmsh.model.occ.synchronize() + gmsh.model.addPhysicalGroup(3, [sphere_tag], -1, "omega") + gmsh.model.addPhysicalGroup(2, [dt[2] for dt in outDimTags], -1, "sigma") + gmsh.model.mesh.generate(2) + gmsh.model.mesh.setOrder(order) + visualize && gmsh.fltk.run() + gmsh.option.setNumber("Mesh.SaveAll", 1) # otherwise only the physical groups are saved + gmsh.write(name) + return gmsh.finalize() + end + nothing #hide +end # ╔═╡ 49f0edcd-9cb8-4722-ae56-b17ee48f8336 md""" @@ -465,11 +470,12 @@ As before, lets write a file with our mesh, and import it into `Inti.jl`: """ # ╔═╡ a18b8726-fa97-4388-bb8b-53965a5d433b -begin # hide -name_sphere = joinpath(@__DIR__, "sphere.msh") -gmsh_sphere(; meshsize=(λ / 5), order = gorder, name=name_sphere, visualize = false) -msh_3d = Inti.import_mesh(name_sphere; dim = 3) -end # hide +# ╠═╡ show_logs = false +begin + name_sphere = joinpath(@__DIR__, "sphere.msh") + gmsh_sphere(; meshsize=(λ / 5), order = gorder, name=name_sphere, visualize = false) + msh_3d = Inti.import_mesh(name_sphere; dim = 3) +end # ╔═╡ 063e3185-8714-4955-b985-5413420a889b md""" @@ -483,11 +489,12 @@ Since we created physical groups in `Gmsh`, we can use them to extract the relev """ # ╔═╡ 631328d5-c961-41e1-ac0e-181c3bb75112 -begin # hide -Ω_3d = Inti.Domain(e -> "omega" ∈ Inti.labels(e), Inti.entities(msh_3d)) -Σ_3d = Inti.Domain(e -> "sigma" ∈ Inti.labels(e), Inti.entities(msh_3d)) -Γ_3d = Inti.boundary(Ω_3d) -end; # hide +begin + Ω_3d = Inti.Domain(e -> "omega" ∈ Inti.labels(e), Inti.entities(msh_3d)) + Σ_3d = Inti.Domain(e -> "sigma" ∈ Inti.labels(e), Inti.entities(msh_3d)) + Γ_3d = Inti.boundary(Ω_3d) + nothing #hide +end # ╔═╡ dbd6d298-0fbf-420f-9622-d1db1d550cc5 md""" @@ -495,28 +502,30 @@ We can now create a quadrature as before """ # ╔═╡ 6096328b-e1af-4ec5-b72b-cd381c166cb7 -begin # hide -Γ_msh_3d = view(msh_3d, Γ_3d) -Q_3d = Inti.Quadrature(Γ_msh_3d; qorder) -end; # hide +begin + Γ_msh_3d = view(msh_3d, Γ_3d) + Q_3d = Inti.Quadrature(Γ_msh_3d; qorder) + nothing #hide +end # ╔═╡ 498fa575-5cf7-4a7e-8d3b-c50d605aa57c -begin # hide -using HMatrices -pde_3d = Inti.Helmholtz(; k, dim = 3) -S_3d, D_3d = Inti.single_double_layer(; - pde = pde_3d, - target = Q_3d, - source = Q_3d, - compression = (method = :hmatrix, tol = 1e-4), - correction = (method = :dim,), -) -end; # hide +begin + using HMatrices + pde_3d = Inti.Helmholtz(; k, dim = 3) + S_3d, D_3d = Inti.single_double_layer(; + pde = pde_3d, + target = Q_3d, + source = Q_3d, + compression = (method = :hmatrix, tol = 1e-4), + correction = (method = :dim,), + ) + nothing #hide +end # ╔═╡ b6cad085-eb74-4152-8850-226ed837febd md""" !!! tip "Writing/reading a mesh from disk" - Writing and reading a mesh to/from disk can be time consuming. You can avoid doing so by using [`import_mesh`](../../docstrings/#Inti.import_mesh-Tuple) without a file name to import the mesh from the current `gmsh` session without the need to write it to disk. + Writing and reading a mesh to/from disk can be time consuming. You can avoid doing so by using [`import_mesh`](@ref Inti.import_mesh) without a file name to import the mesh from the current `gmsh` session without the need to write it to disk. """ # ╔═╡ f5d990e9-8d05-41e6-b6b3-c737692de37a @@ -530,17 +539,9 @@ Here is how much memory it would take to store the dense representation of these """ # ╔═╡ 54f07c21-339b-44c3-9ac2-22af163d55ae -# ╠═╡ show_logs = false -begin # hide -mem = 2 * length(S_3d) * 16 / 1e9 # 16 bytes per complex number, 1e9 bytes per GB, two matrices -println("memory required to store S and D: $(mem) GB") -end # hide - -# ╔═╡ baea69b3-028b-4617-83f1-1ab9e2ca7115 -let # to render terminal output in the documentation - with_terminal() do - println("memory required to store S and D: $(mem) GB") - end +begin + mem = 2 * length(S_3d) * 16 / 1e9 # 16 bytes per complex number, 1e9 bytes per GB, two matrices + println("memory required to store S and D: $(mem) GB") end # ╔═╡ 915d3636-70bd-4001-857f-3aae11eb2d2e @@ -551,7 +552,7 @@ Even for this simple example, the dense representation of the integral operators # ╔═╡ bc09986a-5378-4d0b-a2b2-df9245f3f9cf md""" !!! note "Compression methods" - It is worth mentioning that hierchical matrices are not the only way to compress such integral operators, and may in fact not even be the best for the problem at hand. For example, one could use a fast multipole method (FMM), which has a much lighter memory footprint. See the the [tutorial on compression methods](../../tutorials/compression_methods/#Compression-methods) for more information. + It is worth mentioning that hierchical matrices are not the only way to compress such integral operators, and may in fact not even be the best for the problem at hand. For example, one could use a fast multipole method (FMM), which has a much lighter memory footprint. See the the [tutorial on compression methods](@ref "Compression methods") for more information. """ # ╔═╡ b9e36a69-a3d1-41c8-8951-01f92acf0806 @@ -560,7 +561,10 @@ We will use the generalized minimal residual (GMRES) iterative solver, for the l """ # ╔═╡ a2ddce1e-440e-49e2-8c3e-ec6960ff83f0 -L_3d = I / 2 + LinearMap(D_3d) - im * k * LinearMap(S_3d) ; +begin + L_3d = I / 2 + LinearMap(D_3d) - im * k * LinearMap(S_3d) + nothing #hide +end # ╔═╡ f148c58a-50d3-4ac2-a1da-148563d533e7 md""" @@ -569,15 +573,15 @@ We can now solve the linear system using GMRES solver: # ╔═╡ dcf006a3-5332-442a-9771-f427cd7189a5 # ╠═╡ show_logs = false -begin # hide -rhs_3d = map(Q_3d) do q - x = q.coords - return -uᵢ(x) +begin + rhs_3d = map(Q_3d) do q + x = q.coords + return -uᵢ(x) + end + σ_3d, hist = + gmres(L_3d, rhs_3d; log = true, abstol = 1e-6, verbose = false, restart = 100, maxiter = 100) + @show hist end -σ_3d, hist = - gmres(L_3d, rhs_3d; log = true, abstol = 1e-6, verbose = false, restart = 100, maxiter = 100) -@show hist -end # hide # ╔═╡ 215677a6-af7b-4e5d-863f-aabdfb4a1400 md""" @@ -585,10 +589,11 @@ As before, let us represent the solution using `IntegralPotential`s: """ # ╔═╡ 14a549ad-e23f-40a4-b7fa-ef31354805a9 -begin # hide -𝒮_3d, 𝒟_3d = Inti.single_double_layer_potential(; pde=pde_3d, source = Q_3d) -uₛ_3d = x -> 𝒟_3d[σ_3d](x) - im * k * 𝒮_3d[σ_3d](x) -end; # hide +begin + 𝒮_3d, 𝒟_3d = Inti.single_double_layer_potential(; pde=pde_3d, source = Q_3d) + uₛ_3d = x -> 𝒟_3d[σ_3d](x) - im * k * 𝒮_3d[σ_3d](x) + nothing #hide +end # ╔═╡ 832858dc-2475-4f6a-a820-a557b2883f0c md""" @@ -596,32 +601,33 @@ To check the result, we compare against the exact solution obtained through a se """ # ╔═╡ e00c4d90-aa3b-41f9-b65e-7e9ace89a295 -begin # hide -sphbesselj(l, r) = sqrt(π / (2r)) * besselj(l + 1 / 2, r) -sphbesselh(l, r) = sqrt(π / (2r)) * besselh(l + 1 / 2, r) -sphharmonic(l, m, θ, ϕ) = GSL.sf_legendre_sphPlm(l, abs(m), cos(θ)) * exp(im * m * ϕ) -function sphere_helmholtz_soundsoft(xobs; radius = 1, k = 1, θin = 0, ϕin = 0) - x = xobs[1] - y = xobs[2] - z = xobs[3] - r = sqrt(x^2 + y^2 + z^2) - θ = acos(z / r) - ϕ = atan(y, x) - u = 0.0 - r < radius && return u - function c(l, m) - return -4π * im^l * sphharmonic(l, -m, θin, ϕin) * sphbesselj(l, k * radius) / sphbesselh(l, k * radius) - end - l = 0 - for l in 0:60 - for m in -l:l - u += c(l, m) * sphbesselh(l, k * r) * sphharmonic(l, m, θ, ϕ) - end - l += 1 - end - return u +begin + sphbesselj(l, r) = sqrt(π / (2r)) * besselj(l + 1 / 2, r) + sphbesselh(l, r) = sqrt(π / (2r)) * besselh(l + 1 / 2, r) + sphharmonic(l, m, θ, ϕ) = GSL.sf_legendre_sphPlm(l, abs(m), cos(θ)) * exp(im * m * ϕ) + function sphere_helmholtz_soundsoft(xobs; radius = 1, k = 1, θin = 0, ϕin = 0) + x = xobs[1] + y = xobs[2] + z = xobs[3] + r = sqrt(x^2 + y^2 + z^2) + θ = acos(z / r) + ϕ = atan(y, x) + u = 0.0 + r < radius && return u + function c(l, m) + return -4π * im^l * sphharmonic(l, -m, θin, ϕin) * sphbesselj(l, k * radius) / sphbesselh(l, k * radius) + end + l = 0 + for l in 0:60 + for m in -l:l + u += c(l, m) * sphbesselh(l, k * r) * sphharmonic(l, m, θ, ϕ) + end + l += 1 + end + return u + end + nothing #hide end -end; # hide # ╔═╡ bb87f66d-5e68-49c5-9167-bdbab60109e5 md""" @@ -629,24 +635,18 @@ We will compute the error on some point on the sphere of radius `2`: """ # ╔═╡ 3848717e-0c30-4c0b-82ec-b504c9210483 -# ╠═╡ show_logs = false -begin # hide -uₑ_3d = (x) -> sphere_helmholtz_soundsoft(x; radius = 1, k = k, θin = π / 2, ϕin = 0) -er_3d = maximum(1:100) do _ - x̂ = rand(Inti.Point3D) |> normalize # an SVector of unit norm - x = 2 * x̂ - return abs(uₛ_3d(x) - uₑ_3d(x)) +begin + uₑ_3d = (x) -> sphere_helmholtz_soundsoft(x; radius = 1, k = k, θin = π / 2, ϕin = 0) + er_3d = maximum(1:100) do _ + x̂ = rand(Inti.Point3D) |> normalize # an SVector of unit norm + x = 2 * x̂ + return abs(uₛ_3d(x) - uₑ_3d(x)) + end + @info "error with correction = $er_3d" end -@info "error with correction = $er_3d" -end # hide # ╔═╡ 36ddb3be-7103-429f-9011-99c27c655de5 -let # Render terminal output in documentation - with_terminal() do - @assert er_3d < 1e-3 #hide - @info "error with correction = $er_3d" - end -end +@assert er_3d < 1e-3 # ╔═╡ 386046f6-6909-4e9e-bb90-80c32df59f70 md""" @@ -654,43 +654,42 @@ We see that, once again, the approximation is quite accurate. Let us now visuali """ # ╔═╡ b2b31b38-4c2f-4763-9273-971749c40d5c -begin # hide -Σ_msh = view(msh_3d, Σ_3d) -target = Inti.nodes(Σ_msh) - -S_viz, D_viz = Inti.single_double_layer(; - pde = pde_3d, - target, - source = Q_3d, - compression = (method = :hmatrix, tol = 1e-4), - # correction for the nearfield (for visual purposes, set to `:none` to disable) - correction = (method = :dim, maxdist = meshsize, target_location = :outside), -) - -ui_eval_msh = uᵢ.(target) -us_eval_msh = D_viz * σ_3d - im * k * S_viz * σ_3d -u_eval_msh = ui_eval_msh + us_eval_msh -end; # hide +begin + Σ_msh = view(msh_3d, Σ_3d) + target = Inti.nodes(Σ_msh) + + S_viz, D_viz = Inti.single_double_layer(; + pde = pde_3d, + target, + source = Q_3d, + compression = (method = :hmatrix, tol = 1e-4), + # correction for the nearfield (for visual purposes, set to `:none` to disable) + correction = (method = :dim, maxdist = meshsize, target_location = :outside), + ) + + ui_eval_msh = uᵢ.(target) + us_eval_msh = D_viz * σ_3d - im * k * S_viz * σ_3d + u_eval_msh = ui_eval_msh + us_eval_msh + nothing #hide +end # ╔═╡ 0cec09b1-8806-4aee-970d-cc0b1e4b841c md""" -Finalize, we use [`Meshes.viz`](https://juliageometry.github.io/MeshesDocs/dev/visualization/#Meshes.viz) to visualize the scattered field: +Finalize, we use [`Meshes.viz`](@extref) to visualize the scattered field: """ # ╔═╡ dab9a19c-977e-4ab1-a3d9-f9970af69642 -begin # hide -nv = length(Inti.nodes(Γ_msh_3d)) -colorrange = extrema(real(u_eval_msh)) -colormap = :inferno -fig_3d = Figure(; size = (800, 500)) -ax_3d = Axis3(fig_3d[1, 1]; aspect = :data) -viz!(Γ_msh_3d; colorrange, colormap, color = zeros(nv), interpolate = true) -viz!(Σ_msh; colorrange, colormap, color = real(u_eval_msh)) -cb = Colorbar(fig_3d[1, 2]; label = "real(u)", colormap, colorrange) -end; # hide - -# ╔═╡ 0c1114d1-256c-44e3-bbd4-9b5077fc7ee8 -fig_3d +begin + nv = length(Inti.nodes(Γ_msh_3d)) + colorrange = extrema(real(u_eval_msh)) + colormap = :inferno + fig_3d = Figure(; size = (800, 500)) + ax_3d = Axis3(fig_3d[1, 1]; aspect = :data) + viz!(Γ_msh_3d; colorrange, colormap, color = zeros(nv), interpolate = true) + viz!(Σ_msh; colorrange, colormap, color = real(u_eval_msh)) + cb = Colorbar(fig_3d[1, 2]; label = "real(u)", colormap, colorrange) + fig_3d #hide +end # ╔═╡ 765e46fc-dac3-439a-ab07-2865298aed45 TableOfContents() @@ -2766,7 +2765,6 @@ version = "1.4.1+1" # ╠═cb736b4d-bbd6-456c-9041-f69b2155a470 # ╟─2ed4fd2d-b3c2-4211-bf3f-c551923e65cf # ╠═12e20620-042c-4040-bd64-af01bd0f2ad9 -# ╟─867186cf-fd4c-484b-9ded-344573ccda4f # ╟─24454bd5-00cf-4282-926f-f1324141fe26 # ╠═ff73663c-7cf4-4b23-83b5-095dc66f711f # ╟─176f1fef-f761-4ad0-8fea-982eab4fe24d @@ -2812,7 +2810,6 @@ version = "1.4.1+1" # ╠═498fa575-5cf7-4a7e-8d3b-c50d605aa57c # ╟─ba95db2c-979a-41f2-9705-92d3cedd0160 # ╠═54f07c21-339b-44c3-9ac2-22af163d55ae -# ╟─baea69b3-028b-4617-83f1-1ab9e2ca7115 # ╟─915d3636-70bd-4001-857f-3aae11eb2d2e # ╟─bc09986a-5378-4d0b-a2b2-df9245f3f9cf # ╟─b9e36a69-a3d1-41c8-8951-01f92acf0806 @@ -2830,7 +2827,6 @@ version = "1.4.1+1" # ╠═b2b31b38-4c2f-4763-9273-971749c40d5c # ╟─0cec09b1-8806-4aee-970d-cc0b1e4b841c # ╠═dab9a19c-977e-4ab1-a3d9-f9970af69642 -# ╟─0c1114d1-256c-44e3-bbd4-9b5077fc7ee8 # ╟─765e46fc-dac3-439a-ab07-2865298aed45 # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002 diff --git a/docs/src/pluto-examples/poisson.jl b/docs/src/pluto-examples/poisson.jl index 1667383a..ece579b9 100644 --- a/docs/src/pluto-examples/poisson.jl +++ b/docs/src/pluto-examples/poisson.jl @@ -8,28 +8,27 @@ using InteractiveUtils begin import Pkg as _Pkg haskey(ENV, "PLUTO_PROJECT") && _Pkg.activate(ENV["PLUTO_PROJECT"]) - using PlutoUI: with_terminal, TableOfContents + using PlutoUI: TableOfContents end ; # ╔═╡ 332bd3bb-c720-454e-80af-89ad65041773 -# ╠═╡ show_logs = false -begin # hide -using Inti, Gmsh -meshsize = 0.1 -gmsh.initialize() -jellyfish = Inti.gmsh_curve(0, 2π; meshsize) do s - r = 1 + 0.3*cos(4*s + 2*sin(s)) - return r*Inti.Point2D(cos(s), sin(s)) +begin + using Inti, Gmsh + meshsize = 0.1 + gmsh.initialize() + jellyfish = Inti.gmsh_curve(0, 2π; meshsize) do s + r = 1 + 0.3*cos(4*s + 2*sin(s)) + return r*Inti.Point2D(cos(s), sin(s)) + end + cl = gmsh.model.occ.addCurveLoop([jellyfish]) + surf = gmsh.model.occ.addPlaneSurface([cl]) + gmsh.model.occ.synchronize() + gmsh.option.setNumber("Mesh.MeshSizeMax", meshsize) + gmsh.model.mesh.generate(2) + gmsh.model.mesh.setOrder(2) + msh = Inti.import_mesh(; dim = 2) + gmsh.finalize() end -cl = gmsh.model.occ.addCurveLoop([jellyfish]) -surf = gmsh.model.occ.addPlaneSurface([cl]) -gmsh.model.occ.synchronize() -gmsh.option.setNumber("Mesh.MeshSizeMax", meshsize) -gmsh.model.mesh.generate(2) -gmsh.model.mesh.setOrder(2) -msh = Inti.import_mesh(; dim = 2) -gmsh.finalize() -end # hide # ╔═╡ aca57c74-d084-40e7-9760-edf988a64915 md""" @@ -110,26 +109,6 @@ We use the *Gmsh API* to create a jellyfish-shaped domain and to generate a second order mesh of its interior and boundary: """ -# ╔═╡ 546966b1-58c2-44e6-ac2c-578094251fce -let # For the output in the documentation -with_terminal() do - meshsize = 0.1 -gmsh.initialize() -jellyfish = Inti.gmsh_curve(0, 2π; meshsize) do s - r = 1 + 0.3*cos(4*s + 2*sin(s)) - return r*Inti.Point2D(cos(s), sin(s)) -end -cl = gmsh.model.occ.addCurveLoop([jellyfish]) -surf = gmsh.model.occ.addPlaneSurface([cl]) -gmsh.model.occ.synchronize() -gmsh.option.setNumber("Mesh.MeshSizeMax", meshsize) -gmsh.model.mesh.generate(2) -gmsh.model.mesh.setOrder(2) -msh_output = Inti.import_mesh(; dim = 2) -gmsh.finalize() -end -end - # ╔═╡ 1609838c-67ec-4d67-9c9b-993b1bd01fb6 md""" We can now extract components of the mesh corresponding to the ``\Omega`` and @@ -137,28 +116,27 @@ We can now extract components of the mesh corresponding to the ``\Omega`` and """ # ╔═╡ 4e580f9f-6e22-4160-b262-ca941b6bfb8f -begin # hide -Ω = Inti.Domain(e -> Inti.geometric_dimension(e) == 2, msh) -Γ = Inti.boundary(Ω) -Ω_msh = view(msh, Ω) -Γ_msh = view(msh, Γ) -end; # hide +begin + Ω = Inti.Domain(e -> Inti.geometric_dimension(e) == 2, msh) + Γ = Inti.boundary(Ω) + Ω_msh = view(msh, Ω) + Γ_msh = view(msh, Γ) + nothing #hide +end # ╔═╡ 2c4bace3-ef35-4500-829f-2f5ae6725249 -begin # hide -using Meshes, GLMakie -viz(Ω_msh; showsegments=true) -viz!(Γ_msh; color=:red) -end; # hide +begin + using Meshes, GLMakie + viz(Ω_msh; showsegments=true) + viz!(Γ_msh; color=:red) + Makie.current_figure() #hide +end # ╔═╡ 901578c3-b7aa-4023-bb99-769cf5805f57 md""" and visualize them: """ -# ╔═╡ 1bb0a7a4-8fab-4744-9cf1-94619bde5395 -Makie.current_figure() - # ╔═╡ b142b298-26a8-4373-934d-3bc8448a8fda md""" To conclude the geometric setup, we need a quadrature for the volume and @@ -166,28 +144,29 @@ boundary: """ # ╔═╡ 85ce61fc-086d-4661-8f03-6a6ae4d55511 -begin # hide -Ω_quad = Inti.Quadrature(Ω_msh; qorder = 4) -Γ_quad = Inti.Quadrature(Γ_msh; qorder = 6) -end; # hide +begin + Ω_quad = Inti.Quadrature(Ω_msh; qorder = 4) + Γ_quad = Inti.Quadrature(Γ_msh; qorder = 6) + nothing #hide +end # ╔═╡ 6e3ea607-2b70-485d-94f0-5626bab4f832 -begin # hide -using FMM2D #to accelerate the maps -pde = Inti.Laplace(; dim = 2) -# Newtonian potential mapping domain to boundary -V_d2b = Inti.volume_potential(; - pde, - target = Γ_quad, - source = Ω_quad, - compression = (method = :fmm, tol = 1e-12), - correction = ( - method = :dim, - maxdist = 5 * meshsize, - target_location = :on, - ), -) -end # hide +begin + using FMM2D #to accelerate the maps + pde = Inti.Laplace(; dim = 2) + # Newtonian potential mapping domain to boundary + V_d2b = Inti.volume_potential(; + pde, + target = Γ_quad, + source = Ω_quad, + compression = (method = :fmm, tol = 1e-12), + correction = ( + method = :dim, + maxdist = 5 * meshsize, + target_location = :on, + ), + ) +end # ╔═╡ 731d9ae8-33a8-4f03-8cbc-5e40972996a2 md""" @@ -234,13 +213,14 @@ instead a manufactured solution ``u_e`` from which we will derive the functions """ # ╔═╡ 975b7c01-8147-44f8-a693-1185e7b8d63b -begin # hide -# Create a manufactured solution -uₑ = (x) -> cos(2 * x[1]) * sin(2 * x[2]) -fₑ = (x) -> 8 * cos(2 * x[1]) * sin(2 * x[2]) # -Δuₑ -g = map(q -> uₑ(q.coords), Γ_quad) -f = map(q -> fₑ(q.coords), Ω_quad) -end; # hide +begin + # Create a manufactured solution + uₑ = (x) -> cos(2 * x[1]) * sin(2 * x[2]) + fₑ = (x) -> 8 * cos(2 * x[1]) * sin(2 * x[2]) # -Δuₑ + g = map(q -> uₑ(q.coords), Γ_quad) + f = map(q -> fₑ(q.coords), Ω_quad) + nothing #hide +end # ╔═╡ 700cfbbc-970a-466b-9f8c-748f7ff0bc6e md""" @@ -249,41 +229,36 @@ homogeneous part of the solution: """ # ╔═╡ 6db682e4-e641-4272-ba90-1f10b2ff1150 -rhs = g - V_d2b*f ; +begin + rhs = g - V_d2b*f + nothing #hide +end # ╔═╡ 6eb1d813-e792-4148-8d30-975c49e9dbc6 -# ╠═╡ show_logs = false -begin # hide -using IterativeSolvers, LinearAlgebra -σ = gmres(-I/2 + D_b2b, rhs; abstol = 1e-8, verbose = true, restart = 1000) -end; # hide +begin + using IterativeSolvers, LinearAlgebra + σ = gmres(-I/2 + D_b2b, rhs; abstol = 1e-8, verbose = true, restart = 1000) + nothing #hide +end # ╔═╡ b21911c7-7276-44cb-a15f-64db3430a896 md""" and solve the integral equation for the integral density function ``σ``: """ -# ╔═╡ b5c4b1a6-c13d-416e-b820-02c9bfc1fdca -let # To Render in the Documentation - with_terminal() do - σ = gmres(-I/2 + D_b2b, rhs; abstol = 1e-8, verbose = true, restart = 1000) ; - nothing - end -end - # ╔═╡ 1357bb0a-bf56-4f56-bb2c-65dfe2a78c0c md""" With the density function at hand, we can now reconstruct our approximate solution: """ # ╔═╡ e0e1fa9c-7a43-45b1-ad45-2510533e1aed -begin # hide -G = Inti.SingleLayerKernel(pde) -dG = Inti.DoubleLayerKernel(pde) -𝒱 = Inti.IntegralPotential(G, Ω_quad) -𝒟 = Inti.IntegralPotential(dG, Γ_quad) -u = (x) -> 𝒱[f](x) + 𝒟[σ](x) -end # hide +begin + G = Inti.SingleLayerKernel(pde) + dG = Inti.DoubleLayerKernel(pde) + 𝒱 = Inti.IntegralPotential(G, Ω_quad) + 𝒟 = Inti.IntegralPotential(dG, Γ_quad) + u = (x) -> 𝒱[f](x) + 𝒟[σ](x) +end # ╔═╡ 2c2c943b-30ed-4244-a40c-f061050ca7b8 md""" @@ -291,17 +266,9 @@ and evaluate it at any point in the domain: """ # ╔═╡ 2faa4311-59d9-4b85-b585-937391e94568 -# ╠═╡ show_logs = false -begin # hide -x = Inti.Point2D(0.1,0.4) -println("error at $x: ", u(x)-uₑ(x)) -end # hide - -# ╔═╡ f3495025-ac97-415d-a398-ee5280c2d714 -let # Render for Documentation -with_terminal() do -println("error at $x: ", u(x)-uₑ(x)) -end +begin + x = Inti.Point2D(0.1,0.4) + println("error at $x: ", u(x)-uₑ(x)) end # ╔═╡ f3ee21f2-99e7-4be3-a2cc-930b6c4487f1 @@ -352,46 +319,37 @@ manufactured: """ # ╔═╡ 5be59f68-cf21-4e7e-ac23-7bffd690dc03 -# ╠═╡ show_logs = false -begin # hide -u_quad = V_d2d*f + D_b2d*σ -er_quad = u_quad - map(q -> uₑ(q.coords), Ω_quad) -println("maximum error at all quadrature nodes: ", norm(er_quad, Inf)) -end; # hide - -# ╔═╡ 41f97844-3c86-46b8-9fbb-0632bdcee0f6 -let # render for documentation - with_terminal() do - println("maximum error at all quadrature nodes: ", norm(er_quad, Inf)) - end +begin + u_quad = V_d2d*f + D_b2d*σ + er_quad = u_quad - map(q -> uₑ(q.coords), Ω_quad) + println("maximum error at all quadrature nodes: ", norm(er_quad, Inf)) + nothing #hide end # ╔═╡ a61f336e-15ee-4bb3-a071-1115ac6f1be1 md""" -Lastly, let us visualize the solution and the error on the mesh nodes using [`quadrature_to_node_vals`](../../docstrings/#Inti.quadrature_to_node_vals-Tuple{Inti.Quadrature,%20AbstractVector}): +Lastly, let us visualize the solution and the error on the mesh nodes using [`quadrature_to_node_vals`](@ref Inti.quadrature_to_node_vals): """ # ╔═╡ ce03f9b7-c91c-4f53-bcda-49261a4bdcc2 -begin # hide -nodes = Inti.nodes(Ω_msh) -u_nodes = Inti.quadrature_to_node_vals(Ω_quad, u_quad) -er = u_nodes - map(uₑ, nodes) -colorrange = extrema(u_nodes) -fig = Figure(; size = (800, 300)) -ax = Axis(fig[1, 1]; aspect = DataAspect()) -viz!(Ω_msh; colorrange, color = u_nodes, interpolate = true) -cb = Colorbar(fig[1, 2]; label = "u", colorrange) -# plot error -log_er = log10.(abs.(er)) -colorrange = extrema(log_er) -colormap = :inferno -ax = Axis(fig[1, 3]; aspect = DataAspect()) -viz!(Ω_msh; colorrange, colormap, color = log_er, interpolate = true) -cb = Colorbar(fig[1, 4]; label = "log₁₀|u - uₑ|", colormap, colorrange) -end; # hide - -# ╔═╡ e46f76d5-074b-49ac-b976-9f782df9307d -fig +begin + nodes = Inti.nodes(Ω_msh) + u_nodes = Inti.quadrature_to_node_vals(Ω_quad, u_quad) + er = u_nodes - map(uₑ, nodes) + colorrange = extrema(u_nodes) + fig = Figure(; size = (800, 300)) + ax = Axis(fig[1, 1]; aspect = DataAspect()) + viz!(Ω_msh; colorrange, color = u_nodes, interpolate = true) + cb = Colorbar(fig[1, 2]; label = "u", colorrange) + # plot error + log_er = log10.(abs.(er)) + colorrange = extrema(log_er) + colormap = :inferno + ax = Axis(fig[1, 3]; aspect = DataAspect()) + viz!(Ω_msh; colorrange, colormap, color = log_er, interpolate = true) + cb = Colorbar(fig[1, 4]; label = "log₁₀|u - uₑ|", colormap, colorrange) + fig #hide +end # ╔═╡ e63c776b-6b52-4e6e-aca8-3d67cd9a9c3f TableOfContents() @@ -2446,12 +2404,10 @@ version = "1.4.1+1" # ╟─b287d01b-7d13-414e-9f22-36e8a3a8ca62 # ╟─1d3720bb-c113-44d3-ac0d-275f80e87237 # ╠═332bd3bb-c720-454e-80af-89ad65041773 -# ╟─546966b1-58c2-44e6-ac2c-578094251fce # ╟─1609838c-67ec-4d67-9c9b-993b1bd01fb6 # ╠═4e580f9f-6e22-4160-b262-ca941b6bfb8f # ╟─901578c3-b7aa-4023-bb99-769cf5805f57 # ╠═2c4bace3-ef35-4500-829f-2f5ae6725249 -# ╟─1bb0a7a4-8fab-4744-9cf1-94619bde5395 # ╟─b142b298-26a8-4373-934d-3bc8448a8fda # ╠═85ce61fc-086d-4661-8f03-6a6ae4d55511 # ╟─731d9ae8-33a8-4f03-8cbc-5e40972996a2 @@ -2465,22 +2421,18 @@ version = "1.4.1+1" # ╠═6db682e4-e641-4272-ba90-1f10b2ff1150 # ╟─b21911c7-7276-44cb-a15f-64db3430a896 # ╠═6eb1d813-e792-4148-8d30-975c49e9dbc6 -# ╟─b5c4b1a6-c13d-416e-b820-02c9bfc1fdca # ╟─1357bb0a-bf56-4f56-bb2c-65dfe2a78c0c # ╠═e0e1fa9c-7a43-45b1-ad45-2510533e1aed # ╟─2c2c943b-30ed-4244-a40c-f061050ca7b8 # ╠═2faa4311-59d9-4b85-b585-937391e94568 -# ╟─f3495025-ac97-415d-a398-ee5280c2d714 # ╟─f3ee21f2-99e7-4be3-a2cc-930b6c4487f1 # ╠═fccb6992-32c4-4bd2-a742-fb36906fb62a # ╟─6489d40d-fdd3-488d-ae5d-4e4e489b669f # ╟─66a7946c-a601-4fc8-94a0-429d41b564ac # ╟─a5c7fcd0-1966-49fe-b5bf-7d3c1d9f4aa7 # ╠═5be59f68-cf21-4e7e-ac23-7bffd690dc03 -# ╟─41f97844-3c86-46b8-9fbb-0632bdcee0f6 # ╟─a61f336e-15ee-4bb3-a071-1115ac6f1be1 # ╠═ce03f9b7-c91c-4f53-bcda-49261a4bdcc2 -# ╟─e46f76d5-074b-49ac-b976-9f782df9307d # ╟─e63c776b-6b52-4e6e-aca8-3d67cd9a9c3f # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002 diff --git a/docs/src/pluto-examples/toy_example.jl b/docs/src/pluto-examples/toy_example.jl index 8e35052e..81fc763a 100644 --- a/docs/src/pluto-examples/toy_example.jl +++ b/docs/src/pluto-examples/toy_example.jl @@ -4,16 +4,15 @@ using Markdown using InteractiveUtils +# ╔═╡ d027657d-4f16-40fd-b7c3-8ea9e51c0a98 +using Inti + # ╔═╡ 3f5a1750-7cd7-11ef-2223-4f3db029916b begin import Pkg as _Pkg - haskey(ENV, "PLUTO_PROJECT") && _Pkg.activate(ENV["PLUTO_PROJECT"]) - using PlutoUI: with_terminal + haskey(ENV, "PLUTO_PROJECT") && _Pkg.activate(ENV["PLUTO_PROJECT"]) end ; -# ╔═╡ d027657d-4f16-40fd-b7c3-8ea9e51c0a98 -using Inti - # ╔═╡ 854743f0-8556-4495-ba16-52514c85922a md""" # Toy example @@ -23,7 +22,7 @@ md""" # ╔═╡ 09c0bfc0-1c65-4fad-b486-b6a61ca580e8 md""" -All examples in Inti.jl are autogenerated by executing the `make.jl` script in the `docs` folder. The workflow uses [PlutoStaticHTML.jl](https://plutostatichtml.huijzer.xyz/stable/) and [PlutoSliderServer.jl](https://github.com/JuliaPluto/PlutoSliderServer.jl) via the intermediate of [ExampleJuggler.jl](https://github.com/j-fu/ExampleJuggler.jl) to generate (i) markdown files passed to Documenter.jl, and (ii) pluto notebook files downloadable from the example's page. +All examples in Inti.jl are autogenerated by executing the `make.jl` script in the `docs` folder. The workflow uses [Pluto.jl](https://plutojl.org), [JuliaFormatter](https://domluna.github.io/JuliaFormatter.jl/stable/), and [PlutoSliderServer.jl](https://github.com/JuliaPluto/PlutoSliderServer.jl) (via the intermediate of [ExampleJuggler.jl](https://github.com/j-fu/ExampleJuggler.jl)) to generate (i) markdown files passed to Documenter.jl, and (ii) pluto notebook files downloadable from the example's page. """ # ╔═╡ 00000000-0000-0000-0000-000000000001 @@ -31,11 +30,9 @@ PLUTO_PROJECT_TOML_CONTENTS = """ [deps] Inti = "fb74042b-437e-4c5b-88cf-d4e2beb394d5" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" -PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" [compat] Inti = "~0.1.1" -PlutoUI = "~0.7.60" """ # ╔═╡ 00000000-0000-0000-0000-000000000002 @@ -44,13 +41,7 @@ PLUTO_MANIFEST_TOML_CONTENTS = """ julia_version = "1.10.5" manifest_format = "2.0" -project_hash = "03506df29ac423a8c891aed43b1dcb6697268bfc" - -[[deps.AbstractPlutoDingetjes]] -deps = ["Pkg"] -git-tree-sha1 = "6e1d2a35f2f90a4bc7c2ed98079b2ba09c35b83a" -uuid = "6e696c72-6542-2067-7265-42206c756150" -version = "1.3.2" +project_hash = "e35f19cc8ab3426fd7cbf4d4e2049a8aee789a0a" [[deps.ArgTools]] uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" @@ -62,12 +53,6 @@ uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" -[[deps.ColorTypes]] -deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "b10d0b65641d57b8b4d5e234446582de5047050d" -uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.11.5" - [[deps.CommonSubexpressions]] deps = ["MacroTools"] git-tree-sha1 = "cda2cfaebb4be89c9084adaca7dd7333369715c5" @@ -145,12 +130,6 @@ version = "0.2.2" [[deps.FileWatching]] uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" -[[deps.FixedPointNumbers]] -deps = ["Statistics"] -git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172" -uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" -version = "0.8.5" - [[deps.ForwardDiff]] deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] git-tree-sha1 = "cf0fe81336da9fb90944683b8c41984b08793dad" @@ -161,24 +140,6 @@ weakdeps = ["StaticArrays"] [deps.ForwardDiff.extensions] ForwardDiffStaticArraysExt = "StaticArrays" -[[deps.Hyperscript]] -deps = ["Test"] -git-tree-sha1 = "179267cfa5e712760cd43dcae385d7ea90cc25a4" -uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91" -version = "0.0.5" - -[[deps.HypertextLiteral]] -deps = ["Tricks"] -git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653" -uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" -version = "0.9.5" - -[[deps.IOCapture]] -deps = ["Logging", "Random"] -git-tree-sha1 = "b6d6bfdd7ce25b0f9b2f6b3dd56b2673a66c8770" -uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.2.5" - [[deps.InteractiveUtils]] deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" @@ -217,12 +178,6 @@ git-tree-sha1 = "f389674c99bfcde17dc57454011aa44d5a260a40" uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" version = "1.6.0" -[[deps.JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.4" - [[deps.LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" @@ -289,11 +244,6 @@ version = "0.3.28" [[deps.Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" -[[deps.MIMEs]] -git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" -uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" -version = "0.1.4" - [[deps.MacroTools]] deps = ["Markdown", "Random"] git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" @@ -309,9 +259,6 @@ deps = ["Artifacts", "Libdl"] uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" version = "2.28.2+1" -[[deps.Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" version = "2023.1.10" @@ -353,23 +300,11 @@ git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" version = "1.6.3" -[[deps.Parsers]] -deps = ["Dates", "PrecompileTools", "UUIDs"] -git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.8.1" - [[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" version = "1.10.0" -[[deps.PlutoUI]] -deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"] -git-tree-sha1 = "eba4810d5e6a01f612b948c9fa94f905b49087b0" -uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" -version = "0.7.60" - [[deps.PrecompileTools]] deps = ["Preferences"] git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" @@ -394,11 +329,6 @@ uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" deps = ["SHA"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -[[deps.Reexport]] -git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" -uuid = "189a3867-3050-52da-a836-e630ba90ab69" -version = "1.2.2" - [[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" version = "0.7.0" @@ -477,20 +407,6 @@ deps = ["ArgTools", "SHA"] uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" version = "1.10.0" -[[deps.Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[deps.Tricks]] -git-tree-sha1 = "7822b97e99a1672bfb1b49b668a6d46d58d8cbcb" -uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" -version = "0.1.9" - -[[deps.URIs]] -git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" -uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.5.1" - [[deps.UUIDs]] deps = ["Random", "SHA"] uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" From d56557cc68c369681f7b807700186870a0466355 Mon Sep 17 00:00:00 2001 From: gregoirepourtier Date: Thu, 10 Oct 2024 09:23:04 +0200 Subject: [PATCH 4/6] deploy without nbviewer --- docs/make.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index a9a2ff5f..0cc6e5ee 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -173,7 +173,7 @@ end size_threshold_ignore = last.(notebook_examples) # Generate HTML versions of the notebooks using PlutoSliderServer.jl -notebook_examples_html = @docplutonotebooks(notebook_dir, notebooks, iframe = true) +# notebook_examples_html = @docplutonotebooks(notebook_dir, notebooks, iframe = true) makedocs(; modules = modules, From 98fb79d9604f881f0e3b7458420bce129dca7f6a Mon Sep 17 00:00:00 2001 From: gregoirepourtier Date: Thu, 10 Oct 2024 09:41:31 +0200 Subject: [PATCH 5/6] deploy 2nd try --- docs/make.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index 0cc6e5ee..c3719819 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -211,7 +211,7 @@ makedocs(; "References" => "references.md", "Docstrings" => "docstrings.md", ], - warnonly = ON_CI ? false : Documenter.except(:linkcheck_remotes), + warnonly = ON_CI ? false : Documenter.except(:linkcheck_remotes, :cross_references), # warnonly = true, pagesonly = true, checkdocs = :none, @@ -227,3 +227,5 @@ deploydocs(; devbranch = "main", push_preview = true, ) + +# GLMakie.closeall() From eab7d9e96fe39594a3ae3da5cb370ddd5a6dfb76 Mon Sep 17 00:00:00 2001 From: gregoirepourtier Date: Thu, 10 Oct 2024 10:02:14 +0200 Subject: [PATCH 6/6] fix broken link error --- docs/make.jl | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index c3719819..81e1a8c5 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -118,26 +118,26 @@ end ## TO REMOVE if we decide to use Pluto Notebooks to generate documentation # Generate examples using Literate -const examples_dir = joinpath(Inti.PROJECT_ROOT, "docs", "src", "examples") +# const examples_dir = joinpath(Inti.PROJECT_ROOT, "docs", "src", "examples") const notebook_dir = joinpath(Inti.PROJECT_ROOT, "docs", "src", "pluto-examples") -const generated_dir = joinpath(Inti.PROJECT_ROOT, "docs", "src", "examples", "generated") -const examples = ["toy_example.jl", "helmholtz_scattering.jl"] -for t in examples - println("\n*** Generating $t example") - @time begin - src = joinpath(examples_dir, t) - Literate.markdown(src, generated_dir; mdstrings = true) - # if draft, skip creation of notebooks - Literate.notebook( - src, - generated_dir; - mdstrings = true, - preprocess = insert_setup, - # execute = ON_CI, - execute = false, - ) - end -end +# const generated_dir = joinpath(Inti.PROJECT_ROOT, "docs", "src", "examples", "generated") +# const examples = ["toy_example.jl", "helmholtz_scattering.jl"] +# for t in examples +# println("\n*** Generating $t example") +# @time begin +# src = joinpath(examples_dir, t) +# Literate.markdown(src, generated_dir; mdstrings = true) +# # if draft, skip creation of notebooks +# Literate.notebook( +# src, +# generated_dir; +# mdstrings = true, +# preprocess = insert_setup, +# # execute = ON_CI, +# execute = false, +# ) +# end +# end println("\n*** Generating documentation") @@ -199,19 +199,19 @@ makedocs(; "tutorials/correction_methods.md", "tutorials/solvers.md", ], - "Examples" => [ - "examples/generated/toy_example.md", - "examples/generated/helmholtz_scattering.md", - "examples/poisson.md", - # "examples/generated/lippmann_schwinger.md", - # "examples/generated/poisson.md", - # "examples/generated/stokes_drag.md", - ], + # "Examples" => [ + # "examples/generated/toy_example.md", + # "examples/generated/helmholtz_scattering.md", + # "examples/poisson.md", + # # "examples/generated/lippmann_schwinger.md", + # # "examples/generated/poisson.md", + # # "examples/generated/stokes_drag.md", + # ], "Notebooks" => notebook_examples, "References" => "references.md", "Docstrings" => "docstrings.md", ], - warnonly = ON_CI ? false : Documenter.except(:linkcheck_remotes, :cross_references), + warnonly = Documenter.except(:linkcheck_remotes), # ON_CI ? false : Documenter.except(:linkcheck_remotes), # warnonly = true, pagesonly = true, checkdocs = :none,