Conversation
|
Manifest should be in the gitignore ? |
|
Ok for review, sorry some tutos didnt work on my pc couldn't test doc locally, only could preview. Seems to work now |
|
Really awesome, thanks for the addition!
We have it in the CI to have a fully reproducible state for the docs, as we rely on a lot of packages in the docs. I will review later. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1283 +/- ##
=======================================
Coverage 94.25% 94.25%
=======================================
Files 40 40
Lines 6750 6750
=======================================
Hits 6362 6362
Misses 388 388 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
I get : ┌ Error: failed to run `@example` block in docs\src\tutorials\stokes-flow.md:459-461
│ ```@example stokes-flow
│ main()
│ ```
│ exception =
│
│ Stacktrace:
│ [1] error(s::String)
│ @ Base .\error.jl:44
│ [2] open
│ @ C:\Users\yolha\.julia\artifacts\649584fb27316a4395dbb47fde904c83626feae5\lib\gmsh.jl:113 [inlined]
│ [3] togrid(filename::String; domain::String)
│ @ FerriteGmsh C:\Users\yolha\.julia\packages\FerriteGmsh\MH6r7\src\FerriteGmsh.jl:185
│ [4] togrid
│ @ C:\Users\yolha\.julia\packages\FerriteGmsh\MH6r7\src\FerriteGmsh.jl:176 [inlined]
│ [5] (::Main.var"__atexample__named__stokes-flow".var"#setup_grid##0#setup_grid##1")(dir::String)
│ @ Main.var"__atexample__named__stokes-flow" .\stokes-flow.md:213
│ [6] mktempdir(fn::Main.var"__atexample__named__stokes-flow".var"#setup_grid##0#setup_grid##1", parent::String; prefix::String)
│ @ Base.Filesystem .\file.jl:936
│ [7] mktempdir (repeats 2 times)
│ @ .\file.jl:932 [inlined]
│ [8] setup_grid(h::Float64)
│ @ Main.var"__atexample__named__stokes-flow" .\stokes-flow.md:210
│ [9] main()
│ @ Main.var"__atexample__named__stokes-flow" .\stokes-flow.md:462
│ [10] top-level scope
│ @ stokes-flow.md:460
│ [11] eval(m::Module, e::Any)
│ @ Core .\boot.jl:489
│ [12] #61
│ @ C:\Users\yolha\.julia\packages\Documenter\HdXI4\src\expander_pipeline.jl:856 [inlined]
│ [13] cd(f::Documenter.var"#61#62"{Module, Expr}, dir::String)
│ @ Base.Filesystem .\file.jl:101
│ [14] (::Documenter.var"#59#60"{Documenter.Page, Module, Expr})()
│ @ Documenter C:\Users\yolha\.julia\packages\Documenter\HdXI4\src\expander_pipeline.jl:855
│ [15] (::IOCapture.var"#12#13"{Type{InterruptException}, Documenter.var"#59#60"{Documenter.Page, Module, Expr}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, Base.TTY, Base.TTY})()
│ @ IOCapture C:\Users\yolha\.julia\packages\IOCapture\Y5rEA\src\IOCapture.jl:170
│ [16] with_logstate(f::IOCapture.var"#12#13"{Type{InterruptException}, Documenter.var"#59#60"{Documenter.Page, Module, Expr}, IOContext{Base.PipeEndpoint}, IOContext{Base.PipeEndpoint}, Base.TTY, Base.TTY}, logstate::Base.CoreLogging.LogState)
│ @ Base.CoreLogging .\logging\logging.jl:542
│ [17] with_logger(f::Function, logger::Base.CoreLogging.ConsoleLogger)
│ @ Base.CoreLogging .\logging\logging.jl:653
│ [18] capture(f::Documenter.var"#59#60"{Documenter.Page, Module, Expr}; rethrow::Type, color::Bool, passthrough::Bool, capture_buffer::IOBuffer, io_context::Vector{Any})
│ @ IOCapture C:\Users\yolha\.julia\packages\IOCapture\Y5rEA\src\IOCapture.jl:167
│ [19] runner(::Type{Documenter.Expanders.ExampleBlocks}, node::MarkdownAST.Node{Nothing}, page::Documenter.Page, doc::Documenter.Document)
│ @ Documenter C:\Users\yolha\.julia\packages\Documenter\HdXI4\src\expander_pipeline.jl:854
└ @ Documenter C:\Users\yolha\.julia\packages\Documenter\HdXI4\src\utilities\utilities.jl:47 |
| Ui = @view U[idofs] | ||
| for qp in 1:getnquadpoints(iv) | ||
| n = getnormal(iv, qp; here = true) | ||
| dF = getdetJdV(iv, qp) | ||
| hL = function_value(iv, qp, Ui, dr_h, dr_h .+ ndpc; here = true) | ||
| qxL = function_value(iv, qp, Ui, dr_qx, dr_qx .+ ndpc; here = true) | ||
| qyL = function_value(iv, qp, Ui, dr_qy, dr_qy .+ ndpc; here = true) | ||
| hR = function_value(iv, qp, Ui, dr_h, dr_h .+ ndpc; here = false) | ||
| qxR = function_value(iv, qp, Ui, dr_qx, dr_qx .+ ndpc; here = false) | ||
| qyR = function_value(iv, qp, Ui, dr_qy, dr_qy .+ ndpc; here = false) | ||
| UL = Vec{3}((hL, qxL, qyL)) | ||
| UR = Vec{3}((hR, qxR, qyR)) | ||
| fhat = LF(UL, UR, n) | ||
| for i in 1:nb | ||
| ΦᵢL = shape_value(iv, qp, i; here = true) | ||
| ΦᵢR = shape_value(iv, qp, i + nb; here = false) | ||
| Ri[dr_h[i]] += (-ΦᵢL * fhat[1]) * dF | ||
| Ri[dr_qx[i]] += (-ΦᵢL * fhat[2]) * dF | ||
| Ri[dr_qy[i]] += (-ΦᵢL * fhat[3]) * dF | ||
| Ri[dr_h[i] + ndpc] += (ΦᵢR * fhat[1]) * dF | ||
| Ri[dr_qx[i] + ndpc] += (ΦᵢR * fhat[2]) * dF | ||
| Ri[dr_qy[i] + ndpc] += (ΦᵢR * fhat[3]) * dF | ||
| end | ||
| end |
There was a problem hiding this comment.
@AbdAlazezAhmed can you take a look at this part here? Any chance that we miss some interface for this, so users do not need to manually index this stuff? Also, aren't we missing some 1/h term?
There was a problem hiding this comment.
I found that weird using it too especially, I thought it should be either
hL = function_value(iv, qp, Ui, dr_h; here=true)
hR = function_value(iv, qp, Ui, dr_h; here=false)or
hL = function_value(iv, qp, Ui, dr_h)
hR = function_value(iv, qp, Ui, dr_h .+ ndpc)but having to do both seems weird. Maybe differencing Ui_here and Ui_there since the beggening would be better ?
| Rb[dr_h[i]] -= (Φᵢ * fhat[1]) * dF | ||
| Rb[dr_qx[i]] -= (Φᵢ * fhat[2]) * dF | ||
| Rb[dr_qy[i]] -= (Φᵢ * fhat[3]) * dF |
There was a problem hiding this comment.
Correct me if I am wrong, but don't we need some element size term here to enforce the Dirichlet condition weakly?
There was a problem hiding this comment.
I'm using a ghost element method for the week forcing at the boundary, so the code is exactly similar to the inner interface beside that we dont compute the dofs for the ghost element and we preomcute what we want or wish at the outer trace. Maybe you're thinking of a strong one with a forcing term of order 1/size but that can lead to non-physical solution in this framework. It is ok when DG is used on parabolic / eliptic pdes though.
There was a problem hiding this comment.
Interesting, thanks for sharing this. Do you know some paper analyzing this? I have not read the theory part at the top yet, bit if it is not explained there yet, could you add the reference there?
There was a problem hiding this comment.
The clearest I know is this one :
The Runge–Kutta discontinuous Galerkin method for conservation laws V: multidimensional systems](https://www.sciencedirect.com/science/article/pii/S0021999198958922
by B Cockburn and CW Shu its quite old 1998 but its just too well explained.
Of course can't do that without citing a friend who did his phd at the same time as I did,
Poussel, Camille, Mehmet Ersoy, and Frederic Golay. "Wetting and drying treatments with mesh adaptation for shallow water equations using a Runge–Kutta discontinuous Galerkin method." International Journal for Numerical Methods in Fluids 97.5 (2025): 692-712.
won't cite myself since I'm more on the modelling side but I used this method for every papers I did (with a twist for advection-diffusion problem)
There was a problem hiding this comment.
also if you want the theoric part to be clearer I can do that but I thought I would go really fast to the code since the point stay Ferrite
There was a problem hiding this comment.
I always struggle with a good balance for how much theory should be stated in the docs. @AbdAlazezAhmed what would you put in the docs for this example?
There was a problem hiding this comment.
We also might want to put this tutorial before the Navier-Stokes tutorial, because it shows OrdinaryDiffEq withouth the funky parts to strongly enforce the Dirichlet boundary condition and discontinuity handling.
|
comment for myself : if docs pass, remove the vtk gen froom CI |
| Rb[dr_h[i]] -= (Φᵢ * fhat[1]) * dF | ||
| Rb[dr_qx[i]] -= (Φᵢ * fhat[2]) * dF | ||
| Rb[dr_qy[i]] -= (Φᵢ * fhat[3]) * dF |
There was a problem hiding this comment.
I always struggle with a good balance for how much theory should be stated in the docs. @AbdAlazezAhmed what would you put in the docs for this example?
| Rb[dr_h[i]] -= (Φᵢ * fhat[1]) * dF | ||
| Rb[dr_qx[i]] -= (Φᵢ * fhat[2]) * dF | ||
| Rb[dr_qy[i]] -= (Φᵢ * fhat[3]) * dF |
There was a problem hiding this comment.
We also might want to put this tutorial before the Navier-Stokes tutorial, because it shows OrdinaryDiffEq withouth the funky parts to strongly enforce the Dirichlet boundary condition and discontinuity handling.
|
I think its ok for review again, besides waiting for some answer on the amount of math. |
lijas
left a comment
There was a problem hiding this comment.
Nice work! I dont know anything about the shallow water equations, but from reading the introduction it seems like the fields are grouped in to a vector U = [h, qx, qy] ? In that case, I think it would be better to treat this as a vector problem instead of three scalar equations. The code will become cleaner and follow the equations much closer. Below I will give suggestion on how to update parts of the code, but you have to update other parts of the code accordingly... This requires some refactoring but I think it can be worth it.
| droptol!(M, 1.0e-12) | ||
| M = Diagonal(M) | ||
| # ### Volume integral on each element | ||
| function element_volume_integral!(R, cell, U, dr, param) |
There was a problem hiding this comment.
Element rotine becomes:
function element_volume_integral!(R, cell, U, param)
Re = param.Re
fill!(Re, 0.0)
cv = param.cv
nb = getnbasefunctions(cv)
Ferrite.reinit!(cv, cell)
dofs = celldofs(cell)
Ue = @view U[dofs] # Note: For performance reasons, we don’t recommend using this outside the DG framework; here, the DOFs are guaranteed to be stored contiguously in memory.
coords = getcoordinates(cell)
for qp in 1:getnquadpoints(cv)
dE = getdetJdV(cv, qp)
Uval = function_value(cv, qp, Ue)
F = F_function(Uval)
X = spatial_coordinate(cv, qp, coords)
SS = S(Uval, X)
for i in 1:nb
Φᵢ = shape_value(cv, qp, i)
∇Φᵢ = shape_gradient(cv, qp, i)
Re[i] += (F ⊡ ∇Φᵢ+ SS ⋅ Φᵢ) * dE
end
end
Ferrite.assemble!(R, dofs, Re)
return nothing
end
with
# Define double contraction operator for StaticArrays matrices
⊡(A::StaticMatrix, B::StaticMatrix) = sum(A .* B)
|
|
||
| #- | ||
| # ### Mass matrix (block-diagonal per element) | ||
| function assemble_mass_matrix!(M, dh, cv) |
There was a problem hiding this comment.
Mass matrix routine simplifies to:
function assemble_mass_matrix!(M, dh, cv)
nb = getnbasefunctions(cv)
Me = zeros(nb, nb)
asM = start_assemble(M)
for cell in CellIterator(dh)
Ferrite.reinit!(cv, cell)
dofs = celldofs(cell)
fill!(Me, 0.0)
for qp in 1:getnquadpoints(cv)
dE = getdetJdV(cv, qp)
for i in 1:nb
Φᵢ = shape_value(cv, qp, i)
for j in 1:nb
Φⱼ = shape_value(cv, qp, j)
m = (Φᵢ ⋅ Φⱼ) * dE
Me[i, j] += m
end
end
end
assemble!(asM, dofs, inv(Me))
end
return M
end
|
|
||
| # ### Interface integral on each interface | ||
| function interface_integral!(R, ic, U, dr, param) | ||
| dr_h, dr_qx, dr_qy = dr |
There was a problem hiding this comment.
function interface_integral!(R, ic, U, param)
Ri = param.Ri
fill!(Ri, 0.0)
iv = param.iv
nb = getnbasefunctions(param.cv)
Ferrite.reinit!(iv, ic)
idofs = interfacedofs(ic)
Ui = @view U[idofs]
for qp in 1:getnquadpoints(iv)
n = getnormal(iv, qp; here = true)
dF = getdetJdV(iv, qp)
UL = function_value(iv, qp, Ui; here = true)
UR = function_value(iv, qp, Ui; here = false)
#Ujmp = function_value_jump(iv, qp, U)
#c = max(max_speed(UL, n), max_speed(UR, n))
#fhat = 0.5(F(UL)⋅n + F(UR)⋅n) - c*Ujmp
fhat = LF(UL, UR, n)
for i in 1:nb
Φᵢ = 2*shape_value_jump(iv, qp, i)
Ri[i] += (Φᵢ ⋅ fhat) * dF
end
end
Ferrite.assemble!(R, idofs, Ri)
return nothing
end
| batpx(X) = -2 * (X[1] - 5) * 0.5 * exp(-(X[1] - 5)^2 - (X[2] - 5)^2) | ||
| batpy(X) = -2 * (X[2] - 5) * 0.5 * exp(-(X[1] - 5)^2 - (X[2] - 5)^2) | ||
|
|
||
| function F(U) |
There was a problem hiding this comment.
We need F to ouput and 3x2 matrix, which also matches your equations
function F(U)
h, qx, qy = U
ux = qx / h
uy = qy / h
p = g * h * h / 2
return @SMatrix [qx qy;
qx*ux+p qy*ux;
qx*uy qy*uy+p]
end
There was a problem hiding this comment.
Really nice thank you I will update afaik, I remember now why I didn't do that, I was a bit scared to mix SMatrix with Tensors but since you think it's all right 👍
There was a problem hiding this comment.
If we will merge Ferrite-FEM/Tensors.jl#236 in the future then mixing the SMatrix in here also won't be necessary anymore. :)
This PR adds a shallow water RKDG exemple to showcase how this can be done in Ferrite.
I won't go further on this description since everything is in the md, please suggest anykind of clarification.