From 9e22dbbe59847c0ff90e7cf60314f3e587ad108d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 22 Aug 2024 13:21:50 +1000 Subject: [PATCH 01/47] Added Vanka solvers --- .../PatchBasedSmoothers.jl | 4 +- src/PatchBasedSmoothers/seq/PatchFESpaces.jl | 30 ++-- src/PatchBasedSmoothers/seq/VankaSolvers.jl | 79 ++++++++++ .../seq/ZeroMeanPatchFESpaces.jl | 143 ++++++++++++++++++ test/_dev/MacroFEs/block_stokes.jl | 81 ++++++++++ test/_dev/MacroFEs/stokes.jl | 1 - .../PatchBased/ZeroMeanPatchBasedFESpaces.jl | 96 ++++++++++++ test/_dev/Vanka/darcy_vanka.jl | 79 ++++++++++ test/_dev/Vanka/darcy_vanka_GMG.jl | 132 ++++++++++++++++ test/_dev/Vanka/stokes_vanka.jl | 80 ++++++++++ test/_dev/Vanka/stokes_vanka_GMG.jl | 125 +++++++++++++++ test/_dev/Vanka/stokes_vanka_PCont.jl | 90 +++++++++++ test/_dev/Vanka/stokes_vanka_Pdisc.jl | 99 ++++++++++++ 13 files changed, 1028 insertions(+), 11 deletions(-) create mode 100644 src/PatchBasedSmoothers/seq/VankaSolvers.jl create mode 100644 src/PatchBasedSmoothers/seq/ZeroMeanPatchFESpaces.jl create mode 100644 test/_dev/MacroFEs/block_stokes.jl create mode 100644 test/_dev/PatchBased/ZeroMeanPatchBasedFESpaces.jl create mode 100644 test/_dev/Vanka/darcy_vanka.jl create mode 100644 test/_dev/Vanka/darcy_vanka_GMG.jl create mode 100644 test/_dev/Vanka/stokes_vanka.jl create mode 100644 test/_dev/Vanka/stokes_vanka_GMG.jl create mode 100644 test/_dev/Vanka/stokes_vanka_PCont.jl create mode 100644 test/_dev/Vanka/stokes_vanka_Pdisc.jl diff --git a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl index d00bf981..d836dcfd 100644 --- a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl +++ b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl @@ -13,7 +13,7 @@ using GridapSolvers.MultilevelTools export PatchDecomposition export PatchFESpace -export PatchBasedLinearSolver +export PatchBasedLinearSolver, VankaSolver export PatchProlongationOperator, PatchRestrictionOperator export setup_patch_prolongation_operators, setup_patch_restriction_operators @@ -26,10 +26,12 @@ include("seq/PatchTriangulations.jl") # FESpaces include("seq/PatchFESpaces.jl") include("mpi/PatchFESpaces.jl") +include("seq/ZeroMeanPatchFESpaces.jl") include("seq/PatchMultiFieldFESpaces.jl") # Solvers include("seq/PatchBasedLinearSolvers.jl") include("seq/PatchTransferOperators.jl") +include("seq/VankaSolvers.jl") end \ No newline at end of file diff --git a/src/PatchBasedSmoothers/seq/PatchFESpaces.jl b/src/PatchBasedSmoothers/seq/PatchFESpaces.jl index d019307c..930dd77d 100644 --- a/src/PatchBasedSmoothers/seq/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/seq/PatchFESpaces.jl @@ -38,12 +38,24 @@ FESpace representing a patch-based subspace decomposition `V = Σ_i V_i` of a global space `V`. """ -struct PatchFESpace <: FESpaces.SingleFieldFESpace - Vh :: FESpaces.SingleFieldFESpace +struct PatchFESpace{A,B} <: FESpaces.SingleFieldFESpace + Vh :: A patch_decomposition :: PatchDecomposition num_dofs :: Int patch_cell_dofs_ids :: Arrays.Table dof_to_pdof :: Arrays.Table + metadata :: B + + function PatchFESpace( + space::SingleFieldFESpace, + patch_decomposition::PatchDecomposition, + num_dofs,patch_cell_dofs_ids,dof_to_pdof, + matadata=nothing + ) + A = typeof(space) + B = typeof(matadata) + new{A,B}(space,patch_decomposition,num_dofs,patch_cell_dofs_ids,dof_to_pdof,matadata) + end end @doc """ @@ -103,13 +115,13 @@ function PatchFESpace( return PatchFESpace(space,patch_decomposition,num_dofs,patch_cell_dofs_ids,dof_to_pdof) end -FESpaces.get_dof_value_type(a::PatchFESpace) = Gridap.FESpaces.get_dof_value_type(a.Vh) -FESpaces.get_free_dof_ids(a::PatchFESpace) = Base.OneTo(a.num_dofs) -FESpaces.get_fe_basis(a::PatchFESpace) = get_fe_basis(a.Vh) -FESpaces.ConstraintStyle(::PatchFESpace) = Gridap.FESpaces.UnConstrained() -FESpaces.ConstraintStyle(::Type{PatchFESpace}) = Gridap.FESpaces.UnConstrained() -FESpaces.get_vector_type(a::PatchFESpace) = get_vector_type(a.Vh) -FESpaces.get_fe_dof_basis(a::PatchFESpace) = get_fe_dof_basis(a.Vh) +FESpaces.get_dof_value_type(a::PatchFESpace) = Gridap.FESpaces.get_dof_value_type(a.Vh) +FESpaces.get_free_dof_ids(a::PatchFESpace) = Base.OneTo(a.num_dofs) +FESpaces.get_fe_basis(a::PatchFESpace) = get_fe_basis(a.Vh) +FESpaces.ConstraintStyle(::PatchFESpace) = Gridap.FESpaces.UnConstrained() +FESpaces.ConstraintStyle(::Type{<:PatchFESpace}) = Gridap.FESpaces.UnConstrained() +FESpaces.get_vector_type(a::PatchFESpace) = get_vector_type(a.Vh) +FESpaces.get_fe_dof_basis(a::PatchFESpace) = get_fe_dof_basis(a.Vh) function Gridap.CellData.get_triangulation(a::PatchFESpace) PD = a.patch_decomposition diff --git a/src/PatchBasedSmoothers/seq/VankaSolvers.jl b/src/PatchBasedSmoothers/seq/VankaSolvers.jl new file mode 100644 index 00000000..c819cdf5 --- /dev/null +++ b/src/PatchBasedSmoothers/seq/VankaSolvers.jl @@ -0,0 +1,79 @@ + +struct VankaSolver{A} <: Algebra.LinearSolver + patch_ids::A + function VankaSolver( + patch_ids::AbstractVector{<:AbstractVector{<:Integer}} + ) + A = typeof(patch_ids) + new{A}(patch_ids) + end +end + +function VankaSolver(space::MultiFieldFESpace) + trian = get_triangulation(space) + ncells = num_cells(trian) + patch_cells = Table(1:ncells,1:ncells+1) + return VankaSolver(space,patch_cells) +end + +function VankaSolver(space::MultiFieldFESpace,patch_decomposition::PatchDecomposition) + patch_cells = patch_decomposition.patch_cells + return VankaSolver(space,patch_cells) +end + +function VankaSolver(space::MultiFieldFESpace,patch_cells::Table{<:Integer}) + cell_ids = get_cell_dof_ids(space) + patch_ids = map(patch_cells) do cells + ids = vcat([vcat(cell_ids[cell].array...) for cell in cells]...) + filter!(x->x>0,ids) + sort!(ids) + unique!(ids) + return ids + end + return VankaSolver(patch_ids) +end + +struct VankaSS{A} <: Algebra.SymbolicSetup + solver::VankaSolver{A} +end + +Algebra.symbolic_setup(s::VankaSolver,mat::AbstractMatrix) = VankaSS(s) + +struct VankaNS{A,B,C} <: Algebra.NumericalSetup + solver::VankaSolver{A} + matrix::B + cache ::C +end + +function Algebra.numerical_setup(ss::VankaSS,mat::AbstractMatrix) + T = eltype(mat) + cache = (CachedArray(zeros(T,1)), CachedArray(zeros(T,1,1))) + return VankaNS(ss.solver,mat,cache) +end + +function Algebra.solve!(x::AbstractVector,ns::VankaNS,b::AbstractVector) + A, patch_ids = ns.matrix, ns.solver.patch_ids + c_xk, c_Ak = ns.cache + fill!(x,0.0) + + n_patches = length(patch_ids) + for patch in 1:n_patches + ids = patch_ids[patch] + + n = length(ids) + setsize!(c_xk,(n,)) + setsize!(c_Ak,(n,n)) + Ak = c_Ak.array + bk = c_xk.array + + copyto!(Ak,view(A,ids,ids)) + copyto!(bk,view(b,ids)) + f = lu!(Ak,NoPivot();check=false) + @check issuccess(f) "Factorization failed" + ldiv!(f,bk) + + x[ids] .+= bk + end + + return x +end diff --git a/src/PatchBasedSmoothers/seq/ZeroMeanPatchFESpaces.jl b/src/PatchBasedSmoothers/seq/ZeroMeanPatchFESpaces.jl new file mode 100644 index 00000000..0785dd9a --- /dev/null +++ b/src/PatchBasedSmoothers/seq/ZeroMeanPatchFESpaces.jl @@ -0,0 +1,143 @@ + +const ZeroMeanPatchFESpace{CA,S,B} = PatchFESpace{ZeroMeanFESpace{CA,S},B} + +function PatchFESpace( + space::FESpaces.ZeroMeanFESpace, + patch_decomposition::PatchDecomposition, + reffe::Union{ReferenceFE,Tuple{<:ReferenceFEs.ReferenceFEName,Any,Any}}; + conformity=nothing, + patches_mask = Fill(false,num_patches(patch_decomposition)) +) + pspace = PatchFESpace(space.space.space,patch_decomposition,reffe;conformity,patches_mask) + + n_patches = num_patches(patch_decomposition) + n_pdofs = pspace.num_dofs + patch_cells = patch_decomposition.patch_cells + pcell_to_pdofs = pspace.patch_cell_dofs_ids + dof_to_pdof = pspace.dof_to_pdof + + dof_to_dvol = space.vol_i + pdof_to_dvol = fill(0.0,n_pdofs) + for (dof,pdofs) in enumerate(dof_to_pdof) + pdof_to_dvol[pdofs] .= dof_to_dvol[dof] + end + + patch_vol = fill(0.0,n_patches) + pdof_to_new_pdof = fill(0,n_pdofs) + n_pdofs_free = 0 + n_pdofs_fixed = 1 # -1 reserved for homogeneous dirichlet on filtered patches + for patch in 1:n_patches + if patches_mask[patch] + continue + end + cell_s = patch_cells.ptrs[patch] + cell_e = patch_cells.ptrs[patch+1]-1 + pdof_s = pcell_to_pdofs.ptrs[cell_s] + pdof_e = pcell_to_pdofs.ptrs[cell_e+1]-1 + + # Patch volume + patch_vol[patch] = sum(pdof_to_dvol[pcell_to_pdofs.data[pdof_s:pdof_e]]) + + # First pdof per patch is fixed + pdof = pcell_to_pdofs.data[pdof_s] + n_pdofs_fixed += 1 + pdof_to_new_pdof[pdof] = -n_pdofs_fixed + pcell_to_pdofs.data[pdof_s] = -n_pdofs_fixed + + # The rest is free + for k in pdof_s+1:pdof_e + pdof = pcell_to_pdofs.data[k] + n_pdofs_free += 1 + pdof_to_new_pdof[pdof] = n_pdofs_free + pcell_to_pdofs.data[k] = n_pdofs_free + end + end + + dof_to_new_pdof = Table(collect(pdof_to_new_pdof[dof_to_pdof.data]), dof_to_pdof.ptrs) + + metadata = (patch_vol, pdof_to_dvol, n_pdofs, n_pdofs_free, n_pdofs_fixed, patches_mask) + return PatchFESpace(space,patch_decomposition,n_pdofs_free,pcell_to_pdofs,dof_to_new_pdof,metadata) +end + +# x \in PatchFESpace +# y \in SingleFESpace +function prolongate!(x,Ph::ZeroMeanPatchFESpace,y;dof_ids=LinearIndices(y)) + dof_to_pdof = Ph.dof_to_pdof + fixed_dof = Ph.Vh.space.dof_to_fix + + ptrs = dof_to_pdof.ptrs + data = dof_to_pdof.data + z = VectorWithEntryInserted(y,fixed_dof,zero(eltype(x))) + for dof in dof_ids + for k in ptrs[dof]:ptrs[dof+1]-1 + pdof = data[k] + if pdof > 0 # Is this correct? Should we correct the values in each patch? + x[pdof] = z[dof] + end + end + end +end + +# x \in SingleFESpace +# y \in PatchFESpace +function inject!(x,Ph::ZeroMeanPatchFESpace,y) + dof_to_pdof = Ph.dof_to_pdof + fixed_vals, _ = _compute_new_patch_fixedvals(y,Ph) + fixed_dof = Ph.Vh.space.dof_to_fix + + ptrs = dof_to_pdof.ptrs + data = dof_to_pdof.data + z = VectorWithEntryInserted(x,fixed_dof,zero(eltype(x))) + for dof in 1:length(dof_to_pdof) + z[dof] = 0.0 + for k in ptrs[dof]:ptrs[dof+1]-1 + pdof = data[k] + if pdof > 0 + z[dof] += y[pdof] + elseif pdof != -1 + z[dof] += fixed_vals[-pdof-1] + end + end + end + + x .-= z.value + return x +end + +function _compute_new_patch_fixedvals(x,Ph::ZeroMeanPatchFESpace) + patch_vol, pdof_to_dvol, n_pdofs, n_pdofs_free, n_pdofs_fixed, patches_mask = Ph.metadata + PD = Ph.patch_decomposition + patch_cells = PD.patch_cells + pcell_to_pdofs = Ph.patch_cell_dofs_ids + + n_patches = num_patches(PD) + k = 0 + fixed_vals = fill(0.0,n_pdofs_fixed) + fixed_pdofs = fill(0,n_pdofs_fixed) + for patch in 1:n_patches + if patches_mask[patch] + continue + end + pcell_s = patch_cells.ptrs[patch] + pcell_e = patch_cells.ptrs[patch+1]-1 + + pdof_s = pcell_to_pdofs.ptrs[pcell_s] + pdof_e = pcell_to_pdofs.ptrs[pcell_e+1]-1 + + fixed_pdof = -pcell_to_pdofs.data[pdof_s] + free_pdofs = pcell_to_pdofs.data[pdof_s+1]:pcell_to_pdofs.data[pdof_e] + pdofs = (pcell_to_pdofs.data[pdof_s+1]:pcell_to_pdofs.data[pdof_e]+1) .+ k + + fv = view(x,free_pdofs) + dv = [zero(eltype(fv))] + vol_i = view(pdof_to_dvol,pdofs) + c = FESpaces._compute_new_fixedval(fv,dv,vol_i,patch_vol[patch],1) + + k += 1 + x[free_pdofs] .+= c + fixed_vals[k] = c + fixed_pdofs[k] = fixed_pdof + end + + return fixed_vals, fixed_pdofs +end diff --git a/test/_dev/MacroFEs/block_stokes.jl b/test/_dev/MacroFEs/block_stokes.jl new file mode 100644 index 00000000..10dae068 --- /dev/null +++ b/test/_dev/MacroFEs/block_stokes.jl @@ -0,0 +1,81 @@ + +using Gridap +using Gridap.Adaptivity, Gridap.Geometry, Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Arrays +using Gridap.MultiField, Gridap.Algebra + +using GridapSolvers +using GridapSolvers.BlockSolvers, GridapSolvers.LinearSolvers + +using FillArrays + +# Parameters + +Dc = 3 +reftype = 1 + +u_sol(x) = (Dc == 2) ? VectorValue(x[1]^2*x[2], -x[1]*x[2]^2) : VectorValue(x[1]^2*x[2], -x[1]*x[2]^2,0.0) +p_sol(x) = (x[1] - 1.0/2.0) + +domain = (Dc == 2) ? (0,1,0,1) : (0,1,0,1,0,1) +nc = (Dc == 2) ? (20,20) : (4,4,4) +model = simplexify(CartesianDiscreteModel(domain,nc)) + +min_order = (reftype == 1) ? Dc : Dc-1 +order = max(2,min_order) +poly = (Dc == 2) ? TRI : TET +rrule = (reftype == 1) ? Adaptivity.BarycentricRefinementRule(poly) : Adaptivity.PowellSabinRefinementRule(poly) +reffes = Fill(LagrangianRefFE(VectorValue{Dc,Float64},poly,order),Adaptivity.num_subcells(rrule)) +reffe_u = Adaptivity.MacroReferenceFE(rrule,reffes) +reffe_p = LagrangianRefFE(Float64,poly,order-1) + +qdegree = 2*order +quad = Quadrature(poly,Adaptivity.CompositeQuadrature(),rrule,qdegree) + +V = FESpace(model,reffe_u,dirichlet_tags=["boundary"]) +Q = FESpace(model,reffe_p,conformity=:L2,constraint=:zeromean) +U = TrialFESpace(V,u_sol) + +Ω = Triangulation(model) +dΩ = Measure(Ω,quad) +@assert abs(sum(∫(p_sol)dΩ)) < 1.e-15 +@assert abs(sum(∫(divergence(u_sol))dΩ)) < 1.e-15 + +mfs = BlockMultiFieldStyle() +X = MultiFieldFESpace([U,Q];style=mfs) +Y = MultiFieldFESpace([V,Q];style=mfs) + +α = 1.e2 +f(x) = -Δ(u_sol)(x) + ∇(p_sol)(x) +graddiv(u,v) = ∫(α*(∇⋅v)⋅(∇⋅u))dΩ +lap(u,v) = ∫(∇(u)⊙∇(v))dΩ +a((u,p),(v,q)) = lap(u,v) + ∫(divergence(u)*q - divergence(v)*p)dΩ + graddiv(u,v) +l((v,q)) = ∫(f⋅v)dΩ + +op = AffineFEOperator(a,l,X,Y) +A = get_matrix(op) +b = get_vector(op) + +solver_u = LUSolver() +solver_p = CGSolver(JacobiLinearSolver();maxiter=20,atol=1e-14,rtol=1.e-6) +solver_p.log.depth = 2 + +bblocks = [LinearSystemBlock() LinearSystemBlock(); + LinearSystemBlock() BiformBlock((p,q) -> ∫(-(1.0/α)*p*q)dΩ,Q,Q)] +coeffs = [1.0 1.0; + 0.0 1.0] +P = BlockTriangularSolver(bblocks,[solver_u,solver_p],coeffs,:upper) +solver = FGMRESSolver(20,P;atol=1e-10,rtol=1.e-12,verbose=true) +ns = numerical_setup(symbolic_setup(solver,A),A) + +x = allocate_in_domain(A); fill!(x,0.0) +solve!(x,ns,b) +xh = FEFunction(X,x) + +uh, ph = xh +eh_u = uh - u_sol +eh_p = ph - p_sol +sum(∫(eh_u⋅eh_u)dΩ) +sum(∫(eh_p*eh_p)dΩ) + +norm(assemble_vector( q -> ∫(divergence(uh)*q)dΩ, Q)) +abs(sum(∫(divergence(uh))dΩ)) diff --git a/test/_dev/MacroFEs/stokes.jl b/test/_dev/MacroFEs/stokes.jl index ea5887b1..d575fc53 100644 --- a/test/_dev/MacroFEs/stokes.jl +++ b/test/_dev/MacroFEs/stokes.jl @@ -18,7 +18,6 @@ reffes = Fill(LagrangianRefFE(VectorValue{2,Float64},TRI,order),Adaptivity.num_s reffe_u = Adaptivity.MacroReferenceFE(rrule,reffes) reffe_p = LagrangianRefFE(Float64,TRI,order-1) -#reffe_p = Adaptivity.MacroReferenceFE(rrule,reffes;conformity=L2Conformity()) qdegree = 2*order quad = Quadrature(TRI,Adaptivity.CompositeQuadrature(),rrule,qdegree) diff --git a/test/_dev/PatchBased/ZeroMeanPatchBasedFESpaces.jl b/test/_dev/PatchBased/ZeroMeanPatchBasedFESpaces.jl new file mode 100644 index 00000000..5b86a5d8 --- /dev/null +++ b/test/_dev/PatchBased/ZeroMeanPatchBasedFESpaces.jl @@ -0,0 +1,96 @@ + +using Gridap +using GridapSolvers + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +u_exact(x) = VectorValue(-x[1],x[2]) +p_exact(x) = x[1] + x[2] + +model = CartesianDiscreteModel((0,1,0,1),(2,2)) +PD = PatchDecomposition(model) + +Ω = Triangulation(model) +Ωp = Triangulation(PD) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) + +Vh = TestFESpace(model,reffe_u,dirichlet_tags="boundary") +Uh = TrialFESpace(Vh,u_exact) + +Qh = TestFESpace(model,reffe_p,conformity=:L2,constraint=:zeromean) + +topo = get_grid_topology(model) +#patches_mask = fill(false,PatchBasedSmoothers.num_patches(PD)) +patches_mask = get_isboundary_face(topo,0) +Ph = PatchFESpace(Vh,PD,reffe_u;conformity=H1Conformity(),patches_mask=patches_mask) +Lh = PatchFESpace(Qh,PD,reffe_p;conformity=L2Conformity(),patches_mask=patches_mask) + +Xh = MultiFieldFESpace([Uh,Qh]) +Yh = MultiFieldFESpace([Vh,Qh]) +Zh = MultiFieldFESpace([Ph,Lh]) + +qdegree = 2*order +dΩ = Measure(Ω,qdegree) +dΩp = Measure(Ωp,qdegree) + +p_mean = sum(∫(p_exact)dΩ)/sum(∫(1)dΩ) +p_exact_zm(x) = p_exact(x) - p_mean +f(x) = Δ(u_exact)(x) + ∇(p_exact_zm)(x) +liform((v,q),dΩ) = ∫(v⋅f)dΩ +biform((u,p),(v,q),dΩ) = ∫(∇(u)⊙∇(v) - (∇⋅v)*p - (∇⋅u)*q)dΩ +a(x,y) = biform(x,y,dΩ) +l(y) = liform(y,dΩ) +ap(x,y) = biform(x,y,dΩp) + +op = AffineFEOperator(a,l,Xh,Yh) +A = get_matrix(op) +b = get_vector(op) +x_exact = A\b + +P = PatchBasedSmoothers.PatchBasedLinearSolver(ap,Zh,Yh) +P_ns = numerical_setup(symbolic_setup(P,A),A) +x = zeros(num_free_dofs(Yh)) +solve!(x,P_ns,b) + +solver = FGMRESSolver(10,P;verbose=true) +#solver = GMRESSolver(10,verbose=true) +ns = numerical_setup(symbolic_setup(solver,A),A) + +x = zeros(num_free_dofs(Yh)) +solve!(x,ns,b) + +norm(A*x - b) + +############################################################################################ + +patch_pcells = PD.patch_cells_overlapped +pcell_to_pdofs_u = Ph.patch_cell_dofs_ids +pcell_to_pdofs_p = Lh.patch_cell_dofs_ids + +patch_dofs_u = map(pcells -> unique(filter(x -> x > 0, vcat(pcell_to_pdofs_u[pcells]...))),patch_pcells) +patch_dofs_p = map(pcells -> unique(filter(x -> x > 0, vcat(pcell_to_pdofs_p[pcells]...))),patch_pcells) + +o = num_free_dofs(Ph) +patch_dofs = map((du,dp) -> vcat(du,dp .+ o),patch_dofs_u,patch_dofs_p) + +patch_cells = PD.patch_cells +patch_models = map(patch_cells) do cells + pmodel = DiscreteModelPortion(model,cells) + pgrid = UnstructuredGrid(get_grid(pmodel)) + ptopo = get_grid_topology(pmodel) + plabels = FaceLabeling(ptopo) + UnstructuredDiscreteModel(pgrid,ptopo,plabels) +end + +patch_spaces = map(patch_models) do pmodel + Vhi = TestFESpace(pmodel,reffe_u;dirichlet_tags="boundary") + Qhi = TestFESpace(pmodel,reffe_p,conformity=:L2,constraint=:zeromean) + Yhi = MultiFieldFESpace([Vhi,Qhi]) +end + +Ap = assemble_matrix(ap,Zh,Zh) +patch_mats = map(dofs -> Ap[dofs,dofs],patch_dofs) diff --git a/test/_dev/Vanka/darcy_vanka.jl b/test/_dev/Vanka/darcy_vanka.jl new file mode 100644 index 00000000..bfd185f3 --- /dev/null +++ b/test/_dev/Vanka/darcy_vanka.jl @@ -0,0 +1,79 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +u_exact(x) = VectorValue(-x[1],x[2]) +p_exact(x) = x[1] - 0.5 + +Dc = 2 +model = CartesianDiscreteModel((0,1,0,1),(8,8)) +labels = get_face_labeling(model) +add_tag_from_tags!(labels,"newman",[5]) +add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) + +order = 1 +reffe_u = ReferenceFE(raviart_thomas,Float64,order-1) +reffe_p = ReferenceFE(lagrangian,Float64,order-1) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p,conformity=:L2) + +Xh = MultiFieldFESpace([Uh,Qh]) +Yh = MultiFieldFESpace([Vh,Qh]) + +qdegree = 2*order +Ω = Triangulation(model) +dΩ = Measure(Ω,qdegree) + +Γ = BoundaryTriangulation(model,tags="newman") +dΓ = Measure(Γ,qdegree) +n = get_normal_vector(Γ) + +f(x) = u_exact(x) - ∇(p_exact)(x) +σ(x) = p_exact(x) +a((u,p),(v,q)) = ∫(u⋅v + (∇⋅v)*p - (∇⋅u)*q)dΩ +l((v,q)) = ∫(v⋅f)dΩ + ∫(v⋅(σ⋅n) )dΓ + +op = AffineFEOperator(a,l,Xh,Yh) +A = get_matrix(op) +b = get_vector(op) +cond(Matrix(A)) +x_exact = A\b + +uh_exact, ph_exact = FEFunction(Xh,x_exact) +l2_error(uh_exact,u_exact,dΩ) +l2_error(ph_exact,p_exact,dΩ) +l2_norm(∇⋅uh_exact,dΩ) + +PD = PatchDecomposition(model) +P = VankaSolver(Xh,PD) +P_ns = numerical_setup(symbolic_setup(P,A),A) + +x = zeros(num_free_dofs(Yh)) +r = b - A*x +solve!(x,P_ns,r) +norm(x_exact - x) + + +solver = FGMRESSolver(10,P;rtol=1.e-8,verbose=true) +#solver = GMRESSolver(10,verbose=true) +ns = numerical_setup(symbolic_setup(solver,A),A) + +x = zeros(num_free_dofs(Yh)) +solve!(x,ns,b) +norm(A*x - b) diff --git a/test/_dev/Vanka/darcy_vanka_GMG.jl b/test/_dev/Vanka/darcy_vanka_GMG.jl new file mode 100644 index 00000000..cbd7eb3e --- /dev/null +++ b/test/_dev/Vanka/darcy_vanka_GMG.jl @@ -0,0 +1,132 @@ +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra, Gridap.Arrays, Gridap.Adaptivity +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +u_exact(x) = VectorValue(-x[1],x[2]) +p_exact(x) = x[1] - 0.5 + +Dc = 2 +cmodel = CartesianDiscreteModel((0,1,0,1),(4,4)) +labels = get_face_labeling(cmodel) +add_tag_from_tags!(labels,"newman",[5]) +add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) +model = refine(cmodel,2) + +order = 1 +reffe_u = ReferenceFE(raviart_thomas,Float64,order-1) +reffe_p = ReferenceFE(lagrangian,Float64,order-1) + +VH = TestFESpace(cmodel,reffe_u;dirichlet_tags="dirichlet") +UH = TrialFESpace(VH,u_exact) +QH = TestFESpace(cmodel,reffe_p,conformity=:L2) +XH = MultiFieldFESpace([UH,QH]) +YH = MultiFieldFESpace([VH,QH]) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p,conformity=:L2) +Xh = MultiFieldFESpace([Uh,Qh]) +Yh = MultiFieldFESpace([Vh,Qh]) + +qdegree = 2*order +Ωh = Triangulation(model) +dΩh = Measure(Ωh,qdegree) +ΩH = Triangulation(cmodel) +dΩH = Measure(ΩH,qdegree) +dΩHh = Measure(ΩH,Ωh,qdegree) + +Γh = BoundaryTriangulation(model,tags="newman") +dΓh = Measure(Γh,qdegree) +n = get_normal_vector(Γh) + +α = 10.0 +f(x) = u_exact(x) - ∇(p_exact)(x) +σ(x) = p_exact(x) +graddiv(u,v,dΩ) = ∫((∇⋅u)⋅(∇⋅v))*dΩ +function a((u,p),(v,q),dΩ) + c = ∫(u⋅v + (∇⋅v)*p - (∇⋅u)*q)dΩ + if !iszero(α) + c += graddiv(u,v,dΩ) + end + return c +end +l((v,q),dΩ,dΓ) = ∫(v⋅f)dΩ + ∫(v⋅(σ⋅n))dΓ + +ah(x,y) = a(x,y,dΩh) +aH(x,y) = a(x,y,dΩH) +lh(y) = l(y,dΩh,dΓh) + +op_h = AffineFEOperator(ah,lh,Xh,Yh) +Ah = get_matrix(op_h) +bh = get_vector(op_h) +xh_exact = Ah\bh + +AH = assemble_matrix(aH,XH,YH) +Mhh = assemble_matrix((u,v)->∫(u⋅v)*dΩh,Xh,Xh) + +uh_exact, ph_exact = FEFunction(Xh,xh_exact) +l2_error(uh_exact,u_exact,dΩh) +l2_error(ph_exact,p_exact,dΩh) +l2_norm(∇⋅uh_exact,dΩh) + +PD = PatchDecomposition(model) +smoother = RichardsonSmoother(VankaSolver(Xh,PD),5,0.2) +smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) + +function project_f2c(rh) + Qrh = Mhh\rh + uh, ph = FEFunction(Yh,Qrh) + ll((v,q)) = ∫(v⋅uh + q*ph)*dΩHh + assemble_vector(ll,YH) +end +function interp_c2f(xH) + get_free_dof_values(interpolate(FEFunction(YH,xH),Yh)) +end + +xh = randn(size(Ah,2)) +rh = bh - Ah*xh +niters = 10 + +iter = 0 +error0 = norm(rh) +error = error0 +e_rel = error/error0 +while iter < niters && e_rel > 1.0e-10 + println("Iter $iter:") + println(" > Initial: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + println(" > Pre-smoother: ", norm(rh)) + + rH = project_f2c(rh) + qH = AH\rH + qh = interp_c2f(qH) + + rh = rh - Ah*qh + xh = xh + qh + println(" > Post-correction: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + + iter += 1 + error = norm(rh) + e_rel = error/error0 + println(" > Final: ",error, " - ", e_rel) +end + +uh, ph = FEFunction(Xh,xh) +l2_error(uh,u_exact,dΩh) +l2_error(ph,p_exact,dΩh) diff --git a/test/_dev/Vanka/stokes_vanka.jl b/test/_dev/Vanka/stokes_vanka.jl new file mode 100644 index 00000000..67f9a5bc --- /dev/null +++ b/test/_dev/Vanka/stokes_vanka.jl @@ -0,0 +1,80 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra, Gridap.Arrays +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +u_exact(x) = VectorValue(-x[1],x[2]) +p_exact(x) = x[1] - 0.5 + +Dc = 2 +model = CartesianDiscreteModel((0,1,0,1),(8,8)) +labels = get_face_labeling(model) +add_tag_from_tags!(labels,"newman",[5]) +add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p,conformity=:L2) + +Xh = MultiFieldFESpace([Uh,Qh]) +Yh = MultiFieldFESpace([Vh,Qh]) + +qdegree = 2*order +Ω = Triangulation(model) +dΩ = Measure(Ω,qdegree) + +Γ = BoundaryTriangulation(model,tags="newman") +dΓ = Measure(Γ,qdegree) +n = get_normal_vector(Γ) + +I_tensor = one(TensorValue{Dc,Dc,Float64}) +f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) +σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor +a((u,p),(v,q)) = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ +l((v,q)) = ∫(v⋅f)dΩ + ∫(v⋅(σ⋅n) )dΓ + +op = AffineFEOperator(a,l,Xh,Yh) +A = get_matrix(op) +b = get_vector(op) +cond(Matrix(A)) +x_exact = A\b + +uh_exact, ph_exact = FEFunction(Xh,x_exact) +l2_error(uh_exact,u_exact,dΩ) +l2_error(ph_exact,p_exact,dΩ) +l2_norm(∇⋅uh_exact,dΩ) + +PD = PatchDecomposition(model) +P = VankaSolver(Xh,PD) +P_ns = numerical_setup(symbolic_setup(P,A),A) + +x = zeros(num_free_dofs(Yh)) +r = b - A*x +solve!(x,P_ns,r) +norm(x_exact - x) + + +solver = FGMRESSolver(10,P;rtol=1.e-8,verbose=true) +#solver = GMRESSolver(10,verbose=true) +ns = numerical_setup(symbolic_setup(solver,A),A) + +x = zeros(num_free_dofs(Yh)) +solve!(x,ns,b) +norm(A*x - b) diff --git a/test/_dev/Vanka/stokes_vanka_GMG.jl b/test/_dev/Vanka/stokes_vanka_GMG.jl new file mode 100644 index 00000000..23cbc972 --- /dev/null +++ b/test/_dev/Vanka/stokes_vanka_GMG.jl @@ -0,0 +1,125 @@ +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra, Gridap.Arrays, Gridap.Adaptivity +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +u_exact(x) = VectorValue(-x[1],x[2]) +p_exact(x) = x[1] - 0.5 + +Dc = 2 +cmodel = CartesianDiscreteModel((0,1,0,1),(4,4)) +labels = get_face_labeling(cmodel) +add_tag_from_tags!(labels,"newman",[5]) +add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) +model = refine(cmodel,2) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) + +VH = TestFESpace(cmodel,reffe_u;dirichlet_tags="dirichlet") +UH = TrialFESpace(VH,u_exact) +QH = TestFESpace(cmodel,reffe_p,conformity=:L2) +XH = MultiFieldFESpace([UH,QH]) +YH = MultiFieldFESpace([VH,QH]) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p,conformity=:L2) +Xh = MultiFieldFESpace([Uh,Qh]) +Yh = MultiFieldFESpace([Vh,Qh]) + +qdegree = 2*order +Ωh = Triangulation(model) +dΩh = Measure(Ωh,qdegree) +ΩH = Triangulation(cmodel) +dΩH = Measure(ΩH,qdegree) +dΩHh = Measure(ΩH,Ωh,qdegree) + +Γh = BoundaryTriangulation(model,tags="newman") +dΓh = Measure(Γh,qdegree) +n = get_normal_vector(Γh) + +I_tensor = one(TensorValue{Dc,Dc,Float64}) +f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) +σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor +a((u,p),(v,q),dΩ) = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ +l((v,q),dΩ,dΓ) = ∫(v⋅f)dΩ + ∫(v⋅(σ⋅n) )dΓ + +ah(x,y) = a(x,y,dΩh) +aH(x,y) = a(x,y,dΩH) +lh(y) = l(y,dΩh,dΓh) + +op_h = AffineFEOperator(ah,lh,Xh,Yh) +Ah = get_matrix(op_h) +bh = get_vector(op_h) +xh_exact = Ah\bh + +AH = assemble_matrix(aH,XH,YH) +Mhh = assemble_matrix((u,v)->∫(u⋅v)*dΩh,Xh,Xh) + +uh_exact, ph_exact = FEFunction(Xh,xh_exact) +l2_error(uh_exact,u_exact,dΩh) +l2_error(ph_exact,p_exact,dΩh) +l2_norm(∇⋅uh_exact,dΩh) + +PD = PatchDecomposition(model) +smoother = RichardsonSmoother(VankaSolver(Xh,PD),5,0.2) +smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) + +function project_f2c(rh) + Qrh = Mhh\rh + uh, ph = FEFunction(Yh,Qrh) + ll((v,q)) = ∫(v⋅uh + q*ph)*dΩHh + assemble_vector(ll,YH) +end +function interp_c2f(xH) + get_free_dof_values(interpolate(FEFunction(YH,xH),Yh)) +end + +xh = randn(size(Ah,2)) +rh = bh - Ah*xh +niters = 10 + +iter = 0 +error0 = norm(rh) +error = error0 +e_rel = error/error0 +while iter < niters && e_rel > 1.0e-10 + println("Iter $iter:") + println(" > Initial: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + println(" > Pre-smoother: ", norm(rh)) + + rH = project_f2c(rh) + qH = AH\rH + qh = interp_c2f(qH) + + rh = rh - Ah*qh + xh = xh + qh + println(" > Post-correction: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + + iter += 1 + error = norm(rh) + e_rel = error/error0 + println(" > Final: ",error, " - ", e_rel) +end + +uh, ph = FEFunction(Xh,xh) +l2_error(uh,u_exact,dΩh) +l2_error(ph,p_exact,dΩh) diff --git a/test/_dev/Vanka/stokes_vanka_PCont.jl b/test/_dev/Vanka/stokes_vanka_PCont.jl new file mode 100644 index 00000000..75da9b4c --- /dev/null +++ b/test/_dev/Vanka/stokes_vanka_PCont.jl @@ -0,0 +1,90 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +using GridapSolvers.PatchBasedSmoothers: PatchBoundaryExclude, PatchBoundaryInclude + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +u_exact(x) = VectorValue(-x[1],x[2]) +p_exact(x) = x[1] - 0.5 + +Dc = 2 +model = CartesianDiscreteModel((0,1,0,1),(8,8)) +labels = get_face_labeling(model) +add_tag_from_tags!(labels,"newman",[5]) +add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) + +PD_e = PatchDecomposition(model,patch_boundary_style=PatchBoundaryExclude()) +PD_i = PatchDecomposition(model,patch_boundary_style=PatchBoundaryInclude()) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p) + +PD = PD_i +Ph = PatchFESpace(Vh,PD_i,reffe_u;conformity=H1Conformity()) +Lh = PatchFESpace(Qh,PD_e,reffe_p;conformity=H1Conformity()) + +Xh = MultiFieldFESpace([Uh,Qh]) +Yh = MultiFieldFESpace([Vh,Qh]) +Zh = MultiFieldFESpace([Ph,Lh]) + +qdegree = 2*order +Ω = Triangulation(model) +Ωp = Triangulation(PD) + +dΩ = Measure(Ω,qdegree) +dΩp = Measure(Ωp,qdegree) + +Γ = BoundaryTriangulation(model,tags="newman") +dΓ = Measure(Γ,qdegree) +n = get_normal_vector(Γ) + +I_tensor = one(TensorValue{Dc,Dc,Float64}) +f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) +σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor +biform((u,p),(v,q),dΩ) = ∫(∇(u)⊙∇(v) + (∇⋅v)*p + (∇⋅u)*q)dΩ +a(x,y) = biform(x,y,dΩ) +l((v,q)) = ∫(v⋅f)dΩ + ∫(v⋅(σ⋅n) )dΓ + +ap(x,y) = biform(x,y,dΩp) + +op = AffineFEOperator(a,l,Xh,Yh) +A = get_matrix(op) +b = get_vector(op) +cond(Matrix(A)) +x_exact = A\b +uh_exact, ph_exact = FEFunction(Xh,x_exact) +l2_error(uh_exact,u_exact,dΩ) +l2_error(ph_exact,p_exact,dΩ) +l2_norm(∇⋅uh_exact,dΩ) + +P = PatchBasedSmoothers.PatchBasedLinearSolver(ap,Zh,Yh) +P_ns = numerical_setup(symbolic_setup(P,A),A) +x = zeros(num_free_dofs(Yh)) +solve!(x,P_ns,b) + +solver = FGMRESSolver(10,P;rtol=1.e-8,verbose=true) +#solver = GMRESSolver(10,verbose=true) +ns = numerical_setup(symbolic_setup(solver,A),A) + +x = zeros(num_free_dofs(Yh)) +solve!(x,ns,b) + +norm(A*x - b) diff --git a/test/_dev/Vanka/stokes_vanka_Pdisc.jl b/test/_dev/Vanka/stokes_vanka_Pdisc.jl new file mode 100644 index 00000000..5a2e7b8d --- /dev/null +++ b/test/_dev/Vanka/stokes_vanka_Pdisc.jl @@ -0,0 +1,99 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +using GridapSolvers.PatchBasedSmoothers: PatchBoundaryExclude, PatchBoundaryInclude, num_patches + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +u_exact(x) = VectorValue(-x[1],x[2]) +p_exact(x) = x[1] - 0.5 + +Dc = 2 +model = CartesianDiscreteModel((0,1,0,1),(2,2)) +labels = get_face_labeling(model) +add_tag_from_tags!(labels,"newman",[5]) +add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) + +PD_e = PatchDecomposition(model,patch_boundary_style=PatchBoundaryExclude()) +PD_i = PatchDecomposition(model,patch_boundary_style=PatchBoundaryInclude()) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +#Vh = TestFESpace(model,reffe_u) +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p,conformity=:L2) + +PD = PD_i +topo = get_grid_topology(model) +#patches_mask = fill(false,num_patches(PD)) +patches_mask = get_isboundary_face(topo,0) + +Ph = PatchFESpace(Vh,PD,reffe_u;conformity=H1Conformity(),patches_mask) +Lh = PatchFESpace(Qh,PD,reffe_p;conformity=L2Conformity(),patches_mask) + +Xh = MultiFieldFESpace([Uh,Qh]) +Yh = MultiFieldFESpace([Vh,Qh]) +Zh = MultiFieldFESpace([Ph,Lh]) + +qdegree = 2*order +Ω = Triangulation(model) +Ωp = Triangulation(PD) + +dΩ = Measure(Ω,qdegree) +dΩp = Measure(Ωp,qdegree) + +Γ = BoundaryTriangulation(model,tags="newman") +dΓ = Measure(Γ,qdegree) +n = get_normal_vector(Γ) + +I_tensor = one(TensorValue{Dc,Dc,Float64}) +f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) +σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor +biform((u,p),(v,q),dΩ) = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ +a(x,y) = biform(x,y,dΩ) +l((v,q)) = ∫(v⋅f)dΩ + ∫(v⋅(σ⋅n) )dΓ + +ap(x,y) = biform(x,y,dΩp) + +op = AffineFEOperator(a,l,Xh,Yh) +A = get_matrix(op) +b = get_vector(op) +cond(Matrix(A)) +x_exact = A\b + +uh_exact, ph_exact = FEFunction(Xh,x_exact) +l2_error(uh_exact,u_exact,dΩ) +l2_error(ph_exact,p_exact,dΩ) +l2_norm(∇⋅uh_exact,dΩ) + +P = PatchBasedSmoothers.PatchBasedLinearSolver(ap,Zh,Yh) +P_ns = numerical_setup(symbolic_setup(P,A),A) +x = zeros(num_free_dofs(Yh)) +r = b - A*x +solve!(x,P_ns,r) + +Ap = assemble_matrix(ap,Zh,Zh) + +solver = FGMRESSolver(10,P;rtol=1.e-8,verbose=true) +#solver = GMRESSolver(10,verbose=true) +ns = numerical_setup(symbolic_setup(solver,A),A) + +x = zeros(num_free_dofs(Yh)) +solve!(x,ns,b) + +norm(A*x - b) From 993b08cc65a950db78db7e060287f17e98ea461d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 22 Aug 2024 15:45:21 +1000 Subject: [PATCH 02/47] More drivers --- test/_dev/Vanka/darcy_patch.jl | 69 +++++++++ test/_dev/Vanka/darcy_vanka_GMG.jl | 7 +- test/_dev/Vanka/mhd_vanka_GMG.jl | 172 +++++++++++++++++++++++ test/_dev/Vanka/stokes_vanka_GMG.jl | 15 +- test/_dev/Vanka/stokesdarcy_vanka_GMG.jl | 172 +++++++++++++++++++++++ 5 files changed, 430 insertions(+), 5 deletions(-) create mode 100644 test/_dev/Vanka/darcy_patch.jl create mode 100644 test/_dev/Vanka/mhd_vanka_GMG.jl create mode 100644 test/_dev/Vanka/stokesdarcy_vanka_GMG.jl diff --git a/test/_dev/Vanka/darcy_patch.jl b/test/_dev/Vanka/darcy_patch.jl new file mode 100644 index 00000000..4c1bee29 --- /dev/null +++ b/test/_dev/Vanka/darcy_patch.jl @@ -0,0 +1,69 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +u_exact(x) = VectorValue(-x[1],x[2]) +p_exact(x) = x[1] - 0.5 + +Dc = 2 +model = CartesianDiscreteModel((0,1,0,1),(2,2)) +labels = get_face_labeling(model) +add_tag_from_tags!(labels,"newman",[5]) +add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) + +order = 1 +reffe_u = ReferenceFE(raviart_thomas,Float64,order-1) +reffe_p = ReferenceFE(lagrangian,Float64,order-1) + +Vh = TestFESpace(model,reffe_u) +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p,conformity=:L2) + +Xh = MultiFieldFESpace([Uh,Qh]) +Yh = MultiFieldFESpace([Vh,Qh]) + +qdegree = 2*order +Ω = Triangulation(model) +dΩ = Measure(Ω,qdegree) + +Γ = BoundaryTriangulation(model,tags="boundary") +dΓ = Measure(Γ,qdegree) +n = get_normal_vector(Γ) + +α = 10.0 +f(x) = u_exact(x) - ∇(p_exact)(x) +σ(x) = p_exact(x) +function a((u,p),(v,q)) + c = ∫(u⋅v + (∇⋅v)*p + (∇⋅u)*q)dΩ + if !iszero(α) + c += ∫((∇⋅u)⋅(∇⋅v))*dΩ + end + return c +end +l((v,q)) = ∫(v⋅f)dΩ + ∫(v⋅(σ⋅n) )dΓ + +op = AffineFEOperator(a,l,Xh,Yh) +A = get_matrix(op) +b = get_vector(op) +cond(Matrix(A)) +x_exact = A\b + +uh_exact, ph_exact = FEFunction(Xh,x_exact) +l2_error(uh_exact,u_exact,dΩ) +l2_error(ph_exact,p_exact,dΩ) +l2_norm(∇⋅uh_exact,dΩ) + diff --git a/test/_dev/Vanka/darcy_vanka_GMG.jl b/test/_dev/Vanka/darcy_vanka_GMG.jl index cbd7eb3e..68ae5bc3 100644 --- a/test/_dev/Vanka/darcy_vanka_GMG.jl +++ b/test/_dev/Vanka/darcy_vanka_GMG.jl @@ -57,8 +57,8 @@ f(x) = u_exact(x) - ∇(p_exact)(x) σ(x) = p_exact(x) graddiv(u,v,dΩ) = ∫((∇⋅u)⋅(∇⋅v))*dΩ function a((u,p),(v,q),dΩ) - c = ∫(u⋅v + (∇⋅v)*p - (∇⋅u)*q)dΩ - if !iszero(α) + c = ∫(u⋅v + (∇⋅v)*p + (∇⋅u)*q)dΩ + if α > 0.0 c += graddiv(u,v,dΩ) end return c @@ -82,8 +82,9 @@ l2_error(uh_exact,u_exact,dΩh) l2_error(ph_exact,p_exact,dΩh) l2_norm(∇⋅uh_exact,dΩh) +# NOTE: Convergence seem quite dependent on the damping weight. For ω=0.2, we diverge... PD = PatchDecomposition(model) -smoother = RichardsonSmoother(VankaSolver(Xh,PD),5,0.2) +smoother = RichardsonSmoother(VankaSolver(Xh,PD),10,0.1) smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) function project_f2c(rh) diff --git a/test/_dev/Vanka/mhd_vanka_GMG.jl b/test/_dev/Vanka/mhd_vanka_GMG.jl new file mode 100644 index 00000000..d0858e76 --- /dev/null +++ b/test/_dev/Vanka/mhd_vanka_GMG.jl @@ -0,0 +1,172 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra, Gridap.Arrays, Gridap.Adaptivity +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +function add_labels_2d(model) + labels = get_face_labeling(model) + add_tag_from_tags!(labels,"newman",[5]) + add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) +end + +function add_labels_3d(model) + labels = get_face_labeling(model) + add_tag_from_tags!(labels,"newman",[21]) + add_tag_from_tags!(labels,"dirichlet",[collect(1:20)...,22,23,24,25,26]) +end + +B = VectorValue(0.0,0.0,1.0) +u_exact(x) = VectorValue(x[1],-x[2],0.0) +p_exact(x) = sum(x) +j_exact(x) = VectorValue(-x[2],-x[1],0.0) + VectorValue(1.0,1.0,0.0) +φ_exact(x) = x[1] + x[2] + +Dc = 3 +domain = (Dc == 2) ? (0,1,0,1) : (0,1,0,1,0,1) +ncells = (Dc == 2) ? (4,4) : (2,2,2) +cmodel = CartesianDiscreteModel(domain,ncells) +if Dc == 2 + add_labels_2d(cmodel) +else + add_labels_3d(cmodel) +end +model = refine(cmodel,2) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{Dc,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) +reffe_j = ReferenceFE(raviart_thomas,Float64,order-1) +reffe_φ = ReferenceFE(lagrangian,Float64,order-1) + +VH = TestFESpace(cmodel,reffe_u;dirichlet_tags="dirichlet") +UH = TrialFESpace(VH,u_exact) +QH = TestFESpace(cmodel,reffe_p,conformity=:L2) +DH = TestFESpace(cmodel,reffe_j;dirichlet_tags="dirichlet") +JH = TrialFESpace(DH,j_exact) +ΦH = TestFESpace(cmodel,reffe_φ,conformity=:L2) + +XH = MultiFieldFESpace([UH,QH,JH,ΦH]) +YH = MultiFieldFESpace([VH,QH,DH,ΦH]) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p,conformity=:L2) +Dh = TestFESpace(model,reffe_j;dirichlet_tags="dirichlet") +Jh = TrialFESpace(Dh,j_exact) +Φh = TestFESpace(model,reffe_φ,conformity=:L2) +Xh = MultiFieldFESpace([Uh,Qh,Jh,Φh]) +Yh = MultiFieldFESpace([Vh,Qh,Dh,Φh]) + +qdegree = 2*order +Ωh = Triangulation(model) +dΩh = Measure(Ωh,qdegree) +ΩH = Triangulation(cmodel) +dΩH = Measure(ΩH,qdegree) +dΩHh = Measure(ΩH,Ωh,qdegree) + +Γh = BoundaryTriangulation(model,tags="newman") +dΓh = Measure(Γh,qdegree) +n = get_normal_vector(Γh) + +α = -1.0 +I_tensor = one(TensorValue{Dc,Dc,Float64}) +f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) - cross(j_exact(x),B) +g(x) = j_exact(x) - ∇(φ_exact)(x) - cross(u_exact(x),B) +σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor +γ(x) = φ_exact(x)*I_tensor +crossB(u,v,dΩ) = ∫(cross(u,B)⋅v)dΩ +graddiv(u,v,dΩ) = ∫((∇⋅u)⋅(∇⋅v))*dΩ +function a((u,p,j,φ),(v,q,d,ψ),dΩ) + c = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ + c = c + ∫(j⋅d + (∇⋅d)*φ - (∇⋅j)*ψ)dΩ + c = c - crossB(u,d,dΩ) - crossB(j,v,dΩ) + if α > 0.0 + c += graddiv(u,v,dΩ) + graddiv(j,d,dΩ) + end + return c +end +l((v,q,d,ψ),dΩ,dΓ) = ∫(v⋅f + d⋅g)dΩ + ∫(v⋅(σ⋅n) + d⋅(γ⋅n))dΓ + +ah(x,y) = a(x,y,dΩh) +aH(x,y) = a(x,y,dΩH) +lh(y) = l(y,dΩh,dΓh) + +op_h = AffineFEOperator(ah,lh,Xh,Yh) +Ah = get_matrix(op_h) +bh = get_vector(op_h) +xh_exact = Ah\bh + +AH = assemble_matrix(aH,XH,YH) +Mhh = assemble_matrix((u,v)->∫(u⋅v)*dΩh,Xh,Xh) + +uh_exact, ph_exact, jh_exact, φh_exact = FEFunction(Xh,xh_exact) +l2_error(uh_exact,u_exact,dΩh) +l2_error(ph_exact,p_exact,dΩh) +l2_error(jh_exact,j_exact,dΩh) +l2_error(φh_exact,φ_exact,dΩh) +l2_norm(∇⋅uh_exact,dΩh) +l2_norm(∇⋅jh_exact,dΩh) + +PD = PatchDecomposition(model) +smoother = RichardsonSmoother(VankaSolver(Xh,PD),10,0.05) +smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) + +function project_f2c(rh) + Qrh = Mhh\rh + uh, ph, jh, φh = FEFunction(Yh,Qrh) + ll((v,q,d,ψ)) = ∫(v⋅uh + q*ph + d⋅jh + ψ⋅φh)*dΩHh + assemble_vector(ll,YH) +end +function interp_c2f(xH) + get_free_dof_values(interpolate(FEFunction(YH,xH),Yh)) +end + +xh = randn(size(Ah,2)) +rh = bh - Ah*xh +niters = 10 + +iter = 0 +error0 = norm(rh) +error = error0 +e_rel = error/error0 +while iter < niters && e_rel > 1.0e-10 + println("Iter $iter:") + println(" > Initial: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + println(" > Pre-smoother: ", norm(rh)) + + rH = project_f2c(rh) + qH = AH\rH + qh = interp_c2f(qH) + + rh = rh - Ah*qh + xh = xh + qh + println(" > Post-correction: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + + iter += 1 + error = norm(rh) + e_rel = error/error0 + println(" > Final: ",error, " - ", e_rel) +end + +uh, ph, jh, φh = FEFunction(Xh,xh) +l2_error(uh,u_exact,dΩh) +l2_error(ph,p_exact,dΩh) +l2_error(jh,j_exact,dΩh) +l2_error(φh,φ_exact,dΩh) diff --git a/test/_dev/Vanka/stokes_vanka_GMG.jl b/test/_dev/Vanka/stokes_vanka_GMG.jl index 23cbc972..63a4eea6 100644 --- a/test/_dev/Vanka/stokes_vanka_GMG.jl +++ b/test/_dev/Vanka/stokes_vanka_GMG.jl @@ -52,10 +52,18 @@ dΩHh = Measure(ΩH,Ωh,qdegree) dΓh = Measure(Γh,qdegree) n = get_normal_vector(Γh) +α = 10.0 I_tensor = one(TensorValue{Dc,Dc,Float64}) f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor -a((u,p),(v,q),dΩ) = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ +graddiv(u,v,dΩ) = ∫((∇⋅u)⋅(∇⋅v))*dΩ +function a((u,p),(v,q),dΩ) + c = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ + if α > 0.0 + c += graddiv(u,v,dΩ) + end + return c +end l((v,q),dΩ,dΓ) = ∫(v⋅f)dΩ + ∫(v⋅(σ⋅n) )dΓ ah(x,y) = a(x,y,dΩh) @@ -76,7 +84,7 @@ l2_error(ph_exact,p_exact,dΩh) l2_norm(∇⋅uh_exact,dΩh) PD = PatchDecomposition(model) -smoother = RichardsonSmoother(VankaSolver(Xh,PD),5,0.2) +smoother = RichardsonSmoother(VankaSolver(Xh,PD),10,0.2) smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) function project_f2c(rh) @@ -123,3 +131,6 @@ end uh, ph = FEFunction(Xh,xh) l2_error(uh,u_exact,dΩh) l2_error(ph,p_exact,dΩh) + +# Note: This converges, but I'm quite convinced we would need a patch-based +# prolongation operator (right?) diff --git a/test/_dev/Vanka/stokesdarcy_vanka_GMG.jl b/test/_dev/Vanka/stokesdarcy_vanka_GMG.jl new file mode 100644 index 00000000..2a1aa183 --- /dev/null +++ b/test/_dev/Vanka/stokesdarcy_vanka_GMG.jl @@ -0,0 +1,172 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra, Gridap.Arrays, Gridap.Adaptivity +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +function add_labels_2d(model) + labels = get_face_labeling(model) + add_tag_from_tags!(labels,"newman",[5]) + add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) +end + +function add_labels_3d(model) + labels = get_face_labeling(model) + add_tag_from_tags!(labels,"newman",[21]) + add_tag_from_tags!(labels,"dirichlet",[collect(1:20)...,22,23,24,25,26]) +end + +B = VectorValue(0.0,0.0,1.0) +u_exact(x) = VectorValue(x[1],-x[2],0.0) +p_exact(x) = sum(x) +j_exact(x) = VectorValue(-x[2],-x[1],0.0) + VectorValue(1.0,1.0,0.0) +φ_exact(x) = x[1] + x[2] + +Dc = 3 +domain = (Dc == 2) ? (0,1,0,1) : (0,1,0,1,0,1) +ncells = (Dc == 2) ? (4,4) : (2,2,2) +cmodel = CartesianDiscreteModel(domain,ncells) +if Dc == 2 + add_labels_2d(cmodel) +else + add_labels_3d(cmodel) +end +model = refine(cmodel,2) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{Dc,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) +reffe_j = ReferenceFE(raviart_thomas,Float64,order-1) +reffe_φ = ReferenceFE(lagrangian,Float64,order-1) + +VH = TestFESpace(cmodel,reffe_u;dirichlet_tags="dirichlet") +UH = TrialFESpace(VH,u_exact) +QH = TestFESpace(cmodel,reffe_p,conformity=:L2) +DH = TestFESpace(cmodel,reffe_j;dirichlet_tags="dirichlet") +JH = TrialFESpace(DH,j_exact) +ΦH = TestFESpace(cmodel,reffe_φ,conformity=:L2) + +XH = MultiFieldFESpace([UH,QH,JH,ΦH]) +YH = MultiFieldFESpace([VH,QH,DH,ΦH]) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) +Qh = TestFESpace(model,reffe_p,conformity=:L2) +Dh = TestFESpace(model,reffe_j;dirichlet_tags="dirichlet") +Jh = TrialFESpace(Dh,j_exact) +Φh = TestFESpace(model,reffe_φ,conformity=:L2) +Xh = MultiFieldFESpace([Uh,Qh,Jh,Φh]) +Yh = MultiFieldFESpace([Vh,Qh,Dh,Φh]) + +qdegree = 2*order +Ωh = Triangulation(model) +dΩh = Measure(Ωh,qdegree) +ΩH = Triangulation(cmodel) +dΩH = Measure(ΩH,qdegree) +dΩHh = Measure(ΩH,Ωh,qdegree) + +Γh = BoundaryTriangulation(model,tags="newman") +dΓh = Measure(Γh,qdegree) +n = get_normal_vector(Γh) + +α = -1.0 +I_tensor = one(TensorValue{Dc,Dc,Float64}) +f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) #- cross(j_exact(x),B) +g(x) = j_exact(x) - ∇(φ_exact)(x) #- cross(u_exact(x),B) +σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor +γ(x) = φ_exact(x)*I_tensor +crossB(u,v,dΩ) = ∫(cross(u,B)⋅v)dΩ +graddiv(u,v,dΩ) = ∫((∇⋅u)⋅(∇⋅v))*dΩ +function a((u,p,j,φ),(v,q,d,ψ),dΩ) + c = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ + c = c + ∫(j⋅d + (∇⋅d)*φ - (∇⋅j)*ψ)dΩ +# c = c - crossB(u,d,dΩ) - crossB(j,v,dΩ) + if α > 0.0 + c += graddiv(u,v,dΩ) + graddiv(j,d,dΩ) + end + return c +end +l((v,q,d,ψ),dΩ,dΓ) = ∫(v⋅f + d⋅g)dΩ + ∫(v⋅(σ⋅n) + d⋅(γ⋅n))dΓ + +ah(x,y) = a(x,y,dΩh) +aH(x,y) = a(x,y,dΩH) +lh(y) = l(y,dΩh,dΓh) + +op_h = AffineFEOperator(ah,lh,Xh,Yh) +Ah = get_matrix(op_h) +bh = get_vector(op_h) +xh_exact = Ah\bh + +AH = assemble_matrix(aH,XH,YH) +Mhh = assemble_matrix((u,v)->∫(u⋅v)*dΩh,Xh,Xh) + +uh_exact, ph_exact, jh_exact, φh_exact = FEFunction(Xh,xh_exact) +l2_error(uh_exact,u_exact,dΩh) +l2_error(ph_exact,p_exact,dΩh) +l2_error(jh_exact,j_exact,dΩh) +l2_error(φh_exact,φ_exact,dΩh) +l2_norm(∇⋅uh_exact,dΩh) +l2_norm(∇⋅jh_exact,dΩh) + +PD = PatchDecomposition(model) +smoother = RichardsonSmoother(VankaSolver(Xh,PD),10,0.05) +smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) + +function project_f2c(rh) + Qrh = Mhh\rh + uh, ph, jh, φh = FEFunction(Yh,Qrh) + ll((v,q,d,ψ)) = ∫(v⋅uh + q*ph + d⋅jh + ψ⋅φh)*dΩHh + assemble_vector(ll,YH) +end +function interp_c2f(xH) + get_free_dof_values(interpolate(FEFunction(YH,xH),Yh)) +end + +xh = randn(size(Ah,2)) +rh = bh - Ah*xh +niters = 10 + +iter = 0 +error0 = norm(rh) +error = error0 +e_rel = error/error0 +while iter < niters && e_rel > 1.0e-10 + println("Iter $iter:") + println(" > Initial: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + println(" > Pre-smoother: ", norm(rh)) + + rH = project_f2c(rh) + qH = AH\rH + qh = interp_c2f(qH) + + rh = rh - Ah*qh + xh = xh + qh + println(" > Post-correction: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + + iter += 1 + error = norm(rh) + e_rel = error/error0 + println(" > Final: ",error, " - ", e_rel) +end + +uh, ph, jh, φh = FEFunction(Xh,xh) +l2_error(uh,u_exact,dΩh) +l2_error(ph,p_exact,dΩh) +l2_error(jh,j_exact,dΩh) +l2_error(φh,φ_exact,dΩh) From 56e9821b977bc651d9e40d4cf4d43d404dedf7d1 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 29 Aug 2024 10:06:05 +1000 Subject: [PATCH 03/47] GMG working in serial --- src/LinearSolvers/GMGLinearSolvers.jl | 4 +- .../DistributedGridTransferOperators.jl | 25 +- src/MultilevelTools/FESpaceHierarchies.jl | 10 + src/MultilevelTools/ModelHierarchies.jl | 38 +++ .../PatchBasedSmoothers.jl | 1 + .../seq/CoarsePatchDecompositions.jl | 63 +++++ test/_dev/MacroFEs/riesz_GMG.jl | 201 ++++++++++++++++ .../MultilevelTools/SerialModelHierarchies.jl | 61 +++++ .../PatchBased/CoarsePatchDecompositions.jl | 16 ++ test/_dev/Vanka/mhd_uj_vanka_GMG.jl | 223 ++++++++++++++++++ test/_dev/Vanka/mhd_vanka_GMG.jl | 9 +- test/_dev/Vanka/stokes_vanka_GMG.jl | 77 +++++- 12 files changed, 706 insertions(+), 22 deletions(-) create mode 100644 src/PatchBasedSmoothers/seq/CoarsePatchDecompositions.jl create mode 100644 test/_dev/MacroFEs/riesz_GMG.jl create mode 100644 test/_dev/MultilevelTools/SerialModelHierarchies.jl create mode 100644 test/_dev/PatchBased/CoarsePatchDecompositions.jl create mode 100644 test/_dev/Vanka/mhd_uj_vanka_GMG.jl diff --git a/src/LinearSolvers/GMGLinearSolvers.jl b/src/LinearSolvers/GMGLinearSolvers.jl index cfdf9502..b564e48b 100644 --- a/src/LinearSolvers/GMGLinearSolvers.jl +++ b/src/LinearSolvers/GMGLinearSolvers.jl @@ -415,7 +415,9 @@ function gmg_work_vectors(smatrices::AbstractVector{<:AbstractMatrix}) return work_vectors end -function apply_GMG_level!(lev::Integer,xh::Union{PVector,Nothing},rh::Union{PVector,Nothing},ns::GMGNumericalSetup) +function apply_GMG_level!( + lev::Integer,xh::Union{<:AbstractVector,Nothing},rh::Union{<:AbstractVector,Nothing},ns::GMGNumericalSetup +) mh = ns.solver.mh parts = get_level_parts(mh,lev) if i_am_in(parts) diff --git a/src/MultilevelTools/DistributedGridTransferOperators.jl b/src/MultilevelTools/DistributedGridTransferOperators.jl index 7d1f0936..5c8ba901 100644 --- a/src/MultilevelTools/DistributedGridTransferOperators.jl +++ b/src/MultilevelTools/DistributedGridTransferOperators.jl @@ -65,11 +65,11 @@ function _get_interpolation_cache(lev::Int,sh::FESpaceHierarchy,qdegree::Int,mod if i_am_in(cparts) model_h = get_model_before_redist(sh,lev) Uh = get_fe_space_before_redist(sh,lev) - fv_h = pfill(0.0,partition(Uh.gids)) + fv_h = zero_free_values(Uh) dv_h = (mode == :solution) ? get_dirichlet_dof_values(Uh) : zero_dirichlet_values(Uh) UH = get_fe_space(sh,lev+1) - fv_H = pfill(0.0,partition(UH.gids)) + fv_H = zero_free_values(UH) dv_H = (mode == :solution) ? get_dirichlet_dof_values(UH) : zero_dirichlet_values(UH) cache_refine = model_h, Uh, fv_h, dv_h, UH, fv_H, dv_H @@ -222,7 +222,7 @@ end ### Applying the operators: # A) Prolongation, without redistribution -function LinearAlgebra.mul!(y::PVector,A::DistributedGridTransferOperator{Val{:prolongation},Val{false}},x::PVector) +function LinearAlgebra.mul!(y::AbstractVector,A::DistributedGridTransferOperator{Val{:prolongation},Val{false}},x::AbstractVector) cache_refine, cache_redist = A.cache model_h, Uh, fv_h, dv_h, UH, fv_H, dv_H = cache_refine @@ -235,7 +235,7 @@ function LinearAlgebra.mul!(y::PVector,A::DistributedGridTransferOperator{Val{:p end # B.1) Restriction, without redistribution, by interpolation -function LinearAlgebra.mul!(y::PVector,A::DistributedGridTransferOperator{Val{:restriction},Val{false},Val{:interpolation}},x::PVector) +function LinearAlgebra.mul!(y::AbstractVector,A::DistributedGridTransferOperator{Val{:restriction},Val{false},Val{:interpolation}},x::AbstractVector) cache_refine, cache_redist = A.cache model_h, Uh, fv_h, dv_h, UH, fv_H, dv_H = cache_refine @@ -248,7 +248,7 @@ function LinearAlgebra.mul!(y::PVector,A::DistributedGridTransferOperator{Val{:r end # B.2) Restriction, without redistribution, by projection -function LinearAlgebra.mul!(y::PVector,A::DistributedGridTransferOperator{Val{:restriction},Val{false},Val{:projection}},x::PVector) +function LinearAlgebra.mul!(y::AbstractVector,A::DistributedGridTransferOperator{Val{:restriction},Val{false},Val{:projection}},x::AbstractVector) cache_refine, cache_redist = A.cache model_h, Uh, fv_h, dv_h, VH, AH_ns, lH, xH, bH, bH0, assem = cache_refine @@ -265,7 +265,7 @@ function LinearAlgebra.mul!(y::PVector,A::DistributedGridTransferOperator{Val{:r end # B.3) Restriction, without redistribution, by dof selection (only nodal dofs) -function LinearAlgebra.mul!(y::PVector,A::DistributedGridTransferOperator{Val{:restriction},Val{false},Val{:dof_mask}},x::PVector) +function LinearAlgebra.mul!(y::AbstractVector,A::DistributedGridTransferOperator{Val{:restriction},Val{false},Val{:dof_mask}},x::AbstractVector) cache_refine, cache_redist = A.cache model_h, Uh, fv_h, dv_h, UH, fv_H, dv_H = cache_refine @@ -367,6 +367,19 @@ end ############################################################### +function LinearAlgebra.mul!(y::AbstractVector,A::DistributedGridTransferOperator{Val{:restriction},Val{false},Val{:dual_projection}},x::AbstractVector) + cache_refine, cache_redist = A.cache + model_h, Uh, VH, Mh_ns, rh, uh, assem, dΩhH = cache_refine + fv_h = get_free_dof_values(uh) + + solve!(rh,Mh_ns,x) + copy!(fv_h,rh) + v = get_fe_basis(VH) + assemble_vector!(y,assem,collect_cell_vector(VH,∫(v⋅uh)*dΩhH)) + + return y +end + function LinearAlgebra.mul!(y::PVector,A::DistributedGridTransferOperator{Val{:restriction},Val{false},Val{:dual_projection}},x::PVector) cache_refine, cache_redist = A.cache model_h, Uh, VH, Mh_ns, rh, uh, assem, dΩhH = cache_refine diff --git a/src/MultilevelTools/FESpaceHierarchies.jl b/src/MultilevelTools/FESpaceHierarchies.jl index 9f4cd05e..cd7025a3 100644 --- a/src/MultilevelTools/FESpaceHierarchies.jl +++ b/src/MultilevelTools/FESpaceHierarchies.jl @@ -56,6 +56,16 @@ function _cell_conformity( return CellConformity(cell_reffe,conformity) end +function _cell_conformity( + model::DiscreteModel, + reffe::ReferenceFE; + conformity=nothing, kwargs... +) :: CellConformity + cell_reffe = Fill(reffe,num_cells(model)) + conformity = Conformity(Gridap.Arrays.testitem(cell_reffe),conformity) + return CellConformity(cell_reffe,conformity) +end + function _cell_conformity( model::GridapDistributed.DistributedDiscreteModel,args...;kwargs... ) :: AbstractVector{<:CellConformity} diff --git a/src/MultilevelTools/ModelHierarchies.jl b/src/MultilevelTools/ModelHierarchies.jl index 77654e46..ef825939 100644 --- a/src/MultilevelTools/ModelHierarchies.jl +++ b/src/MultilevelTools/ModelHierarchies.jl @@ -139,6 +139,44 @@ function CartesianModelHierarchy( return HierarchicalArray(meshes,level_parts) end +function ModelHierarchy(models::Vector{<:DiscreteModel}) + nlevs = length(models) + @check all(map(i -> isa(models[i],AdaptedDiscreteModel),1:nlevs-1)) "Hierarchy models are not adapted models." + for lev in 1:nlevs-1 + @check Adaptivity.is_child(models[lev],models[lev+1]) "Incorrect hierarchy of models." + end + + level_parts = fill(DebugArray([1]),nlevs) + meshes = Vector{ModelHierarchyLevel}(undef,nlevs) + for lev in 1:nlevs-1 + glue = Gridap.Adaptivity.get_adaptivity_glue(models[lev]) + model = models[lev] + meshes[lev] = ModelHierarchyLevel(lev,model,glue,nothing,nothing) + end + meshes[nlevs] = ModelHierarchyLevel(nlevs,models[nlevs],nothing,nothing,nothing) + return HierarchicalArray(meshes,level_parts) +end + +function ModelHierarchy(models::Vector{<:GridapDistributed.DistributedDiscreteModel}) + nlevs = length(models) + @check all(map(i -> isa(models[i],GridapDistributed.DistributedAdaptedDiscreteModel),1:nlevs-1)) "Hierarchy models are not adapted models." + for lev in 1:nlevs-1 + @check Adaptivity.is_child(models[lev],models[lev+1]) "Incorrect hierarchy of models." + end + ranks = get_parts(models[1]) + @check all(m -> get_parts(m) === ranks, models) "Models have different communicators." + + level_parts = fill(ranks,nlevs) + meshes = Vector{ModelHierarchyLevel}(undef,nlevs) + for lev in 1:nlevs-1 + glue = Gridap.Adaptivity.get_adaptivity_glue(models[lev]) + model = models[lev] + meshes[lev] = ModelHierarchyLevel(lev,model,glue,nothing,nothing) + end + meshes[nlevs] = ModelHierarchyLevel(nlevs,models[nlevs],nothing,nothing,nothing) + return HierarchicalArray(meshes,level_parts) +end + """ P4estCartesianModelHierarchy( ranks,np_per_level,domain,nc::NTuple{D,<:Integer}; diff --git a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl index d836dcfd..d8f6733d 100644 --- a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl +++ b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl @@ -22,6 +22,7 @@ export setup_patch_prolongation_operators, setup_patch_restriction_operators include("seq/PatchDecompositions.jl") include("mpi/PatchDecompositions.jl") include("seq/PatchTriangulations.jl") +include("seq/CoarsePatchDecompositions.jl") # FESpaces include("seq/PatchFESpaces.jl") diff --git a/src/PatchBasedSmoothers/seq/CoarsePatchDecompositions.jl b/src/PatchBasedSmoothers/seq/CoarsePatchDecompositions.jl new file mode 100644 index 00000000..d62bfbb6 --- /dev/null +++ b/src/PatchBasedSmoothers/seq/CoarsePatchDecompositions.jl @@ -0,0 +1,63 @@ + +# PatchDecomposition where each patch is given by a coarse cell on the parent mesh +function CoarsePatchDecomposition( + model::Gridap.Adaptivity.AdaptedDiscreteModel{Dc,Dp}, + patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude(), + boundary_tag_names::AbstractArray{String}=["boundary"] +) where {Dc,Dp} + glue = Gridap.Adaptivity.get_adaptivity_glue(model) + + patch_cells = glue.o2n_faces_map + patch_cells_overlapped = compute_patch_overlapped_cells(patch_cells) + patch_facets = get_coarse_patch_facets(model, patch_cells) + patch_cells_faces_on_boundary = compute_patch_cells_faces_on_boundary( + model, patch_cells, patch_cells_overlapped, + patch_facets, patch_boundary_style, boundary_tag_names + ) + + return PatchDecomposition{Dc,Dc,Dp}( + model, patch_cells, patch_cells_overlapped, patch_cells_faces_on_boundary + ) +end + +function get_coarse_patch_facets( + model::Gridap.Adaptivity.AdaptedDiscreteModel{Dc,Dp},patch_cells +) where {Dc,Dp} + topo = get_grid_topology(model) + c2f_map = Geometry.get_faces(topo,Dc,Dc-1) + f2c_map = Geometry.get_faces(topo,Dc-1,Dc) + + touched = fill(false,num_faces(topo,Dc-1)) + ptrs = fill(0,length(patch_cells)+1) + for (patch,cells) in enumerate(patch_cells) + for c in cells + for f in c2f_map[c] + nbors = f2c_map[f] + if !touched[f] && (length(nbors) == 2) && all(n -> n ∈ cells, nbors) + touched[f] = true + ptrs[patch+1] += 1 + end + end + end + end + Arrays.length_to_ptrs!(ptrs) + + data = fill(0,ptrs[end]-1) + fill!(touched,false) + for (patch,cells) in enumerate(patch_cells) + for c in cells + for f in c2f_map[c] + nbors = f2c_map[f] + if !touched[f] && (length(nbors) == 2) && all(n -> n ∈ cells, nbors) + touched[f] = true + data[ptrs[patch]] = f + ptrs[patch] += 1 + end + end + end + end + Arrays.rewind_ptrs!(ptrs) + + patch_facets = Table(data,ptrs) + return patch_facets +end diff --git a/test/_dev/MacroFEs/riesz_GMG.jl b/test/_dev/MacroFEs/riesz_GMG.jl new file mode 100644 index 00000000..2a00e7f9 --- /dev/null +++ b/test/_dev/MacroFEs/riesz_GMG.jl @@ -0,0 +1,201 @@ +using Gridap +using GridapSolvers +using LinearAlgebra +using FillArrays + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra, Gridap.Arrays, Gridap.Adaptivity +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +function mock_model() + coords = [VectorValue(0.0,0.0),VectorValue(1.0,0.0),VectorValue(0.5,sqrt(3.0)/2.0)] + polys = [TRI] + cell_types = Int8[1] + conn = Table([[1,2,3]]) + reffes = map(x->LagrangianRefFE(Float64,x,1),polys) + + ref_grid = UnstructuredGrid(coords,conn,reffes,cell_types;has_affine_map=true) + model = UnstructuredDiscreteModel(ref_grid) + + labels = get_face_labeling(model) + labels.d_to_dface_to_entity[1] .= [1,2,3] + labels.d_to_dface_to_entity[2] .= [4,5,6] + labels.d_to_dface_to_entity[3] .= [7] + for i in 1:7 + push!(labels.tag_to_entities,Int32[i]) + push!(labels.tag_to_name,"tag_$(i)") + end + push!(labels.tag_to_entities,Int32[1,2,3,4,5,6]) + push!(labels.tag_to_name,"boundary") + push!(labels.tag_to_entities,Int32[7]) + push!(labels.tag_to_name,"interior") + + return model +end + +u_exact(x) = VectorValue(-x[1],x[2]) + +Dc = 2 +#cmodel = simplexify(CartesianDiscreteModel((0,1,0,1),(2,2))) +cmodel = refine(mock_model()).model + +labels = get_face_labeling(cmodel) +#add_tag_from_tags!(labels,"newman",[5]) +#add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) +add_tag_from_tags!(labels,"dirichlet",[collect(1:3)...,4,5]) +add_tag_from_tags!(labels,"newman",[6]) +model = refine(cmodel) + +order = 2 +rrule = Adaptivity.BarycentricRefinementRule(TRI) +reffes = Fill(LagrangianRefFE(VectorValue{2,Float64},TRI,order),Adaptivity.num_subcells(rrule)) +reffe_u = Adaptivity.MacroReferenceFE(rrule,reffes) + +VH = TestFESpace(cmodel,reffe_u;dirichlet_tags="dirichlet") +UH = TrialFESpace(VH,u_exact) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) + +qdegree = 2*order +quad = Quadrature(rrule,qdegree) +Ωh = Triangulation(model) +dΩh = Measure(Ωh,quad) +ΩH = Triangulation(cmodel) +dΩH = Measure(ΩH,quad) +dΩHh = Measure(ΩH,Ωh,quad) + +Γh = Boundary(model.model) +dΓh = Measure(Γh,4*order) +nh = get_normal_vector(Γh) + +ν = 1.e-2 +α = 10.0 +f(x) = -ν*Δ(u_exact)(x) +graddiv(u,v,dΩ) = ∫(α*(∇⋅u)⋅(∇⋅v))*dΩ +function a(u,v,dΩ) + c = ∫(ν*∇(u)⊙∇(v))*dΩ + if α > 0.0 + c += graddiv(u,v,dΩ) + end + return c +end +l(v,dΩ) = ∫(v⋅f)dΩ + +∇u_exact(x) = ∇(u_exact)(x) +ah(x,y) = a(x,y,dΩh) +aH(x,y) = a(x,y,dΩH) +lh(v) = l(v,dΩh) + ∫(ν*v⋅(∇u_exact⋅nh))dΓh + +op_h = AffineFEOperator(ah,lh,Uh,Vh) +Ah = get_matrix(op_h) +bh = get_vector(op_h) +xh_exact = Ah\bh + +AH = assemble_matrix(aH,UH,VH) +Mhh = assemble_matrix((u,v)->∫(u⋅v)*dΩh,Uh,Vh) + +uh_exact = FEFunction(Uh,xh_exact) +l2_error(uh_exact,u_exact,dΩh) +l2_norm(∇⋅uh_exact,dΩh) + +topo = get_grid_topology(model) +patches_mask = get_isboundary_face(topo,0) +PD = PatchDecomposition(model) +Ph = PatchFESpace(Vh,PD,reffe_u;conformity=H1Conformity())#,patches_mask) +Ωp = Triangulation(PD) +dΩp = Measure(Ωp,qdegree) +ap(x,y) = a(x,y,dΩp) +smoother = RichardsonSmoother(PatchBasedLinearSolver(ap,Ph,Vh),20,0.01) +smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) + +function project_f2c(rh) + Qrh = Mhh\rh + uh = FEFunction(Vh,Qrh) + ll(v) = ∫(v⋅uh)*dΩHh + assemble_vector(ll,VH) +end +function interp_c2f(xH) + get_free_dof_values(interpolate(FEFunction(VH,xH),Vh)) +end + +PDi = PatchBasedSmoothers.CoarsePatchDecomposition(model) +Ih = PatchFESpace(Vh,PDi,reffe_u;conformity=H1Conformity()) + +Ωpi = Triangulation(PDi) +dΩpi = Measure(Ωpi,qdegree) +api(x,y) = a(x,y,dΩpi) +Ai = assemble_matrix(api,Ih,Ih) + +function P1(dxH) + interp_c2f(dxH) +end +function R1(rh) + project_f2c(rh) +end + +function P2(dxH) + dxh = interp_c2f(dxH) + uh = FEFunction(Vh,dxh) + r̃h = assemble_vector(v -> graddiv(uh,v,dΩpi),Ih) + dx̃ = Ai\r̃h + Pdxh = fill(0.0,length(dxh)) + PatchBasedSmoothers.inject!(Pdxh,Ih,dx̃) + y = dxh - Pdxh + return y +end +function R2(rh) + r̃h = zero_free_values(Ih) + PatchBasedSmoothers.prolongate!(r̃h,Ih,rh) + dr̃h = Ai\r̃h + dxh = zero_free_values(Vh) + PatchBasedSmoothers.inject!(dxh,Ih,dr̃h) + drh = assemble_vector(v -> graddiv(FEFunction(Vh,dxh),v,dΩh),Vh) + rH = project_f2c(rh - drh) + return rH +end + + +xh = randn(size(Ah,2)) +rh = bh - Ah*xh +niters = 5 + +iter = 0 +error0 = norm(rh) +error = error0 +e_rel = error/error0 +while iter < niters && e_rel > 1.0e-8 + println("Iter $iter:") + println(" > Initial: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + println(" > Pre-smoother: ", norm(rh)) + + rH = R2(rh) + qH = AH\rH + qh = P2(qH) + + rh = rh - Ah*qh + xh = xh + qh + println(" > Post-correction: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + + iter += 1 + error = norm(rh) + e_rel = error/error0 + println(" > Final: ",error, " - ", e_rel) +end + +uh = FEFunction(Xh,xh) +l2_error(uh,u_exact,dΩh) +l2_norm(∇⋅uh,dΩh) diff --git a/test/_dev/MultilevelTools/SerialModelHierarchies.jl b/test/_dev/MultilevelTools/SerialModelHierarchies.jl new file mode 100644 index 00000000..3febf2a7 --- /dev/null +++ b/test/_dev/MultilevelTools/SerialModelHierarchies.jl @@ -0,0 +1,61 @@ +using Gridap +using GridapDistributed, PartitionedArrays +using GridapSolvers + +using Gridap.MultiField, Gridap.Adaptivity +using GridapSolvers.LinearSolvers, GridapSolvers.MultilevelTools, GridapSolvers.PatchBasedSmoothers + +function get_bilinear_form(mh_lev,biform,qdegree) + model = GridapSolvers.get_model(mh_lev) + Ω = Triangulation(model) + dΩ = Measure(Ω,qdegree) + return (u,v) -> biform(u,v,dΩ) +end + +cmodel = CartesianDiscreteModel((0,1,0,1),(10,10)) +fmodel = refine(cmodel,2) +mh = ModelHierarchy([fmodel,cmodel]) + +order = 1 +reffe = ReferenceFE(lagrangian,Float64,order) +sh = FESpace(mh,reffe;dirichlet_tags="boundary") + +qdegree = 2*(order+1) +biform(u,v,dΩ) = ∫(∇(u)⋅∇(v))dΩ + +biforms = map(mhl -> get_bilinear_form(mhl,biform,qdegree),mh) + +smoothers = [RichardsonSmoother(JacobiLinearSolver(),10,0.2)] +prolongations = setup_prolongation_operators( + sh,qdegree;mode=:residual +) +restrictions = setup_restriction_operators( + sh,qdegree;mode=:residual +) + +gmg = GMGLinearSolver( + mh,sh,sh,biforms, + prolongations,restrictions, + pre_smoothers=smoothers, + post_smoothers=smoothers, + coarsest_solver=LUSolver(), + maxiter=3,mode=:preconditioner,verbose=true +) + +solver = CGSolver(gmg;verbose=true) + +# Finest level +model = GridapSolvers.get_model(mh,1) +Ω = Triangulation(model) +dΩ = Measure(Ω,qdegree) +V = get_fe_space(sh,1) +a(u,v) = biform(u,v,dΩ) +l(v) = ∫(v)dΩ + +op = AffineFEOperator(a,l,V,V) +A, b = get_matrix(op), get_vector(op) + +ns = numerical_setup(symbolic_setup(solver,A),A) + +x = zeros(size(b)) +solve!(x,ns,b) diff --git a/test/_dev/PatchBased/CoarsePatchDecompositions.jl b/test/_dev/PatchBased/CoarsePatchDecompositions.jl new file mode 100644 index 00000000..c8b4abaf --- /dev/null +++ b/test/_dev/PatchBased/CoarsePatchDecompositions.jl @@ -0,0 +1,16 @@ +using Gridap +using Gridap.Geometry, Gridap.Arrays + +using GridapSolvers +using GridapSolvers: PatchBasedSmoothers + +cmodel = CartesianDiscreteModel((0,1,0,1),(2,2)) +model = Gridap.Adaptivity.refine(cmodel) + +glue = Gridap.Adaptivity.get_adaptivity_glue(model) + +PD = PatchBasedSmoothers.CoarsePatchDecomposition(model) + +reffe = ReferenceFE(lagrangian,Float64,2) +Vh = FESpace(model,reffe) +Ph = PatchFESpace(Vh,PD,reffe) diff --git a/test/_dev/Vanka/mhd_uj_vanka_GMG.jl b/test/_dev/Vanka/mhd_uj_vanka_GMG.jl new file mode 100644 index 00000000..7a1569f8 --- /dev/null +++ b/test/_dev/Vanka/mhd_uj_vanka_GMG.jl @@ -0,0 +1,223 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra, Gridap.Arrays, Gridap.Adaptivity +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers + +function l2_norm(uh,dΩ) + sqrt(sum(∫(uh⋅uh)dΩ)) +end + +function l2_error(uh,u_exact,dΩ) + eh = uh - u_exact + return sqrt(sum(∫(eh⋅eh)dΩ)) +end + +function add_labels_2d(model) + labels = get_face_labeling(model) + add_tag_from_tags!(labels,"newman",[5]) + add_tag_from_tags!(labels,"dirichlet",[collect(1:4)...,6,7,8]) +end + +function add_labels_3d(model) + labels = get_face_labeling(model) + add_tag_from_tags!(labels,"newman",[21]) + add_tag_from_tags!(labels,"dirichlet",[collect(1:20)...,22,23,24,25,26]) +end + +B = VectorValue(0.0,0.0,1.0) +u_exact(x) = VectorValue(x[1],-x[2],0.0) +p_exact(x) = sum(x) +j_exact(x) = VectorValue(-x[2],-x[1],0.0) + VectorValue(1.0,1.0,0.0) +φ_exact(x) = x[1] + x[2] + +Dc = 3 +domain = (Dc == 2) ? (0,1,0,1) : (0,1,0,1,0,1) +ncells = (Dc == 2) ? (4,4) : (2,2,2) +cmodel = CartesianDiscreteModel(domain,ncells) +if Dc == 2 + add_labels_2d(cmodel) +else + add_labels_3d(cmodel) +end +model = refine(cmodel,2) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{Dc,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) +reffe_j = ReferenceFE(raviart_thomas,Float64,order-1) +reffe_φ = ReferenceFE(lagrangian,Float64,order-1) + +using Badia2024 +using SpecialPolynomials +using Polynomials +reffe_j = Badia2024.SpecialRTReffe(ChebyshevT,order,Dc) + +VH = TestFESpace(cmodel,reffe_u;dirichlet_tags="dirichlet") +UH = TrialFESpace(VH,u_exact) +DH = TestFESpace(cmodel,reffe_j;dirichlet_tags="dirichlet") +JH = TrialFESpace(DH,j_exact) +XH = MultiFieldFESpace([UH,JH]) +YH = MultiFieldFESpace([VH,DH]) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="dirichlet") +Uh = TrialFESpace(Vh,u_exact) +Dh = TestFESpace(model,reffe_j;dirichlet_tags="dirichlet") +Jh = TrialFESpace(Dh,j_exact) +Xh = MultiFieldFESpace([Uh,Jh]) +Yh = MultiFieldFESpace([Vh,Dh]) + +qdegree = 2*order +Ωh = Triangulation(model) +dΩh = Measure(Ωh,qdegree) +ΩH = Triangulation(cmodel) +dΩH = Measure(ΩH,qdegree) +dΩHh = Measure(ΩH,Ωh,qdegree) + +Γh = BoundaryTriangulation(model,tags="newman") +dΓh = Measure(Γh,qdegree) +n = get_normal_vector(Γh) + +ν = 1.e-8 +α = 1.0 +f(x) = -(-Δ(u_exact)(x) - cross(j_exact(x),B)) +g(x) = j_exact(x) - cross(u_exact(x),B) +σ(x) = ∇(u_exact)(x) + +crossB(u,v,dΩ) = ∫(cross(u,B)⋅v)dΩ +Π = GridapSolvers.MultilevelTools.LocalProjectionMap(divergence,reffe_p,qdegree) +Πgraddiv(u,v,dΩ) = ∫(α*Π(u)⋅(∇⋅v))*dΩ +graddiv(u,v,dΩ) = ∫(α*(∇⋅u)⋅(∇⋅v))*dΩ +function a((u,j),(v,d),dΩ) + c = ∫((-ν)*∇(u)⊙∇(v) + j⋅d)dΩ + c = c - crossB(u,d,dΩ) + crossB(j,v,dΩ) + if α > 0.0 + c += Πgraddiv(u,v,dΩ) #+ graddiv(j,d,dΩ) + end + return c +end +function a_u(u,v,dΩ) + c = ∫(ν*∇(u)⊙∇(v))*dΩ + if α > 0.0 + c += Πgraddiv(u,v,dΩ) + end + return c +end +l((v,d),dΩ,dΓ) = ∫(v⋅f + d⋅g)dΩ + ∫(v⋅(σ⋅n))dΓ + +ah(x,y) = a(x,y,dΩh) +aH(x,y) = a(x,y,dΩH) +lh(y) = l(y,dΩh,dΓh) + +op_h = AffineFEOperator(ah,lh,Xh,Yh) +Ah = get_matrix(op_h) +bh = get_vector(op_h) +xh_exact = Ah\bh + +AH = assemble_matrix(aH,XH,YH) +Mhh = assemble_matrix((u,v)->∫(u⋅v)*dΩh,Xh,Xh) + +uh_exact, jh_exact = FEFunction(Xh,xh_exact) +l2_error(uh_exact,u_exact,dΩh) +l2_error(jh_exact,j_exact,dΩh) +l2_norm(∇⋅uh_exact,dΩh) +l2_norm(∇⋅jh_exact,dΩh) + +PD = PatchDecomposition(model) +smoother = RichardsonSmoother(VankaSolver(Xh,PD),10,ν) +smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) + +function project_f2c(rh) + Qrh = Mhh\rh + uh, jh = FEFunction(Yh,Qrh) + ll((v,d)) = ∫(v⋅uh + d⋅jh)*dΩHh + assemble_vector(ll,YH) +end +function interp_c2f(xH) + get_free_dof_values(interpolate(FEFunction(YH,xH),Yh)) +end + +############################################################################################ + +patches_mask = PatchBasedSmoothers.get_coarse_node_mask(model,model.glue) +Ih = PatchFESpace(Vh,PD,reffe_u;conformity=H1Conformity(),patches_mask=patches_mask) + +Ωp = Triangulation(PD) +dΩp = Measure(Ωp,qdegree) +ap(x,y) = a_u(x,y,dΩp) +Ai = assemble_matrix(ap,Ih,Ih) + +function P1(dxH) + interp_c2f(dxH) +end +function R1(rh) + project_f2c(rh) +end + +function P2(dxH) + xh = interpolate(FEFunction(YH,dxH),Yh) + dxh = get_free_dof_values(xh) + + uh, jh = xh + r̃h = assemble_vector(v -> Πgraddiv(uh,v,dΩp),Ih) + dx̃ = Ai\r̃h + Pdxh = zero_free_values(Xh) + Pdxh_u = Gridap.MultiField.restrict_to_field(Xh,Pdxh,1) + PatchBasedSmoothers.inject!(Pdxh_u,Ih,dx̃) + y = dxh - Pdxh + return y +end +function R2(rh) + rh_u = Gridap.MultiField.restrict_to_field(YH,rh,1) + r̃h = zero_free_values(Ih) + PatchBasedSmoothers.prolongate!(r̃h,Ih,rh_u) + dr̃h = Ai\r̃h + + Pdxh = zero_free_values(Vh) + PatchBasedSmoothers.inject!(Pdxh,Ih,dr̃h) + uh = FEFunction(Vh,Pdxh) + ll((v,q)) = Πgraddiv(uh,v,dΩh) + drh = assemble_vector(ll,Yh) + rH = project_f2c(rh - drh) + return rH +end + +############################################################################################ + +xh = zeros(size(Ah,2)) +rh = bh - Ah*xh +niters = 10 + +iter = 0 +error0 = norm(rh) +error = error0 +e_rel = error/error0 +while iter < niters && e_rel > 1.0e-10 + println("Iter $iter:") + println(" > Initial: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + println(" > Pre-smoother: ", norm(rh)) + + rH = R2(rh) + qH = AH\rH + qh = P2(qH) + + rh = rh - Ah*qh + xh = xh + qh + println(" > Post-correction: ", norm(rh)) + + solve!(xh,smoother_ns,rh) + + iter += 1 + error = norm(rh) + e_rel = error/error0 + println(" > Final: ",error, " - ", e_rel) +end + +uh, jh = FEFunction(Xh,xh) +l2_error(uh,u_exact,dΩh) +l2_error(jh,j_exact,dΩh) diff --git a/test/_dev/Vanka/mhd_vanka_GMG.jl b/test/_dev/Vanka/mhd_vanka_GMG.jl index d0858e76..771b729b 100644 --- a/test/_dev/Vanka/mhd_vanka_GMG.jl +++ b/test/_dev/Vanka/mhd_vanka_GMG.jl @@ -81,6 +81,7 @@ dΩHh = Measure(ΩH,Ωh,qdegree) dΓh = Measure(Γh,qdegree) n = get_normal_vector(Γh) +ν = 1.e-2 α = -1.0 I_tensor = one(TensorValue{Dc,Dc,Float64}) f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) - cross(j_exact(x),B) @@ -88,13 +89,15 @@ g(x) = j_exact(x) - ∇(φ_exact)(x) - cross(u_exact(x),B) σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor γ(x) = φ_exact(x)*I_tensor crossB(u,v,dΩ) = ∫(cross(u,B)⋅v)dΩ -graddiv(u,v,dΩ) = ∫((∇⋅u)⋅(∇⋅v))*dΩ +Π = GridapSolvers.MultilevelTools.LocalProjectionMap(divergence,reffe_p,qdegree) +Πgraddiv(u,v,dΩ) = ∫(α*Π(u)⋅(∇⋅v))*dΩ +graddiv(u,v,dΩ) = ∫(α*(∇⋅u)⋅(∇⋅v))*dΩ function a((u,p,j,φ),(v,q,d,ψ),dΩ) - c = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ + c = ∫(ν*∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ c = c + ∫(j⋅d + (∇⋅d)*φ - (∇⋅j)*ψ)dΩ c = c - crossB(u,d,dΩ) - crossB(j,v,dΩ) if α > 0.0 - c += graddiv(u,v,dΩ) + graddiv(j,d,dΩ) + c += Πgraddiv(u,v,dΩ) + graddiv(j,d,dΩ) end return c end diff --git a/test/_dev/Vanka/stokes_vanka_GMG.jl b/test/_dev/Vanka/stokes_vanka_GMG.jl index 63a4eea6..a91838dd 100644 --- a/test/_dev/Vanka/stokes_vanka_GMG.jl +++ b/test/_dev/Vanka/stokes_vanka_GMG.jl @@ -52,13 +52,24 @@ dΩHh = Measure(ΩH,Ωh,qdegree) dΓh = Measure(Γh,qdegree) n = get_normal_vector(Γh) +ν = 1.e-8 α = 10.0 I_tensor = one(TensorValue{Dc,Dc,Float64}) -f(x) = -Δ(u_exact)(x) - ∇(p_exact)(x) -σ(x) = ∇(u_exact)(x) + p_exact(x)*I_tensor -graddiv(u,v,dΩ) = ∫((∇⋅u)⋅(∇⋅v))*dΩ +f(x) = -ν*Δ(u_exact)(x) - ∇(p_exact)(x) +σ(x) = ν*∇(u_exact)(x) + p_exact(x)*I_tensor + +Π = GridapSolvers.MultilevelTools.LocalProjectionMap(divergence,reffe_p,qdegree) +#graddiv(u,v,dΩ) = ∫(α*(∇⋅u)⋅(∇⋅v))*dΩ +graddiv(u,v,dΩ) = ∫(α*Π(u)⋅(∇⋅v))*dΩ +function a_u(u,v,dΩ) + c = ∫(ν*∇(u)⊙∇(v))*dΩ + if α > 0.0 + c += graddiv(u,v,dΩ) + end + return c +end function a((u,p),(v,q),dΩ) - c = ∫(∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ + c = ∫(ν*∇(u)⊙∇(v) + (∇⋅v)*p - (∇⋅u)*q)dΩ if α > 0.0 c += graddiv(u,v,dΩ) end @@ -84,7 +95,7 @@ l2_error(ph_exact,p_exact,dΩh) l2_norm(∇⋅uh_exact,dΩh) PD = PatchDecomposition(model) -smoother = RichardsonSmoother(VankaSolver(Xh,PD),10,0.2) +smoother = RichardsonSmoother(VankaSolver(Xh,PD),10,0.1) smoother_ns = numerical_setup(symbolic_setup(smoother,Ah),Ah) function project_f2c(rh) @@ -97,24 +108,68 @@ function interp_c2f(xH) get_free_dof_values(interpolate(FEFunction(YH,xH),Yh)) end +patches_mask = PatchBasedSmoothers.get_coarse_node_mask(model,model.glue) +Ih = PatchFESpace(Vh,PD,reffe_u;conformity=H1Conformity(),patches_mask=patches_mask) + +Ωp = Triangulation(PD) +dΩp = Measure(Ωp,qdegree) +ap(x,y) = a_u(x,y,dΩp) +Ai = assemble_matrix(ap,Ih,Ih) + +function P1(dxH) + interp_c2f(dxH) +end +function R1(rh) + project_f2c(rh) +end + +function P2(dxH) + xh = interpolate(FEFunction(YH,dxH),Yh) + dxh = get_free_dof_values(xh) + + uh, ph = xh + r̃h = assemble_vector(v -> graddiv(uh,v,dΩp),Ih) + dx̃ = Ai\r̃h + Pdxh = zero_free_values(Xh) + Pdxh_u = Gridap.MultiField.restrict_to_field(Xh,Pdxh,1) + PatchBasedSmoothers.inject!(Pdxh_u,Ih,dx̃) + y = dxh - Pdxh + return y +end +function R2(rh) + rh_u = Gridap.MultiField.restrict_to_field(YH,rh,1) + r̃h = zero_free_values(Ih) + PatchBasedSmoothers.prolongate!(r̃h,Ih,rh_u) + dr̃h = Ai\r̃h + + Pdxh = zero_free_values(Vh) + PatchBasedSmoothers.inject!(Pdxh,Ih,dr̃h) + uh = FEFunction(Vh,Pdxh) + ll((v,q)) = graddiv(uh,v,dΩh) + drh = assemble_vector(ll,Yh) + rH = project_f2c(rh - drh) + return rH +end + + xh = randn(size(Ah,2)) rh = bh - Ah*xh -niters = 10 +niters = 20 iter = 0 error0 = norm(rh) error = error0 e_rel = error/error0 -while iter < niters && e_rel > 1.0e-10 +while iter < niters && e_rel > 1.0e-8 println("Iter $iter:") println(" > Initial: ", norm(rh)) solve!(xh,smoother_ns,rh) println(" > Pre-smoother: ", norm(rh)) - rH = project_f2c(rh) + rH = R2(rh) qH = AH\rH - qh = interp_c2f(qH) + qh = P2(qH) rh = rh - Ah*qh xh = xh + qh @@ -131,6 +186,4 @@ end uh, ph = FEFunction(Xh,xh) l2_error(uh,u_exact,dΩh) l2_error(ph,p_exact,dΩh) - -# Note: This converges, but I'm quite convinced we would need a patch-based -# prolongation operator (right?) +l2_norm(∇⋅uh,dΩh) From 59620a77b9932f348949be9d8102b9f637a46a18 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 29 Aug 2024 11:59:30 +1000 Subject: [PATCH 04/47] Minor --- src/PatchBasedSmoothers/mpi/PatchFESpaces.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PatchBasedSmoothers/mpi/PatchFESpaces.jl b/src/PatchBasedSmoothers/mpi/PatchFESpaces.jl index 01d3e736..892b8203 100644 --- a/src/PatchBasedSmoothers/mpi/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/mpi/PatchFESpaces.jl @@ -44,8 +44,7 @@ function default_patches_mask(patch_decomposition::DistributedPatchDecomposition end function PatchFESpace( - sh::FESpaceHierarchy, - patch_decompositions::AbstractArray{<:DistributedPatchDecomposition} + sh::FESpaceHierarchy,patch_decompositions::AbstractArray ) nlevs = num_levels(sh) psh = map(view(sh,1:nlevs-1),patch_decompositions) do shl,decomp From 3c72adee95ab012edb6aa06e1be47bb8248f715f Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 29 Aug 2024 12:57:50 +1000 Subject: [PATCH 05/47] Added distributed VankaSolvers --- src/PatchBasedSmoothers/seq/VankaSolvers.jl | 39 +++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/PatchBasedSmoothers/seq/VankaSolvers.jl b/src/PatchBasedSmoothers/seq/VankaSolvers.jl index c819cdf5..c4dd8eaa 100644 --- a/src/PatchBasedSmoothers/seq/VankaSolvers.jl +++ b/src/PatchBasedSmoothers/seq/VankaSolvers.jl @@ -2,8 +2,8 @@ struct VankaSolver{A} <: Algebra.LinearSolver patch_ids::A function VankaSolver( - patch_ids::AbstractVector{<:AbstractVector{<:Integer}} - ) + patch_ids::Union{T,AbstractVector{<:T}} # Serial / Distributed + ) where T <: AbstractVector{<:AbstractVector{<:Integer}} A = typeof(patch_ids) new{A}(patch_ids) end @@ -33,6 +33,22 @@ function VankaSolver(space::MultiFieldFESpace,patch_cells::Table{<:Integer}) return VankaSolver(patch_ids) end +function VankaSolver(space::GridapDistributed.DistributedMultiFieldFESpace) + patch_ids = map(local_views(space)) do space + solver = VankaSolver(space) + return solver.patch_ids + end + return VankaSolver(patch_ids) +end + +function VankaSolver(space::GridapDistributed.DistributedMultiFieldFESpace,patch_decomposition::DistributedPatchDecomposition) + patch_ids = map(local_views(space),local_views(patch_decomposition)) do space, patch_decomposition + solver = VankaSolver(space,patch_decomposition) + return solver.patch_ids + end + return VankaSolver(patch_ids) +end + struct VankaSS{A} <: Algebra.SymbolicSetup solver::VankaSolver{A} end @@ -77,3 +93,22 @@ function Algebra.solve!(x::AbstractVector,ns::VankaNS,b::AbstractVector) return x end + +struct DistributedVankaNS{A,B} <: Algebra.NumericalSetup + solver::VankaSolver{A} + ns::B +end + +function Algebra.numerical_setup(ss::VankaSS,mat::PSparseMatrix) + ns = map(partition(mat)) do mat + numerical_setup(ss,mat) + end + return DistributedVankaNS(ss.solver,ns) +end + +function Algebra.solve!(x::PVector,ns::DistributedVankaNS,b::PVector) + map(solve!,x,ns.ns,b) + assemble!(x) |> wait + consistent!(x) |> wait + return x +end From f7da3587b68b4b65ae8b48d665b6a0ec6bbb5e76 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 29 Aug 2024 15:03:14 +1000 Subject: [PATCH 06/47] Minor --- src/MultilevelTools/ModelHierarchies.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MultilevelTools/ModelHierarchies.jl b/src/MultilevelTools/ModelHierarchies.jl index ef825939..ac66a789 100644 --- a/src/MultilevelTools/ModelHierarchies.jl +++ b/src/MultilevelTools/ModelHierarchies.jl @@ -164,7 +164,7 @@ function ModelHierarchy(models::Vector{<:GridapDistributed.DistributedDiscreteMo @check Adaptivity.is_child(models[lev],models[lev+1]) "Incorrect hierarchy of models." end ranks = get_parts(models[1]) - @check all(m -> get_parts(m) === ranks, models) "Models have different communicators." + @check all(m -> length(get_parts(m)) === length(ranks), models) "Models have different communicators." level_parts = fill(ranks,nlevs) meshes = Vector{ModelHierarchyLevel}(undef,nlevs) From ae0ea85d49a3804a59913c1c95b8c84c02c11905 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 29 Aug 2024 15:22:23 +1000 Subject: [PATCH 07/47] Minor --- src/PatchBasedSmoothers/seq/VankaSolvers.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PatchBasedSmoothers/seq/VankaSolvers.jl b/src/PatchBasedSmoothers/seq/VankaSolvers.jl index c4dd8eaa..cd3d2557 100644 --- a/src/PatchBasedSmoothers/seq/VankaSolvers.jl +++ b/src/PatchBasedSmoothers/seq/VankaSolvers.jl @@ -107,7 +107,7 @@ function Algebra.numerical_setup(ss::VankaSS,mat::PSparseMatrix) end function Algebra.solve!(x::PVector,ns::DistributedVankaNS,b::PVector) - map(solve!,x,ns.ns,b) + map(solve!,partition(x),ns.ns,partition(b)) assemble!(x) |> wait consistent!(x) |> wait return x From 2e2034d5be55b28bbfb2d63a3ccf248d7532c873 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 2 Sep 2024 16:34:12 +1000 Subject: [PATCH 08/47] PathcBasedPrologationOps working in serial --- src/LinearSolvers/LinearSolvers.jl | 2 + src/LinearSolvers/SchwarzLinearSolvers.jl | 49 +++++++ .../seq/PatchBasedLinearSolvers.jl | 134 ++++++++---------- .../seq/PatchTransferOperators.jl | 40 +++--- src/PatchBasedSmoothers/seq/VankaSolvers.jl | 38 ++--- test/LinearSolvers/SchwarzSolversTests.jl | 51 +++++++ test/LinearSolvers/SmoothersTests.jl | 14 +- test/LinearSolvers/mpi/SchwarzSolversTests.jl | 10 ++ .../DistributedPatchFESpacesDebuggingTests.jl | 2 +- test/_dev/Vanka/distributed_vanka.jl | 32 +++++ 10 files changed, 231 insertions(+), 141 deletions(-) create mode 100644 src/LinearSolvers/SchwarzLinearSolvers.jl create mode 100644 test/LinearSolvers/SchwarzSolversTests.jl create mode 100644 test/LinearSolvers/mpi/SchwarzSolversTests.jl create mode 100644 test/_dev/Vanka/distributed_vanka.jl diff --git a/src/LinearSolvers/LinearSolvers.jl b/src/LinearSolvers/LinearSolvers.jl index 6cf18672..371df4e4 100644 --- a/src/LinearSolvers/LinearSolvers.jl +++ b/src/LinearSolvers/LinearSolvers.jl @@ -24,6 +24,7 @@ export SymGaussSeidelSmoother export GMGLinearSolver export BlockDiagonalSmoother export SchurComplementSolver +export SchwarzLinearSolver # Wrappers for IterativeSolvers.jl export IS_ConjugateGradientSolver @@ -56,5 +57,6 @@ include("GMGLinearSolvers.jl") include("IterativeLinearSolvers.jl") include("SchurComplementSolvers.jl") include("MatrixSolvers.jl") +include("SchwarzLinearSolvers.jl") end \ No newline at end of file diff --git a/src/LinearSolvers/SchwarzLinearSolvers.jl b/src/LinearSolvers/SchwarzLinearSolvers.jl new file mode 100644 index 00000000..cf41701e --- /dev/null +++ b/src/LinearSolvers/SchwarzLinearSolvers.jl @@ -0,0 +1,49 @@ + +# TODO: +# - Implement the multiplicative case +# - Add support for weights/averaging when aggregating the additive case? + +struct SchwarzLinearSolver{T,S,A} <: Algebra.LinearSolver + local_solvers::A + function SchwarzLinearSolver( + solver::Union{S,AbstractVector{<:S}}; + type = :additive + ) where S <: Algebra.LinearSolver + @check type in (:additive,:multiplicative) + @notimplementedif type == :multiplicative # TODO + A = typeof(solver) + new{type,S,A}(solver) + end +end + +struct SchwarzSymbolicSetup{T,S,A,B} <: Algebra.SymbolicSetup + solver::SchwarzLinearSolver{T,S,A} + local_ss::B +end + +function Algebra.symbolic_setup(s::SchwarzLinearSolver,mat::AbstractMatrix) + # TODO: This is where we should compute the comm coloring for the multiplicative case + expand(s) = map(m -> s,partition(mat)) + expand(s::AbstractVector) = s + + local_solvers = expand(s.local_solvers) + local_ss = map(symbolic_setup,local_solvers,partition(mat)) + return SchwarzSymbolicSetup(s,local_ss) +end + +struct SchwarzNumericalSetup{T,S,A,B} <: Algebra.NumericalSetup + solver::SchwarzLinearSolver{T,S,A} + local_ns::B +end + +function Algebra.numerical_setup(ss::SchwarzSymbolicSetup,mat::PSparseMatrix) + local_ns = map(numerical_setup,ss.local_ss,partition(mat)) + return SchwarzNumericalSetup(ss.solver,local_ns) +end + +function Algebra.solve!(x::PVector,ns::SchwarzNumericalSetup{:additive},b::PVector) + map(solve!,partition(x),ns.local_ns,partition(b)) + assemble!(x) |> wait + consistent!(x) |> wait + return x +end diff --git a/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl b/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl index 07875b0b..55476602 100644 --- a/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl +++ b/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl @@ -73,112 +73,92 @@ struct PatchBasedSmootherNumericalSetup{A,B,C,D} <: Gridap.Algebra.NumericalSetu caches :: D end -function Gridap.Algebra.numerical_setup(ss::PatchBasedSymbolicSetup,A::AbstractMatrix) - @check !ss.solver.is_nonlinear - solver = ss.solver - Ph, Vh = solver.patch_space, solver.space - weights = solver.weighted ? compute_weight_operators(Ph,Vh) : nothing - - ap(u,v) = solver.biform(u,v) +function assemble_patch_matrices(Ph::PatchFESpace,ap;local_solver=LUSolver()) assem = SparseMatrixAssembler(Ph,Ph) Ap = assemble_matrix(ap,assem,Ph,Ph) - Ap_ns = numerical_setup(symbolic_setup(solver.local_solver,Ap),Ap) - - # Caches - rp = allocate_in_range(Ap); fill!(rp,0.0) - dxp = allocate_in_domain(Ap); fill!(dxp,0.0) - caches = (rp,dxp) + Ap_ns = numerical_setup(symbolic_setup(local_solver,Ap),Ap) + return Ap, Ap_ns +end - return PatchBasedSmootherNumericalSetup(solver,nothing,Ap_ns,weights,caches) +function assemble_patch_matrices(Ph::DistributedPatchFESpace,ap;local_solver=LUSolver()) + u, v = get_trial_fe_basis(Vh), get_fe_basis(Vh) + matdata = collect_cell_matrix(Ph,Ph,ap(u,v)) + Ap, Ap_ns = map(local_views(Ph),matdata) do Ph, matdata + assem = SparseMatrixAssembler(Ph,Ph) + Ap = assemble_matrix(assem,matdata) + Ap_ns = numerical_setup(symbolic_setup(local_solver,Ap),Ap) + return Ap, Ap_ns + end |> PartitionedArrays.tuple_of_arrays + return Ap, Ap_ns end -function Gridap.Algebra.numerical_setup(ss::PatchBasedSymbolicSetup,A::AbstractMatrix,x::AbstractVector) - @check ss.solver.is_nonlinear - solver = ss.solver - Ph, Vh = solver.patch_space, solver.space - weights = solver.weighted ? compute_weight_operators(Ph,Vh) : nothing - - u0 = FEFunction(Vh,x) - ap(u,v) = solver.biform(u0,u,v) +function update_patch_matrices!(Ap,Ap_ns,Ph::PatchFESpace,ap) assem = SparseMatrixAssembler(Ph,Ph) - Ap = assemble_matrix(ap,assem,Ph,Ph) - Ap_ns = numerical_setup(symbolic_setup(solver.local_solver,Ap),Ap) + assemble_matrix!(Ap,assem,Ph,Ph,ap) + numerical_setup!(Ap_ns,Ap) +end + +function update_patch_matrices!(Ap,Ap_ns,Ph::DistributedPatchFESpace,ap) + u, v = get_trial_fe_basis(Vh), get_fe_basis(Vh) + matdata = collect_cell_matrix(Ph,Ph,ap(u,v)) + map(Ap, Ap_ns, local_views(Ph), matdata) do Ap, Ap_ns, Ph, matdata + assem = SparseMatrixAssembler(Ph,Ph) + assemble_matrix!(Ap,assem,matdata) + numerical_setup!(Ap_ns,Ap) + end +end - # Caches - rp = allocate_in_range(Ap); fill!(rp,0.0) - dxp = allocate_in_domain(Ap); fill!(dxp,0.0) - caches = (rp,dxp) +function allocate_patch_workvectors(Ph::PatchFESpace,Vh::FESpace) + rp = zero_free_values(Ph) + dxp = zero_free_values(Ph) + return rp,dxp +end - return PatchBasedSmootherNumericalSetup(solver,Ap,Ap_ns,weights,caches) +function allocate_patch_workvectors(Ph::DistributedPatchFESpace,Vh::GridapDistributed.DistributedFESpace) + rp = zero_free_values(Ph) + dxp = zero_free_values(Ph) + r = zero_free_values(Vh) + x = zero_free_values(Vh) + return rp,dxp,r,x end -function Gridap.Algebra.numerical_setup(ss::PatchBasedSymbolicSetup,A::PSparseMatrix) +function Gridap.Algebra.numerical_setup(ss::PatchBasedSymbolicSetup,A::AbstractMatrix) @check !ss.solver.is_nonlinear solver = ss.solver + local_solver = solver.local_solver Ph, Vh = solver.patch_space, solver.space - weights = solver.weighted ? compute_weight_operators(Ph,Vh) : nothing - - # Patch system solver (only local systems need to be solved) - u, v = get_trial_fe_basis(Vh), get_fe_basis(Vh) - contr = solver.biform(u,v) - matdata = collect_cell_matrix(Ph,Ph,contr) - Ap, Ap_ns = map(local_views(Ph),matdata) do Ph, matdata - assem = SparseMatrixAssembler(Ph,Ph) - Ap = assemble_matrix(assem,matdata) - Ap_ns = numerical_setup(symbolic_setup(solver.local_solver,Ap),Ap) - return Ap, Ap_ns - end |> PartitionedArrays.tuple_of_arrays - - # Caches - rp = pfill(0.0,partition(Ph.gids)) - dxp = pfill(0.0,partition(Ph.gids)) - r = pfill(0.0,partition(Vh.gids)) - x = pfill(0.0,partition(Vh.gids)) - caches = (rp,dxp,r,x) + ap(u,v) = solver.biform(u,v) + Ap, Ap_ns = assemble_patch_matrices(Ph,ap;local_solver) + weights = solver.weighted ? compute_weight_operators(Ph,Vh) : nothing + caches = allocate_patch_workvectors(Ph,Vh) return PatchBasedSmootherNumericalSetup(solver,nothing,Ap_ns,weights,caches) end -function Gridap.Algebra.numerical_setup(ss::PatchBasedSymbolicSetup,A::PSparseMatrix,x::PVector) +function Gridap.Algebra.numerical_setup(ss::PatchBasedSymbolicSetup,A::AbstractMatrix,x::AbstractVector) @check ss.solver.is_nonlinear solver = ss.solver + local_solver = solver.local_solver Ph, Vh = solver.patch_space, solver.space + + u0 = FEFunction(Vh,x) + ap(u,v) = solver.biform(u0,u,v) + Ap, Ap_ns = assemble_patch_matrices(Ph,ap;local_solver) weights = solver.weighted ? compute_weight_operators(Ph,Vh) : nothing - - # Patch system solver (only local systems need to be solved) - u0, u, v = FEFunction(Vh,x), get_trial_fe_basis(Vh), get_fe_basis(Vh) - contr = solver.biform(u0,u,v) - matdata = collect_cell_matrix(Ph,Ph,contr) - Ap, Ap_ns = map(local_views(Ph),matdata) do Ph, matdata - assem = SparseMatrixAssembler(Ph,Ph) - Ap = assemble_matrix(assem,matdata) - Ap_ns = numerical_setup(symbolic_setup(solver.local_solver,Ap),Ap) - return Ap, Ap_ns - end |> PartitionedArrays.tuple_of_arrays - - # Caches - rp = pfill(0.0,partition(Ph.gids)) - dxp = pfill(0.0,partition(Ph.gids)) - r = pfill(0.0,partition(Vh.gids)) - x = pfill(0.0,partition(Vh.gids)) - caches = (rp,dxp,r,x) + caches = allocate_patch_workvectors(Ph,Vh) return PatchBasedSmootherNumericalSetup(solver,Ap,Ap_ns,weights,caches) end -function Gridap.Algebra.numerical_setup!(ns::PatchBasedSmootherNumericalSetup,A::PSparseMatrix,x::PVector) +function Gridap.Algebra.numerical_setup!(ns::PatchBasedSmootherNumericalSetup,A::AbstractMatrix,x::AbstractVector) @check ns.solver.is_nonlinear solver = ns.solver Ph, Vh = solver.patch_space, solver.space Ap, Ap_ns = ns.local_A, ns.local_ns - u0, u, v = FEFunction(Vh,x), get_trial_fe_basis(Vh), get_fe_basis(Vh) - contr = solver.biform(u0,u,v) - matdata = collect_cell_matrix(Ph,Ph,contr) - map(Ap, Ap_ns, local_views(Ph), matdata) do Ap, Ap_ns, Ph, matdata - assem = SparseMatrixAssembler(Ph,Ph) - assemble_matrix!(Ap,assem,matdata) - numerical_setup!(Ap_ns,Ap) - end + u0 = FEFunction(Vh,x) + ap(u,v) = solver.biform(u0,u,v) + update_patch_matrices!(Ap,Ap_ns,Ph,ap) + return ns end function Gridap.Algebra.solve!(x::AbstractVector,ns::PatchBasedSmootherNumericalSetup,r::AbstractVector) diff --git a/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl b/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl index 55e1a41b..b66c0aa5 100644 --- a/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl +++ b/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl @@ -72,16 +72,8 @@ function _get_patch_cache(lev,sh,PD,lhs,rhs,is_nonlinear,cache_refine) Ph = PatchFESpace(Uh,PD,cell_conformity;patches_mask) # Solver caches - u, v = get_trial_fe_basis(Uh), get_fe_basis(Uh) - contr = is_nonlinear ? lhs(zero(Uh),u,v) : lhs(u,v) - matdata = collect_cell_matrix(Ph,Ph,contr) - Ap_ns, Ap = map(local_views(Ph),matdata) do Ph, matdata - assem = SparseMatrixAssembler(Ph,Ph) - Ap = assemble_matrix(assem,matdata) - Ap_ns = numerical_setup(symbolic_setup(LUSolver(),Ap),Ap) - return Ap_ns, Ap - end |> tuple_of_arrays - Ap = is_nonlinear ? Ap : nothing + ap(u,v) = is_nonlinear ? lhs(zero(Uh),u,v) : lhs(u,v) + Ap, Ap_ns = assemble_patch_matrices(Ph,ap) # TODO: This is using an LUSolver duh = zero(Uh) dxp, rp = zero_free_values(Ph), zero_free_values(Ph) @@ -107,18 +99,12 @@ function MultilevelTools.update_transfer_operator!(op::PatchProlongationOperator end if !isa(fv_h,Nothing) - u, v = get_trial_fe_basis(Uh), get_fe_basis(Uh) - contr = op.is_nonlinear ? op.lhs(FEFunction(Uh,fv_h),u,v) : op.lhs(u,v) - matdata = collect_cell_matrix(Ph,Ph,contr) - map(Ap_ns,Ap,local_views(Ph),matdata) do Ap_ns, Ap, Ph, matdata - assem = SparseMatrixAssembler(Ph,Ph) - assemble_matrix!(Ap,assem,matdata) - numerical_setup!(Ap_ns,Ap) - end + ap(u,v) = op.is_nonlinear ? op.lhs(FEFunction(Uh,fv_h),u,v) : op.lhs(u,v) + update_patch_matrices!(Ap,Ap_ns,Ph,ap) end end -function LinearAlgebra.mul!(y::PVector,A::PatchProlongationOperator{Val{false}},x::PVector) +function LinearAlgebra.mul!(y::AbstractVector,A::PatchProlongationOperator{Val{false}},x::AbstractVector) cache_refine, cache_patch, cache_redist = A.caches model_h, Uh, fv_h, dv_h, UH, fv_H, dv_H = cache_refine Ph, Ap_ns, Ap, duh, dxp, rp = cache_patch @@ -130,7 +116,11 @@ function LinearAlgebra.mul!(y::PVector,A::PatchProlongationOperator{Val{false}}, uh = FEFunction(Uh,fv_h,dv_h) assemble_vector!(v->A.rhs(uh,v),rp,Ph) - map(solve!,partition(dxp),Ap_ns,partition(rp)) + if isa(y,PVector) + map(solve!,partition(dxp),Ap_ns,partition(rp)) + else + solve!(dxp,Ap_ns,rp) + end inject!(dxh,Ph,dxp) fv_h .= fv_h .- dxh copy!(y,fv_h) @@ -230,7 +220,6 @@ struct PatchRestrictionOperator{R,A,B} end function PatchRestrictionOperator(lev,sh,Ip,rhs,qdegree;solver=LUSolver()) - cache_refine = MultilevelTools._get_dual_projection_cache(lev,sh,qdegree,solver) cache_redist = MultilevelTools._get_redistribution_cache(lev,sh,:residual,:restriction,:dual_projection,cache_refine) cache_patch = Ip.caches[2] @@ -242,6 +231,7 @@ function PatchRestrictionOperator(lev,sh,Ip,rhs,qdegree;solver=LUSolver()) end function MultilevelTools.update_transfer_operator!(op::PatchRestrictionOperator,x::Union{PVector,Nothing}) + # Note: Update is done in the prolongation operator, with which we share the cache nothing end @@ -262,7 +252,7 @@ function setup_patch_restriction_operators(sh,patch_prolongations,rhs,qdegrees;k end end -function LinearAlgebra.mul!(y::PVector,A::PatchRestrictionOperator{Val{false}},x::PVector) +function LinearAlgebra.mul!(y::AbstractVector,A::PatchRestrictionOperator{Val{false}},x::AbstractVector) cache_refine, cache_patch, _ = A.caches model_h, Uh, VH, Mh_ns, rh, uh, assem, dΩhH = cache_refine Ph, Ap_ns, Ap, duh, dxp, rp = cache_patch @@ -272,7 +262,11 @@ function LinearAlgebra.mul!(y::PVector,A::PatchRestrictionOperator{Val{false}},x copy!(fv_h,x) fill!(rp,0.0) prolongate!(rp,Ph,fv_h) - map(solve!,partition(dxp),Ap_ns,partition(rp)) + if isa(y,PVector) + map(solve!,partition(dxp),Ap_ns,partition(rp)) + else + solve!(dxp,Ap_ns,rp) + end inject!(dxh,Ph,dxp) consistent!(dxh) |> fetch diff --git a/src/PatchBasedSmoothers/seq/VankaSolvers.jl b/src/PatchBasedSmoothers/seq/VankaSolvers.jl index cd3d2557..16e146ba 100644 --- a/src/PatchBasedSmoothers/seq/VankaSolvers.jl +++ b/src/PatchBasedSmoothers/seq/VankaSolvers.jl @@ -34,19 +34,16 @@ function VankaSolver(space::MultiFieldFESpace,patch_cells::Table{<:Integer}) end function VankaSolver(space::GridapDistributed.DistributedMultiFieldFESpace) - patch_ids = map(local_views(space)) do space - solver = VankaSolver(space) - return solver.patch_ids - end - return VankaSolver(patch_ids) + local_solvers = map(VankaSolver,local_views(space)) + return SchwarzLinearSolver(local_solvers) end -function VankaSolver(space::GridapDistributed.DistributedMultiFieldFESpace,patch_decomposition::DistributedPatchDecomposition) - patch_ids = map(local_views(space),local_views(patch_decomposition)) do space, patch_decomposition - solver = VankaSolver(space,patch_decomposition) - return solver.patch_ids - end - return VankaSolver(patch_ids) +function VankaSolver( + space::GridapDistributed.DistributedMultiFieldFESpace, + patch_decomposition::DistributedPatchDecomposition +) + local_solvers = map(VankaSolver,local_views(space),local_views(patch_decomposition)) + return SchwarzLinearSolver(local_solvers) end struct VankaSS{A} <: Algebra.SymbolicSetup @@ -93,22 +90,3 @@ function Algebra.solve!(x::AbstractVector,ns::VankaNS,b::AbstractVector) return x end - -struct DistributedVankaNS{A,B} <: Algebra.NumericalSetup - solver::VankaSolver{A} - ns::B -end - -function Algebra.numerical_setup(ss::VankaSS,mat::PSparseMatrix) - ns = map(partition(mat)) do mat - numerical_setup(ss,mat) - end - return DistributedVankaNS(ss.solver,ns) -end - -function Algebra.solve!(x::PVector,ns::DistributedVankaNS,b::PVector) - map(solve!,partition(x),ns.ns,partition(b)) - assemble!(x) |> wait - consistent!(x) |> wait - return x -end diff --git a/test/LinearSolvers/SchwarzSolversTests.jl b/test/LinearSolvers/SchwarzSolversTests.jl new file mode 100644 index 00000000..b2fd0605 --- /dev/null +++ b/test/LinearSolvers/SchwarzSolversTests.jl @@ -0,0 +1,51 @@ +module SchwarzSolversTests + +using Test +using MPI +using Gridap, Gridap.Algebra +using GridapDistributed +using PartitionedArrays + +using GridapSolvers +using GridapSolvers.LinearSolvers + +function main(distribute,np) + sol(x) = x[1] + x[2] + f(x) = -Δ(sol)(x) + + parts = distribute(LinearIndices((prod(np),))) + model = CartesianDiscreteModel(parts,np,(0,1,0,1),(8,8)) + + order = 1 + qorder = order*2 + 1 + reffe = ReferenceFE(lagrangian,Float64,order) + Vh = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags="boundary") + Uh = TrialFESpace(Vh,sol) + u = interpolate(sol,Uh) + + Ω = Triangulation(model) + dΩ = Measure(Ω,qorder) + a(u,v) = ∫(v⋅u)*dΩ + l(v) = ∫(v⋅sol)*dΩ + + op = AffineFEOperator(a,l,Uh,Vh) + A, b = get_matrix(op), get_vector(op) + + P = SchwarzLinearSolver(LUSolver()) + solver = CGSolver(P;rtol=1.0e-8,verbose=i_am_main(parts)) + ns = numerical_setup(symbolic_setup(solver,A),A) + x = allocate_in_domain(A); fill!(x,zero(eltype(x))) + solve!(x,ns,b) + + u = interpolate(sol,Uh) + uh = FEFunction(Uh,x) + eh = uh - u + E = sum(∫(eh*eh)*dΩ) + if i_am_main(parts) + println("L2 Error: ", E) + end + + @test E < 1.e-8 +end + +end # module \ No newline at end of file diff --git a/test/LinearSolvers/SmoothersTests.jl b/test/LinearSolvers/SmoothersTests.jl index 530029f0..6c315706 100644 --- a/test/LinearSolvers/SmoothersTests.jl +++ b/test/LinearSolvers/SmoothersTests.jl @@ -5,7 +5,6 @@ using MPI using Gridap, Gridap.Algebra using GridapDistributed using PartitionedArrays -using IterativeSolvers using GridapSolvers using GridapSolvers.LinearSolvers @@ -29,15 +28,10 @@ function smoothers_driver(parts,model,P) op = AffineFEOperator(a,l,Uh,Vh) A, b = get_matrix(op), get_vector(op) - ss = symbolic_setup(P,A) - ns = numerical_setup(ss,A) - - x = allocate_in_domain(A); ; fill!(x,zero(eltype(x))) - x, history = IterativeSolvers.cg!(x,A,b; - verbose=i_am_main(parts), - reltol=1.0e-8, - Pl=ns, - log=true) + solver = CGSolver(P;rtol=1.0e-8,verbose=i_am_main(parts)) + ns = numerical_setup(sumbolic_setup(solver,A),A) + x = allocate_in_domain(A); fill!(x,zero(eltype(x))) + solve!(x,ns,b) u = interpolate(sol,Uh) uh = FEFunction(Uh,x) diff --git a/test/LinearSolvers/mpi/SchwarzSolversTests.jl b/test/LinearSolvers/mpi/SchwarzSolversTests.jl new file mode 100644 index 00000000..12e2466a --- /dev/null +++ b/test/LinearSolvers/mpi/SchwarzSolversTests.jl @@ -0,0 +1,10 @@ +module SmoothersTestsMPI +using MPI, PartitionedArrays +include("../SchwarzSolversTests.jl") + +with_mpi() do distribute + SchwarzSolversTests.main(distribute,(2,2)) # 2D + SchwarzSolversTests.main(distribute,(2,2,1)) # 3D +end + +end \ No newline at end of file diff --git a/test/_dev/PatchBased/DistributedPatchFESpacesDebuggingTests.jl b/test/_dev/PatchBased/DistributedPatchFESpacesDebuggingTests.jl index a88f390b..6c937d33 100644 --- a/test/_dev/PatchBased/DistributedPatchFESpacesDebuggingTests.jl +++ b/test/_dev/PatchBased/DistributedPatchFESpacesDebuggingTests.jl @@ -72,7 +72,7 @@ function run(ranks) ap(u,v) = biform(u,v,dΩₚ) lp(v) = liform(v,dΩₚ) - assembler_P = SparseMatrixAssembler(Ph,Ph,FullyAssembledRows()) + assembler_P = SparseMatrixAssembler(Ph,Ph,LocallyAssembled()) Ahp = assemble_matrix(ap,assembler_P,Ph,Ph) fhp = assemble_vector(lp,assembler_P,Ph) diff --git a/test/_dev/Vanka/distributed_vanka.jl b/test/_dev/Vanka/distributed_vanka.jl new file mode 100644 index 00000000..116acc30 --- /dev/null +++ b/test/_dev/Vanka/distributed_vanka.jl @@ -0,0 +1,32 @@ + +using Gridap +using PartitionedArrays +using GridapDistributed + + +np = (2,1) +ranks = with_debug() do distribute + distribute(LinearIndices((prod(np),))) +end + +model = CartesianDiscreteModel(ranks,np,(0,1,0,1),(4,4)) + +order = 1 +reffe = ReferenceFE(lagrangian,Float64,order) +Vh = TestFESpace(model,reffe) + +Ω = Triangulation(model) +dΩ = Measure(Ω,2*order) + +a(u,v) = ∫(v⋅u)*dΩ +A = assemble_matrix(a,Vh,Vh) + + +rows, cols = axes(A) + +nbors_snd, nbors_rcv = assembly_neighbors(partition(rows)) + +map(partition(rows),partition(cols),partition(A)) do rows,cols,mat + own_rows = own_to_local(rows) +end + From ac049e6d3e0ba1a6bf203cf2a4fb6f1bdc46f93f Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 2 Sep 2024 16:46:50 +1000 Subject: [PATCH 09/47] Minor --- src/PatchBasedSmoothers/seq/PatchTransferOperators.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl b/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl index b66c0aa5..63cf932e 100644 --- a/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl +++ b/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl @@ -268,15 +268,13 @@ function LinearAlgebra.mul!(y::AbstractVector,A::PatchRestrictionOperator{Val{fa solve!(dxp,Ap_ns,rp) end inject!(dxh,Ph,dxp) - consistent!(dxh) |> fetch assemble_vector!(v->A.rhs(duh,v),rh,Uh) fv_h .= fv_h .- rh - consistent!(fv_h) |> fetch solve!(rh,Mh_ns,fv_h) copy!(fv_h,rh) - consistent!(fv_h) |> fetch + isa(y,PVector) && wait(consistent!(fv_h)) v = get_fe_basis(VH) assemble_vector!(y,assem,collect_cell_vector(VH,∫(v⋅uh)*dΩhH)) From 0349ff197530a990d13a0bf6d9b03b2279c9ac71 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 2 Sep 2024 17:30:03 +1000 Subject: [PATCH 10/47] Minor --- .../MultiFieldTransferOperators.jl | 11 +++++++--- .../seq/PatchMultiFieldFESpaces.jl | 21 +++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/MultilevelTools/MultiFieldTransferOperators.jl b/src/MultilevelTools/MultiFieldTransferOperators.jl index a1264a65..f7d86224 100644 --- a/src/MultilevelTools/MultiFieldTransferOperators.jl +++ b/src/MultilevelTools/MultiFieldTransferOperators.jl @@ -42,11 +42,12 @@ function MultiFieldTransferOperator(sh::FESpaceHierarchy,operators;op_type=:prol return mfops end -function update_transfer_operator!(op::MultiFieldTransferOperator,x::PVector) +function update_transfer_operator!(op::MultiFieldTransferOperator,x::AbstractVector) xh, _ = op.cache if !isnothing(xh) copy!(x,xh) + isa(x,PVector) && wait(consistent!(x)) end for (i,op_i) in enumerate(op.ops) @@ -55,7 +56,11 @@ function update_transfer_operator!(op::MultiFieldTransferOperator,x::PVector) end end -function LinearAlgebra.mul!(x,op::MultiFieldTransferOperator,y) +function LinearAlgebra.mul!( + x::Union{Nothing,<:AbstractVector}, + op::MultiFieldTransferOperator, + y::Union{Nothing,<:AbstractVector} +) xh, yh = op.cache if !isnothing(yh) @@ -70,7 +75,7 @@ function LinearAlgebra.mul!(x,op::MultiFieldTransferOperator,y) if !isnothing(xh) copy!(x,xh) - consistent!(x) |> fetch + isa(x,PVector) && wait(consistent!(x)) end return x diff --git a/src/PatchBasedSmoothers/seq/PatchMultiFieldFESpaces.jl b/src/PatchBasedSmoothers/seq/PatchMultiFieldFESpaces.jl index efc56486..3d4fe41d 100644 --- a/src/PatchBasedSmoothers/seq/PatchMultiFieldFESpaces.jl +++ b/src/PatchBasedSmoothers/seq/PatchMultiFieldFESpaces.jl @@ -76,21 +76,24 @@ function inject!(x,Ph::MultiFieldFESpace,y) end end -function prolongate!(x::PVector, - Ph::GridapDistributed.DistributedMultiFieldFESpace, - y::PVector; - is_consistent::Bool=false) +function prolongate!( + x::PVector, + Ph::GridapDistributed.DistributedMultiFieldFESpace, + y::PVector; + is_consistent::Bool=false +) if !is_consistent consistent!(y) |> fetch end map(prolongate!,partition(x),local_views(Ph),partition(y)) end -function inject!(x::PVector, - Ph::GridapDistributed.DistributedMultiFieldFESpace, - y::PVector; - make_consistent::Bool=true) - +function inject!( + x::PVector, + Ph::GridapDistributed.DistributedMultiFieldFESpace, + y::PVector; + make_consistent::Bool=true +) map(partition(x),local_views(Ph),partition(y)) do x,Ph,y inject!(x,Ph,y) end From fa5f2d76aa86eb0496300bede5876bf128b192ca Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 4 Sep 2024 15:18:27 +1000 Subject: [PATCH 11/47] Added patch closures --- .../PatchBasedSmoothers.jl | 1 + src/PatchBasedSmoothers/seq/PatchClosures.jl | 36 +++ .../seq/PatchDecompositions.jl | 280 ++++++++++++++---- src/PatchBasedSmoothers/seq/PatchFESpaces.jl | 98 ++++-- .../seq/PatchTriangulations.jl | 8 +- .../PatchBased/ZeroMeanPatchBasedFESpaces.jl | 2 +- test/_dev/PatchBased/patch_closures.jl | 79 +++++ test/_dev/Vanka/kernel_analysis.jl | 70 +++++ 8 files changed, 482 insertions(+), 92 deletions(-) create mode 100644 src/PatchBasedSmoothers/seq/PatchClosures.jl create mode 100644 test/_dev/PatchBased/patch_closures.jl create mode 100644 test/_dev/Vanka/kernel_analysis.jl diff --git a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl index d8f6733d..a44cd594 100644 --- a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl +++ b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl @@ -22,6 +22,7 @@ export setup_patch_prolongation_operators, setup_patch_restriction_operators include("seq/PatchDecompositions.jl") include("mpi/PatchDecompositions.jl") include("seq/PatchTriangulations.jl") +include("seq/PatchClosures.jl") include("seq/CoarsePatchDecompositions.jl") # FESpaces diff --git a/src/PatchBasedSmoothers/seq/PatchClosures.jl b/src/PatchBasedSmoothers/seq/PatchClosures.jl new file mode 100644 index 00000000..9a0269f7 --- /dev/null +++ b/src/PatchBasedSmoothers/seq/PatchClosures.jl @@ -0,0 +1,36 @@ + +struct PatchClosureTriangulation{Dc,Dp} <: Triangulation{Dc,Dp} + trian :: PatchTriangulation{Dc,Dp} +end + +function Closure(PD::PatchDecomposition) + patch_cells = generate_patch_closures(PD) + trian = Triangulation(PD.model) + ptrian = PatchTriangulation(trian,PD,patch_cells,nothing) + return PatchClosureTriangulation(ptrian) +end + +function Geometry.get_background_model(t::PatchClosureTriangulation) + get_background_model(t.trian) +end + +function Geometry.get_grid(t::PatchClosureTriangulation) + get_grid(t.trian) +end + +function Geometry.get_glue(t::PatchClosureTriangulation,::Val{d}) where d + get_glue(t.trian,Val(d)) +end + +function Geometry.get_facet_normal(trian::PatchClosureTriangulation) + get_facet_normal(trian.trian) +end + +function Geometry.is_change_possible(strian::PatchClosureTriangulation,ttrian::Triangulation) + return is_change_possible(strian.trian,ttrian) +end + +function Geometry.move_contributions(scell_to_val::AbstractArray,strian::PatchClosureTriangulation) + vals, _ = move_contributions(scell_to_val,strian.trian) + return vals, strian +end diff --git a/src/PatchBasedSmoothers/seq/PatchDecompositions.jl b/src/PatchBasedSmoothers/seq/PatchDecompositions.jl index 764577e0..5a0b88ee 100644 --- a/src/PatchBasedSmoothers/seq/PatchDecompositions.jl +++ b/src/PatchBasedSmoothers/seq/PatchDecompositions.jl @@ -23,21 +23,17 @@ of `Ω` such that `Ω = Σ_i Ω_i`. - `Dr::Integer` : Dimension of the patch root - `model::DiscreteModel{Dc,Dp}` : Underlying discrete model - `patch_cells::Table` : [patch][local cell] -> cell -- `patch_cells_overlapped::Table` : [patch][local cell] -> overlapped cell - `patch_cells_faces_on_boundary::Table` : [d][overlapped cell][local face] -> face is on patch boundary """ struct PatchDecomposition{Dr,Dc,Dp} <: GridapType model :: DiscreteModel{Dc,Dp} - patch_cells :: Gridap.Arrays.Table # [patch][local cell] -> cell - patch_cells_overlapped :: Gridap.Arrays.Table # [patch][local cell] -> overlapped cell - patch_cells_faces_on_boundary :: Vector{Gridap.Arrays.Table} # [d][overlapped cell][local face] -> face is on patch boundary + patch_cells :: Arrays.Table # [patch][local cell] -> cell + patch_cells_faces_on_boundary :: Vector{Arrays.Table} # [d][overlapped cell][local face] -> face is on patch boundary + patch_boundary_style :: PatchBoundaryStyle end -num_patches(a::PatchDecomposition) = length(a.patch_cells) -Gridap.Geometry.num_cells(a::PatchDecomposition) = length(a.patch_cells.data) - -@doc """ +""" function PatchDecomposition( model::DiscreteModel{Dc,Dp}; Dr=0, @@ -49,31 +45,112 @@ Returns an instance of [`PatchDecomposition`](@ref) from a given discrete model. """ function PatchDecomposition( model::DiscreteModel{Dc,Dp}; - Dr=0, + Dr::Integer=0, patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude(), boundary_tag_names::AbstractArray{String}=["boundary"] ) where {Dc,Dp} - Gridap.Helpers.@check 0 <= Dr <= Dc-1 + @assert 0 <= Dr <= Dc-1 topology = get_grid_topology(model) - patch_cells = Gridap.Geometry.get_faces(topology,Dr,Dc) - patch_facets = Gridap.Geometry.get_faces(topology,Dr,Dc-1) - patch_cells_overlapped = compute_patch_overlapped_cells(patch_cells) + patch_cells = Geometry.get_faces(topology,Dr,Dc) + patch_facets = Geometry.get_faces(topology,Dr,Dc-1) patch_cells_faces_on_boundary = compute_patch_cells_faces_on_boundary( - model, patch_cells, patch_cells_overlapped, - patch_facets, patch_boundary_style, boundary_tag_names + model, patch_cells, patch_facets, patch_boundary_style, boundary_tag_names ) return PatchDecomposition{Dr,Dc,Dp}( - model, patch_cells, patch_cells_overlapped, patch_cells_faces_on_boundary + model, patch_cells, patch_cells_faces_on_boundary, patch_boundary_style ) end -function compute_patch_overlapped_cells(patch_cells) - num_overlapped_cells = length(patch_cells.data) - data = Gridap.Arrays.IdentityVector(num_overlapped_cells) - return Gridap.Arrays.Table(data,patch_cells.ptrs) +""" + num_patches(a::PatchDecomposition) +""" +num_patches(a::PatchDecomposition) = length(a.patch_cells) + +""" + get_patch_cells(PD::PatchDecomposition) -> patch_to_cells +""" +get_patch_cells(PD::PatchDecomposition) = PD.patch_cells + +""" + get_patch_cell_offsets(PD::PatchDecomposition) +""" +get_patch_cell_offsets(PD::PatchDecomposition) = PD.patch_cells.ptrs + +Geometry.num_cells(a::PatchDecomposition) = length(a.patch_cells.data) +Geometry.get_isboundary_face(PD::PatchDecomposition) = PD.patch_cells_faces_on_boundary +Geometry.get_isboundary_face(PD::PatchDecomposition,d::Integer) = PD.patch_cells_faces_on_boundary[d+1] + +""" + get_patch_cells_overlapped(PD::PatchDecomposition) -> patch_to_pcells +""" +function get_patch_cells_overlapped(PD::PatchDecomposition) + patch_cells = get_patch_cells(PD) + n_pcells = length(patch_cells.data) + data = Arrays.IdentityVector(n_pcells) + return Arrays.Table(data,patch_cells.ptrs) +end + +function Base.view(PD::PatchDecomposition{Dr,Dc,Dp},patch_ids) where {Dr,Dc,Dp} + patch_cells = view(get_patch_cells(PD),patch_ids) + patch_faces_on_boundary = [ + view(PD.patch_cells_faces_on_boundary[d+1],patch_ids) for d = 0:Dc-1 + ] + return PatchDecomposition{Dr,Dc,Dp}(PD.model,patch_cells,patch_faces_on_boundary,PD.patch_boundary_style) +end + +""" + patch_view(PD::PatchDecomposition,a::AbstractArray,patch::Integer) + patch_view(PD::PatchDecomposition,a::AbstractArray,patch_ids::AbstractUnitRange{<:Integer}) + +Returns a view of the pcell-wise array `a` restricted to the pcells of the patch `patch` or `patch_ids`. +""" +function patch_view(PD::PatchDecomposition,a::AbstractArray,patch::Integer) + offsets = get_patch_cell_offsets(PD) + return view(a,offsets[patch]:offsets[patch+1]-1) +end + +function patch_view(PD::PatchDecomposition,a::AbstractArray,patch_ids::AbstractUnitRange{<:Integer}) + offsets = get_patch_cell_offsets(PD) + start = offsets[first(patch_ids)] + stop = offsets[last(patch_ids)+1]-1 + return view(a,start:stop) +end + +""" + patch_reindex(PD::PatchDecomposition,cell_to_data) -> pcell_to_data +""" +function patch_reindex(PD::PatchDecomposition,cell_to_data) + patch_cells = get_patch_cells(PD) + pcell_to_data = lazy_map(Reindex(cell_to_data),patch_cells.data) + return pcell_to_data +end + +""" + allocate_patch_cell_array(PD::PatchDecomposition,cell_to_data::Table{T};init=zero(T)) + +Allocates a patch-cell-wise array from a cell-wise array. +""" +function allocate_patch_cell_array( + PD::PatchDecomposition, cell_to_data::Table{T}; init=zero(T) +) where T + patch_cells = get_patch_cells(PD) + return allocate_patch_cell_array(patch_cells,cell_to_data;init) +end + +function allocate_patch_cell_array( + patch_cells::Table, cell_to_data::Table{T}; init = zero(T) +) where T + ptrs = zeros(Int,length(patch_cells.data)+1) + ptrs[1] = 1 + for (pcell,cell) in enumerate(patch_cells.data) + n = cell_to_data.ptrs[cell+1] - cell_to_data.ptrs[cell] + ptrs[pcell+1] = ptrs[pcell] + n + end + data = fill(init,ptrs[end]-1) + return Arrays.Table(data,ptrs) end # patch_cell_faces_on_boundary :: @@ -81,17 +158,16 @@ end function compute_patch_cells_faces_on_boundary( model::DiscreteModel, patch_cells, - patch_cells_overlapped, patch_facets, patch_boundary_style, boundary_tag_names ) patch_cell_faces_on_boundary = _allocate_patch_cells_faces_on_boundary(model,patch_cells) - if !isa(patch_boundary_style,PatchBoundaryInclude) + if isa(patch_boundary_style,PatchBoundaryExclude) _compute_patch_cells_faces_on_boundary!( patch_cell_faces_on_boundary, - model, patch_cells, patch_cells_overlapped, - patch_facets, patch_boundary_style, boundary_tag_names + model, patch_cells,patch_facets, + patch_boundary_style, boundary_tag_names ) end return patch_cell_faces_on_boundary @@ -103,7 +179,7 @@ function _allocate_patch_cells_faces_on_boundary(model::DiscreteModel{Dc},patch_ patch_cells_faces_on_boundary = Vector{Gridap.Arrays.Table}(undef,Dc) for d = 0:Dc-1 - ctype_to_num_dfaces = map(reffe -> num_faces(reffe,d),ctype_to_reffe) + ctype_to_num_dfaces = map(reffe -> num_faces(reffe,d), ctype_to_reffe) patch_cells_faces_on_boundary[d+1] = _allocate_ocell_to_dface(Bool, patch_cells,cell_to_ctype, ctype_to_num_dfaces) end @@ -111,11 +187,11 @@ function _allocate_patch_cells_faces_on_boundary(model::DiscreteModel{Dc},patch_ end function _allocate_ocell_to_dface(::Type{T},patch_cells,cell_to_ctype,ctype_to_num_dfaces) where T<:Number - num_overlapped_cells = length(patch_cells.data) - ptrs = Vector{Int}(undef,num_overlapped_cells+1) + n_pcells = length(patch_cells.data) + ptrs = Vector{Int}(undef,n_pcells+1) ptrs[1] = 1 - for i = 1:num_overlapped_cells + for i = 1:n_pcells cell = patch_cells.data[i] ctype = cell_to_ctype[cell] ptrs[i+1] = ptrs[i] + ctype_to_num_dfaces[ctype] @@ -128,7 +204,6 @@ function _compute_patch_cells_faces_on_boundary!( patch_cells_faces_on_boundary, model::DiscreteModel, patch_cells, - patch_cells_overlapped, patch_facets, patch_boundary_style, boundary_tag_names @@ -137,14 +212,14 @@ function _compute_patch_cells_faces_on_boundary!( cache_patch_cells = array_cache(patch_cells) cache_patch_facets = array_cache(patch_facets) for patch = 1:num_patches + first_patch_cell = patch_cells.ptrs[patch] current_patch_cells = getindex!(cache_patch_cells,patch_cells,patch) current_patch_facets = getindex!(cache_patch_facets,patch_facets,patch) _compute_patch_cells_faces_on_boundary!( patch_cells_faces_on_boundary, model, - patch, + first_patch_cell, current_patch_cells, - patch_cells_overlapped, current_patch_facets, patch_boundary_style, boundary_tag_names @@ -155,9 +230,8 @@ end function _compute_patch_cells_faces_on_boundary!( patch_cells_faces_on_boundary, model::DiscreteModel{Dc}, - patch, + first_patch_cell, patch_cells, - patch_cells_overlapped, patch_facets, patch_boundary_style, boundary_tag_names @@ -166,7 +240,7 @@ function _compute_patch_cells_faces_on_boundary!( topology = get_grid_topology(model) boundary_tags = findall(x -> (x ∈ boundary_tag_names), face_labeling.tag_to_name) - Gridap.Helpers.@check !isempty(boundary_tags) + @assert !isempty(boundary_tags) boundary_entities = vcat(face_labeling.tag_to_entities[boundary_tags]...) # Cells facets @@ -182,7 +256,7 @@ function _compute_patch_cells_faces_on_boundary!( # Go over all cells in the current patch for (lcell,cell) in enumerate(patch_cells) - overlapped_cell = patch_cells_overlapped.data[patch_cells_overlapped.ptrs[patch]+lcell-1] + overlapped_cell = first_patch_cell+lcell-1 cell_facets = getindex!(cache_cell_to_facets,cell_to_facets,cell) # Go over the facets (i.e., faces of dim Dc-1) in the current cell for (lfacet,facet) in enumerate(cell_facets) @@ -216,7 +290,7 @@ function _compute_patch_cells_faces_on_boundary!( lface = findfirst(x -> x==facet_face, cell_dfaces) lcell2 = findfirst(x -> x==cell_around_face, patch_cells) - overlapped_cell2 = patch_cells_overlapped.data[patch_cells_overlapped.ptrs[patch]+lcell2-1] + overlapped_cell2 = first_patch_cell+lcell2-1 position = patch_cells_faces_on_boundary[d+1].ptrs[overlapped_cell2]+lface-1 patch_cells_faces_on_boundary[d+1].data[position] = true end @@ -228,11 +302,19 @@ function _compute_patch_cells_faces_on_boundary!( end end -# Patch cell faces: -# patch_faces[pcell] = [face1, face2, ...] -# where face1, face2, ... are the faces of the overlapped cell `pcell` such that -# - they are NOT on the boundary of the patch -# - they are flagged `true` in faces_mask +""" + get_patch_cell_faces(PD::PatchDecomposition,Df::Integer) + get_patch_cell_faces(PD::PatchDecomposition,Df::Integer,faces_mask::AbstractVector{Bool}) + +Returns a patch-wise Table containing the faces on each patch cell, i.e + + patch_faces[pcell] = [face1, face2, ...] + +where face1, face2, ... are the faces on the overlapped cell `pcell` such that + + - they are NOT on the boundary of the patch + - they are flagged `true` in `faces_mask` +""" function get_patch_cell_faces(PD::PatchDecomposition,Df::Integer) model = PD.model topo = get_grid_topology(model) @@ -240,18 +322,19 @@ function get_patch_cell_faces(PD::PatchDecomposition,Df::Integer) return get_patch_cell_faces(PD,Df,faces_mask) end -function get_patch_cell_faces(PD::PatchDecomposition{Dr,Dc},Df::Integer,faces_mask) where {Dr,Dc} +function get_patch_cell_faces( + PD::PatchDecomposition{Dr,Dc},Df::Integer,faces_mask::AbstractVector{Bool} +) where {Dr,Dc} model = PD.model topo = get_grid_topology(model) c2e_map = Gridap.Geometry.get_faces(topo,Dc,Df) patch_cells = Gridap.Arrays.Table(PD.patch_cells) - patch_cell_faces = map(Reindex(c2e_map),patch_cells.data) + patch_cell_faces = lazy_map(Reindex(c2e_map),patch_cells.data) faces_on_boundary = PD.patch_cells_faces_on_boundary[Df+1] patch_faces = _allocate_patch_cell_faces(patch_cell_faces,faces_on_boundary,faces_mask) _generate_patch_cell_faces!(patch_faces,patch_cell_faces,faces_on_boundary,faces_mask) - return patch_faces end @@ -300,21 +383,29 @@ function _generate_patch_cell_faces!(patch_faces,patch_cell_faces,faces_on_bound return patch_faces end -# Patch faces: -# patch_faces[patch] = [face1, face2, ...] -# where face1, face2, ... are the faces of the patch such that -# - they are NOT on the boundary of the patch -# - they are flagged `true` in faces_mask -# If `reverse` is `true`, the faces are the ones ON the boundary of the patch. +""" + get_patch_faces(PD::PatchDecomposition,Df::Integer,faces_mask::AbstractVector{Bool};reverse=false) + +Returns a patch-wise Table containing the faces on each patch, i.e + + patch_faces[patch] = [face1, face2, ...] + +where face1, face2, ... are the faces on the patch such that + + - they are NOT on the boundary of the patch + - they are flagged `true` in `faces_mask` + +If `reverse` is `true`, the faces are the ones ON the boundary of the patch. +""" function get_patch_faces( - PD::PatchDecomposition{Dr,Dc},Df::Integer,faces_mask;reverse=false + PD::PatchDecomposition{Dr,Dc},Df::Integer,faces_mask::AbstractVector{Bool};reverse=false ) where {Dr,Dc} model = PD.model topo = get_grid_topology(model) c2e_map = Gridap.Geometry.get_faces(topo,Dc,Df) patch_cells = Gridap.Arrays.Table(PD.patch_cells) - patch_cell_faces = map(Reindex(c2e_map),patch_cells.data) + patch_cell_faces = lazy_map(Reindex(c2e_map),patch_cells.data) faces_on_boundary = PD.patch_cells_faces_on_boundary[Df+1] patch_faces = _allocate_patch_faces(patch_cells,patch_cell_faces,faces_on_boundary,faces_mask,reverse) @@ -392,12 +483,24 @@ function _generate_patch_faces!( return patch_faces end -# Face connectivity for the patches -# pface_to_pcell[pface] = [pcell1, pcell2, ...] -# This would be the Gridap equivalent to `get_faces(patch_topology,Df,Dc)`. -# On top of this, we also return the local cell index (within the face connectivity) of cell, -# which is needed when a pface touches different cells depending on the patch. -# The argument `patch_faces` allows to select only some pfaces (i.e boundary/skeleton/etc...). +""" + get_pface_to_pcell(PD::PatchDecomposition{Dr,Dc},Df::Integer,patch_faces) + +Returns two pface-wise Tables containing + + 1) the patch cells touched by each patch face and + 2) the local cell index (within the face connectivity) of the cell touched by the patch face, + which is needed when a pface touches different cells depending on the patch + +i.e + + pface_to_pcell[pface] = [pcell1, pcell2, ...] + pface_to_lcell[pface] = [lcell1, lcell2, ...] + +where pcell1, pcell2, ... are the patch cells touched by the patch face `pface`. + +This would be the Gridap equivalent to `get_faces(patch_topology,Df,Dc)`. +""" function get_pface_to_pcell(PD::PatchDecomposition{Dr,Dc},Df::Integer,patch_faces) where {Dr,Dc} model = PD.model topo = get_grid_topology(model) @@ -405,7 +508,7 @@ function get_pface_to_pcell(PD::PatchDecomposition{Dr,Dc},Df::Integer,patch_face faces_to_cells = Gridap.Geometry.get_faces(topo,Df,Dc) pfaces_to_cells = lazy_map(Reindex(faces_to_cells),patch_faces.data) patch_cells = Gridap.Arrays.Table(PD.patch_cells) - patch_cells_overlapped = PD.patch_cells_overlapped + patch_cells_overlapped = get_patch_cells_overlapped(PD) num_patches = length(patch_cells) num_pfaces = length(pfaces_to_cells) @@ -447,3 +550,62 @@ function get_pface_to_pcell(PD::PatchDecomposition{Dr,Dc},Df::Integer,patch_face pface_to_pcell = Gridap.Arrays.Table(data,ptrs) return pface_to_pcell, pface_to_lcell end + +""" + generate_patch_closures(PD::PatchDecomposition{Dr,Dc}) + +Returns a patch-wise Table containing the closure of each patch. +""" +function generate_patch_closures(PD::PatchDecomposition{Dr,Dc}) where {Dr,Dc} + topo = get_grid_topology(PD.model) + nodes_to_cells = Geometry.get_faces(topo,0,Dc) + cells_to_nodes = Geometry.get_faces(topo,Dc,0) + + patch_cells = get_patch_cells(PD) + + n_patches = length(patch_cells) + ptrs = zeros(Int,n_patches+1) + for patch in 1:n_patches + cells = view(patch_cells,patch) + closure = Set(cells) + for cell in cells + nodes = view(cells_to_nodes,cell) + for node in nodes + nbors = view(nodes_to_cells,node) + push!(closure,nbors...) + end + end + ptrs[patch+1] = length(closure) + end + Arrays.length_to_ptrs!(ptrs) + + data = zeros(Int,ptrs[end]-1) + for patch in 1:n_patches + cells = view(patch_cells,patch) + + # First we push the interior patch cells + for cell in cells + data[ptrs[patch]] = cell + ptrs[patch] += 1 + end + + # Then we push the extra cells in the closure + closure = Set(cells) + for cell in cells + nodes = view(cells_to_nodes,cell) + for node in nodes + nbors = view(nodes_to_cells,node) + for nbor in nbors + if nbor ∉ closure + data[ptrs[patch]] = nbor + push!(closure,nbor) + ptrs[patch] += 1 + end + end + end + end + end + Arrays.rewind_ptrs!(ptrs) + + return Table(data,ptrs) +end diff --git a/src/PatchBasedSmoothers/seq/PatchFESpaces.jl b/src/PatchBasedSmoothers/seq/PatchFESpaces.jl index 930dd77d..4c39be20 100644 --- a/src/PatchBasedSmoothers/seq/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/seq/PatchFESpaces.jl @@ -104,10 +104,11 @@ function PatchFESpace( patches_mask = Fill(false,num_patches(patch_decomposition)) ) cell_dofs_ids = get_cell_dof_ids(space) + patch_cells_overlapped = get_patch_cells_overlapped(patch_decomposition) patch_cell_dofs_ids, num_dofs = generate_patch_cell_dofs_ids( get_grid_topology(patch_decomposition.model), patch_decomposition.patch_cells, - patch_decomposition.patch_cells_overlapped, + patch_cells_overlapped, patch_decomposition.patch_cells_faces_on_boundary, cell_dofs_ids,cell_conformity,patches_mask ) @@ -166,6 +167,11 @@ function FESpaces.get_cell_dof_ids(::SkeletonTriangulation,a::PatchFESpace,trian return lazy_map(Fields.BlockMap(2,[1,2]),plus,minus) end +function FESpaces.get_cell_dof_ids(a::PatchFESpace,trian::PatchClosureTriangulation) + patch_cells = trian.trian.patch_faces + return propagate_patch_dof_ids(a,patch_cells) +end + # scatter dof values function FESpaces.scatter_free_and_dirichlet_values(f::PatchFESpace,free_values,dirichlet_values) @@ -184,7 +190,7 @@ function generate_patch_cell_dofs_ids( cell_conformity, patches_mask ) - patch_cell_dofs_ids = allocate_patch_cell_dofs_ids(patch_cells,cell_dofs_ids) + patch_cell_dofs_ids = allocate_patch_cell_array(patch_cells,cell_dofs_ids;init=Int32(-1)) num_dofs = generate_patch_cell_dofs_ids!( patch_cell_dofs_ids,topology, patch_cells,patch_cells_overlapped, @@ -194,27 +200,6 @@ function generate_patch_cell_dofs_ids( return patch_cell_dofs_ids, num_dofs end -function allocate_patch_cell_dofs_ids(patch_cells,cell_dofs_ids) - cache_cells = array_cache(patch_cells) - cache_cdofs = array_cache(cell_dofs_ids) - - num_overlapped_cells = length(patch_cells.data) - ptrs = Vector{Int}(undef,num_overlapped_cells+1) - ptrs[1] = 1; ncells = 1 - for patch = 1:length(patch_cells) - cells = getindex!(cache_cells,patch_cells,patch) - for cell in cells - current_cell_dof_ids = getindex!(cache_cdofs,cell_dofs_ids,cell) - ptrs[ncells+1] = ptrs[ncells]+length(current_cell_dof_ids) - ncells += 1 - end - end - - @check num_overlapped_cells+1 == ncells - data = Vector{Int}(undef,ptrs[end]-1) - return Gridap.Arrays.Table(data,ptrs) -end - function generate_patch_cell_dofs_ids!( patch_cell_dofs_ids, topology, @@ -246,11 +231,6 @@ function generate_patch_cell_dofs_ids!( return current_dof-1 end -# TO-THINK/STRESS: -# 1. MultiFieldFESpace case? -# 2. FESpaces which are directly defined on physical space? We think this case is covered by -# the fact that we are using a CellConformity instance to rely on ownership info. -# free_dofs_offset : the ID from which we start to assign free DoF IDs upwards # Note: we do not actually need to generate a global numbering for Dirichlet DoFs. We can # tag all as them with -1, as we are always imposing homogenous Dirichlet boundary # conditions, and thus there is no need to address the result of interpolating Dirichlet @@ -391,6 +371,68 @@ function _generate_dof_to_pdof!(dof_to_pdof,Vh,PD,patch_cell_dofs_ids) end end +""" + propagate_patch_dof_ids(patch_space::PatchFESpace,new_patch_cells::Table) + +Propagates the DoF ids of the patch_space to a new set of patch cells given by +a patch-wise Table `new_patch_cells`. +""" +function propagate_patch_dof_ids( + patch_space::PatchFESpace, + new_patch_cells::Table +) + space = patch_space.Vh + patch_decomposition = patch_space.patch_decomposition + patch_cells = get_patch_cells(patch_decomposition) + patch_pcells = get_patch_cells_overlapped(patch_decomposition) + + cell_dof_ids = get_cell_dof_ids(space) + patch_cell_dof_ids = patch_space.patch_cell_dofs_ids + ext_dof_ids = allocate_patch_cell_array(new_patch_cells,cell_dof_ids;init=Int32(-1)) + + new_pcell = 1 + n_patches = length(patch_cells) + for patch in 1:n_patches + cells = view(patch_cells,patch) + pcells = view(patch_pcells,patch) + + # Create local dof to pdof maps + dof_to_pdof = Dict{Int,Int}() + for (cell,pcell) in zip(cells,pcells) + dofs = view(cell_dof_ids,cell) + pdofs = view(patch_cell_dof_ids,pcell) + for (dof,pdof) in zip(dofs,pdofs) + if pdof != -1 + dof_to_pdof[dof] = pdof + end + end + end + + # Propagate dofs to patch extensions + for new_cell in view(new_patch_cells,patch) + dofs = view(cell_dof_ids,new_cell) + pdofs = view(ext_dof_ids,new_pcell) + + pos = findfirst(c -> c == new_cell, cells) + if !isnothing(pos) # Cell is in the patch + pcell = pcells[pos] + pdofs .= view(patch_cell_dof_ids,pcell) + else # Cell is new (not in the patch) + for (ldof,dof) in enumerate(dofs) + if haskey(dof_to_pdof,dof) + pdofs[ldof] = dof_to_pdof[dof] + else + pdofs[ldof] = -1 + end + end + end + new_pcell += 1 + end + end + + return ext_dof_ids +end + # x \in PatchFESpace # y \in SingleFESpace function prolongate!(x,Ph::PatchFESpace,y;dof_ids=LinearIndices(y)) diff --git a/src/PatchBasedSmoothers/seq/PatchTriangulations.jl b/src/PatchBasedSmoothers/seq/PatchTriangulations.jl index 5c5ab3e8..b633f83b 100644 --- a/src/PatchBasedSmoothers/seq/PatchTriangulations.jl +++ b/src/PatchBasedSmoothers/seq/PatchTriangulations.jl @@ -5,7 +5,7 @@ Wrapper around a Triangulation, for patch-based assembly. """ -struct PatchTriangulation{Dc,Dp,A,B,C,D} <: Gridap.Geometry.Triangulation{Dc,Dp} +struct PatchTriangulation{Dc,Dp,A,B,C,D} <: Triangulation{Dc,Dp} trian :: A PD :: B patch_faces :: C @@ -56,7 +56,7 @@ end # Constructors function Geometry.Triangulation(PD::PatchDecomposition) - patch_cells = Gridap.Arrays.Table(PD.patch_cells) + patch_cells = PD.patch_cells trian = Triangulation(PD.model) return PatchTriangulation(trian,PD,patch_cells,nothing) end @@ -144,7 +144,6 @@ function OverlappingBoundaryTriangulation( face_to_bgface::AbstractVector{<:Integer}, face_to_lcell::AbstractVector{<:Integer} ) - D = num_cell_dims(model) topo = get_grid_topology(model) bgface_grid = Grid(ReferenceFE{D-1},model) @@ -195,7 +194,8 @@ function OverlappingFaceToCellGlue( face_to_ftype, cell_to_ctype, cell_to_lface_to_pindex, - ctype_to_lface_to_ftype) + ctype_to_lface_to_ftype + ) end function overlapped_find_local_index( diff --git a/test/_dev/PatchBased/ZeroMeanPatchBasedFESpaces.jl b/test/_dev/PatchBased/ZeroMeanPatchBasedFESpaces.jl index 5b86a5d8..63e97732 100644 --- a/test/_dev/PatchBased/ZeroMeanPatchBasedFESpaces.jl +++ b/test/_dev/PatchBased/ZeroMeanPatchBasedFESpaces.jl @@ -67,7 +67,7 @@ norm(A*x - b) ############################################################################################ -patch_pcells = PD.patch_cells_overlapped +patch_pcells = get_patch_cells_overlapped(PD) pcell_to_pdofs_u = Ph.patch_cell_dofs_ids pcell_to_pdofs_p = Lh.patch_cell_dofs_ids diff --git a/test/_dev/PatchBased/patch_closures.jl b/test/_dev/PatchBased/patch_closures.jl new file mode 100644 index 00000000..2669acb9 --- /dev/null +++ b/test/_dev/PatchBased/patch_closures.jl @@ -0,0 +1,79 @@ +using Gridap +using Gridap.Geometry, Gridap.Arrays + +using GridapSolvers +using GridapSolvers: PatchBasedSmoothers + +function generate_dual_graph( + topo::GridTopology{Dc}, D::Integer = Dc +) where Dc + @assert 0 < D <= Dc + edge_to_face = Geometry.get_faces(topo,D-1,D) + n_faces = Geometry.num_faces(topo,D) + return generate_dual_graph(edge_to_face,n_faces) +end + +# Given a table `edge_to_face`, creates the dual graph `face_to_face`. +function generate_dual_graph( + edge_to_face::Table, + n_faces = maximum(edge_to_face.data) +) + n_edges = length(edge_to_face) + + ptrs = zeros(Int,n_faces+1) + for e in 1:n_edges + faces = view(edge_to_face,e) + if length(faces) > 1 + @assert length(faces) == 2 + f1, f2 = faces + ptrs[f1+1] += 1 + ptrs[f2+1] += 1 + end + end + Arrays.length_to_ptrs!(ptrs) + + data = zeros(Int,ptrs[end]-1) + for e in 1:n_edges + faces = view(edge_to_face,e) + if length(faces) > 1 + f1, f2 = faces + data[ptrs[f1]] = f2 + data[ptrs[f2]] = f1 + ptrs[f1] += 1 + ptrs[f2] += 1 + end + end + Arrays.rewind_ptrs!(ptrs) + + return Table(data,ptrs) +end + +model = CartesianDiscreteModel((0,1,0,1),(2,2)) +topo = get_grid_topology(model) + +PD = PatchDecomposition(model;patch_boundary_style=PatchBasedSmoothers.PatchBoundaryInclude()) + +order = 2 +reffe = ReferenceFE(lagrangian,Float64,order) +Vh = FESpace(model,reffe) +Ph = PatchFESpace(Vh,PD,reffe) + +Ω = Triangulation(model) +Ωp = Triangulation(PD) +Ωc = PatchBasedSmoothers.Closure(PD) + +dΩ = Measure(Ω,2*order) +dΩp = Measure(Ωp,2*order) +dΩc = Measure(Ωc,2*order) + +biform(u,v,dΩ) = ∫(u⋅v)dΩ +a(u,v) = biform(u,v,dΩ) +ap(u,v) = biform(u,v,dΩp) +ac(u,v) = biform(u,v,dΩc) + +A = assemble_matrix(a,Vh,Vh) +Ap = assemble_matrix(ap,Ph,Ph) +Ac = assemble_matrix(ac,Ph,Ph) + + + diff --git a/test/_dev/Vanka/kernel_analysis.jl b/test/_dev/Vanka/kernel_analysis.jl new file mode 100644 index 00000000..89f4ef7a --- /dev/null +++ b/test/_dev/Vanka/kernel_analysis.jl @@ -0,0 +1,70 @@ + +using Gridap +using GridapSolvers +using LinearAlgebra + +using Gridap.ReferenceFEs, Gridap.FESpaces, Gridap.Geometry +using Gridap.Algebra, Gridap.Arrays +using GridapSolvers.PatchBasedSmoothers, GridapSolvers.LinearSolvers +using GridapSolvers.MultilevelTools + +Dc = 2 +model = CartesianDiscreteModel((0,1,0,1),(4,4)) + +order = 2 +reffe_u = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) + +V = TestFESpace(model,reffe_u) +Q = TestFESpace(model,reffe_p,conformity=:L2) +X = MultiFieldFESpace([V,Q]) + +qdegree = 2*order +Ω = Triangulation(model) +dΩ = Measure(Ω,qdegree) + +PD = PatchDecomposition(model) +PD.patch_cells + +ν = 1.e-8 +η = -1.0 +ε = 1.e-4 +Π = LocalProjectionMap(divergence,reffe_p) +#graddiv(u,v,dΩ) = ∫(η*(∇⋅v)⋅Π(u))*dΩ +graddiv(u,v,dΩ) = ∫(η*Π(v)⋅Π(u))*dΩ +lap(u,v,dΩ) = ∫(ν*∇(u)⊙∇(v))*dΩ +mass(u,v,dΩ) = ∫(u*v)*dΩ + +function a((u,p),(v,q),dΩ) + c = lap(u,v,dΩ) + c += ∫((∇⋅v)*p + (∇⋅u)*q)dΩ + if η > 0.0 + c += graddiv(u,v,dΩ) + end + if ε > 0.0 + c += mass(p,q,dΩ) + end + return c +end + +A = assemble_matrix((u,v) -> a(u,v,dΩ),X,X) +x = A\ones(size(A,1)) + +cells = [6,7,10,11] +dof_ids = get_cell_dof_ids(X) +patch_ids = unique(sort(vcat(map(ids -> vcat(ids.array...), dof_ids[cells])...))) + +A_vanka = Matrix(A[patch_ids,patch_ids]) +cond(A_vanka) +x_vanka = A_vanka\randn(size(A_vanka,1)) + +s = VankaSolver(X,PD) +ns = numerical_setup(symbolic_setup(s,A),A) + +for i in 1:10 + x = zeros(size(A,1)) + x_exact = randn(size(A,1)) + b = A*x_exact + solve!(x,ns,b) + println(norm(x-x_exact)) +end From d0914d90ad0c9ca37a7da44d1c88a2998276f19a Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 4 Sep 2024 16:10:28 +1000 Subject: [PATCH 12/47] Minor fixes --- src/PatchBasedSmoothers/seq/VankaSolvers.jl | 11 ++++++--- test/_dev/PatchBased/patch_closures.jl | 27 ++++++++++++++++++++- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/PatchBasedSmoothers/seq/VankaSolvers.jl b/src/PatchBasedSmoothers/seq/VankaSolvers.jl index 16e146ba..6e05fdcc 100644 --- a/src/PatchBasedSmoothers/seq/VankaSolvers.jl +++ b/src/PatchBasedSmoothers/seq/VankaSolvers.jl @@ -9,22 +9,25 @@ struct VankaSolver{A} <: Algebra.LinearSolver end end -function VankaSolver(space::MultiFieldFESpace) +function VankaSolver(space::FESpace) trian = get_triangulation(space) ncells = num_cells(trian) patch_cells = Table(1:ncells,1:ncells+1) return VankaSolver(space,patch_cells) end -function VankaSolver(space::MultiFieldFESpace,patch_decomposition::PatchDecomposition) +function VankaSolver(space::FESpace,patch_decomposition::PatchDecomposition) patch_cells = patch_decomposition.patch_cells return VankaSolver(space,patch_cells) end -function VankaSolver(space::MultiFieldFESpace,patch_cells::Table{<:Integer}) +function VankaSolver(space::FESpace,patch_cells::Table{<:Integer}) + collect_ids(ids::AbstractArray) = ids + collect_ids(ids::ArrayBlock) = vcat(ids.array...) + cell_ids = get_cell_dof_ids(space) patch_ids = map(patch_cells) do cells - ids = vcat([vcat(cell_ids[cell].array...) for cell in cells]...) + ids = vcat([collect_ids(cell_ids[cell]) for cell in cells]...) filter!(x->x>0,ids) sort!(ids) unique!(ids) diff --git a/test/_dev/PatchBased/patch_closures.jl b/test/_dev/PatchBased/patch_closures.jl index 2669acb9..7d5994c4 100644 --- a/test/_dev/PatchBased/patch_closures.jl +++ b/test/_dev/PatchBased/patch_closures.jl @@ -71,9 +71,34 @@ a(u,v) = biform(u,v,dΩ) ap(u,v) = biform(u,v,dΩp) ac(u,v) = biform(u,v,dΩc) -A = assemble_matrix(a,Vh,Vh) +A = assemble_matrix(a,Vh,Vh) Ap = assemble_matrix(ap,Ph,Ph) Ac = assemble_matrix(ac,Ph,Ph) +vanka_PD = PatchDecomposition(model;patch_boundary_style=PatchBasedSmoothers.PatchBoundaryExclude()) +vanka = PatchBasedSmoothers.VankaSolver(Vh,vanka_PD) +vanka_ids = vanka.patch_ids +dof_to_pdof = Ph.dof_to_pdof +patch_cell_ids = get_cell_dof_ids(Ph) +pdof_to_dof = flatten_partition(dof_to_pdof) +for (patch,ids) in enumerate(vanka_ids) + patch_ids = unique(vcat(PatchBasedSmoothers.patch_view(PD,patch_cell_ids,patch)...)) + + perm = sortperm(pdof_to_dof[patch_ids]) + patch_ids = patch_ids[perm] + + println("> Patch $patch") + println(" > Vanka: ",ids) + println(" > Space: ",pdof_to_dof[patch_ids]) + @assert ids == pdof_to_dof[patch_ids] + + A_vanka = A[ids,ids] + A_vanka_bis = Ac[patch_ids,patch_ids] + @assert A_vanka ≈ A_vanka_bis +end + +b(u,v) = ∫(u⋅v)dΩc + ∫(u⋅v)dΩp +B = assemble_matrix(b,Ph,Ph) +@assert B ≈ Ac + Ap From 651f33071890d2c53d50bfa90889b16ac85a96b5 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 4 Sep 2024 16:19:06 +1000 Subject: [PATCH 13/47] Added set_depth! --- src/SolverInterfaces/ConvergenceLogs.jl | 20 ++++++++++++++++++++ src/SolverInterfaces/SolverInterfaces.jl | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/SolverInterfaces/ConvergenceLogs.jl b/src/SolverInterfaces/ConvergenceLogs.jl index 87603b5c..fdc86749 100644 --- a/src/SolverInterfaces/ConvergenceLogs.jl +++ b/src/SolverInterfaces/ConvergenceLogs.jl @@ -62,6 +62,26 @@ end @inline get_tabulation(log::ConvergenceLog) = get_tabulation(log,2) @inline get_tabulation(log::ConvergenceLog,n::Int) = repeat(' ', n + 2*log.depth) +""" + set_depth!(log::ConvergenceLog,depth::Int) + set_depth!(log::LinearSolver,depth::Int) + +Sets the tabulation depth of the convergence log `log` to `depth`. +""" +function set_depth!(log::ConvergenceLog,depth::Int) + log.depth = depth + return log +end + +function set_depth!(solver::Algebra.LinearSolver,depth::Int) + if hasproperty(solver,:log) + set_depth!(solver.log,depth) + end + map(children(solver)) do child + set_depth!(child,depth) + end +end + """ reset!(log::ConvergenceLog{T}) diff --git a/src/SolverInterfaces/SolverInterfaces.jl b/src/SolverInterfaces/SolverInterfaces.jl index 24563838..8b9aa724 100644 --- a/src/SolverInterfaces/SolverInterfaces.jl +++ b/src/SolverInterfaces/SolverInterfaces.jl @@ -14,7 +14,7 @@ include("SolverInfos.jl") export SolverVerboseLevel, SolverConvergenceFlag export SolverTolerances, get_solver_tolerances, set_solver_tolerances! -export ConvergenceLog, init!, update!, finalize!, reset!, print_message +export ConvergenceLog, init!, update!, finalize!, reset!, print_message, set_depth! export SolverInfo From b2c2a9f3f3fdce9a4e8b24ceb2688ecb0f5c84a2 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 6 Sep 2024 09:28:23 +1000 Subject: [PATCH 14/47] Minor --- .../seq/PatchBasedLinearSolvers.jl | 12 ++++++------ src/SolverInterfaces/ConvergenceLogs.jl | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl b/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl index 55476602..99b9873d 100644 --- a/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl +++ b/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl @@ -73,14 +73,14 @@ struct PatchBasedSmootherNumericalSetup{A,B,C,D} <: Gridap.Algebra.NumericalSetu caches :: D end -function assemble_patch_matrices(Ph::PatchFESpace,ap;local_solver=LUSolver()) +function assemble_patch_matrices(Ph::FESpace,ap;local_solver=LUSolver()) assem = SparseMatrixAssembler(Ph,Ph) Ap = assemble_matrix(ap,assem,Ph,Ph) Ap_ns = numerical_setup(symbolic_setup(local_solver,Ap),Ap) return Ap, Ap_ns end -function assemble_patch_matrices(Ph::DistributedPatchFESpace,ap;local_solver=LUSolver()) +function assemble_patch_matrices(Ph::GridapDistributed.DistributedFESpace,ap;local_solver=LUSolver()) u, v = get_trial_fe_basis(Vh), get_fe_basis(Vh) matdata = collect_cell_matrix(Ph,Ph,ap(u,v)) Ap, Ap_ns = map(local_views(Ph),matdata) do Ph, matdata @@ -92,13 +92,13 @@ function assemble_patch_matrices(Ph::DistributedPatchFESpace,ap;local_solver=LUS return Ap, Ap_ns end -function update_patch_matrices!(Ap,Ap_ns,Ph::PatchFESpace,ap) +function update_patch_matrices!(Ap,Ap_ns,Ph::FESpace,ap) assem = SparseMatrixAssembler(Ph,Ph) assemble_matrix!(Ap,assem,Ph,Ph,ap) numerical_setup!(Ap_ns,Ap) end -function update_patch_matrices!(Ap,Ap_ns,Ph::DistributedPatchFESpace,ap) +function update_patch_matrices!(Ap,Ap_ns,Ph::GridapDistributed.DistributedFESpace,ap) u, v = get_trial_fe_basis(Vh), get_fe_basis(Vh) matdata = collect_cell_matrix(Ph,Ph,ap(u,v)) map(Ap, Ap_ns, local_views(Ph), matdata) do Ap, Ap_ns, Ph, matdata @@ -108,13 +108,13 @@ function update_patch_matrices!(Ap,Ap_ns,Ph::DistributedPatchFESpace,ap) end end -function allocate_patch_workvectors(Ph::PatchFESpace,Vh::FESpace) +function allocate_patch_workvectors(Ph::FESpace,Vh::FESpace) rp = zero_free_values(Ph) dxp = zero_free_values(Ph) return rp,dxp end -function allocate_patch_workvectors(Ph::DistributedPatchFESpace,Vh::GridapDistributed.DistributedFESpace) +function allocate_patch_workvectors(Ph::GridapDistributed.DistributedFESpace,Vh::GridapDistributed.DistributedFESpace) rp = zero_free_values(Ph) dxp = zero_free_values(Ph) r = zero_free_values(Vh) diff --git a/src/SolverInterfaces/ConvergenceLogs.jl b/src/SolverInterfaces/ConvergenceLogs.jl index fdc86749..25d7f61e 100644 --- a/src/SolverInterfaces/ConvergenceLogs.jl +++ b/src/SolverInterfaces/ConvergenceLogs.jl @@ -78,7 +78,7 @@ function set_depth!(solver::Algebra.LinearSolver,depth::Int) set_depth!(solver.log,depth) end map(children(solver)) do child - set_depth!(child,depth) + set_depth!(child,depth+2) end end From d137360f4aa32d7c3c41e9dace16ad2d9ba5992b Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 6 Sep 2024 10:11:31 +1000 Subject: [PATCH 15/47] Resolved minor issues when changing triangulations --- src/GridapSolvers.jl | 107 +++++++++--------- .../PatchBasedSmoothers.jl | 2 +- src/PatchBasedSmoothers/seq/PatchClosures.jl | 8 +- .../seq/PatchTriangulations.jl | 4 +- test/_dev/PatchBased/patch_closures.jl | 16 ++- 5 files changed, 78 insertions(+), 59 deletions(-) diff --git a/src/GridapSolvers.jl b/src/GridapSolvers.jl index a6020006..1135ca96 100644 --- a/src/GridapSolvers.jl +++ b/src/GridapSolvers.jl @@ -1,57 +1,58 @@ module GridapSolvers - include("SolverInterfaces/SolverInterfaces.jl") - include("MultilevelTools/MultilevelTools.jl") - include("BlockSolvers/BlockSolvers.jl") - include("PatchBasedSmoothers/PatchBasedSmoothers.jl") - include("LinearSolvers/LinearSolvers.jl") - include("NonlinearSolvers/NonlinearSolvers.jl") - - using GridapSolvers.SolverInterfaces - using GridapSolvers.MultilevelTools - using GridapSolvers.BlockSolvers - using GridapSolvers.LinearSolvers - using GridapSolvers.PatchBasedSmoothers - using GridapSolvers.NonlinearSolvers - - # MultilevelTools - export get_parts, generate_level_parts, generate_subparts - - export ModelHierarchy, CartesianModelHierarchy, P4estCartesianModelHierarchy - export num_levels, get_level, get_level_parts - export get_model, get_model_before_redist - - export FESpaceHierarchy - export get_fe_space, get_fe_space_before_redist - export compute_hierarchy_matrices - - export DistributedGridTransferOperator - export RestrictionOperator, ProlongationOperator - export setup_transfer_operators - - # BlockSolvers - export BlockDiagonalSolver - - # LinearSolvers - export JacobiLinearSolver - export RichardsonSmoother - export SymGaussSeidelSmoother - export GMGLinearSolver - export BlockDiagonalSmoother - - export ConjugateGradientSolver - export IS_GMRESSolver - export IS_MINRESSolver - export IS_SSORSolver - - export CGSolver - export MINRESSolver - export GMRESSolver - export FGMRESSolver - - # PatchBasedSmoothers - export PatchDecomposition - export PatchFESpace - export PatchBasedLinearSolver +include("SolverInterfaces/SolverInterfaces.jl") +include("MultilevelTools/MultilevelTools.jl") +include("BlockSolvers/BlockSolvers.jl") +include("PatchBasedSmoothers/PatchBasedSmoothers.jl") +include("LinearSolvers/LinearSolvers.jl") +include("NonlinearSolvers/NonlinearSolvers.jl") + +using GridapSolvers.SolverInterfaces +using GridapSolvers.MultilevelTools +using GridapSolvers.BlockSolvers +using GridapSolvers.LinearSolvers +using GridapSolvers.PatchBasedSmoothers +using GridapSolvers.NonlinearSolvers + +# MultilevelTools +export get_parts, generate_level_parts, generate_subparts + +export ModelHierarchy, CartesianModelHierarchy, P4estCartesianModelHierarchy +export num_levels, get_level, get_level_parts +export get_model, get_model_before_redist + +export FESpaceHierarchy +export get_fe_space, get_fe_space_before_redist +export compute_hierarchy_matrices + +export DistributedGridTransferOperator +export RestrictionOperator, ProlongationOperator +export setup_transfer_operators + +# BlockSolvers +export BlockDiagonalSolver + +# LinearSolvers +export JacobiLinearSolver +export RichardsonSmoother +export SymGaussSeidelSmoother +export GMGLinearSolver +export BlockDiagonalSmoother + +export ConjugateGradientSolver +export IS_GMRESSolver +export IS_MINRESSolver +export IS_SSORSolver + +export CGSolver +export MINRESSolver +export GMRESSolver +export FGMRESSolver + +# PatchBasedSmoothers +export PatchDecomposition +export PatchFESpace +export PatchBasedLinearSolver +export Closure end diff --git a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl index a44cd594..f9a6f303 100644 --- a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl +++ b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl @@ -11,7 +11,7 @@ using GridapDistributed using GridapSolvers.MultilevelTools -export PatchDecomposition +export PatchDecomposition, Closure export PatchFESpace export PatchBasedLinearSolver, VankaSolver diff --git a/src/PatchBasedSmoothers/seq/PatchClosures.jl b/src/PatchBasedSmoothers/seq/PatchClosures.jl index 9a0269f7..723c094d 100644 --- a/src/PatchBasedSmoothers/seq/PatchClosures.jl +++ b/src/PatchBasedSmoothers/seq/PatchClosures.jl @@ -26,8 +26,12 @@ function Geometry.get_facet_normal(trian::PatchClosureTriangulation) get_facet_normal(trian.trian) end -function Geometry.is_change_possible(strian::PatchClosureTriangulation,ttrian::Triangulation) - return is_change_possible(strian.trian,ttrian) +function Geometry.is_change_possible(strian::PatchClosureTriangulation,ttrian::PatchClosureTriangulation) + return is_change_possible(strian.trian,ttrian.trian) +end + +function Geometry.is_change_possible(strian::PatchTriangulation,ttrian::PatchClosureTriangulation) + return is_change_possible(strian,ttrian.trian) end function Geometry.move_contributions(scell_to_val::AbstractArray,strian::PatchClosureTriangulation) diff --git a/src/PatchBasedSmoothers/seq/PatchTriangulations.jl b/src/PatchBasedSmoothers/seq/PatchTriangulations.jl index b633f83b..949e2910 100644 --- a/src/PatchBasedSmoothers/seq/PatchTriangulations.jl +++ b/src/PatchBasedSmoothers/seq/PatchTriangulations.jl @@ -49,8 +49,8 @@ end # the inverse map mface_to_tface. # I believe this could technically be relaxed in the future, but for now I don't see a # scenario where we would need this. -function Geometry.is_change_possible(strian::PatchTriangulation,ttrian::Triangulation) - return strian === ttrian +function Geometry.is_change_possible(strian::PatchTriangulation,ttrian::PatchTriangulation) + return (strian === ttrian) || (strian.PD === ttrian.PD) end # Constructors diff --git a/test/_dev/PatchBased/patch_closures.jl b/test/_dev/PatchBased/patch_closures.jl index 7d5994c4..b007fc06 100644 --- a/test/_dev/PatchBased/patch_closures.jl +++ b/test/_dev/PatchBased/patch_closures.jl @@ -60,7 +60,7 @@ Ph = PatchFESpace(Vh,PD,reffe) Ω = Triangulation(model) Ωp = Triangulation(PD) -Ωc = PatchBasedSmoothers.Closure(PD) +Ωc = Closure(PD) dΩ = Measure(Ω,2*order) dΩp = Measure(Ωp,2*order) @@ -102,3 +102,17 @@ end b(u,v) = ∫(u⋅v)dΩc + ∫(u⋅v)dΩp B = assemble_matrix(b,Ph,Ph) @assert B ≈ Ac + Ap + +# Multifield + +Xh = MultiFieldFESpace([Vh,Vh]) +Zh = MultiFieldFESpace([Ph,Ph]) + +biform_mf((u1,u2),(v1,v2),dΩ) = ∫(u1⋅v1 + u2⋅v2)dΩ +a_mf(u,v) = biform_mf(u,v,dΩ) +ap_mf(u,v) = biform_mf(u,v,dΩp) +ac_mf(u,v) = biform_mf(u,v,dΩc) + +A = assemble_matrix(a_mf,Xh,Xh) +Ap = assemble_matrix(ap_mf,Zh,Zh) +Ac = assemble_matrix(ac_mf,Zh,Zh) From 7060b01ece23ee3c3ee7cbb85ebf6e716c6f5c8d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 12 Sep 2024 17:01:30 +1000 Subject: [PATCH 16/47] Started re-structuring PatchBased --- .../{seq => }/CoarsePatchDecompositions.jl | 3 +-- ...s.jl => DistributedPatchDecompositions.jl} | 0 ...ESpaces.jl => DistributedPatchFESpaces.jl} | 1 + .../{seq => }/PatchBasedLinearSolvers.jl | 0 .../PatchBasedSmoothers.jl | 24 +++++++++---------- .../{seq => }/PatchClosures.jl | 0 .../{seq => }/PatchDecompositions.jl | 13 ++++++++++ .../{seq => }/PatchFESpaces.jl | 13 +++------- .../{seq => }/PatchMultiFieldFESpaces.jl | 0 .../{seq => }/PatchTransferOperators.jl | 0 .../{seq => }/PatchTriangulations.jl | 0 .../{seq => }/VankaSolvers.jl | 0 .../{seq => }/ZeroMeanPatchFESpaces.jl | 0 src/SolverInterfaces/ConvergenceLogs.jl | 2 +- src/SolverInterfaces/SolverInfos.jl | 9 +++++-- src/SolverInterfaces/SolverTolerances.jl | 4 ++-- test/_dev/PatchBased/patch_closures.jl | 3 +++ 17 files changed, 43 insertions(+), 29 deletions(-) rename src/PatchBasedSmoothers/{seq => }/CoarsePatchDecompositions.jl (94%) rename src/PatchBasedSmoothers/{mpi/PatchDecompositions.jl => DistributedPatchDecompositions.jl} (100%) rename src/PatchBasedSmoothers/{mpi/PatchFESpaces.jl => DistributedPatchFESpaces.jl} (99%) rename src/PatchBasedSmoothers/{seq => }/PatchBasedLinearSolvers.jl (100%) rename src/PatchBasedSmoothers/{seq => }/PatchClosures.jl (100%) rename src/PatchBasedSmoothers/{seq => }/PatchDecompositions.jl (98%) rename src/PatchBasedSmoothers/{seq => }/PatchFESpaces.jl (97%) rename src/PatchBasedSmoothers/{seq => }/PatchMultiFieldFESpaces.jl (100%) rename src/PatchBasedSmoothers/{seq => }/PatchTransferOperators.jl (100%) rename src/PatchBasedSmoothers/{seq => }/PatchTriangulations.jl (100%) rename src/PatchBasedSmoothers/{seq => }/VankaSolvers.jl (100%) rename src/PatchBasedSmoothers/{seq => }/ZeroMeanPatchFESpaces.jl (100%) diff --git a/src/PatchBasedSmoothers/seq/CoarsePatchDecompositions.jl b/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl similarity index 94% rename from src/PatchBasedSmoothers/seq/CoarsePatchDecompositions.jl rename to src/PatchBasedSmoothers/CoarsePatchDecompositions.jl index d62bfbb6..669d0cd0 100644 --- a/src/PatchBasedSmoothers/seq/CoarsePatchDecompositions.jl +++ b/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl @@ -11,8 +11,7 @@ function CoarsePatchDecomposition( patch_cells_overlapped = compute_patch_overlapped_cells(patch_cells) patch_facets = get_coarse_patch_facets(model, patch_cells) patch_cells_faces_on_boundary = compute_patch_cells_faces_on_boundary( - model, patch_cells, patch_cells_overlapped, - patch_facets, patch_boundary_style, boundary_tag_names + model, patch_cells, patch_facets, patch_boundary_style, boundary_tag_names ) return PatchDecomposition{Dc,Dc,Dp}( diff --git a/src/PatchBasedSmoothers/mpi/PatchDecompositions.jl b/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl similarity index 100% rename from src/PatchBasedSmoothers/mpi/PatchDecompositions.jl rename to src/PatchBasedSmoothers/DistributedPatchDecompositions.jl diff --git a/src/PatchBasedSmoothers/mpi/PatchFESpaces.jl b/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl similarity index 99% rename from src/PatchBasedSmoothers/mpi/PatchFESpaces.jl rename to src/PatchBasedSmoothers/DistributedPatchFESpaces.jl index 892b8203..a34150fa 100644 --- a/src/PatchBasedSmoothers/mpi/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl @@ -1,4 +1,5 @@ + const DistributedPatchFESpace = GridapDistributed.DistributedSingleFieldFESpace{<:AbstractVector{<:PatchFESpace}} function PatchFESpace( diff --git a/src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl b/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl similarity index 100% rename from src/PatchBasedSmoothers/seq/PatchBasedLinearSolvers.jl rename to src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl diff --git a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl index f9a6f303..fb164ef5 100644 --- a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl +++ b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl @@ -19,21 +19,21 @@ export PatchProlongationOperator, PatchRestrictionOperator export setup_patch_prolongation_operators, setup_patch_restriction_operators # Geometry -include("seq/PatchDecompositions.jl") -include("mpi/PatchDecompositions.jl") -include("seq/PatchTriangulations.jl") -include("seq/PatchClosures.jl") -include("seq/CoarsePatchDecompositions.jl") +include("PatchDecompositions.jl") +include("DistributedPatchDecompositions.jl") +include("PatchTriangulations.jl") +include("PatchClosures.jl") +include("CoarsePatchDecompositions.jl") # FESpaces -include("seq/PatchFESpaces.jl") -include("mpi/PatchFESpaces.jl") -include("seq/ZeroMeanPatchFESpaces.jl") -include("seq/PatchMultiFieldFESpaces.jl") +include("PatchFESpaces.jl") +include("DistributedPatchFESpaces.jl") +include("ZeroMeanPatchFESpaces.jl") +include("PatchMultiFieldFESpaces.jl") # Solvers -include("seq/PatchBasedLinearSolvers.jl") -include("seq/PatchTransferOperators.jl") -include("seq/VankaSolvers.jl") +include("PatchBasedLinearSolvers.jl") +include("PatchTransferOperators.jl") +include("VankaSolvers.jl") end \ No newline at end of file diff --git a/src/PatchBasedSmoothers/seq/PatchClosures.jl b/src/PatchBasedSmoothers/PatchClosures.jl similarity index 100% rename from src/PatchBasedSmoothers/seq/PatchClosures.jl rename to src/PatchBasedSmoothers/PatchClosures.jl diff --git a/src/PatchBasedSmoothers/seq/PatchDecompositions.jl b/src/PatchBasedSmoothers/PatchDecompositions.jl similarity index 98% rename from src/PatchBasedSmoothers/seq/PatchDecompositions.jl rename to src/PatchBasedSmoothers/PatchDecompositions.jl index 5a0b88ee..6760656f 100644 --- a/src/PatchBasedSmoothers/seq/PatchDecompositions.jl +++ b/src/PatchBasedSmoothers/PatchDecompositions.jl @@ -153,6 +153,19 @@ function allocate_patch_cell_array( return Arrays.Table(data,ptrs) end +function allocate_patch_cell_array( + patch_cells::Table, cell_to_data::AbstractVector{<:AbstractVector{T}}; init = zero(T) +) where T + ptrs = zeros(Int,length(patch_cells.data)+1) + ptrs[1] = 1 + for (pcell,cell) in enumerate(patch_cells.data) + n = length(cell_to_data[cell]) + ptrs[pcell+1] = ptrs[pcell] + n + end + data = fill(init,ptrs[end]-1) + return Arrays.Table(data,ptrs) +end + # patch_cell_faces_on_boundary :: # [Df][overlapped cell][lface] -> Face is boundary of the patch function compute_patch_cells_faces_on_boundary( diff --git a/src/PatchBasedSmoothers/seq/PatchFESpaces.jl b/src/PatchBasedSmoothers/PatchFESpaces.jl similarity index 97% rename from src/PatchBasedSmoothers/seq/PatchFESpaces.jl rename to src/PatchBasedSmoothers/PatchFESpaces.jl index 4c39be20..af5f674b 100644 --- a/src/PatchBasedSmoothers/seq/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/PatchFESpaces.jl @@ -258,7 +258,7 @@ function generate_patch_cell_dofs_ids!( else g2l = Dict{Int,Int}() Dc = length(patch_cells_faces_on_boundary) - d_to_cell_to_dface = [Gridap.Geometry.get_faces(topology,Dc,d) for d in 0:Dc-1] + d_to_cell_to_dface = [Gridap.Geometry.get_faces(topology,Dc,d) for d in 0:Dc] # Loop over cells of the patch (local_cell_id_within_patch) for (lpatch_cell,patch_cell) in enumerate(patch_cells) @@ -268,15 +268,14 @@ function generate_patch_cell_dofs_ids!( current_patch_cell_dofs_ids = view(patch_cell_dofs_ids.data,s:e) ctype = cell_conformity.cell_ctype[patch_cell] - # 1) DoFs belonging to faces (Df < Dc) face_offset = 0 - for d = 0:Dc-1 + for d = 0:Dc num_cell_faces = length(d_to_cell_to_dface[d+1][patch_cell]) for lface in 1:num_cell_faces for ldof in cell_conformity.ctype_lface_own_ldofs[ctype][face_offset+lface] gdof = global_space_cell_dofs_ids[patch_cell][ldof] - face_in_patch_boundary = patch_cells_faces_on_boundary[d+1][cell_overlapped_mesh][lface] + face_in_patch_boundary = (d != Dc) && patch_cells_faces_on_boundary[d+1][cell_overlapped_mesh][lface] dof_is_dirichlet = (gdof < 0) if face_in_patch_boundary || dof_is_dirichlet current_patch_cell_dofs_ids[ldof] = -1 @@ -291,12 +290,6 @@ function generate_patch_cell_dofs_ids!( end face_offset += cell_conformity.d_ctype_num_dfaces[d+1][ctype] end - - # 2) Interior DoFs - for ldof in cell_conformity.ctype_lface_own_ldofs[ctype][face_offset+1] - current_patch_cell_dofs_ids[ldof] = free_dofs_offset - free_dofs_offset += 1 - end end end return free_dofs_offset diff --git a/src/PatchBasedSmoothers/seq/PatchMultiFieldFESpaces.jl b/src/PatchBasedSmoothers/PatchMultiFieldFESpaces.jl similarity index 100% rename from src/PatchBasedSmoothers/seq/PatchMultiFieldFESpaces.jl rename to src/PatchBasedSmoothers/PatchMultiFieldFESpaces.jl diff --git a/src/PatchBasedSmoothers/seq/PatchTransferOperators.jl b/src/PatchBasedSmoothers/PatchTransferOperators.jl similarity index 100% rename from src/PatchBasedSmoothers/seq/PatchTransferOperators.jl rename to src/PatchBasedSmoothers/PatchTransferOperators.jl diff --git a/src/PatchBasedSmoothers/seq/PatchTriangulations.jl b/src/PatchBasedSmoothers/PatchTriangulations.jl similarity index 100% rename from src/PatchBasedSmoothers/seq/PatchTriangulations.jl rename to src/PatchBasedSmoothers/PatchTriangulations.jl diff --git a/src/PatchBasedSmoothers/seq/VankaSolvers.jl b/src/PatchBasedSmoothers/VankaSolvers.jl similarity index 100% rename from src/PatchBasedSmoothers/seq/VankaSolvers.jl rename to src/PatchBasedSmoothers/VankaSolvers.jl diff --git a/src/PatchBasedSmoothers/seq/ZeroMeanPatchFESpaces.jl b/src/PatchBasedSmoothers/ZeroMeanPatchFESpaces.jl similarity index 100% rename from src/PatchBasedSmoothers/seq/ZeroMeanPatchFESpaces.jl rename to src/PatchBasedSmoothers/ZeroMeanPatchFESpaces.jl diff --git a/src/SolverInterfaces/ConvergenceLogs.jl b/src/SolverInterfaces/ConvergenceLogs.jl index 25d7f61e..17839d9e 100644 --- a/src/SolverInterfaces/ConvergenceLogs.jl +++ b/src/SolverInterfaces/ConvergenceLogs.jl @@ -142,7 +142,7 @@ function finalize!(log::ConvergenceLog{T},r::T) where T msg = @sprintf("Iterations: %3i - Residuals: %.2e, %.2e ", log.num_iters, r, r_rel) println(t,msg) if log.verbose > SOLVER_VERBOSE_LOW - footer = " Exiting $(log.name) solver " + footer = " Exiting $(log.name) solver " println(t,rpad(string(repeat('-',15),footer),55,'-')) end end diff --git a/src/SolverInterfaces/SolverInfos.jl b/src/SolverInterfaces/SolverInfos.jl index 9ceae76b..49cb7b98 100644 --- a/src/SolverInterfaces/SolverInfos.jl +++ b/src/SolverInterfaces/SolverInfos.jl @@ -4,10 +4,15 @@ struct SolverInfo data :: Dict{Symbol, Any} end -SolverInfo(name::String) = SolverInfo(name,Dict{Symbol, Any}()) +SolverInfo(name::String;kwargs...) = SolverInfo(name,Dict{Symbol,Any}(kwargs)) function get_solver_info(solver::Gridap.Algebra.LinearSolver) - return SolverInfo(string(typeof(solver))) + info = SolverInfo(string(typeof(solver))) + if hasproperty(solver,:log) + add_tolerance_info!(info,solver.log) + add_convergence_info!(info,solver.log) + end + return info end function merge_info!(a::SolverInfo,b::SolverInfo;prefix=b.name) diff --git a/src/SolverInterfaces/SolverTolerances.jl b/src/SolverInterfaces/SolverTolerances.jl index dfe4aaf2..f3ac835d 100644 --- a/src/SolverInterfaces/SolverTolerances.jl +++ b/src/SolverInterfaces/SolverTolerances.jl @@ -114,7 +114,7 @@ end Returns `true` if the solver has finished, `false` otherwise. """ -function finished(tols::SolverTolerances,niter,e_a,e_r) :: Bool +@inline function finished(tols::SolverTolerances,niter,e_a,e_r) :: Bool return (niter >= tols.maxiter) || converged(tols,niter,e_a,e_r) end @@ -123,7 +123,7 @@ end Returns `true` if the solver has converged, `false` otherwise. """ -function converged(tols::SolverTolerances,niter,e_a,e_r) :: Bool +@inline function converged(tols::SolverTolerances,niter,e_a,e_r) :: Bool return (e_r < tols.rtol) || (e_a < tols.atol) end diff --git a/test/_dev/PatchBased/patch_closures.jl b/test/_dev/PatchBased/patch_closures.jl index b007fc06..82014750 100644 --- a/test/_dev/PatchBased/patch_closures.jl +++ b/test/_dev/PatchBased/patch_closures.jl @@ -116,3 +116,6 @@ ac_mf(u,v) = biform_mf(u,v,dΩc) A = assemble_matrix(a_mf,Xh,Xh) Ap = assemble_matrix(ap_mf,Zh,Zh) Ac = assemble_matrix(ac_mf,Zh,Zh) + + + From fac43c2a99e7abe97a419643fd8ab5ded4d67233 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 18 Sep 2024 16:11:23 +1000 Subject: [PATCH 17/47] patch-wise patch solvers --- src/LinearSolvers/CallbackSolver.jl | 52 ++++++ src/LinearSolvers/LinearSolvers.jl | 4 + src/MultilevelTools/FESpaceHierarchies.jl | 25 +++ ...rOperators.jl => GridTransferOperators.jl} | 0 src/MultilevelTools/MultilevelTools.jl | 2 +- .../CoarsePatchDecompositions.jl | 3 +- .../PatchBasedSmoothers.jl | 1 + .../PatchDecompositions.jl | 11 ++ src/PatchBasedSmoothers/PatchFESpaces.jl | 119 ++++++++----- src/PatchBasedSmoothers/PatchSolvers.jl | 164 ++++++++++++++++++ test/_dev/PatchBased/PatchSolvers.jl | 80 +++++++++ 11 files changed, 419 insertions(+), 42 deletions(-) create mode 100644 src/LinearSolvers/CallbackSolver.jl rename src/MultilevelTools/{DistributedGridTransferOperators.jl => GridTransferOperators.jl} (100%) create mode 100644 src/PatchBasedSmoothers/PatchSolvers.jl create mode 100644 test/_dev/PatchBased/PatchSolvers.jl diff --git a/src/LinearSolvers/CallbackSolver.jl b/src/LinearSolvers/CallbackSolver.jl new file mode 100644 index 00000000..87eca8d0 --- /dev/null +++ b/src/LinearSolvers/CallbackSolver.jl @@ -0,0 +1,52 @@ + +struct CallbackSolver{A,B} <: Algebra.LinearSolver + solver :: A + callback :: B + + function CallbackSolver(solver::LinearSolver,callback::Function) + A = typeof(solver) + B = typeof(callback) + new{A,B}(solver,callback) + end +end + +struct CallbackSolverSS{A,B} <: Algebra.SymbolicSetup + solver :: A + ss :: B +end + +function Algebra.symbolic_setup(solver::CallbackSolver,mat::AbstractMatrix) + ss = Algebra.symbolic_setup(solver.solver,mat) + return CallbackSolverSS(solver,ss) +end + +struct CallbackSolverNS{A,B} <: Algebra.NumericalSetup + solver :: A + ns :: B +end + +function Algebra.numerical_setup(ss::CallbackSolverSS,mat::AbstractMatrix) + ns = Algebra.numerical_setup(ss.ss,mat) + return CallbackSolverNS(ss.solver,ns) +end + +function Algebra.numerical_setup(ss::CallbackSolverSS,mat::AbstractMatrix,x::AbstractVector) + ns = Algebra.numerical_setup(ss.ss,mat,x) + return CallbackSolverNS(ss.solver,ns) +end + +function Algebra.numerical_setup!(ns::CallbackSolverNS,mat::AbstractMatrix) + Algebra.numerical_setup!(ns.ns,mat) + return ns +end + +function Algebra.numerical_setup!(ns::CallbackSolverNS,mat::AbstractMatrix,x::AbstractVector) + Algebra.numerical_setup!(ns.ns,mat,x) + return ns +end + +function Algebra.solve!(x::AbstractVector,ns::CallbackSolverNS,b::AbstractVector) + solve!(x,ns.ns,b) + ns.solver.callback(x) + return x +end diff --git a/src/LinearSolvers/LinearSolvers.jl b/src/LinearSolvers/LinearSolvers.jl index 371df4e4..43b0658d 100644 --- a/src/LinearSolvers/LinearSolvers.jl +++ b/src/LinearSolvers/LinearSolvers.jl @@ -26,6 +26,8 @@ export BlockDiagonalSmoother export SchurComplementSolver export SchwarzLinearSolver +export CallbackSolver + # Wrappers for IterativeSolvers.jl export IS_ConjugateGradientSolver export IS_GMRESSolver @@ -59,4 +61,6 @@ include("SchurComplementSolvers.jl") include("MatrixSolvers.jl") include("SchwarzLinearSolvers.jl") +include("CallbackSolver.jl") + end \ No newline at end of file diff --git a/src/MultilevelTools/FESpaceHierarchies.jl b/src/MultilevelTools/FESpaceHierarchies.jl index cd7025a3..a38bfd60 100644 --- a/src/MultilevelTools/FESpaceHierarchies.jl +++ b/src/MultilevelTools/FESpaceHierarchies.jl @@ -144,6 +144,31 @@ function Gridap.MultiField.MultiFieldFESpace(spaces::Vector{<:HierarchicalArray} end end +# Constant FESpaces + +function FESpaces.ConstantFESpace(mh::ModelHierarchy) + map(mh) do mhl + ConstantFESpace(mhl) + end +end + +function FESpaces.ConstantFESpace(mh::MultilevelTools.ModelHierarchyLevel) + reffe = ReferenceFE(lagrangian,Float64,0) + if has_redistribution(mh) + cparts, _ = get_old_and_new_parts(mh.red_glue,Val(false)) + Vh = i_am_in(cparts) ? ConstantFESpace(get_model_before_redist(mh)) : nothing + Vh_red = ConstantFESpace(get_model(mh)) + cell_conformity = i_am_in(cparts) ? _cell_conformity(get_model_before_redist(mh),reffe) : nothing + cell_conformity_red = _cell_conformity(get_model(mh),reffe) + else + Vh = ConstantFESpace(get_model(mh)) + Vh_red = nothing + cell_conformity = _cell_conformity(get_model(mh),reffe) + cell_conformity_red = nothing + end + return FESpaceHierarchyLevel(mh.level,Vh,Vh_red,cell_conformity,cell_conformity_red,mh) +end + # Computing system matrices function compute_hierarchy_matrices( diff --git a/src/MultilevelTools/DistributedGridTransferOperators.jl b/src/MultilevelTools/GridTransferOperators.jl similarity index 100% rename from src/MultilevelTools/DistributedGridTransferOperators.jl rename to src/MultilevelTools/GridTransferOperators.jl diff --git a/src/MultilevelTools/MultilevelTools.jl b/src/MultilevelTools/MultilevelTools.jl index 5fbb59a5..4ef8c95a 100644 --- a/src/MultilevelTools/MultilevelTools.jl +++ b/src/MultilevelTools/MultilevelTools.jl @@ -51,7 +51,7 @@ include("RefinementTools.jl") include("ModelHierarchies.jl") include("FESpaceHierarchies.jl") include("LocalProjectionMaps.jl") -include("DistributedGridTransferOperators.jl") +include("GridTransferOperators.jl") include("MultiFieldTransferOperators.jl") end \ No newline at end of file diff --git a/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl b/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl index 669d0cd0..69547f94 100644 --- a/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl +++ b/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl @@ -8,14 +8,13 @@ function CoarsePatchDecomposition( glue = Gridap.Adaptivity.get_adaptivity_glue(model) patch_cells = glue.o2n_faces_map - patch_cells_overlapped = compute_patch_overlapped_cells(patch_cells) patch_facets = get_coarse_patch_facets(model, patch_cells) patch_cells_faces_on_boundary = compute_patch_cells_faces_on_boundary( model, patch_cells, patch_facets, patch_boundary_style, boundary_tag_names ) return PatchDecomposition{Dc,Dc,Dp}( - model, patch_cells, patch_cells_overlapped, patch_cells_faces_on_boundary + model, patch_cells, patch_cells_faces_on_boundary, patch_boundary_style ) end diff --git a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl index fb164ef5..9a7b7675 100644 --- a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl +++ b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl @@ -35,5 +35,6 @@ include("PatchMultiFieldFESpaces.jl") include("PatchBasedLinearSolvers.jl") include("PatchTransferOperators.jl") include("VankaSolvers.jl") +include("PatchSolvers.jl") end \ No newline at end of file diff --git a/src/PatchBasedSmoothers/PatchDecompositions.jl b/src/PatchBasedSmoothers/PatchDecompositions.jl index 6760656f..5e736469 100644 --- a/src/PatchBasedSmoothers/PatchDecompositions.jl +++ b/src/PatchBasedSmoothers/PatchDecompositions.jl @@ -128,6 +128,17 @@ function patch_reindex(PD::PatchDecomposition,cell_to_data) return pcell_to_data end +function patch_extend(PD::PatchDecomposition,patch_to_data) + pcell_to_patch = fill(0,num_cells(PD)) + patch_offsets = get_patch_cell_offsets(PD) + for patch in 1:num_patches(PD) + pcell_to_patch[patch_offsets[patch]:patch_offsets[patch+1]-1] .= patch + end + + pcell_to_data = lazy_map(Reindex(patch_to_data),pcell_to_patch) + return pcell_to_data +end + """ allocate_patch_cell_array(PD::PatchDecomposition,cell_to_data::Table{T};init=zero(T)) diff --git a/src/PatchBasedSmoothers/PatchFESpaces.jl b/src/PatchBasedSmoothers/PatchFESpaces.jl index af5f674b..54a2b26a 100644 --- a/src/PatchBasedSmoothers/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/PatchFESpaces.jl @@ -106,11 +106,10 @@ function PatchFESpace( cell_dofs_ids = get_cell_dof_ids(space) patch_cells_overlapped = get_patch_cells_overlapped(patch_decomposition) patch_cell_dofs_ids, num_dofs = generate_patch_cell_dofs_ids( - get_grid_topology(patch_decomposition.model), patch_decomposition.patch_cells, patch_cells_overlapped, patch_decomposition.patch_cells_faces_on_boundary, - cell_dofs_ids,cell_conformity,patches_mask + cell_dofs_ids,cell_conformity;patches_mask ) dof_to_pdof = generate_dof_to_pdof(space,patch_decomposition,patch_cell_dofs_ids) return PatchFESpace(space,patch_decomposition,num_dofs,patch_cell_dofs_ids,dof_to_pdof) @@ -182,72 +181,71 @@ end # Construction of the patch cell dofs ids function generate_patch_cell_dofs_ids( - topology, patch_cells, patch_cells_overlapped, patch_cells_faces_on_boundary, cell_dofs_ids, - cell_conformity, - patches_mask + cell_conformity::CellConformity; + patches_mask = Fill(false,length(patch_cells)), + numbering = :global ) + @assert numbering in [:global,:local] patch_cell_dofs_ids = allocate_patch_cell_array(patch_cells,cell_dofs_ids;init=Int32(-1)) num_dofs = generate_patch_cell_dofs_ids!( - patch_cell_dofs_ids,topology, + patch_cell_dofs_ids, patch_cells,patch_cells_overlapped, patch_cells_faces_on_boundary, - cell_dofs_ids,cell_conformity,patches_mask + cell_dofs_ids,cell_conformity; + patches_mask,numbering ) return patch_cell_dofs_ids, num_dofs end function generate_patch_cell_dofs_ids!( patch_cell_dofs_ids, - topology, patch_cells, patch_cells_overlapped, patch_cells_faces_on_boundary, cell_dofs_ids, - cell_conformity, - patches_mask + cell_conformity::CellConformity; + patches_mask = Fill(false,length(patch_cells)), + numbering = :global ) - cache = array_cache(patch_cells) - num_patches = length(patch_cells) - current_dof = 1 - for patch = 1:num_patches - current_patch_cells = getindex!(cache,patch_cells,patch) - current_dof = generate_patch_cell_dofs_ids!( + @assert numbering in [:global,:local] + dof_offset = 1 + for patch = 1:length(patch_cells) + current_patch_cells = view(patch_cells,patch) + dof_offset = generate_patch_cell_dofs_ids!( patch_cell_dofs_ids, - topology, - patch, - current_patch_cells, - patch_cells_overlapped, + patch,current_patch_cells,patch_cells_overlapped, patch_cells_faces_on_boundary, - cell_dofs_ids, - cell_conformity; - free_dofs_offset=current_dof, + cell_dofs_ids,cell_conformity; + dof_offset=dof_offset, mask=patches_mask[patch] ) + if numbering == :local + dof_offset = 1 + end end - return current_dof-1 + return dof_offset-1 end -# Note: we do not actually need to generate a global numbering for Dirichlet DoFs. We can -# tag all as them with -1, as we are always imposing homogenous Dirichlet boundary -# conditions, and thus there is no need to address the result of interpolating Dirichlet -# Data into the FE space. +# Note: We do not actually need to generate a global numbering for Dirichlet DoFs. We can +# tag all as them with -1, as we are always imposing homogenous Dirichlet boundary +# conditions, and thus there is no need to address the result of interpolating Dirichlet +# Data into the FE space. function generate_patch_cell_dofs_ids!( patch_cell_dofs_ids, - topology, patch::Integer, patch_cells::AbstractVector{<:Integer}, patch_cells_overlapped::Gridap.Arrays.Table, patch_cells_faces_on_boundary, global_space_cell_dofs_ids, - cell_conformity; - free_dofs_offset=1, + cell_conformity::CellConformity; + dof_offset=1, mask=false ) - o = patch_cells_overlapped.ptrs[patch] + o = patch_cells_overlapped.ptrs[patch] if mask for lpatch_cell = 1:length(patch_cells) cell_overlapped_mesh = patch_cells_overlapped.data[o+lpatch_cell-1] @@ -258,7 +256,6 @@ function generate_patch_cell_dofs_ids!( else g2l = Dict{Int,Int}() Dc = length(patch_cells_faces_on_boundary) - d_to_cell_to_dface = [Gridap.Geometry.get_faces(topology,Dc,d) for d in 0:Dc] # Loop over cells of the patch (local_cell_id_within_patch) for (lpatch_cell,patch_cell) in enumerate(patch_cells) @@ -270,8 +267,8 @@ function generate_patch_cell_dofs_ids!( face_offset = 0 for d = 0:Dc - num_cell_faces = length(d_to_cell_to_dface[d+1][patch_cell]) - for lface in 1:num_cell_faces + n_dfaces = cell_conformity.d_ctype_num_dfaces[d+1][ctype] + for lface in 1:n_dfaces for ldof in cell_conformity.ctype_lface_own_ldofs[ctype][face_offset+lface] gdof = global_space_cell_dofs_ids[patch_cell][ldof] @@ -282,9 +279,9 @@ function generate_patch_cell_dofs_ids!( elseif gdof in keys(g2l) current_patch_cell_dofs_ids[ldof] = g2l[gdof] else - g2l[gdof] = free_dofs_offset - current_patch_cell_dofs_ids[ldof] = free_dofs_offset - free_dofs_offset += 1 + g2l[gdof] = dof_offset + current_patch_cell_dofs_ids[ldof] = dof_offset + dof_offset += 1 end end end @@ -292,7 +289,7 @@ function generate_patch_cell_dofs_ids!( end end end - return free_dofs_offset + return dof_offset end function generate_dof_to_pdof(Vh,PD,patch_cell_dofs_ids) @@ -364,6 +361,50 @@ function _generate_dof_to_pdof!(dof_to_pdof,Vh,PD,patch_cell_dofs_ids) end end +function generate_pdof_to_dof( + patch_decomposition::PatchDecomposition, + cell_dof_ids::Table{Ti}, + patch_cell_lids::Table{Ti} +) where Ti <: Integer + + n_patches = num_patches(patch_decomposition) + patch_cells = get_patch_cells(patch_decomposition) + + ptrs = fill(0,n_patches+1) + for patch in 1:n_patches + cell_lids = patch_view(patch_decomposition,patch_cell_lids,patch) + ptrs[patch+1] = maximum(map(maximum,cell_lids)) + end + PartitionedArrays.length_to_ptrs!(ptrs) + + data = fill(0,ptrs[end]-1) + for (patch,cells) in enumerate(patch_cells) + cell_lids = patch_view(patch_decomposition,patch_cell_lids,patch) + for (lcell,cell) in enumerate(cells) + dofs = view(cell_dof_ids,cell) + pdofs = view(cell_lids,lcell) + for (ldof,dof) in zip(pdofs,dofs) + if ldof > 0 + data[ptrs[patch]+ldof-1] = dof + end + end + end + end + + return Arrays.Table(data,ptrs) +end + +# TODO: Just For lagrange multipliers, fiz this better +function generate_pdof_to_dof( + patch_decomposition::PatchDecomposition, + cell_dof_ids::Fill, + patch_cell_lids::Table{Ti} +) where Ti <: Integer + ptrs = collect(1:num_patches(patch_decomposition)+1) + data = collect(Fill(1,num_patches(patch_decomposition))) + return Arrays.Table(data,ptrs) +end + """ propagate_patch_dof_ids(patch_space::PatchFESpace,new_patch_cells::Table) diff --git a/src/PatchBasedSmoothers/PatchSolvers.jl b/src/PatchBasedSmoothers/PatchSolvers.jl new file mode 100644 index 00000000..39960241 --- /dev/null +++ b/src/PatchBasedSmoothers/PatchSolvers.jl @@ -0,0 +1,164 @@ + +struct PatchSolver{A,B,C,D,E} <: Algebra.LinearSolver + space::A + patch_decomposition::B + patch_ids::C + patch_cell_lids::D + biform::E +end + +function PatchSolver( + space::FESpace,patch_decomposition::PatchDecomposition,biform,reffe;conformity=nothing +) + cell_conformity = MultilevelTools._cell_conformity( + get_background_model(get_triangulation(space)),reffe;conformity + ) + return PatchSolver(space,patch_decomposition,biform,cell_conformity) +end + +function PatchSolver( + space::FESpace,patch_decomposition::PatchDecomposition,biform,cell_conformity::CellConformity +) + cell_dof_ids = get_cell_dof_ids(space) + patch_cells = get_patch_cells(patch_decomposition) + patch_cells_overlapped = get_patch_cells_overlapped(patch_decomposition) + + patch_cell_lids, _ = generate_patch_cell_dofs_ids( + patch_cells,patch_cells_overlapped, + patch_decomposition.patch_cells_faces_on_boundary, + cell_dof_ids,cell_conformity;numbering=:local + ) + patch_ids = generate_pdof_to_dof( + patch_decomposition,cell_dof_ids,patch_cell_lids + ) + return PatchSolver(space,patch_decomposition,patch_ids,patch_cell_lids,biform) +end + +function PatchSolver( + space::MultiFieldFESpace,patch_decomposition::PatchDecomposition,biform,reffes;kwargs... +) + solvers = map((Si,reffe)->PatchSolver(Si,patch_decomposition,biform,reffe;kwargs...),space,reffes) + field_to_patch_cell_lids = map(s -> s.patch_cell_lids ,solvers) + field_to_patch_ids = map(s -> s.patch_ids ,solvers) + field_to_ndofs = map(s -> num_free_dofs(s), space) + + patch_cell_lids, patch_ids = block_patch_ids(patch_decomposition,field_to_patch_cell_lids,field_to_patch_ids,field_to_ndofs) + return PatchSolver(space,patch_decomposition,patch_ids,patch_cell_lids,biform) +end + +function compute_patch_offsets( + patch_decomposition::PatchDecomposition, + field_to_patch_ids::Vector +) + nfields = length(field_to_patch_ids) + npatches = num_patches(patch_decomposition) + + offsets = zeros(Int,(nfields,npatches)) + for i in 1:(nfields-1) + offsets[i+1,:] .= offsets[i,:] .+ map(length,field_to_patch_ids[i]) + end + + return offsets +end + +function block_patch_ids( + patch_decomposition::PatchDecomposition, + field_to_patch_cell_lids::Vector, + field_to_patch_ids::Vector, + field_to_ndofs::Vector +) + offsets = compute_patch_offsets(patch_decomposition,field_to_patch_ids) + nfields = length(field_to_patch_ids) + npatches = num_patches(patch_decomposition) + + field_offsets = zeros(Int,nfields) + for i in 1:(nfields-1) + field_offsets[i+1] = field_offsets[i] + field_to_ndofs[i] + end + + block_cell_lids = Any[] + block_ids = Any[] + for i in 1:nfields + patch_cell_lids_i = field_to_patch_cell_lids[i] + patch_ids_i = field_to_patch_ids[i] + if i == 1 + push!(block_cell_lids,patch_cell_lids_i) + push!(block_ids,patch_ids_i) + else + offsets_i = Int32.(offsets[i,:]) + pcell_to_offsets = patch_extend(patch_decomposition,offsets_i) + patch_cell_lids_i_b = lazy_map(Broadcasting(Gridap.MultiField._sum_if_first_positive),patch_cell_lids_i,pcell_to_offsets) + patch_ids_i_b = lazy_map(Broadcasting(Gridap.MultiField._sum_if_first_positive),patch_ids_i,Fill(field_offsets[i],npatches)) + push!(block_cell_lids,patch_cell_lids_i_b) + push!(block_ids,patch_ids_i_b) + end + end + patch_cell_lids = lazy_map(BlockMap(nfields,collect(1:nfields)),block_cell_lids...) + patch_ids = map(vcat,block_ids...) + return patch_cell_lids, patch_ids +end + +struct PatchSS{A} <: Algebra.SymbolicSetup + solver::PatchSolver{A} +end + +Algebra.symbolic_setup(s::PatchSolver,mat::AbstractMatrix) = PatchSS(s) + +struct PatchNS{A,B} <: Algebra.NumericalSetup + solver::A + cache ::B +end + +function Algebra.numerical_setup(ss::PatchSS,mat::AbstractMatrix) + T = eltype(mat) + + space = ss.solver.space + biform = ss.solver.biform + cellmat, _ = move_contributions( # TODO: Generalise + get_array(biform(get_trial_fe_basis(space),get_fe_basis(space))), + Triangulation(ss.solver.patch_decomposition) + ) + cache = (CachedArray(zeros(T,1)), CachedArray(zeros(T,1,1)), cellmat) + return PatchNS(ss.solver,cache) +end + +function Algebra.solve!(x::AbstractVector,ns::PatchNS,b::AbstractVector) + PD = ns.solver.patch_decomposition + patch_ids, patch_cell_lids = ns.solver.patch_ids, ns.solver.patch_cell_lids + c_xk, c_Ak, cellmat = ns.cache + fill!(x,0.0) + + rows_cache = array_cache(patch_cell_lids) + cols_cache = array_cache(patch_cell_lids) + vals_cache = array_cache(cellmat) + + add! = AddEntriesMap(+) + add_cache = return_cache(add!,c_Ak.array,first(cellmat),first(patch_cell_lids),first(patch_cell_lids)) + caches = add_cache, vals_cache, rows_cache, cols_cache + + n_patches = length(patch_ids) + for patch in 1:n_patches + ids = patch_ids[patch] + + n = length(ids) + setsize!(c_xk,(n,)) + setsize!(c_Ak,(n,n)) + Ak = c_Ak.array + bk = c_xk.array + + patch_cellmat = patch_view(PD,cellmat,patch) + patch_rows = patch_view(PD,patch_cell_lids,patch) + patch_cols = patch_view(PD,patch_cell_lids,patch) + fill!(Ak,0.0) + FESpaces._numeric_loop_matrix!(Ak,caches,patch_cellmat,patch_rows,patch_cols) + + copyto!(bk,view(b,ids)) + f = lu!(Ak;check=false) + @check issuccess(f) "Factorization failed" + ldiv!(f,bk) + + x[ids] .+= bk + end + + return x +end diff --git a/test/_dev/PatchBased/PatchSolvers.jl b/test/_dev/PatchBased/PatchSolvers.jl new file mode 100644 index 00000000..e8b17239 --- /dev/null +++ b/test/_dev/PatchBased/PatchSolvers.jl @@ -0,0 +1,80 @@ +using Gridap +using Gridap.Geometry, Gridap.FESpaces, Gridap.ReferenceFEs, Gridap.MultiField + +using GridapSolvers +using GridapSolvers.MultilevelTools +using GridapSolvers.LinearSolvers +using GridapSolvers.PatchBasedSmoothers + +using LinearAlgebra + +function mean_value(p,dΩ) + sum(∫(p)dΩ) +end + +model = UnstructuredDiscreteModel(CartesianDiscreteModel((0,1,0,1),(4,4))) + +order = 2 +qdegree = 2*order+1 +reffe_u = LagrangianRefFE(VectorValue{2,Float64},QUAD,order) +reffe_p = LagrangianRefFE(Float64,QUAD,order-1;space=:P) +reffe_λ = LagrangianRefFE(Float64,QUAD,0) + +Vh = TestFESpace(model,reffe_u;dirichlet_tags="boundary") +Qh = TestFESpace(model,reffe_p,conformity=:L2) +Λh = ConstantFESpace(model) +Xh = MultiFieldFESpace([Vh,Qh,Λh]) + +qdegree = 2*order+1 +f(x) = VectorValue(1.0,1.0) +Π = LocalProjectionMap(divergence,Qh,qdegree) +a(u,v,dΩ) = ∫(∇(u)⊙∇(v))dΩ +b((u,p),(v,q),dΩ) = ∫(p*(∇⋅v) + q*(∇⋅u))dΩ +d(u,v,dΩ) = ∫(Π(v)*Π(u))dΩ +c((p,λ),(q,μ),dΩ) = ∫(λ*q + μ*p)dΩ + +β = 1.0 +biform((u,p,λ),(v,q,μ),dΩ) = a(u,v,dΩ) + b((u,p),(v,q),dΩ) + β*c((p,λ),(q,μ),dΩ) #+ d(u,v,dΩ) +liform((v,q),dΩ) = ∫(f⋅v)dΩ + +PD = PatchDecomposition(model,patch_boundary_style=PatchBasedSmoothers.PatchBoundaryInclude()) + +Vp = PatchFESpace(Vh,PD,reffe_u) +Qp = PatchFESpace(Qh,PD,reffe_p) +Λp = PatchFESpace(Λh,PD,reffe_λ) +Zh = MultiFieldFESpace([Vp,Qp,Λp]) + +Ω = Triangulation(model) +dΩ = Measure(Ω,4) + +Ωp = Triangulation(PD) +dΩp = Measure(Ωp,4) + +ap(u,v) = a(u,v,dΩp) +ps = PatchBasedSmoothers.PatchSolver(Vh,PD,ap,reffe_u) + +patch_ids = ps.patch_ids +patch_cell_lids = ps.patch_cell_lids + +A = assemble_matrix((u,v)->a(u,v,dΩ),Vh,Vh) +ss = symbolic_setup(ps,A) +ns = numerical_setup(ss,A) + +rhs = assemble_vector(v -> ∫(f⋅v)dΩ,Vh) +x = zeros(num_free_dofs(Vh)) +solve!(x,ns,rhs) + +biformp((u,p,λ),(v,q,μ)) = biform((u,p,λ),(v,q,μ),dΩp) +ps_mf = PatchBasedSmoothers.PatchSolver(Xh,PD,biformp,[reffe_u,reffe_p,reffe_λ]) + +patch_ids = ps_mf.patch_ids +patch_cell_lids = ps_mf.patch_cell_lids + +A = assemble_matrix((u,v)->biform(u,v,dΩ),Xh,Xh) +ss = symbolic_setup(ps_mf,A) +ns = numerical_setup(ss,A) + +rhs = assemble_vector(y -> liform(y,dΩ),Xh) +x = zeros(num_free_dofs(Xh)) +solve!(x,ns,rhs) + From 4813c19b41806ac45ba706050482fce574477278 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 25 Sep 2024 22:17:13 +1000 Subject: [PATCH 18/47] LocalProjectionMap bugfix in parallel --- src/MultilevelTools/GridapFixes.jl | 82 ++++++++----------- src/MultilevelTools/LocalProjectionMaps.jl | 5 -- .../MultilevelTools/LocalProjectionMaps.jl | 50 ++++++++++- 3 files changed, 79 insertions(+), 58 deletions(-) diff --git a/src/MultilevelTools/GridapFixes.jl b/src/MultilevelTools/GridapFixes.jl index df058db1..712f6300 100644 --- a/src/MultilevelTools/GridapFixes.jl +++ b/src/MultilevelTools/GridapFixes.jl @@ -1,60 +1,42 @@ -""" -function Base.map(::typeof(Gridap.Arrays.testitem), - a::Tuple{<:AbstractVector{<:AbstractVector{<:VectorValue}},<:AbstractVector{<:Gridap.Fields.LinearCombinationFieldVector}}) - a2=Gridap.Arrays.testitem(a[2]) - a1=Vector{eltype(eltype(a[1]))}(undef,size(a2,1)) - a1.=zero(Gridap.Arrays.testitem(a1)) - (a1,a2) +# Necessary when integrating the result from LocalProjectionMaps onto MultiFieldFEBasisComponents +# in parallel. In general, this would also get triggered when doing a change_domain operation +# between two different Triangulation views. +# It has to do with blocks and how `extend` and `pos_neg_data` are getting dispatched. +function Geometry._similar_empty(val::Fields.LinearCombinationFieldVector) + #Fields.VoidBasis(val,true) + values = zeros(eltype(val.values),size(val.values)) + Gridap.Fields.LinearCombinationFieldVector(values,val.fields) end -""" - -# MultiField/DistributedMultiField missing API +# This below is another attempt to fix the issue. +# I'm close, but doesn't work. """ -function Gridap.FESpaces.zero_dirichlet_values(f::MultiFieldFESpace) - map(zero_dirichlet_values,f.spaces) -end - -function Gridap.FESpaces.interpolate_everywhere!(objects,free_values::AbstractVector,dirichlet_values::Vector,fe::MultiFieldFESpace) - blocks = SingleFieldFEFunction[] - for (field, (U,object)) in enumerate(zip(fe.spaces,objects)) - free_values_i = restrict_to_field(fe,free_values,field) - dirichlet_values_i = dirichlet_values[field] - uhi = interpolate!(object, free_values_i, dirichlet_values_i, U) - push!(blocks,uhi) +function Geometry._similar_empty(val::ArrayBlock{<:AbstractArray{<:Field},N}) where N + T = typeof(Geometry._similar_empty(testitem(val.array))) + array = Array{T,N}(undef,size(val.array)) + touched = copy(val.touched) + a = ArrayBlock(array,touched) + for i in eachindex(a) + if a.touched[i] + a.array[i] = Geometry._similar_empty(val.array[i]) + end end - Gridap.MultiField.MultiFieldFEFunction(free_values,fe,blocks) + a end -function Gridap.FESpaces.interpolate!(objects::GridapDistributed.DistributedMultiFieldFEFunction,free_values::AbstractVector,fe::GridapDistributed.DistributedMultiFieldFESpace) - part_fe_fun = map(local_views(objects),partition(free_values),local_views(fe)) do objects,x,f - interpolate!(objects,x,f) - end - field_fe_fun = GridapDistributed.DistributedSingleFieldFEFunction[] - for i in 1:num_fields(fe) - free_values_i = Gridap.MultiField.restrict_to_field(fe,free_values,i) - fe_space_i = fe.field_fe_space[i] - fe_fun_i = FEFunction(fe_space_i,free_values_i) - push!(field_fe_fun,fe_fun_i) - end - GridapDistributed.DistributedMultiFieldFEFunction(field_fe_fun,part_fe_fun,free_values) +function Gridap.Geometry.pos_neg_data( + ipos_to_val::AbstractArray{<:ArrayBlock{<:AbstractArray{<:Field}}},i_to_iposneg::PosNegPartition +) + nineg = length(i_to_iposneg.ineg_to_i) + void = Geometry._similar_empty(testitem(ipos_to_val)) + ineg_to_val = Fill(void,nineg) + _ipos_to_val = lazy_map(Broadcasting(Fields.VoidBasisMap(false)),ipos_to_val) + _ipos_to_val, ineg_to_val end -function Gridap.FESpaces.FEFunction( - f::GridapDistributed.DistributedMultiFieldFESpace,x::AbstractVector, - dirichlet_values::AbstractArray{<:AbstractVector},isconsistent=false - ) - free_values = GridapDistributed.change_ghost(x,f.gids;is_consistent=isconsistent,make_consistent=true) - part_fe_fun = map(FEFunction,f.part_fe_space,partition(free_values)) - field_fe_fun = GridapDistributed.DistributedSingleFieldFEFunction[] - for i in 1:num_fields(f) - free_values_i = Gridap.MultiField.restrict_to_field(f,free_values,i) - dirichlet_values_i = dirichlet_values[i] - fe_space_i = f.field_fe_space[i] - fe_fun_i = FEFunction(fe_space_i,free_values_i,dirichlet_values_i,true) - push!(field_fe_fun,fe_fun_i) - end - GridapDistributed.DistributedMultiFieldFEFunction(field_fe_fun,part_fe_fun,free_values) +function Arrays.lazy_map(k::Broadcasting{<:Fields.VoidBasisMap},a::Arrays.LazyArray{<:Fill{<:Fields.BlockMap}}) + args = map(ai -> lazy_map(k.f, ai), a.args) + lazy_map(a.maps.value,args) end -""" \ No newline at end of file +""" diff --git a/src/MultilevelTools/LocalProjectionMaps.jl b/src/MultilevelTools/LocalProjectionMaps.jl index 01d8ec8a..6d277223 100644 --- a/src/MultilevelTools/LocalProjectionMaps.jl +++ b/src/MultilevelTools/LocalProjectionMaps.jl @@ -135,11 +135,6 @@ function _compute_local_projections( return lazy_map(k,lhs_data,rhs_data,basis_data) end -# Note on the caches: -# - We CANNOT overwrite `lhs`: In the case of constant cell_maps and `u` being a `FEFunction`, -# the lhs will be a Fill, but the rhs will not be optimized (regular LazyArray). -# In that case, we will see multiple times the same `lhs` being used for different `rhs`. -# - The converse never happens (I think), so we can overwrite `rhs` since it will always be recomputed. function Arrays.return_cache(::LocalProjectionMap,lhs::Matrix{T},rhs::A,basis) where {T,A<:Union{Matrix{T},Vector{T}}} return CachedArray(copy(lhs)), CachedArray(copy(rhs)) end diff --git a/test/_dev/MultilevelTools/LocalProjectionMaps.jl b/test/_dev/MultilevelTools/LocalProjectionMaps.jl index eb820ad0..b732b5b2 100644 --- a/test/_dev/MultilevelTools/LocalProjectionMaps.jl +++ b/test/_dev/MultilevelTools/LocalProjectionMaps.jl @@ -3,7 +3,7 @@ using Gridap using GridapDistributed, PartitionedArrays using GridapSolvers using GridapSolvers.MultilevelTools -using Gridap.Arrays +using Gridap.Arrays, Gridap.CellData, Gridap.FESpaces np = (2,2) ranks = with_debug() do distribute @@ -28,8 +28,8 @@ Q = TestFESpace(model,reffe_p;conformity=:L2,constraint=:zeromean) mfs = Gridap.MultiField.BlockMultiFieldStyle() X = MultiFieldFESpace([V,Q];style=mfs) -#Π_Qh = LocalProjectionMap(divergence,reffe_p,qdegree) -Π_Qh = LocalProjectionMap(divergence,Q,qdegree) +Π_Qh = LocalProjectionMap(divergence,reffe_p,qdegree) +#Π_Qh = LocalProjectionMap(divergence,Q,qdegree) A = assemble_matrix((u,v) -> ∫(∇(v)⊙∇(u))dΩ, V, V) D = assemble_matrix((u,v) -> ∫(Π_Qh(u)⋅(∇⋅v))dΩ, V, V) @@ -44,3 +44,47 @@ G = Matrix(D) F-G norm(F-G) maximum(abs.(F-G)) + +####################################################################### + +Ωf = Triangulation(model,tags="interior") +Vf = TestFESpace(Ωf,reffe_u); +Qf = TestFESpace(Ωf,reffe_p;conformity=:L2) +Xf = MultiFieldFESpace([Vf,Qf];style=mfs) + +Ωv = Triangulation(model,[1,2,3]) +dΩv = Measure(Ωv,2) + +u1 = get_trial_fe_basis(Vf) +cf1 = Π_Qh(u1) +∫(cf1)dΩv # OK + +u2 = get_trial_fe_basis(Xf)[1] +cf2 = Π_Qh(u2) +∫(cf2)dΩv # Not OK + +cf2_bis = GenericCellField(cf2.cell_field.args[1].args[1],Ωf,ReferenceDomain()) +∫(cf2_bis)dΩv # OK + +u3 = get_trial_fe_basis(Xf)[2] +∫(u3)dΩv # OK + +u3_bis = ∇⋅(u3) +u3_bisbis = change_domain(u3_bis,Ωv,ReferenceDomain()) + +################################### + +eltype(cf2.cell_field.args[1].args[1]) +eltype(cf2.cell_field.args[1]) + +val = testitem(cf2.cell_field.args[1]) +Gridap.Geometry._similar_empty(val) + +val_copy = deepcopy(val) + +Gridap.Geometry._similar_empty(val.array[1]) + +val1 = val.array[1] +zs = 0 .* size(val1) +void = similar(val,eltype(val1),zs) + From 07b979c37538d0a908cb89463724404d11daa14a Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 26 Sep 2024 10:57:58 +1000 Subject: [PATCH 19/47] Minor --- test/_dev/MultilevelTools/LocalProjectionMaps.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/test/_dev/MultilevelTools/LocalProjectionMaps.jl b/test/_dev/MultilevelTools/LocalProjectionMaps.jl index b732b5b2..9fb73ecc 100644 --- a/test/_dev/MultilevelTools/LocalProjectionMaps.jl +++ b/test/_dev/MultilevelTools/LocalProjectionMaps.jl @@ -87,4 +87,3 @@ Gridap.Geometry._similar_empty(val.array[1]) val1 = val.array[1] zs = 0 .* size(val1) void = similar(val,eltype(val1),zs) - From d4be46070c66e21efd12460708a59c0e015c8dbc Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 30 Sep 2024 11:11:56 +1000 Subject: [PATCH 20/47] Fixed PatchSkeletons for adapted models --- .../PatchTriangulations.jl | 47 +++++++++++++++---- test/_dev/PatchBased/BoundaryTrians.jl | 22 +++++++-- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/PatchBasedSmoothers/PatchTriangulations.jl b/src/PatchBasedSmoothers/PatchTriangulations.jl index 949e2910..8703ed5c 100644 --- a/src/PatchBasedSmoothers/PatchTriangulations.jl +++ b/src/PatchBasedSmoothers/PatchTriangulations.jl @@ -45,7 +45,7 @@ end # For now, I am disabling changes from PatchTriangulations to other Triangulations. # Reason: When the tface_to_mface map is not injective (i.e when we have overlapping), -# the glue is not well defined. Gridap will throe an error when trying to create +# the glue is not well defined. Gridap will throw an error when trying to create # the inverse map mface_to_tface. # I believe this could technically be relaxed in the future, but for now I don't see a # scenario where we would need this. @@ -75,7 +75,6 @@ function Geometry.BoundaryTriangulation( pface_to_pcell, pface_to_lcell = get_pface_to_pcell(PD,Df,patch_faces) trian = OverlappingBoundaryTriangulation(model,patch_faces.data,pface_to_lcell) - return PatchTriangulation(trian,PD,patch_faces,pface_to_pcell) end @@ -88,11 +87,7 @@ function Geometry.SkeletonTriangulation(PD::PatchDecomposition{Dr,Dc}) where {Dr patch_faces = get_patch_faces(PD,Df,is_interior) pface_to_pcell, _ = get_pface_to_pcell(PD,Df,patch_faces) - nfaces = length(patch_faces.data) - plus = OverlappingBoundaryTriangulation(model,patch_faces.data,fill(Int8(1),nfaces)) - minus = OverlappingBoundaryTriangulation(model,patch_faces.data,fill(Int8(2),nfaces)) - trian = SkeletonTriangulation(plus,minus) - + trian = OverlappingSkeletonTriangulation(model,patch_faces.data) return PatchTriangulation(trian,PD,patch_faces,pface_to_pcell) end @@ -128,7 +123,6 @@ function Geometry.move_contributions( return scell_to_val, strian end - # Overlapping BoundaryTriangulation # # This is the situation: I do not see any show-stopper for us to have an overlapping @@ -139,6 +133,19 @@ end # The following code does just that, and returns a regular BoundaryTriangulation. It is # mostly copied from Gridap/Geometry/BoundaryTriangulations.jl +function OverlappingBoundaryTriangulation( + model::Gridap.Adaptivity.AdaptedDiscreteModel, + face_to_bgface::AbstractVector{<:Integer}, + face_to_lcell::AbstractVector{<:Integer} +) + trian = OverlappingBoundaryTriangulation( + Gridap.Adaptivity.get_model(model), + face_to_bgface, + face_to_lcell, + ) + return Gridap.Adaptivity.AdaptedTriangulation(trian,model) +end + function OverlappingBoundaryTriangulation( model::DiscreteModel, face_to_bgface::AbstractVector{<:Integer}, @@ -217,3 +224,27 @@ function overlapped_find_local_index( end return c_to_lc end + + +# Overlapping SkeletonTriangulation + +function OverlappingSkeletonTriangulation( + model::Gridap.Adaptivity.AdaptedDiscreteModel, + face_to_bgface::AbstractVector{<:Integer}, +) + trian = OverlappingSkeletonTriangulation( + Gridap.Adaptivity.get_model(model), + face_to_bgface, + ) + return Gridap.Adaptivity.AdaptedTriangulation(trian,model) +end + +function OverlappingSkeletonTriangulation( + model::DiscreteModel, + face_to_bgface::AbstractVector{<:Integer}, +) + nfaces = length(face_to_bgface) + plus = OverlappingBoundaryTriangulation(model,face_to_bgface,fill(Int8(1),nfaces)) + minus = OverlappingBoundaryTriangulation(model,face_to_bgface,fill(Int8(2),nfaces)) + return SkeletonTriangulation(plus,minus) +end diff --git a/test/_dev/PatchBased/BoundaryTrians.jl b/test/_dev/PatchBased/BoundaryTrians.jl index bcc6a484..887283db 100644 --- a/test/_dev/PatchBased/BoundaryTrians.jl +++ b/test/_dev/PatchBased/BoundaryTrians.jl @@ -14,6 +14,12 @@ using GridapSolvers.LinearSolvers using GridapSolvers.MultilevelTools using GridapSolvers.PatchBasedSmoothers +function get_cell_size(Ω::Triangulation{Dc}) where Dc + dΩ = Measure(Ω,1) + h_e = Gridap.CellData.get_array(∫(1)dΩ) .^ (1/Dc) + return CellField(h_e,Ω) +end + function weakforms(model) Ω = Triangulation(model) Γ = BoundaryTriangulation(model) @@ -26,10 +32,13 @@ function weakforms(model) n_Γ = get_normal_vector(Γ) n_Λ = get_normal_vector(Λ) + h_e = get_cell_size(Λ) + a1(u,v) = ∫(∇(u)⊙∇(v))dΩ a2(u,v) = ∫((∇(v)⋅n_Γ)⋅u)dΓ a3(u,v) = ∫(jump(u⋅n_Λ)⋅jump(v⋅n_Λ))dΛ - return a1, a2, a3 + a4(u,v) = ∫(h_e*jump(u⋅n_Λ)⋅jump(v⋅n_Λ))dΛ + return a1, a2, a3, a4 end model = CartesianDiscreteModel((0,1,0,1),(2,2)) @@ -52,8 +61,8 @@ Ph = PatchFESpace(Vh,PD,reffe) Γp_virtual = BoundaryTriangulation(PD,tags=["boundary","interior"],reverse=true) -a1, a2, a3 = weakforms(model) -ap1, ap2, ap3 = weakforms(PD) +a1, a2, a3, a4 = weakforms(model) +ap1, ap2, ap3, ap4 = weakforms(PD) A1 = assemble_matrix(a1,Vh,Vh) Ap1 = assemble_matrix(ap1,Ph,Ph) @@ -63,3 +72,10 @@ Ap2 = assemble_matrix(ap2,Ph,Ph) A3 = assemble_matrix(a3,Vh,Vh) Ap3 = assemble_matrix(ap3,Ph,Ph) + +A4 = assemble_matrix(a4,Vh,Vh) +Ap4 = assemble_matrix(ap4,Ph,Ph) + + + + From 94b08110f872572b82d6c426590ce6194734a4c4 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 2 Oct 2024 15:07:20 +1000 Subject: [PATCH 21/47] Minor bugfix --- src/NonlinearSolvers/NonlinearSolvers.jl | 1 - src/PatchBasedSmoothers/PatchFESpaces.jl | 4 ++-- .../PatchTriangulations.jl | 1 - test/_dev/PatchBased/BoundaryTrians.jl | 19 +++++++++++++++++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/NonlinearSolvers/NonlinearSolvers.jl b/src/NonlinearSolvers/NonlinearSolvers.jl index 4eb24a53..0b4b1981 100644 --- a/src/NonlinearSolvers/NonlinearSolvers.jl +++ b/src/NonlinearSolvers/NonlinearSolvers.jl @@ -12,7 +12,6 @@ module NonlinearSolvers using GridapSolvers.SolverInterfaces using GridapSolvers.MultilevelTools - using GridapSolvers.SolverInterfaces include("NewtonRaphsonSolver.jl") export NewtonSolver diff --git a/src/PatchBasedSmoothers/PatchFESpaces.jl b/src/PatchBasedSmoothers/PatchFESpaces.jl index 54a2b26a..834dd57f 100644 --- a/src/PatchBasedSmoothers/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/PatchFESpaces.jl @@ -148,14 +148,14 @@ function FESpaces.get_cell_dof_ids(::Triangulation,a::PatchFESpace,trian::PatchT end function FESpaces.get_cell_dof_ids(::BoundaryTriangulation,a::PatchFESpace,trian::PatchTriangulation) - cell_dof_ids = get_cell_dof_ids(a) + cell_dof_ids = get_cell_dof_ids(a) pface_to_pcell = trian.pface_to_pcell pcells = isempty(pface_to_pcell) ? Int[] : lazy_map(x->x[1],pface_to_pcell) return lazy_map(Reindex(cell_dof_ids),pcells) end function FESpaces.get_cell_dof_ids(::SkeletonTriangulation,a::PatchFESpace,trian::PatchTriangulation) - cell_dof_ids = get_cell_dof_ids(a) + cell_dof_ids = get_cell_dof_ids(a) pface_to_pcell = trian.pface_to_pcell pcells_plus = isempty(pface_to_pcell) ? Int[] : lazy_map(x->x[1],pface_to_pcell) diff --git a/src/PatchBasedSmoothers/PatchTriangulations.jl b/src/PatchBasedSmoothers/PatchTriangulations.jl index 8703ed5c..9b1f1be1 100644 --- a/src/PatchBasedSmoothers/PatchTriangulations.jl +++ b/src/PatchBasedSmoothers/PatchTriangulations.jl @@ -119,7 +119,6 @@ function Geometry.move_contributions( scell_to_val::AbstractArray, strian::PatchTriangulation ) - display(ndims(eltype(scell_to_val))) return scell_to_val, strian end diff --git a/test/_dev/PatchBased/BoundaryTrians.jl b/test/_dev/PatchBased/BoundaryTrians.jl index 887283db..2ebf4513 100644 --- a/test/_dev/PatchBased/BoundaryTrians.jl +++ b/test/_dev/PatchBased/BoundaryTrians.jl @@ -42,10 +42,16 @@ function weakforms(model) end model = CartesianDiscreteModel((0,1,0,1),(2,2)) +model = Gridap.Adaptivity.refine(model) -order = 1 +#order = 1 +#qorder = 2*order+1 +#reffe = ReferenceFE(raviart_thomas,Float64,order-1) +#Vh = FESpace(model,reffe) + +order = 2 qorder = 2*order+1 -reffe = ReferenceFE(raviart_thomas,Float64,order-1) +reffe = ReferenceFE(lagrangian,VectorValue{2,Float64},order) Vh = FESpace(model,reffe) Ω = Triangulation(model) @@ -77,5 +83,14 @@ A4 = assemble_matrix(a4,Vh,Vh) Ap4 = assemble_matrix(ap4,Ph,Ph) +Λ = SkeletonTriangulation(PD) +dΛ = Measure(Λ, qorder) +n_Λ = get_normal_vector(Λ) + +up = get_trial_fe_basis(Ph) +ap(u,v) = ∫(jump(u⋅n_Λ)⋅jump(v⋅n_Λ))dΛ + +A = assemble_matrix(ap,Ph,Ph) +@which is_change_possible(Ω,Λ) From 847bcb65e623fd227418fd32fb1535cc2974083d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 2 Oct 2024 17:28:34 +1000 Subject: [PATCH 22/47] Minor --- .../CoarsePatchDecompositions.jl | 61 ---------------- .../PatchBasedSmoothers.jl | 1 - .../PatchDecompositions.jl | 72 +++++++++++++++++++ 3 files changed, 72 insertions(+), 62 deletions(-) delete mode 100644 src/PatchBasedSmoothers/CoarsePatchDecompositions.jl diff --git a/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl b/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl deleted file mode 100644 index 69547f94..00000000 --- a/src/PatchBasedSmoothers/CoarsePatchDecompositions.jl +++ /dev/null @@ -1,61 +0,0 @@ - -# PatchDecomposition where each patch is given by a coarse cell on the parent mesh -function CoarsePatchDecomposition( - model::Gridap.Adaptivity.AdaptedDiscreteModel{Dc,Dp}, - patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude(), - boundary_tag_names::AbstractArray{String}=["boundary"] -) where {Dc,Dp} - glue = Gridap.Adaptivity.get_adaptivity_glue(model) - - patch_cells = glue.o2n_faces_map - patch_facets = get_coarse_patch_facets(model, patch_cells) - patch_cells_faces_on_boundary = compute_patch_cells_faces_on_boundary( - model, patch_cells, patch_facets, patch_boundary_style, boundary_tag_names - ) - - return PatchDecomposition{Dc,Dc,Dp}( - model, patch_cells, patch_cells_faces_on_boundary, patch_boundary_style - ) -end - -function get_coarse_patch_facets( - model::Gridap.Adaptivity.AdaptedDiscreteModel{Dc,Dp},patch_cells -) where {Dc,Dp} - topo = get_grid_topology(model) - c2f_map = Geometry.get_faces(topo,Dc,Dc-1) - f2c_map = Geometry.get_faces(topo,Dc-1,Dc) - - touched = fill(false,num_faces(topo,Dc-1)) - ptrs = fill(0,length(patch_cells)+1) - for (patch,cells) in enumerate(patch_cells) - for c in cells - for f in c2f_map[c] - nbors = f2c_map[f] - if !touched[f] && (length(nbors) == 2) && all(n -> n ∈ cells, nbors) - touched[f] = true - ptrs[patch+1] += 1 - end - end - end - end - Arrays.length_to_ptrs!(ptrs) - - data = fill(0,ptrs[end]-1) - fill!(touched,false) - for (patch,cells) in enumerate(patch_cells) - for c in cells - for f in c2f_map[c] - nbors = f2c_map[f] - if !touched[f] && (length(nbors) == 2) && all(n -> n ∈ cells, nbors) - touched[f] = true - data[ptrs[patch]] = f - ptrs[patch] += 1 - end - end - end - end - Arrays.rewind_ptrs!(ptrs) - - patch_facets = Table(data,ptrs) - return patch_facets -end diff --git a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl index 9a7b7675..43053cae 100644 --- a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl +++ b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl @@ -23,7 +23,6 @@ include("PatchDecompositions.jl") include("DistributedPatchDecompositions.jl") include("PatchTriangulations.jl") include("PatchClosures.jl") -include("CoarsePatchDecompositions.jl") # FESpaces include("PatchFESpaces.jl") diff --git a/src/PatchBasedSmoothers/PatchDecompositions.jl b/src/PatchBasedSmoothers/PatchDecompositions.jl index 5e736469..86355d36 100644 --- a/src/PatchBasedSmoothers/PatchDecompositions.jl +++ b/src/PatchBasedSmoothers/PatchDecompositions.jl @@ -64,6 +64,31 @@ function PatchDecomposition( ) end +function PatchDecomposition( + model::Gridap.Adaptivity.AdaptedDiscreteModel{Dc,Dp}, + patch_cells, + patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude(), + boundary_tag_names::AbstractArray{String}=["boundary"] +) where {Dc,Dp} + patch_facets = generate_patch_facets(model,patch_cells) + patch_cells_faces_on_boundary = compute_patch_cells_faces_on_boundary( + model, patch_cells, patch_facets, patch_boundary_style, boundary_tag_names + ) + return PatchDecomposition{Dc,Dc,Dp}( + model, patch_cells, patch_cells_faces_on_boundary, patch_boundary_style + ) +end + +function CoarsePatchDecomposition( + model::Gridap.Adaptivity.AdaptedDiscreteModel, + patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude(), + boundary_tag_names::AbstractArray{String}=["boundary"] +) + glue = Gridap.Adaptivity.get_adaptivity_glue(model) + patch_cells = glue.o2n_faces_map + return PatchDecomposition(model,patch_cells,patch_boundary_style,boundary_tag_names) +end + """ num_patches(a::PatchDecomposition) """ @@ -633,3 +658,50 @@ function generate_patch_closures(PD::PatchDecomposition{Dr,Dc}) where {Dr,Dc} return Table(data,ptrs) end + +""" + generate_patch_facets(model::DiscreteModel{Dc,Dp},patch_cells) + +Given a model and the cells within each patch, returns a patch-wise Table containing the facets on each patch. +""" +function generate_patch_facets( + model::DiscreteModel{Dc,Dp},patch_cells +) where {Dc,Dp} + topo = get_grid_topology(model) + c2f_map = Geometry.get_faces(topo,Dc,Dc-1) + f2c_map = Geometry.get_faces(topo,Dc-1,Dc) + + touched = fill(false,num_faces(topo,Dc-1)) + ptrs = fill(0,length(patch_cells)+1) + for (patch,cells) in enumerate(patch_cells) + for c in cells + for f in c2f_map[c] + nbors = f2c_map[f] + if !touched[f] && (length(nbors) == 2) && all(n -> n ∈ cells, nbors) + touched[f] = true + ptrs[patch+1] += 1 + end + end + end + end + Arrays.length_to_ptrs!(ptrs) + + data = fill(0,ptrs[end]-1) + fill!(touched,false) + for (patch,cells) in enumerate(patch_cells) + for c in cells + for f in c2f_map[c] + nbors = f2c_map[f] + if !touched[f] && (length(nbors) == 2) && all(n -> n ∈ cells, nbors) + touched[f] = true + data[ptrs[patch]] = f + ptrs[patch] += 1 + end + end + end + end + Arrays.rewind_ptrs!(ptrs) + + patch_facets = Table(data,ptrs) + return patch_facets +end From 2ad676e0f95c678da238cccb3630552ff39d7498 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 2 Oct 2024 17:30:59 +1000 Subject: [PATCH 23/47] Minor --- src/PatchBasedSmoothers/PatchDecompositions.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PatchBasedSmoothers/PatchDecompositions.jl b/src/PatchBasedSmoothers/PatchDecompositions.jl index 86355d36..8435fe5f 100644 --- a/src/PatchBasedSmoothers/PatchDecompositions.jl +++ b/src/PatchBasedSmoothers/PatchDecompositions.jl @@ -65,8 +65,8 @@ function PatchDecomposition( end function PatchDecomposition( - model::Gridap.Adaptivity.AdaptedDiscreteModel{Dc,Dp}, - patch_cells, + model::DiscreteModel{Dc,Dp}, + patch_cells::AbstractArray{<:AbstractVector{<:Integer}}, patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude(), boundary_tag_names::AbstractArray{String}=["boundary"] ) where {Dc,Dp} From dd250efee291a23a587e3ba9a43cb70d0f69720a Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 7 Oct 2024 14:52:50 +1100 Subject: [PATCH 24/47] Now using CoarsePatchDecompositions --- .../DistributedPatchDecompositions.jl | 35 ++++++++++++++++--- .../PatchTransferOperators.jl | 6 ++-- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl b/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl index 7e0c8055..1042b38a 100644 --- a/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl +++ b/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl @@ -2,6 +2,14 @@ struct DistributedPatchDecomposition{Dr,Dc,Dp,A,B} <: GridapType patch_decompositions::A model::B + function DistributedPatchDecomposition( + patch_decompositions::AbstractVector{<:PatchDecomposition{Dr,Dc,Dp}}, + model::GridapDistributed.DistributedDiscreteModel{Dc,Dp} + ) where {Dr,Dc,Dp} + A = typeof(patch_decompositions) + B = typeof(model) + new{Dr,Dc,Dp,A,B}(patch_decompositions,model) + end end GridapDistributed.local_views(a::DistributedPatchDecomposition) = a.patch_decompositions @@ -12,17 +20,34 @@ function PatchDecomposition( patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude() ) where {Dc,Dp} mark_interface_facets!(model) - patch_decompositions = map(local_views(model)) do lmodel + patch_decompositions = map(local_views(model)) do model PatchDecomposition( - lmodel; + model; Dr=Dr, patch_boundary_style=patch_boundary_style, boundary_tag_names=["boundary","interface"] ) end - A = typeof(patch_decompositions) - B = typeof(model) - return DistributedPatchDecomposition{Dr,Dc,Dp,A,B}(patch_decompositions,model) + return DistributedPatchDecomposition(patch_decompositions,model) +end + +function CoarsePatchDecomposition( + model::GridapDistributed.DistributedAdaptedDiscreteModel{Dc,Dp}; + patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude() +) where {Dc,Dp} + gids = get_cell_gids(get_parent(model)) + mark_interface_facets!(model) + patch_decompositions = map(local_views(model),partition(gids)) do model, cids + own_cells = own_to_local(cids) + glue = Gridap.Adaptivity.get_adaptivity_glue(model) + patch_cells = glue.o2n_faces_map[own_cells] + PatchDecomposition( + model,patch_cells, + patch_boundary_style=patch_boundary_style, + boundary_tag_names=["boundary","interface"] + ) + end + return DistributedPatchDecomposition(patch_decompositions,model) end function PatchDecomposition(mh::ModelHierarchy;kwargs...) diff --git a/src/PatchBasedSmoothers/PatchTransferOperators.jl b/src/PatchBasedSmoothers/PatchTransferOperators.jl index 63cf932e..3d2b765d 100644 --- a/src/PatchBasedSmoothers/PatchTransferOperators.jl +++ b/src/PatchBasedSmoothers/PatchTransferOperators.jl @@ -66,10 +66,8 @@ function _get_patch_cache(lev,sh,PD,lhs,rhs,is_nonlinear,cache_refine) cparts = get_level_parts(sh,lev+1) if i_am_in(cparts) # Patch-based correction fespace - glue = sh[lev].mh_level.ref_glue - patches_mask = get_coarse_node_mask(model_h,glue) cell_conformity = MultilevelTools.get_cell_conformity_before_redist(sh,lev) - Ph = PatchFESpace(Uh,PD,cell_conformity;patches_mask) + Ph = PatchFESpace(Uh,PD,cell_conformity) # Solver caches ap(u,v) = is_nonlinear ? lhs(zero(Uh),u,v) : lhs(u,v) @@ -161,7 +159,7 @@ function setup_patch_prolongation_operators(sh,lhs,rhs,qdegrees;is_nonlinear=fal cparts = get_level_parts(sh,lev+1) if i_am_in(cparts) model = get_model_before_redist(sh,lev) - PD = PatchDecomposition(model) + PD = CoarsePatchDecomposition(model) Ω = Triangulation(PD) dΩ = Measure(Ω,qdegree) lhs_i = is_nonlinear ? (u,du,dv) -> lhs(u,du,dv,dΩ) : (u,v) -> lhs(u,v,dΩ) From 7338b067d04a5f17bcced4236922d0a19fb2d759 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 7 Oct 2024 15:14:50 +1100 Subject: [PATCH 25/47] Minor --- src/PatchBasedSmoothers/PatchFESpaces.jl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/PatchBasedSmoothers/PatchFESpaces.jl b/src/PatchBasedSmoothers/PatchFESpaces.jl index 834dd57f..a95d992d 100644 --- a/src/PatchBasedSmoothers/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/PatchFESpaces.jl @@ -469,7 +469,9 @@ end # x \in PatchFESpace # y \in SingleFESpace -function prolongate!(x,Ph::PatchFESpace,y;dof_ids=LinearIndices(y)) +function prolongate!( + x::AbstractVector,Ph::PatchFESpace,y::AbstractVector;dof_ids=LinearIndices(y) +) dof_to_pdof = Ph.dof_to_pdof ptrs = dof_to_pdof.ptrs @@ -484,7 +486,9 @@ end # x \in SingleFESpace # y \in PatchFESpace -function inject!(x,Ph::PatchFESpace,y) +function inject!( + x::AbstractVector,Ph::PatchFESpace,y::AbstractVector +) dof_to_pdof = Ph.dof_to_pdof ptrs = dof_to_pdof.ptrs @@ -498,7 +502,9 @@ function inject!(x,Ph::PatchFESpace,y) end end -function inject!(x,Ph::PatchFESpace,y,w,w_sums) +function inject!( + x::AbstractVector,Ph::PatchFESpace,y::AbstractVector,w,w_sums +) dof_to_pdof = Ph.dof_to_pdof ptrs = dof_to_pdof.ptrs From c8aa8ad7d445e69dae89770c8afef468e84b85fe Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 7 Oct 2024 17:42:44 +1100 Subject: [PATCH 26/47] Minor --- src/PatchBasedSmoothers/PatchTransferOperators.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PatchBasedSmoothers/PatchTransferOperators.jl b/src/PatchBasedSmoothers/PatchTransferOperators.jl index 3d2b765d..36025ecc 100644 --- a/src/PatchBasedSmoothers/PatchTransferOperators.jl +++ b/src/PatchBasedSmoothers/PatchTransferOperators.jl @@ -155,7 +155,7 @@ end function setup_patch_prolongation_operators(sh,lhs,rhs,qdegrees;is_nonlinear=false) map(view(linear_indices(sh),1:num_levels(sh)-1)) do lev - qdegree = isa(qdegrees,Number) ? qdegrees : qdegrees[lev] + qdegree = isa(qdegrees,Vector) ? qdegrees[lev] : qdegrees cparts = get_level_parts(sh,lev+1) if i_am_in(cparts) model = get_model_before_redist(sh,lev) @@ -235,7 +235,7 @@ end function setup_patch_restriction_operators(sh,patch_prolongations,rhs,qdegrees;kwargs...) map(view(linear_indices(sh),1:num_levels(sh)-1)) do lev - qdegree = isa(qdegrees,Number) ? qdegrees : qdegrees[lev] + qdegree = isa(qdegrees,Vector) ? qdegrees[lev] : qdegrees cparts = get_level_parts(sh,lev+1) if i_am_in(cparts) model = get_model_before_redist(sh,lev) From 543b258d163ca1cef759011aea1d23ea5a1dc69c Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 7 Oct 2024 17:44:44 +1100 Subject: [PATCH 27/47] Minor --- src/MultilevelTools/GridTransferOperators.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MultilevelTools/GridTransferOperators.jl b/src/MultilevelTools/GridTransferOperators.jl index 5c8ba901..1c614edc 100644 --- a/src/MultilevelTools/GridTransferOperators.jl +++ b/src/MultilevelTools/GridTransferOperators.jl @@ -59,7 +59,7 @@ function DistributedGridTransferOperator( return DistributedGridTransferOperator(op_type,redist,restriction_method,sh,cache) end -function _get_interpolation_cache(lev::Int,sh::FESpaceHierarchy,qdegree::Int,mode::Symbol) +function _get_interpolation_cache(lev::Int,sh::FESpaceHierarchy,qdegree,mode::Symbol) cparts = get_level_parts(sh,lev+1) if i_am_in(cparts) @@ -82,7 +82,7 @@ function _get_interpolation_cache(lev::Int,sh::FESpaceHierarchy,qdegree::Int,mod return cache_refine end -function _get_projection_cache(lev::Int,sh::FESpaceHierarchy,qdegree::Int,mode::Symbol,solver) +function _get_projection_cache(lev::Int,sh::FESpaceHierarchy,qdegree,mode::Symbol,solver) cparts = get_level_parts(sh,lev+1) if i_am_in(cparts) @@ -126,7 +126,7 @@ function _get_projection_cache(lev::Int,sh::FESpaceHierarchy,qdegree::Int,mode:: return cache_refine end -function _get_dual_projection_cache(lev::Int,sh::FESpaceHierarchy,qdegree::Int,solver) +function _get_dual_projection_cache(lev::Int,sh::FESpaceHierarchy,qdegree,solver) cparts = get_level_parts(sh,lev+1) if i_am_in(cparts) From 4c37e5d80663c9d26d2dc423dc35a7fe46293e9b Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 8 Oct 2024 21:55:18 +1100 Subject: [PATCH 28/47] Minor --- src/PatchBasedSmoothers/DistributedPatchDecompositions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl b/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl index 1042b38a..1f9ae352 100644 --- a/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl +++ b/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl @@ -35,7 +35,7 @@ function CoarsePatchDecomposition( model::GridapDistributed.DistributedAdaptedDiscreteModel{Dc,Dp}; patch_boundary_style::PatchBoundaryStyle=PatchBoundaryExclude() ) where {Dc,Dp} - gids = get_cell_gids(get_parent(model)) + gids = get_cell_gids(Gridap.Adaptivity.get_parent(model)) mark_interface_facets!(model) patch_decompositions = map(local_views(model),partition(gids)) do model, cids own_cells = own_to_local(cids) From 15a7dcc57d84f2b0a21b365008bf82f25940bc5b Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 8 Oct 2024 21:58:05 +1100 Subject: [PATCH 29/47] Minor --- src/MultilevelTools/FESpaceHierarchies.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MultilevelTools/FESpaceHierarchies.jl b/src/MultilevelTools/FESpaceHierarchies.jl index a38bfd60..2331af41 100644 --- a/src/MultilevelTools/FESpaceHierarchies.jl +++ b/src/MultilevelTools/FESpaceHierarchies.jl @@ -61,8 +61,8 @@ function _cell_conformity( reffe::ReferenceFE; conformity=nothing, kwargs... ) :: CellConformity - cell_reffe = Fill(reffe,num_cells(model)) - conformity = Conformity(Gridap.Arrays.testitem(cell_reffe),conformity) + cell_reffe = CompressedArray([reffe],fill(one(Int8),num_cells(model))) + conformity = Conformity(reffe,conformity) return CellConformity(cell_reffe,conformity) end From a9b2543671e5fafcb5cc90f358f165c2a8b0af5d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 8 Oct 2024 22:04:55 +1100 Subject: [PATCH 30/47] Minor --- src/PatchBasedSmoothers/DistributedPatchDecompositions.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl b/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl index 1f9ae352..85897984 100644 --- a/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl +++ b/src/PatchBasedSmoothers/DistributedPatchDecompositions.jl @@ -42,9 +42,7 @@ function CoarsePatchDecomposition( glue = Gridap.Adaptivity.get_adaptivity_glue(model) patch_cells = glue.o2n_faces_map[own_cells] PatchDecomposition( - model,patch_cells, - patch_boundary_style=patch_boundary_style, - boundary_tag_names=["boundary","interface"] + model,patch_cells,patch_boundary_style,["boundary","interface"] ) end return DistributedPatchDecomposition(patch_decompositions,model) From a107ac234be165beae6ed8af8565a7937b42a817 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 8 Oct 2024 22:08:10 +1100 Subject: [PATCH 31/47] Minor --- src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl b/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl index 99b9873d..b12801e4 100644 --- a/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl +++ b/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl @@ -81,7 +81,7 @@ function assemble_patch_matrices(Ph::FESpace,ap;local_solver=LUSolver()) end function assemble_patch_matrices(Ph::GridapDistributed.DistributedFESpace,ap;local_solver=LUSolver()) - u, v = get_trial_fe_basis(Vh), get_fe_basis(Vh) + u, v = get_trial_fe_basis(Ph), get_fe_basis(Ph) matdata = collect_cell_matrix(Ph,Ph,ap(u,v)) Ap, Ap_ns = map(local_views(Ph),matdata) do Ph, matdata assem = SparseMatrixAssembler(Ph,Ph) @@ -99,7 +99,7 @@ function update_patch_matrices!(Ap,Ap_ns,Ph::FESpace,ap) end function update_patch_matrices!(Ap,Ap_ns,Ph::GridapDistributed.DistributedFESpace,ap) - u, v = get_trial_fe_basis(Vh), get_fe_basis(Vh) + u, v = get_trial_fe_basis(Ph), get_fe_basis(Ph) matdata = collect_cell_matrix(Ph,Ph,ap(u,v)) map(Ap, Ap_ns, local_views(Ph), matdata) do Ap, Ap_ns, Ph, matdata assem = SparseMatrixAssembler(Ph,Ph) From bfd2a5f69e81e7d31436453debb7efd4b1252e27 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 23 Oct 2024 12:53:57 +1100 Subject: [PATCH 32/47] Bugfix in LocalProjection maps when used with empty triangulations --- src/MultilevelTools/LocalProjectionMaps.jl | 12 ++++- .../MultilevelTools/LocalProjectionMaps.jl | 51 ++++++++++++++++--- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/src/MultilevelTools/LocalProjectionMaps.jl b/src/MultilevelTools/LocalProjectionMaps.jl index 6d277223..c56f5b2b 100644 --- a/src/MultilevelTools/LocalProjectionMaps.jl +++ b/src/MultilevelTools/LocalProjectionMaps.jl @@ -129,12 +129,17 @@ function _compute_local_projections( q = SingleFieldFEBasis(test_shapefuns,Ω,TestBasis(),ReferenceDomain()) op = k.op.op - lhs_data = get_array(∫(p⋅q)dΩ) + lhs_data = get_array(∫(q⋅p)dΩ) rhs_data = get_array(∫(q⋅op(u))dΩ) basis_data = CellData.get_data(q) return lazy_map(k,lhs_data,rhs_data,basis_data) end +function Arrays.return_value(::LocalProjectionMap,lhs::Matrix{T},rhs::A,basis) where {T,A<:Union{Matrix{T},Vector{T}}} + vec = zeros(T,size(rhs)) + return linear_combination(vec,basis) +end + function Arrays.return_cache(::LocalProjectionMap,lhs::Matrix{T},rhs::A,basis) where {T,A<:Union{Matrix{T},Vector{T}}} return CachedArray(copy(lhs)), CachedArray(copy(rhs)) end @@ -228,6 +233,11 @@ function _compute_local_projections( return lazy_map(k,lhs_data,rhs_data,basis_data,ids) end +function Arrays.return_value(::LocalProjectionMap,lhs::Matrix{T},rhs::A,basis,ids) where {T,A<:Union{Matrix{T},Vector{T}}} + vec = zeros(T,size(rhs)) + return linear_combination(vec,basis) +end + function Arrays.return_cache(::LocalProjectionMap,lhs::Matrix{T},rhs::A,basis,ids) where {T,A<:Union{Matrix{T},Vector{T}}} return CachedArray(copy(lhs)), CachedArray(copy(rhs)), CachedArray(zeros(eltype(rhs),(length(ids),size(rhs,2)))) end diff --git a/test/_dev/MultilevelTools/LocalProjectionMaps.jl b/test/_dev/MultilevelTools/LocalProjectionMaps.jl index 9fb73ecc..8af39925 100644 --- a/test/_dev/MultilevelTools/LocalProjectionMaps.jl +++ b/test/_dev/MultilevelTools/LocalProjectionMaps.jl @@ -5,25 +5,38 @@ using GridapSolvers using GridapSolvers.MultilevelTools using Gridap.Arrays, Gridap.CellData, Gridap.FESpaces -np = (2,2) +np = (2,2,1) ranks = with_debug() do distribute distribute(LinearIndices((prod(np),))) end +function half_empty_trian(ranks,model) + cell_ids = get_cell_gids(model) + trians = map(ranks,local_views(model),partition(cell_ids)) do rank, model, ids + cell_mask = zeros(Bool, num_cells(model)) + if rank ∈ (3,4) + cell_mask[own_to_local(ids)] .= true + end + Triangulation(model,cell_mask) + end + GridapDistributed.DistributedTriangulation(trians,model) +end + layer(x) = sign(x)*abs(x)^(1/3) -cmap(x) = VectorValue(layer(x[1]),layer(x[2])) -model = CartesianDiscreteModel((0,-1,0,-1),(10,10),map=cmap) +cmap(x) = VectorValue(layer(x[1]),layer(x[2]),x[3]) +model = CartesianDiscreteModel(ranks,np,(0,1,0,1,0,1),(5,5,5),map=cmap) -Ω = Triangulation(model) +#Ω = Triangulation(model) +Ω = half_empty_trian(ranks,model) dΩ = Measure(Ω,2) order = 2 -qdegree = 2*(order+1) -reffe_u = ReferenceFE(lagrangian,VectorValue{2,Float64},order) +qdegree = 2*(order) +reffe_u = ReferenceFE(lagrangian,VectorValue{3,Float64},order) reffe_p = ReferenceFE(lagrangian,Float64,order-1;space=:P) -V = TestFESpace(model,reffe_u,dirichlet_tags="boundary"); -Q = TestFESpace(model,reffe_p;conformity=:L2,constraint=:zeromean) +V = TestFESpace(Ω,reffe_u,dirichlet_tags="boundary"); +Q = TestFESpace(Ω,reffe_p;conformity=:L2) mfs = Gridap.MultiField.BlockMultiFieldStyle() X = MultiFieldFESpace([V,Q];style=mfs) @@ -45,6 +58,27 @@ F-G norm(F-G) maximum(abs.(F-G)) +u,p = get_trial_fe_basis(X) +v,q = get_fe_basis(X) + +Πu = Π_Qh(u) +∇v = ∇⋅(v) +Πu ⋅ ∇v + +∫(Π_Qh(u)⋅(∇⋅v))dΩ + +cf = Π_Qh(u)⋅(∇⋅v) + +i = 1 +integrate(cf.fields.items[i],dΩ.measures.items[i]) + +map(num_cells,local_views(Ω)) + +data = Πu.fields.items[1].cell_field.args[1].args[1] +testitem(data) + +length(u.fields.items[1].cell_basis) + ####################################################################### Ωf = Triangulation(model,tags="interior") @@ -61,6 +95,7 @@ cf1 = Π_Qh(u1) u2 = get_trial_fe_basis(Xf)[1] cf2 = Π_Qh(u2) +testitem(cf2.cell_field.args[1].args[1]) ∫(cf2)dΩv # Not OK cf2_bis = GenericCellField(cf2.cell_field.args[1].args[1],Ωf,ReferenceDomain()) From 231c52c4e92021c8fa665a90a99a5d3f6a19b409 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 28 Oct 2024 14:36:34 +1100 Subject: [PATCH 33/47] Minor bugfix in tests --- test/LinearSolvers/SmoothersTests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/LinearSolvers/SmoothersTests.jl b/test/LinearSolvers/SmoothersTests.jl index 6c315706..6adc056b 100644 --- a/test/LinearSolvers/SmoothersTests.jl +++ b/test/LinearSolvers/SmoothersTests.jl @@ -29,7 +29,7 @@ function smoothers_driver(parts,model,P) A, b = get_matrix(op), get_vector(op) solver = CGSolver(P;rtol=1.0e-8,verbose=i_am_main(parts)) - ns = numerical_setup(sumbolic_setup(solver,A),A) + ns = numerical_setup(symbolic_setup(solver,A),A) x = allocate_in_domain(A); fill!(x,zero(eltype(x))) solve!(x,ns,b) From c6bba391250844a0a05989f13fd0e08e28c25d48 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 29 Oct 2024 09:35:35 +1100 Subject: [PATCH 34/47] Added get_cell_conformity --- src/MultilevelTools/FESpaceHierarchies.jl | 60 +++---------------- src/MultilevelTools/GridapFixes.jl | 45 ++++++++++++++ .../DistributedPatchFESpaces.jl | 11 ++-- src/PatchBasedSmoothers/PatchFESpaces.jl | 6 +- src/PatchBasedSmoothers/PatchSolvers.jl | 8 +-- .../PatchTransferOperators.jl | 3 +- src/PatchBasedSmoothers/VankaSolvers.jl | 2 + 7 files changed, 64 insertions(+), 71 deletions(-) diff --git a/src/MultilevelTools/FESpaceHierarchies.jl b/src/MultilevelTools/FESpaceHierarchies.jl index 2331af41..8163635a 100644 --- a/src/MultilevelTools/FESpaceHierarchies.jl +++ b/src/MultilevelTools/FESpaceHierarchies.jl @@ -1,10 +1,8 @@ -struct FESpaceHierarchyLevel{A,B,C,D,E} +struct FESpaceHierarchyLevel{A,B,C} level :: Int fe_space :: A fe_space_red :: B - cell_conformity :: C - cell_conformity_red :: D - mh_level :: E + mh_level :: C end """ @@ -25,11 +23,9 @@ get_fe_space_before_redist(sh::FESpaceHierarchy,lev::Int) = get_fe_space_before_ get_fe_space_before_redist(a::FESpaceHierarchyLevel) = a.fe_space get_cell_conformity(sh::FESpaceHierarchy,lev::Int) = get_cell_conformity(sh[lev]) -get_cell_conformity(a::FESpaceHierarchyLevel{A,Nothing}) where A = a.cell_conformity -get_cell_conformity(a::FESpaceHierarchyLevel{A,B}) where {A,B} = a.cell_conformity_red - +get_cell_conformity(a::FESpaceHierarchyLevel) = get_cell_conformity(get_fe_space(a)) get_cell_conformity_before_redist(sh::FESpaceHierarchy,lev::Int) = get_cell_conformity_before_redist(sh[lev]) -get_cell_conformity_before_redist(a::FESpaceHierarchyLevel) = a.cell_conformity +get_cell_conformity_before_redist(a::FESpaceHierarchyLevel) = get_cell_conformity(get_fe_space_before_redist(a)) get_model(sh::FESpaceHierarchy,level::Integer) = get_model(sh[level]) get_model(a::FESpaceHierarchyLevel) = get_model(a.mh_level) @@ -45,56 +41,22 @@ has_refinement(a::FESpaceHierarchyLevel) = has_refinement(a.mh_level) # Test/Trial FESpaces for ModelHierarchyLevels -function _cell_conformity( - model::DiscreteModel, - reffe::Tuple{<:Gridap.FESpaces.ReferenceFEName,Any,Any}; - conformity=nothing, kwargs... -) :: CellConformity - basis, reffe_args, reffe_kwargs = reffe - cell_reffe = ReferenceFE(model,basis,reffe_args...;reffe_kwargs...) - conformity = Conformity(Gridap.Arrays.testitem(cell_reffe),conformity) - return CellConformity(cell_reffe,conformity) -end - -function _cell_conformity( - model::DiscreteModel, - reffe::ReferenceFE; - conformity=nothing, kwargs... -) :: CellConformity - cell_reffe = CompressedArray([reffe],fill(one(Int8),num_cells(model))) - conformity = Conformity(reffe,conformity) - return CellConformity(cell_reffe,conformity) -end - -function _cell_conformity( - model::GridapDistributed.DistributedDiscreteModel,args...;kwargs... -) :: AbstractVector{<:CellConformity} - cell_conformities = map(local_views(model)) do model - _cell_conformity(model,args...;kwargs...) - end - return cell_conformities -end - function FESpaces.FESpace(mh::ModelHierarchyLevel,args...;kwargs...) if has_redistribution(mh) cparts, _ = get_old_and_new_parts(mh.red_glue,Val(false)) Vh = i_am_in(cparts) ? FESpace(get_model_before_redist(mh),args...;kwargs...) : nothing Vh_red = FESpace(get_model(mh),args...;kwargs...) - cell_conformity = i_am_in(cparts) ? _cell_conformity(get_model_before_redist(mh),args...;kwargs...) : nothing - cell_conformity_red = _cell_conformity(get_model(mh),args...;kwargs...) else Vh = FESpace(get_model(mh),args...;kwargs...) Vh_red = nothing - cell_conformity = _cell_conformity(get_model(mh),args...;kwargs...) - cell_conformity_red = nothing end - return FESpaceHierarchyLevel(mh.level,Vh,Vh_red,cell_conformity,cell_conformity_red,mh) + return FESpaceHierarchyLevel(mh.level,Vh,Vh_red,mh) end function FESpaces.TrialFESpace(a::FESpaceHierarchyLevel,args...;kwargs...) Uh = !isa(a.fe_space,Nothing) ? TrialFESpace(a.fe_space,args...;kwargs...) : nothing Uh_red = !isa(a.fe_space_red,Nothing) ? TrialFESpace(a.fe_space_red,args...;kwargs...) : nothing - return FESpaceHierarchyLevel(a.level,Uh,Uh_red,a.cell_conformity,a.cell_conformity_red,a.mh_level) + return FESpaceHierarchyLevel(a.level,Uh,Uh_red,a.mh_level) end # Test/Trial FESpaces for ModelHierarchies/FESpaceHierarchy @@ -132,9 +94,7 @@ function Gridap.MultiField.MultiFieldFESpace(spaces::Vector{<:FESpaceHierarchyLe level = spaces[1].level Uh = all(map(s -> !isa(s.fe_space,Nothing),spaces)) ? MultiFieldFESpace(map(s -> s.fe_space, spaces); kwargs...) : nothing Uh_red = all(map(s -> !isa(s.fe_space_red,Nothing),spaces)) ? MultiFieldFESpace(map(s -> s.fe_space_red, spaces); kwargs...) : nothing - cell_conformity = map(s -> s.cell_conformity, spaces) - cell_conformity_red = map(s -> s.cell_conformity_red, spaces) - return FESpaceHierarchyLevel(level,Uh,Uh_red,cell_conformity,cell_conformity_red,first(spaces).mh_level) + return FESpaceHierarchyLevel(level,Uh,Uh_red,first(spaces).mh_level) end function Gridap.MultiField.MultiFieldFESpace(spaces::Vector{<:HierarchicalArray};kwargs...) @@ -158,15 +118,11 @@ function FESpaces.ConstantFESpace(mh::MultilevelTools.ModelHierarchyLevel) cparts, _ = get_old_and_new_parts(mh.red_glue,Val(false)) Vh = i_am_in(cparts) ? ConstantFESpace(get_model_before_redist(mh)) : nothing Vh_red = ConstantFESpace(get_model(mh)) - cell_conformity = i_am_in(cparts) ? _cell_conformity(get_model_before_redist(mh),reffe) : nothing - cell_conformity_red = _cell_conformity(get_model(mh),reffe) else Vh = ConstantFESpace(get_model(mh)) Vh_red = nothing - cell_conformity = _cell_conformity(get_model(mh),reffe) - cell_conformity_red = nothing end - return FESpaceHierarchyLevel(mh.level,Vh,Vh_red,cell_conformity,cell_conformity_red,mh) + return FESpaceHierarchyLevel(mh.level,Vh,Vh_red,mh) end # Computing system matrices diff --git a/src/MultilevelTools/GridapFixes.jl b/src/MultilevelTools/GridapFixes.jl index 712f6300..99ed7ca4 100644 --- a/src/MultilevelTools/GridapFixes.jl +++ b/src/MultilevelTools/GridapFixes.jl @@ -40,3 +40,48 @@ function Arrays.lazy_map(k::Broadcasting{<:Fields.VoidBasisMap},a::Arrays.LazyAr lazy_map(a.maps.value,args) end """ + +############################################################################################ +# New API: get_cell_conformity + +using Gridap.FESpaces: CellConformity, NodeToDofGlue +using Gridap.TensorValues: change_eltype + +function get_cell_polytopes(trian::Triangulation) + reffes = get_reffes(trian) + polys = map(get_polytope,reffes) + ctypes = get_cell_type(trian) + return expand_cell_data(polys,ctypes) +end + +function get_cell_conformity(space::UnstructuredFESpace{V,<:CellConformity}) where V + return space.metadata +end + +function get_cell_conformity(space::UnstructuredFESpace{V,<:NodeToDofGlue{T}}) where {V,T} + cell_polys = get_cell_polytopes(get_triangulation(space)) + polys, ctypes = compress_cell_data(cell_polys) + reffes = map(p -> LagrangianRefFE(change_eltype(T,eltype(V)),p,1), polys) + cell_reffe = expand_cell_data(reffes,ctypes) + return CellConformity(cell_reffe,H1Conformity()) +end + +for ST in [:TrialFESpace,ZeroMeanFESpace,FESpaceWithConstantFixed] + @eval begin + function get_cell_conformity(space::$ST) + return get_cell_conformity(space.space) + end + end +end + +function get_cell_conformity(space::MultiFieldFESpace) + map(get_cell_conformity,space) +end + +function get_cell_conformity(space::GridapDistributed.DistributedFESpace) + map(get_cell_conformity,local_views(space)) +end + +function get_cell_conformity(space::GridapDistributed.DistributedMultiFieldFESpace) + map(get_cell_conformity,space) +end diff --git a/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl b/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl index a34150fa..57a6c659 100644 --- a/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl +++ b/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl @@ -4,11 +4,9 @@ const DistributedPatchFESpace = GridapDistributed.DistributedSingleFieldFESpace{ function PatchFESpace( space::GridapDistributed.DistributedSingleFieldFESpace, - patch_decomposition::DistributedPatchDecomposition, - reffe::Union{ReferenceFE,Tuple{<:ReferenceFEs.ReferenceFEName,Any,Any}}; - conformity=nothing + patch_decomposition::DistributedPatchDecomposition ) - cell_conformity = MultilevelTools._cell_conformity(patch_decomposition.model,reffe;conformity=conformity) + cell_conformity = get_cell_conformity(space) return PatchFESpace(space,patch_decomposition,cell_conformity) end @@ -48,10 +46,9 @@ function PatchFESpace( sh::FESpaceHierarchy,patch_decompositions::AbstractArray ) nlevs = num_levels(sh) - psh = map(view(sh,1:nlevs-1),patch_decompositions) do shl,decomp + psh = map(view(sh,1:nlevs-1),patch_decompositions) do shl, decomp space = MultilevelTools.get_fe_space(shl) - cell_conformity = MultilevelTools.get_cell_conformity(shl) - return PatchFESpace(space,decomp,cell_conformity) + return PatchFESpace(space,decomp) end return psh end diff --git a/src/PatchBasedSmoothers/PatchFESpaces.jl b/src/PatchBasedSmoothers/PatchFESpaces.jl index a95d992d..5950a42f 100644 --- a/src/PatchBasedSmoothers/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/PatchFESpaces.jl @@ -62,8 +62,6 @@ end function PatchFESpace( space::FESpaces.SingleFieldFESpace, patch_decomposition::PatchDecomposition, - reffe::Union{ReferenceFE,Tuple{<:ReferenceFEs.ReferenceFEName,Any,Any}}; - conformity=nothing, patches_mask=Fill(false,num_patches(patch_decomposition)) ) @@ -76,11 +74,9 @@ If `patches_mask[p] = true`, the patch `p` is ignored. Used in parallel. function PatchFESpace( space::FESpaces.SingleFieldFESpace, patch_decomposition::PatchDecomposition, - reffe::Union{ReferenceFE,Tuple{<:ReferenceFEs.ReferenceFEName,Any,Any}}; - conformity=nothing, patches_mask=Fill(false,num_patches(patch_decomposition)) ) - cell_conformity = MultilevelTools._cell_conformity(patch_decomposition.model,reffe;conformity=conformity) + cell_conformity = get_cell_conformity(space) return PatchFESpace(space,patch_decomposition,cell_conformity;patches_mask=patches_mask) end diff --git a/src/PatchBasedSmoothers/PatchSolvers.jl b/src/PatchBasedSmoothers/PatchSolvers.jl index 39960241..5dc850c6 100644 --- a/src/PatchBasedSmoothers/PatchSolvers.jl +++ b/src/PatchBasedSmoothers/PatchSolvers.jl @@ -8,16 +8,14 @@ struct PatchSolver{A,B,C,D,E} <: Algebra.LinearSolver end function PatchSolver( - space::FESpace,patch_decomposition::PatchDecomposition,biform,reffe;conformity=nothing + space::FESpace,patch_decomposition::PatchDecomposition,biform::Function ) - cell_conformity = MultilevelTools._cell_conformity( - get_background_model(get_triangulation(space)),reffe;conformity - ) + cell_conformity = get_cell_conformity(space) return PatchSolver(space,patch_decomposition,biform,cell_conformity) end function PatchSolver( - space::FESpace,patch_decomposition::PatchDecomposition,biform,cell_conformity::CellConformity + space::FESpace,patch_decomposition::PatchDecomposition,biform::Function,cell_conformity::CellConformity ) cell_dof_ids = get_cell_dof_ids(space) patch_cells = get_patch_cells(patch_decomposition) diff --git a/src/PatchBasedSmoothers/PatchTransferOperators.jl b/src/PatchBasedSmoothers/PatchTransferOperators.jl index 36025ecc..4d3aa747 100644 --- a/src/PatchBasedSmoothers/PatchTransferOperators.jl +++ b/src/PatchBasedSmoothers/PatchTransferOperators.jl @@ -66,8 +66,7 @@ function _get_patch_cache(lev,sh,PD,lhs,rhs,is_nonlinear,cache_refine) cparts = get_level_parts(sh,lev+1) if i_am_in(cparts) # Patch-based correction fespace - cell_conformity = MultilevelTools.get_cell_conformity_before_redist(sh,lev) - Ph = PatchFESpace(Uh,PD,cell_conformity) + Ph = PatchFESpace(Uh,PD) # Solver caches ap(u,v) = is_nonlinear ? lhs(zero(Uh),u,v) : lhs(u,v) diff --git a/src/PatchBasedSmoothers/VankaSolvers.jl b/src/PatchBasedSmoothers/VankaSolvers.jl index 6e05fdcc..251a9031 100644 --- a/src/PatchBasedSmoothers/VankaSolvers.jl +++ b/src/PatchBasedSmoothers/VankaSolvers.jl @@ -37,6 +37,7 @@ function VankaSolver(space::FESpace,patch_cells::Table{<:Integer}) end function VankaSolver(space::GridapDistributed.DistributedMultiFieldFESpace) + @notimplemented "Distributed not implemented yet" local_solvers = map(VankaSolver,local_views(space)) return SchwarzLinearSolver(local_solvers) end @@ -45,6 +46,7 @@ function VankaSolver( space::GridapDistributed.DistributedMultiFieldFESpace, patch_decomposition::DistributedPatchDecomposition ) + @notimplemented "Distributed not implemented yet" local_solvers = map(VankaSolver,local_views(space),local_views(patch_decomposition)) return SchwarzLinearSolver(local_solvers) end From 7bb163743f2f7fe771ad6182f07cbde07b75c13a Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 29 Oct 2024 11:36:04 +1100 Subject: [PATCH 35/47] Fixes --- src/MultilevelTools/FESpaceHierarchies.jl | 5 ----- src/MultilevelTools/GridapFixes.jl | 4 ++-- .../DistributedPatchFESpaces.jl | 8 -------- src/PatchBasedSmoothers/PatchBasedSmoothers.jl | 1 + src/PatchBasedSmoothers/PatchFESpaces.jl | 16 +++------------- .../PatchMultiFieldFESpaces.jl | 1 - 6 files changed, 6 insertions(+), 29 deletions(-) diff --git a/src/MultilevelTools/FESpaceHierarchies.jl b/src/MultilevelTools/FESpaceHierarchies.jl index 8163635a..a52d97c2 100644 --- a/src/MultilevelTools/FESpaceHierarchies.jl +++ b/src/MultilevelTools/FESpaceHierarchies.jl @@ -22,11 +22,6 @@ FESpaces.get_fe_space(a::FESpaceHierarchyLevel{A,B}) where {A,B} = a.fe_space_re get_fe_space_before_redist(sh::FESpaceHierarchy,lev::Int) = get_fe_space_before_redist(sh[lev]) get_fe_space_before_redist(a::FESpaceHierarchyLevel) = a.fe_space -get_cell_conformity(sh::FESpaceHierarchy,lev::Int) = get_cell_conformity(sh[lev]) -get_cell_conformity(a::FESpaceHierarchyLevel) = get_cell_conformity(get_fe_space(a)) -get_cell_conformity_before_redist(sh::FESpaceHierarchy,lev::Int) = get_cell_conformity_before_redist(sh[lev]) -get_cell_conformity_before_redist(a::FESpaceHierarchyLevel) = get_cell_conformity(get_fe_space_before_redist(a)) - get_model(sh::FESpaceHierarchy,level::Integer) = get_model(sh[level]) get_model(a::FESpaceHierarchyLevel) = get_model(a.mh_level) diff --git a/src/MultilevelTools/GridapFixes.jl b/src/MultilevelTools/GridapFixes.jl index 99ed7ca4..5db5568f 100644 --- a/src/MultilevelTools/GridapFixes.jl +++ b/src/MultilevelTools/GridapFixes.jl @@ -54,11 +54,11 @@ function get_cell_polytopes(trian::Triangulation) return expand_cell_data(polys,ctypes) end -function get_cell_conformity(space::UnstructuredFESpace{V,<:CellConformity}) where V +function get_cell_conformity(space::UnconstrainedFESpace{V,<:CellConformity}) where V return space.metadata end -function get_cell_conformity(space::UnstructuredFESpace{V,<:NodeToDofGlue{T}}) where {V,T} +function get_cell_conformity(space::UnconstrainedFESpace{V,<:NodeToDofGlue{T}}) where {V,T} cell_polys = get_cell_polytopes(get_triangulation(space)) polys, ctypes = compress_cell_data(cell_polys) reffes = map(p -> LagrangianRefFE(change_eltype(T,eltype(V)),p,1), polys) diff --git a/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl b/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl index 57a6c659..1dbf1b6c 100644 --- a/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl +++ b/src/PatchBasedSmoothers/DistributedPatchFESpaces.jl @@ -2,14 +2,6 @@ const DistributedPatchFESpace = GridapDistributed.DistributedSingleFieldFESpace{<:AbstractVector{<:PatchFESpace}} -function PatchFESpace( - space::GridapDistributed.DistributedSingleFieldFESpace, - patch_decomposition::DistributedPatchDecomposition -) - cell_conformity = get_cell_conformity(space) - return PatchFESpace(space,patch_decomposition,cell_conformity) -end - function PatchFESpace( space::GridapDistributed.DistributedSingleFieldFESpace, patch_decomposition::DistributedPatchDecomposition, diff --git a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl index 43053cae..ab7416b4 100644 --- a/src/PatchBasedSmoothers/PatchBasedSmoothers.jl +++ b/src/PatchBasedSmoothers/PatchBasedSmoothers.jl @@ -10,6 +10,7 @@ using PartitionedArrays using GridapDistributed using GridapSolvers.MultilevelTools +using GridapSolvers.MultilevelTools: get_cell_conformity export PatchDecomposition, Closure export PatchFESpace diff --git a/src/PatchBasedSmoothers/PatchFESpaces.jl b/src/PatchBasedSmoothers/PatchFESpaces.jl index 5950a42f..25f050ab 100644 --- a/src/PatchBasedSmoothers/PatchFESpaces.jl +++ b/src/PatchBasedSmoothers/PatchFESpaces.jl @@ -60,24 +60,14 @@ end @doc """ function PatchFESpace( - space::FESpaces.SingleFieldFESpace, - patch_decomposition::PatchDecomposition, - patches_mask=Fill(false,num_patches(patch_decomposition)) + space::FESpace,patch_decomposition;kwargs... ) - -Constructs a `PatchFESpace` from a global `SingleFieldFESpace` and a `PatchDecomposition`. -The conformity of the FESpace is deduced from `reffe` and `conformity`, which need to be -the same as the ones used to construct the global FESpace. - -If `patches_mask[p] = true`, the patch `p` is ignored. Used in parallel. """ function PatchFESpace( - space::FESpaces.SingleFieldFESpace, - patch_decomposition::PatchDecomposition, - patches_mask=Fill(false,num_patches(patch_decomposition)) + space::FESpace,patch_decomposition;kwargs... ) cell_conformity = get_cell_conformity(space) - return PatchFESpace(space,patch_decomposition,cell_conformity;patches_mask=patches_mask) + return PatchFESpace(space,patch_decomposition,cell_conformity;kwargs...) end @doc """ diff --git a/src/PatchBasedSmoothers/PatchMultiFieldFESpaces.jl b/src/PatchBasedSmoothers/PatchMultiFieldFESpaces.jl index 3d4fe41d..9fe7f448 100644 --- a/src/PatchBasedSmoothers/PatchMultiFieldFESpaces.jl +++ b/src/PatchBasedSmoothers/PatchMultiFieldFESpaces.jl @@ -28,7 +28,6 @@ function PatchFESpace( cell_conformity::Vector; patches_mask = default_patches_mask(patch_decomposition) ) - field_spaces = map((s,c) -> PatchFESpace(s,patch_decomposition,c;patches_mask),space,cell_conformity) part_spaces = map(MultiFieldFESpace,GridapDistributed.to_parray_of_arrays(map(local_views,field_spaces))) From bd6bfbf8360fbb4dc9e7e2e28691e7f894d2ef35 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 29 Oct 2024 12:21:50 +1100 Subject: [PATCH 36/47] Added LinearSolverFromSmoother --- .../LinearSolverFromSmoothers.jl | 50 +++++++++++++++++++ src/LinearSolvers/LinearSolvers.jl | 4 ++ test/LinearSolvers/SmoothersTests.jl | 6 +-- 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/LinearSolvers/LinearSolverFromSmoothers.jl diff --git a/src/LinearSolvers/LinearSolverFromSmoothers.jl b/src/LinearSolvers/LinearSolverFromSmoothers.jl new file mode 100644 index 00000000..1e6264db --- /dev/null +++ b/src/LinearSolvers/LinearSolverFromSmoothers.jl @@ -0,0 +1,50 @@ + +struct LinearSolverFromSmoother{A} <: Algebra.LinearSolver + smoother :: A +end + +struct LinearSolverFromSmootherSS{A,B} <: Algebra.SymbolicSetup + smoother :: A + smoother_ss :: B +end + +struct LinearSolverFromSmootherNS{A,B,C} <: Algebra.NumericalSetup + smoother :: A + smoother_ns :: B + caches :: C +end + +function Gridap.Algebra.symbolic_setup(solver::LinearSolverFromSmoother, mat::AbstractMatrix) + ss = symbolic_setup(solver.smoother,mat) + return LinearSolverFromSmootherSS(solver.smoother,ss) +end + +function Gridap.Algebra.numerical_setup(ss::LinearSolverFromSmootherSS, mat::AbstractMatrix) + ns = numerical_setup(ss.smoother_ss, mat) + caches = allocate_in_domain(mat) + return LinearSolverFromSmootherNS(ss.smoother,ns,caches) +end + +function Gridap.Algebra.numerical_setup(ss::LinearSolverFromSmootherSS, mat::AbstractMatrix, vec::AbstractVector) + ns = numerical_setup(ss.smoother_ss, mat, vec) + caches = allocate_in_domain(mat) + return LinearSolverFromSmootherNS(ss.smoother,ns,caches) +end + +function Gridap.Algebra.numerical_setup!(ns::LinearSolverFromSmootherNS, mat::AbstractMatrix) + numerical_setup!(ns.smoother_ns, mat) + return ns +end + +function Gridap.Algebra.numerical_setup!(ns::LinearSolverFromSmootherNS, mat::AbstractMatrix, vec::AbstractVector) + numerical_setup!(ns.smoother_ns, mat, vec) + return ns +end + +function Gridap.Algebra.solve!(x::AbstractVector,ns::LinearSolverFromSmootherNS, b::AbstractVector) + r = ns.caches + fill!(x,zero(eltype(x))) + copy!(r,b) + solve!(x,ns.smoother_ns,r) + return x +end diff --git a/src/LinearSolvers/LinearSolvers.jl b/src/LinearSolvers/LinearSolvers.jl index 43b0658d..ff806b34 100644 --- a/src/LinearSolvers/LinearSolvers.jl +++ b/src/LinearSolvers/LinearSolvers.jl @@ -18,6 +18,7 @@ using GridapSolvers.MultilevelTools using GridapSolvers.SolverInterfaces using GridapSolvers.PatchBasedSmoothers +export LinearSolverFromSmoother export JacobiLinearSolver export RichardsonSmoother export SymGaussSeidelSmoother @@ -52,9 +53,12 @@ include("PETSc/ElasticitySolvers.jl") include("PETSc/HipmairXuSolvers.jl") include("IdentityLinearSolvers.jl") + +include("LinearSolverFromSmoothers.jl") include("JacobiLinearSolvers.jl") include("RichardsonSmoothers.jl") include("SymGaussSeidelSmoothers.jl") + include("GMGLinearSolvers.jl") include("IterativeLinearSolvers.jl") include("SchurComplementSolvers.jl") diff --git a/test/LinearSolvers/SmoothersTests.jl b/test/LinearSolvers/SmoothersTests.jl index 6adc056b..8261c7fd 100644 --- a/test/LinearSolvers/SmoothersTests.jl +++ b/test/LinearSolvers/SmoothersTests.jl @@ -18,7 +18,6 @@ function smoothers_driver(parts,model,P) reffe = ReferenceFE(lagrangian,Float64,order) Vh = TestFESpace(model,reffe;conformity=:H1,dirichlet_tags="boundary") Uh = TrialFESpace(Vh,sol) - u = interpolate(sol,Uh) Ω = Triangulation(model) dΩ = Measure(Ω,qorder) @@ -46,12 +45,13 @@ end function main_smoother_driver(parts,model,smoother) if smoother === :richardson - P = RichardsonSmoother(JacobiLinearSolver(),5,2.0/3.0) + S = RichardsonSmoother(JacobiLinearSolver(),5,2.0/3.0) elseif smoother === :sym_gauss_seidel - P = SymGaussSeidelSmoother(5) + S = SymGaussSeidelSmoother(5) else error("Unknown smoother") end + P = LinearSolverFromSmoother(S) smoothers_driver(parts,model,P) end From 85895d417faee97746a3be6f8c8d57060e893fc1 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 29 Oct 2024 12:41:54 +1100 Subject: [PATCH 37/47] Removedd manifest from docs --- docs/Manifest.toml | 893 --------------------------------------------- 1 file changed, 893 deletions(-) delete mode 100644 docs/Manifest.toml diff --git a/docs/Manifest.toml b/docs/Manifest.toml deleted file mode 100644 index 9f908d25..00000000 --- a/docs/Manifest.toml +++ /dev/null @@ -1,893 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -julia_version = "1.9.4" -manifest_format = "2.0" -project_hash = "05ee931d038d2d9d772b560fd10c3fb284fdf988" - -[[deps.ANSIColoredPrinters]] -git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" -uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" -version = "0.0.1" - -[[deps.AbstractFFTs]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "d92ad398961a3ed262d8bf04a1a2b8340f915fef" -uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" -version = "1.5.0" - - [deps.AbstractFFTs.extensions] - AbstractFFTsChainRulesCoreExt = "ChainRulesCore" - AbstractFFTsTestExt = "Test" - - [deps.AbstractFFTs.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[deps.AbstractTrees]] -git-tree-sha1 = "2d9c9a55f9c93e8887ad391fbae72f8ef55e1177" -uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" -version = "0.4.5" - -[[deps.Adapt]] -deps = ["LinearAlgebra", "Requires"] -git-tree-sha1 = "6a55b747d1812e699320963ffde36f1ebdda4099" -uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "4.0.4" -weakdeps = ["StaticArrays"] - - [deps.Adapt.extensions] - AdaptStaticArraysExt = "StaticArrays" - -[[deps.ArgCheck]] -git-tree-sha1 = "a3a402a35a2f7e0b87828ccabbd5ebfbebe356b4" -uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197" -version = "2.3.0" - -[[deps.ArgParse]] -deps = ["Logging", "TextWrap"] -git-tree-sha1 = "22cf435ac22956a7b45b0168abbc871176e7eecc" -uuid = "c7e460c6-2fb9-53a9-8c5b-16f535851c63" -version = "1.2.0" - -[[deps.ArgTools]] -uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" -version = "1.1.1" - -[[deps.ArrayInterface]] -deps = ["Adapt", "LinearAlgebra", "Requires", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "c5aeb516a84459e0318a02507d2261edad97eb75" -uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "7.7.1" - - [deps.ArrayInterface.extensions] - ArrayInterfaceBandedMatricesExt = "BandedMatrices" - ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices" - ArrayInterfaceCUDAExt = "CUDA" - ArrayInterfaceGPUArraysCoreExt = "GPUArraysCore" - ArrayInterfaceStaticArraysCoreExt = "StaticArraysCore" - ArrayInterfaceTrackerExt = "Tracker" - - [deps.ArrayInterface.weakdeps] - BandedMatrices = "aae01518-5342-5314-be14-df237901396f" - BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" - CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" - GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" - StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" - Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" - -[[deps.ArrayLayouts]] -deps = ["FillArrays", "LinearAlgebra"] -git-tree-sha1 = "ce2ca959f932f5dad70697dd93133d1167cf1e4e" -uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" -version = "1.10.2" -weakdeps = ["SparseArrays"] - - [deps.ArrayLayouts.extensions] - ArrayLayoutsSparseArraysExt = "SparseArrays" - -[[deps.Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" - -[[deps.AutoHashEquals]] -deps = ["Pkg"] -git-tree-sha1 = "daaeb6f7f77b88c072a83a2451801818acb5c63b" -uuid = "15f4f7f2-30c1-5605-9d31-71845cf9641f" -version = "2.1.0" - -[[deps.BSON]] -git-tree-sha1 = "4c3e506685c527ac6a54ccc0c8c76fd6f91b42fb" -uuid = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0" -version = "0.3.9" - -[[deps.Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" - -[[deps.BlockArrays]] -deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra"] -git-tree-sha1 = "9a9610fbe5779636f75229e423e367124034af41" -uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -version = "0.16.43" - -[[deps.CEnum]] -git-tree-sha1 = "eb4cb44a499229b3b8426dcfb5dd85333951ff90" -uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" -version = "0.4.2" - -[[deps.CircularArrays]] -deps = ["OffsetArrays"] -git-tree-sha1 = "e24a6f390e5563583bb4315c73035b5b3f3e7ab4" -uuid = "7a955b69-7140-5f4e-a0ed-f168c5e2e749" -version = "1.4.0" - -[[deps.CodecZlib]] -deps = ["TranscodingStreams", "Zlib_jll"] -git-tree-sha1 = "bce6804e5e6044c6daab27bb533d1295e4a2e759" -uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.6" - -[[deps.Combinatorics]] -git-tree-sha1 = "08c8b6831dc00bfea825826be0bc8336fc369860" -uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" -version = "1.0.2" - -[[deps.CommonSubexpressions]] -deps = ["MacroTools", "Test"] -git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" -uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" -version = "0.3.0" - -[[deps.Compat]] -deps = ["TOML", "UUIDs"] -git-tree-sha1 = "8ae8d32e09f0dcf42a36b90d4e17f5dd2e4c4215" -uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.16.0" -weakdeps = ["Dates", "LinearAlgebra"] - - [deps.Compat.extensions] - CompatLinearAlgebraExt = "LinearAlgebra" - -[[deps.CompilerSupportLibraries_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "1.0.5+0" - -[[deps.ConstructionBase]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "d8a9c0b6ac2d9081bf76324b39c78ca3ce4f0c98" -uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" -version = "1.5.6" - - [deps.ConstructionBase.extensions] - ConstructionBaseIntervalSetsExt = "IntervalSets" - ConstructionBaseStaticArraysExt = "StaticArrays" - - [deps.ConstructionBase.weakdeps] - IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" - StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[[deps.DataStructures]] -deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82" -uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.20" - -[[deps.Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" - -[[deps.DiffResults]] -deps = ["StaticArraysCore"] -git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" -uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" -version = "1.1.0" - -[[deps.DiffRules]] -deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] -git-tree-sha1 = "23163d55f885173722d1e4cf0f6110cdbaf7e272" -uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" -version = "1.15.1" - -[[deps.Distances]] -deps = ["LinearAlgebra", "Statistics", "StatsAPI"] -git-tree-sha1 = "66c4c81f259586e8f002eacebc177e1fb06363b0" -uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" -version = "0.10.11" - - [deps.Distances.extensions] - DistancesChainRulesCoreExt = "ChainRulesCore" - DistancesSparseArraysExt = "SparseArrays" - - [deps.Distances.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[deps.Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - -[[deps.DocStringExtensions]] -deps = ["LibGit2"] -git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.9.3" - -[[deps.Documenter]] -deps = ["ANSIColoredPrinters", "AbstractTrees", "Base64", "CodecZlib", "Dates", "DocStringExtensions", "Downloads", "Git", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "MarkdownAST", "Pkg", "PrecompileTools", "REPL", "RegistryInstances", "SHA", "TOML", "Test", "Unicode"] -git-tree-sha1 = "76deb8c15f37a3853f13ea2226b8f2577652de05" -uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "1.5.0" - -[[deps.Downloads]] -deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] -uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" -version = "1.6.0" - -[[deps.Expat_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1c6317308b9dc757616f0b5cb379db10494443a7" -uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.6.2+0" - -[[deps.FFTW]] -deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] -git-tree-sha1 = "4820348781ae578893311153d69049a93d05f39d" -uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" -version = "1.8.0" - -[[deps.FFTW_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea" -uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" -version = "3.3.10+0" - -[[deps.FastGaussQuadrature]] -deps = ["LinearAlgebra", "SpecialFunctions", "StaticArrays"] -git-tree-sha1 = "fd923962364b645f3719855c88f7074413a6ad92" -uuid = "442a2c76-b920-505d-bb47-c5924d526838" -version = "1.0.2" - -[[deps.FileIO]] -deps = ["Pkg", "Requires", "UUIDs"] -git-tree-sha1 = "82d8afa92ecf4b52d78d869f038ebfb881267322" -uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" -version = "1.16.3" - -[[deps.FileWatching]] -uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" - -[[deps.FillArrays]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "0653c0a2396a6da5bc4766c43041ef5fd3efbe57" -uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "1.11.0" - - [deps.FillArrays.extensions] - FillArraysPDMatsExt = "PDMats" - FillArraysSparseArraysExt = "SparseArrays" - FillArraysStatisticsExt = "Statistics" - - [deps.FillArrays.weakdeps] - PDMats = "90014a1f-27ba-587c-ab20-58faa44d9150" - SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" - -[[deps.FiniteDiff]] -deps = ["ArrayInterface", "LinearAlgebra", "Requires", "Setfield", "SparseArrays"] -git-tree-sha1 = "73d1214fec245096717847c62d389a5d2ac86504" -uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.22.0" - - [deps.FiniteDiff.extensions] - FiniteDiffBandedMatricesExt = "BandedMatrices" - FiniteDiffBlockBandedMatricesExt = "BlockBandedMatrices" - FiniteDiffStaticArraysExt = "StaticArrays" - - [deps.FiniteDiff.weakdeps] - BandedMatrices = "aae01518-5342-5314-be14-df237901396f" - BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" - StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[[deps.ForwardDiff]] -deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] -git-tree-sha1 = "cf0fe81336da9fb90944683b8c41984b08793dad" -uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "0.10.36" -weakdeps = ["StaticArrays"] - - [deps.ForwardDiff.extensions] - ForwardDiffStaticArraysExt = "StaticArrays" - -[[deps.Future]] -deps = ["Random"] -uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" - -[[deps.Git]] -deps = ["Git_jll"] -git-tree-sha1 = "04eff47b1354d702c3a85e8ab23d539bb7d5957e" -uuid = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2" -version = "1.3.1" - -[[deps.Git_jll]] -deps = ["Artifacts", "Expat_jll", "JLLWrappers", "LibCURL_jll", "Libdl", "Libiconv_jll", "OpenSSL_jll", "PCRE2_jll", "Zlib_jll"] -git-tree-sha1 = "d18fb8a1f3609361ebda9bf029b60fd0f120c809" -uuid = "f8c6e375-362e-5223-8a59-34ff63f689eb" -version = "2.44.0+2" - -[[deps.Gridap]] -deps = ["AbstractTrees", "BSON", "BlockArrays", "Combinatorics", "DataStructures", "DocStringExtensions", "FastGaussQuadrature", "FileIO", "FillArrays", "ForwardDiff", "JLD2", "JSON", "LineSearches", "LinearAlgebra", "NLsolve", "NearestNeighbors", "PolynomialBases", "Preferences", "QuadGK", "Random", "SparseArrays", "SparseMatricesCSR", "StaticArrays", "Statistics", "Test", "WriteVTK"] -git-tree-sha1 = "8c735f66c5fa081c3ea32a803df434c8790e1a47" -uuid = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" -version = "0.18.4" - -[[deps.GridapDistributed]] -deps = ["BlockArrays", "FillArrays", "Gridap", "LinearAlgebra", "MPI", "PartitionedArrays", "SparseArrays", "SparseMatricesCSR", "WriteVTK"] -git-tree-sha1 = "72b7eb03a098c79860f8676bf3959449285516f5" -uuid = "f9701e48-63b3-45aa-9a63-9bc6c271f355" -version = "0.4.4" - -[[deps.GridapP4est]] -deps = ["ArgParse", "FillArrays", "Gridap", "GridapDistributed", "Libdl", "MPI", "P4est_wrapper", "PartitionedArrays", "Test"] -git-tree-sha1 = "f92d49f8b162ce9eba7543be9c075131f9ef7f5a" -uuid = "c2c8e14b-f5fd-423d-9666-1dd9ad120af9" -version = "0.3.8" - -[[deps.GridapPETSc]] -deps = ["Gridap", "GridapDistributed", "Libdl", "LinearAlgebra", "MPI", "PETSc_jll", "PartitionedArrays", "Random", "SparseArrays", "SparseMatricesCSR"] -git-tree-sha1 = "549d0dce1a8051e6cd2c6dc4edcf0422d48ceecb" -uuid = "bcdc36c2-0c3e-11ea-095a-c9dadae499f1" -version = "0.5.2" - -[[deps.GridapSolvers]] -deps = ["AbstractTrees", "BlockArrays", "FillArrays", "Gridap", "GridapDistributed", "GridapP4est", "GridapPETSc", "IterativeSolvers", "LineSearches", "LinearAlgebra", "MPI", "NLsolve", "PartitionedArrays", "Printf", "SparseArrays", "SparseMatricesCSR"] -path = ".." -uuid = "6d3209ee-5e3c-4db7-a716-942eb12ed534" -version = "0.3.0" - -[[deps.Hwloc_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "5e19e1e4fa3e71b774ce746274364aef0234634e" -uuid = "e33a78d0-f292-5ffc-b300-72abe9b543c8" -version = "2.11.1+0" - -[[deps.IOCapture]] -deps = ["Logging", "Random"] -git-tree-sha1 = "b6d6bfdd7ce25b0f9b2f6b3dd56b2673a66c8770" -uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.2.5" - -[[deps.IntelOpenMP_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "14eb2b542e748570b56446f4c50fbfb2306ebc45" -uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" -version = "2024.2.0+0" - -[[deps.InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[deps.IrrationalConstants]] -git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" -uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.2.2" - -[[deps.IterativeSolvers]] -deps = ["LinearAlgebra", "Printf", "Random", "RecipesBase", "SparseArrays"] -git-tree-sha1 = "59545b0a2b27208b0650df0a46b8e3019f85055b" -uuid = "42fd0dbc-a981-5370-80f2-aaf504508153" -version = "0.9.4" - -[[deps.JLD2]] -deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "PrecompileTools", "Reexport", "Requires", "TranscodingStreams", "UUIDs", "Unicode"] -git-tree-sha1 = "67d4690d32c22e28818a434b293a374cc78473d3" -uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.4.51" - -[[deps.JLLWrappers]] -deps = ["Artifacts", "Preferences"] -git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca" -uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.5.0" - -[[deps.JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.4" - -[[deps.LazilyInitializedFields]] -git-tree-sha1 = "8f7f3cabab0fd1800699663533b6d5cb3fc0e612" -uuid = "0e77f7df-68c5-4e49-93ce-4cd80f5598bf" -version = "1.2.2" - -[[deps.LazyArtifacts]] -deps = ["Artifacts", "Pkg"] -uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" - -[[deps.LibCURL]] -deps = ["LibCURL_jll", "MozillaCACerts_jll"] -uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" -version = "0.6.4" - -[[deps.LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] -uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.4.0+0" - -[[deps.LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" - -[[deps.LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] -uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.0+1" - -[[deps.Libdl]] -uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" - -[[deps.Libiconv_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "f9557a255370125b405568f9767d6d195822a175" -uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" -version = "1.17.0+0" - -[[deps.LightXML]] -deps = ["Libdl", "XML2_jll"] -git-tree-sha1 = "3a994404d3f6709610701c7dabfc03fed87a81f8" -uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179" -version = "0.9.1" - -[[deps.LineSearches]] -deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] -git-tree-sha1 = "e4c3be53733db1051cc15ecf573b1042b3a712a1" -uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" -version = "7.3.0" - -[[deps.LinearAlgebra]] -deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[deps.Literate]] -deps = ["Base64", "IOCapture", "JSON", "REPL"] -git-tree-sha1 = "eef2e1fc1dc38af90a18eb16e519e06d1fd10c2a" -uuid = "98b081ad-f1c9-55d3-8b20-4c87d4299306" -version = "2.19.0" - -[[deps.LogExpFunctions]] -deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] -git-tree-sha1 = "a2d09619db4e765091ee5c6ffe8872849de0feea" -uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -version = "0.3.28" - - [deps.LogExpFunctions.extensions] - LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" - LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables" - LogExpFunctionsInverseFunctionsExt = "InverseFunctions" - - [deps.LogExpFunctions.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" - InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" - -[[deps.Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[deps.MKL_jll]] -deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] -git-tree-sha1 = "f046ccd0c6db2832a9f639e2c669c6fe867e5f4f" -uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" -version = "2024.2.0+0" - -[[deps.MPI]] -deps = ["Distributed", "DocStringExtensions", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "PkgVersion", "PrecompileTools", "Requires", "Serialization", "Sockets"] -git-tree-sha1 = "b4d8707e42b693720b54f0b3434abee6dd4d947a" -uuid = "da04e1cc-30fd-572f-bb4f-1f8673147195" -version = "0.20.16" - - [deps.MPI.extensions] - AMDGPUExt = "AMDGPU" - CUDAExt = "CUDA" - - [deps.MPI.weakdeps] - AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" - CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" - -[[deps.MPICH_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML"] -git-tree-sha1 = "19d4bd098928a3263693991500d05d74dbdc2004" -uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4" -version = "4.2.2+0" - -[[deps.MPIPreferences]] -deps = ["Libdl", "Preferences"] -git-tree-sha1 = "c105fe467859e7f6e9a852cb15cb4301126fac07" -uuid = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267" -version = "0.1.11" - -[[deps.MPItrampoline_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML"] -git-tree-sha1 = "8c35d5420193841b2f367e658540e8d9e0601ed0" -uuid = "f1f71cc9-e9ae-5b93-9b94-4fe0e1ad3748" -version = "5.4.0+0" - -[[deps.MacroTools]] -deps = ["Markdown", "Random"] -git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" -uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.13" - -[[deps.Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[deps.MarkdownAST]] -deps = ["AbstractTrees", "Markdown"] -git-tree-sha1 = "465a70f0fc7d443a00dcdc3267a497397b8a3899" -uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" -version = "0.1.2" - -[[deps.MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.28.2+0" - -[[deps.MicrosoftMPI_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "f12a29c4400ba812841c6ace3f4efbb6dbb3ba01" -uuid = "9237b28f-5490-5468-be7b-bb81f5f5e6cf" -version = "10.1.4+2" - -[[deps.Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" - -[[deps.MozillaCACerts_jll]] -uuid = "14a3606d-f60d-562e-9121-12d972cd8159" -version = "2022.10.11" - -[[deps.NLSolversBase]] -deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"] -git-tree-sha1 = "a0b464d183da839699f4c79e7606d9d186ec172c" -uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" -version = "7.8.3" - -[[deps.NLsolve]] -deps = ["Distances", "LineSearches", "LinearAlgebra", "NLSolversBase", "Printf", "Reexport"] -git-tree-sha1 = "019f12e9a1a7880459d0173c182e6a99365d7ac1" -uuid = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" -version = "4.5.1" - -[[deps.NaNMath]] -deps = ["OpenLibm_jll"] -git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" -uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "1.0.2" - -[[deps.NearestNeighbors]] -deps = ["Distances", "StaticArrays"] -git-tree-sha1 = "91a67b4d73842da90b526011fa85c5c4c9343fe0" -uuid = "b8a86587-4115-5ab1-83bc-aa920d37bbce" -version = "0.4.18" - -[[deps.NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" -version = "1.2.0" - -[[deps.OffsetArrays]] -git-tree-sha1 = "1a27764e945a152f7ca7efa04de513d473e9542e" -uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.14.1" -weakdeps = ["Adapt"] - - [deps.OffsetArrays.extensions] - OffsetArraysAdaptExt = "Adapt" - -[[deps.OpenBLAS32_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "2fb9ee2dc14d555a6df2a714b86b7125178344c2" -uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.21+0" - -[[deps.OpenBLAS_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] -uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.21+4" - -[[deps.OpenLibm_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.1+0" - -[[deps.OpenMPI_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML", "Zlib_jll"] -git-tree-sha1 = "bfce6d523861a6c562721b262c0d1aaeead2647f" -uuid = "fe0851c0-eecd-5654-98d4-656369965a5c" -version = "5.0.5+0" - -[[deps.OpenSSL_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "a028ee3cb5641cccc4c24e90c36b0a4f7707bdf5" -uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.0.14+0" - -[[deps.OpenSpecFun_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" -uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" -version = "0.5.5+0" - -[[deps.OrderedCollections]] -git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.6.3" - -[[deps.P4est_jll]] -deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "Pkg", "TOML", "Zlib_jll"] -git-tree-sha1 = "70c2d9a33b8810198314a5722ee3e9520110b28d" -uuid = "6b5a15aa-cf52-5330-8376-5e5d90283449" -version = "2.8.1+2" - -[[deps.P4est_wrapper]] -deps = ["CEnum", "Libdl", "MPI", "P4est_jll"] -git-tree-sha1 = "d3730f758f8364d734dd35506ea3639db301d87a" -uuid = "3743d7c0-8adf-11ea-380b-7d33b0ecc1da" -version = "0.2.3" - -[[deps.PCRE2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" -version = "10.42.0+0" - -[[deps.PETSc_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "MPICH_jll", "MicrosoftMPI_jll", "OpenBLAS32_jll", "Pkg"] -git-tree-sha1 = "8384198eba24438cee406ec7ca8854acdcbbd2c8" -uuid = "8fa3689e-f0b9-5420-9873-adf6ccf46f2d" -version = "3.15.2+0" - -[[deps.Parameters]] -deps = ["OrderedCollections", "UnPack"] -git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" -uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" -version = "0.12.3" - -[[deps.Parsers]] -deps = ["Dates", "PrecompileTools", "UUIDs"] -git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.8.1" - -[[deps.PartitionedArrays]] -deps = ["CircularArrays", "Distances", "FillArrays", "IterativeSolvers", "LinearAlgebra", "MPI", "Printf", "Random", "SparseArrays", "SparseMatricesCSR"] -git-tree-sha1 = "149d2287770c6a533507d74beaa73d76c0727922" -uuid = "5a9dfac6-5c52-46f7-8278-5e2210713be9" -version = "0.3.4" - -[[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.9.2" - -[[deps.PkgVersion]] -deps = ["Pkg"] -git-tree-sha1 = "f9501cc0430a26bc3d156ae1b5b0c1b47af4d6da" -uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688" -version = "0.3.3" - -[[deps.PolynomialBases]] -deps = ["ArgCheck", "AutoHashEquals", "FFTW", "FastGaussQuadrature", "LinearAlgebra", "Requires", "SimpleUnPack", "SpecialFunctions"] -git-tree-sha1 = "b62fd0464edfffce54393cd617135af30fa47006" -uuid = "c74db56a-226d-5e98-8bb0-a6049094aeea" -version = "0.4.22" - -[[deps.PrecompileTools]] -deps = ["Preferences"] -git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" -uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" -version = "1.2.1" - -[[deps.Preferences]] -deps = ["TOML"] -git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" -uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.4.3" - -[[deps.Printf]] -deps = ["Unicode"] -uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" - -[[deps.QuadGK]] -deps = ["DataStructures", "LinearAlgebra"] -git-tree-sha1 = "e237232771fdafbae3db5c31275303e056afaa9f" -uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" -version = "2.10.1" - -[[deps.REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[deps.Random]] -deps = ["SHA", "Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[deps.RecipesBase]] -deps = ["PrecompileTools"] -git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff" -uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" -version = "1.3.4" - -[[deps.Reexport]] -git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" -uuid = "189a3867-3050-52da-a836-e630ba90ab69" -version = "1.2.2" - -[[deps.RegistryInstances]] -deps = ["LazilyInitializedFields", "Pkg", "TOML", "Tar"] -git-tree-sha1 = "ffd19052caf598b8653b99404058fce14828be51" -uuid = "2792f1a3-b283-48e8-9a74-f99dce5104f3" -version = "0.1.0" - -[[deps.Requires]] -deps = ["UUIDs"] -git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" -uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.3.0" - -[[deps.SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" -version = "0.7.0" - -[[deps.Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[deps.Setfield]] -deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"] -git-tree-sha1 = "e2cc6d8c88613c05e1defb55170bf5ff211fbeac" -uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" -version = "1.1.1" - -[[deps.SimpleUnPack]] -git-tree-sha1 = "58e6353e72cde29b90a69527e56df1b5c3d8c437" -uuid = "ce78b400-467f-4804-87d8-8f486da07d0a" -version = "1.1.0" - -[[deps.Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[deps.SparseArrays]] -deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[deps.SparseMatricesCSR]] -deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "38677ca58e80b5cad2382e5a1848f93b054ad28d" -uuid = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1" -version = "0.6.7" - -[[deps.SpecialFunctions]] -deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "2f5d4697f21388cbe1ff299430dd169ef97d7e14" -uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.4.0" - - [deps.SpecialFunctions.extensions] - SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" - - [deps.SpecialFunctions.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - -[[deps.StaticArrays]] -deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] -git-tree-sha1 = "eeafab08ae20c62c44c8399ccb9354a04b80db50" -uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.9.7" - - [deps.StaticArrays.extensions] - StaticArraysChainRulesCoreExt = "ChainRulesCore" - StaticArraysStatisticsExt = "Statistics" - - [deps.StaticArrays.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" - -[[deps.StaticArraysCore]] -git-tree-sha1 = "192954ef1208c7019899fbf8049e717f92959682" -uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" -version = "1.4.3" - -[[deps.Statistics]] -deps = ["LinearAlgebra", "SparseArrays"] -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -version = "1.9.0" - -[[deps.StatsAPI]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed" -uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.7.0" - -[[deps.SuiteSparse]] -deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] -uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" - -[[deps.SuiteSparse_jll]] -deps = ["Artifacts", "Libdl", "Pkg", "libblastrampoline_jll"] -uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "5.10.1+6" - -[[deps.TOML]] -deps = ["Dates"] -uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" -version = "1.0.3" - -[[deps.Tar]] -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.TextWrap]] -git-tree-sha1 = "43044b737fa70bc12f6105061d3da38f881a3e3c" -uuid = "b718987f-49a8-5099-9789-dcd902bef87d" -version = "1.0.2" - -[[deps.TranscodingStreams]] -git-tree-sha1 = "e84b3a11b9bece70d14cce63406bbc79ed3464d2" -uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" -version = "0.11.2" - -[[deps.UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[deps.UnPack]] -git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" -uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" -version = "1.0.2" - -[[deps.Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" - -[[deps.VTKBase]] -git-tree-sha1 = "c2d0db3ef09f1942d08ea455a9e252594be5f3b6" -uuid = "4004b06d-e244-455f-a6ce-a5f9919cc534" -version = "1.0.1" - -[[deps.WriteVTK]] -deps = ["Base64", "CodecZlib", "FillArrays", "LightXML", "TranscodingStreams", "VTKBase"] -git-tree-sha1 = "46664bb833f24e4fe561192e3753c9168c3b71b2" -uuid = "64499a7a-5c06-52f2-abe2-ccb03c286192" -version = "1.19.2" - -[[deps.XML2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] -git-tree-sha1 = "d9717ce3518dc68a99e6b96300813760d887a01d" -uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" -version = "2.13.1+0" - -[[deps.Zlib_jll]] -deps = ["Libdl"] -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.2.13+0" - -[[deps.libblastrampoline_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.8.0+0" - -[[deps.nghttp2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.52.0+1" - -[[deps.oneTBB_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "7d0ea0f4895ef2f5cb83645fa689e52cb55cf493" -uuid = "1317d2d5-d96f-522e-a858-c73665f53c3e" -version = "2021.12.0+0" - -[[deps.p7zip_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" -version = "17.4.0+0" From ed070d91d52b8ec7b8408dbdd7b8aaa8b9b8a239 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 30 Oct 2024 16:20:18 +1100 Subject: [PATCH 38/47] Bugfixes in MultiFieldTransferOps --- src/MultilevelTools/GridTransferOperators.jl | 6 +++++ .../MultiFieldTransferOperators.jl | 26 ++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/MultilevelTools/GridTransferOperators.jl b/src/MultilevelTools/GridTransferOperators.jl index 1c614edc..8473097f 100644 --- a/src/MultilevelTools/GridTransferOperators.jl +++ b/src/MultilevelTools/GridTransferOperators.jl @@ -219,6 +219,12 @@ function setup_restriction_operators(sh::FESpaceHierarchy,qdegrees::AbstractArra end end +function update_transfer_operator!( + op::DistributedGridTransferOperator,x::AbstractVector +) + nothing +end + ### Applying the operators: # A) Prolongation, without redistribution diff --git a/src/MultilevelTools/MultiFieldTransferOperators.jl b/src/MultilevelTools/MultiFieldTransferOperators.jl index f7d86224..6b8c69c2 100644 --- a/src/MultilevelTools/MultiFieldTransferOperators.jl +++ b/src/MultilevelTools/MultiFieldTransferOperators.jl @@ -42,12 +42,14 @@ function MultiFieldTransferOperator(sh::FESpaceHierarchy,operators;op_type=:prol return mfops end -function update_transfer_operator!(op::MultiFieldTransferOperator,x::AbstractVector) +function update_transfer_operator!( + op::MultiFieldTransferOperator{Val{:prolongation}},x::Union{AbstractVector,Nothing} +) xh, _ = op.cache - if !isnothing(xh) - copy!(x,xh) - isa(x,PVector) && wait(consistent!(x)) + if !isnothing(x) + copy!(xh,x) + isa(xh,PVector) && wait(consistent!(xh)) end for (i,op_i) in enumerate(op.ops) @@ -56,6 +58,22 @@ function update_transfer_operator!(op::MultiFieldTransferOperator,x::AbstractVec end end +function update_transfer_operator!( + op::MultiFieldTransferOperator{Val{:restriction}},y::Union{AbstractVector,Nothing} +) + _, yh = op.cache + + if !isnothing(y) + copy!(yh,y) + isa(yh,PVector) && wait(consistent!(yh)) + end + + for (i,op_i) in enumerate(op.ops) + yh_i = isnothing(yh) ? nothing : MultiField.restrict_to_field(op.Vh_in,yh,i) + update_transfer_operator!(op_i,yh_i) + end +end + function LinearAlgebra.mul!( x::Union{Nothing,<:AbstractVector}, op::MultiFieldTransferOperator, From 93e246ab5b168262fa50896abad447d9f5726dae Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 7 Nov 2024 14:44:58 +1100 Subject: [PATCH 39/47] Added ContinuationFEOperators --- .../ContinuationFEOperators.jl | 140 ++++++++++++++++++ src/NonlinearSolvers/NewtonRaphsonSolver.jl | 2 + src/NonlinearSolvers/NonlinearSolvers.jl | 4 + .../NonlinearSolvers/NonlinearSolversTests.jl | 13 +- .../mpi/NonlinearSolversTests.jl | 10 ++ test/NonlinearSolvers/mpi/runtests.jl | 20 +++ test/NonlinearSolvers/seq/runtests.jl | 16 +- 7 files changed, 200 insertions(+), 5 deletions(-) create mode 100644 src/NonlinearSolvers/ContinuationFEOperators.jl create mode 100644 test/NonlinearSolvers/mpi/NonlinearSolversTests.jl create mode 100644 test/NonlinearSolvers/mpi/runtests.jl diff --git a/src/NonlinearSolvers/ContinuationFEOperators.jl b/src/NonlinearSolvers/ContinuationFEOperators.jl new file mode 100644 index 00000000..4f14314f --- /dev/null +++ b/src/NonlinearSolvers/ContinuationFEOperators.jl @@ -0,0 +1,140 @@ + +""" + mutable struct ContinuationSwitch{A} + callback :: Function + caches :: A + switched :: Bool + end + + ContinuationSwitch(callback::Function, caches) + +Switch that implements the switching logic for a ContinuationFEOperator. + +The callback function must provide the following signatures: + +- Reset: `callback(u::FEFunction,::Nothing,cache) -> (switch::Bool, new_cache)` +- Update: `callback(u::FEFunction,b::AbstractVector,cache) -> (switch::Bool, new_cache)` + +where `u` is the current solution (as a FEFunction) and `b` is the current residual. The first +signature is called by `allocate_residual` and is typically used to reset the switch for a new +nonlinear solve. The second signature is called by `residual!` and is used to update the switch +based on the current residual. + +The cache is (potentially) mutated between each call, and can hold any extra information +needed for the continuation logic. +""" +mutable struct ContinuationSwitch{A} + callback :: Function + caches :: A + switched :: Bool + + function ContinuationSwitch(callback::Function, caches) + A = typeof(caches) + new{A}(callback, caches, false) + end +end + +has_switched(s::ContinuationSwitch) = s.switched + +switch!(s::ContinuationSwitch, u) = switch!(s, u, nothing) + +function switch!(s::ContinuationSwitch, u, b) + has_switched(s) && return s.switched + s.switched, s.caches = s.callback(u, b, s.caches) + if has_switched(s) + @debug "ContinuationFEOperator: Switching operators!" + end + return s.switched +end + +""" + ContinuationSwitch(niter::Int) + +Switch that will change operators after `niter` iterations. +""" +function ContinuationSwitch(niter::Int) + caches = (;it = -1, niter = niter) + callback(u,::Nothing,c) = (false, (;it = -1, niter = c.niter)) + callback(u,b,c) = (c.it+1 >= c.niter, (;it = c.it+1, niter = c.niter)) + return ContinuationSwitch(callback, caches) +end + +""" + struct ContinuationFEOperator <: FESpaces.FEOperator + op1 :: FEOperator + op2 :: FEOperator + switch :: ContinuationSwitch + reuse_caches :: Bool + end + +FEOperator implementing the continuation method for nonlinear solvers. It switches between +its two operators when the switch is triggered. + +Continuation between more that two operators can be achieved by daisy-chaining two or more +ContinuationFEOperators. + +If `reuse_caches` is `true`, the Jacobian of the first operator is reused for the second +operator. This is only possible if the sparsity pattern of the Jacobian does not change. +""" +struct ContinuationFEOperator{A,B,C} <: FESpaces.FEOperator + op1 :: A + op2 :: B + switch :: C + reuse_caches :: Bool + + function ContinuationFEOperator( + op1::FEOperator, + op2::FEOperator, + switch::ContinuationSwitch; + reuse_caches::Bool = true + ) + A, B, C = typeof(op1), typeof(op2), typeof(switch) + new{A,B,C}(op1, op2, switch, reuse_caches) + end +end + +has_switched(op::ContinuationFEOperator) = has_switched(op.switch) + +""" + ContinuationFEOperator(op1::FEOperator, op2::FEOperator, niter::Int; reuse_caches::Bool = true) + +ContinuationFEOperator that switches between `op1` and `op2` after `niter` iterations. +""" +function ContinuationFEOperator( + op1::FEOperator, op2::FEOperator, niter::Int; reuse_caches::Bool = true +) + switch = ContinuationSwitch(niter) + return ContinuationFEOperator(op1, op2, switch; reuse_caches) +end + +# FEOperator API + +function FESpaces.get_test(op::ContinuationFEOperator) + ifelse(!has_switched(op), get_test(op.op1), get_test(op.op2)) +end + +function FESpaces.get_trial(op::ContinuationFEOperator) + ifelse(!has_switched(op), get_trial(op.op1), get_trial(op.op2)) +end + +function Algebra.allocate_residual(op::ContinuationFEOperator,u) + switch!(op.switch, u, nothing) + ifelse(!has_switched(op), allocate_residual(op.op1, u), allocate_residual(op.op2, u)) +end + +function Algebra.residual!(b::AbstractVector,op::ContinuationFEOperator,u) + switch!(op.switch, u, b) + ifelse(!has_switched(op), residual!(b, op.op1, u), residual!(b, op.op2, u)) +end + +function Algebra.allocate_jacobian(op::ContinuationFEOperator,u) + ifelse(!has_switched(op), allocate_jacobian(op.op1, u), allocate_jacobian(op.op2, u)) +end + +function Algebra.jacobian!(A::AbstractMatrix,op::ContinuationFEOperator,u) + if op.reuse_caches + ifelse(!has_switched(op), jacobian!(A, op.op1, u), jacobian!(A, op.op2, u)) + else + ifelse(!has_switched(op), jacobian(op.op1, u), jacobian(op.op2, u)) + end +end diff --git a/src/NonlinearSolvers/NewtonRaphsonSolver.jl b/src/NonlinearSolvers/NewtonRaphsonSolver.jl index 93e0d32f..470366df 100644 --- a/src/NonlinearSolvers/NewtonRaphsonSolver.jl +++ b/src/NonlinearSolvers/NewtonRaphsonSolver.jl @@ -19,6 +19,8 @@ function NewtonSolver(ls;maxiter=100,atol=1e-12,rtol=1.e-6,verbose=0,name="Newto return NewtonSolver(ls,log) end +AbstractTrees.children(s::NewtonSolver) = [s.ls] + struct NewtonCache A::AbstractMatrix b::AbstractVector diff --git a/src/NonlinearSolvers/NonlinearSolvers.jl b/src/NonlinearSolvers/NonlinearSolvers.jl index 0b4b1981..8446ab63 100644 --- a/src/NonlinearSolvers/NonlinearSolvers.jl +++ b/src/NonlinearSolvers/NonlinearSolvers.jl @@ -1,4 +1,5 @@ module NonlinearSolvers + using AbstractTrees using LinearAlgebra using SparseArrays using SparseMatricesCSR @@ -13,6 +14,9 @@ module NonlinearSolvers using GridapSolvers.SolverInterfaces using GridapSolvers.MultilevelTools + include("ContinuationFEOperators.jl") + export ContinuationFEOperator + include("NewtonRaphsonSolver.jl") export NewtonSolver diff --git a/test/NonlinearSolvers/NonlinearSolversTests.jl b/test/NonlinearSolvers/NonlinearSolversTests.jl index 74360760..871851fa 100644 --- a/test/NonlinearSolvers/NonlinearSolversTests.jl +++ b/test/NonlinearSolvers/NonlinearSolversTests.jl @@ -13,7 +13,9 @@ using Gridap.Algebra using GridapSolvers using GridapSolvers.NonlinearSolvers, GridapSolvers.LinearSolvers -function main(ranks,model,solver) +const ModelTypes = Union{<:DiscreteModel,<:GridapDistributed.DistributedDiscreteModel} + +function main(ranks,model::ModelTypes,solver::Symbol) u_sol(x) = sum(x) order = 1 @@ -40,6 +42,9 @@ function main(ranks,model,solver) nls = NLsolveNonlinearSolver(ls; show_trace=true, method=:anderson, linesearch=BackTracking(), iterations=40, m=10) elseif solver == :newton nls = NewtonSolver(ls,maxiter=20,verbose=true) + elseif solver == :newton_continuation + op = ContinuationFEOperator(op,op,2;reuse_caches=true) + nls = NewtonSolver(ls,maxiter=20,verbose=true) else @error "Unknown solver" end @@ -52,15 +57,15 @@ function main(ranks,model,solver) end # Serial -function main(solver) +function main(solver::Symbol) model = CartesianDiscreteModel((0,1,0,1),(8,8)) ranks = DebugArray([1]) main(ranks,model,solver) end # Distributed -function main(distribute,solver) - ranks = distribute(LinearIndices((4,))) +function main(distribute,np,solver::Symbol) + ranks = distribute(LinearIndices((prod(np),))) model = CartesianDiscreteModel((0,1,0,1),(8,8)) main(ranks,model,solver) end diff --git a/test/NonlinearSolvers/mpi/NonlinearSolversTests.jl b/test/NonlinearSolvers/mpi/NonlinearSolversTests.jl new file mode 100644 index 00000000..24cf4fcf --- /dev/null +++ b/test/NonlinearSolvers/mpi/NonlinearSolversTests.jl @@ -0,0 +1,10 @@ +module NonlinearSolversTestsMPI +using MPI, PartitionedArrays +include("../NonlinearSolversTests.jl") + +with_mpi() do distribute + NonlinearSolversTests.main(distribute,4,:newton) + NonlinearSolversTests.main(distribute,4,:newton_continuation) +end + +end \ No newline at end of file diff --git a/test/NonlinearSolvers/mpi/runtests.jl b/test/NonlinearSolvers/mpi/runtests.jl new file mode 100644 index 00000000..b43e871a --- /dev/null +++ b/test/NonlinearSolvers/mpi/runtests.jl @@ -0,0 +1,20 @@ +using Test +using MPI +using GridapSolvers + +function run_tests(testdir) + istest(f) = endswith(f, ".jl") && !(f=="runtests.jl") + testfiles = sort(filter(istest, readdir(testdir))) + @time @testset "$f" for f in testfiles + MPI.mpiexec() do cmd + np = 4 + cmd = `$cmd -n $(np) --oversubscribe $(Base.julia_cmd()) --project=. $(joinpath(testdir, f))` + @show cmd + run(cmd) + @test true + end + end +end + +# MPI tests +run_tests(@__DIR__) diff --git a/test/NonlinearSolvers/seq/runtests.jl b/test/NonlinearSolvers/seq/runtests.jl index c9c1b0d1..7600c8a4 100644 --- a/test/NonlinearSolvers/seq/runtests.jl +++ b/test/NonlinearSolvers/seq/runtests.jl @@ -1,9 +1,10 @@ using Test +using PartitionedArrays include("../NonlinearSolversTests.jl") -@testset "NonlinearSolvers" begin +@testset "NonlinearSolvers - Serial" begin @testset "NLSolvers" begin NonlinearSolversTests.main(:nlsolvers_newton) NonlinearSolversTests.main(:nlsolvers_trust_region) @@ -11,5 +12,18 @@ include("../NonlinearSolversTests.jl") end @testset "Newton" begin NonlinearSolversTests.main(:newton) + NonlinearSolversTests.main(:newton_continuation) + end +end + +@testset "NonlinearSolvers - Sequential" begin + @testset "NLSolvers" begin + NonlinearSolversTests.main(DebugArray,4,:nlsolvers_newton) + NonlinearSolversTests.main(DebugArray,4,:nlsolvers_trust_region) + NonlinearSolversTests.main(DebugArray,4,:nlsolvers_anderson) + end + @testset "Newton" begin + NonlinearSolversTests.main(DebugArray,4,:newton) + NonlinearSolversTests.main(DebugArray,4,:newton_continuation) end end From fa82c92551429e5acc1386f623cc23055ad2eed0 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 28 Nov 2024 16:11:16 +1100 Subject: [PATCH 40/47] Minor --- src/MultilevelTools/LocalProjectionMaps.jl | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/MultilevelTools/LocalProjectionMaps.jl b/src/MultilevelTools/LocalProjectionMaps.jl index c56f5b2b..4ea54365 100644 --- a/src/MultilevelTools/LocalProjectionMaps.jl +++ b/src/MultilevelTools/LocalProjectionMaps.jl @@ -89,7 +89,7 @@ struct ReffeProjectionMap{T,A} <: LocalProjectionMap{T} qdegree::Int function ReffeProjectionMap( op::Function, - reffe::Tuple{<:ReferenceFEName,Any,Any}, + reffe::Union{<:Tuple{<:ReferenceFEName,Any,Any},<:ReferenceFE}, qdegree::Integer ) T = typeof(op) @@ -100,7 +100,7 @@ end function LocalProjectionMap( op::Function, - reffe::Tuple{<:ReferenceFEName,Any,Any}, + reffe::Union{<:Tuple{<:ReferenceFEName,Any,Any},<:ReferenceFE}, qdegree::Integer=2*maximum(reffe[2][2]) ) ReffeProjectionMap(op,reffe,qdegree) @@ -118,11 +118,16 @@ end function _compute_local_projections( k::ReffeProjectionMap,u::CellField ) + function _cell_reffe(reffe::Tuple,Ω) + basis, args, kwargs = reffe + cell_polytopes = lazy_map(get_polytope,get_cell_reffe(Ω)) + return lazy_map(p -> ReferenceFE(p,basis,args...;kwargs...),cell_polytopes) + end + _cell_reffe(reffe::ReferenceFE,Ω) = Fill(reffe,num_cells(Ω)) + Ω = get_triangulation(u) dΩ = Measure(Ω,k.qdegree) - basis, args, kwargs = k.reffe - cell_polytopes = lazy_map(get_polytope,get_cell_reffe(Ω)) - cell_reffe = lazy_map(p -> ReferenceFE(p,basis,args...;kwargs...),cell_polytopes) + cell_reffe = _cell_reffe(k.reffe,Ω) test_shapefuns = lazy_map(get_shapefuns,cell_reffe) trial_shapefuns = lazy_map(transpose,test_shapefuns) p = SingleFieldFEBasis(trial_shapefuns,Ω,TrialBasis(),ReferenceDomain()) From 214bef73ca25b9604c54fec5b506939e714c63fe Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 29 Nov 2024 12:25:46 +1100 Subject: [PATCH 41/47] Remove isconsitent from transfer ops to accomodate serial cases --- src/MultilevelTools/GridTransferOperators.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MultilevelTools/GridTransferOperators.jl b/src/MultilevelTools/GridTransferOperators.jl index 8473097f..61d45d2d 100644 --- a/src/MultilevelTools/GridTransferOperators.jl +++ b/src/MultilevelTools/GridTransferOperators.jl @@ -105,8 +105,8 @@ function _get_projection_cache(lev::Int,sh::FESpaceHierarchy,qdegree,mode::Symbo fv_H = zero_free_values(UH) dv_H = zero_dirichlet_values(UH) - u0 = FEFunction(UH,fv_H,true) # Zero at free dofs - u00 = FEFunction(UH,fv_H,dv_H,true) # Zero everywhere + u0 = FEFunction(UH,fv_H) # Zero at free dofs + u00 = FEFunction(UH,fv_H,dv_H) # Zero everywhere u_dir = (mode == :solution) ? u0 : u00 u,v = get_trial_fe_basis(UH), get_fe_basis(VH) From ccf24926c0ff54e28ce7675d29efbc2308dbf897 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 29 Nov 2024 12:59:45 +1100 Subject: [PATCH 42/47] More changes towards serial GMG --- src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl | 4 +++- src/PatchBasedSmoothers/PatchTransferOperators.jl | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl b/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl index b12801e4..d72faf6e 100644 --- a/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl +++ b/src/PatchBasedSmoothers/PatchBasedLinearSolvers.jl @@ -94,7 +94,9 @@ end function update_patch_matrices!(Ap,Ap_ns,Ph::FESpace,ap) assem = SparseMatrixAssembler(Ph,Ph) - assemble_matrix!(Ap,assem,Ph,Ph,ap) + u, v = get_trial_fe_basis(Ph), get_fe_basis(Ph) + matdata = collect_cell_matrix(Ph,Ph,ap(u,v)) + assemble_matrix!(Ap,assem,matdata) numerical_setup!(Ap_ns,Ap) end diff --git a/src/PatchBasedSmoothers/PatchTransferOperators.jl b/src/PatchBasedSmoothers/PatchTransferOperators.jl index 36025ecc..bc9464c8 100644 --- a/src/PatchBasedSmoothers/PatchTransferOperators.jl +++ b/src/PatchBasedSmoothers/PatchTransferOperators.jl @@ -82,7 +82,7 @@ function _get_patch_cache(lev,sh,PD,lhs,rhs,is_nonlinear,cache_refine) end # Please make this a standard API or something -function MultilevelTools.update_transfer_operator!(op::PatchProlongationOperator,x::Union{PVector,Nothing}) +function MultilevelTools.update_transfer_operator!(op::PatchProlongationOperator,x::Union{AbstractVector,Nothing}) cache_refine, cache_patch, cache_redist = op.caches model_h, Uh, fv_h, dv_h, UH, fv_H, dv_H = cache_refine Ph, Ap_ns, Ap, duh, dxp, rp = cache_patch From dee498d1a081511142ecb3aaffa492d79765b124 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 3 Dec 2024 22:59:13 +1100 Subject: [PATCH 43/47] Added missing constructors for p4est --- src/MultilevelTools/ModelHierarchies.jl | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/MultilevelTools/ModelHierarchies.jl b/src/MultilevelTools/ModelHierarchies.jl index ac66a789..61147c3e 100644 --- a/src/MultilevelTools/ModelHierarchies.jl +++ b/src/MultilevelTools/ModelHierarchies.jl @@ -206,6 +206,26 @@ function P4estCartesianModelHierarchy( return mh end +function GridapDistributed.DistributedAdaptedDiscreteModel( + model :: GridapP4est.OctreeDistributedDiscreteModel, + parent :: GridapDistributed.DistributedDiscreteModel, + glue :: AbstractArray{<:Gridap.Adaptivity.AdaptivityGlue}; +) + GridapDistributed.DistributedAdaptedDiscreteModel( + model.dmodel,parent,glue + ) +end + +function GridapDistributed.DistributedAdaptedDiscreteModel( + model :: GridapP4est.OctreeDistributedDiscreteModel, + parent :: GridapP4est.OctreeDistributedDiscreteModel, + glue :: AbstractArray{<:Gridap.Adaptivity.AdaptivityGlue}; +) + GridapDistributed.DistributedAdaptedDiscreteModel( + model.dmodel,parent.dmodel,glue + ) +end + """ ModelHierarchy(root_parts,model,num_procs_x_level) From 2f6d704bdf4175b51e610e870ddb6647339beee2 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Tue, 3 Dec 2024 23:02:42 +1100 Subject: [PATCH 44/47] Deactivated SchwarzSolvers tests --- test/LinearSolvers/mpi/SchwarzSolversTests.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/LinearSolvers/mpi/SchwarzSolversTests.jl b/test/LinearSolvers/mpi/SchwarzSolversTests.jl index 12e2466a..6d443431 100644 --- a/test/LinearSolvers/mpi/SchwarzSolversTests.jl +++ b/test/LinearSolvers/mpi/SchwarzSolversTests.jl @@ -2,9 +2,10 @@ module SmoothersTestsMPI using MPI, PartitionedArrays include("../SchwarzSolversTests.jl") +# Deactivated for now. We require sub-assembled matrices for this with_mpi() do distribute - SchwarzSolversTests.main(distribute,(2,2)) # 2D - SchwarzSolversTests.main(distribute,(2,2,1)) # 3D + # SchwarzSolversTests.main(distribute,(2,2)) # 2D + # SchwarzSolversTests.main(distribute,(2,2,1)) # 3D end end \ No newline at end of file From 911f6cf1c4c20c9c5ce6a4f64d6fbaf96bafb633 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 4 Dec 2024 09:15:36 +1100 Subject: [PATCH 45/47] Update README --- README.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a89591bb..39ed14ab 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,14 @@ Solvers follow a modular design, where most blocks can be combined to produce PD - **Geometric Multigrid**: We provide a full-fledged geometric multigrid solver. Highly scalable adaptivity and redistribution of meshes, provided by `p4est` through `GridapP4est.jl`. - **PETSc interface**: Full access to PETSc algebraic solvers, through `GridapPETSc.jl`, with full interoperability with the rest of the aforementioned solvers. +## Documentation and examples + +A (hopefully) comprehensive documentation is available at [https://gridap.github.io/GridapSolvers.jl/stable/](https://gridap.github.io/GridapSolvers.jl/stable/). + +A list of examples is available in the documentation. These include some very well known examples such as the Stokes, Incompressible Navier-Stokes and Darcy problems. The featured scripts are available in `test/Applications`. + +An example on how to use the library within an HPC cluster is available in `joss_paper/scalability`. The included example and drivers are used to generate the scalability results in our [JOSS paper](https://doi.org/10.21105/joss.07162). + ## Installation GridapSolvers is a registered package in the official [Julia package registry](https://github.com/JuliaRegistries/General). Thus, the installation of GridapSolvers is straight forward using the [Julia's package manager](https://julialang.github.io/Pkg.jl/v1/). Open the Julia REPL, type `]` to enter package mode, and install as follows @@ -40,4 +48,29 @@ The previous installations steps will setup GridapSolvers to work using Julia's ## Citation -In order to give credit to the `GridapSolvers` contributors, we ask that you please reference our [JOSS paper](https://joss.theoj.org/papers/10.21105/joss.07162) along with the required citations for [Gridap](https://github.com/gridap/Gridap.jl?tab=readme-ov-file#how-to-cite-gridap). +In order to give credit to the `GridapSolvers` contributors, we simply ask you to cite the `Gridap` main project as indicated [here](https://github.com/gridap/Gridap.jl#how-to-cite-gridap) and the sub-packages you use as indicated in the corresponding repositories. Please, use the reference below in any publication in which you have made use of `GridapSolvers`: + +``` +@article{Manyer2024, + doi = {10.21105/joss.07162}, + url = {https://doi.org/10.21105/joss.07162}, + year = {2024}, + publisher = {The Open Journal}, + volume = {9}, + number = {102}, + pages = {7162}, + author = {Jordi Manyer and Alberto F. Martín and Santiago Badia}, + title = {GridapSolvers.jl: Scalable multiphysics finite element solvers in Julia}, + journal = {Journal of Open Source Software} +} +``` + +## Contributing + +GridapSolvers is a collaborative project open to contributions. If you want to contribute, please take into account: + + - Before opening a PR with a significant contribution, contact the project administrators by [opening an issue](https://github.com/gridap/GridapSolvers.jl/issues/new) describing what you are willing to implement. Wait for feedback from other community members. + - We adhere to the contribution and code-of-conduct instructions of the Gridap.jl project, available [here](https://github.com/gridap/Gridap.jl/blob/master/CONTRIBUTING.md) and [here](https://github.com/gridap/Gridap.jl/blob/master/CODE_OF_CONDUCT.md), resp. Please, carefully read and follow the instructions in these files. + - Open a PR with your contribution. + +Want to help? We have [issues waiting for help](https://github.com/gridap/GridapSolvers.jl/labels/help%20wanted). You can start contributing to the GridapSolvers project by solving some of those issues. From ff72ecca49517a440a63cf5a3cfc1f53765de3ab Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 5 Dec 2024 00:08:37 +1100 Subject: [PATCH 46/47] Added set_depth! to docs --- docs/src/SolverInterfaces.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/SolverInterfaces.md b/docs/src/SolverInterfaces.md index 774713cf..68809dfb 100644 --- a/docs/src/SolverInterfaces.md +++ b/docs/src/SolverInterfaces.md @@ -26,5 +26,6 @@ CurrentModule = GridapSolvers.SolverInterfaces init! update! finalize! + set_depth! print_message ``` From 26defd50f3728358b23aa101aeb32871d6046c91 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 5 Dec 2024 08:49:22 +1100 Subject: [PATCH 47/47] Added changelog --- CHANGELOG.md | 10 ++++++++++ src/SolverInterfaces/ConvergenceLogs.jl | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..5aad4212 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Previous versions + +A changelog is not maintained for older versions than 0.5.0. diff --git a/src/SolverInterfaces/ConvergenceLogs.jl b/src/SolverInterfaces/ConvergenceLogs.jl index 17839d9e..da76a963 100644 --- a/src/SolverInterfaces/ConvergenceLogs.jl +++ b/src/SolverInterfaces/ConvergenceLogs.jl @@ -64,7 +64,7 @@ end """ set_depth!(log::ConvergenceLog,depth::Int) - set_depth!(log::LinearSolver,depth::Int) + set_depth!(log::NonlinearSolver,depth::Int) Sets the tabulation depth of the convergence log `log` to `depth`. """ @@ -73,7 +73,7 @@ function set_depth!(log::ConvergenceLog,depth::Int) return log end -function set_depth!(solver::Algebra.LinearSolver,depth::Int) +function set_depth!(solver::Algebra.NonlinearSolver,depth::Int) if hasproperty(solver,:log) set_depth!(solver.log,depth) end