From 5bb7d4af9fc13766f3deebae48b080daa776e4ba Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:14:20 +1000 Subject: [PATCH 001/120] DistributedDiscreteGeometry implementation --- src/Distributed/Distributed.jl | 3 + .../DistributedDiscreteGeometries.jl | 102 ++++++++++++ src/Distributed/DistributedDiscretizations.jl | 8 +- .../DistributedDiscreteGeometryPoissonTest.jl | 148 ++++++++++++++++++ .../DistributedDiscreteGeometryPoissonTest.jl | 8 + test/DistributedTests/sequential/runtests.jl | 1 + 6 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 src/Distributed/DistributedDiscreteGeometries.jl create mode 100644 test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl create mode 100644 test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index aadb4d5b..4fc3e95e 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -43,6 +43,7 @@ import GridapEmbedded.Interfaces: EmbeddedBoundary import GridapEmbedded.Interfaces: compute_bgfacet_to_inoutcut import GridapEmbedded.Interfaces: compute_bgcell_to_inoutcut import GridapEmbedded.CSG: get_geometry +import GridapEmbedded.LevelSetCutters: discretize import Gridap.Geometry: Triangulation import Gridap.Geometry: SkeletonTriangulation import Gridap.Geometry: BoundaryTriangulation @@ -52,6 +53,8 @@ import GridapDistributed: remove_ghost_cells include("DistributedDiscretizations.jl") +include("DistributedDiscreteGeometries.jl") + include("DistributedAgFEM.jl") include("DistributedQuadratures.jl") diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl new file mode 100644 index 00000000..ce3c8be3 --- /dev/null +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -0,0 +1,102 @@ +struct DistributedDiscreteGeometry{A} <: GridapType + geometries::A +end + +local_views(a::DistributedDiscreteGeometry) = a.geometries + +function DistributedDiscreteGeometry(φh::CellField,model::DistributedDiscreteModel) + gids = get_cell_gids(model) + geometries = map(local_views(model),local_views(gids),local_views(φh)) do model,gids,φh + ownmodel = remove_ghost_cells(model,gids) + point_to_coords = collect1d(get_node_coordinates(ownmodel)) + DiscreteGeometry(φh(point_to_coords),point_to_coords) + end + DistributedDiscreteGeometry(geometries) +end + +function get_geometry(a::AbstractArray{<:DiscreteGeometry}) + DistributedDiscreteGeometry(a) +end + +function discretize(a::AnalyticalGeometry,model::DistributedDiscreteModel) + gids = get_cell_gids(model) + geometries = map(local_views(model),local_views(gids)) do model,gids + ownmodel = remove_ghost_cells(model,gids) + point_to_coords = collect1d(get_node_coordinates(ownmodel)) + discretize(a,point_to_coords) + end + DistributedDiscreteGeometry(geometries) +end + +function cut(cutter::Cutter,bgmodel::DistributedDiscreteModel,geom::DistributedDiscreteGeometry) + gids = get_cell_gids(bgmodel) + cuts = map(local_views(bgmodel),local_views(gids),local_views(geom)) do bgmodel,gids,geom + ownmodel = remove_ghost_cells(bgmodel,gids) + cutgeo = cut(cutter,ownmodel,geom) + change_bgmodel(cutgeo,bgmodel,own_to_local(gids)) + end + consistent_bgcell_to_inoutcut!(cuts,gids) + DistributedEmbeddedDiscretization(cuts,bgmodel) +end + +function cut_facets(cutter::Cutter,bgmodel::DistributedDiscreteModel,geom::DistributedDiscreteGeometry) + D = map(num_dims,local_views(bgmodel)) |> PartitionedArrays.getany + cell_gids = get_cell_gids(bgmodel) + facet_gids = get_face_gids(bgmodel,D-1) + cuts = map( + local_views(bgmodel), + local_views(cell_gids), + local_views(facet_gids), + local_views(geom)) do bgmodel,cell_gids,facet_gids,geom + ownmodel = remove_ghost_cells(bgmodel,cell_gids) + facet_to_pfacet = get_face_to_parent_face(ownmodel,D-1) + cutfacets = cut_facets(cutter,ownmodel,geom) + cutfacets = change_bgmodel(cutfacets,bgmodel,facet_to_pfacet) + remove_ghost_subfacets(cutfacets,facet_gids) + end + consistent_bgfacet_to_inoutcut!(cuts,facet_gids) + DistributedEmbeddedDiscretization(cuts,bgmodel) +end + +function distributed_embedded_triangulation( + T, + cutgeo::DistributedEmbeddedDiscretization, + cutinorout, + geom::DistributedDiscreteGeometry) + + trians = map(local_views(cutgeo),local_views(geom)) do lcutgeo,lgeom + T(lcutgeo,cutinorout,lgeom) + end + bgmodel = get_background_model(cutgeo) + DistributedTriangulation(trians,bgmodel) +end + +function distributed_aggregate( + strategy::AggregateCutCellsByThreshold, + cut::DistributedEmbeddedDiscretization, + geo::DistributedDiscreteGeometry, + in_or_out=IN) + + bgmodel = get_background_model(cut) + facet_to_inoutcut = compute_bgfacet_to_inoutcut(bgmodel,geo) + _distributed_aggregate_by_threshold(strategy.threshold,cut,geo,in_or_out,facet_to_inoutcut) +end + +function compute_bgcell_to_inoutcut(cutgeo::DistributedEmbeddedDiscretization,geo::DistributedDiscreteGeometry) + map(local_views(cutgeo),local_views(geo)) do cutgeo,geo + compute_bgcell_to_inoutcut(cutgeo,geo) + end +end + +function compute_bgfacet_to_inoutcut( + cutter::Cutter, + bgmodel::DistributedDiscreteModel, + geo::DistributedDiscreteGeometry) + + gids = get_cell_gids(bgmodel) + bgf_to_ioc = map(local_views(bgmodel),local_views(gids),local_views(geo)) do model,gids,geo + ownmodel = remove_ghost_cells(model,gids) + compute_bgfacet_to_inoutcut(cutter,ownmodel,geo) + end + compute_bgfacet_to_inoutcut(bgmodel,bgf_to_ioc) +end \ No newline at end of file diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index 850eb181..742a2336 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -16,8 +16,12 @@ local_views(a::DistributedEmbeddedDiscretization) = a.discretizations get_background_model(a::DistributedEmbeddedDiscretization) = a.model function get_geometry(a::DistributedEmbeddedDiscretization) - cut = local_views(a) |> PartitionedArrays.getany - get_geometry(cut) + loc_geometries = map(get_geometry,local_views(a)) + get_geometry(loc_geometries) +end + +function get_geometry(a::AbstractArray{<:CSG.Geometry}) + PartitionedArrays.getany(a) end function cut(bgmodel::DistributedDiscreteModel,args...) diff --git a/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..ffe8f674 --- /dev/null +++ b/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl @@ -0,0 +1,148 @@ +module DistributedDiscreteGeometryPoissonTest + +using Gridap +using GridapEmbedded +using GridapDistributed +using PartitionedArrays +using Test + +using GridapEmbedded.CSG +using GridapEmbedded.LevelSetCutters + +function main(distribute,parts; + threshold=1, + n=8, + cells=(n,n), + geometry=:circle) + + ranks = distribute(LinearIndices((prod(parts),))) + + u(x) = x[1] - x[2] + f(x) = -Δ(u)(x) + ud(x) = u(x) + + geometries = Dict( + :circle => circle_geometry, + :remotes => remotes_geometry, + ) + + bgmodel,_geo = geometries[geometry](ranks,parts,cells) + geo = discretize(_geo,bgmodel) + + D = 2 + cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) + meas = map(first,cell_meas) |> PartitionedArrays.getany + h = meas^(1/D) + + cutgeo = cut(bgmodel,geo) + cutgeo_facets = cut_facets(bgmodel,geo) + + strategy = AggregateCutCellsByThreshold(threshold) + bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) + + Ω_bg = Triangulation(bgmodel) + Ω_act = Triangulation(cutgeo,ACTIVE) + Ω = Triangulation(cutgeo,PHYSICAL) + Γ = EmbeddedBoundary(cutgeo) + + n_Γ = get_normal_vector(Γ) + + order = 1 + degree = 2*order + dΩ = Measure(Ω,degree) + dΓ = Measure(Γ,degree) + + reffe = ReferenceFE(lagrangian,Float64,order) + + Vstd = FESpace(Ω_act,reffe) + + V = AgFEMSpace(bgmodel,Vstd,aggregates) + U = TrialFESpace(V) + + + γd = 10.0 + + a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + + l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + + op = AffineFEOperator(a,l,U,V) + uh = solve(op) + + e = u - uh + + l2(u) = sqrt(sum( ∫( u*u )*dΩ )) + h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + + el2 = l2(e) + eh1 = h1(e) + ul2 = l2(uh) + uh1 = h1(uh) + + # + colors = map(color_aggregates,aggregates,local_views(bgmodel)) + gids = get_cell_gids(bgmodel) + + + global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid + map(i-> i==0 ? 0 : gid[i],agg) + end + own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid + map(Reindex(agg),oid) + end + own_colors = map(colors,own_to_local(gids)) do col,oid + map(Reindex(col),oid) + end + + writevtk(Ω_bg,"trian", + celldata=[ + "aggregate"=>own_aggregates, + "color"=>own_colors, + "gid"=>own_to_global(gids)])#, + # cellfields=["uh"=>uh]) + + writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) + writevtk(Γ,"trian_G") + @test el2/ul2 < 1.e-8 + @test eh1/uh1 < 1.e-7 + +end + +function circle_geometry(ranks,parts,cells) + L = 1 + p0 = Point(0.0,0.0) + pmin = p0-L/2 + pmax = p0+L/2 + R = 0.35 + geo = disk(R,x0=p0) + bgmodel = CartesianDiscreteModel(ranks,parts,pmin,pmax,cells) + bgmodel,geo +end + +function remotes_geometry(ranks,parts,cells) + x0 = Point(0.05,0.05) + d1 = VectorValue(0.9,0.0) + d2 = VectorValue(0.0,0.1) + geo1 = quadrilateral(;x0=x0,d1=d1,d2=d2) + + x0 = Point(0.15,0.1) + d1 = VectorValue(0.25,0.0) + d2 = VectorValue(0.0,0.6) + geo2 = quadrilateral(;x0=x0,d1=d1,d2=d2) + geo = union(geo1,geo2) + + domain = (0, 1, 0, 1) + bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells) + bgmodel,geo +end + +with_debug() do distribute + main(distribute,(2,2)) + main(distribute,(4,1),cells=(12,12),geometry=:remotes) +end + +end # module \ No newline at end of file diff --git a/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..9e29dee1 --- /dev/null +++ b/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl @@ -0,0 +1,8 @@ +module DistributedDiscreteGeometryPoissonTestsSeq +using PartitionedArrays +include("../DistributedDiscreteGeometryPoissonTest.jl") +with_debug() do distribute + PoissonTests.main(distribute,(2,2)) + PoissonTests.main(distribute,(4,1),cells=(12,12),geometry=:remotes) +end +end diff --git a/test/DistributedTests/sequential/runtests.jl b/test/DistributedTests/sequential/runtests.jl index e68831c3..5819b694 100644 --- a/test/DistributedTests/sequential/runtests.jl +++ b/test/DistributedTests/sequential/runtests.jl @@ -3,5 +3,6 @@ module SequentialTests using Test @time @testset "PoissonSeq" begin include("PoissonTests.jl") end +@time @testset "PoissonSeq" begin include("DistributedDiscreteGeometryPoissonTest.jl") end end From 1ac42f2b57551c94c9ae2132fa3a0bccfe07b8e2 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:24:37 +1000 Subject: [PATCH 002/120] Fix test --- .../sequential/DistributedDiscreteGeometryPoissonTest.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl index 9e29dee1..080d4b9f 100644 --- a/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl +++ b/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl @@ -2,7 +2,7 @@ module DistributedDiscreteGeometryPoissonTestsSeq using PartitionedArrays include("../DistributedDiscreteGeometryPoissonTest.jl") with_debug() do distribute - PoissonTests.main(distribute,(2,2)) - PoissonTests.main(distribute,(4,1),cells=(12,12),geometry=:remotes) + DistributedDiscreteGeometryPoissonTest.main(distribute,(2,2)) + DistributedDiscreteGeometryPoissonTest.main(distribute,(4,1),cells=(12,12),geometry=:remotes) end end From 643efc205a13c8a7a9b6a3e0352d19cb2f6cac3d Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Sat, 8 Jun 2024 10:41:18 +1000 Subject: [PATCH 003/120] Missing MPI test call --- test/DistributedTests/mpi/runtests_body.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/DistributedTests/mpi/runtests_body.jl b/test/DistributedTests/mpi/runtests_body.jl index fe600b7c..7c44d8bc 100644 --- a/test/DistributedTests/mpi/runtests_body.jl +++ b/test/DistributedTests/mpi/runtests_body.jl @@ -6,6 +6,7 @@ using MPI include("../PoissonTests.jl") include("../AggregatesTests.jl") +include("../DistributedDiscreteGeometryPoissonTest.jl") if ! MPI.Initialized() MPI.Init() @@ -21,6 +22,11 @@ function all_tests(distribute,parts) PoissonTests.main(distribute,(prod(parts),1),cells=(12,12),geometry=:remotes) PArrays.toc!(t,"Poisson") + PArrays.tic!(t) + DistributedDiscreteGeometryPoissonTest.main(distribute,parts) + DistributedDiscreteGeometryPoissonTest.main(distribute,(prod(parts),1),cells=(12,12),geometry=:remotes) + PArrays.toc!(t,"DistributedDiscreteGeometryPoisson") + if prod(parts) == 4 DistributedAggregatesTests.main(distribute,parts) end From 2c1d835b91ac94ffe14f4b5cb814800869310c88 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Mon, 10 Jun 2024 13:21:12 +1000 Subject: [PATCH 004/120] Include name in DistributedDiscreteGeometry --- src/Distributed/DistributedDiscreteGeometries.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index ce3c8be3..1f3d32b6 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -4,12 +4,12 @@ end local_views(a::DistributedDiscreteGeometry) = a.geometries -function DistributedDiscreteGeometry(φh::CellField,model::DistributedDiscreteModel) +function DistributedDiscreteGeometry(φh::CellField,model::DistributedDiscreteModel;name::String="") gids = get_cell_gids(model) geometries = map(local_views(model),local_views(gids),local_views(φh)) do model,gids,φh ownmodel = remove_ghost_cells(model,gids) point_to_coords = collect1d(get_node_coordinates(ownmodel)) - DiscreteGeometry(φh(point_to_coords),point_to_coords) + DiscreteGeometry(φh(point_to_coords),point_to_coords;name) end DistributedDiscreteGeometry(geometries) end From 1b5a49014db5568b088a1c0a2a32961c68b27a2a Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 19 Jun 2024 00:59:43 +1000 Subject: [PATCH 005/120] Added _get_value_at_coords to avoid interpolation --- src/Distributed/Distributed.jl | 2 +- .../DistributedDiscreteGeometries.jl | 49 +++++++++++++++++-- src/LevelSetCutters/DiscreteGeometries.jl | 32 ++++++++++++ 3 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index 4fc3e95e..a08527e7 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -43,7 +43,7 @@ import GridapEmbedded.Interfaces: EmbeddedBoundary import GridapEmbedded.Interfaces: compute_bgfacet_to_inoutcut import GridapEmbedded.Interfaces: compute_bgcell_to_inoutcut import GridapEmbedded.CSG: get_geometry -import GridapEmbedded.LevelSetCutters: discretize +import GridapEmbedded.LevelSetCutters: discretize, DiscreteGeometry import Gridap.Geometry: Triangulation import Gridap.Geometry: SkeletonTriangulation import Gridap.Geometry: BoundaryTriangulation diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index 1f3d32b6..616c7120 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -4,12 +4,55 @@ end local_views(a::DistributedDiscreteGeometry) = a.geometries -function DistributedDiscreteGeometry(φh::CellField,model::DistributedDiscreteModel;name::String="") +function _get_values_at_owned_coords(φh,model::DistributedDiscreteModel{Dc,Dp}) where {Dc,Dp} + @assert DomainStyle(φh) == ReferenceDomain() gids = get_cell_gids(model) - geometries = map(local_views(model),local_views(gids),local_views(φh)) do model,gids,φh + values = map(local_views(φh),local_views(model),local_views(gids)) do φh, model, gids + # Maps from the no-ghost model to the original model + own_model = remove_ghost_cells(model,gids) + own_to_local_node = Geometry.get_face_to_parent_face(own_model,0) + local_to_own_node = Arrays.find_inverse_index_map(own_to_local_node,num_nodes(model)) + own_to_local_cell = Geometry.get_face_to_parent_face(own_model,Dc) + + # Cell-to-node map for the original model + # topo = get_grid_topology(model) + # c2n_map = get_faces(topo,Dc,0) + c2n_map = collect1d(get_cell_node_ids(model)) + + # Cell-wise node coordinates (in ReferenceDomain coordinates) + cell_reffe = get_cell_reffe(model) + cell_node_coords = lazy_map(get_node_coordinates,cell_reffe) + + φh_data = CellData.get_data(φh) + space = get_fe_space(φh) + T = get_dof_value_type(space) + values = Vector{T}(undef,num_nodes(own_model)) + touched = fill(false,num_nodes(model)) + + cell_node_coords_cache = array_cache(cell_node_coords) + for cell in own_to_local_cell # For each owned cell + field = φh_data[cell] + node_coords = getindex!(cell_node_coords_cache,cell_node_coords,cell) + for (iN,node) in enumerate(c2n_map[cell]) # Go over local nodes + own_node = local_to_own_node[node] + if (own_node != 0) && !touched[node] # Compute value if suitable + values[own_node] = field(node_coords[iN]) + touched[node] = true + end + end + end + return values + end + return values +end + +function DiscreteGeometry(φh::CellField,model::DistributedDiscreteModel;name::String="") + φ_values = _get_values_at_owned_coords(φh,model) + gids = get_cell_gids(model) + geometries = map(local_views(model),local_views(gids),local_views(φ_values)) do model,gids,loc_φ ownmodel = remove_ghost_cells(model,gids) point_to_coords = collect1d(get_node_coordinates(ownmodel)) - DiscreteGeometry(φh(point_to_coords),point_to_coords;name) + DiscreteGeometry(loc_φ,point_to_coords;name) end DistributedDiscreteGeometry(geometries) end diff --git a/src/LevelSetCutters/DiscreteGeometries.jl b/src/LevelSetCutters/DiscreteGeometries.jl index 5289299a..d2e15ffe 100644 --- a/src/LevelSetCutters/DiscreteGeometries.jl +++ b/src/LevelSetCutters/DiscreteGeometries.jl @@ -65,9 +65,41 @@ function _find_unique_leaves(tree) j_to_fun, oid_to_j end +function _get_value_at_coords(φh::CellField,model::DiscreteModel{Dc,Dp}) where {Dc,Dp} + @assert DomainStyle(φh) == ReferenceDomain() + # Cell-to-node map for the original model + c2n_map = collect1d(get_cell_node_ids(model)) + + # Cell-wise node coordinates (in ReferenceDomain coordinates) + cell_reffe = get_cell_reffe(model) + cell_node_coords = lazy_map(get_node_coordinates,cell_reffe) + + # Get cell data + φh_data = CellData.get_data(φh) + space = get_fe_space(φh) + T = get_dof_value_type(space) + values = Vector{T}(undef,num_nodes(model)) + cell_node_coords_cache = array_cache(cell_node_coords) + # Loop over cells + for cell in eachindex(c2n_map) + field = φh_data[cell] + node_coords = getindex!(cell_node_coords_cache,cell_node_coords,cell) + for (iN,node) in enumerate(c2n_map[cell]) + values[node] = field(node_coords[iN]) + end + end +end + function DiscreteGeometry( point_to_value::AbstractVector,point_to_coords::AbstractVector;name::String="") data = (point_to_value,name,nothing) tree = Leaf(data) DiscreteGeometry(tree,point_to_coords) end + +function DiscreteGeometry( + φh::CellField,model::DiscreteModel;name::String="") + point_to_value = _get_value_at_coords(φh,model) + point_to_coords = collect1d(get_node_coordinates(model)) + DiscreteGeometry(point_to_value,point_to_coords;name) +end \ No newline at end of file From e80c763c717ee28cdd8b215c7a0e191da300f1db Mon Sep 17 00:00:00 2001 From: Z J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:12:25 +1000 Subject: [PATCH 006/120] Remove unused test --- .../DistributedDiscreteGeometryPoissonTest.jl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl index ffe8f674..10a99591 100644 --- a/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl +++ b/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl @@ -140,9 +140,4 @@ function remotes_geometry(ranks,parts,cells) bgmodel,geo end -with_debug() do distribute - main(distribute,(2,2)) - main(distribute,(4,1),cells=(12,12),geometry=:remotes) -end - end # module \ No newline at end of file From 5195d51dcf189b3e401051114cbf80c6c26a93da Mon Sep 17 00:00:00 2001 From: Z J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:50:21 +1000 Subject: [PATCH 007/120] added periodic testing, suggests that weak method is likely required here. --- src/LevelSetCutters/DiscreteGeometries.jl | 3 +- src/LevelSetCutters/LevelSetCutters.jl | 1 + test/AgFEMTests/PeriodicAgFEMSpacesTests.jl | 75 +++++++++ test/AgFEMTests/runtests.jl | 2 + ...cDistributedDiscreteGeometryPoissonTest.jl | 143 ++++++++++++++++++ ...istributedLSDiscreteGeometryPoissonTest.jl | 110 ++++++++++++++ test/DistributedTests/PeriodicPoissonTests.jl | 141 +++++++++++++++++ test/DistributedTests/mpi/runtests_body.jl | 17 +++ ...cDistributedDiscreteGeometryPoissonTest.jl | 8 + ...istributedLSDiscreteGeometryPoissonTest.jl | 7 + .../sequential/PeriodicPoissonTests.jl | 8 + test/DistributedTests/sequential/runtests.jl | 4 +- .../PeriodicDiscreteGeoPoissonAgFEMTests.jl | 76 ++++++++++ .../PeriodicPoissonAgFEMTests.jl | 74 +++++++++ test/GridapEmbeddedTests/runtests.jl | 4 + 15 files changed, 671 insertions(+), 2 deletions(-) create mode 100644 test/AgFEMTests/PeriodicAgFEMSpacesTests.jl create mode 100644 test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl create mode 100644 test/DistributedTests/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl create mode 100644 test/DistributedTests/PeriodicPoissonTests.jl create mode 100644 test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl create mode 100644 test/DistributedTests/sequential/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl create mode 100644 test/DistributedTests/sequential/PeriodicPoissonTests.jl create mode 100644 test/GridapEmbeddedTests/PeriodicDiscreteGeoPoissonAgFEMTests.jl create mode 100644 test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl diff --git a/src/LevelSetCutters/DiscreteGeometries.jl b/src/LevelSetCutters/DiscreteGeometries.jl index d2e15ffe..3eb9705d 100644 --- a/src/LevelSetCutters/DiscreteGeometries.jl +++ b/src/LevelSetCutters/DiscreteGeometries.jl @@ -76,7 +76,7 @@ function _get_value_at_coords(φh::CellField,model::DiscreteModel{Dc,Dp}) where # Get cell data φh_data = CellData.get_data(φh) - space = get_fe_space(φh) + space = FESpaces.get_fe_space(φh) T = get_dof_value_type(space) values = Vector{T}(undef,num_nodes(model)) cell_node_coords_cache = array_cache(cell_node_coords) @@ -88,6 +88,7 @@ function _get_value_at_coords(φh::CellField,model::DiscreteModel{Dc,Dp}) where values[node] = field(node_coords[iN]) end end + return values end function DiscreteGeometry( diff --git a/src/LevelSetCutters/LevelSetCutters.jl b/src/LevelSetCutters/LevelSetCutters.jl index aa5b1472..75296ea1 100644 --- a/src/LevelSetCutters/LevelSetCutters.jl +++ b/src/LevelSetCutters/LevelSetCutters.jl @@ -28,6 +28,7 @@ using Gridap.Geometry using Gridap.CellData using Gridap.Polynomials using Gridap.Visualization +using Gridap.FESpaces export LevelSetCutter export AnalyticalGeometry diff --git a/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl new file mode 100644 index 00000000..cc1845fd --- /dev/null +++ b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl @@ -0,0 +1,75 @@ +module PeriodicAgFEMSpacesTests + +using Test +using Gridap +using GridapEmbedded +using Gridap.Geometry: get_active_model + +const R = 0.5 +geom = disk(R,x0=Point(0.5,0.5)) +n = 21 +partition = (n,n) + +domain = (0,1,0,1) +bgmodel = CartesianDiscreteModel(domain,partition;isperiodic=(true,true)) + +cutdisc = cut(bgmodel,geom) + +strategy = AggregateCutCellsByThreshold(1) +aggregates = aggregate(strategy,cutdisc) + +Ω_bg = Triangulation(bgmodel) +Ω_ac = Triangulation(cutdisc,ACTIVE) +Ω = Triangulation(cutdisc,PHYSICAL) +Ω_in = Triangulation(cutdisc,IN) + +dΩ_bg = Measure(Ω_bg,2) +dΩ = Measure(Ω,2) +dΩ_in = Measure(Ω_in,2) + +model = get_active_model(Ω_ac) +order = 2 + +# In the physical domain +cell_fe = FiniteElements(PhysicalDomain(),model,lagrangian,Float64,order) +Vstd = FESpace(Ω_ac,cell_fe) + +Vagg = AgFEMSpace(Vstd,aggregates) +U = TrialFESpace(Vagg) + +v(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 +vhagg = interpolate(v,Vagg) + +writevtk(Ω_ac,"test",cellfields=["v"=>vhagg]) + +tol = 10e-9 +@test sum( ∫(abs2(v-vhagg))dΩ ) < tol +@test sum( ∫(abs2(v-vhagg))dΩ_in ) < tol + +vh = FEFunction(V,rand(num_free_dofs(V))) +vhagg = interpolate(vh,Vagg) +@test sum( ∫(abs2(vh-vhagg))dΩ_in ) < tol + +# In the reference space + +reffe = ReferenceFE(lagrangian,Float64,order) +V = FESpace(Ω_ac,reffe) +Vagg = AgFEMSpace(V,aggregates) + +v(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 +vhagg = interpolate(v,Vagg) + +tol = 10e-9 +@test sum( ∫(abs2(v-vhagg))dΩ ) < tol +@test sum( ∫(abs2(v-vhagg))dΩ_in ) < tol + +vh = FEFunction(V,rand(num_free_dofs(V))) +vhagg = interpolate(vh,Vagg) +@test sum( ∫(abs2(vh-vhagg))dΩ_in ) < tol + +#cellfields = ["vh"=>vh,"vhagg"=>vhagg,"e"=>vh-vhagg] +#writevtk(Ω_bg,"trian_bg",nsubcells=10,cellfields=cellfields) +#writevtk(Ω_in,"trian_in",nsubcells=10,cellfields=cellfields) +#writevtk(Ω,"trian_phys",cellfields=cellfields) + +end # module diff --git a/test/AgFEMTests/runtests.jl b/test/AgFEMTests/runtests.jl index 9d039176..66d7f07b 100644 --- a/test/AgFEMTests/runtests.jl +++ b/test/AgFEMTests/runtests.jl @@ -6,4 +6,6 @@ using Test @testset "AgFEMSpaces" begin include("AgFEMSpacesTests.jl") end +@testset "PeriodicAgFEMSpaces" begin include("PeriodicAgFEMSpacesTests.jl") end + end # module diff --git a/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..8bd3e679 --- /dev/null +++ b/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl @@ -0,0 +1,143 @@ +module PeriodicDistributedDiscreteGeometryPoissonTest + +using Gridap +using GridapEmbedded +using GridapDistributed +using PartitionedArrays +using Test + +using GridapEmbedded.CSG +using GridapEmbedded.LevelSetCutters + +function main(distribute,parts; + threshold=1, + n=8, + cells=(n,n), + geometry=:circle) + + ranks = distribute(LinearIndices((prod(parts),))) + + u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 + f(x) = -Δ(u)(x) + ud(x) = u(x) + + geometries = Dict( + :circle => circle_geometry, + :remotes => remotes_geometry, + ) + + bgmodel,_geo = geometries[geometry](ranks,parts,cells) + geo = discretize(_geo,bgmodel) + + D = 2 + cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) + meas = map(first,cell_meas) |> PartitionedArrays.getany + h = meas^(1/D) + + cutgeo = cut(bgmodel,geo) + cutgeo_facets = cut_facets(bgmodel,geo) + + strategy = AggregateCutCellsByThreshold(threshold) + bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) + + Ω_bg = Triangulation(bgmodel) + Ω_act = Triangulation(cutgeo,ACTIVE) + Ω = Triangulation(cutgeo,PHYSICAL) + Γ = EmbeddedBoundary(cutgeo) + + n_Γ = get_normal_vector(Γ) + + order = 2 + degree = 2*order + dΩ = Measure(Ω,degree) + dΓ = Measure(Γ,degree) + + reffe = ReferenceFE(lagrangian,Float64,order) + + Vstd = FESpace(Ω_act,reffe) + + V = AgFEMSpace(bgmodel,Vstd,aggregates) + U = TrialFESpace(V) + + + γd = 10.0 + + a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + + l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + + op = AffineFEOperator(a,l,U,V) + uh = solve(op) + + e = u - uh + + l2(u) = sqrt(sum( ∫( u*u )*dΩ )) + h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + + el2 = l2(e) + eh1 = h1(e) + ul2 = l2(uh) + uh1 = h1(uh) + + # + colors = map(color_aggregates,aggregates,local_views(bgmodel)) + gids = get_cell_gids(bgmodel) + + + global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid + map(i-> i==0 ? 0 : gid[i],agg) + end + own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid + map(Reindex(agg),oid) + end + own_colors = map(colors,own_to_local(gids)) do col,oid + map(Reindex(col),oid) + end + + writevtk(Ω_bg,"trian", + celldata=[ + "aggregate"=>own_aggregates, + "color"=>own_colors, + "gid"=>own_to_global(gids)])#, + # cellfields=["uh"=>uh]) + + writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) + writevtk(Γ,"trian_G") + @test el2/ul2 < 1.e-8 + @test eh1/uh1 < 1.e-7 + +end + +function circle_geometry(ranks,parts,cells) + L = 1 + p0 = Point(0.5,0.5) + pmin = p0-L/2 + pmax = p0+L/2 + R = 0.55 + geo = disk(R,x0=p0) + bgmodel = CartesianDiscreteModel(ranks,parts,pmin,pmax,cells;isperiodic=(true,true)) + bgmodel,geo +end + +function remotes_geometry(ranks,parts,cells) + x0 = Point(0.0,0.4) + d1 = VectorValue(1.0,0.0) + d2 = VectorValue(0.0,0.2) + geo1 = quadrilateral(;x0=x0,d1=d1,d2=d2) + + x0 = Point(0.4,0.0) + d1 = VectorValue(0.2,0.0) + d2 = VectorValue(0.0,1.0) + geo2 = quadrilateral(;x0=x0,d1=d1,d2=d2) + geo = union(geo1,geo2) + + domain = (0, 1, 0, 1) + bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells;isperiodic=(true,true)) + bgmodel,geo +end + +end # module \ No newline at end of file diff --git a/test/DistributedTests/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..f0b659e0 --- /dev/null +++ b/test/DistributedTests/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl @@ -0,0 +1,110 @@ +module PeriodicDistributedLSDiscreteGeometryPoissonTest + +using Gridap +using GridapEmbedded +using GridapDistributed +using PartitionedArrays +using Test + +using GridapEmbedded.CSG +using GridapEmbedded.LevelSetCutters + +function main(distribute,parts; + threshold=1, + n=21, + cells=(n,n)) + + order = 2 + ranks = distribute(LinearIndices((prod(parts),))) + domain = (0,1,0,1) + bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells;isperiodic=(true,true)) + + u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 + f(x) = -Δ(u)(x) + ud(x) = u(x) + + reffe = ReferenceFE(lagrangian,Float64,order) + Ω_bg = Triangulation(bgmodel) + V_bg = FESpace(Ω_bg,reffe) + φh = interpolate(x->sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.55,V_bg) + geo = DiscreteGeometry(φh,bgmodel) + + D = 2 + cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) + meas = map(first,cell_meas) |> PartitionedArrays.getany + h = meas^(1/D) + + cutgeo = cut(bgmodel,geo) + cutgeo_facets = cut_facets(bgmodel,geo) + + strategy = AggregateCutCellsByThreshold(threshold) + bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) + + Ω_act = Triangulation(cutgeo,ACTIVE) + Ω = Triangulation(cutgeo,PHYSICAL) + Γ = EmbeddedBoundary(cutgeo) + + n_Γ = get_normal_vector(Γ) + + order = 2 + degree = 2*order + dΩ = Measure(Ω,degree) + dΓ = Measure(Γ,degree) + + Vstd = FESpace(Ω_act,reffe) + V = AgFEMSpace(bgmodel,Vstd,aggregates) + U = TrialFESpace(V) + + γd = 10.0 + + a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + + l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + + op = AffineFEOperator(a,l,U,V) + uh = solve(op) + + e = u - uh + + l2(u) = sqrt(sum( ∫( u*u )*dΩ )) + h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + + el2 = l2(e) + eh1 = h1(e) + ul2 = l2(uh) + uh1 = h1(uh) + + # + colors = map(color_aggregates,aggregates,local_views(bgmodel)) + gids = get_cell_gids(bgmodel) + + + global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid + map(i-> i==0 ? 0 : gid[i],agg) + end + own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid + map(Reindex(agg),oid) + end + own_colors = map(colors,own_to_local(gids)) do col,oid + map(Reindex(col),oid) + end + + writevtk(Ω_bg,"trian", + celldata=[ + "aggregate"=>own_aggregates, + "color"=>own_colors, + "gid"=>own_to_global(gids)])#, + # cellfields=["uh"=>uh]) + + writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) + writevtk(Γ,"trian_G") + @test el2/ul2 < 1.e-8 + @test eh1/uh1 < 1.e-7 + +end + +end # module \ No newline at end of file diff --git a/test/DistributedTests/PeriodicPoissonTests.jl b/test/DistributedTests/PeriodicPoissonTests.jl new file mode 100644 index 00000000..130ad414 --- /dev/null +++ b/test/DistributedTests/PeriodicPoissonTests.jl @@ -0,0 +1,141 @@ +module PeriodicPoissonTests + +using Gridap +using GridapEmbedded +using GridapDistributed +using PartitionedArrays +using Test + +using GridapEmbedded.CSG + +function main(distribute,parts; + threshold=1, + n=8, + cells=(n,n), + geometry=:circle) + + ranks = distribute(LinearIndices((prod(parts),))) + + u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 + f(x) = -Δ(u)(x) + ud(x) = u(x) + + geometries = Dict( + :circle => circle_geometry, + :remotes => remotes_geometry, + ) + + bgmodel,geo = geometries[geometry](ranks,parts,cells) + + D = 2 + cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) + meas = map(first,cell_meas) |> PartitionedArrays.getany + h = meas^(1/D) + + cutgeo = cut(bgmodel,geo) + cutgeo_facets = cut_facets(bgmodel,geo) + + strategy = AggregateCutCellsByThreshold(threshold) + bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) + + Ω_bg = Triangulation(bgmodel) + Ω_act = Triangulation(cutgeo,ACTIVE) + Ω = Triangulation(cutgeo,PHYSICAL) + Γ = EmbeddedBoundary(cutgeo) + + n_Γ = get_normal_vector(Γ) + + order = 2 + degree = 2*order + dΩ = Measure(Ω,degree) + dΓ = Measure(Γ,degree) + + reffe = ReferenceFE(lagrangian,Float64,order) + + Vstd = FESpace(Ω_act,reffe) + + V = AgFEMSpace(bgmodel,Vstd,aggregates) + U = TrialFESpace(V) + + + γd = 10.0 + + a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + + l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + + op = AffineFEOperator(a,l,U,V) + uh = solve(op) + + e = u - uh + + l2(u) = sqrt(sum( ∫( u*u )*dΩ )) + h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + + el2 = l2(e) + eh1 = h1(e) + ul2 = l2(uh) + uh1 = h1(uh) + + # + colors = map(color_aggregates,aggregates,local_views(bgmodel)) + gids = get_cell_gids(bgmodel) + + + global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid + map(i-> i==0 ? 0 : gid[i],agg) + end + own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid + map(Reindex(agg),oid) + end + own_colors = map(colors,own_to_local(gids)) do col,oid + map(Reindex(col),oid) + end + + writevtk(Ω_bg,"trian", + celldata=[ + "aggregate"=>own_aggregates, + "color"=>own_colors, + "gid"=>own_to_global(gids)])#, + # cellfields=["uh"=>uh]) + + writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) + writevtk(Γ,"trian_G") + @test el2/ul2 < 1.e-8 + @test eh1/uh1 < 1.e-7 + +end + +function circle_geometry(ranks,parts,cells) + L = 1 + p0 = Point(0.5,0.5) + pmin = p0-L/2 + pmax = p0+L/2 + R = 0.55 + geo = disk(R,x0=p0) + bgmodel = CartesianDiscreteModel(ranks,parts,pmin,pmax,cells;isperiodic=(true,true)) + bgmodel,geo +end + +function remotes_geometry(ranks,parts,cells) + x0 = Point(0.0,0.4) + d1 = VectorValue(1.0,0.0) + d2 = VectorValue(0.0,0.2) + geo1 = quadrilateral(;x0=x0,d1=d1,d2=d2) + + x0 = Point(0.4,0.0) + d1 = VectorValue(0.2,0.0) + d2 = VectorValue(0.0,1.0) + geo2 = quadrilateral(;x0=x0,d1=d1,d2=d2) + geo = union(geo1,geo2) + + domain = (0, 1, 0, 1) + bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells;isperiodic=(true,true)) + bgmodel,geo +end + +end # module diff --git a/test/DistributedTests/mpi/runtests_body.jl b/test/DistributedTests/mpi/runtests_body.jl index 7c44d8bc..cdbb6dcb 100644 --- a/test/DistributedTests/mpi/runtests_body.jl +++ b/test/DistributedTests/mpi/runtests_body.jl @@ -7,6 +7,9 @@ using MPI include("../PoissonTests.jl") include("../AggregatesTests.jl") include("../DistributedDiscreteGeometryPoissonTest.jl") +include("../PeriodicPoissonTests.jl") +include("../PeriodicDistributedDiscreteGeometryPoissonTest.jl") +include("../PeriodicDistributedLSDiscreteGeometryPoissonTest.jl") if ! MPI.Initialized() MPI.Init() @@ -27,6 +30,20 @@ function all_tests(distribute,parts) DistributedDiscreteGeometryPoissonTest.main(distribute,(prod(parts),1),cells=(12,12),geometry=:remotes) PArrays.toc!(t,"DistributedDiscreteGeometryPoisson") + PArrays.tic!(t) + PeriodicPoissonTests.main(distribute,parts,cells=(21,21)) + PeriodicPoissonTests.main(distribute,(prod(parts),1),cells=(21,21),geometry=:remotes) + PArrays.toc!(t,"PeriodicPoissonTests") + + PArrays.tic!(t) + PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,parts,cells=(21,21)) + PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(prod(parts),1),cells=(21,21),geometry=:remotes) + PArrays.toc!(t,"PeriodicDistributedDiscreteGeometryPoissonTest") + + PArrays.tic!(t) + PeriodicDistributedLSDiscreteGeometryPoissonTest.main(distribute,parts,cells=(21,21)) + PArrays.toc!(t,"PeriodicDistributedLSDiscreteGeometryPoissonTest") + if prod(parts) == 4 DistributedAggregatesTests.main(distribute,parts) end diff --git a/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..87bf08ea --- /dev/null +++ b/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl @@ -0,0 +1,8 @@ +module PeriodicDistributedDiscreteGeometryPoissonTestsSeq +using PartitionedArrays +include("../PeriodicDistributedDiscreteGeometryPoissonTest.jl") +with_debug() do distribute + PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(2,2),cells=(21,21)) + PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(4,1),cells=(21,21),geometry=:remotes) +end +end diff --git a/test/DistributedTests/sequential/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..52a24dac --- /dev/null +++ b/test/DistributedTests/sequential/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl @@ -0,0 +1,7 @@ +module PeriodicDistributedLSDiscreteGeometryPoissonTestsSeq +using PartitionedArrays +include("../PeriodicDistributedLSDiscreteGeometryPoissonTest.jl") +with_debug() do distribute + PeriodicDistributedLSDiscreteGeometryPoissonTest.main(distribute,(2,2),cells=(21,21)) +end +end diff --git a/test/DistributedTests/sequential/PeriodicPoissonTests.jl b/test/DistributedTests/sequential/PeriodicPoissonTests.jl new file mode 100644 index 00000000..e0d8ebb0 --- /dev/null +++ b/test/DistributedTests/sequential/PeriodicPoissonTests.jl @@ -0,0 +1,8 @@ +module PeriodicPoissonTestsSeq +using PartitionedArrays +include("../PeriodicPoissonTests.jl") +with_debug() do distribute + PeriodicPoissonTests.main(distribute,(2,2),cells=(21,21)) + PeriodicPoissonTests.main(distribute,(4,1),cells=(21,21),geometry=:remotes) +end +end diff --git a/test/DistributedTests/sequential/runtests.jl b/test/DistributedTests/sequential/runtests.jl index 5819b694..a9ac9931 100644 --- a/test/DistributedTests/sequential/runtests.jl +++ b/test/DistributedTests/sequential/runtests.jl @@ -3,6 +3,8 @@ module SequentialTests using Test @time @testset "PoissonSeq" begin include("PoissonTests.jl") end -@time @testset "PoissonSeq" begin include("DistributedDiscreteGeometryPoissonTest.jl") end +@time @testset "DiscreteGeoPoissonSeq" begin include("DistributedDiscreteGeometryPoissonTest.jl") end +@time @testset "PeriodicPoissonSeq" begin include("PeriodicPoissonTests.jl") end +@time @testset "PeriodicDiscreteGeoPoissonSeq" begin include("PeriodicDistributedDiscreteGeometryPoissonTest.jl") end end diff --git a/test/GridapEmbeddedTests/PeriodicDiscreteGeoPoissonAgFEMTests.jl b/test/GridapEmbeddedTests/PeriodicDiscreteGeoPoissonAgFEMTests.jl new file mode 100644 index 00000000..4e791365 --- /dev/null +++ b/test/GridapEmbeddedTests/PeriodicDiscreteGeoPoissonAgFEMTests.jl @@ -0,0 +1,76 @@ +# module PoissonAgFEMTests + +using Gridap +using GridapEmbedded +using Test + +u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 +f(x) = -Δ(u)(x) +ud(x) = u(x) + +order = 2 +n = 31 +partition = (n,n) +domain = (0,1,0,1) +bgmodel = CartesianDiscreteModel(domain,partition;isperiodic=(true,true)) +dp = 1 +const h = dp/n + +reffe = ReferenceFE(lagrangian,Float64,order) +Ω_bg = Triangulation(bgmodel) +V_bg = FESpace(Ω_bg,reffe) +φh = interpolate(x->sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.55,V_bg) +geo = DiscreteGeometry(φh,bgmodel) +cutgeo = cut(bgmodel,geo) + +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +Ω_bg = Triangulation(bgmodel) +Ω_act = Triangulation(cutgeo,ACTIVE) +Ω = Triangulation(cutgeo,PHYSICAL) +Γ = EmbeddedBoundary(cutgeo) + +n_Γ = get_normal_vector(Γ) + +degree = 2*order +dΩ = Measure(Ω,degree) +dΓ = Measure(Γ,degree) + +model = get_active_model(Ω_act) +Vstd = FESpace(Ω_act,FiniteElements(PhysicalDomain(),model,lagrangian,Float64,order)) + +V = AgFEMSpace(Vstd,aggregates) +U = TrialFESpace(V) + +const γd = 10.0 + +a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + +l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + +op = AffineFEOperator(a,l,U,V) +uh = solve(op) + +e = u - uh + +l2(u) = sqrt(sum( ∫( u*u )*dΩ )) +h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + +el2 = l2(e) +eh1 = h1(e) +ul2 = l2(uh) +uh1 = h1(uh) + +colors = color_aggregates(aggregates,bgmodel) +writevtk(Ω_bg,"trian",celldata=["aggregate"=>aggregates,"color"=>colors],cellfields=["uh"=>uh]) +writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) +writevtk(Γ,"trian_G") +@test el2/ul2 < 1.e-8 +@test eh1/uh1 < 1.e-7 + +# end # module diff --git a/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl b/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl new file mode 100644 index 00000000..c45c38d9 --- /dev/null +++ b/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl @@ -0,0 +1,74 @@ +module PoissonAgFEMTests + +using Gridap +using GridapEmbedded +using Test + +u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 +f(x) = -Δ(u)(x) +ud(x) = u(x) + +const R = 0.55 +geom = disk(R,x0=Point(0.5,0.5)) + +n = 31 +partition = (n,n) +domain = (0,1,0,1) +bgmodel = CartesianDiscreteModel(domain,partition;isperiodic=(true,true)) +dp = 1 +const h = dp/n + +cutgeo = cut(bgmodel,geom) + +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +Ω_bg = Triangulation(bgmodel) +Ω_act = Triangulation(cutgeo,ACTIVE) +Ω = Triangulation(cutgeo,PHYSICAL) +Γ = EmbeddedBoundary(cutgeo) + +n_Γ = get_normal_vector(Γ) + +order = 2 +degree = 2*order +dΩ = Measure(Ω,degree) +dΓ = Measure(Γ,degree) + +model = get_active_model(Ω_act) +Vstd = FESpace(Ω_act,FiniteElements(PhysicalDomain(),model,lagrangian,Float64,order)) + +V = AgFEMSpace(Vstd,aggregates) +U = TrialFESpace(V) + +const γd = 10.0 + +a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + +l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + +op = AffineFEOperator(a,l,U,V) +uh = solve(op) + +e = u - uh + +l2(u) = sqrt(sum( ∫( u*u )*dΩ )) +h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + +el2 = l2(e) +eh1 = h1(e) +ul2 = l2(uh) +uh1 = h1(uh) + +#colors = color_aggregates(aggregates,bgmodel) +#writevtk(Ω_bg,"trian",celldata=["aggregate"=>aggregates,"color"=>colors],cellfields=["uh"=>uh]) +#writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) +#writevtk(Γ,"trian_G") +@test el2/ul2 < 1.e-8 +@test eh1/uh1 < 1.e-7 + +end # module diff --git a/test/GridapEmbeddedTests/runtests.jl b/test/GridapEmbeddedTests/runtests.jl index 1576bc42..a7e3d787 100644 --- a/test/GridapEmbeddedTests/runtests.jl +++ b/test/GridapEmbeddedTests/runtests.jl @@ -6,6 +6,10 @@ using Test @time @testset "PoissonAgFEM" begin include("PoissonAgFEMTests.jl") end +@time @testset "PeriodicPoissonAgFEM" begin include("PeriodicPoissonAgFEMTests.jl") end + +@time @testset "PeriodicDiscreteGeoPoissonAgFEM" begin include("PeriodicDiscreteGeoPoissonAgFEMTests.jl") end + @time @testset "PoissonModalC0AgFEM" begin include("PoissonModalC0AgFEMTests.jl") end @time @testset "BimaterialPoissonCutFEM" begin include("BimaterialPoissonCutFEMTests.jl") end From e0fb29835305190ab4fd49b0b65d25c549eaf3d0 Mon Sep 17 00:00:00 2001 From: Z J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 19 Jun 2024 16:51:10 +1000 Subject: [PATCH 008/120] add dep --- src/Distributed/Distributed.jl | 1 + src/Distributed/DistributedDiscreteGeometries.jl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index a08527e7..3c845702 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -10,6 +10,7 @@ using Gridap.CellData using Gridap.Geometry using Gridap.Helpers using Gridap.ReferenceFEs +using Gridap.FESpaces using GridapEmbedded.CSG using GridapEmbedded.LevelSetCutters diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index 616c7120..2ea37887 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -24,7 +24,7 @@ function _get_values_at_owned_coords(φh,model::DistributedDiscreteModel{Dc,Dp}) cell_node_coords = lazy_map(get_node_coordinates,cell_reffe) φh_data = CellData.get_data(φh) - space = get_fe_space(φh) + space = FESpaces.get_fe_space(φh) T = get_dof_value_type(space) values = Vector{T}(undef,num_nodes(own_model)) touched = fill(false,num_nodes(model)) From 67faf8399d598b91e2bfbfb26d3f8a46c64e52dc Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:21:15 +1000 Subject: [PATCH 009/120] fix test --- test/AgFEMTests/PeriodicAgFEMSpacesTests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl index cc1845fd..ec84d4e1 100644 --- a/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl +++ b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl @@ -5,7 +5,7 @@ using Gridap using GridapEmbedded using Gridap.Geometry: get_active_model -const R = 0.5 +const R = 0.55 geom = disk(R,x0=Point(0.5,0.5)) n = 21 partition = (n,n) @@ -46,7 +46,7 @@ tol = 10e-9 @test sum( ∫(abs2(v-vhagg))dΩ ) < tol @test sum( ∫(abs2(v-vhagg))dΩ_in ) < tol -vh = FEFunction(V,rand(num_free_dofs(V))) +vh = FEFunction(Vstd,rand(num_free_dofs(Vstd))) vhagg = interpolate(vh,Vagg) @test sum( ∫(abs2(vh-vhagg))dΩ_in ) < tol From 82d459791f0ac827678af6d185da54dd7cfc476c Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Thu, 20 Jun 2024 10:03:02 +1000 Subject: [PATCH 010/120] Revert changes --- test/AgFEMTests/PeriodicAgFEMSpacesTests.jl | 14 +- ...cDistributedDiscreteGeometryPoissonTest.jl | 143 ------------------ ...istributedLSDiscreteGeometryPoissonTest.jl | 110 -------------- test/DistributedTests/PeriodicPoissonTests.jl | 141 ----------------- test/DistributedTests/mpi/runtests_body.jl | 17 --- ...cDistributedDiscreteGeometryPoissonTest.jl | 8 - ...istributedLSDiscreteGeometryPoissonTest.jl | 7 - .../sequential/PeriodicPoissonTests.jl | 8 - test/DistributedTests/sequential/runtests.jl | 2 - .../PeriodicDiscreteGeoPoissonAgFEMTests.jl | 76 ---------- .../PeriodicPoissonAgFEMTests.jl | 74 --------- 11 files changed, 3 insertions(+), 597 deletions(-) delete mode 100644 test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl delete mode 100644 test/DistributedTests/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl delete mode 100644 test/DistributedTests/PeriodicPoissonTests.jl delete mode 100644 test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl delete mode 100644 test/DistributedTests/sequential/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl delete mode 100644 test/DistributedTests/sequential/PeriodicPoissonTests.jl delete mode 100644 test/GridapEmbeddedTests/PeriodicDiscreteGeoPoissonAgFEMTests.jl delete mode 100644 test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl diff --git a/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl index ec84d4e1..26b34bae 100644 --- a/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl +++ b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl @@ -28,7 +28,7 @@ dΩ = Measure(Ω,2) dΩ_in = Measure(Ω_in,2) model = get_active_model(Ω_ac) -order = 2 +order = 1 # In the physical domain cell_fe = FiniteElements(PhysicalDomain(),model,lagrangian,Float64,order) @@ -42,14 +42,10 @@ vhagg = interpolate(v,Vagg) writevtk(Ω_ac,"test",cellfields=["v"=>vhagg]) -tol = 10e-9 +tol = 10e-7 @test sum( ∫(abs2(v-vhagg))dΩ ) < tol @test sum( ∫(abs2(v-vhagg))dΩ_in ) < tol -vh = FEFunction(Vstd,rand(num_free_dofs(Vstd))) -vhagg = interpolate(vh,Vagg) -@test sum( ∫(abs2(vh-vhagg))dΩ_in ) < tol - # In the reference space reffe = ReferenceFE(lagrangian,Float64,order) @@ -59,14 +55,10 @@ Vagg = AgFEMSpace(V,aggregates) v(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 vhagg = interpolate(v,Vagg) -tol = 10e-9 +tol = 10e-7 @test sum( ∫(abs2(v-vhagg))dΩ ) < tol @test sum( ∫(abs2(v-vhagg))dΩ_in ) < tol -vh = FEFunction(V,rand(num_free_dofs(V))) -vhagg = interpolate(vh,Vagg) -@test sum( ∫(abs2(vh-vhagg))dΩ_in ) < tol - #cellfields = ["vh"=>vh,"vhagg"=>vhagg,"e"=>vh-vhagg] #writevtk(Ω_bg,"trian_bg",nsubcells=10,cellfields=cellfields) #writevtk(Ω_in,"trian_in",nsubcells=10,cellfields=cellfields) diff --git a/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl deleted file mode 100644 index 8bd3e679..00000000 --- a/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl +++ /dev/null @@ -1,143 +0,0 @@ -module PeriodicDistributedDiscreteGeometryPoissonTest - -using Gridap -using GridapEmbedded -using GridapDistributed -using PartitionedArrays -using Test - -using GridapEmbedded.CSG -using GridapEmbedded.LevelSetCutters - -function main(distribute,parts; - threshold=1, - n=8, - cells=(n,n), - geometry=:circle) - - ranks = distribute(LinearIndices((prod(parts),))) - - u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 - f(x) = -Δ(u)(x) - ud(x) = u(x) - - geometries = Dict( - :circle => circle_geometry, - :remotes => remotes_geometry, - ) - - bgmodel,_geo = geometries[geometry](ranks,parts,cells) - geo = discretize(_geo,bgmodel) - - D = 2 - cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) - meas = map(first,cell_meas) |> PartitionedArrays.getany - h = meas^(1/D) - - cutgeo = cut(bgmodel,geo) - cutgeo_facets = cut_facets(bgmodel,geo) - - strategy = AggregateCutCellsByThreshold(threshold) - bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) - - Ω_bg = Triangulation(bgmodel) - Ω_act = Triangulation(cutgeo,ACTIVE) - Ω = Triangulation(cutgeo,PHYSICAL) - Γ = EmbeddedBoundary(cutgeo) - - n_Γ = get_normal_vector(Γ) - - order = 2 - degree = 2*order - dΩ = Measure(Ω,degree) - dΓ = Measure(Γ,degree) - - reffe = ReferenceFE(lagrangian,Float64,order) - - Vstd = FESpace(Ω_act,reffe) - - V = AgFEMSpace(bgmodel,Vstd,aggregates) - U = TrialFESpace(V) - - - γd = 10.0 - - a(u,v) = - ∫( ∇(v)⋅∇(u) ) * dΩ + - ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ - - l(v) = - ∫( v*f ) * dΩ + - ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ - - op = AffineFEOperator(a,l,U,V) - uh = solve(op) - - e = u - uh - - l2(u) = sqrt(sum( ∫( u*u )*dΩ )) - h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) - - el2 = l2(e) - eh1 = h1(e) - ul2 = l2(uh) - uh1 = h1(uh) - - # - colors = map(color_aggregates,aggregates,local_views(bgmodel)) - gids = get_cell_gids(bgmodel) - - - global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid - map(i-> i==0 ? 0 : gid[i],agg) - end - own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid - map(Reindex(agg),oid) - end - own_colors = map(colors,own_to_local(gids)) do col,oid - map(Reindex(col),oid) - end - - writevtk(Ω_bg,"trian", - celldata=[ - "aggregate"=>own_aggregates, - "color"=>own_colors, - "gid"=>own_to_global(gids)])#, - # cellfields=["uh"=>uh]) - - writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) - writevtk(Γ,"trian_G") - @test el2/ul2 < 1.e-8 - @test eh1/uh1 < 1.e-7 - -end - -function circle_geometry(ranks,parts,cells) - L = 1 - p0 = Point(0.5,0.5) - pmin = p0-L/2 - pmax = p0+L/2 - R = 0.55 - geo = disk(R,x0=p0) - bgmodel = CartesianDiscreteModel(ranks,parts,pmin,pmax,cells;isperiodic=(true,true)) - bgmodel,geo -end - -function remotes_geometry(ranks,parts,cells) - x0 = Point(0.0,0.4) - d1 = VectorValue(1.0,0.0) - d2 = VectorValue(0.0,0.2) - geo1 = quadrilateral(;x0=x0,d1=d1,d2=d2) - - x0 = Point(0.4,0.0) - d1 = VectorValue(0.2,0.0) - d2 = VectorValue(0.0,1.0) - geo2 = quadrilateral(;x0=x0,d1=d1,d2=d2) - geo = union(geo1,geo2) - - domain = (0, 1, 0, 1) - bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells;isperiodic=(true,true)) - bgmodel,geo -end - -end # module \ No newline at end of file diff --git a/test/DistributedTests/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl deleted file mode 100644 index f0b659e0..00000000 --- a/test/DistributedTests/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl +++ /dev/null @@ -1,110 +0,0 @@ -module PeriodicDistributedLSDiscreteGeometryPoissonTest - -using Gridap -using GridapEmbedded -using GridapDistributed -using PartitionedArrays -using Test - -using GridapEmbedded.CSG -using GridapEmbedded.LevelSetCutters - -function main(distribute,parts; - threshold=1, - n=21, - cells=(n,n)) - - order = 2 - ranks = distribute(LinearIndices((prod(parts),))) - domain = (0,1,0,1) - bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells;isperiodic=(true,true)) - - u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 - f(x) = -Δ(u)(x) - ud(x) = u(x) - - reffe = ReferenceFE(lagrangian,Float64,order) - Ω_bg = Triangulation(bgmodel) - V_bg = FESpace(Ω_bg,reffe) - φh = interpolate(x->sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.55,V_bg) - geo = DiscreteGeometry(φh,bgmodel) - - D = 2 - cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) - meas = map(first,cell_meas) |> PartitionedArrays.getany - h = meas^(1/D) - - cutgeo = cut(bgmodel,geo) - cutgeo_facets = cut_facets(bgmodel,geo) - - strategy = AggregateCutCellsByThreshold(threshold) - bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) - - Ω_act = Triangulation(cutgeo,ACTIVE) - Ω = Triangulation(cutgeo,PHYSICAL) - Γ = EmbeddedBoundary(cutgeo) - - n_Γ = get_normal_vector(Γ) - - order = 2 - degree = 2*order - dΩ = Measure(Ω,degree) - dΓ = Measure(Γ,degree) - - Vstd = FESpace(Ω_act,reffe) - V = AgFEMSpace(bgmodel,Vstd,aggregates) - U = TrialFESpace(V) - - γd = 10.0 - - a(u,v) = - ∫( ∇(v)⋅∇(u) ) * dΩ + - ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ - - l(v) = - ∫( v*f ) * dΩ + - ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ - - op = AffineFEOperator(a,l,U,V) - uh = solve(op) - - e = u - uh - - l2(u) = sqrt(sum( ∫( u*u )*dΩ )) - h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) - - el2 = l2(e) - eh1 = h1(e) - ul2 = l2(uh) - uh1 = h1(uh) - - # - colors = map(color_aggregates,aggregates,local_views(bgmodel)) - gids = get_cell_gids(bgmodel) - - - global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid - map(i-> i==0 ? 0 : gid[i],agg) - end - own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid - map(Reindex(agg),oid) - end - own_colors = map(colors,own_to_local(gids)) do col,oid - map(Reindex(col),oid) - end - - writevtk(Ω_bg,"trian", - celldata=[ - "aggregate"=>own_aggregates, - "color"=>own_colors, - "gid"=>own_to_global(gids)])#, - # cellfields=["uh"=>uh]) - - writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) - writevtk(Γ,"trian_G") - @test el2/ul2 < 1.e-8 - @test eh1/uh1 < 1.e-7 - -end - -end # module \ No newline at end of file diff --git a/test/DistributedTests/PeriodicPoissonTests.jl b/test/DistributedTests/PeriodicPoissonTests.jl deleted file mode 100644 index 130ad414..00000000 --- a/test/DistributedTests/PeriodicPoissonTests.jl +++ /dev/null @@ -1,141 +0,0 @@ -module PeriodicPoissonTests - -using Gridap -using GridapEmbedded -using GridapDistributed -using PartitionedArrays -using Test - -using GridapEmbedded.CSG - -function main(distribute,parts; - threshold=1, - n=8, - cells=(n,n), - geometry=:circle) - - ranks = distribute(LinearIndices((prod(parts),))) - - u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 - f(x) = -Δ(u)(x) - ud(x) = u(x) - - geometries = Dict( - :circle => circle_geometry, - :remotes => remotes_geometry, - ) - - bgmodel,geo = geometries[geometry](ranks,parts,cells) - - D = 2 - cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) - meas = map(first,cell_meas) |> PartitionedArrays.getany - h = meas^(1/D) - - cutgeo = cut(bgmodel,geo) - cutgeo_facets = cut_facets(bgmodel,geo) - - strategy = AggregateCutCellsByThreshold(threshold) - bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) - - Ω_bg = Triangulation(bgmodel) - Ω_act = Triangulation(cutgeo,ACTIVE) - Ω = Triangulation(cutgeo,PHYSICAL) - Γ = EmbeddedBoundary(cutgeo) - - n_Γ = get_normal_vector(Γ) - - order = 2 - degree = 2*order - dΩ = Measure(Ω,degree) - dΓ = Measure(Γ,degree) - - reffe = ReferenceFE(lagrangian,Float64,order) - - Vstd = FESpace(Ω_act,reffe) - - V = AgFEMSpace(bgmodel,Vstd,aggregates) - U = TrialFESpace(V) - - - γd = 10.0 - - a(u,v) = - ∫( ∇(v)⋅∇(u) ) * dΩ + - ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ - - l(v) = - ∫( v*f ) * dΩ + - ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ - - op = AffineFEOperator(a,l,U,V) - uh = solve(op) - - e = u - uh - - l2(u) = sqrt(sum( ∫( u*u )*dΩ )) - h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) - - el2 = l2(e) - eh1 = h1(e) - ul2 = l2(uh) - uh1 = h1(uh) - - # - colors = map(color_aggregates,aggregates,local_views(bgmodel)) - gids = get_cell_gids(bgmodel) - - - global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid - map(i-> i==0 ? 0 : gid[i],agg) - end - own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid - map(Reindex(agg),oid) - end - own_colors = map(colors,own_to_local(gids)) do col,oid - map(Reindex(col),oid) - end - - writevtk(Ω_bg,"trian", - celldata=[ - "aggregate"=>own_aggregates, - "color"=>own_colors, - "gid"=>own_to_global(gids)])#, - # cellfields=["uh"=>uh]) - - writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) - writevtk(Γ,"trian_G") - @test el2/ul2 < 1.e-8 - @test eh1/uh1 < 1.e-7 - -end - -function circle_geometry(ranks,parts,cells) - L = 1 - p0 = Point(0.5,0.5) - pmin = p0-L/2 - pmax = p0+L/2 - R = 0.55 - geo = disk(R,x0=p0) - bgmodel = CartesianDiscreteModel(ranks,parts,pmin,pmax,cells;isperiodic=(true,true)) - bgmodel,geo -end - -function remotes_geometry(ranks,parts,cells) - x0 = Point(0.0,0.4) - d1 = VectorValue(1.0,0.0) - d2 = VectorValue(0.0,0.2) - geo1 = quadrilateral(;x0=x0,d1=d1,d2=d2) - - x0 = Point(0.4,0.0) - d1 = VectorValue(0.2,0.0) - d2 = VectorValue(0.0,1.0) - geo2 = quadrilateral(;x0=x0,d1=d1,d2=d2) - geo = union(geo1,geo2) - - domain = (0, 1, 0, 1) - bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells;isperiodic=(true,true)) - bgmodel,geo -end - -end # module diff --git a/test/DistributedTests/mpi/runtests_body.jl b/test/DistributedTests/mpi/runtests_body.jl index cdbb6dcb..7c44d8bc 100644 --- a/test/DistributedTests/mpi/runtests_body.jl +++ b/test/DistributedTests/mpi/runtests_body.jl @@ -7,9 +7,6 @@ using MPI include("../PoissonTests.jl") include("../AggregatesTests.jl") include("../DistributedDiscreteGeometryPoissonTest.jl") -include("../PeriodicPoissonTests.jl") -include("../PeriodicDistributedDiscreteGeometryPoissonTest.jl") -include("../PeriodicDistributedLSDiscreteGeometryPoissonTest.jl") if ! MPI.Initialized() MPI.Init() @@ -30,20 +27,6 @@ function all_tests(distribute,parts) DistributedDiscreteGeometryPoissonTest.main(distribute,(prod(parts),1),cells=(12,12),geometry=:remotes) PArrays.toc!(t,"DistributedDiscreteGeometryPoisson") - PArrays.tic!(t) - PeriodicPoissonTests.main(distribute,parts,cells=(21,21)) - PeriodicPoissonTests.main(distribute,(prod(parts),1),cells=(21,21),geometry=:remotes) - PArrays.toc!(t,"PeriodicPoissonTests") - - PArrays.tic!(t) - PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,parts,cells=(21,21)) - PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(prod(parts),1),cells=(21,21),geometry=:remotes) - PArrays.toc!(t,"PeriodicDistributedDiscreteGeometryPoissonTest") - - PArrays.tic!(t) - PeriodicDistributedLSDiscreteGeometryPoissonTest.main(distribute,parts,cells=(21,21)) - PArrays.toc!(t,"PeriodicDistributedLSDiscreteGeometryPoissonTest") - if prod(parts) == 4 DistributedAggregatesTests.main(distribute,parts) end diff --git a/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl deleted file mode 100644 index 87bf08ea..00000000 --- a/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl +++ /dev/null @@ -1,8 +0,0 @@ -module PeriodicDistributedDiscreteGeometryPoissonTestsSeq -using PartitionedArrays -include("../PeriodicDistributedDiscreteGeometryPoissonTest.jl") -with_debug() do distribute - PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(2,2),cells=(21,21)) - PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(4,1),cells=(21,21),geometry=:remotes) -end -end diff --git a/test/DistributedTests/sequential/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl deleted file mode 100644 index 52a24dac..00000000 --- a/test/DistributedTests/sequential/PeriodicDistributedLSDiscreteGeometryPoissonTest.jl +++ /dev/null @@ -1,7 +0,0 @@ -module PeriodicDistributedLSDiscreteGeometryPoissonTestsSeq -using PartitionedArrays -include("../PeriodicDistributedLSDiscreteGeometryPoissonTest.jl") -with_debug() do distribute - PeriodicDistributedLSDiscreteGeometryPoissonTest.main(distribute,(2,2),cells=(21,21)) -end -end diff --git a/test/DistributedTests/sequential/PeriodicPoissonTests.jl b/test/DistributedTests/sequential/PeriodicPoissonTests.jl deleted file mode 100644 index e0d8ebb0..00000000 --- a/test/DistributedTests/sequential/PeriodicPoissonTests.jl +++ /dev/null @@ -1,8 +0,0 @@ -module PeriodicPoissonTestsSeq -using PartitionedArrays -include("../PeriodicPoissonTests.jl") -with_debug() do distribute - PeriodicPoissonTests.main(distribute,(2,2),cells=(21,21)) - PeriodicPoissonTests.main(distribute,(4,1),cells=(21,21),geometry=:remotes) -end -end diff --git a/test/DistributedTests/sequential/runtests.jl b/test/DistributedTests/sequential/runtests.jl index a9ac9931..bf7521b2 100644 --- a/test/DistributedTests/sequential/runtests.jl +++ b/test/DistributedTests/sequential/runtests.jl @@ -4,7 +4,5 @@ using Test @time @testset "PoissonSeq" begin include("PoissonTests.jl") end @time @testset "DiscreteGeoPoissonSeq" begin include("DistributedDiscreteGeometryPoissonTest.jl") end -@time @testset "PeriodicPoissonSeq" begin include("PeriodicPoissonTests.jl") end -@time @testset "PeriodicDiscreteGeoPoissonSeq" begin include("PeriodicDistributedDiscreteGeometryPoissonTest.jl") end end diff --git a/test/GridapEmbeddedTests/PeriodicDiscreteGeoPoissonAgFEMTests.jl b/test/GridapEmbeddedTests/PeriodicDiscreteGeoPoissonAgFEMTests.jl deleted file mode 100644 index 4e791365..00000000 --- a/test/GridapEmbeddedTests/PeriodicDiscreteGeoPoissonAgFEMTests.jl +++ /dev/null @@ -1,76 +0,0 @@ -# module PoissonAgFEMTests - -using Gridap -using GridapEmbedded -using Test - -u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 -f(x) = -Δ(u)(x) -ud(x) = u(x) - -order = 2 -n = 31 -partition = (n,n) -domain = (0,1,0,1) -bgmodel = CartesianDiscreteModel(domain,partition;isperiodic=(true,true)) -dp = 1 -const h = dp/n - -reffe = ReferenceFE(lagrangian,Float64,order) -Ω_bg = Triangulation(bgmodel) -V_bg = FESpace(Ω_bg,reffe) -φh = interpolate(x->sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.55,V_bg) -geo = DiscreteGeometry(φh,bgmodel) -cutgeo = cut(bgmodel,geo) - -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -Ω_bg = Triangulation(bgmodel) -Ω_act = Triangulation(cutgeo,ACTIVE) -Ω = Triangulation(cutgeo,PHYSICAL) -Γ = EmbeddedBoundary(cutgeo) - -n_Γ = get_normal_vector(Γ) - -degree = 2*order -dΩ = Measure(Ω,degree) -dΓ = Measure(Γ,degree) - -model = get_active_model(Ω_act) -Vstd = FESpace(Ω_act,FiniteElements(PhysicalDomain(),model,lagrangian,Float64,order)) - -V = AgFEMSpace(Vstd,aggregates) -U = TrialFESpace(V) - -const γd = 10.0 - -a(u,v) = - ∫( ∇(v)⋅∇(u) ) * dΩ + - ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ - -l(v) = - ∫( v*f ) * dΩ + - ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ - -op = AffineFEOperator(a,l,U,V) -uh = solve(op) - -e = u - uh - -l2(u) = sqrt(sum( ∫( u*u )*dΩ )) -h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) - -el2 = l2(e) -eh1 = h1(e) -ul2 = l2(uh) -uh1 = h1(uh) - -colors = color_aggregates(aggregates,bgmodel) -writevtk(Ω_bg,"trian",celldata=["aggregate"=>aggregates,"color"=>colors],cellfields=["uh"=>uh]) -writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) -writevtk(Γ,"trian_G") -@test el2/ul2 < 1.e-8 -@test eh1/uh1 < 1.e-7 - -# end # module diff --git a/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl b/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl deleted file mode 100644 index c45c38d9..00000000 --- a/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl +++ /dev/null @@ -1,74 +0,0 @@ -module PoissonAgFEMTests - -using Gridap -using GridapEmbedded -using Test - -u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 -f(x) = -Δ(u)(x) -ud(x) = u(x) - -const R = 0.55 -geom = disk(R,x0=Point(0.5,0.5)) - -n = 31 -partition = (n,n) -domain = (0,1,0,1) -bgmodel = CartesianDiscreteModel(domain,partition;isperiodic=(true,true)) -dp = 1 -const h = dp/n - -cutgeo = cut(bgmodel,geom) - -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -Ω_bg = Triangulation(bgmodel) -Ω_act = Triangulation(cutgeo,ACTIVE) -Ω = Triangulation(cutgeo,PHYSICAL) -Γ = EmbeddedBoundary(cutgeo) - -n_Γ = get_normal_vector(Γ) - -order = 2 -degree = 2*order -dΩ = Measure(Ω,degree) -dΓ = Measure(Γ,degree) - -model = get_active_model(Ω_act) -Vstd = FESpace(Ω_act,FiniteElements(PhysicalDomain(),model,lagrangian,Float64,order)) - -V = AgFEMSpace(Vstd,aggregates) -U = TrialFESpace(V) - -const γd = 10.0 - -a(u,v) = - ∫( ∇(v)⋅∇(u) ) * dΩ + - ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ - -l(v) = - ∫( v*f ) * dΩ + - ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ - -op = AffineFEOperator(a,l,U,V) -uh = solve(op) - -e = u - uh - -l2(u) = sqrt(sum( ∫( u*u )*dΩ )) -h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) - -el2 = l2(e) -eh1 = h1(e) -ul2 = l2(uh) -uh1 = h1(uh) - -#colors = color_aggregates(aggregates,bgmodel) -#writevtk(Ω_bg,"trian",celldata=["aggregate"=>aggregates,"color"=>colors],cellfields=["uh"=>uh]) -#writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) -#writevtk(Γ,"trian_G") -@test el2/ul2 < 1.e-8 -@test eh1/uh1 < 1.e-7 - -end # module From de2d2bbe87ce6399fc5fc306284449bf9a6a6026 Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Thu, 20 Jun 2024 12:03:54 +1000 Subject: [PATCH 011/120] tests passing --- src/Distributed/Distributed.jl | 1 + .../DistributedDiscreteGeometries.jl | 6 +- ...istributedLSDiscreteGeometryPoissonTest.jl | 110 ++++++++++++++++++ test/DistributedTests/mpi/runtests_body.jl | 5 + ...istributedLSDiscreteGeometryPoissonTest.jl | 7 ++ test/DistributedTests/sequential/runtests.jl | 1 + .../DiscreteGeometriesTests.jl | 12 ++ 7 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl create mode 100644 test/DistributedTests/sequential/DistributedLSDiscreteGeometryPoissonTest.jl diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index 3c845702..dec113c3 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -26,6 +26,7 @@ using GridapEmbedded.AgFEM: AggregateCutCellsByThreshold using GridapEmbedded.MomentFittedQuadratures: MomentFitted using Gridap.Geometry: AppendedTriangulation using Gridap.Geometry: get_face_to_parent_face +using Gridap.Arrays: find_inverse_index_map using GridapDistributed: DistributedDiscreteModel using GridapDistributed: DistributedTriangulation using GridapDistributed: DistributedFESpace diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index 2ea37887..c8a949ee 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -10,9 +10,9 @@ function _get_values_at_owned_coords(φh,model::DistributedDiscreteModel{Dc,Dp}) values = map(local_views(φh),local_views(model),local_views(gids)) do φh, model, gids # Maps from the no-ghost model to the original model own_model = remove_ghost_cells(model,gids) - own_to_local_node = Geometry.get_face_to_parent_face(own_model,0) - local_to_own_node = Arrays.find_inverse_index_map(own_to_local_node,num_nodes(model)) - own_to_local_cell = Geometry.get_face_to_parent_face(own_model,Dc) + own_to_local_node = get_face_to_parent_face(own_model,0) + local_to_own_node = find_inverse_index_map(own_to_local_node,num_nodes(model)) + own_to_local_cell = get_face_to_parent_face(own_model,Dc) # Cell-to-node map for the original model # topo = get_grid_topology(model) diff --git a/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..68bbf39f --- /dev/null +++ b/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl @@ -0,0 +1,110 @@ +module DistributedLSDiscreteGeometryPoissonTest + +using Gridap +using GridapEmbedded +using GridapDistributed +using PartitionedArrays +using Test + +using GridapEmbedded.CSG +using GridapEmbedded.LevelSetCutters + +function main(distribute,parts; + threshold=1, + n=21, + cells=(n,n)) + + order = 2 + ranks = distribute(LinearIndices((prod(parts),))) + domain = (0,1,0,1) + bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells) + + u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 + f(x) = -Δ(u)(x) + ud(x) = u(x) + + reffe = ReferenceFE(lagrangian,Float64,order) + Ω_bg = Triangulation(bgmodel) + V_bg = FESpace(Ω_bg,reffe) + φh = interpolate(x->sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.35,V_bg) + geo = DiscreteGeometry(φh,bgmodel) + + D = 2 + cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) + meas = map(first,cell_meas) |> PartitionedArrays.getany + h = meas^(1/D) + + cutgeo = cut(bgmodel,geo) + cutgeo_facets = cut_facets(bgmodel,geo) + + strategy = AggregateCutCellsByThreshold(threshold) + bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) + + Ω_act = Triangulation(cutgeo,ACTIVE) + Ω = Triangulation(cutgeo,PHYSICAL) + Γ = EmbeddedBoundary(cutgeo) + + n_Γ = get_normal_vector(Γ) + + order = 2 + degree = 2*order + dΩ = Measure(Ω,degree) + dΓ = Measure(Γ,degree) + + Vstd = FESpace(Ω_act,reffe) + V = AgFEMSpace(bgmodel,Vstd,aggregates) + U = TrialFESpace(V) + + γd = 10.0 + + a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + + l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + + op = AffineFEOperator(a,l,U,V) + uh = solve(op) + + e = u - uh + + l2(u) = sqrt(sum( ∫( u*u )*dΩ )) + h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + + el2 = l2(e) + eh1 = h1(e) + ul2 = l2(uh) + uh1 = h1(uh) + + # + colors = map(color_aggregates,aggregates,local_views(bgmodel)) + gids = get_cell_gids(bgmodel) + + + global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid + map(i-> i==0 ? 0 : gid[i],agg) + end + own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid + map(Reindex(agg),oid) + end + own_colors = map(colors,own_to_local(gids)) do col,oid + map(Reindex(col),oid) + end + + writevtk(Ω_bg,"trian", + celldata=[ + "aggregate"=>own_aggregates, + "color"=>own_colors, + "gid"=>own_to_global(gids)])#, + # cellfields=["uh"=>uh]) + + writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) + writevtk(Γ,"trian_G") + @test el2/ul2 < 1.e-8 + @test eh1/uh1 < 1.e-7 + +end + +end # module \ No newline at end of file diff --git a/test/DistributedTests/mpi/runtests_body.jl b/test/DistributedTests/mpi/runtests_body.jl index 7c44d8bc..048144f9 100644 --- a/test/DistributedTests/mpi/runtests_body.jl +++ b/test/DistributedTests/mpi/runtests_body.jl @@ -7,6 +7,7 @@ using MPI include("../PoissonTests.jl") include("../AggregatesTests.jl") include("../DistributedDiscreteGeometryPoissonTest.jl") +include("../DistributedLSDiscreteGeometryPoissonTest.jl") if ! MPI.Initialized() MPI.Init() @@ -27,6 +28,10 @@ function all_tests(distribute,parts) DistributedDiscreteGeometryPoissonTest.main(distribute,(prod(parts),1),cells=(12,12),geometry=:remotes) PArrays.toc!(t,"DistributedDiscreteGeometryPoisson") + PArrays.tic!(t) + DistributedLSDiscreteGeometryPoissonTest.main(distribute,parts,cells=(21,21)) + PArrays.toc!(t,"DistributedLSDiscreteGeometryPoissonTest") + if prod(parts) == 4 DistributedAggregatesTests.main(distribute,parts) end diff --git a/test/DistributedTests/sequential/DistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/DistributedLSDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..afdba273 --- /dev/null +++ b/test/DistributedTests/sequential/DistributedLSDiscreteGeometryPoissonTest.jl @@ -0,0 +1,7 @@ +module DistributedLSDiscreteGeometryPoissonTestsSeq +using PartitionedArrays +include("../DistributedLSDiscreteGeometryPoissonTest.jl") +with_debug() do distribute + DistributedLSDiscreteGeometryPoissonTest.main(distribute,(2,2),cells=(21,21)) +end +end diff --git a/test/DistributedTests/sequential/runtests.jl b/test/DistributedTests/sequential/runtests.jl index bf7521b2..0e8f21fe 100644 --- a/test/DistributedTests/sequential/runtests.jl +++ b/test/DistributedTests/sequential/runtests.jl @@ -4,5 +4,6 @@ using Test @time @testset "PoissonSeq" begin include("PoissonTests.jl") end @time @testset "DiscreteGeoPoissonSeq" begin include("DistributedDiscreteGeometryPoissonTest.jl") end +@time @testset "LSDiscreteGeoPoissonSeq" begin include("DistributedLSDiscreteGeometryPoissonTest.jl") end end diff --git a/test/LevelSetCuttersTests/DiscreteGeometriesTests.jl b/test/LevelSetCuttersTests/DiscreteGeometriesTests.jl index 5a7479e3..f246c2e0 100644 --- a/test/LevelSetCuttersTests/DiscreteGeometriesTests.jl +++ b/test/LevelSetCuttersTests/DiscreteGeometriesTests.jl @@ -38,4 +38,16 @@ test_geometry(geo4_y) #print_tree(stdout,get_tree(geo4_x)) #print_tree(stdout,replace_data(d->objectid(first(d)),get_tree(geo4_x))) +#using a cellfield +domain = (0,1,0,1) +n = 10 +bgmodel = CartesianDiscreteModel(domain,(n,n)) + +reffe = ReferenceFE(lagrangian,Float64,1) +Ω_bg = Triangulation(bgmodel) +V_bg = FESpace(Ω_bg,reffe) +φh = interpolate(x->sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.55,V_bg) +geo = DiscreteGeometry(φh,bgmodel) +test_geometry(geo) + end # module From c9da43dedc9981cfdbe5fed169db517f9d8ec37b Mon Sep 17 00:00:00 2001 From: "Z J Wegert (Workstation)" Date: Thu, 20 Jun 2024 14:24:36 +1000 Subject: [PATCH 012/120] Added periodic tests --- ...cDistributedDiscreteGeometryPoissonTest.jl | 193 ++++++++++++++++++ test/DistributedTests/mpi/runtests_body.jl | 7 + ...cDistributedDiscreteGeometryPoissonTest.jl | 8 + test/DistributedTests/sequential/runtests.jl | 3 + .../PeriodicPoissonAgFEMTests.jl | 111 ++++++++++ test/GridapEmbeddedTests/runtests.jl | 2 - 6 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl create mode 100644 test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl create mode 100644 test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl diff --git a/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..26cde8c3 --- /dev/null +++ b/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl @@ -0,0 +1,193 @@ +module PeriodicDistributedDiscreteGeometryPoissonTest + +using Gridap +using GridapEmbedded +using GridapDistributed +using PartitionedArrays +using Test + +using GridapDistributed: DistributedDiscreteModel + +using Gridap.Geometry +using Gridap.Geometry: get_vertex_coordinates,get_faces + +using GridapEmbedded.CSG +using GridapEmbedded.LevelSetCutters + +function update_labels!(e::Integer,model::DistributedDiscreteModel,f_Γ::Function,name::String) + mask = mark_nodes(f_Γ,model) + cell_to_entity = map(local_views(model),local_views(mask)) do model,mask + _update_labels_locally!(e,model,mask,name) + end + cell_gids=get_cell_gids(model) + cache=GridapDistributed.fetch_vector_ghost_values_cache(cell_to_entity,partition(cell_gids)) + GridapDistributed.fetch_vector_ghost_values!(cell_to_entity,cache) + nothing +end + +function _update_labels_locally!(e,model::CartesianDiscreteModel{2},mask,name) + topo = get_grid_topology(model) + labels = get_face_labeling(model) + cell_to_entity = labels.d_to_dface_to_entity[end] + entity = maximum(cell_to_entity) + e + # Vertices + vtxs_Γ = findall(mask) + vtx_edge_connectivity = Array(get_faces(topo,0,1)[vtxs_Γ]) + # Edges + edge_entries = [findall(x->any(x .∈ vtx_edge_connectivity[1:end.!=j]), + vtx_edge_connectivity[j]) for j = 1:length(vtx_edge_connectivity)] + edge_Γ = unique(reduce(vcat,getindex.(vtx_edge_connectivity,edge_entries),init=[])) + labels.d_to_dface_to_entity[1][vtxs_Γ] .= entity + labels.d_to_dface_to_entity[2][edge_Γ] .= entity + add_tag!(labels,name,[entity]) + return cell_to_entity +end + +function mark_nodes(f,model::DistributedDiscreteModel) + local_masks = map(local_views(model)) do model + mark_nodes(f,model) + end + gids = get_face_gids(model,0) + mask = PVector(local_masks,partition(gids)) + assemble!(|,mask) |> fetch # Ghosts -> Owned with `or` applied + consistent!(mask) |> fetch # Owned -> Ghost + return mask +end + +function mark_nodes(f,model::DiscreteModel) + topo = get_grid_topology(model) + coords = get_vertex_coordinates(topo) + mask = map(f,coords) + return mask +end + +function main(distribute,parts; + threshold=1, + n=8, + cells=(n,n), + geometry=:circle) + + ranks = distribute(LinearIndices((prod(parts),))) + + u(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 + f(x) = -Δ(u)(x) + ud(x) = u(x) + + geometries = Dict( + :circle => circle_geometry, + :remotes => remotes_geometry, + ) + + bgmodel,_geo = geometries[geometry](ranks,parts,cells) + update_labels!(1,bgmodel,x->iszero(x[1]) || iszero(x[2]),"outer_boundary") + + geo = discretize(_geo,bgmodel) + + D = 2 + cell_meas = map(get_cell_measure∘Triangulation,local_views(bgmodel)) + meas = map(first,cell_meas) |> PartitionedArrays.getany + h = meas^(1/D) + + cutgeo = cut(bgmodel,geo) + cutgeo_facets = cut_facets(bgmodel,geo) + + strategy = AggregateCutCellsByThreshold(threshold) + bgmodel,cutgeo,aggregates = aggregate(strategy,cutgeo) + + Ω_bg = Triangulation(bgmodel) + Ω_act = Triangulation(cutgeo,ACTIVE) + Ω = Triangulation(cutgeo,PHYSICAL) + Γ = EmbeddedBoundary(cutgeo) + + n_Γ = get_normal_vector(Γ) + + order = 2 + degree = 2*order + dΩ = Measure(Ω,degree) + dΓ = Measure(Γ,degree) + + reffe = ReferenceFE(lagrangian,Float64,order) + + Vstd = FESpace(Ω_act,reffe;dirichlet_tags="outer_boundary") + + V = AgFEMSpace(bgmodel,Vstd,aggregates) + U = TrialFESpace(V,ud) + + γd = 10.0 + + a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + + l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + + op = AffineFEOperator(a,l,U,V) + uh = solve(op) + + e = u - uh + + l2(u) = sqrt(sum( ∫( u*u )*dΩ )) + h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + + el2 = l2(e) + eh1 = h1(e) + ul2 = l2(uh) + uh1 = h1(uh) + + # + colors = map(color_aggregates,aggregates,local_views(bgmodel)) + gids = get_cell_gids(bgmodel) + + + global_aggregates = map(aggregates,local_to_global(gids)) do agg,gid + map(i-> i==0 ? 0 : gid[i],agg) + end + own_aggregates = map(global_aggregates,own_to_local(gids)) do agg,oid + map(Reindex(agg),oid) + end + own_colors = map(colors,own_to_local(gids)) do col,oid + map(Reindex(col),oid) + end + + writevtk(Ω_bg,"trian", + celldata=[ + "aggregate"=>own_aggregates, + "color"=>own_colors, + "gid"=>own_to_global(gids)])#, + # cellfields=["uh"=>uh]) + + writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) + writevtk(Γ,"trian_G") + @test el2/ul2 < 1.e-8 + @test eh1/uh1 < 1.e-7 + +end + +function circle_geometry(ranks,parts,cells) + p0 = Point(0.5,0.5) + R = 0.55 + geo = disk(R,x0=p0) + bgmodel = CartesianDiscreteModel(ranks,parts,(0,1,0,1),cells;isperiodic=(true,true)) + bgmodel,geo +end + +function remotes_geometry(ranks,parts,cells) + x0 = Point(0.0,0.4) + d1 = VectorValue(1.0,0.0) + d2 = VectorValue(0.0,0.2) + geo1 = quadrilateral(;x0=x0,d1=d1,d2=d2) + + x0 = Point(0.4,0.0) + d1 = VectorValue(0.2,0.0) + d2 = VectorValue(0.0,1.0) + geo2 = quadrilateral(;x0=x0,d1=d1,d2=d2) + geo = union(geo1,geo2) + + domain = (0, 1, 0, 1) + bgmodel = CartesianDiscreteModel(ranks,parts,domain,cells;isperiodic=(true,true)) + bgmodel,geo +end + +end # module \ No newline at end of file diff --git a/test/DistributedTests/mpi/runtests_body.jl b/test/DistributedTests/mpi/runtests_body.jl index 048144f9..d0510c01 100644 --- a/test/DistributedTests/mpi/runtests_body.jl +++ b/test/DistributedTests/mpi/runtests_body.jl @@ -8,6 +8,7 @@ include("../PoissonTests.jl") include("../AggregatesTests.jl") include("../DistributedDiscreteGeometryPoissonTest.jl") include("../DistributedLSDiscreteGeometryPoissonTest.jl") +include("../PeriodicDistributedDiscreteGeometryPoissonTest.jl") if ! MPI.Initialized() MPI.Init() @@ -32,6 +33,12 @@ function all_tests(distribute,parts) DistributedLSDiscreteGeometryPoissonTest.main(distribute,parts,cells=(21,21)) PArrays.toc!(t,"DistributedLSDiscreteGeometryPoissonTest") + ## Disabled due to Issue #87 + # PArrays.tic!(t) + # PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(4,4),cells=(31,31),geometry=:circle) + # PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(4,1),cells=(31,31),geometry=:remotes) + # PArrays.toc!(t,"PeriodicDistributedDiscreteGeometryPoisson") + if prod(parts) == 4 DistributedAggregatesTests.main(distribute,parts) end diff --git a/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 00000000..7802ba31 --- /dev/null +++ b/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl @@ -0,0 +1,8 @@ +module PeriodicDistributedDiscreteGeometryPoissonTest +using PartitionedArrays +include("../PeriodicDistributedDiscreteGeometryPoissonTest.jl") +with_debug() do distribute + PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(4,4),cells=(31,31),geometry=:circle) + PeriodicDistributedDiscreteGeometryPoissonTest.main(distribute,(4,1),cells=(31,31),geometry=:remotes) +end +end diff --git a/test/DistributedTests/sequential/runtests.jl b/test/DistributedTests/sequential/runtests.jl index 0e8f21fe..57910a85 100644 --- a/test/DistributedTests/sequential/runtests.jl +++ b/test/DistributedTests/sequential/runtests.jl @@ -6,4 +6,7 @@ using Test @time @testset "DiscreteGeoPoissonSeq" begin include("DistributedDiscreteGeometryPoissonTest.jl") end @time @testset "LSDiscreteGeoPoissonSeq" begin include("DistributedLSDiscreteGeometryPoissonTest.jl") end +## Disabled due to Issue #87 +# @time @testset "PeriodicDiscreteGeoPoissonSeq" begin include("PeriodicDistributedDiscreteGeometryPoissonTest.jl") end + end diff --git a/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl b/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl new file mode 100644 index 00000000..0ce321ef --- /dev/null +++ b/test/GridapEmbeddedTests/PeriodicPoissonAgFEMTests.jl @@ -0,0 +1,111 @@ +module PeriodicPoissonAgFEMTests + +using Gridap +using GridapEmbedded +using Test + +function update_labels!(e::Integer,model::CartesianDiscreteModel,f_Γ::Function,name::String) + mask = mark_nodes(f_Γ,model) + _update_labels_locally!(e,model,mask,name) + nothing +end + +function _update_labels_locally!(e,model::CartesianDiscreteModel{2},mask,name) + topo = Gridap.Geometry.get_grid_topology(model) + labels = Gridap.Geometry.get_face_labeling(model) + cell_to_entity = labels.d_to_dface_to_entity[end] + entity = maximum(cell_to_entity) + e + # Vertices + vtxs_Γ = findall(mask) + vtx_edge_connectivity = Array(Gridap.Geometry.get_faces(topo,0,1)[vtxs_Γ]) + # Edges + edge_entries = [findall(x->any(x .∈ vtx_edge_connectivity[1:end.!=j]), + vtx_edge_connectivity[j]) for j = 1:length(vtx_edge_connectivity)] + edge_Γ = unique(reduce(vcat,getindex.(vtx_edge_connectivity,edge_entries),init=[])) + labels.d_to_dface_to_entity[1][vtxs_Γ] .= entity + labels.d_to_dface_to_entity[2][edge_Γ] .= entity + add_tag!(labels,name,[entity]) + return cell_to_entity +end + +function mark_nodes(f,model::DiscreteModel) + topo = Gridap.Geometry.get_grid_topology(model) + coords = Gridap.Geometry.get_vertex_coordinates(topo) + mask = map(f,coords) + return mask +end + +u(x) = (x[1]-0.5)^2 + 2(x[2]-0.5)^2 +f(x) = -Δ(u)(x) +ud(x) = u(x) + +# R = 0.3 +# geo1 = square(;L=2) +# geo2 = disk(R,x0=Point(0.5,0.5)) + +geom = disk(0.55,x0=Point(0.5,0.5)) +# geom = setdiff(geo1,geo2) + +n = 31 +partition = (n,n) +domain = (0,1,0,1) +bgmodel = CartesianDiscreteModel(domain,partition;isperiodic=(true,true)) +update_labels!(1,bgmodel,x->iszero(x[1]) || iszero(x[2]),"outer_boundary") + +dp = 1 +const h = dp/n + +cutgeo = cut(bgmodel,geom) + +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +Ω_bg = Triangulation(bgmodel) +Ω_act = Triangulation(cutgeo,ACTIVE) +Ω = Triangulation(cutgeo,PHYSICAL) +Γ = EmbeddedBoundary(cutgeo) + +n_Γ = get_normal_vector(Γ) + +order = 2 +degree = 2*order +dΩ = Measure(Ω,degree) +dΓ = Measure(Γ,degree) + +model = get_active_model(Ω_act) +Vstd = FESpace(Ω_act,FiniteElements(PhysicalDomain(),model,lagrangian,Float64,order);dirichlet_tags="outer_boundary") + +V = AgFEMSpace(Vstd,aggregates) +U = TrialFESpace(V,ud) + +const γd = 10.0 + +a(u,v) = + ∫( ∇(v)⋅∇(u) ) * dΩ + + ∫( (γd/h)*v*u - v*(n_Γ⋅∇(u)) - (n_Γ⋅∇(v))*u ) * dΓ + +l(v) = + ∫( v*f ) * dΩ + + ∫( (γd/h)*v*ud - (n_Γ⋅∇(v))*ud ) * dΓ + +op = AffineFEOperator(a,l,U,V) +uh = solve(op) + +e = u - uh + +l2(u) = sqrt(sum( ∫( u*u )*dΩ )) +h1(u) = sqrt(sum( ∫( u*u + ∇(u)⋅∇(u) )*dΩ )) + +el2 = l2(e) +eh1 = h1(e) +ul2 = l2(uh) +uh1 = h1(uh) + +#colors = color_aggregates(aggregates,bgmodel) +#writevtk(Ω_bg,"trian",celldata=["aggregate"=>aggregates,"color"=>colors],cellfields=["uh"=>uh]) +# writevtk(Ω,"trian_O",cellfields=["uh"=>uh,"u"=>u]) +# writevtk(Γ,"trian_G") +@test el2/ul2 < 1.e-8 +@test eh1/uh1 < 1.e-7 + +end # module diff --git a/test/GridapEmbeddedTests/runtests.jl b/test/GridapEmbeddedTests/runtests.jl index a7e3d787..f6d52df3 100644 --- a/test/GridapEmbeddedTests/runtests.jl +++ b/test/GridapEmbeddedTests/runtests.jl @@ -8,8 +8,6 @@ using Test @time @testset "PeriodicPoissonAgFEM" begin include("PeriodicPoissonAgFEMTests.jl") end -@time @testset "PeriodicDiscreteGeoPoissonAgFEM" begin include("PeriodicDiscreteGeoPoissonAgFEMTests.jl") end - @time @testset "PoissonModalC0AgFEM" begin include("PoissonModalC0AgFEMTests.jl") end @time @testset "BimaterialPoissonCutFEM" begin include("BimaterialPoissonCutFEMTests.jl") end From ef1fc9ab14d48328703872901ceb5dc060547de8 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 21 Jun 2024 10:51:28 +1000 Subject: [PATCH 013/120] Allow propagation of dual numbers in _get_value_... --- src/Distributed/DistributedDiscreteGeometries.jl | 3 +-- src/LevelSetCutters/DiscreteGeometries.jl | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index c8a949ee..53463289 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -24,8 +24,7 @@ function _get_values_at_owned_coords(φh,model::DistributedDiscreteModel{Dc,Dp}) cell_node_coords = lazy_map(get_node_coordinates,cell_reffe) φh_data = CellData.get_data(φh) - space = FESpaces.get_fe_space(φh) - T = get_dof_value_type(space) + T = typeof(first(φh_data)(first(first(cell_node_coords)))) values = Vector{T}(undef,num_nodes(own_model)) touched = fill(false,num_nodes(model)) diff --git a/src/LevelSetCutters/DiscreteGeometries.jl b/src/LevelSetCutters/DiscreteGeometries.jl index 3eb9705d..15824e88 100644 --- a/src/LevelSetCutters/DiscreteGeometries.jl +++ b/src/LevelSetCutters/DiscreteGeometries.jl @@ -76,8 +76,7 @@ function _get_value_at_coords(φh::CellField,model::DiscreteModel{Dc,Dp}) where # Get cell data φh_data = CellData.get_data(φh) - space = FESpaces.get_fe_space(φh) - T = get_dof_value_type(space) + T = typeof(first(φh_data)(first(first(cell_node_coords)))) # Allow propogation of dual numbers values = Vector{T}(undef,num_nodes(model)) cell_node_coords_cache = array_cache(cell_node_coords) # Loop over cells From 0fcedea8b1993caf00f381d9379502e56f4dbf9e Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Fri, 21 Jun 2024 11:44:10 +1000 Subject: [PATCH 014/120] Adjust to use Gridap.Arrays API --- src/Distributed/Distributed.jl | 2 +- src/Distributed/DistributedDiscreteGeometries.jl | 2 +- src/LevelSetCutters/DiscreteGeometries.jl | 2 +- src/LevelSetCutters/LevelSetCutters.jl | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index dec113c3..71d34cdd 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -26,7 +26,7 @@ using GridapEmbedded.AgFEM: AggregateCutCellsByThreshold using GridapEmbedded.MomentFittedQuadratures: MomentFitted using Gridap.Geometry: AppendedTriangulation using Gridap.Geometry: get_face_to_parent_face -using Gridap.Arrays: find_inverse_index_map +using Gridap.Arrays: find_inverse_index_map, testitem, return_type using GridapDistributed: DistributedDiscreteModel using GridapDistributed: DistributedTriangulation using GridapDistributed: DistributedFESpace diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index 53463289..935e3b90 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -24,7 +24,7 @@ function _get_values_at_owned_coords(φh,model::DistributedDiscreteModel{Dc,Dp}) cell_node_coords = lazy_map(get_node_coordinates,cell_reffe) φh_data = CellData.get_data(φh) - T = typeof(first(φh_data)(first(first(cell_node_coords)))) + T = return_type(testitem(CellData.get_data(φh)),testitem(testitem(cell_node_coords))) values = Vector{T}(undef,num_nodes(own_model)) touched = fill(false,num_nodes(model)) diff --git a/src/LevelSetCutters/DiscreteGeometries.jl b/src/LevelSetCutters/DiscreteGeometries.jl index 15824e88..23d8cbe4 100644 --- a/src/LevelSetCutters/DiscreteGeometries.jl +++ b/src/LevelSetCutters/DiscreteGeometries.jl @@ -76,7 +76,7 @@ function _get_value_at_coords(φh::CellField,model::DiscreteModel{Dc,Dp}) where # Get cell data φh_data = CellData.get_data(φh) - T = typeof(first(φh_data)(first(first(cell_node_coords)))) # Allow propogation of dual numbers + T = return_type(testitem(CellData.get_data(φh)),testitem(testitem(cell_node_coords))) values = Vector{T}(undef,num_nodes(model)) cell_node_coords_cache = array_cache(cell_node_coords) # Loop over cells diff --git a/src/LevelSetCutters/LevelSetCutters.jl b/src/LevelSetCutters/LevelSetCutters.jl index 75296ea1..ac7caf57 100644 --- a/src/LevelSetCutters/LevelSetCutters.jl +++ b/src/LevelSetCutters/LevelSetCutters.jl @@ -22,6 +22,7 @@ using MiniQhull using Gridap.TensorValues using Gridap.ReferenceFEs using Gridap.Arrays +using Gridap.Arrays: testitem, return_type using Gridap.Fields using Gridap.Helpers using Gridap.Geometry From 969d173d426dceaac7c079bc245bddbaa6a83599 Mon Sep 17 00:00:00 2001 From: Eric Neiva Date: Fri, 18 Oct 2024 07:46:32 +0200 Subject: [PATCH 015/120] Bump new Algoim version --- Project.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Project.toml b/Project.toml index 5ccc3783..2df29281 100644 --- a/Project.toml +++ b/Project.toml @@ -22,9 +22,9 @@ algoimWrapper_jll = "3c43aa7b-5398-51f3-8d75-8f051e6faa4d" [compat] AbstractTrees = "0.3.3, 0.4" -Algoim = "0.2" +Algoim = "0.2.2" Combinatorics = "1" -CxxWrap = "0.14" +CxxWrap = "0.16" FillArrays = "0.10, 0.11, 0.12, 0.13, 1" Gridap = "0.17, 0.18" GridapDistributed = "0.3, 0.4" From d0b2a9341ab95c9a96a24856a6772abc95965904 Mon Sep 17 00:00:00 2001 From: Eric Neiva Date: Fri, 18 Oct 2024 07:48:39 +0200 Subject: [PATCH 016/120] Update NEWS.md --- NEWS.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 53030e64..875cf8d7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,12 +4,15 @@ 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). -## [Unreleased] +## [0.9.5] - 2024-10-18 ### Added - Adding `compute_redistribute_weights` and `compute_adaptive_flags` functions for load balancing and adaptive mesh refinement, respectively. Since PR [#95](https://github.com/gridap/GridapEmbedded.jl/pull/95). +### Changed + +- Updated to Algoim v0.2.2, which runs on Julia 1.11. Since PR [#96](https://github.com/gridap/GridapEmbedded.jl/pull/96). ## [0.9.4] - 2024-07-09 From 03e11c8ff091210c4f0b672538b42d8c5d40d64c Mon Sep 17 00:00:00 2001 From: Eric Neiva Date: Fri, 18 Oct 2024 07:49:36 +0200 Subject: [PATCH 017/120] New GE 0.9.5 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 2df29281..08903581 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GridapEmbedded" uuid = "8838a6a3-0006-4405-b874-385995508d5d" authors = ["Francesc Verdugo ", "Eric Neiva ", "Pere Antoni Martorell ", "Santiago Badia "] -version = "0.9.4" +version = "0.9.5" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" From ca1256a2cbebd70d25797b18bd344385c1a8dc0f Mon Sep 17 00:00:00 2001 From: Eric Neiva Date: Fri, 18 Oct 2024 07:51:37 +0200 Subject: [PATCH 018/120] Update NEWS.md [skip ci] --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 875cf8d7..bb65c903 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Updated to Algoim v0.2.2, which runs on Julia 1.11. Since PR [#96](https://github.com/gridap/GridapEmbedded.jl/pull/96). +- Updated to Algoim v0.2.2, which runs on Julia 1.11. Since PR [#97](https://github.com/gridap/GridapEmbedded.jl/pull/97). ## [0.9.4] - 2024-07-09 From b30581ed82b2dc5d1120836b912df4c969cdcf5e Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Thu, 7 Nov 2024 11:29:06 +1100 Subject: [PATCH 019/120] added (non-working) canvas for div stab term --- bulk_ghost_penalty_canvas_div.jl | 749 +++++++++++++++++++++++++++++++ 1 file changed, 749 insertions(+) create mode 100644 bulk_ghost_penalty_canvas_div.jl diff --git a/bulk_ghost_penalty_canvas_div.jl b/bulk_ghost_penalty_canvas_div.jl new file mode 100644 index 00000000..d796f031 --- /dev/null +++ b/bulk_ghost_penalty_canvas_div.jl @@ -0,0 +1,749 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 +# Select geometry +R = 0.2 +geom = disk(R, x0=Point(0.5,0.5)) + +# Setup background model +n=10 +partition = (n,n) +box = get_metadata(geom) +bgmodel = CartesianDiscreteModel((0,1,0,1),partition) +dp = box.pmax - box.pmin +h = dp[1]/n + +# Cut the background model with the mesh +cutdisk = cut(bgmodel,geom) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutdisk) + +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cells in the background + model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_aggregate_to_cells(aggregates) + + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]>1) + if !haskey(touched,agg) + push!(aggregate_to_cells,[i]) + touched[agg]=current_aggregate + current_aggregate+=1 + else + push!(aggregate_to_cells[touched[agg]],i) + end + end + end + end + aggregate_to_cells +end + +function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) + g=get_grid(bgmodel) + cell_coords=get_cell_coordinates(g) + D=num_dims(bgmodel) + xmin=Vector{Float64}(undef,D) + xmax=Vector{Float64}(undef,D) + + # Compute coordinates of the nodes defining the bounding boxes + bounding_box_node_coords= + Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) + ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] + data = collect(1:length(bounding_box_node_coords)) + bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) + for (agg,cells) in enumerate(aggregate_to_cells) + p=first(cell_coords[cells[1]]) + for i in 1:D + xmin[i]=p[i] + xmax[i]=p[i] + end + for cell in cells + for p in cell_coords[cell] + for i in 1:D + xmin[i]=min(xmin[i],p[i]) + xmax[i]=max(xmax[i],p[i]) + end + end + end + bounds = [(xmin[i], xmax[i]) for i in 1:D] + point_iterator = Iterators.product(bounds...) + bounding_box_node_coords[bounding_box_node_ids[agg]] = + reshape([Point(p...) for p in point_iterator],2^D) + end + + # Set up the discrete model of bounding boxes + HEX_AXIS=1 + polytope=Polytope(Fill(HEX_AXIS,D)...) + scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) + cell_types=fill(1,length(bounding_box_node_ids)) + cell_reffes=[scalar_reffe] + grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, + bounding_box_node_ids, + cell_reffes, + cell_types, + Gridap.Geometry.Oriented()) + Gridap.Geometry.UnstructuredDiscreteModel(grid) +end + +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# colors = color_aggregates(aggregates,bgmodel) +# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) +# writevtk(aggregates_bounding_box_model, "bb_model") +# writevtk(bgmodel, "bg_model") + +""" + Changes the domain of a trial/test basis defined on + the reference space of bounding boxes to the reference + space of the agg cells + + TO-DO: in the future, for system of PDEs (MultiField) we should + also take care of blocks (BlockMap) +""" +function change_domain_bb_to_agg_cells(basis_bb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) + @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() + bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) + bb_basis_array = Gridap.CellData.get_data(basis_bb) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Remove transpose map; we will add it later + @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) + @assert isa(bb_basis_array.maps,Fill) + @assert isa(bb_basis_array.maps.value,typeof(transpose)) + bb_basis_array=bb_basis_array.args[1] + end + + bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) + bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), + bb_basis_array_to_Ωagg_cells_array, + ref_agg_cell_to_ref_bb_map) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Add transpose + bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) + end + + Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, + Ωagg_cells, + ReferenceDomain()) +end + + +# Set up objects required to compute both LHS and RHS of the L2 projection + +# Set up global spaces +Ωhact = Triangulation(cutdisk,ACTIVE) + +V = FESpace(Ωhact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +Q = FESpace(Ωhact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +U = TrialFESpace(V) +P = TrialFESpace(Q) +Y = MultiFieldFESpace([V, Q]) +X = MultiFieldFESpace([U, P]) + +# Generate an array with the global IDs of the cells +# that belong to an aggregrate. From now on, we will +# use the terminology "agg_cells" to refer to those +# cells of the background model that belong to an aggregate +# (i.e., they can be either cut or interior cells) +agg_cells=Vector{Int}() +for cells in aggregate_to_cells + append!(agg_cells,cells) +end + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +Ω=Triangulation(bgmodel) +Ωagg_cells=view(Ω,agg_cells) +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) + +# Generate an array that given the local ID of an "agg_cell" +# returns the ID of the aggregate to which it belongs +# (i.e., flattened version of aggregate_to_cells) +agg_cells_to_aggregate=Vector{Int}() +for (i,cells) in enumerate(aggregate_to_cells) + for _ in cells + push!(agg_cells_to_aggregate,i) + end +end + +# ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} +bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) +bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) +ref_agg_cell_to_ref_bb_map= + lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) + +# Compute LHS of L2 projection +degree=2*(order+1) +dΩagg_cells = Measure(Ωagg_cells,degree) +reffe =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) + +reffe=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + + +aggregate_to_local_cells=copy(aggregate_to_cells) +current_local_cell=1 +for (i,cells) in enumerate(aggregate_to_local_cells) + for j in 1:length(cells) + cells[j]=current_local_cell + current_local_cell+=1 + end +end + +function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + ubb, + vbb) + Ωagg_cells=dΩagg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + # Change domain of ubb (trial) from Ωbb to Ωagg_cells + ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + # Compute contributions to LHS of L2 projection + agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) + + # Finally assemble LHS contributions + ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) + lazy_map(ass_lhs_map,aggregate_to_local_cells) +end + +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + ubb, + vbb) + +# Compute contributions to the RHS of the L2 projection +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) + map=cell_dof_ids.maps.value + @assert length(map.size)==1 + @assert blockid >= 1 + @assert blockid <= map.size[1] + cell_dof_ids.args[blockid] +end + +Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) +U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) +P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) +# Ωagg_cell_dof_ids[1][1] # cell 1, velo dof +# Ωagg_cell_dof_ids[1][2] # cell 1, pressure dofs + +### BEGIN TESTING CODE +# This code is just for testing purposes, so I have commented it out +# It allows to evaluate the LHS of the L2 projection corresponding to a +# particular FE function, instead of a basis +# uhex=interpolate(uex,Ustd) +# agg_cells_lhs_contribs_uhex=get_array(∫(vbb_Ωagg_cells*uhex)dΩagg_cells) +# ass_lhs_map_uhex=AssembleLhsMap(agg_cells_lhs_contribs_uhex) +# lhs_uhex=lazy_map(ass_lhs_map_uhex,aggregate_to_local_cells) +### END TESTING CODE + +function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + agg_cells_local_dof_ids=copy(agg_cells_dof_ids) + current_cell=1 + for agg_cells in aggregate_to_agg_cells + g2l=Dict{Int32,Int32}() + current_local_dof=1 + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in keys(g2l)) + g2l[dof]=current_local_dof + agg_cells_local_dof_ids[current_cell][j]=current_local_dof + current_local_dof+=1 + else + agg_cells_local_dof_ids[current_cell][j]=g2l[dof] + end + end + current_cell+=1 + println(agg_cells_local_dof_ids) + end + end + agg_cells_local_dof_ids +end + +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωagg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωagg_cell_dof_ids, aggregate_to_local_cells) + + +function set_up_h_U(aggregates_bounding_box_model, + agg_cells_to_aggregate, + Ωagg_cells) + degree = 0 # We are integrating a constant function + # Thus, degree=0 is enough for exact integration + Ωbb = Triangulation(aggregates_bounding_box_model) + dΩbb = Measure(Ωbb, degree) + h_U_array = get_array(∫(1.0)dΩbb) + h_U_array = lazy_map(Reindex(h_U_array), agg_cells_to_aggregate) + CellField(h_U_array, Ωagg_cells) +end + + +function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) + current_aggregate=1 + current_cell=1 + for agg_cells in aggregate_to_agg_cells + current_aggregate_dof_ids=Int[] + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in current_aggregate_dof_ids) + push!(current_aggregate_dof_ids, dof) + end + end + current_cell+=1 + end + aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids + current_aggregate+=1 + end + aggregate_dof_ids +end + +function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.single_field +end +function _get_single_field_fe_basis(a) + a +end +function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) + true +end +function _is_multifield_fe_basis_component(a) + false +end +function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.nfields +end +function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.fieldid +end + +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) + # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) +""" +function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωagg_cell_dof_ids, + agg_cells_local_dof_ids, + agg_cells_to_aggregate_dof_ids, + h_U, + γ) + + + Ωagg_cells=dΩagg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, + dΩagg_cells.quad.trian, + ReferenceDomain()) + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) + end + push!(w, dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, Ωagg_cell_dof_ids) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + + proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) + end + + push!(w, proj_dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, agg_cells_to_aggregate_dof_ids) + + w, r, c +end + +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) + +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +γ = 10.0 # Interior bulk-penalty stabilization parameter + # (@amartinhuertas no idea what a reasonable value is) + +h_U = set_up_h_U(aggregates_bounding_box_model, agg_cells_to_aggregate, Ωagg_cells) + +# Manually set up the arrays that collect_cell_matrix would return automatically +wp,rp,cp=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωagg_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + +wu,ru,cu=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωagg_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + +Ωcut = Triangulation(cutdisk,PHYSICAL) +dΩcut = Measure(Ωcut,degree) +# # Set up global projection matrix +# Ωcut = Triangulation(cutdisk,PHYSICAL) +# dΩcut = Measure(Ωcut,degree) +# a_nodiv((u,p),(v,q))=∫(v⋅u+q*p)dΩcut +# wrc_nodiv=Gridap.FESpaces.collect_cell_matrix(X,Y,a_nodiv(dx,dy)) + +# assem_nodiv=SparseMatrixAssembler(X,Y) +# Anostab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) +# cond(Array(Anostab_nodiv)) + +# # Add the bulk penalty stabilization term to wrc_nodiv +# push!(wrc_nodiv[1], wp...) +# push!(wrc_nodiv[2], rp...) +# push!(wrc_nodiv[3], cp...) + +# push!(wrc_nodiv[1], wu...) +# push!(wrc_nodiv[2], ru...) +# push!(wrc_nodiv[3], cu...) + +# Awithstab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) +# cond(Array(Awithstab_nodiv)) + +# # Set up rhs global projection +# l_nodiv((v,q))=∫(v⋅uex+q*pex)dΩcut +# b_nodiv = assemble_vector(l_nodiv, Y) + +# global_l2_proj_dofs_nodiv = Awithstab_nodiv\b_nodiv +# xh_nodiv = FEFunction(X, global_l2_proj_dofs_nodiv) +# uh_nodiv,ph_nodiv = xh_nodiv + +# euh_nodiv = uex-uh_nodiv +# # @assert sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) < 1.0e-12 + +# eph_nodiv = pex-ph_nodiv +# # @assert sum(∫(eph_nodiv*eph_nodiv)*dΩcut) < 1.0e-12 +# eph_nodiv_norm = sum(∫(eph_nodiv*eph_nodiv)*dΩcut) +# euh_nodiv_norm = sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) +# # k=0 yields eph = 0.00012 and euh = 5.5e-30 +# edivuh_nodiv = divuex-(∇⋅uh_nodiv) +# edivuh_nodiv_norm = sum(∫(edivuh_nodiv⋅edivuh_nodiv)*dΩcut) + +## TEST 1 +a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩcut +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) + +assem=SparseMatrixAssembler(X,Y) +Anostab=assemble_matrix(assem, wrc) +cond_nostab = cond(Array(Anostab)) + +# Set up rhs global projection +l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩcut +b = assemble_vector(l, Y) + +## NO STABILIZATION +if cond_nostab<1e35 + global_l2_proj_dofs_nostab = Anostab\b + xh_nostab = FEFunction(X, global_l2_proj_dofs_nostab) + uh_nostab,ph_nostab = xh_nostab + euh_nostab = uex-uh_nostab + eph_nostab = pex-ph_nostab + edivuh_nostab = divuex-(∇⋅uh_nostab) + norm_euh_nostab = sum(∫(euh_nostab⋅euh_nostab)*dΩcut) + norm_eph_nostab = sum(∫(eph_nostab*eph_nostab)*dΩcut) + edivuh_nostab = sum(∫(edivuh_nostab⋅edivuh_nostab)*dΩcut) +else + println("Singular exception is raised as error when solving the system (as cond= $cond_nostab is high?)") +end +# k=0 yields euh = 1.2e-32, eph = 0.00017, edivuh = 6.8e-30, κ= 3.15e32 +# k=0 yields euh = ?, eph = ?, edivuh = ?, κ= 4.3e36 + +## U + P STABILIZATION +# Add the bulk penalty stabilization terms for u and p to wrc +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) + +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) + +# Check the condition number when only the p and u stabilization terms are included. +Aupstab=assemble_matrix(assem, wrc) +cond_upstab = cond(Array(Aupstab)) + +# CHECK errors when only the p and u stabilization terms are included. +global_l2_proj_dofs_upstab = Aupstab\b +xh_upstab = FEFunction(X, global_l2_proj_dofs_upstab) +uh_upstab,ph_upstab = xh_upstab +euh_upstab = uex-uh_upstab +eph_upstab = pex-ph_upstab +edivuh_upstab = divuex-(∇⋅uh_upstab) +norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩcut) +norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩcut) +norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩcut) +# k=0 yields euh = 6.3e-31, eph = 0.00055, edivuh = 2.4e-28, κ= 11492 +# k=2 yields euh = 5.3e-22, eph = 3.0e-18, edivuh = 3.0e-18, κ= 1.7e11 + +## +DIVU STABILIZATION +## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) +# Manually set up the arrays that collect_cell_matrix would return automatically +w_divu = [] +r_divu = [] +c_divu = [] + +## (I) Let's set up the div_dv_div_du_mat_contribs (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells +div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) +U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) +if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) +end + +push!(w_divu, div_dv_div_du_mat_contribs) +push!(r_divu, U_Ωagg_cell_dof_ids) +push!(c_divu, U_Ωagg_cell_dof_ids) + +## Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩ_agg_cells +div_dv=∇⋅(_get_single_field_fe_basis(dv)) +pdofs=Gridap.FESpaces.get_fe_dof_basis(P) +div_dv_pdofs_values=pdofs(div_dv) +div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, + div_dv_pdofs_values, + Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) +div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, + get_triangulation(P), + Gridap.FESpaces.TestBasis(), + Gridap.CellData.ReferenceDomain()) +div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) + +div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) +div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, + get_triangulation(P), + Gridap.FESpaces.TrialBasis(), + Gridap.CellData.ReferenceDomain()) +div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) + +div_dv_div_du_in_pressure_space_mat_contribs=get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? +div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs + +### Compute Π_Q_bb(div_du) +dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) +agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) +# agg_cells_rhs_contribs[1] +ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) +rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) +div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + +# Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate +div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + div_dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(qbb)) + +div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + +div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + +if (_is_multifield_fe_basis_component(dp)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + div_du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + div_du_l2_proj_bb_array_agg_cells) +end + +div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) + +# In the MultiField case, I have had to add this change domain +# call before setting up the term right below. Otherwise, we get an error +# when trying to multiply the fields. Not sure why this is happening +# dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) +div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) + +proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) + +P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_agg_cells_to_aggregate_dof_ids) +end + +push!(w_divu, proj_div_dv_div_du_mat_contribs) +push!(r_divu, U_Ωagg_cell_dof_ids) # test +push!(c_divu, P_agg_cells_to_aggregate_dof_ids) # trial + +## Now add div stabilization to A +push!(wrc[1], w_divu...) +push!(wrc[2], r_divu...) +push!(wrc[3], c_divu...) + +# Assembly +Awithstab=assemble_matrix(assem, wrc) +cond_withstab = cond(Array(Awithstab)) + +global_l2_proj_dofs_withstab = Awithstab\b +xh_withstab = FEFunction(X, global_l2_proj_dofs_withstab) +uh_withstab,ph_withstab = xh_withstab +euh_withstab = uex-uh_withstab +eph_withstab = pex-ph_withstab +edivuh_withstab = divuex-(∇⋅uh_withstab) +norm_euh_withstab = sum(∫(euh_withstab⋅euh_withstab)*dΩcut) +norm_eph_withstab = sum(∫(eph_withstab*eph_withstab)*dΩcut) +norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) +# k=0 yields euh = 0.0014, eph = 0.47, edivuh = 0.47, κ= 8.51e11 +# k=2 yields euh = 0.00013, eph = 0.088, edivuh = 0.088, κ= 2.9e14 \ No newline at end of file From 5e4338edd0068aae34cb3746aee03fe09f894f2a Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 8 Nov 2024 13:34:02 +1100 Subject: [PATCH 020/120] extracted root cells --- bulk_ghost_penalty_canvas_u-only.jl | 910 ++++++++++++++++++++++++++++ 1 file changed, 910 insertions(+) create mode 100644 bulk_ghost_penalty_canvas_u-only.jl diff --git a/bulk_ghost_penalty_canvas_u-only.jl b/bulk_ghost_penalty_canvas_u-only.jl new file mode 100644 index 00000000..2a21a754 --- /dev/null +++ b/bulk_ghost_penalty_canvas_u-only.jl @@ -0,0 +1,910 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +divuex(x) = -4.0 + +# Select geometry +R = 0.2 +geom = disk(R, x0=Point(0.5,0.5)) + +# Setup background model +n=16 +partition = (n,n) +box = get_metadata(geom) +bgmodel = CartesianDiscreteModel((0,1,0,1),partition) +dp = box.pmax - box.pmin +h = dp[1]/n + +# Cut the background model with the mesh +cutgeo = cut(bgmodel,geom) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +#INVESTIGATING: Number of aggregates, cells and bg cells. +@assert length(aggregates) == n*n +num_cell = length(aggregates) +using StatsBase +counts = countmap(aggregates,alg=:dict) +agg_counts = filter(((k,v),) -> v > 1 && k != 0, counts) +num_aggregates = length(agg_counts) +num_cells_in_aggregates = 0 +for (k,v) in agg_counts + println(v) + num_cells_in_aggregates +=v +end +num_cells_not_in_aggregates = counts[0] +non_agg_counts = filter(((k,v),) -> v <= 1 || k==0, counts) +num_cells_not_in_aggregates = 0 +for (k,v) in non_agg_counts + println(v) + num_cells_not_in_aggregates +=v +end +num_ext_cells = counts[0] +@assert num_cells_in_aggregates + num_cells_not_in_aggregates == num_cell +println("Out of the $num_cell cells, $num_cells_in_aggregates belong to aggregates and $num_cells_not_in_aggregates are not part of aggregates. Note that we have $num_ext_cells exterior cells") +println("Assuming that there is one root per aggregate, we have $(num_cells_in_aggregates-num_aggregates) cut cells and $num_aggregates roots in the $num_aggregates aggregates cotntaining $num_cells_in_aggregates in total.") + +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cells in the background + model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_aggregate_to_cells(aggregates) + + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]>1) + if !haskey(touched,agg) + push!(aggregate_to_cells,[i]) + touched[agg]=current_aggregate + current_aggregate+=1 + else + push!(aggregate_to_cells[touched[agg]],i) + end + end + end + end + aggregate_to_cells +end + +""" + Creates an array of arrays with as many entries + as interior cells that are not part of any aggegrate. + For each interior cell, the array + contains the global cell IDs of that cells in the background + model that belong to the same interior cell + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_int_nonagg_cell_to_cells(aggregates) + + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + interior_cell_to_cells=Vector{Vector{Int}}() + current_interior_cell=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]==1) + if !haskey(touched,agg) + push!(interior_cell_to_cells,[i]) + touched[agg]=current_interior_cell + current_interior_cell+=1 + else + push!(interior_cell_to_cells[touched[agg]],i) + end + end + end + end + interior_cell_to_cells +end + + +function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) + g=get_grid(bgmodel) + cell_coords=get_cell_coordinates(g) + D=num_dims(bgmodel) + xmin=Vector{Float64}(undef,D) + xmax=Vector{Float64}(undef,D) + + # Compute coordinates of the nodes defining the bounding boxes + bounding_box_node_coords= + Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) + ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] + data = collect(1:length(bounding_box_node_coords)) + bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) + for (agg,cells) in enumerate(aggregate_to_cells) + p=first(cell_coords[cells[1]]) + for i in 1:D + xmin[i]=p[i] + xmax[i]=p[i] + end + for cell in cells + for p in cell_coords[cell] + for i in 1:D + xmin[i]=min(xmin[i],p[i]) + xmax[i]=max(xmax[i],p[i]) + end + end + end + bounds = [(xmin[i], xmax[i]) for i in 1:D] + point_iterator = Iterators.product(bounds...) + bounding_box_node_coords[bounding_box_node_ids[agg]] = + reshape([Point(p...) for p in point_iterator],2^D) + end + + # Set up the discrete model of bounding boxes + HEX_AXIS=1 + polytope=Polytope(Fill(HEX_AXIS,D)...) + scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) + cell_types=fill(1,length(bounding_box_node_ids)) + cell_reffes=[scalar_reffe] + grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, + bounding_box_node_ids, + cell_reffes, + cell_types, + Gridap.Geometry.Oriented()) + Gridap.Geometry.UnstructuredDiscreteModel(grid) +end + +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# colors = color_aggregates(aggregates,bgmodel) +# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) +# writevtk(aggregates_bounding_box_model, "bb_model") +# writevtk(bgmodel, "bg_model") + +""" + Changes the domain of a trial/test basis defined on + the reference space of bounding boxes to the reference + space of the agg cells + + TO-DO: in the future, for system of PDEs (MultiField) we should + also take care of blocks (BlockMap) +""" +function change_domain_bb_to_agg_cells(basis_bb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) + @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() + bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) + bb_basis_array = Gridap.CellData.get_data(basis_bb) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Remove transpose map; we will add it later + @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) + @assert isa(bb_basis_array.maps,Fill) + @assert isa(bb_basis_array.maps.value,typeof(transpose)) + bb_basis_array=bb_basis_array.args[1] + end + + bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) + bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), + bb_basis_array_to_Ωagg_cells_array, + ref_agg_cell_to_ref_bb_map) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Add transpose + bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) + end + + Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, + Ωagg_cells, + ReferenceDomain()) +end + +# Generate an array with the global IDs of the cells +# that belong to an aggregrate. From now on, we will +# use the terminology "agg_cells" to refer to those +# cells of the background model that belong to an aggregate +# (i.e., they can be either cut or interior cells) +agg_cells=Vector{Int}() +for cells in aggregate_to_cells + append!(agg_cells,cells) +end + +# Generate an array with the global IDs of the cells +# that belong to the interior, yet do not belong to the +# aggregate. We will use "int_nonagg_cells" to refer to those +# cells of the background model that belong to the interior +# but are not part of any of the aggregates. +int_nonagg_cells=Vector{Int}() +for cell in int_nonagg_cell_to_cells + append!(int_nonagg_cells,cell) +end + +#INSPECTION +# agg_cells +# int_nonagg_cells +# aggregates + +## Triangulation +Ωbg = Triangulation(bgmodel) +Ω = Triangulation(cutgeo,PHYSICAL) +Ωact = Triangulation(cutgeo,ACTIVE) +Ωcut = Triangulation(cutgeo) + +# Interior cells +Ωbg_agg_cells = view(Ωbg,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface +# construct the interior aggregate cells, in other words the root cells +root_cells=Vector{Int}() +tester_int_nonagg_cells=Vector{Int}() +for cell in int_cells + if cell ∈ int_nonagg_cells + append!(tester_int_nonagg_cells,cell) + else + append!(root_cells,cell) + end +end +@assert(tester_int_nonagg_cells==int_nonagg_cells) + +# TODO Potentially useful?: +# Ω_agg_cells.parent.a.subgrid.cell_node_ids.data == Ω.a.subgrid.cell_node_ids.data # vector containing cell ids + + +# Subdomains in background mesh (aggegrate cells are already defined) +Ωbg_int_cells = view(Ωbg,int_cells) # cells in interior +Ωbg_int_nonagg_cells = view(Ωbg,int_nonagg_cells) # cells in interior but not in aggregate +Ωbg_root_cells = view(Ωbg,root_cells) # root cells: in interior and part of aggregate + +# Subdomains in physical mesh +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +Ω_int_cells = view(Ω,int_cells) # cells in interior +Ω_int_nonagg_cells = view(Ω,int_nonagg_cells) # cells in interior but not in aggregate +Ω_root_cells = view(Ω,root_cells) # root cells: in interior and part of aggregate + +## VISUALISATION: +writevtk(Ωbg,"trian_bg") +writevtk(Ωbg_agg_cells,"trian_bg_agg_cells") +writevtk(Ωbg_int_cells,"trian_bg_int_cells") +writevtk(Ωbg_int_nonagg_cells,"trian_bg_int_nonagg_cells") +writevtk(Ωbg_root_cells,"trian_bg_root_cells") + +writevtk(Ωact,"trian_act") +writevtk(Ω,"trian_phys") +#TODO: WHY DOESN'T THIS WORK? +# writevtk(Ω_agg_cells,"trian_phys_agg_cells") +# writevtk(Ω_int_cells,"trian_phys_int_cells") +# writevtk(Ω_int_nonagg_cells,"trian_phys_int_nonagg_cells") +# writevtk(Ω_int_cells,"trian_phys_int_root_cells") + + +# Generate an array with the global IDs of the cells +# that belong to the cut cells (and are thus also part of an aggregate). From now on, we will +# use the terminology "cut_cells" to refer to those +# cells of the background model that belong to the cut domain +interior_cells=Vector{Int}() +for cell in true_interior_cells + if cell ∈ interior_cells + append!(interior_cells,cells) +end +bgmodel.grid_topology.vertex_coordinates + +Ω_agg_cells.parent.b.tface_to_mface #what is this (len =24) + + + +intcellstest = filter(!in[interior_cells], Ω_agg_cells.parent.b.tface_to_mface) + +dΩ = Measure(Ω,2*order*2) +dΩ_agg_cells = Measure(Ω_agg_cells,2*order*2) + + +colors = color_aggregates(aggregates,bgmodel) +unique(colors) +countmap(colors) + +cut_bgtrian = Triangulation(cut,CUT,cutgeo) + +# (Q1) WHEN WE DEFINE dΩagg_cells are we intergrating over the entire aggregate or only up to the physical part of it? That is, when we add the stabilization what do we intend to do? + +## Set up global spaces +Ωact = Triangulation(cutgeo,ACTIVE) +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +# Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +U = TrialFESpace(V) +# P = TrialFESpace(Q) +# Y = MultiFieldFESpace([V, Q]) +# X = MultiFieldFESpace([U, P]) + +## MAPS + + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) + +# Generate an array that given the local ID of an "agg_cell" +# returns the ID of the aggregate to which it belongs +# (i.e., flattened version of aggregate_to_cells) +agg_cells_to_aggregate=Vector{Int}() +for (i,cells) in enumerate(aggregate_to_cells) + for _ in cells + push!(agg_cells_to_aggregate,i) + end +end + +# ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} +bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) +bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) +ref_agg_cell_to_ref_bb_map= + lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) + +# Compute LHS of L2 projection +degree=2*(order+1) +dΩagg_cells = Measure(Ωagg_cells,degree) +reffe =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) + +reffe=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + + +aggregate_to_local_cells=copy(aggregate_to_cells) +current_local_cell=1 +for (i,cells) in enumerate(aggregate_to_local_cells) + for j in 1:length(cells) + cells[j]=current_local_cell + current_local_cell+=1 + end +end + +function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + ubb, + vbb) + Ωagg_cells=dΩagg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + # Change domain of ubb (trial) from Ωbb to Ωagg_cells + ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + # Compute contributions to LHS of L2 projection + agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) + + # Finally assemble LHS contributions + ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) + lazy_map(ass_lhs_map,aggregate_to_local_cells) +end + +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + ubb, + vbb) + +# Compute contributions to the RHS of the L2 projection +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) + map=cell_dof_ids.maps.value + @assert length(map.size)==1 + @assert blockid >= 1 + @assert blockid <= map.size[1] + cell_dof_ids.args[blockid] +end + +Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) +U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) +P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) +# Ωagg_cell_dof_ids[1][1] # cell 1, velo dof +# Ωagg_cell_dof_ids[1][2] # cell 1, pressure dofs + +### BEGIN TESTING CODE +# This code is just for testing purposes, so I have commented it out +# It allows to evaluate the LHS of the L2 projection corresponding to a +# particular FE function, instead of a basis +# uhex=interpolate(uex,Ustd) +# agg_cells_lhs_contribs_uhex=get_array(∫(vbb_Ωagg_cells*uhex)dΩagg_cells) +# ass_lhs_map_uhex=AssembleLhsMap(agg_cells_lhs_contribs_uhex) +# lhs_uhex=lazy_map(ass_lhs_map_uhex,aggregate_to_local_cells) +### END TESTING CODE + +function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + agg_cells_local_dof_ids=copy(agg_cells_dof_ids) + current_cell=1 + for agg_cells in aggregate_to_agg_cells + g2l=Dict{Int32,Int32}() + current_local_dof=1 + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in keys(g2l)) + g2l[dof]=current_local_dof + agg_cells_local_dof_ids[current_cell][j]=current_local_dof + current_local_dof+=1 + else + agg_cells_local_dof_ids[current_cell][j]=g2l[dof] + end + end + current_cell+=1 + println(agg_cells_local_dof_ids) + end + end + agg_cells_local_dof_ids +end + +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωagg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωagg_cell_dof_ids, aggregate_to_local_cells) + + +function set_up_h_U(aggregates_bounding_box_model, + agg_cells_to_aggregate, + Ωagg_cells) + degree = 0 # We are integrating a constant function + # Thus, degree=0 is enough for exact integration + Ωbb = Triangulation(aggregates_bounding_box_model) + dΩbb = Measure(Ωbb, degree) + h_U_array = get_array(∫(1.0)dΩbb) + h_U_array = lazy_map(Reindex(h_U_array), agg_cells_to_aggregate) + CellField(h_U_array, Ωagg_cells) +end + + +function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) + current_aggregate=1 + current_cell=1 + for agg_cells in aggregate_to_agg_cells + current_aggregate_dof_ids=Int[] + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in current_aggregate_dof_ids) + push!(current_aggregate_dof_ids, dof) + end + end + current_cell+=1 + end + aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids + current_aggregate+=1 + end + aggregate_dof_ids +end + +function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.single_field +end +function _get_single_field_fe_basis(a) + a +end +function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) + true +end +function _is_multifield_fe_basis_component(a) + false +end +function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.nfields +end +function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.fieldid +end + +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) + # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) +""" +function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωagg_cell_dof_ids, + agg_cells_local_dof_ids, + agg_cells_to_aggregate_dof_ids, + h_U, + γ) + + + Ωagg_cells=dΩagg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, + dΩagg_cells.quad.trian, + ReferenceDomain()) + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) + end + push!(w, dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, Ωagg_cell_dof_ids) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + + proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) + end + + push!(w, proj_dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, agg_cells_to_aggregate_dof_ids) + + w, r, c +end + +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) + +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +γ = 10.0 # Interior bulk-penalty stabilization parameter + # (@amartinhuertas no idea what a reasonable value is) + +h_U = set_up_h_U(aggregates_bounding_box_model, agg_cells_to_aggregate, Ωagg_cells) + +# Manually set up the arrays that collect_cell_matrix would return automatically +wp,rp,cp=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωagg_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + +wu,ru,cu=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωagg_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + +Ωcut = Triangulation(cutgeo,PHYSICAL) +dΩcut = Measure(Ωcut,degree) +# # Set up global projection matrix +# Ωcut = Triangulation(cutgeo,PHYSICAL) +# dΩcut = Measure(Ωcut,degree) +# a_nodiv((u,p),(v,q))=∫(v⋅u+q*p)dΩcut +# wrc_nodiv=Gridap.FESpaces.collect_cell_matrix(X,Y,a_nodiv(dx,dy)) + +# assem_nodiv=SparseMatrixAssembler(X,Y) +# Anostab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) +# cond(Array(Anostab_nodiv)) + +# # Add the bulk penalty stabilization term to wrc_nodiv +# push!(wrc_nodiv[1], wp...) +# push!(wrc_nodiv[2], rp...) +# push!(wrc_nodiv[3], cp...) + +# push!(wrc_nodiv[1], wu...) +# push!(wrc_nodiv[2], ru...) +# push!(wrc_nodiv[3], cu...) + +# Awithstab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) +# cond(Array(Awithstab_nodiv)) + +# # Set up rhs global projection +# l_nodiv((v,q))=∫(v⋅uex+q*pex)dΩcut +# b_nodiv = assemble_vector(l_nodiv, Y) + +# global_l2_proj_dofs_nodiv = Awithstab_nodiv\b_nodiv +# xh_nodiv = FEFunction(X, global_l2_proj_dofs_nodiv) +# uh_nodiv,ph_nodiv = xh_nodiv + +# euh_nodiv = uex-uh_nodiv +# # @assert sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) < 1.0e-12 + +# eph_nodiv = pex-ph_nodiv +# # @assert sum(∫(eph_nodiv*eph_nodiv)*dΩcut) < 1.0e-12 +# eph_nodiv_norm = sum(∫(eph_nodiv*eph_nodiv)*dΩcut) +# euh_nodiv_norm = sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) +# # k=0 yields eph = 0.00012 and euh = 5.5e-30 +# edivuh_nodiv = divuex-(∇⋅uh_nodiv) +# edivuh_nodiv_norm = sum(∫(edivuh_nodiv⋅edivuh_nodiv)*dΩcut) + +## TEST 1 +a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩcut +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) + +assem=SparseMatrixAssembler(X,Y) +Anostab=assemble_matrix(assem, wrc) +cond_nostab = cond(Array(Anostab)) + +# Set up rhs global projection +l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩcut +b = assemble_vector(l, Y) + +## NO STABILIZATION +if cond_nostab<1e35 + global_l2_proj_dofs_nostab = Anostab\b + xh_nostab = FEFunction(X, global_l2_proj_dofs_nostab) + uh_nostab,ph_nostab = xh_nostab + euh_nostab = uex-uh_nostab + eph_nostab = pex-ph_nostab + edivuh_nostab = divuex-(∇⋅uh_nostab) + norm_euh_nostab = sum(∫(euh_nostab⋅euh_nostab)*dΩcut) + norm_eph_nostab = sum(∫(eph_nostab*eph_nostab)*dΩcut) + edivuh_nostab = sum(∫(edivuh_nostab⋅edivuh_nostab)*dΩcut) +else + println("Singular exception is raised as error when solving the system (as cond= $cond_nostab is high?)") +end +# k=0 yields euh = 1.2e-32, eph = 0.00017, edivuh = 6.8e-30, κ= 3.15e32 +# k=0 yields euh = ?, eph = ?, edivuh = ?, κ= 4.3e36 + +## U + P STABILIZATION +# Add the bulk penalty stabilization terms for u and p to wrc +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) + +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) + +# Check the condition number when only the p and u stabilization terms are included. +Aupstab=assemble_matrix(assem, wrc) +cond_upstab = cond(Array(Aupstab)) + +# CHECK errors when only the p and u stabilization terms are included. +global_l2_proj_dofs_upstab = Aupstab\b +xh_upstab = FEFunction(X, global_l2_proj_dofs_upstab) +uh_upstab,ph_upstab = xh_upstab +euh_upstab = uex-uh_upstab +eph_upstab = pex-ph_upstab +edivuh_upstab = divuex-(∇⋅uh_upstab) +norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩcut) +norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩcut) +norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩcut) +# k=0 yields euh = 6.3e-31, eph = 0.00055, edivuh = 2.4e-28, κ= 11492 +# k=2 yields euh = 5.3e-22, eph = 3.0e-18, edivuh = 3.0e-18, κ= 1.7e11 + +## +DIVU STABILIZATION +## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) +# Manually set up the arrays that collect_cell_matrix would return automatically +w_divu = [] +r_divu = [] +c_divu = [] + +## (I) Let's set up the div_dv_div_du_mat_contribs (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells +div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) +U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) +if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) +end + +push!(w_divu, div_dv_div_du_mat_contribs) +push!(r_divu, U_Ωagg_cell_dof_ids) +push!(c_divu, U_Ωagg_cell_dof_ids) + +## Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩ_agg_cells +div_dv=∇⋅(_get_single_field_fe_basis(dv)) +pdofs=Gridap.FESpaces.get_fe_dof_basis(P) +div_dv_pdofs_values=pdofs(div_dv) +div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, + div_dv_pdofs_values, + Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) +div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, + get_triangulation(P), + Gridap.FESpaces.TestBasis(), + Gridap.CellData.ReferenceDomain()) +div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) + +div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) +div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, + get_triangulation(P), + Gridap.FESpaces.TrialBasis(), + Gridap.CellData.ReferenceDomain()) +div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) + +div_dv_div_du_in_pressure_space_mat_contribs=get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? +div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs + +### Compute Π_Q_bb(div_du) +dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) +agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) +# agg_cells_rhs_contribs[1] +ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) +rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) +div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + +# Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate +div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + div_dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(qbb)) + +div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + +div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + +if (_is_multifield_fe_basis_component(dp)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + div_du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + div_du_l2_proj_bb_array_agg_cells) +end + +div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) + +# In the MultiField case, I have had to add this change domain +# call before setting up the term right below. Otherwise, we get an error +# when trying to multiply the fields. Not sure why this is happening +# dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) +div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) + +proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) + +P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_agg_cells_to_aggregate_dof_ids) +end + +push!(w_divu, proj_div_dv_div_du_mat_contribs) +push!(r_divu, U_Ωagg_cell_dof_ids) # test +push!(c_divu, P_agg_cells_to_aggregate_dof_ids) # trial + +## Now add div stabilization to A +push!(wrc[1], w_divu...) +push!(wrc[2], r_divu...) +push!(wrc[3], c_divu...) + +# Assembly +Awithstab=assemble_matrix(assem, wrc) +cond_withstab = cond(Array(Awithstab)) + +global_l2_proj_dofs_withstab = Awithstab\b +xh_withstab = FEFunction(X, global_l2_proj_dofs_withstab) +uh_withstab,ph_withstab = xh_withstab +euh_withstab = uex-uh_withstab +eph_withstab = pex-ph_withstab +edivuh_withstab = divuex-(∇⋅uh_withstab) +norm_euh_withstab = sum(∫(euh_withstab⋅euh_withstab)*dΩcut) +norm_eph_withstab = sum(∫(eph_withstab*eph_withstab)*dΩcut) +norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) +# k=0 yields euh = 0.0014, eph = 0.47, edivuh = 0.47, κ= 8.51e11 +# k=2 yields euh = 0.00013, eph = 0.088, edivuh = 0.088, κ= 2.9e14 \ No newline at end of file From dc6a3e0455736d152b1981082c12a11c0eb773d8 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 8 Nov 2024 13:39:19 +1100 Subject: [PATCH 021/120] selection cut cells --- bulk_ghost_penalty_canvas_u-only.jl | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/bulk_ghost_penalty_canvas_u-only.jl b/bulk_ghost_penalty_canvas_u-only.jl index 2a21a754..151fb9ec 100644 --- a/bulk_ghost_penalty_canvas_u-only.jl +++ b/bulk_ghost_penalty_canvas_u-only.jl @@ -278,21 +278,34 @@ for cell in int_cells end end @assert(tester_int_nonagg_cells==int_nonagg_cells) +# Cut cells +cut_cells=Vector{Int}() +tester_root_cells=Vector{Int}() +for cell in agg_cells + if cell ∈ root_cells + append!(tester_root_cells,cell) + else + append!(cut_cells,cell) + end +end +@assert(tester_root_cells==root_cells) + # TODO Potentially useful?: # Ω_agg_cells.parent.a.subgrid.cell_node_ids.data == Ω.a.subgrid.cell_node_ids.data # vector containing cell ids - # Subdomains in background mesh (aggegrate cells are already defined) Ωbg_int_cells = view(Ωbg,int_cells) # cells in interior Ωbg_int_nonagg_cells = view(Ωbg,int_nonagg_cells) # cells in interior but not in aggregate Ωbg_root_cells = view(Ωbg,root_cells) # root cells: in interior and part of aggregate +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) # Subdomains in physical mesh Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates Ω_int_cells = view(Ω,int_cells) # cells in interior Ω_int_nonagg_cells = view(Ω,int_nonagg_cells) # cells in interior but not in aggregate Ω_root_cells = view(Ω,root_cells) # root cells: in interior and part of aggregate +Ω_cut_cells = view(Ω,cut_cells) # cut cells (part of aggregate) ## VISUALISATION: writevtk(Ωbg,"trian_bg") @@ -300,6 +313,7 @@ writevtk(Ωbg_agg_cells,"trian_bg_agg_cells") writevtk(Ωbg_int_cells,"trian_bg_int_cells") writevtk(Ωbg_int_nonagg_cells,"trian_bg_int_nonagg_cells") writevtk(Ωbg_root_cells,"trian_bg_root_cells") +writevtk(Ωbg_cut_cells,"trian_bg_cut_cells") writevtk(Ωact,"trian_act") writevtk(Ω,"trian_phys") @@ -307,7 +321,8 @@ writevtk(Ω,"trian_phys") # writevtk(Ω_agg_cells,"trian_phys_agg_cells") # writevtk(Ω_int_cells,"trian_phys_int_cells") # writevtk(Ω_int_nonagg_cells,"trian_phys_int_nonagg_cells") -# writevtk(Ω_int_cells,"trian_phys_int_root_cells") +# writevtk(Ω_root_cells,"trian_phys_root_cells") +# writevtk(Ω_cut_cells,"trian_phys_cut_coot_cells") # Generate an array with the global IDs of the cells From fd466d6cd280f9fb62f50b907cba539a1e24a11c Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 8 Nov 2024 13:50:44 +1100 Subject: [PATCH 022/120] area check --- bulk_ghost_penalty_canvas_u-only.jl | 55 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/bulk_ghost_penalty_canvas_u-only.jl b/bulk_ghost_penalty_canvas_u-only.jl index 151fb9ec..4a985f34 100644 --- a/bulk_ghost_penalty_canvas_u-only.jl +++ b/bulk_ghost_penalty_canvas_u-only.jl @@ -323,36 +323,33 @@ writevtk(Ω,"trian_phys") # writevtk(Ω_int_nonagg_cells,"trian_phys_int_nonagg_cells") # writevtk(Ω_root_cells,"trian_phys_root_cells") # writevtk(Ω_cut_cells,"trian_phys_cut_coot_cells") +degree = 2*2*order +dΩ = Measure(Ω,degree) +dΩact = Measure(Ωact,degree) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) +dΩbg_root_cells = Measure(Ωbg_root_cells,degree) + + +dΩagg_cells = Measure(Ω_agg_cells,degree) +dΩcut_cells = Measure(Ω_cut_cells,degree) +dΩroot_cells = Measure(Ω_root_cells,degree) + +# TESTING +area_phys_domain = sum(∫(1.0)dΩ) +area_act_domain = sum(∫(1.0)dΩact) +area_agg_cells = sum(∫(1.0)dΩbg_agg_cells) +area_cut_cells = sum(∫(1.0)dΩbg_cut_cells) +area_root_cells = sum(∫(1.0)dΩbg_root_cells) +@assert(area_agg_cells ≈ area_cut_cells + area_root_cells) + +# TODO: not possible to integrate over the physical part of the domain, e.g. +area_phys_agg_cells = sum(∫(1.0)dΩ_agg_cells) +area_phys_cut_cells = sum(∫(1.0)dΩ_cut_cells) +area_phys_root_cells = sum(∫(1.0)dΩ_root_cells) - -# Generate an array with the global IDs of the cells -# that belong to the cut cells (and are thus also part of an aggregate). From now on, we will -# use the terminology "cut_cells" to refer to those -# cells of the background model that belong to the cut domain -interior_cells=Vector{Int}() -for cell in true_interior_cells - if cell ∈ interior_cells - append!(interior_cells,cells) -end -bgmodel.grid_topology.vertex_coordinates - -Ω_agg_cells.parent.b.tface_to_mface #what is this (len =24) - - - -intcellstest = filter(!in[interior_cells], Ω_agg_cells.parent.b.tface_to_mface) - -dΩ = Measure(Ω,2*order*2) -dΩ_agg_cells = Measure(Ω_agg_cells,2*order*2) - - -colors = color_aggregates(aggregates,bgmodel) -unique(colors) -countmap(colors) - -cut_bgtrian = Triangulation(cut,CUT,cutgeo) - -# (Q1) WHEN WE DEFINE dΩagg_cells are we intergrating over the entire aggregate or only up to the physical part of it? That is, when we add the stabilization what do we intend to do? +# colors = color_aggregates(aggregates,bgmodel) +# TODO: (Q1) WHEN WE DEFINE dΩagg_cells are we intergrating over the entire aggregate or only up to the physical part of it? That is, when we add the stabilization what do we intend to do? ## Set up global spaces Ωact = Triangulation(cutgeo,ACTIVE) From fe745e79c7caa61ce86c366603a6cbcab50dc66d Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 8 Nov 2024 16:33:48 +1100 Subject: [PATCH 023/120] towards div stab term: issues with projection --- bulk_ghost_penalty_canvas_towardsdiv.jl | 749 ++++++++++++++++++++++++ 1 file changed, 749 insertions(+) create mode 100644 bulk_ghost_penalty_canvas_towardsdiv.jl diff --git a/bulk_ghost_penalty_canvas_towardsdiv.jl b/bulk_ghost_penalty_canvas_towardsdiv.jl new file mode 100644 index 00000000..d796f031 --- /dev/null +++ b/bulk_ghost_penalty_canvas_towardsdiv.jl @@ -0,0 +1,749 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 +# Select geometry +R = 0.2 +geom = disk(R, x0=Point(0.5,0.5)) + +# Setup background model +n=10 +partition = (n,n) +box = get_metadata(geom) +bgmodel = CartesianDiscreteModel((0,1,0,1),partition) +dp = box.pmax - box.pmin +h = dp[1]/n + +# Cut the background model with the mesh +cutdisk = cut(bgmodel,geom) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutdisk) + +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cells in the background + model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_aggregate_to_cells(aggregates) + + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]>1) + if !haskey(touched,agg) + push!(aggregate_to_cells,[i]) + touched[agg]=current_aggregate + current_aggregate+=1 + else + push!(aggregate_to_cells[touched[agg]],i) + end + end + end + end + aggregate_to_cells +end + +function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) + g=get_grid(bgmodel) + cell_coords=get_cell_coordinates(g) + D=num_dims(bgmodel) + xmin=Vector{Float64}(undef,D) + xmax=Vector{Float64}(undef,D) + + # Compute coordinates of the nodes defining the bounding boxes + bounding_box_node_coords= + Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) + ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] + data = collect(1:length(bounding_box_node_coords)) + bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) + for (agg,cells) in enumerate(aggregate_to_cells) + p=first(cell_coords[cells[1]]) + for i in 1:D + xmin[i]=p[i] + xmax[i]=p[i] + end + for cell in cells + for p in cell_coords[cell] + for i in 1:D + xmin[i]=min(xmin[i],p[i]) + xmax[i]=max(xmax[i],p[i]) + end + end + end + bounds = [(xmin[i], xmax[i]) for i in 1:D] + point_iterator = Iterators.product(bounds...) + bounding_box_node_coords[bounding_box_node_ids[agg]] = + reshape([Point(p...) for p in point_iterator],2^D) + end + + # Set up the discrete model of bounding boxes + HEX_AXIS=1 + polytope=Polytope(Fill(HEX_AXIS,D)...) + scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) + cell_types=fill(1,length(bounding_box_node_ids)) + cell_reffes=[scalar_reffe] + grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, + bounding_box_node_ids, + cell_reffes, + cell_types, + Gridap.Geometry.Oriented()) + Gridap.Geometry.UnstructuredDiscreteModel(grid) +end + +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# colors = color_aggregates(aggregates,bgmodel) +# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) +# writevtk(aggregates_bounding_box_model, "bb_model") +# writevtk(bgmodel, "bg_model") + +""" + Changes the domain of a trial/test basis defined on + the reference space of bounding boxes to the reference + space of the agg cells + + TO-DO: in the future, for system of PDEs (MultiField) we should + also take care of blocks (BlockMap) +""" +function change_domain_bb_to_agg_cells(basis_bb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) + @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() + bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) + bb_basis_array = Gridap.CellData.get_data(basis_bb) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Remove transpose map; we will add it later + @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) + @assert isa(bb_basis_array.maps,Fill) + @assert isa(bb_basis_array.maps.value,typeof(transpose)) + bb_basis_array=bb_basis_array.args[1] + end + + bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) + bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), + bb_basis_array_to_Ωagg_cells_array, + ref_agg_cell_to_ref_bb_map) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Add transpose + bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) + end + + Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, + Ωagg_cells, + ReferenceDomain()) +end + + +# Set up objects required to compute both LHS and RHS of the L2 projection + +# Set up global spaces +Ωhact = Triangulation(cutdisk,ACTIVE) + +V = FESpace(Ωhact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +Q = FESpace(Ωhact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +U = TrialFESpace(V) +P = TrialFESpace(Q) +Y = MultiFieldFESpace([V, Q]) +X = MultiFieldFESpace([U, P]) + +# Generate an array with the global IDs of the cells +# that belong to an aggregrate. From now on, we will +# use the terminology "agg_cells" to refer to those +# cells of the background model that belong to an aggregate +# (i.e., they can be either cut or interior cells) +agg_cells=Vector{Int}() +for cells in aggregate_to_cells + append!(agg_cells,cells) +end + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +Ω=Triangulation(bgmodel) +Ωagg_cells=view(Ω,agg_cells) +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) + +# Generate an array that given the local ID of an "agg_cell" +# returns the ID of the aggregate to which it belongs +# (i.e., flattened version of aggregate_to_cells) +agg_cells_to_aggregate=Vector{Int}() +for (i,cells) in enumerate(aggregate_to_cells) + for _ in cells + push!(agg_cells_to_aggregate,i) + end +end + +# ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} +bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) +bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) +ref_agg_cell_to_ref_bb_map= + lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) + +# Compute LHS of L2 projection +degree=2*(order+1) +dΩagg_cells = Measure(Ωagg_cells,degree) +reffe =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) + +reffe=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + + +aggregate_to_local_cells=copy(aggregate_to_cells) +current_local_cell=1 +for (i,cells) in enumerate(aggregate_to_local_cells) + for j in 1:length(cells) + cells[j]=current_local_cell + current_local_cell+=1 + end +end + +function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + ubb, + vbb) + Ωagg_cells=dΩagg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + # Change domain of ubb (trial) from Ωbb to Ωagg_cells + ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + # Compute contributions to LHS of L2 projection + agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) + + # Finally assemble LHS contributions + ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) + lazy_map(ass_lhs_map,aggregate_to_local_cells) +end + +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + ubb, + vbb) + +# Compute contributions to the RHS of the L2 projection +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) + map=cell_dof_ids.maps.value + @assert length(map.size)==1 + @assert blockid >= 1 + @assert blockid <= map.size[1] + cell_dof_ids.args[blockid] +end + +Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) +U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) +P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) +# Ωagg_cell_dof_ids[1][1] # cell 1, velo dof +# Ωagg_cell_dof_ids[1][2] # cell 1, pressure dofs + +### BEGIN TESTING CODE +# This code is just for testing purposes, so I have commented it out +# It allows to evaluate the LHS of the L2 projection corresponding to a +# particular FE function, instead of a basis +# uhex=interpolate(uex,Ustd) +# agg_cells_lhs_contribs_uhex=get_array(∫(vbb_Ωagg_cells*uhex)dΩagg_cells) +# ass_lhs_map_uhex=AssembleLhsMap(agg_cells_lhs_contribs_uhex) +# lhs_uhex=lazy_map(ass_lhs_map_uhex,aggregate_to_local_cells) +### END TESTING CODE + +function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + agg_cells_local_dof_ids=copy(agg_cells_dof_ids) + current_cell=1 + for agg_cells in aggregate_to_agg_cells + g2l=Dict{Int32,Int32}() + current_local_dof=1 + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in keys(g2l)) + g2l[dof]=current_local_dof + agg_cells_local_dof_ids[current_cell][j]=current_local_dof + current_local_dof+=1 + else + agg_cells_local_dof_ids[current_cell][j]=g2l[dof] + end + end + current_cell+=1 + println(agg_cells_local_dof_ids) + end + end + agg_cells_local_dof_ids +end + +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωagg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωagg_cell_dof_ids, aggregate_to_local_cells) + + +function set_up_h_U(aggregates_bounding_box_model, + agg_cells_to_aggregate, + Ωagg_cells) + degree = 0 # We are integrating a constant function + # Thus, degree=0 is enough for exact integration + Ωbb = Triangulation(aggregates_bounding_box_model) + dΩbb = Measure(Ωbb, degree) + h_U_array = get_array(∫(1.0)dΩbb) + h_U_array = lazy_map(Reindex(h_U_array), agg_cells_to_aggregate) + CellField(h_U_array, Ωagg_cells) +end + + +function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) + current_aggregate=1 + current_cell=1 + for agg_cells in aggregate_to_agg_cells + current_aggregate_dof_ids=Int[] + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in current_aggregate_dof_ids) + push!(current_aggregate_dof_ids, dof) + end + end + current_cell+=1 + end + aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids + current_aggregate+=1 + end + aggregate_dof_ids +end + +function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.single_field +end +function _get_single_field_fe_basis(a) + a +end +function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) + true +end +function _is_multifield_fe_basis_component(a) + false +end +function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.nfields +end +function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.fieldid +end + +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) + # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) +""" +function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωagg_cell_dof_ids, + agg_cells_local_dof_ids, + agg_cells_to_aggregate_dof_ids, + h_U, + γ) + + + Ωagg_cells=dΩagg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, + dΩagg_cells.quad.trian, + ReferenceDomain()) + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) + end + push!(w, dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, Ωagg_cell_dof_ids) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + + proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) + end + + push!(w, proj_dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, agg_cells_to_aggregate_dof_ids) + + w, r, c +end + +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) + +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +γ = 10.0 # Interior bulk-penalty stabilization parameter + # (@amartinhuertas no idea what a reasonable value is) + +h_U = set_up_h_U(aggregates_bounding_box_model, agg_cells_to_aggregate, Ωagg_cells) + +# Manually set up the arrays that collect_cell_matrix would return automatically +wp,rp,cp=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωagg_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + +wu,ru,cu=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωagg_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + +Ωcut = Triangulation(cutdisk,PHYSICAL) +dΩcut = Measure(Ωcut,degree) +# # Set up global projection matrix +# Ωcut = Triangulation(cutdisk,PHYSICAL) +# dΩcut = Measure(Ωcut,degree) +# a_nodiv((u,p),(v,q))=∫(v⋅u+q*p)dΩcut +# wrc_nodiv=Gridap.FESpaces.collect_cell_matrix(X,Y,a_nodiv(dx,dy)) + +# assem_nodiv=SparseMatrixAssembler(X,Y) +# Anostab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) +# cond(Array(Anostab_nodiv)) + +# # Add the bulk penalty stabilization term to wrc_nodiv +# push!(wrc_nodiv[1], wp...) +# push!(wrc_nodiv[2], rp...) +# push!(wrc_nodiv[3], cp...) + +# push!(wrc_nodiv[1], wu...) +# push!(wrc_nodiv[2], ru...) +# push!(wrc_nodiv[3], cu...) + +# Awithstab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) +# cond(Array(Awithstab_nodiv)) + +# # Set up rhs global projection +# l_nodiv((v,q))=∫(v⋅uex+q*pex)dΩcut +# b_nodiv = assemble_vector(l_nodiv, Y) + +# global_l2_proj_dofs_nodiv = Awithstab_nodiv\b_nodiv +# xh_nodiv = FEFunction(X, global_l2_proj_dofs_nodiv) +# uh_nodiv,ph_nodiv = xh_nodiv + +# euh_nodiv = uex-uh_nodiv +# # @assert sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) < 1.0e-12 + +# eph_nodiv = pex-ph_nodiv +# # @assert sum(∫(eph_nodiv*eph_nodiv)*dΩcut) < 1.0e-12 +# eph_nodiv_norm = sum(∫(eph_nodiv*eph_nodiv)*dΩcut) +# euh_nodiv_norm = sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) +# # k=0 yields eph = 0.00012 and euh = 5.5e-30 +# edivuh_nodiv = divuex-(∇⋅uh_nodiv) +# edivuh_nodiv_norm = sum(∫(edivuh_nodiv⋅edivuh_nodiv)*dΩcut) + +## TEST 1 +a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩcut +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) + +assem=SparseMatrixAssembler(X,Y) +Anostab=assemble_matrix(assem, wrc) +cond_nostab = cond(Array(Anostab)) + +# Set up rhs global projection +l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩcut +b = assemble_vector(l, Y) + +## NO STABILIZATION +if cond_nostab<1e35 + global_l2_proj_dofs_nostab = Anostab\b + xh_nostab = FEFunction(X, global_l2_proj_dofs_nostab) + uh_nostab,ph_nostab = xh_nostab + euh_nostab = uex-uh_nostab + eph_nostab = pex-ph_nostab + edivuh_nostab = divuex-(∇⋅uh_nostab) + norm_euh_nostab = sum(∫(euh_nostab⋅euh_nostab)*dΩcut) + norm_eph_nostab = sum(∫(eph_nostab*eph_nostab)*dΩcut) + edivuh_nostab = sum(∫(edivuh_nostab⋅edivuh_nostab)*dΩcut) +else + println("Singular exception is raised as error when solving the system (as cond= $cond_nostab is high?)") +end +# k=0 yields euh = 1.2e-32, eph = 0.00017, edivuh = 6.8e-30, κ= 3.15e32 +# k=0 yields euh = ?, eph = ?, edivuh = ?, κ= 4.3e36 + +## U + P STABILIZATION +# Add the bulk penalty stabilization terms for u and p to wrc +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) + +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) + +# Check the condition number when only the p and u stabilization terms are included. +Aupstab=assemble_matrix(assem, wrc) +cond_upstab = cond(Array(Aupstab)) + +# CHECK errors when only the p and u stabilization terms are included. +global_l2_proj_dofs_upstab = Aupstab\b +xh_upstab = FEFunction(X, global_l2_proj_dofs_upstab) +uh_upstab,ph_upstab = xh_upstab +euh_upstab = uex-uh_upstab +eph_upstab = pex-ph_upstab +edivuh_upstab = divuex-(∇⋅uh_upstab) +norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩcut) +norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩcut) +norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩcut) +# k=0 yields euh = 6.3e-31, eph = 0.00055, edivuh = 2.4e-28, κ= 11492 +# k=2 yields euh = 5.3e-22, eph = 3.0e-18, edivuh = 3.0e-18, κ= 1.7e11 + +## +DIVU STABILIZATION +## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) +# Manually set up the arrays that collect_cell_matrix would return automatically +w_divu = [] +r_divu = [] +c_divu = [] + +## (I) Let's set up the div_dv_div_du_mat_contribs (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells +div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) +U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) +if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) +end + +push!(w_divu, div_dv_div_du_mat_contribs) +push!(r_divu, U_Ωagg_cell_dof_ids) +push!(c_divu, U_Ωagg_cell_dof_ids) + +## Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩ_agg_cells +div_dv=∇⋅(_get_single_field_fe_basis(dv)) +pdofs=Gridap.FESpaces.get_fe_dof_basis(P) +div_dv_pdofs_values=pdofs(div_dv) +div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, + div_dv_pdofs_values, + Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) +div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, + get_triangulation(P), + Gridap.FESpaces.TestBasis(), + Gridap.CellData.ReferenceDomain()) +div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) + +div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) +div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, + get_triangulation(P), + Gridap.FESpaces.TrialBasis(), + Gridap.CellData.ReferenceDomain()) +div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) + +div_dv_div_du_in_pressure_space_mat_contribs=get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? +div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs + +### Compute Π_Q_bb(div_du) +dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) +agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) +# agg_cells_rhs_contribs[1] +ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) +rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) +div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + +# Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate +div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + div_dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(qbb)) + +div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + +div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + +if (_is_multifield_fe_basis_component(dp)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + div_du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + div_du_l2_proj_bb_array_agg_cells) +end + +div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) + +# In the MultiField case, I have had to add this change domain +# call before setting up the term right below. Otherwise, we get an error +# when trying to multiply the fields. Not sure why this is happening +# dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) +div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) + +proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) + +P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_agg_cells_to_aggregate_dof_ids) +end + +push!(w_divu, proj_div_dv_div_du_mat_contribs) +push!(r_divu, U_Ωagg_cell_dof_ids) # test +push!(c_divu, P_agg_cells_to_aggregate_dof_ids) # trial + +## Now add div stabilization to A +push!(wrc[1], w_divu...) +push!(wrc[2], r_divu...) +push!(wrc[3], c_divu...) + +# Assembly +Awithstab=assemble_matrix(assem, wrc) +cond_withstab = cond(Array(Awithstab)) + +global_l2_proj_dofs_withstab = Awithstab\b +xh_withstab = FEFunction(X, global_l2_proj_dofs_withstab) +uh_withstab,ph_withstab = xh_withstab +euh_withstab = uex-uh_withstab +eph_withstab = pex-ph_withstab +edivuh_withstab = divuex-(∇⋅uh_withstab) +norm_euh_withstab = sum(∫(euh_withstab⋅euh_withstab)*dΩcut) +norm_eph_withstab = sum(∫(eph_withstab*eph_withstab)*dΩcut) +norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) +# k=0 yields euh = 0.0014, eph = 0.47, edivuh = 0.47, κ= 8.51e11 +# k=2 yields euh = 0.00013, eph = 0.088, edivuh = 0.088, κ= 2.9e14 \ No newline at end of file From 4c7b4839cd06285ad2d081f40d485675e284ddca Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 8 Nov 2024 17:42:10 +1100 Subject: [PATCH 024/120] Breaks in BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,test_agg_cells_rhs_contribs). Fix with rank does not seem to work. --- BulkGhostPenaltyAssembleMaps.jl | 29 +- bulk_ghost_penalty_canvas_towardsdiv.jl | 463 +++++++----------------- 2 files changed, 154 insertions(+), 338 deletions(-) diff --git a/BulkGhostPenaltyAssembleMaps.jl b/BulkGhostPenaltyAssembleMaps.jl index 3068b92c..628d87b4 100644 --- a/BulkGhostPenaltyAssembleMaps.jl +++ b/BulkGhostPenaltyAssembleMaps.jl @@ -13,7 +13,7 @@ function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleLhsMap,cells) evaluate_result=Gridap.Arrays.CachedArray(eltype(T),_get_rank(T)) cache_unassembled_lhs,evaluate_result end - + function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleLhsMap,cells) cache_unassembled_lhs,result=cache contrib = getindex!(cache_unassembled_lhs,m.agg_cells_lhs_contribs,1) @@ -26,16 +26,17 @@ function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleLhsMap,cells) end result.array end - -struct BulkGhostPenaltyAssembleRhsMap{A,B} <: Gridap.Fields.Map - agg_cells_local_dof_ids::A +#TODO: add {RANK,A,B} +struct BulkGhostPenaltyAssembleRhsMap{A,B} <: Gridap.Fields.Map + agg_cells_local_dof_ids::A agg_cells_rhs_contribs::B -end +end function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleRhsMap,aggregate_local_cells) cache_agg_cells_local_dof_ids=array_cache(m.agg_cells_local_dof_ids) cache_unassembled_rhs=array_cache(m.agg_cells_rhs_contribs) - evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),2) + rank=length(size(m.agg_cells_rhs_contribs[1])) + evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),rank) cache_agg_cells_local_dof_ids,cache_unassembled_rhs,evaluate_result end @@ -51,14 +52,24 @@ function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleRhsMap,aggrega end end - Gridap.Arrays.setsize!(result,(size(contrib,1),max_local_dof_id)) + rank=length(size(result)) + if rank==2 + Gridap.Arrays.setsize!(result,(size(contrib,1),max_local_dof_id)) + else + @assert rank==1 + Gridap.Arrays.setsize!(result,max_local_dof_id) + end result.array .= 0.0 for (i,cell) in enumerate(aggregate_local_cells) current_cell_local_dof_ids = getindex!(cache_agg_cells_local_dof_ids,m.agg_cells_local_dof_ids,cell) contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,cell) for (j,local_dof) in enumerate(current_cell_local_dof_ids) - result.array[:,local_dof] += contrib[:,j] + if rank==2 + result.array[:,local_dof] += contrib[:,j] + else + result.array[local_dof] += contrib[j] + end end end result.array -end \ No newline at end of file +end diff --git a/bulk_ghost_penalty_canvas_towardsdiv.jl b/bulk_ghost_penalty_canvas_towardsdiv.jl index d796f031..a66474b6 100644 --- a/bulk_ghost_penalty_canvas_towardsdiv.jl +++ b/bulk_ghost_penalty_canvas_towardsdiv.jl @@ -25,32 +25,32 @@ h = dp[1]/n # Cut the background model with the mesh cutdisk = cut(bgmodel,geom) -# Compute mapping among background model -# cut cells and interior cells +# Compute mapping among background model +# cut cells and interior cells strategy = AggregateAllCutCells() aggregates = aggregate(strategy,cutdisk) """ - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains the global cell IDs of that cells in the background + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cells in the background model that belong to the same aggregate - TO-DO: with efficiency in mind we may want to store this + TO-DO: with efficiency in mind we may want to store this array of arrays as a Gridap.Arrays.Table. """ function setup_aggregate_to_cells(aggregates) - + size_aggregates=Dict{Int,Int}() for (i,agg) in enumerate(aggregates) if agg>0 if !haskey(size_aggregates,agg) size_aggregates[agg]=1 - else + else size_aggregates[agg]+=1 end end - end + end touched=Dict{Int,Int}() aggregate_to_cells=Vector{Vector{Int}}() @@ -62,14 +62,14 @@ function setup_aggregate_to_cells(aggregates) push!(aggregate_to_cells,[i]) touched[agg]=current_aggregate current_aggregate+=1 - else + else push!(aggregate_to_cells[touched[agg]],i) end - end + end end end aggregate_to_cells -end +end function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) g=get_grid(bgmodel) @@ -77,7 +77,7 @@ function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) D=num_dims(bgmodel) xmin=Vector{Float64}(undef,D) xmax=Vector{Float64}(undef,D) - + # Compute coordinates of the nodes defining the bounding boxes bounding_box_node_coords= Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) @@ -95,12 +95,12 @@ function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) for i in 1:D xmin[i]=min(xmin[i],p[i]) xmax[i]=max(xmax[i],p[i]) - end - end + end + end end bounds = [(xmin[i], xmax[i]) for i in 1:D] point_iterator = Iterators.product(bounds...) - bounding_box_node_coords[bounding_box_node_ids[agg]] = + bounding_box_node_coords[bounding_box_node_ids[agg]] = reshape([Point(p...) for p in point_iterator],2^D) end @@ -116,32 +116,32 @@ function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) cell_types, Gridap.Geometry.Oriented()) Gridap.Geometry.UnstructuredDiscreteModel(grid) -end +end aggregate_to_cells=setup_aggregate_to_cells(aggregates) aggregates_bounding_box_model= setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) # colors = color_aggregates(aggregates,bgmodel) -# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) +# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) # writevtk(aggregates_bounding_box_model, "bb_model") # writevtk(bgmodel, "bg_model") """ - Changes the domain of a trial/test basis defined on - the reference space of bounding boxes to the reference + Changes the domain of a trial/test basis defined on + the reference space of bounding boxes to the reference space of the agg cells - TO-DO: in the future, for system of PDEs (MultiField) we should + TO-DO: in the future, for system of PDEs (MultiField) we should also take care of blocks (BlockMap) """ -function change_domain_bb_to_agg_cells(basis_bb, - ref_agg_cell_to_ref_bb_map, +function change_domain_bb_to_agg_cells(basis_bb, + ref_agg_cell_to_ref_bb_map, Ωagg_cells, agg_cells_to_aggregate) @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() - bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) + bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) bb_basis_array = Gridap.CellData.get_data(basis_bb) if (bb_basis_style==Gridap.FESpaces.TrialBasis()) # Remove transpose map; we will add it later @@ -150,26 +150,25 @@ function change_domain_bb_to_agg_cells(basis_bb, @assert isa(bb_basis_array.maps.value,typeof(transpose)) bb_basis_array=bb_basis_array.args[1] end - + bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), bb_basis_array_to_Ωagg_cells_array, ref_agg_cell_to_ref_bb_map) if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Add transpose + # Add transpose bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) - end + end Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, Ωagg_cells, ReferenceDomain()) end - -# Set up objects required to compute both LHS and RHS of the L2 projection - -# Set up global spaces +# Set up global spaces Ωhact = Triangulation(cutdisk,ACTIVE) +degree=2*(order+1) +dΩhact = Measure(Ωhact,degree) V = FESpace(Ωhact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) Q = FESpace(Ωhact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) @@ -177,18 +176,22 @@ U = TrialFESpace(V) P = TrialFESpace(Q) Y = MultiFieldFESpace([V, Q]) X = MultiFieldFESpace([U, P]) +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy -# Generate an array with the global IDs of the cells -# that belong to an aggregrate. From now on, we will -# use the terminology "agg_cells" to refer to those -# cells of the background model that belong to an aggregate +# Generate an array with the global IDs of the cells +# that belong to an aggregrate. From now on, we will +# use the terminology "agg_cells" to refer to those +# cells of the background model that belong to an aggregate # (i.e., they can be either cut or interior cells) agg_cells=Vector{Int}() for cells in aggregate_to_cells append!(agg_cells,cells) end -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K Ω=Triangulation(bgmodel) Ωagg_cells=view(Ω,agg_cells) ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) @@ -198,19 +201,18 @@ ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) # (i.e., flattened version of aggregate_to_cells) agg_cells_to_aggregate=Vector{Int}() for (i,cells) in enumerate(aggregate_to_cells) - for _ in cells + for _ in cells push!(agg_cells_to_aggregate,i) end -end +end # ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) -bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) +bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) ref_agg_cell_to_ref_bb_map= lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) -# Compute LHS of L2 projection -degree=2*(order+1) +# Compute LHS of L2 projection dΩagg_cells = Measure(Ωagg_cells,degree) reffe =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) Qbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) # We need a DG space to represent the L2 projection @@ -224,7 +226,6 @@ Ubb=TrialFESpace(Vbb) ubb=get_trial_fe_basis(Ubb) vbb=get_fe_basis(Vbb) - aggregate_to_local_cells=copy(aggregate_to_cells) current_local_cell=1 for (i,cells) in enumerate(aggregate_to_local_cells) @@ -238,7 +239,7 @@ function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, - ubb, + ubb, vbb) Ωagg_cells=dΩagg_cells.quad.trian @@ -248,7 +249,7 @@ function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, Ωagg_cells, agg_cells_to_aggregate) - # Change domain of ubb (trial) from Ωbb to Ωagg_cells + # Change domain of ubb (trial) from Ωbb to Ωagg_cells ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, ref_agg_cell_to_ref_bb_map, Ωagg_cells, @@ -260,7 +261,7 @@ function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, # Finally assemble LHS contributions ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) lazy_map(ass_lhs_map,aggregate_to_local_cells) -end +end p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, agg_cells_to_aggregate, @@ -274,37 +275,20 @@ u_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, ref_agg_cell_to_ref_bb_map, dΩagg_cells, ubb, - vbb) + vbb) -# Compute contributions to the RHS of the L2 projection -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) - map=cell_dof_ids.maps.value + map=cell_dof_ids.maps.value @assert length(map.size)==1 @assert blockid >= 1 @assert blockid <= map.size[1] cell_dof_ids.args[blockid] -end +end Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) +U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) -# Ωagg_cell_dof_ids[1][1] # cell 1, velo dof -# Ωagg_cell_dof_ids[1][2] # cell 1, pressure dofs - -### BEGIN TESTING CODE -# This code is just for testing purposes, so I have commented it out -# It allows to evaluate the LHS of the L2 projection corresponding to a -# particular FE function, instead of a basis -# uhex=interpolate(uex,Ustd) -# agg_cells_lhs_contribs_uhex=get_array(∫(vbb_Ωagg_cells*uhex)dΩagg_cells) -# ass_lhs_map_uhex=AssembleLhsMap(agg_cells_lhs_contribs_uhex) -# lhs_uhex=lazy_map(ass_lhs_map_uhex,aggregate_to_local_cells) -### END TESTING CODE function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) agg_cells_local_dof_ids=copy(agg_cells_dof_ids) @@ -319,10 +303,10 @@ function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cel g2l[dof]=current_local_dof agg_cells_local_dof_ids[current_cell][j]=current_local_dof current_local_dof+=1 - else + else agg_cells_local_dof_ids[current_cell][j]=g2l[dof] - end - end + end + end current_cell+=1 println(agg_cells_local_dof_ids) end @@ -336,19 +320,6 @@ P_agg_cells_local_dof_ids= compute_agg_cells_local_dof_ids(P_Ωagg_cell_dof_ids, aggregate_to_local_cells) -function set_up_h_U(aggregates_bounding_box_model, - agg_cells_to_aggregate, - Ωagg_cells) - degree = 0 # We are integrating a constant function - # Thus, degree=0 is enough for exact integration - Ωbb = Triangulation(aggregates_bounding_box_model) - dΩbb = Measure(Ωbb, degree) - h_U_array = get_array(∫(1.0)dΩbb) - h_U_array = lazy_map(Reindex(h_U_array), agg_cells_to_aggregate) - CellField(h_U_array, Ωagg_cells) -end - - function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) current_aggregate=1 @@ -360,10 +331,10 @@ function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) for (j, dof) in enumerate(current_cell_dof_ids) if !(dof in current_aggregate_dof_ids) push!(current_aggregate_dof_ids, dof) - end - end + end + end current_cell+=1 - end + end aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids current_aggregate+=1 end @@ -406,7 +377,6 @@ function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_ag Ωagg_cell_dof_ids, agg_cells_local_dof_ids, agg_cells_to_aggregate_dof_ids, - h_U, γ) @@ -416,20 +386,20 @@ function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_ag dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, ref_agg_cell_to_ref_bb_map, Ωagg_cells, - agg_cells_to_aggregate) + agg_cells_to_aggregate) - du_single_field=_get_single_field_fe_basis(du) + du_single_field=_get_single_field_fe_basis(du) agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # TO-DO: optimize using our own optimized version Gridap.Fields.Map # of backslash that re-uses storage for lu factors among cells, etc. dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, dv_l2_proj_bb_dofs, Gridap.CellData.get_data(dvbb)) @@ -440,7 +410,7 @@ function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_ag ref_agg_cell_to_ref_bb_map) du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - + if (_is_multifield_fe_basis_component(du)) @assert _is_multifield_fe_basis_component(dv) @assert _nfields(du)==_nfields(dv) @@ -449,7 +419,7 @@ function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_ag du_l2_proj_bb_array_agg_cells=lazy_map( Gridap.Fields.BlockMap((1,nfields),fieldid), du_l2_proj_bb_array_agg_cells) - end + end du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian, @@ -470,185 +440,79 @@ function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_ag push!(r, Ωagg_cell_dof_ids) push!(c, Ωagg_cell_dof_ids) - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error # when trying to multiply the fields. Not sure why this is happening dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) - + if (_is_multifield_fe_basis_component(du)) nfields=_nfields(du) fieldid=_fieldid(du) agg_cells_to_aggregate_dof_ids= lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) end - + push!(w, proj_dv_du_mat_contribs) push!(r, Ωagg_cell_dof_ids) push!(c, agg_cells_to_aggregate_dof_ids) w, r, c end - + U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) -γ = 10.0 # Interior bulk-penalty stabilization parameter - # (@amartinhuertas no idea what a reasonable value is) - -h_U = set_up_h_U(aggregates_bounding_box_model, agg_cells_to_aggregate, Ωagg_cells) - -# Manually set up the arrays that collect_cell_matrix would return automatically -wp,rp,cp=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωagg_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - -wu,ru,cu=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωagg_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - -Ωcut = Triangulation(cutdisk,PHYSICAL) -dΩcut = Measure(Ωcut,degree) -# # Set up global projection matrix -# Ωcut = Triangulation(cutdisk,PHYSICAL) -# dΩcut = Measure(Ωcut,degree) -# a_nodiv((u,p),(v,q))=∫(v⋅u+q*p)dΩcut -# wrc_nodiv=Gridap.FESpaces.collect_cell_matrix(X,Y,a_nodiv(dx,dy)) - -# assem_nodiv=SparseMatrixAssembler(X,Y) -# Anostab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) -# cond(Array(Anostab_nodiv)) - -# # Add the bulk penalty stabilization term to wrc_nodiv -# push!(wrc_nodiv[1], wp...) -# push!(wrc_nodiv[2], rp...) -# push!(wrc_nodiv[3], cp...) - -# push!(wrc_nodiv[1], wu...) -# push!(wrc_nodiv[2], ru...) -# push!(wrc_nodiv[3], cu...) - -# Awithstab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) -# cond(Array(Awithstab_nodiv)) - -# # Set up rhs global projection -# l_nodiv((v,q))=∫(v⋅uex+q*pex)dΩcut -# b_nodiv = assemble_vector(l_nodiv, Y) - -# global_l2_proj_dofs_nodiv = Awithstab_nodiv\b_nodiv -# xh_nodiv = FEFunction(X, global_l2_proj_dofs_nodiv) -# uh_nodiv,ph_nodiv = xh_nodiv - -# euh_nodiv = uex-uh_nodiv -# # @assert sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) < 1.0e-12 - -# eph_nodiv = pex-ph_nodiv -# # @assert sum(∫(eph_nodiv*eph_nodiv)*dΩcut) < 1.0e-12 -# eph_nodiv_norm = sum(∫(eph_nodiv*eph_nodiv)*dΩcut) -# euh_nodiv_norm = sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) -# # k=0 yields eph = 0.00012 and euh = 5.5e-30 -# edivuh_nodiv = divuex-(∇⋅uh_nodiv) -# edivuh_nodiv_norm = sum(∫(edivuh_nodiv⋅edivuh_nodiv)*dΩcut) - -## TEST 1 -a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩcut -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) - -assem=SparseMatrixAssembler(X,Y) -Anostab=assemble_matrix(assem, wrc) -cond_nostab = cond(Array(Anostab)) - -# Set up rhs global projection -l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩcut -b = assemble_vector(l, Y) - -## NO STABILIZATION -if cond_nostab<1e35 - global_l2_proj_dofs_nostab = Anostab\b - xh_nostab = FEFunction(X, global_l2_proj_dofs_nostab) - uh_nostab,ph_nostab = xh_nostab - euh_nostab = uex-uh_nostab - eph_nostab = pex-ph_nostab - edivuh_nostab = divuex-(∇⋅uh_nostab) - norm_euh_nostab = sum(∫(euh_nostab⋅euh_nostab)*dΩcut) - norm_eph_nostab = sum(∫(eph_nostab*eph_nostab)*dΩcut) - edivuh_nostab = sum(∫(edivuh_nostab⋅edivuh_nostab)*dΩcut) -else - println("Singular exception is raised as error when solving the system (as cond= $cond_nostab is high?)") -end -# k=0 yields euh = 1.2e-32, eph = 0.00017, edivuh = 6.8e-30, κ= 3.15e32 -# k=0 yields euh = ?, eph = ?, edivuh = ?, κ= 4.3e36 - -## U + P STABILIZATION -# Add the bulk penalty stabilization terms for u and p to wrc -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) - -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) - -# Check the condition number when only the p and u stabilization terms are included. -Aupstab=assemble_matrix(assem, wrc) -cond_upstab = cond(Array(Aupstab)) - -# CHECK errors when only the p and u stabilization terms are included. -global_l2_proj_dofs_upstab = Aupstab\b -xh_upstab = FEFunction(X, global_l2_proj_dofs_upstab) -uh_upstab,ph_upstab = xh_upstab -euh_upstab = uex-uh_upstab -eph_upstab = pex-ph_upstab -edivuh_upstab = divuex-(∇⋅uh_upstab) -norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩcut) -norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩcut) -norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩcut) -# k=0 yields euh = 6.3e-31, eph = 0.00055, edivuh = 2.4e-28, κ= 11492 -# k=2 yields euh = 5.3e-22, eph = 3.0e-18, edivuh = 3.0e-18, κ= 1.7e11 - -## +DIVU STABILIZATION -## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) -# Manually set up the arrays that collect_cell_matrix would return automatically -w_divu = [] -r_divu = [] -c_divu = [] - -## (I) Let's set up the div_dv_div_du_mat_contribs (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells -div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) -if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) -end +## TESTING THE PROJECTION of a FE function + + +# writevtk(Ωhact,"output" , cellfields=["div_u"=>∇⋅uh,"pproj"=>testFEfunction]) -push!(w_divu, div_dv_div_du_mat_contribs) -push!(r_divu, U_Ωagg_cell_dof_ids) -push!(c_divu, U_Ωagg_cell_dof_ids) +function divergence_in_pressure_space_fe_function(uh::Gridap.FESpaces.SingleFieldFEFunction,P,dq) + dq_data = Gridap.CellData.get_data(_get_single_field_fe_basis(dq)) + div_dv = ∇⋅(uh) ## We should be fine here. + pdofs=Gridap.FESpaces.get_fe_dof_basis(P) -## Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩ_agg_cells + # DoFs of the FEFunction cell-wise + div_dv_pdofs_values_cell_wise=pdofs(div_dv) + + # Gather cell-wise DoFs into global DoFs vector + div_dv_pdofs_values=Vector{Float64}(undef, num_free_dofs(P)) + Gridap.FESpaces.gather_free_values!(div_dv_pdofs_values,P,div_dv_pdofs_values_cell_wise) + + # free_dof_values is actually a global DoFs vector (!!!) + FEFunction(P,div_dv_pdofs_values) +end +testxh=FEFunction(X, rand(num_free_dofs(X))) +testuh,testph = testxh +testFEfunction = divergence_in_pressure_space_fe_function(testuh,P, dq) +eh = testFEfunction-(∇⋅testuh) +norm_testFEfunction = sum(∫(eh⋅eh)dΩhact) + +# TODO: the following functions should be tested and can then replace the lines below these commented lines. +# function divergence_in_pressure_space_basis(uh::FEBasis,P,dq) +# dq_data = Gridap.CellData.get_data(_get_single_field_fe_basis(dq)) +# div_dv = ∇⋅(_get_single_field_fe_basis(uh)) +# pdofs=Gridap.FESpaces.get_fe_dof_basis(P) +# div_dv_pdofs_values=pdofs(div_dv) +# div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, +# div_dv_pdofs_values, +# dq_data) +# if (Gridap.FESpaces.BasisStyle(uh)==Gridap.FESpaces.TrialBasis()) +# div_dv_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) +# end +# div_dv_in_pressure_space_single_field= +# Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, +# get_triangulation(P), +# BasisStyle(uh), +# Gridap.CellData.ReferenceDomain()) +# div_dv_in_pressure_space= +# Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) +# end div_dv=∇⋅(_get_single_field_fe_basis(dv)) pdofs=Gridap.FESpaces.get_fe_dof_basis(P) div_dv_pdofs_values=pdofs(div_dv) @@ -659,91 +523,32 @@ div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv get_triangulation(P), Gridap.FESpaces.TestBasis(), Gridap.CellData.ReferenceDomain()) -div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) - -div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) -div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, - get_triangulation(P), - Gridap.FESpaces.TrialBasis(), - Gridap.CellData.ReferenceDomain()) -div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) - -div_dv_div_du_in_pressure_space_mat_contribs=get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? -div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs - ### Compute Π_Q_bb(div_du) -dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) -agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) -# agg_cells_rhs_contribs[1] -ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) -rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) -div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - -# Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate -div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(qbb)) - -div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - -div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) +dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) -if (_is_multifield_fe_basis_component(dp)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - div_du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - div_du_l2_proj_bb_array_agg_cells) -end +# OLD ROUTINE: +# agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) +# ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) ## TODO: prep to assemble vectors +# rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) +test_agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅testFEfunction)dΩagg_cells) +test_ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,test_agg_cells_rhs_contribs) +test_rhs=lazy_map(test_ass_rhs_map,aggregate_to_local_cells) -div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) +test_div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,test_rhs) -# In the MultiField case, I have had to add this change domain -# call before setting up the term right below. Otherwise, we get an error -# when trying to multiply the fields. Not sure why this is happening -# dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) -div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) +# TODO: can be removed if we fix the BulkGhostPenaltyAssembleRhsMap. +# transposed_test_div_dv_l2_proj_bb_dofs= lazy_map(x->collect(reshape(x,(size(x,1)))),lazy_map(transpose,test_div_dv_l2_proj_bb_dofs)) -proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) - -P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) +test_div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + transposed_test_div_dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(qbb)) +test_div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(test_div_dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) +div_uh_proj_bb=Gridap.CellData.GenericCellField(test_div_dv_l2_proj_bb_array_agg_cells,dΩagg_cells.quad.trian,ReferenceDomain()) -if (_is_multifield_fe_basis_component(dp)) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - P_agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_agg_cells_to_aggregate_dof_ids) -end +x=get_cell_points(dΩagg_cells.quad.trian) +div_uh_proj_bb(x)[1] -push!(w_divu, proj_div_dv_div_du_mat_contribs) -push!(r_divu, U_Ωagg_cell_dof_ids) # test -push!(c_divu, P_agg_cells_to_aggregate_dof_ids) # trial - -## Now add div stabilization to A -push!(wrc[1], w_divu...) -push!(wrc[2], r_divu...) -push!(wrc[3], c_divu...) - -# Assembly -Awithstab=assemble_matrix(assem, wrc) -cond_withstab = cond(Array(Awithstab)) - -global_l2_proj_dofs_withstab = Awithstab\b -xh_withstab = FEFunction(X, global_l2_proj_dofs_withstab) -uh_withstab,ph_withstab = xh_withstab -euh_withstab = uex-uh_withstab -eph_withstab = pex-ph_withstab -edivuh_withstab = divuex-(∇⋅uh_withstab) -norm_euh_withstab = sum(∫(euh_withstab⋅euh_withstab)*dΩcut) -norm_eph_withstab = sum(∫(eph_withstab*eph_withstab)*dΩcut) -norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) -# k=0 yields euh = 0.0014, eph = 0.47, edivuh = 0.47, κ= 8.51e11 -# k=2 yields euh = 0.00013, eph = 0.088, edivuh = 0.088, κ= 2.9e14 \ No newline at end of file +res = testFEfunction - div_uh_proj_bb +norm = sum(∫((res)*(res))*dΩagg_cells) \ No newline at end of file From 9f1b91ebf9e20a1a10304dd8fb8e8c728bdb4950 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 8 Nov 2024 17:43:30 +1100 Subject: [PATCH 025/120] selecting cut cells --- ...host_penalty_canvas_selecting_cut_cells.jl | 349 ++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 bulk_ghost_penalty_canvas_selecting_cut_cells.jl diff --git a/bulk_ghost_penalty_canvas_selecting_cut_cells.jl b/bulk_ghost_penalty_canvas_selecting_cut_cells.jl new file mode 100644 index 00000000..1d4d7235 --- /dev/null +++ b/bulk_ghost_penalty_canvas_selecting_cut_cells.jl @@ -0,0 +1,349 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +divuex(x) = -4.0 + +# Select geometry +R = 0.2 +geom = disk(R, x0=Point(0.5,0.5)) + +# Setup background model +n=16 +partition = (n,n) +box = get_metadata(geom) +bgmodel = CartesianDiscreteModel((0,1,0,1),partition) +dp = box.pmax - box.pmin +h = dp[1]/n + +# Cut the background model with the mesh +cutgeo = cut(bgmodel,geom) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +#INVESTIGATING: Number of aggregates, cells and bg cells. +@assert length(aggregates) == n*n +num_cell = length(aggregates) +using StatsBase +counts = countmap(aggregates,alg=:dict) +agg_counts = filter(((k,v),) -> v > 1 && k != 0, counts) +num_aggregates = length(agg_counts) +num_cells_in_aggregates = 0 +for (k,v) in agg_counts + println(v) + num_cells_in_aggregates +=v +end +num_cells_not_in_aggregates = counts[0] +non_agg_counts = filter(((k,v),) -> v <= 1 || k==0, counts) +num_cells_not_in_aggregates = 0 +for (k,v) in non_agg_counts + println(v) + num_cells_not_in_aggregates +=v +end +num_ext_cells = counts[0] +@assert num_cells_in_aggregates + num_cells_not_in_aggregates == num_cell +println("Out of the $num_cell cells, $num_cells_in_aggregates belong to aggregates and $num_cells_not_in_aggregates are not part of aggregates. Note that we have $num_ext_cells exterior cells") +println("Assuming that there is one root per aggregate, we have $(num_cells_in_aggregates-num_aggregates) cut cells and $num_aggregates roots in the $num_aggregates aggregates cotntaining $num_cells_in_aggregates in total.") + +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cells in the background + model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_aggregate_to_cells(aggregates) + + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]>1) + if !haskey(touched,agg) + push!(aggregate_to_cells,[i]) + touched[agg]=current_aggregate + current_aggregate+=1 + else + push!(aggregate_to_cells[touched[agg]],i) + end + end + end + end + aggregate_to_cells +end + +""" + Creates an array of arrays with as many entries + as interior cells that are not part of any aggegrate. + For each interior cell, the array + contains the global cell IDs of that cells in the background + model that belong to the same interior cell + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_int_nonagg_cell_to_cells(aggregates) + + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + interior_cell_to_cells=Vector{Vector{Int}}() + current_interior_cell=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]==1) + if !haskey(touched,agg) + push!(interior_cell_to_cells,[i]) + touched[agg]=current_interior_cell + current_interior_cell+=1 + else + push!(interior_cell_to_cells[touched[agg]],i) + end + end + end + end + interior_cell_to_cells +end + + +function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) + g=get_grid(bgmodel) + cell_coords=get_cell_coordinates(g) + D=num_dims(bgmodel) + xmin=Vector{Float64}(undef,D) + xmax=Vector{Float64}(undef,D) + + # Compute coordinates of the nodes defining the bounding boxes + bounding_box_node_coords= + Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) + ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] + data = collect(1:length(bounding_box_node_coords)) + bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) + for (agg,cells) in enumerate(aggregate_to_cells) + p=first(cell_coords[cells[1]]) + for i in 1:D + xmin[i]=p[i] + xmax[i]=p[i] + end + for cell in cells + for p in cell_coords[cell] + for i in 1:D + xmin[i]=min(xmin[i],p[i]) + xmax[i]=max(xmax[i],p[i]) + end + end + end + bounds = [(xmin[i], xmax[i]) for i in 1:D] + point_iterator = Iterators.product(bounds...) + bounding_box_node_coords[bounding_box_node_ids[agg]] = + reshape([Point(p...) for p in point_iterator],2^D) + end + + # Set up the discrete model of bounding boxes + HEX_AXIS=1 + polytope=Polytope(Fill(HEX_AXIS,D)...) + scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) + cell_types=fill(1,length(bounding_box_node_ids)) + cell_reffes=[scalar_reffe] + grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, + bounding_box_node_ids, + cell_reffes, + cell_types, + Gridap.Geometry.Oriented()) + Gridap.Geometry.UnstructuredDiscreteModel(grid) +end + +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# colors = color_aggregates(aggregates,bgmodel) +# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) +# writevtk(aggregates_bounding_box_model, "bb_model") +# writevtk(bgmodel, "bg_model") + +""" + Changes the domain of a trial/test basis defined on + the reference space of bounding boxes to the reference + space of the agg cells + + TO-DO: in the future, for system of PDEs (MultiField) we should + also take care of blocks (BlockMap) +""" +function change_domain_bb_to_agg_cells(basis_bb, + ref_agg_cell_to_ref_bb_map, + Ω_agg_cells, + agg_cells_to_aggregate) + @assert num_cells(Ω_agg_cells)==length(ref_agg_cell_to_ref_bb_map) + @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() + bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) + bb_basis_array = Gridap.CellData.get_data(basis_bb) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Remove transpose map; we will add it later + @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) + @assert isa(bb_basis_array.maps,Fill) + @assert isa(bb_basis_array.maps.value,typeof(transpose)) + bb_basis_array=bb_basis_array.args[1] + end + + bb_basis_array_to_Ω_agg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) + bb_basis_array_to_Ω_agg_cells_array = lazy_map(Broadcasting(∘), + bb_basis_array_to_Ω_agg_cells_array, + ref_agg_cell_to_ref_bb_map) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Add transpose + bb_basis_array_to_Ω_agg_cells_array=lazy_map(transpose, bb_basis_array_to_Ω_agg_cells_array) + end + + Gridap.CellData.GenericCellField(bb_basis_array_to_Ω_agg_cells_array, + Ω_agg_cells, + ReferenceDomain()) +end + +# Generate an array with the global IDs of the cells +# that belong to an aggregrate. From now on, we will +# use the terminology "agg_cells" to refer to those +# cells of the background model that belong to an aggregate +# (i.e., they can be either cut or interior cells) +agg_cells=Vector{Int}() +for cells in aggregate_to_cells + append!(agg_cells,cells) +end + +# Generate an array with the global IDs of the cells +# that belong to the interior, yet do not belong to the +# aggregate. We will use "int_nonagg_cells" to refer to those +# cells of the background model that belong to the interior +# but are not part of any of the aggregates. +int_nonagg_cells=Vector{Int}() +for cell in int_nonagg_cell_to_cells + append!(int_nonagg_cells,cell) +end + +#INSPECTION +# agg_cells +# int_nonagg_cells +# aggregates + +## Triangulation +Ωbg = Triangulation(bgmodel) +Ω = Triangulation(cutgeo,PHYSICAL) +Ωact = Triangulation(cutgeo,ACTIVE) +Ωcut = Triangulation(cutgeo) + +# Interior cells +Ωbg_agg_cells = view(Ωbg,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface +# construct the interior aggregate cells, in other words the root cells +root_cells=Vector{Int}() +tester_int_nonagg_cells=Vector{Int}() +for cell in int_cells + if cell ∈ int_nonagg_cells + append!(tester_int_nonagg_cells,cell) + else + append!(root_cells,cell) + end +end +@assert(tester_int_nonagg_cells==int_nonagg_cells) +# Cut cells +cut_cells=Vector{Int}() +tester_root_cells=Vector{Int}() +for cell in agg_cells + if cell ∈ root_cells + append!(tester_root_cells,cell) + else + append!(cut_cells,cell) + end +end +@assert(tester_root_cells==root_cells) + + +# TODO Potentially useful?: +# Ω_agg_cells.parent.a.subgrid.cell_node_ids.data == Ω.a.subgrid.cell_node_ids.data # vector containing cell ids + +# Subdomains in background mesh (aggegrate cells are already defined) +Ωbg_int_cells = view(Ωbg,int_cells) # cells in interior +Ωbg_int_nonagg_cells = view(Ωbg,int_nonagg_cells) # cells in interior but not in aggregate +Ωbg_root_cells = view(Ωbg,root_cells) # root cells: in interior and part of aggregate +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) + +# Subdomains in physical mesh +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +Ω_int_cells = view(Ω,int_cells) # cells in interior +Ω_int_nonagg_cells = view(Ω,int_nonagg_cells) # cells in interior but not in aggregate +Ω_root_cells = view(Ω,root_cells) # root cells: in interior and part of aggregate +Ω_cut_cells = view(Ω,cut_cells) # cut cells (part of aggregate) + +## VISUALISATION: +writevtk(Ωbg,"trian_bg") +writevtk(Ωbg_agg_cells,"trian_bg_agg_cells") +writevtk(Ωbg_int_cells,"trian_bg_int_cells") +writevtk(Ωbg_int_nonagg_cells,"trian_bg_int_nonagg_cells") +writevtk(Ωbg_root_cells,"trian_bg_root_cells") +writevtk(Ωbg_cut_cells,"trian_bg_cut_cells") + +writevtk(Ωact,"trian_act") +writevtk(Ω,"trian_phys") +#TODO: WHY DOESN'T THIS WORK? +# writevtk(Ω_agg_cells,"trian_phys_agg_cells") +# writevtk(Ω_int_cells,"trian_phys_int_cells") +# writevtk(Ω_int_nonagg_cells,"trian_phys_int_nonagg_cells") +# writevtk(Ω_root_cells,"trian_phys_root_cells") +# writevtk(Ω_cut_cells,"trian_phys_cut_coot_cells") +degree = 2*2*order +dΩ = Measure(Ω,degree) +dΩact = Measure(Ωact,degree) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) +dΩbg_root_cells = Measure(Ωbg_root_cells,degree) + + +dΩ_agg_cells = Measure(Ω_agg_cells,degree) +dΩcut_cells = Measure(Ω_cut_cells,degree) +dΩroot_cells = Measure(Ω_root_cells,degree) + +# TESTING +area_phys_domain = sum(∫(1.0)dΩ) +area_act_domain = sum(∫(1.0)dΩact) +area_agg_cells = sum(∫(1.0)dΩbg_agg_cells) +area_cut_cells = sum(∫(1.0)dΩbg_cut_cells) +area_root_cells = sum(∫(1.0)dΩbg_root_cells) +@assert(area_agg_cells ≈ area_cut_cells + area_root_cells) + +# TODO: not possible to integrate over the physical part of the domain, e.g. +area_phys_agg_cells = sum(∫(1.0)dΩ_agg_cells) +area_phys_cut_cells = sum(∫(1.0)dΩ_cut_cells) +area_phys_root_cells = sum(∫(1.0)dΩ_root_cells) \ No newline at end of file From 39cb26c36712a6846465222a0b594ad671ed1040 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 8 Nov 2024 17:58:40 +1100 Subject: [PATCH 026/120] A check failed error. Seems no longer need for the transpose/reshape as this has been fixed by changing the BulkGhostPenaltyAssembleRhsMap. --- BulkGhostPenaltyAssembleMaps.jl | 2 +- bulk_ghost_penalty_canvas_towardsdiv.jl | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/BulkGhostPenaltyAssembleMaps.jl b/BulkGhostPenaltyAssembleMaps.jl index 628d87b4..e18749a1 100644 --- a/BulkGhostPenaltyAssembleMaps.jl +++ b/BulkGhostPenaltyAssembleMaps.jl @@ -57,7 +57,7 @@ function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleRhsMap,aggrega Gridap.Arrays.setsize!(result,(size(contrib,1),max_local_dof_id)) else @assert rank==1 - Gridap.Arrays.setsize!(result,max_local_dof_id) + Gridap.Arrays.setsize!(result,(max_local_dof_id,)) end result.array .= 0.0 for (i,cell) in enumerate(aggregate_local_cells) diff --git a/bulk_ghost_penalty_canvas_towardsdiv.jl b/bulk_ghost_penalty_canvas_towardsdiv.jl index a66474b6..d6cc4006 100644 --- a/bulk_ghost_penalty_canvas_towardsdiv.jl +++ b/bulk_ghost_penalty_canvas_towardsdiv.jl @@ -538,9 +538,12 @@ test_div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,test_rhs) # TODO: can be removed if we fix the BulkGhostPenaltyAssembleRhsMap. # transposed_test_div_dv_l2_proj_bb_dofs= lazy_map(x->collect(reshape(x,(size(x,1)))),lazy_map(transpose,test_div_dv_l2_proj_bb_dofs)) +# test_div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, +# transposed_test_div_dv_l2_proj_bb_dofs, +# Gridap.CellData.get_data(qbb)) test_div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - transposed_test_div_dv_l2_proj_bb_dofs, + test_div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) test_div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), lazy_map(Reindex(test_div_dv_l2_proj_bb_array),agg_cells_to_aggregate), From 5af2a2b9e7b762576dbb0dca05a64cb2bfcb165d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 11 Nov 2024 15:32:35 +1100 Subject: [PATCH 027/120] Revised some of the changes --- .../DistributedDiscreteGeometries.jl | 57 +++++++------------ src/Distributed/DistributedDiscretizations.jl | 43 +++++++------- src/LevelSetCutters/DiscreteGeometries.jl | 38 +++---------- 3 files changed, 51 insertions(+), 87 deletions(-) diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index 935e3b90..0e1b6021 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -4,41 +4,28 @@ end local_views(a::DistributedDiscreteGeometry) = a.geometries +# TODO: Is this really necessary? function _get_values_at_owned_coords(φh,model::DistributedDiscreteModel{Dc,Dp}) where {Dc,Dp} @assert DomainStyle(φh) == ReferenceDomain() gids = get_cell_gids(model) values = map(local_views(φh),local_views(model),local_views(gids)) do φh, model, gids - # Maps from the no-ghost model to the original model own_model = remove_ghost_cells(model,gids) - own_to_local_node = get_face_to_parent_face(own_model,0) - local_to_own_node = find_inverse_index_map(own_to_local_node,num_nodes(model)) - own_to_local_cell = get_face_to_parent_face(own_model,Dc) - - # Cell-to-node map for the original model - # topo = get_grid_topology(model) - # c2n_map = get_faces(topo,Dc,0) - c2n_map = collect1d(get_cell_node_ids(model)) - - # Cell-wise node coordinates (in ReferenceDomain coordinates) - cell_reffe = get_cell_reffe(model) - cell_node_coords = lazy_map(get_node_coordinates,cell_reffe) - - φh_data = CellData.get_data(φh) - T = return_type(testitem(CellData.get_data(φh)),testitem(testitem(cell_node_coords))) + own_cells = get_face_to_parent_face(own_model,Dc) + + trian = get_triangulation(φh) + cell_points = get_cell_points(trian) + cell_ids = get_cell_node_ids(own_model) + cell_values = φh(cell_points) + + T = eltype(testitem(cell_values)) values = Vector{T}(undef,num_nodes(own_model)) - touched = fill(false,num_nodes(model)) - cell_node_coords_cache = array_cache(cell_node_coords) - for cell in own_to_local_cell # For each owned cell - field = φh_data[cell] - node_coords = getindex!(cell_node_coords_cache,cell_node_coords,cell) - for (iN,node) in enumerate(c2n_map[cell]) # Go over local nodes - own_node = local_to_own_node[node] - if (own_node != 0) && !touched[node] # Compute value if suitable - values[own_node] = field(node_coords[iN]) - touched[node] = true - end - end + cell_ids_cache = array_cache(cell_ids) + cell_values_cache = array_cache(cell_values) + for (ocell,cell) in enumerate(own_cells) + ids = getindex!(cell_ids_cache,cell_ids,ocell) + vals = getindex!(cell_values_cache,cell_values,cell) + values[ids] .= vals end return values end @@ -56,7 +43,7 @@ function DiscreteGeometry(φh::CellField,model::DistributedDiscreteModel;name::S DistributedDiscreteGeometry(geometries) end -function get_geometry(a::AbstractArray{<:DiscreteGeometry}) +function distributed_geometry(a::AbstractArray{<:DiscreteGeometry}) DistributedDiscreteGeometry(a) end @@ -104,8 +91,8 @@ function distributed_embedded_triangulation( T, cutgeo::DistributedEmbeddedDiscretization, cutinorout, - geom::DistributedDiscreteGeometry) - + geom::DistributedDiscreteGeometry +) trians = map(local_views(cutgeo),local_views(geom)) do lcutgeo,lgeom T(lcutgeo,cutinorout,lgeom) end @@ -117,8 +104,8 @@ function distributed_aggregate( strategy::AggregateCutCellsByThreshold, cut::DistributedEmbeddedDiscretization, geo::DistributedDiscreteGeometry, - in_or_out=IN) - + in_or_out = IN +) bgmodel = get_background_model(cut) facet_to_inoutcut = compute_bgfacet_to_inoutcut(bgmodel,geo) _distributed_aggregate_by_threshold(strategy.threshold,cut,geo,in_or_out,facet_to_inoutcut) @@ -133,8 +120,8 @@ end function compute_bgfacet_to_inoutcut( cutter::Cutter, bgmodel::DistributedDiscreteModel, - geo::DistributedDiscreteGeometry) - + geo::DistributedDiscreteGeometry +) gids = get_cell_gids(bgmodel) bgf_to_ioc = map(local_views(bgmodel),local_views(gids),local_views(geo)) do model,gids,geo ownmodel = remove_ghost_cells(model,gids) diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index 9ae968cf..8bb2d6e4 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -3,11 +3,12 @@ struct DistributedEmbeddedDiscretization{A,B} <: GridapType discretizations::A model::B function DistributedEmbeddedDiscretization( - d::AbstractArray{<:AbstractEmbeddedDiscretization}, - model::DistributedDiscreteModel) - A = typeof(d) + discretizations::AbstractArray{<:AbstractEmbeddedDiscretization}, + model::DistributedDiscreteModel + ) + A = typeof(discretizations) B = typeof(model) - new{A,B}(d,model) + new{A,B}(discretizations,model) end end @@ -16,12 +17,13 @@ local_views(a::DistributedEmbeddedDiscretization) = a.discretizations get_background_model(a::DistributedEmbeddedDiscretization) = a.model function get_geometry(a::DistributedEmbeddedDiscretization) - loc_geometries = map(get_geometry,local_views(a)) - get_geometry(loc_geometries) + geometries = map(get_geometry,local_views(a)) + distributed_geometry(geometries) end -function get_geometry(a::AbstractArray{<:CSG.Geometry}) - PartitionedArrays.getany(a) +# Neeed for dispatching between analytical geometries and distributed geometries +function distributed_geometry(geometries::AbstractArray{<:CSG.Geometry}) + PartitionedArrays.getany(geometries) end function cut(bgmodel::DistributedDiscreteModel,args...) @@ -127,8 +129,8 @@ end function compute_bgfacet_to_inoutcut( cutter::Cutter, bgmodel::DistributedDiscreteModel, - geo) - + geo +) gids = get_cell_gids(bgmodel) bgf_to_ioc = map(local_views(bgmodel),local_views(gids)) do model,gids ownmodel = remove_ghost_cells(model,gids) @@ -243,12 +245,11 @@ function change_bgmodel( DistributedEmbeddedDiscretization(cuts,model) end - function _change_bgmodels( cutgeo::DistributedEmbeddedDiscretization, model::DistributedDiscreteModel, - cell_to_newcell) - + cell_to_newcell +) map(local_views(cutgeo),local_views(model),cell_to_newcell) do c,m,c_to_nc change_bgmodel(c,m,c_to_nc) end @@ -256,8 +257,8 @@ end function _change_bgmodels( cutgeo::DistributedEmbeddedDiscretization, - model::DistributedDiscreteModel) - + model::DistributedDiscreteModel +) map(local_views(cutgeo),local_views(model)) do c,m change_bgmodel(c,m) end @@ -266,8 +267,8 @@ end function change_bgmodel( cut::EmbeddedDiscretization, newmodel::DiscreteModel, - cell_to_newcell=1:num_cells(get_background_model(cut))) - + cell_to_newcell=1:num_cells(get_background_model(cut)) +) ls_to_bgc_to_ioc = map(cut.ls_to_bgcell_to_inoutcut) do bgc_to_ioc new_bgc_to_ioc = Vector{Int8}(undef,num_cells(newmodel)) new_bgc_to_ioc[cell_to_newcell] = bgc_to_ioc @@ -289,10 +290,9 @@ end function change_bgmodel( cut::EmbeddedFacetDiscretization, newmodel::DiscreteModel, - facet_to_newfacet=1:num_facets(get_background_model(cut))) - + facet_to_newfacet=1:num_facets(get_background_model(cut)) +) nfacets = num_facets(newmodel) - ls_to_bgf_to_ioc = map(cut.ls_to_facet_to_inoutcut) do bgf_to_ioc new_bgf_to_ioc = Vector{Int8}(undef,nfacets) new_bgf_to_ioc[facet_to_newfacet] = bgf_to_ioc @@ -305,7 +305,8 @@ function change_bgmodel( subfacets, cut.ls_to_subfacet_to_inout, cut.oid_to_ls, - cut.geo) + cut.geo + ) end function change_bgmodel(cells::SubCellData,cell_to_newcell) diff --git a/src/LevelSetCutters/DiscreteGeometries.jl b/src/LevelSetCutters/DiscreteGeometries.jl index 23d8cbe4..472fa278 100644 --- a/src/LevelSetCutters/DiscreteGeometries.jl +++ b/src/LevelSetCutters/DiscreteGeometries.jl @@ -34,7 +34,6 @@ function discretize(a::AnalyticalGeometry,point_to_coords::AbstractArray{<:Point end function discretize(a::AnalyticalGeometry,point_to_coords::Vector{<:Point}) - tree = get_tree(a) j_to_fun, oid_to_j = _find_unique_leaves(tree) j_to_ls = [ fun.(point_to_coords) for fun in j_to_fun ] @@ -48,13 +47,10 @@ function discretize(a::AnalyticalGeometry,point_to_coords::Vector{<:Point}) end newtree = replace_data(identity,conversion,tree) - DiscreteGeometry(newtree,point_to_coords) - end function _find_unique_leaves(tree) - i_to_fun = map(n->first(n.data),collect(Leaves(tree))) i_to_oid = map(objectid,i_to_fun) j_to_oid = unique(i_to_oid) @@ -65,31 +61,6 @@ function _find_unique_leaves(tree) j_to_fun, oid_to_j end -function _get_value_at_coords(φh::CellField,model::DiscreteModel{Dc,Dp}) where {Dc,Dp} - @assert DomainStyle(φh) == ReferenceDomain() - # Cell-to-node map for the original model - c2n_map = collect1d(get_cell_node_ids(model)) - - # Cell-wise node coordinates (in ReferenceDomain coordinates) - cell_reffe = get_cell_reffe(model) - cell_node_coords = lazy_map(get_node_coordinates,cell_reffe) - - # Get cell data - φh_data = CellData.get_data(φh) - T = return_type(testitem(CellData.get_data(φh)),testitem(testitem(cell_node_coords))) - values = Vector{T}(undef,num_nodes(model)) - cell_node_coords_cache = array_cache(cell_node_coords) - # Loop over cells - for cell in eachindex(c2n_map) - field = φh_data[cell] - node_coords = getindex!(cell_node_coords_cache,cell_node_coords,cell) - for (iN,node) in enumerate(c2n_map[cell]) - values[node] = field(node_coords[iN]) - end - end - return values -end - function DiscreteGeometry( point_to_value::AbstractVector,point_to_coords::AbstractVector;name::String="") data = (point_to_value,name,nothing) @@ -97,9 +68,14 @@ function DiscreteGeometry( DiscreteGeometry(tree,point_to_coords) end +# TODO: This assumes that the level set φh is 1st order, i.e that there is a 1-to-1 correspondence +# between nodes in the mesh and dofs in φh. +# Even if we allowed higher order, the cuts are always linear. Not only it would be a waste +# of time to use higher order, but cuts could actually be wrong. +# This might be developped in the future. function DiscreteGeometry( φh::CellField,model::DiscreteModel;name::String="") - point_to_value = _get_value_at_coords(φh,model) + point_to_value = get_free_dof_values(φh) point_to_coords = collect1d(get_node_coordinates(model)) DiscreteGeometry(point_to_value,point_to_coords;name) -end \ No newline at end of file +end From f04cbcbb90995be46d8b45aa5364917e45bc9e7e Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 11 Nov 2024 15:38:24 +1100 Subject: [PATCH 028/120] Minor --- src/Distributed/DistributedDiscretizations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index 8bb2d6e4..e7a8aa1b 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -21,7 +21,7 @@ function get_geometry(a::DistributedEmbeddedDiscretization) distributed_geometry(geometries) end -# Neeed for dispatching between analytical geometries and distributed geometries +# Needed for dispatching between analytical geometries and discrete geometries function distributed_geometry(geometries::AbstractArray{<:CSG.Geometry}) PartitionedArrays.getany(geometries) end From 5d31c824215c0bb3d2ec18d949a665ce956a1be0 Mon Sep 17 00:00:00 2001 From: Jordi Manyer Fuertes Date: Tue, 12 Nov 2024 08:01:39 +1100 Subject: [PATCH 029/120] Update NEWS.md --- NEWS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS.md b/NEWS.md index bb65c903..7d7bb3a4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,12 @@ 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). +## [Unreleased] + +### Added + +- Added support for distributed level-set geometries. Since PR[#99](https://github.com/gridap/GridapEmbedded.jl/pull/99). + ## [0.9.5] - 2024-10-18 ### Added From 5a5acc393dfa88de7df7a90f8b60cf18715db262 Mon Sep 17 00:00:00 2001 From: "Alberto F. Martin" Date: Thu, 14 Nov 2024 09:02:01 +1100 Subject: [PATCH 030/120] Solved error in the BB space projection of the divergence of a flux FE function --- BulkGhostPenaltyAssembleMaps.jl | 41 ++++++++++++++++--------- bulk_ghost_penalty_canvas_towardsdiv.jl | 27 ++++++++-------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/BulkGhostPenaltyAssembleMaps.jl b/BulkGhostPenaltyAssembleMaps.jl index e18749a1..9c85630e 100644 --- a/BulkGhostPenaltyAssembleMaps.jl +++ b/BulkGhostPenaltyAssembleMaps.jl @@ -26,7 +26,6 @@ function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleLhsMap,cells) end result.array end -#TODO: add {RANK,A,B} struct BulkGhostPenaltyAssembleRhsMap{A,B} <: Gridap.Fields.Map agg_cells_local_dof_ids::A agg_cells_rhs_contribs::B @@ -35,8 +34,7 @@ end function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleRhsMap,aggregate_local_cells) cache_agg_cells_local_dof_ids=array_cache(m.agg_cells_local_dof_ids) cache_unassembled_rhs=array_cache(m.agg_cells_rhs_contribs) - rank=length(size(m.agg_cells_rhs_contribs[1])) - evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),rank) + evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),2) cache_agg_cells_local_dof_ids,cache_unassembled_rhs,evaluate_result end @@ -52,24 +50,37 @@ function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleRhsMap,aggrega end end - rank=length(size(result)) - if rank==2 - Gridap.Arrays.setsize!(result,(size(contrib,1),max_local_dof_id)) - else - @assert rank==1 - Gridap.Arrays.setsize!(result,(max_local_dof_id,)) - end + Gridap.Arrays.setsize!(result,(size(contrib,1),max_local_dof_id)) + result.array .= 0.0 for (i,cell) in enumerate(aggregate_local_cells) current_cell_local_dof_ids = getindex!(cache_agg_cells_local_dof_ids,m.agg_cells_local_dof_ids,cell) contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,cell) for (j,local_dof) in enumerate(current_cell_local_dof_ids) - if rank==2 - result.array[:,local_dof] += contrib[:,j] - else - result.array[local_dof] += contrib[j] - end + result.array[:,local_dof] += contrib[:,j] end end result.array end + +struct BulkGhostPenaltyAssembleRhsFEFunctionMap{A} <: Gridap.Fields.Map + agg_cells_rhs_contribs::A +end + +function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleRhsFEFunctionMap,aggregate_local_cells) + cache_unassembled_rhs=array_cache(m.agg_cells_rhs_contribs) + evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),1) + cache_unassembled_rhs,evaluate_result +end + +function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleRhsFEFunctionMap,aggregate_local_cells) + cache_unassembled_rhs,result=cache + contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,1) + Gridap.Arrays.setsize!(result,(size(contrib,1),)) + result.array .= 0.0 + for (i,cell) in enumerate(aggregate_local_cells) + contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,cell) + result.array .+= contrib + end + result.array +end \ No newline at end of file diff --git a/bulk_ghost_penalty_canvas_towardsdiv.jl b/bulk_ghost_penalty_canvas_towardsdiv.jl index d6cc4006..05a395c3 100644 --- a/bulk_ghost_penalty_canvas_towardsdiv.jl +++ b/bulk_ghost_penalty_canvas_towardsdiv.jl @@ -489,9 +489,9 @@ function divergence_in_pressure_space_fe_function(uh::Gridap.FESpaces.SingleFiel end testxh=FEFunction(X, rand(num_free_dofs(X))) testuh,testph = testxh -testFEfunction = divergence_in_pressure_space_fe_function(testuh,P, dq) -eh = testFEfunction-(∇⋅testuh) -norm_testFEfunction = sum(∫(eh⋅eh)dΩhact) +testdivuh_pressure = divergence_in_pressure_space_fe_function(testuh,P, dq) +eh = testdivuh_pressure-(∇⋅testuh) +@assert sum(∫(eh⋅eh)dΩhact) < 1.0e-12 # TODO: the following functions should be tested and can then replace the lines below these commented lines. # function divergence_in_pressure_space_basis(uh::FEBasis,P,dq) @@ -530,28 +530,25 @@ dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map, # agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) # ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) ## TODO: prep to assemble vectors # rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) -test_agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅testFEfunction)dΩagg_cells) -test_ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,test_agg_cells_rhs_contribs) +test_agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅testdivuh_pressure)dΩagg_cells) +test_ass_rhs_map=BulkGhostPenaltyAssembleRhsFEFunctionMap(test_agg_cells_rhs_contribs) test_rhs=lazy_map(test_ass_rhs_map,aggregate_to_local_cells) test_div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,test_rhs) -# TODO: can be removed if we fix the BulkGhostPenaltyAssembleRhsMap. -# transposed_test_div_dv_l2_proj_bb_dofs= lazy_map(x->collect(reshape(x,(size(x,1)))),lazy_map(transpose,test_div_dv_l2_proj_bb_dofs)) -# test_div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, -# transposed_test_div_dv_l2_proj_bb_dofs, -# Gridap.CellData.get_data(qbb)) - test_div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, test_div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) test_div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), lazy_map(Reindex(test_div_dv_l2_proj_bb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) -div_uh_proj_bb=Gridap.CellData.GenericCellField(test_div_dv_l2_proj_bb_array_agg_cells,dΩagg_cells.quad.trian,ReferenceDomain()) +div_uh_proj_bb=Gridap.CellData.GenericCellField(test_div_dv_l2_proj_bb_array_agg_cells, + dΩagg_cells.quad.trian, + ReferenceDomain()) x=get_cell_points(dΩagg_cells.quad.trian) -div_uh_proj_bb(x)[1] +div_uh_proj_bb(x)[8] +testdivuh_pressure(x)[7] -res = testFEfunction - div_uh_proj_bb -norm = sum(∫((res)*(res))*dΩagg_cells) \ No newline at end of file +res = testdivuh_pressure - div_uh_proj_bb +sum(∫(res*res)*dΩagg_cells) \ No newline at end of file From 3185beb8c5e2af57af4bc9009d9be659fdd455b3 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 14 Nov 2024 14:50:38 +1100 Subject: [PATCH 031/120] Started refactoring the distributed code --- src/Distributed/Distributed.jl | 13 +- .../DistributedDiscreteGeometries.jl | 114 ++---- src/Distributed/DistributedDiscretizations.jl | 375 ++++++------------ src/Interfaces/EmbeddedDiscretizations.jl | 8 +- .../EmbeddedFacetDiscretizations.jl | 2 +- 5 files changed, 156 insertions(+), 356 deletions(-) diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index ee2ea62d..e204227b 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -31,14 +31,11 @@ using Gridap.Geometry: get_face_to_parent_face using Gridap.Arrays: find_inverse_index_map, testitem, return_type using Gridap.FESpaces: FESpaceWithLinearConstraints using Gridap.FESpaces: _dof_to_DOF, _DOF_to_dof -using GridapDistributed: DistributedDiscreteModel -using GridapDistributed: DistributedTriangulation -using GridapDistributed: DistributedFESpace -using GridapDistributed: DistributedSingleFieldFESpace -using GridapDistributed: DistributedMeasure -using GridapDistributed: add_ghost_cells -using GridapDistributed: generate_gids -using GridapDistributed: generate_cell_gids + +using GridapDistributed: DistributedDiscreteModel, DistributedTriangulation, DistributedMeasure +using GridapDistributed: DistributedFESpace, DistributedSingleFieldFESpace +using GridapDistributed: NoGhost, WithGhost, filter_cells_when_needed, add_ghost_cells +using GridapDistributed: generate_gids, generate_cell_gids using GridapDistributed: _find_vector_type import GridapEmbedded.AgFEM: aggregate diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index 0e1b6021..83f96ad9 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -4,41 +4,9 @@ end local_views(a::DistributedDiscreteGeometry) = a.geometries -# TODO: Is this really necessary? -function _get_values_at_owned_coords(φh,model::DistributedDiscreteModel{Dc,Dp}) where {Dc,Dp} - @assert DomainStyle(φh) == ReferenceDomain() - gids = get_cell_gids(model) - values = map(local_views(φh),local_views(model),local_views(gids)) do φh, model, gids - own_model = remove_ghost_cells(model,gids) - own_cells = get_face_to_parent_face(own_model,Dc) - - trian = get_triangulation(φh) - cell_points = get_cell_points(trian) - cell_ids = get_cell_node_ids(own_model) - cell_values = φh(cell_points) - - T = eltype(testitem(cell_values)) - values = Vector{T}(undef,num_nodes(own_model)) - - cell_ids_cache = array_cache(cell_ids) - cell_values_cache = array_cache(cell_values) - for (ocell,cell) in enumerate(own_cells) - ids = getindex!(cell_ids_cache,cell_ids,ocell) - vals = getindex!(cell_values_cache,cell_values,cell) - values[ids] .= vals - end - return values - end - return values -end - function DiscreteGeometry(φh::CellField,model::DistributedDiscreteModel;name::String="") - φ_values = _get_values_at_owned_coords(φh,model) - gids = get_cell_gids(model) - geometries = map(local_views(model),local_views(gids),local_views(φ_values)) do model,gids,loc_φ - ownmodel = remove_ghost_cells(model,gids) - point_to_coords = collect1d(get_node_coordinates(ownmodel)) - DiscreteGeometry(loc_φ,point_to_coords;name) + geometries = map(local_views(φh),local_views(model)) do φh, model + DiscreteGeometry(φh,model;name) end DistributedDiscreteGeometry(geometries) end @@ -48,56 +16,45 @@ function distributed_geometry(a::AbstractArray{<:DiscreteGeometry}) end function discretize(a::AnalyticalGeometry,model::DistributedDiscreteModel) - gids = get_cell_gids(model) - geometries = map(local_views(model),local_views(gids)) do model,gids - ownmodel = remove_ghost_cells(model,gids) - point_to_coords = collect1d(get_node_coordinates(ownmodel)) - discretize(a,point_to_coords) + geometries = map(local_views(model)) do model + discretize(a,model) end DistributedDiscreteGeometry(geometries) end -function cut(cutter::Cutter,bgmodel::DistributedDiscreteModel,geom::DistributedDiscreteGeometry) +function cut( + cutter::Cutter,bgmodel::DistributedDiscreteModel,geom::DistributedDiscreteGeometry +) gids = get_cell_gids(bgmodel) - cuts = map(local_views(bgmodel),local_views(gids),local_views(geom)) do bgmodel,gids,geom - ownmodel = remove_ghost_cells(bgmodel,gids) - cutgeo = cut(cutter,ownmodel,geom) - change_bgmodel(cutgeo,bgmodel,own_to_local(gids)) + cuts = map(local_views(bgmodel),local_views(geom)) do bgmodel,geom + cut(cutter,bgmodel,geom) end - consistent_bgcell_to_inoutcut!(cuts,gids) + @notimplementedif !isconsistent_bgcell_to_inoutcut(cuts,partition(gids)) DistributedEmbeddedDiscretization(cuts,bgmodel) end -function cut_facets(cutter::Cutter,bgmodel::DistributedDiscreteModel,geom::DistributedDiscreteGeometry) - D = map(num_dims,local_views(bgmodel)) |> PartitionedArrays.getany - cell_gids = get_cell_gids(bgmodel) - facet_gids = get_face_gids(bgmodel,D-1) - cuts = map( - local_views(bgmodel), - local_views(cell_gids), - local_views(facet_gids), - local_views(geom)) do bgmodel,cell_gids,facet_gids,geom - ownmodel = remove_ghost_cells(bgmodel,cell_gids) - facet_to_pfacet = get_face_to_parent_face(ownmodel,D-1) - cutfacets = cut_facets(cutter,ownmodel,geom) - cutfacets = change_bgmodel(cutfacets,bgmodel,facet_to_pfacet) - remove_ghost_subfacets(cutfacets,facet_gids) +function cut_facets( + cutter::Cutter,bgmodel::DistributedDiscreteModel{Dc},geom::DistributedDiscreteGeometry +) where Dc + gids = get_face_gids(bgmodel,Dc-1) + cuts = map(local_views(bgmodel),local_views(geom)) do bgmodel,geom + cut_facets(cutter,bgmodel,geom) end - consistent_bgfacet_to_inoutcut!(cuts,facet_gids) + @notimplementedif !isconsistent_bgcell_to_inoutcut(cuts,partition(gids)) DistributedEmbeddedDiscretization(cuts,bgmodel) end -function distributed_embedded_triangulation( - T, - cutgeo::DistributedEmbeddedDiscretization, - cutinorout, - geom::DistributedDiscreteGeometry -) - trians = map(local_views(cutgeo),local_views(geom)) do lcutgeo,lgeom - T(lcutgeo,cutinorout,lgeom) +for TT in (:Triangulation,:SkeletonTriangulation,:BoundaryTriangulation,:EmbeddedBoundary) + @eval begin + function $TT(portion,cutgeo::DistributedEmbeddedDiscretization,cutinorout,geom::DistributedDiscreteGeometry) + model = get_background_model(cutgeo) + gids = get_cell_gids(model) + trians = map(local_views(cutgeo),local_views(geom),partition(gids)) do cutgeo, geom, gids + $TT(portion,gids,cutgeo,cutinorout,geom) + end + DistributedTriangulation(trians,model) + end end - bgmodel = get_background_model(cutgeo) - DistributedTriangulation(trians,bgmodel) end function distributed_aggregate( @@ -111,21 +68,18 @@ function distributed_aggregate( _distributed_aggregate_by_threshold(strategy.threshold,cut,geo,in_or_out,facet_to_inoutcut) end -function compute_bgcell_to_inoutcut(cutgeo::DistributedEmbeddedDiscretization,geo::DistributedDiscreteGeometry) - map(local_views(cutgeo),local_views(geo)) do cutgeo,geo +function compute_bgcell_to_inoutcut( + cutgeo::DistributedEmbeddedDiscretization,geo::DistributedDiscreteGeometry +) + map(local_views(cutgeo),local_views(geo)) do cutgeo, geo compute_bgcell_to_inoutcut(cutgeo,geo) end end function compute_bgfacet_to_inoutcut( - cutter::Cutter, - bgmodel::DistributedDiscreteModel, - geo::DistributedDiscreteGeometry + cutter::Cutter, bgmodel::DistributedDiscreteModel, geo::DistributedDiscreteGeometry ) - gids = get_cell_gids(bgmodel) - bgf_to_ioc = map(local_views(bgmodel),local_views(gids),local_views(geo)) do model,gids,geo - ownmodel = remove_ghost_cells(model,gids) - compute_bgfacet_to_inoutcut(cutter,ownmodel,geo) + map(local_views(bgmodel),local_views(geo)) do model, geo + compute_bgfacet_to_inoutcut(cutter,model,geo) end - compute_bgfacet_to_inoutcut(bgmodel,bgf_to_ioc) end \ No newline at end of file diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index e7a8aa1b..3c84be45 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -1,14 +1,14 @@ -struct DistributedEmbeddedDiscretization{A,B} <: GridapType +struct DistributedEmbeddedDiscretization{Dc,Dp,A,B} <: GridapType discretizations::A model::B function DistributedEmbeddedDiscretization( - discretizations::AbstractArray{<:AbstractEmbeddedDiscretization}, + discretizations::AbstractArray{<:AbstractEmbeddedDiscretization{Dc,Dp}}, model::DistributedDiscreteModel - ) + ) where {Dc,Dp} A = typeof(discretizations) B = typeof(model) - new{A,B}(discretizations,model) + new{Dc,Dp,A,B}(discretizations,model) end end @@ -30,14 +30,12 @@ function cut(bgmodel::DistributedDiscreteModel,args...) cut(LevelSetCutter(),bgmodel,args...) end -function cut(cutter::Cutter,bgmodel::DistributedDiscreteModel,args...) - gids = get_cell_gids(bgmodel) - cuts = map(local_views(bgmodel),local_views(gids)) do bgmodel,gids - ownmodel = remove_ghost_cells(bgmodel,gids) - cutgeo = cut(cutter,ownmodel,args...) - change_bgmodel(cutgeo,bgmodel,own_to_local(gids)) +function cut(cutter::Cutter,bgmodel::DistributedDiscreteModel{Dc},args...) where Dc + gids = get_face_gids(bgmodel,Dc) + cuts = map(local_views(bgmodel)) do bgmodel + cut(cutter,bgmodel,args...) end - consistent_bgcell_to_inoutcut!(cuts,gids) + @notimplementedif !isconsistent_bgcell_to_inoutcut(cuts,partition(gids)) DistributedEmbeddedDiscretization(cuts,bgmodel) end @@ -45,124 +43,51 @@ function cut_facets(bgmodel::DistributedDiscreteModel,args...) cut_facets(LevelSetCutter(),bgmodel,args...) end -function cut_facets(cutter::Cutter,bgmodel::DistributedDiscreteModel,args...) - D = map(num_dims,local_views(bgmodel)) |> PartitionedArrays.getany - cell_gids = get_cell_gids(bgmodel) - facet_gids = get_face_gids(bgmodel,D-1) - cuts = map( - local_views(bgmodel), - local_views(cell_gids), - local_views(facet_gids)) do bgmodel,cell_gids,facet_gids - ownmodel = remove_ghost_cells(bgmodel,cell_gids) - facet_to_pfacet = get_face_to_parent_face(ownmodel,D-1) - cutfacets = cut_facets(cutter,ownmodel,args...) - cutfacets = change_bgmodel(cutfacets,bgmodel,facet_to_pfacet) - remove_ghost_subfacets(cutfacets,facet_gids) +function cut_facets(cutter::Cutter,bgmodel::DistributedDiscreteModel{Dc},args...) where Dc + gids = get_face_gids(bgmodel,Dc-1) + cuts = map(local_views(bgmodel)) do bgmodel + cut_facets(cutter,bgmodel,args...) end - consistent_bgfacet_to_inoutcut!(cuts,facet_gids) + @notimplementedif !isconsistent_bgcell_to_inoutcut(cuts,partition(gids)) DistributedEmbeddedDiscretization(cuts,bgmodel) end -function Triangulation( - cutgeo::DistributedEmbeddedDiscretization, - in_or_out::ActiveInOrOut, - args...) - - distributed_embedded_triangulation(Triangulation,cutgeo,in_or_out,args...) -end - -function Triangulation(cutgeo::DistributedEmbeddedDiscretization,args...) - trian = distributed_embedded_triangulation(Triangulation,cutgeo,args...) - remove_ghost_cells(trian) -end - -function EmbeddedBoundary(cutgeo::DistributedEmbeddedDiscretization,args...) - trian = distributed_embedded_triangulation(EmbeddedBoundary,cutgeo,args...) - remove_ghost_cells(trian) -end - -function SkeletonTriangulation(cutgeo::DistributedEmbeddedDiscretization,args...) - trian = distributed_embedded_triangulation(SkeletonTriangulation,cutgeo,args...) - remove_ghost_cells(trian) -end - -function BoundaryTriangulation(cutgeo::DistributedEmbeddedDiscretization,args...) - trian = distributed_embedded_triangulation(BoundaryTriangulation,cutgeo,args...) - remove_ghost_cells(trian) -end - -function distributed_embedded_triangulation( - T, - cutgeo::DistributedEmbeddedDiscretization, - args...) +""" +Note on distributed triangulations: - trians = map(local_views(cutgeo)) do lcutgeo - T(lcutgeo,args...) - end - bgmodel = get_background_model(cutgeo) - DistributedTriangulation(trians,bgmodel) -end +- We allow for more one argument, `portion`, which allows the user to filter +some of the cells/faces. In particular, this is used to remove ghosts from the +local triangulations. +- The default for `portion` is `NoGhost()`, wich filters out all ghost cells, except +when we have the argument `in_or_out`. +""" -function compute_bgfacet_to_inoutcut( - bgmodel::DistributedDiscreteModel, - bgf_to_ioc::AbstractArray{<:AbstractVector}) - - D = num_dims(eltype(local_views(bgmodel))) - gids = get_cell_gids(bgmodel) - bgf_to_ioc = map( - local_views(bgmodel), - local_views(gids), - bgf_to_ioc) do bgmodel,gids,bgf_to_ioc - - ownmodel = remove_ghost_cells(bgmodel,gids) - f_to_pf = Gridap.Geometry.get_face_to_parent_face(ownmodel,D-1) - _bgf_to_ioc = Vector{eltype(bgf_to_ioc)}(undef,num_faces(bgmodel,D-1)) - _bgf_to_ioc[f_to_pf] .= bgf_to_ioc - _bgf_to_ioc - end - facet_gids = get_face_gids(bgmodel,D-1) - pbgf_to_ioc = PVector(bgf_to_ioc,partition(facet_gids)) - consistent!(pbgf_to_ioc) |> wait - local_values(pbgf_to_ioc) -end - -function compute_bgfacet_to_inoutcut( - cutter::Cutter, - bgmodel::DistributedDiscreteModel, - geo +function Triangulation( + cutgeo::DistributedEmbeddedDiscretization,in_or_out::ActiveInOrOut,args... ) - gids = get_cell_gids(bgmodel) - bgf_to_ioc = map(local_views(bgmodel),local_views(gids)) do model,gids - ownmodel = remove_ghost_cells(model,gids) - compute_bgfacet_to_inoutcut(cutter,ownmodel,geo) - end - compute_bgfacet_to_inoutcut(bgmodel,bgf_to_ioc) + Triangulation(WithGhost(),cutgeo,in_or_out,args...) end -function compute_bgfacet_to_inoutcut(bgmodel::DistributedDiscreteModel,args...) - cutter = LevelSetCutter() - compute_bgfacet_to_inoutcut(cutter,bgmodel,args...) -end - -function compute_bgcell_to_inoutcut(cutgeo::DistributedEmbeddedDiscretization,args...) - map(local_views(cutgeo)) do cutgeo - compute_bgcell_to_inoutcut(cutgeo,args...) - end -end +for TT in (:Triangulation,:SkeletonTriangulation,:BoundaryTriangulation,:EmbeddedBoundary) + @eval begin + function $TT(cutgeo::DistributedEmbeddedDiscretization,args...) + $TT(NoGhost(),cutgeo,args...) + end -function compute_bgfacet_to_inoutcut(cutgeo::DistributedEmbeddedDiscretization,args...) - map(local_views(cutgeo)) do cutgeo - compute_bgfacet_to_inoutcut(cutgeo,args...) - end -end + function $TT(portion,cutgeo::DistributedEmbeddedDiscretization,args...) + model = get_background_model(cutgeo) + gids = get_cell_gids(model) + trians = map(local_views(cutgeo),partition(gids)) do cutgeo, gids + $TT(portion,gids,cutgeo,args...) + end + DistributedTriangulation(trians,model) + end -function remove_ghost_cells(trian::DistributedTriangulation) - model = get_background_model(trian) - gids = get_cell_gids(model) - trians = map(local_views(trian),local_views(gids)) do trian,gids - remove_ghost_cells(trian,gids) + function $TT(portion,gids::AbstractLocalIndices,cutgeo::AbstractEmbeddedDiscretization,args...) + trian = $TT(cutgeo,args...) + filter_cells_when_needed(portion,gids,trian) + end end - DistributedTriangulation(trians,model) end function remove_ghost_cells(trian::AppendedTriangulation,gids) @@ -171,180 +96,104 @@ function remove_ghost_cells(trian::AppendedTriangulation,gids) lazy_append(a,b) end -function remove_ghost_cells(trian::SubFacetTriangulation,gids) - model = get_background_model(trian) - D = num_cell_dims(model) - glue = get_glue(trian,Val{D}()) +function remove_ghost_cells(trian::SubFacetTriangulation{Df,Dc},gids) where {Df,Dc} + glue = get_glue(trian,Val{Dc}()) remove_ghost_cells(glue,trian,gids) end -function remove_ghost_cells(model::DiscreteModel,gids::AbstractLocalIndices) - DiscreteModelPortion(model,own_to_local(gids)) -end - -function consistent_bgcell_to_inoutcut!( - cuts::AbstractArray{<:AbstractEmbeddedDiscretization}, - gids::PRange) - - ls_to_bgcell_to_inoutcut = map(get_ls_to_bgcell_to_inoutcut,cuts) - _consistent!(ls_to_bgcell_to_inoutcut,gids) -end - -function get_ls_to_bgcell_to_inoutcut(cut::EmbeddedDiscretization) - cut.ls_to_bgcell_to_inoutcut -end - -function consistent_bgfacet_to_inoutcut!( - cuts::AbstractArray{<:AbstractEmbeddedDiscretization}, - gids::PRange) - - ls_to_bgfacet_to_inoutcut = map(get_ls_to_bgfacet_to_inoutcut,cuts) - _consistent!(ls_to_bgfacet_to_inoutcut,gids) -end - -function get_ls_to_bgfacet_to_inoutcut(cut::EmbeddedFacetDiscretization) - cut.ls_to_facet_to_inoutcut -end - -function _consistent!( - p_to_i_to_a::AbstractArray{<:Vector{<:Vector}}, - prange::PRange) - - n = map(length,p_to_i_to_a) |> PartitionedArrays.getany - for i in 1:n - p_to_a = map(i_to_a->i_to_a[i],p_to_i_to_a) - PVector(p_to_a,partition(prange)) |> consistent! |> wait - map(p_to_a,p_to_i_to_a) do p_to_a,p_to_ia - copyto!(p_to_ia[i],p_to_a) - end +function remove_ghost_subfacets(cut::EmbeddedFacetDiscretization,facet_gids) + bgfacet_mask = map(!iszero,local_to_owner(facet_gids)) + subfacet_mask = map(Reindex(bgfacet_mask),cut.subfacets.cell_to_bgcell) + new_subfacets = findall(subfacet_mask) + subfacets = SubCellData(cut.subfacets,new_subfacets) + ls_to_subfacet_to_inout = map(cut.ls_to_subfacet_to_inout) do sf_to_io + map(Reindex(sf_to_io),new_subfacets) end + EmbeddedFacetDiscretization( + cut.bgmodel, + cut.ls_to_facet_to_inoutcut, + subfacets, + ls_to_subfacet_to_inout, + cut.oid_to_ls, + cut.geo + ) end -function change_bgmodel( - cutgeo::DistributedEmbeddedDiscretization, - model::DistributedDiscreteModel, - args...) - - cuts = _change_bgmodels(cutgeo,model,args...) - gids = get_cell_gids(model) - ls_to_bgcell_to_inoutcut = map(c->c.ls_to_bgcell_to_inoutcut,cuts) - _consistent!(ls_to_bgcell_to_inoutcut,gids) - DistributedEmbeddedDiscretization(cuts,model) -end +# Distributed InOutCut flag methods -function change_bgmodel( - cutgeo::DistributedEmbeddedDiscretization{<:AbstractArray{<:EmbeddedFacetDiscretization}}, - model::DistributedDiscreteModel, - args...) +""" + isconsistent_bgcell_to_inoutcut(cut::DistributedEmbeddedDiscretization) + isconsistent_bgcell_to_inoutcut(cuts::AbstractArray{<:AbstractEmbeddedDiscretization},indices) - D = map(num_dims,local_views(model)) |> PartitionedArrays.getany - cuts = _change_bgmodels(cutgeo,model,args...) - gids = get_face_gids(model,D-1) - ls_to_facet_to_inoutcut = map(c->c.ls_to_facet_to_inoutcut,cuts) - _consistent!(ls_to_facet_to_inoutcut,gids) - DistributedEmbeddedDiscretization(cuts,model) +Returns true if the local `ls_to_bgcell_to_inoutcut` arrays are consistent +accross processors. +""" +function isconsistent_bgcell_to_inoutcut( + cut::DistributedEmbeddedDiscretization{Dc} +) where Dc + model = get_background_model(cut) + gids = get_face_gids(model,Dc) + isconsistent_bgcell_to_inoutcut(local_views(cut),partition(gids)) end -function _change_bgmodels( - cutgeo::DistributedEmbeddedDiscretization, - model::DistributedDiscreteModel, - cell_to_newcell +function isconsistent_bgcell_to_inoutcut( + cuts::AbstractArray{<:AbstractEmbeddedDiscretization},indices::AbstractArray ) - map(local_views(cutgeo),local_views(model),cell_to_newcell) do c,m,c_to_nc - change_bgmodel(c,m,c_to_nc) + get_inoutcut(cut::EmbeddedDiscretization) = Tuple(cut.ls_to_bgcell_to_inoutcut) + get_inoutcut(cut::EmbeddedFacetDiscretization) = Tuple(cut.ls_to_facet_to_inoutcut) + ls_to_bgcell_to_inoutcut = tuple_of_arrays(map(get_inoutcut,cuts)) + return isconsistent_bgcell_to_inoutcut(ls_to_bgcell_to_inoutcut,indices) +end + +function isconsistent_bgcell_to_inoutcut( + ls_to_bgcell_to_inoutcut::NTuple{N,<:AbstractArray{<:Vector}},indices::AbstractArray +) where N + for bgcell_to_inoutcut in ls_to_bgcell_to_inoutcut + if !isconsistent_bgcell_to_inoutcut(bgcell_to_inoutcut,indices) + return false + end end + return true end -function _change_bgmodels( - cutgeo::DistributedEmbeddedDiscretization, - model::DistributedDiscreteModel +function isconsistent_bgcell_to_inoutcut( + bgcell_to_inoutcut::AbstractArray{<:Vector},indices::AbstractArray ) - map(local_views(cutgeo),local_views(model)) do c,m - change_bgmodel(c,m) + # TODO: Some allocations can be avoided by going to the low-level communication API + ref = map(copy,bgcell_to_inoutcut) + wait(consistent!(PVector(ref,indices))) + is_consistent = map(bgcell_to_inoutcut,ref) do bgcell_to_inoutcut,ref + bgcell_to_inoutcut == ref end + return reduce(&,is_consistent,init=true) end -function change_bgmodel( - cut::EmbeddedDiscretization, - newmodel::DiscreteModel, - cell_to_newcell=1:num_cells(get_background_model(cut)) -) - ls_to_bgc_to_ioc = map(cut.ls_to_bgcell_to_inoutcut) do bgc_to_ioc - new_bgc_to_ioc = Vector{Int8}(undef,num_cells(newmodel)) - new_bgc_to_ioc[cell_to_newcell] = bgc_to_ioc - new_bgc_to_ioc - end - subcells = change_bgmodel(cut.subcells,cell_to_newcell) - subfacets = change_bgmodel(cut.subfacets,cell_to_newcell) - EmbeddedDiscretization( - newmodel, - ls_to_bgc_to_ioc, - subcells, - cut.ls_to_subcell_to_inout, - subfacets, - cut.ls_to_subfacet_to_inout, - cut.oid_to_ls, - cut.geo) +# TODO: Should we check for consistency here? +function compute_bgfacet_to_inoutcut(bgmodel::DistributedDiscreteModel,args...) + cutter = LevelSetCutter() + compute_bgfacet_to_inoutcut(cutter,bgmodel,args...) end -function change_bgmodel( - cut::EmbeddedFacetDiscretization, - newmodel::DiscreteModel, - facet_to_newfacet=1:num_facets(get_background_model(cut)) -) - nfacets = num_facets(newmodel) - ls_to_bgf_to_ioc = map(cut.ls_to_facet_to_inoutcut) do bgf_to_ioc - new_bgf_to_ioc = Vector{Int8}(undef,nfacets) - new_bgf_to_ioc[facet_to_newfacet] = bgf_to_ioc - new_bgf_to_ioc +function compute_bgfacet_to_inoutcut(cutter::Cutter,bgmodel::DistributedDiscreteModel,args...) + map(local_views(bgmodel)) do bgmodel + compute_bgfacet_to_inoutcut(cutter,bgmodel,args...) end - subfacets = change_bgmodel(cut.subfacets,facet_to_newfacet) - EmbeddedFacetDiscretization( - newmodel, - ls_to_bgf_to_ioc, - subfacets, - cut.ls_to_subfacet_to_inout, - cut.oid_to_ls, - cut.geo - ) end -function change_bgmodel(cells::SubCellData,cell_to_newcell) - cell_to_bgcell = lazy_map(Reindex(cell_to_newcell),cells.cell_to_bgcell) - SubCellData( - cells.cell_to_points, - collect(Int32,cell_to_bgcell), - cells.point_to_coords, - cells.point_to_rcoords) -end - -function change_bgmodel(facets::SubFacetData,cell_to_newcell) - facet_to_bgcell = lazy_map(Reindex(cell_to_newcell),facets.facet_to_bgcell) - SubFacetData( - facets.facet_to_points, - facets.facet_to_normal, - collect(Int32,facet_to_bgcell), - facets.point_to_coords, - facets.point_to_rcoords) +function compute_bgcell_to_inoutcut(cutgeo::DistributedEmbeddedDiscretization,args...) + map(local_views(cutgeo)) do cutgeo + compute_bgcell_to_inoutcut(cutgeo,args...) + end end -function remove_ghost_subfacets(cut::EmbeddedFacetDiscretization,facet_gids) - bgfacet_mask = map(!iszero,local_to_owner(facet_gids)) - subfacet_mask = map(Reindex(bgfacet_mask),cut.subfacets.cell_to_bgcell) - new_subfacets = findall(subfacet_mask) - subfacets = SubCellData(cut.subfacets,new_subfacets) - ls_to_subfacet_to_inout = map(cut.ls_to_subfacet_to_inout) do sf_to_io - map(Reindex(sf_to_io),new_subfacets) +function compute_bgfacet_to_inoutcut(cutgeo::DistributedEmbeddedDiscretization,args...) + map(local_views(cutgeo)) do cutgeo + compute_bgfacet_to_inoutcut(cutgeo,args...) end - EmbeddedFacetDiscretization( - cut.bgmodel, - cut.ls_to_facet_to_inoutcut, - subfacets, - ls_to_subfacet_to_inout, - cut.oid_to_ls, - cut.geo) end +# AMR + function compute_redistribute_wights( cut::DistributedEmbeddedDiscretization, args...) diff --git a/src/Interfaces/EmbeddedDiscretizations.jl b/src/Interfaces/EmbeddedDiscretizations.jl index 9dcf6237..61d2e759 100644 --- a/src/Interfaces/EmbeddedDiscretizations.jl +++ b/src/Interfaces/EmbeddedDiscretizations.jl @@ -1,12 +1,12 @@ -abstract type AbstractEmbeddedDiscretization <: GridapType end +abstract type AbstractEmbeddedDiscretization{Dc,Dp} <: GridapType end -struct EmbeddedDiscretization{Dp,T} <: AbstractEmbeddedDiscretization +struct EmbeddedDiscretization{Dc,T} <: AbstractEmbeddedDiscretization{Dc,Dc} bgmodel::DiscreteModel ls_to_bgcell_to_inoutcut::Vector{Vector{Int8}} - subcells::SubCellData{Dp,Dp,T} + subcells::SubCellData{Dc,Dc,T} ls_to_subcell_to_inout::Vector{Vector{Int8}} - subfacets::SubFacetData{Dp,T} + subfacets::SubFacetData{Dc,T} ls_to_subfacet_to_inout::Vector{Vector{Int8}} oid_to_ls::Dict{UInt,Int} geo::CSG.Geometry diff --git a/src/Interfaces/EmbeddedFacetDiscretizations.jl b/src/Interfaces/EmbeddedFacetDiscretizations.jl index 4086fb69..b521906c 100644 --- a/src/Interfaces/EmbeddedFacetDiscretizations.jl +++ b/src/Interfaces/EmbeddedFacetDiscretizations.jl @@ -1,5 +1,5 @@ -struct EmbeddedFacetDiscretization{Dc,Dp,T} <: AbstractEmbeddedDiscretization +struct EmbeddedFacetDiscretization{Dc,Dp,T} <: AbstractEmbeddedDiscretization{Dc,Dp} bgmodel::DiscreteModel{Dp,Dp} ls_to_facet_to_inoutcut::Vector{Vector{Int8}} subfacets::SubCellData{Dc,Dp,T} From 1d82808cd65bcff9557a1d3d57ef071db992f3dc Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 14 Nov 2024 15:38:58 +1100 Subject: [PATCH 032/120] Added add_ghost_cells and generate_cell_gids for distributed SubFacetTriangulations --- src/Distributed/Distributed.jl | 2 + .../DistributedDiscreteGeometries.jl | 1 + src/Distributed/DistributedDiscretizations.jl | 17 +++-- .../DistributedSubFacetTriangulations.jl | 63 +++++++++++++++++++ 4 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 src/Distributed/DistributedSubFacetTriangulations.jl diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index e204227b..6d881bba 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -58,6 +58,8 @@ include("DistributedDiscretizations.jl") include("DistributedDiscreteGeometries.jl") +include("DistributedSubFacetTriangulations.jl") + include("DistributedAgFEM.jl") include("DistributedQuadratures.jl") diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index 83f96ad9..f196c6e9 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -1,3 +1,4 @@ + struct DistributedDiscreteGeometry{A} <: GridapType geometries::A end diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index 3c84be45..a35de042 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -52,15 +52,13 @@ function cut_facets(cutter::Cutter,bgmodel::DistributedDiscreteModel{Dc},args... DistributedEmbeddedDiscretization(cuts,bgmodel) end -""" -Note on distributed triangulations: - -- We allow for more one argument, `portion`, which allows the user to filter -some of the cells/faces. In particular, this is used to remove ghosts from the -local triangulations. -- The default for `portion` is `NoGhost()`, wich filters out all ghost cells, except -when we have the argument `in_or_out`. -""" +# Note on distributed triangulations: +# +# - We allow for more one argument, `portion`, which allows the user to filter +# some of the cells/faces. In particular, this is used to remove ghosts from the +# local triangulations. +# - The default for `portion` is `NoGhost()`, wich filters out all ghost cells, except +# when we have the argument `in_or_out`. function Triangulation( cutgeo::DistributedEmbeddedDiscretization,in_or_out::ActiveInOrOut,args... @@ -90,6 +88,7 @@ for TT in (:Triangulation,:SkeletonTriangulation,:BoundaryTriangulation,:Embedde end end +# TODO: This should go to GridapDistributed function remove_ghost_cells(trian::AppendedTriangulation,gids) a = remove_ghost_cells(trian.a,gids) b = remove_ghost_cells(trian.b,gids) diff --git a/src/Distributed/DistributedSubFacetTriangulations.jl b/src/Distributed/DistributedSubFacetTriangulations.jl new file mode 100644 index 00000000..d47c3501 --- /dev/null +++ b/src/Distributed/DistributedSubFacetTriangulations.jl @@ -0,0 +1,63 @@ + +const DistributedSubFacetTriangulation{Df,Dc} = DistributedTriangulation{Df,Dc,<:AbstractArray{<:Union{SubFacetTriangulation{Df,Dc},TriangulationView{Df,Dc,<:SubFacetTriangulation{Df,Dc}}}}} + +# Each cut facet belongs to the background cell containing it. So we can generate +# ownership information for the cut facets from the background cell gids. +function GridapDistributed.generate_cell_gids( + trian::DistributedSubFacetTriangulation{Df,Dc}, +) where {Df,Dc} + model = get_background_model(trian) + cgids = get_cell_gids(model) + + n_lfacets = map(num_cells,local_views(trian)) + first_gid = scan(+,n_lfacets,type=:exclusive,init=one(eltype(n_lfacets))) + n_facets = reduce(+,n_lfacets,init=zero(eltype(n_lfacets))) + + fgids = map(local_views(trian),partition(cgids),first_gid,n_lfacets) do trian, cgids, first_gid, n_lfacets + glue = get_glue(trian,Val(Dc)) # Glue from cut facets to background cells + facet_to_bgcell = glue.tface_to_mface + + facet_to_gid = collect(first_gid:(first_gid+n_lfacets-1)) + facet_to_owner = local_to_owner(cgids)[facet_to_bgcell] + LocalIndices(n_facets,part_id(cgids),facet_to_gid,facet_to_owner) + end + return PRange(fgids) +end + +function GridapDistributed.add_ghost_cells( + trian::DistributedSubFacetTriangulation{Df,Dc}, +) where {Df,Dc} + + # In this case, we already have all ghost facets + if eltype(local_views(trian)) <: SubFacetTriangulation + return trian + end + + # First, we create a new Triangulation containing all the cut facets + model = get_background_model(trian) + bgtrians, facet_to_bgfacet = map(local_views(trian)) do trian + @assert isa(trian,TriangulationView) + trian.parent, trian.cell_to_parent_cell + end |> tuple_of_arrays + bgtrian = DistributedTriangulation(bgtrians,model) + fgids = partition(generate_cell_gids(bgtrian)) + + # Exchange info about cut facets + inside_facets = map(fgids,facet_to_bgfacet) do fgids, facet_to_bgfacet + inside_facets = falses(local_length(fgids)) + inside_facets[facet_to_bgfacet] .= true + return inside_facets + end + wait(consistent!(PVector(inside_facets,fgids))) # Exchange information + + # Return ghosted Triangulation + covers_all = reduce(&,map(all,inside_facets),init=true) + if covers_all + ghosted_trian = bgtrian + else + ghosted_trian = DistributedTriangulation( + map(TriangulationView,bgtrians,inside_facets), model + ) + end + return ghosted_trian +end From 946cdc120bf72ce251e1d608cd09abdbcf3a9d66 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 14 Nov 2024 15:45:49 +1100 Subject: [PATCH 033/120] Fixed distributed moment-fitted quads (maybe?) --- src/Distributed/DistributedQuadratures.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Distributed/DistributedQuadratures.jl b/src/Distributed/DistributedQuadratures.jl index 06a40a4c..634b7786 100644 --- a/src/Distributed/DistributedQuadratures.jl +++ b/src/Distributed/DistributedQuadratures.jl @@ -1,18 +1,18 @@ function CellData.Measure( - t::DistributedTriangulation, + trian::DistributedTriangulation, quad::Tuple{MomentFitted,Vararg}; kwargs...) @notimplemented name, _args, _kwargs = quad cut,cutfacets,_args... = _args - t = remove_ghost_cells(t) - measures = map( - local_views(t), - local_views(cut), - local_views(cutfacets)) do trian,cut,cutfacets - quad = name, (cut,cutfacets,_args...), _kwargs - Measure(trian,quad;kwargs...) + + model = get_background_model(trian) + gids = get_cell_gids(model) + trian = remove_ghost_cells(trian,gids) + measures = map(local_views(trian),local_views(cut),local_views(cutfacets)) do trian,cut,cutfacets + quad = name, (cut,cutfacets,_args...), _kwargs + Measure(trian,quad;kwargs...) end DistributedMeasure(measures) end From 7eac5af045a120f5b10a6dde3132b2f00d282d62 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 14 Nov 2024 16:38:16 +1100 Subject: [PATCH 034/120] Fixes --- src/Distributed/DistributedAgFEM.jl | 122 +++++++++++++++--- src/Distributed/DistributedDiscretizations.jl | 12 +- 2 files changed, 107 insertions(+), 27 deletions(-) diff --git a/src/Distributed/DistributedAgFEM.jl b/src/Distributed/DistributedAgFEM.jl index 4501ba76..cdb65ab1 100644 --- a/src/Distributed/DistributedAgFEM.jl +++ b/src/Distributed/DistributedAgFEM.jl @@ -3,8 +3,8 @@ function AgFEMSpace( bgmodel::DistributedDiscreteModel, f::DistributedFESpace, bgcell_to_bgcellin::AbstractArray{<:AbstractVector}, - g::DistributedFESpace=f) - + g::DistributedFESpace=f +) bgmodel_gids = get_cell_gids(bgmodel) spaces = map( local_views(f), @@ -13,9 +13,7 @@ function AgFEMSpace( local_views(bgmodel_gids)) do f,bgcell_to_bgcellin,g,gids AgFEMSpace(f,bgcell_to_bgcellin,g,local_to_global(gids)) end - trians = map(get_triangulation,local_views(f)) - trian = DistributedTriangulation(trians,bgmodel) - trian = add_ghost_cells(trian) + trian = add_ghost_cells(get_triangulation(f)) trian_gids = generate_cell_gids(trian) cell_to_cellin = _active_aggregates(bgcell_to_bgcellin) cell_to_ldofs = cell_ldof_to_mdof(spaces,cell_to_cellin) @@ -26,7 +24,7 @@ function AgFEMSpace( end function aggregate(strategy,cutgeo::DistributedEmbeddedDiscretization,args...) - aggregates,aggregate_owner = distributed_aggregate(strategy,cutgeo,args...) + aggregates, aggregate_owner = distributed_aggregate(strategy,cutgeo,args...) bgmodel = get_background_model(cutgeo) if has_remote_aggregation(bgmodel,aggregates) bgmodel = add_remote_aggregates(bgmodel,aggregates,aggregate_owner) @@ -40,8 +38,8 @@ end function distributed_aggregate( strategy::AggregateCutCellsByThreshold, cut::DistributedEmbeddedDiscretization, - in_or_out=IN) - + in_or_out=IN +) geo = get_geometry(cut) distributed_aggregate(strategy,cut,geo,in_or_out) end @@ -50,14 +48,13 @@ function distributed_aggregate( strategy::AggregateCutCellsByThreshold, cut::DistributedEmbeddedDiscretization, geo::CSG.Geometry, - in_or_out=IN) - + in_or_out=IN +) bgmodel = get_background_model(cut) facet_to_inoutcut = compute_bgfacet_to_inoutcut(bgmodel,geo) _distributed_aggregate_by_threshold(strategy.threshold,cut,geo,in_or_out,facet_to_inoutcut) end - function _distributed_aggregate_by_threshold(threshold,cutgeo,geo,loc,facet_to_inoutcut) @assert loc in (IN,OUT) @@ -82,15 +79,14 @@ function _distributed_aggregate_by_threshold(threshold,cutgeo,geo,loc,facet_to_i _distributed_aggregate_by_threshold_barrier( threshold,cell_to_unit_cut_meas,facet_to_inoutcut,cell_to_inoutcut, - loc,cell_to_coords,cell_to_faces,face_to_cells,gids) + loc,cell_to_coords,cell_to_faces,face_to_cells,gids + ) end - function _distributed_aggregate_by_threshold_barrier( threshold,cell_to_unit_cut_meas,facet_to_inoutcut,cell_to_inoutcut, - loc,cell_to_coords,cell_to_faces,face_to_cells,gids) - - + loc,cell_to_coords,cell_to_faces,face_to_cells,gids +) ocell_to_touched = map(cell_to_unit_cut_meas) do c_to_m map(≥,c_to_m,Fill(threshold,length(c_to_m))) end @@ -111,7 +107,6 @@ function _distributed_aggregate_by_threshold_barrier( end cell_to_neig = map(n->zeros(Int32,n),n_cells) - cell_to_root_part = map(collect,local_to_owner(gids)) c1 = map(array_cache,cell_to_faces) @@ -129,7 +124,8 @@ function _distributed_aggregate_by_threshold_barrier( cell_to_faces, face_to_cells, facet_to_inoutcut, - loc) + loc + ) PVector(cell_to_touched,partition(gids)) |> consistent! |> wait PVector(cell_to_neig,partition(gids)) |> consistent! |> wait @@ -248,8 +244,8 @@ function _find_best_neighbor_from_centroid_distance( cell_to_touched, cell_to_root_centroid, facet_to_inoutcut, - loc) - + loc +) faces = getindex!(c1,cell_to_faces,cell) dmin = Inf T = eltype(eltype(face_to_cells)) @@ -559,6 +555,8 @@ function _local_aggregates(cell_to_gcellin,gcell_to_cell) end end +# change_bgmodel + function change_bgmodel(cell_to_gcellin,gids::PRange) map(change_bgmodel,cell_to_gcellin,local_to_global(gids)) end @@ -571,3 +569,87 @@ function change_bgmodel(cell_to_gcellin,ncell_to_gcell) end ncell_to_gcellin end + +function change_bgmodel( + cutgeo::DistributedEmbeddedDiscretization, + model::DistributedDiscreteModel +) + cuts = map(change_bgmodel,local_views(cutgeo),local_views(model)) + DistributedEmbeddedDiscretization(cuts,model) +end + +function change_bgmodel( + cutgeo::DistributedEmbeddedDiscretization, + model::DistributedDiscreteModel, + cell_to_new_cell +) + cuts = map(change_bgmodel,local_views(cutgeo),local_views(model),cell_to_new_cell) + DistributedEmbeddedDiscretization(cuts,model) +end + +function change_bgmodel( + cut::EmbeddedDiscretization, + newmodel::DiscreteModel, + cell_to_newcell=1:num_cells(get_background_model(cut)) +) + ls_to_bgc_to_ioc = map(cut.ls_to_bgcell_to_inoutcut) do bgc_to_ioc + new_bgc_to_ioc = Vector{Int8}(undef,num_cells(newmodel)) + new_bgc_to_ioc[cell_to_newcell] = bgc_to_ioc + new_bgc_to_ioc + end + subcells = change_bgmodel(cut.subcells,cell_to_newcell) + subfacets = change_bgmodel(cut.subfacets,cell_to_newcell) + EmbeddedDiscretization( + newmodel, + ls_to_bgc_to_ioc, + subcells, + cut.ls_to_subcell_to_inout, + subfacets, + cut.ls_to_subfacet_to_inout, + cut.oid_to_ls, + cut.geo + ) +end + +function change_bgmodel( + cut::EmbeddedFacetDiscretization, + newmodel::DiscreteModel, + facet_to_newfacet=1:num_facets(get_background_model(cut)) +) + nfacets = num_facets(newmodel) + ls_to_bgf_to_ioc = map(cut.ls_to_facet_to_inoutcut) do bgf_to_ioc + new_bgf_to_ioc = Vector{Int8}(undef,nfacets) + new_bgf_to_ioc[facet_to_newfacet] = bgf_to_ioc + new_bgf_to_ioc + end + subfacets = change_bgmodel(cut.subfacets,facet_to_newfacet) + EmbeddedFacetDiscretization( + newmodel, + ls_to_bgf_to_ioc, + subfacets, + cut.ls_to_subfacet_to_inout, + cut.oid_to_ls, + cut.geo + ) +end + +function change_bgmodel(cells::SubCellData,cell_to_newcell) + cell_to_bgcell = lazy_map(Reindex(cell_to_newcell),cells.cell_to_bgcell) + SubCellData( + cells.cell_to_points, + collect(Int32,cell_to_bgcell), + cells.point_to_coords, + cells.point_to_rcoords + ) +end + +function change_bgmodel(facets::SubFacetData,cell_to_newcell) + facet_to_bgcell = lazy_map(Reindex(cell_to_newcell),facets.facet_to_bgcell) + SubFacetData( + facets.facet_to_points, + facets.facet_to_normal, + collect(Int32,facet_to_bgcell), + facets.point_to_coords, + facets.point_to_rcoords + ) +end diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index a35de042..5d6a22ba 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -120,13 +120,11 @@ end # Distributed InOutCut flag methods -""" - isconsistent_bgcell_to_inoutcut(cut::DistributedEmbeddedDiscretization) - isconsistent_bgcell_to_inoutcut(cuts::AbstractArray{<:AbstractEmbeddedDiscretization},indices) - -Returns true if the local `ls_to_bgcell_to_inoutcut` arrays are consistent -accross processors. -""" +# isconsistent_bgcell_to_inoutcut(cut::DistributedEmbeddedDiscretization) +# isconsistent_bgcell_to_inoutcut(cuts::AbstractArray{<:AbstractEmbeddedDiscretization},indices) +# +# Returns true if the local `ls_to_bgcell_to_inoutcut` arrays are consistent +# accross processors. function isconsistent_bgcell_to_inoutcut( cut::DistributedEmbeddedDiscretization{Dc} ) where Dc From af3720f38dbee38a3d20939648f1660dca431d43 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 14 Nov 2024 16:44:42 +1100 Subject: [PATCH 035/120] Minor --- src/Distributed/Distributed.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index 6d881bba..47d92880 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -26,7 +26,7 @@ using GridapEmbedded.Interfaces: AbstractEmbeddedDiscretization using GridapEmbedded.AgFEM: _touch_aggregated_cells! using GridapEmbedded.AgFEM: AggregateCutCellsByThreshold using GridapEmbedded.MomentFittedQuadratures: MomentFitted -using Gridap.Geometry: AppendedTriangulation +using Gridap.Geometry: AppendedTriangulation, TriangulationView using Gridap.Geometry: get_face_to_parent_face using Gridap.Arrays: find_inverse_index_map, testitem, return_type using Gridap.FESpaces: FESpaceWithLinearConstraints From 963800ff7cd3bdef45186b20f73d40e7c1e9ed58 Mon Sep 17 00:00:00 2001 From: "Alberto F. Martin" Date: Thu, 14 Nov 2024 21:20:09 +1100 Subject: [PATCH 036/120] Added test: What I said is, take a function u_ex such that div(u_ex) in Q_BB And check that the stab term is zero E.g, u = (x,y), its div(u) is a constant Then, you must get zero --- bulk_ghost_penalty_canvas_towardsdiv.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bulk_ghost_penalty_canvas_towardsdiv.jl b/bulk_ghost_penalty_canvas_towardsdiv.jl index 05a395c3..126f3a0f 100644 --- a/bulk_ghost_penalty_canvas_towardsdiv.jl +++ b/bulk_ghost_penalty_canvas_towardsdiv.jl @@ -487,7 +487,11 @@ function divergence_in_pressure_space_fe_function(uh::Gridap.FESpaces.SingleFiel # free_dof_values is actually a global DoFs vector (!!!) FEFunction(P,div_dv_pdofs_values) end -testxh=FEFunction(X, rand(num_free_dofs(X))) + +uex(x)=VectorValue(x[1],x[2]) +pex(x)=x[1] + +testxh=interpolate(X,[uex,pex]) testuh,testph = testxh testdivuh_pressure = divergence_in_pressure_space_fe_function(testuh,P, dq) eh = testdivuh_pressure-(∇⋅testuh) @@ -551,4 +555,4 @@ div_uh_proj_bb(x)[8] testdivuh_pressure(x)[7] res = testdivuh_pressure - div_uh_proj_bb -sum(∫(res*res)*dΩagg_cells) \ No newline at end of file +@assert sum(∫(res*res)*dΩagg_cells) < 1.0e-12 \ No newline at end of file From 392b451f8f72d551bd4f665ea40941eacf966f82 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 14 Nov 2024 21:55:26 +1100 Subject: [PATCH 037/120] Updated NEWS --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index 7d7bb3a4..325955f8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added support for distributed level-set geometries. Since PR[#99](https://github.com/gridap/GridapEmbedded.jl/pull/99). +- Refactored the distributed code to allow for ghosted/unghosted geometries and triangulations. Since PR[#100](https://github.com/gridap/GridapEmbedded.jl/pull/100). ## [0.9.5] - 2024-10-18 From c8e8a09387101dff7ebc0116bbc7944a0760b299 Mon Sep 17 00:00:00 2001 From: "Alberto F. Martin" Date: Fri, 15 Nov 2024 00:11:51 +1100 Subject: [PATCH 038/120] Fixed bulk_ghost_penalty_canvas_div.jl script such that we indeed such behaviour, i.e., with u_ex and p_ex in FE spaces, eps for both; if only uex in FE space, eps only for u. --- bulk_ghost_penalty_canvas_div.jl | 43 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/bulk_ghost_penalty_canvas_div.jl b/bulk_ghost_penalty_canvas_div.jl index d796f031..48ffa8c4 100644 --- a/bulk_ghost_penalty_canvas_div.jl +++ b/bulk_ghost_penalty_canvas_div.jl @@ -659,7 +659,7 @@ div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv get_triangulation(P), Gridap.FESpaces.TestBasis(), Gridap.CellData.ReferenceDomain()) -div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) +div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, @@ -668,14 +668,15 @@ div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_ Gridap.CellData.ReferenceDomain()) div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) -div_dv_div_du_in_pressure_space_mat_contribs=get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? +div_dv_div_du_in_pressure_space_mat_contribs= + get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs ### Compute Π_Q_bb(div_du) dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) # agg_cells_rhs_contribs[1] -ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) +ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) @@ -692,17 +693,18 @@ div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) -if (_is_multifield_fe_basis_component(dp)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dp) - fieldid=_fieldid(dp) +if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(du) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(dv) div_du_l2_proj_bb_array_agg_cells=lazy_map( Gridap.Fields.BlockMap((1,nfields),fieldid), div_du_l2_proj_bb_array_agg_cells) end -div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) +div_du_l2_proj_agg_cells = + Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) # In the MultiField case, I have had to add this change domain # call before setting up the term right below. Otherwise, we get an error @@ -712,20 +714,21 @@ div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceD proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) -P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) +U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) -if (_is_multifield_fe_basis_component(dp)) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - P_agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_agg_cells_to_aggregate_dof_ids) +if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_agg_cells_to_aggregate_dof_ids) + U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) end push!(w_divu, proj_div_dv_div_du_mat_contribs) push!(r_divu, U_Ωagg_cell_dof_ids) # test -push!(c_divu, P_agg_cells_to_aggregate_dof_ids) # trial +push!(c_divu, U_agg_cells_to_aggregate_dof_ids) # trial ## Now add div stabilization to A push!(wrc[1], w_divu...) @@ -744,6 +747,4 @@ eph_withstab = pex-ph_withstab edivuh_withstab = divuex-(∇⋅uh_withstab) norm_euh_withstab = sum(∫(euh_withstab⋅euh_withstab)*dΩcut) norm_eph_withstab = sum(∫(eph_withstab*eph_withstab)*dΩcut) -norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) -# k=0 yields euh = 0.0014, eph = 0.47, edivuh = 0.47, κ= 8.51e11 -# k=2 yields euh = 0.00013, eph = 0.088, edivuh = 0.088, κ= 2.9e14 \ No newline at end of file +norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) \ No newline at end of file From c5859323aa2210df9deebce867bddb28a678a5ad Mon Sep 17 00:00:00 2001 From: "Alberto F. Martin" Date: Sat, 16 Nov 2024 22:26:06 +1100 Subject: [PATCH 039/120] Refactoring common functionality in different Julia files --- aggregates_bounding_boxes_tools.jl | 215 +++++++++++ bulk_ghost_penalty_canvas_div.jl | 550 ++--------------------------- bulk_ghost_penalty_stab_tools.jl | 241 +++++++++++++ fields_and_blocks_tools.jl | 26 ++ 4 files changed, 509 insertions(+), 523 deletions(-) create mode 100644 aggregates_bounding_boxes_tools.jl create mode 100644 bulk_ghost_penalty_stab_tools.jl create mode 100644 fields_and_blocks_tools.jl diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl new file mode 100644 index 00000000..13f5284f --- /dev/null +++ b/aggregates_bounding_boxes_tools.jl @@ -0,0 +1,215 @@ +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cells in the background + model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_aggregate_to_cells(aggregates) + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]>1) + if !haskey(touched,agg) + push!(aggregate_to_cells,[i]) + touched[agg]=current_aggregate + current_aggregate+=1 + else + push!(aggregate_to_cells[touched[agg]],i) + end + end + end + end + aggregate_to_cells +end + +function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) + g=get_grid(bgmodel) + cell_coords=get_cell_coordinates(g) + D=num_dims(bgmodel) + xmin=Vector{Float64}(undef,D) + xmax=Vector{Float64}(undef,D) + + # Compute coordinates of the nodes defining the bounding boxes + bounding_box_node_coords= + Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) + ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] + data = collect(1:length(bounding_box_node_coords)) + bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) + for (agg,cells) in enumerate(aggregate_to_cells) + p=first(cell_coords[cells[1]]) + for i in 1:D + xmin[i]=p[i] + xmax[i]=p[i] + end + for cell in cells + for p in cell_coords[cell] + for i in 1:D + xmin[i]=min(xmin[i],p[i]) + xmax[i]=max(xmax[i],p[i]) + end + end + end + bounds = [(xmin[i], xmax[i]) for i in 1:D] + point_iterator = Iterators.product(bounds...) + bounding_box_node_coords[bounding_box_node_ids[agg]] = + reshape([Point(p...) for p in point_iterator],2^D) + end + + # Set up the discrete model of bounding boxes + HEX_AXIS=1 + polytope=Polytope(Fill(HEX_AXIS,D)...) + scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) + cell_types=fill(1,length(bounding_box_node_ids)) + cell_reffes=[scalar_reffe] + grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, + bounding_box_node_ids, + cell_reffes, + cell_types, + Gridap.Geometry.Oriented()) + Gridap.Geometry.UnstructuredDiscreteModel(grid) +end + +function setup_agg_cells(aggregate_to_cells) + # Generate an array with the global IDs of the cells + # that belong to an aggregrate. From now on, we will + # use the terminology "agg_cells" to refer to those + # cells of the background model that belong to an aggregate + # (i.e., they can be either cut or interior cells) + agg_cells=Vector{Int}() + for cells in aggregate_to_cells + append!(agg_cells,cells) + end + return agg_cells +end + +function setup_agg_cells_to_aggregate(aggregate_to_cells) + # Generate an array that given the local ID of an "agg_cell" + # returns the ID of the aggregate to which it belongs + # (i.e., flattened version of aggregate_to_cells) + agg_cells_to_aggregate=Vector{Int}() + for (i,cells) in enumerate(aggregate_to_cells) + for _ in cells + push!(agg_cells_to_aggregate,i) + end + end + agg_cells_to_aggregate +end + +function setup_aggregate_to_local_cells(aggregate_to_cells) + aggregate_to_local_cells=copy(aggregate_to_cells) + current_local_cell=1 + for (i,cells) in enumerate(aggregate_to_local_cells) + for j in 1:length(cells) + cells[j]=current_local_cell + current_local_cell+=1 + end + end + aggregate_to_local_cells +end + +""" + Changes the domain of a trial/test basis defined on + the reference space of bounding boxes to the reference + space of the agg cells + + TO-DO: in the future, for system of PDEs (MultiField) we should + also take care of blocks (BlockMap) +""" +function change_domain_bb_to_agg_cells(basis_bb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) + @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() + bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) + bb_basis_array = Gridap.CellData.get_data(basis_bb) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Remove transpose map; we will add it later + @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) + @assert isa(bb_basis_array.maps,Fill) + @assert isa(bb_basis_array.maps.value,typeof(transpose)) + bb_basis_array=bb_basis_array.args[1] + end + + bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) + bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), + bb_basis_array_to_Ωagg_cells_array, + ref_agg_cell_to_ref_bb_map) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Add transpose + bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) + end + + Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, + Ωagg_cells, + ReferenceDomain()) +end + +function setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model,agg_cells_to_aggregate) + # ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} + bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) + bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) + ref_agg_cell_to_ref_bb_map= + lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) +end + +function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + agg_cells_local_dof_ids=copy(agg_cells_dof_ids) + current_cell=1 + for agg_cells in aggregate_to_agg_cells + g2l=Dict{Int32,Int32}() + current_local_dof=1 + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in keys(g2l)) + g2l[dof]=current_local_dof + agg_cells_local_dof_ids[current_cell][j]=current_local_dof + current_local_dof+=1 + else + agg_cells_local_dof_ids[current_cell][j]=g2l[dof] + end + end + current_cell+=1 + println(agg_cells_local_dof_ids) + end + end + agg_cells_local_dof_ids +end + +function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) + current_aggregate=1 + current_cell=1 + for agg_cells in aggregate_to_agg_cells + current_aggregate_dof_ids=Int[] + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in current_aggregate_dof_ids) + push!(current_aggregate_dof_ids, dof) + end + end + current_cell+=1 + end + aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids + current_aggregate+=1 + end + aggregate_dof_ids +end \ No newline at end of file diff --git a/bulk_ghost_penalty_canvas_div.jl b/bulk_ghost_penalty_canvas_div.jl index 48ffa8c4..eac4503a 100644 --- a/bulk_ghost_penalty_canvas_div.jl +++ b/bulk_ghost_penalty_canvas_div.jl @@ -3,6 +3,9 @@ using GridapEmbedded using FillArrays using LinearAlgebra +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") include("BulkGhostPenaltyAssembleMaps.jl") # Manufactured solution @@ -30,93 +33,6 @@ cutdisk = cut(bgmodel,geom) strategy = AggregateAllCutCells() aggregates = aggregate(strategy,cutdisk) -""" - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains the global cell IDs of that cells in the background - model that belong to the same aggregate - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_aggregate_to_cells(aggregates) - - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]>1) - if !haskey(touched,agg) - push!(aggregate_to_cells,[i]) - touched[agg]=current_aggregate - current_aggregate+=1 - else - push!(aggregate_to_cells[touched[agg]],i) - end - end - end - end - aggregate_to_cells -end - -function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) - g=get_grid(bgmodel) - cell_coords=get_cell_coordinates(g) - D=num_dims(bgmodel) - xmin=Vector{Float64}(undef,D) - xmax=Vector{Float64}(undef,D) - - # Compute coordinates of the nodes defining the bounding boxes - bounding_box_node_coords= - Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) - ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] - data = collect(1:length(bounding_box_node_coords)) - bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) - for (agg,cells) in enumerate(aggregate_to_cells) - p=first(cell_coords[cells[1]]) - for i in 1:D - xmin[i]=p[i] - xmax[i]=p[i] - end - for cell in cells - for p in cell_coords[cell] - for i in 1:D - xmin[i]=min(xmin[i],p[i]) - xmax[i]=max(xmax[i],p[i]) - end - end - end - bounds = [(xmin[i], xmax[i]) for i in 1:D] - point_iterator = Iterators.product(bounds...) - bounding_box_node_coords[bounding_box_node_ids[agg]] = - reshape([Point(p...) for p in point_iterator],2^D) - end - - # Set up the discrete model of bounding boxes - HEX_AXIS=1 - polytope=Polytope(Fill(HEX_AXIS,D)...) - scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) - cell_types=fill(1,length(bounding_box_node_ids)) - cell_reffes=[scalar_reffe] - grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, - bounding_box_node_ids, - cell_reffes, - cell_types, - Gridap.Geometry.Oriented()) - Gridap.Geometry.UnstructuredDiscreteModel(grid) -end aggregate_to_cells=setup_aggregate_to_cells(aggregates) aggregates_bounding_box_model= @@ -127,45 +43,6 @@ aggregates_bounding_box_model= # writevtk(aggregates_bounding_box_model, "bb_model") # writevtk(bgmodel, "bg_model") -""" - Changes the domain of a trial/test basis defined on - the reference space of bounding boxes to the reference - space of the agg cells - - TO-DO: in the future, for system of PDEs (MultiField) we should - also take care of blocks (BlockMap) -""" -function change_domain_bb_to_agg_cells(basis_bb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) - @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() - bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) - bb_basis_array = Gridap.CellData.get_data(basis_bb) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Remove transpose map; we will add it later - @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) - @assert isa(bb_basis_array.maps,Fill) - @assert isa(bb_basis_array.maps.value,typeof(transpose)) - bb_basis_array=bb_basis_array.args[1] - end - - bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) - bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), - bb_basis_array_to_Ωagg_cells_array, - ref_agg_cell_to_ref_bb_map) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Add transpose - bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) - end - - Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, - Ωagg_cells, - ReferenceDomain()) -end - - # Set up objects required to compute both LHS and RHS of the L2 projection # Set up global spaces @@ -178,36 +55,17 @@ P = TrialFESpace(Q) Y = MultiFieldFESpace([V, Q]) X = MultiFieldFESpace([U, P]) -# Generate an array with the global IDs of the cells -# that belong to an aggregrate. From now on, we will -# use the terminology "agg_cells" to refer to those -# cells of the background model that belong to an aggregate -# (i.e., they can be either cut or interior cells) -agg_cells=Vector{Int}() -for cells in aggregate_to_cells - append!(agg_cells,cells) -end +agg_cells=setup_agg_cells(aggregate_to_cells) # ref_agg_cell_to_agg_cell_map: \hat{K} -> K Ω=Triangulation(bgmodel) Ωagg_cells=view(Ω,agg_cells) ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) -# Generate an array that given the local ID of an "agg_cell" -# returns the ID of the aggregate to which it belongs -# (i.e., flattened version of aggregate_to_cells) -agg_cells_to_aggregate=Vector{Int}() -for (i,cells) in enumerate(aggregate_to_cells) - for _ in cells - push!(agg_cells_to_aggregate,i) - end -end +agg_cells_to_aggregate=setup_agg_cells_to_aggregate(aggregate_to_cells) -# ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} -bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) -bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) -ref_agg_cell_to_ref_bb_map= - lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) +ref_agg_cell_to_ref_bb_map=setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate) # Compute LHS of L2 projection degree=2*(order+1) @@ -224,43 +82,7 @@ Ubb=TrialFESpace(Vbb) ubb=get_trial_fe_basis(Ubb) vbb=get_fe_basis(Vbb) - -aggregate_to_local_cells=copy(aggregate_to_cells) -current_local_cell=1 -for (i,cells) in enumerate(aggregate_to_local_cells) - for j in 1:length(cells) - cells[j]=current_local_cell - current_local_cell+=1 - end -end - -function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - # Change domain of ubb (trial) from Ωbb to Ωagg_cells - ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - # Compute contributions to LHS of L2 projection - agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) - - # Finally assemble LHS contributions - ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) - lazy_map(ass_lhs_map,aggregate_to_local_cells) -end +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, agg_cells_to_aggregate, @@ -282,14 +104,6 @@ dy = get_fe_basis(Y) du,dp = dx dv,dq = dy -function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) - map=cell_dof_ids.maps.value - @assert length(map.size)==1 - @assert blockid >= 1 - @assert blockid <= map.size[1] - cell_dof_ids.args[blockid] -end - Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) @@ -306,29 +120,6 @@ P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) # lhs_uhex=lazy_map(ass_lhs_map_uhex,aggregate_to_local_cells) ### END TESTING CODE -function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - agg_cells_local_dof_ids=copy(agg_cells_dof_ids) - current_cell=1 - for agg_cells in aggregate_to_agg_cells - g2l=Dict{Int32,Int32}() - current_local_dof=1 - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in keys(g2l)) - g2l[dof]=current_local_dof - agg_cells_local_dof_ids[current_cell][j]=current_local_dof - current_local_dof+=1 - else - agg_cells_local_dof_ids[current_cell][j]=g2l[dof] - end - end - current_cell+=1 - println(agg_cells_local_dof_ids) - end - end - agg_cells_local_dof_ids -end U_agg_cells_local_dof_ids= compute_agg_cells_local_dof_ids(U_Ωagg_cell_dof_ids, aggregate_to_local_cells) @@ -348,149 +139,6 @@ function set_up_h_U(aggregates_bounding_box_model, CellField(h_U_array, Ωagg_cells) end - -function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) - current_aggregate=1 - current_cell=1 - for agg_cells in aggregate_to_agg_cells - current_aggregate_dof_ids=Int[] - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in current_aggregate_dof_ids) - push!(current_aggregate_dof_ids, dof) - end - end - current_cell+=1 - end - aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids - current_aggregate+=1 - end - aggregate_dof_ids -end - -function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.single_field -end -function _get_single_field_fe_basis(a) - a -end -function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) - true -end -function _is_multifield_fe_basis_component(a) - false -end -function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.nfields -end -function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.fieldid -end - -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) -""" -function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωagg_cell_dof_ids, - agg_cells_local_dof_ids, - agg_cells_to_aggregate_dof_ids, - h_U, - γ) - - - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, - dΩagg_cells.quad.trian, - ReferenceDomain()) - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) - end - push!(w, dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, Ωagg_cell_dof_ids) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - - proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) - end - - push!(w, proj_dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, agg_cells_to_aggregate_dof_ids) - - w, r, c -end - U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) @@ -503,7 +151,7 @@ P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells h_U = set_up_h_U(aggregates_bounding_box_model, agg_cells_to_aggregate, Ωagg_cells) # Manually set up the arrays that collect_cell_matrix would return automatically -wp,rp,cp=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, dq, # Test basis @@ -516,7 +164,7 @@ wp,rp,cp=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_ag h_U, γ) -wu,ru,cu=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, dv, # Test basis @@ -529,48 +177,22 @@ wu,ru,cu=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_ag h_U, γ) +wdivu,rdivu,cdivu=div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωagg_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + Ωcut = Triangulation(cutdisk,PHYSICAL) dΩcut = Measure(Ωcut,degree) -# # Set up global projection matrix -# Ωcut = Triangulation(cutdisk,PHYSICAL) -# dΩcut = Measure(Ωcut,degree) -# a_nodiv((u,p),(v,q))=∫(v⋅u+q*p)dΩcut -# wrc_nodiv=Gridap.FESpaces.collect_cell_matrix(X,Y,a_nodiv(dx,dy)) - -# assem_nodiv=SparseMatrixAssembler(X,Y) -# Anostab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) -# cond(Array(Anostab_nodiv)) - -# # Add the bulk penalty stabilization term to wrc_nodiv -# push!(wrc_nodiv[1], wp...) -# push!(wrc_nodiv[2], rp...) -# push!(wrc_nodiv[3], cp...) - -# push!(wrc_nodiv[1], wu...) -# push!(wrc_nodiv[2], ru...) -# push!(wrc_nodiv[3], cu...) - -# Awithstab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) -# cond(Array(Awithstab_nodiv)) - -# # Set up rhs global projection -# l_nodiv((v,q))=∫(v⋅uex+q*pex)dΩcut -# b_nodiv = assemble_vector(l_nodiv, Y) - -# global_l2_proj_dofs_nodiv = Awithstab_nodiv\b_nodiv -# xh_nodiv = FEFunction(X, global_l2_proj_dofs_nodiv) -# uh_nodiv,ph_nodiv = xh_nodiv - -# euh_nodiv = uex-uh_nodiv -# # @assert sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) < 1.0e-12 - -# eph_nodiv = pex-ph_nodiv -# # @assert sum(∫(eph_nodiv*eph_nodiv)*dΩcut) < 1.0e-12 -# eph_nodiv_norm = sum(∫(eph_nodiv*eph_nodiv)*dΩcut) -# euh_nodiv_norm = sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) -# # k=0 yields eph = 0.00012 and euh = 5.5e-30 -# edivuh_nodiv = divuex-(∇⋅uh_nodiv) -# edivuh_nodiv_norm = sum(∫(edivuh_nodiv⋅edivuh_nodiv)*dΩcut) + ## TEST 1 a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩcut @@ -584,23 +206,6 @@ cond_nostab = cond(Array(Anostab)) l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩcut b = assemble_vector(l, Y) -## NO STABILIZATION -if cond_nostab<1e35 - global_l2_proj_dofs_nostab = Anostab\b - xh_nostab = FEFunction(X, global_l2_proj_dofs_nostab) - uh_nostab,ph_nostab = xh_nostab - euh_nostab = uex-uh_nostab - eph_nostab = pex-ph_nostab - edivuh_nostab = divuex-(∇⋅uh_nostab) - norm_euh_nostab = sum(∫(euh_nostab⋅euh_nostab)*dΩcut) - norm_eph_nostab = sum(∫(eph_nostab*eph_nostab)*dΩcut) - edivuh_nostab = sum(∫(edivuh_nostab⋅edivuh_nostab)*dΩcut) -else - println("Singular exception is raised as error when solving the system (as cond= $cond_nostab is high?)") -end -# k=0 yields euh = 1.2e-32, eph = 0.00017, edivuh = 6.8e-30, κ= 3.15e32 -# k=0 yields euh = ?, eph = ?, edivuh = ?, κ= 4.3e36 - ## U + P STABILIZATION # Add the bulk penalty stabilization terms for u and p to wrc push!(wrc[1], wp...) @@ -628,112 +233,11 @@ norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩcut) # k=0 yields euh = 6.3e-31, eph = 0.00055, edivuh = 2.4e-28, κ= 11492 # k=2 yields euh = 5.3e-22, eph = 3.0e-18, edivuh = 3.0e-18, κ= 1.7e11 -## +DIVU STABILIZATION -## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) -# Manually set up the arrays that collect_cell_matrix would return automatically -w_divu = [] -r_divu = [] -c_divu = [] - -## (I) Let's set up the div_dv_div_du_mat_contribs (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells -div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) -if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) -end - -push!(w_divu, div_dv_div_du_mat_contribs) -push!(r_divu, U_Ωagg_cell_dof_ids) -push!(c_divu, U_Ωagg_cell_dof_ids) - -## Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩ_agg_cells -div_dv=∇⋅(_get_single_field_fe_basis(dv)) -pdofs=Gridap.FESpaces.get_fe_dof_basis(P) -div_dv_pdofs_values=pdofs(div_dv) -div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_pdofs_values, - Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) -div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, - get_triangulation(P), - Gridap.FESpaces.TestBasis(), - Gridap.CellData.ReferenceDomain()) -div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) - -div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) -div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, - get_triangulation(P), - Gridap.FESpaces.TrialBasis(), - Gridap.CellData.ReferenceDomain()) -div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) - -div_dv_div_du_in_pressure_space_mat_contribs= - get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? -div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs - -### Compute Π_Q_bb(div_du) -dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) -agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) -# agg_cells_rhs_contribs[1] -ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) -rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) -div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - -# Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate -div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(qbb)) - -div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - -div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - -if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(du) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(dv) - div_du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - div_du_l2_proj_bb_array_agg_cells) -end - -div_du_l2_proj_agg_cells = - Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) - -# In the MultiField case, I have had to add this change domain -# call before setting up the term right below. Otherwise, we get an error -# when trying to multiply the fields. Not sure why this is happening -# dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) -div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) - -proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) - -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) - -if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_agg_cells_to_aggregate_dof_ids) - U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) -end - -push!(w_divu, proj_div_dv_div_du_mat_contribs) -push!(r_divu, U_Ωagg_cell_dof_ids) # test -push!(c_divu, U_agg_cells_to_aggregate_dof_ids) # trial ## Now add div stabilization to A -push!(wrc[1], w_divu...) -push!(wrc[2], r_divu...) -push!(wrc[3], c_divu...) +push!(wrc[1], wdivu...) +push!(wrc[2], rdivu...) +push!(wrc[3], cdivu...) # Assembly Awithstab=assemble_matrix(assem, wrc) diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl new file mode 100644 index 00000000..6af1e4ec --- /dev/null +++ b/bulk_ghost_penalty_stab_tools.jl @@ -0,0 +1,241 @@ +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) + # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) +""" +function bulk_ghost_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωagg_cell_dof_ids, + agg_cells_local_dof_ids, + agg_cells_to_aggregate_dof_ids, + h_U, + γ) + + + Ωagg_cells=dΩagg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, + dΩagg_cells.quad.trian, + ReferenceDomain()) + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) + end + push!(w, dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, Ωagg_cell_dof_ids) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + + proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) + end + + push!(w, proj_dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, agg_cells_to_aggregate_dof_ids) + + w, r, c +end + +function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωagg_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + ## +DIVU STABILIZATION + ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) + end + + ## (I) Let's set up the div_dv_div_du_mat_contribs + # (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells + div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) + push!(w, div_dv_div_du_mat_contribs) + push!(r, U_Ωagg_cell_dof_ids) + push!(c, U_Ωagg_cell_dof_ids) + + ## Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩ_agg_cells + # div_dv=∇⋅(_get_single_field_fe_basis(dv)) + # pdofs=Gridap.FESpaces.get_fe_dof_basis(P) + # div_dv_pdofs_values=pdofs(div_dv) + # div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, + # div_dv_pdofs_values, + # Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) + # div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, + # get_triangulation(P), + # Gridap.FESpaces.TestBasis(), + # Gridap.CellData.ReferenceDomain()) + # div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) + + # div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) + # div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, + # get_triangulation(P), + # Gridap.FESpaces.TrialBasis(), + # Gridap.CellData.ReferenceDomain()) + # div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) + + # div_dv_div_du_in_pressure_space_mat_contribs= + # get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? + # div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs + + div_du=∇⋅(_get_single_field_fe_basis(du)) + + ### Compute Π_Q_bb(div_du) + dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩagg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + div_dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(qbb)) + + div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(du) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(dv) + div_du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((fieldid,nfields),fieldid), + div_du_l2_proj_bb_array_agg_cells) + end + + div_du_l2_proj_agg_cells = + Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + # dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) + + proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_agg_cells_to_aggregate_dof_ids) + end + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_Ωagg_cell_dof_ids) # test + push!(c, U_agg_cells_to_aggregate_dof_ids) # trial + w,r,c +end + +function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + ubb, + vbb) +Ωagg_cells=dΩagg_cells.quad.trian + +# Change domain of vbb (test) from Ωbb to Ωagg_cells +vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + +# Change domain of ubb (trial) from Ωbb to Ωagg_cells +ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + +# Compute contributions to LHS of L2 projection +agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) + +# Finally assemble LHS contributions +ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) +lazy_map(ass_lhs_map,aggregate_to_local_cells) +end \ No newline at end of file diff --git a/fields_and_blocks_tools.jl b/fields_and_blocks_tools.jl new file mode 100644 index 00000000..ff40c7f6 --- /dev/null +++ b/fields_and_blocks_tools.jl @@ -0,0 +1,26 @@ +function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) + map=cell_dof_ids.maps.value + @assert length(map.size)==1 + @assert blockid >= 1 + @assert blockid <= map.size[1] + cell_dof_ids.args[blockid] +end + +function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.single_field +end +function _get_single_field_fe_basis(a) + a +end +function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) + true +end +function _is_multifield_fe_basis_component(a) + false +end +function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.nfields +end +function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.fieldid +end From 6850b686cc41cf5a018436377fc35efa63e60ed2 Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Mon, 25 Nov 2024 13:19:20 +1000 Subject: [PATCH 040/120] Distributed ghost skeleton --- src/Distributed/Distributed.jl | 1 + .../DistributedDiscreteGeometries.jl | 2 +- src/Distributed/DistributedDiscretizations.jl | 22 +++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index 47d92880..b4cf0b8e 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -45,6 +45,7 @@ import GridapEmbedded.Interfaces: cut_facets import GridapEmbedded.Interfaces: EmbeddedBoundary import GridapEmbedded.Interfaces: compute_bgfacet_to_inoutcut import GridapEmbedded.Interfaces: compute_bgcell_to_inoutcut +import GridapEmbedded.Interfaces: GhostSkeleton import GridapEmbedded.CSG: get_geometry import GridapEmbedded.LevelSetCutters: discretize, DiscreteGeometry import Gridap.Geometry: Triangulation diff --git a/src/Distributed/DistributedDiscreteGeometries.jl b/src/Distributed/DistributedDiscreteGeometries.jl index f196c6e9..0f9b55f2 100644 --- a/src/Distributed/DistributedDiscreteGeometries.jl +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -45,7 +45,7 @@ function cut_facets( DistributedEmbeddedDiscretization(cuts,bgmodel) end -for TT in (:Triangulation,:SkeletonTriangulation,:BoundaryTriangulation,:EmbeddedBoundary) +for TT in (:Triangulation,:SkeletonTriangulation,:BoundaryTriangulation,:EmbeddedBoundary,:GhostSkeleton) @eval begin function $TT(portion,cutgeo::DistributedEmbeddedDiscretization,cutinorout,geom::DistributedDiscreteGeometry) model = get_background_model(cutgeo) diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index 5d6a22ba..3fdf7e5d 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -52,12 +52,12 @@ function cut_facets(cutter::Cutter,bgmodel::DistributedDiscreteModel{Dc},args... DistributedEmbeddedDiscretization(cuts,bgmodel) end -# Note on distributed triangulations: -# -# - We allow for more one argument, `portion`, which allows the user to filter -# some of the cells/faces. In particular, this is used to remove ghosts from the -# local triangulations. -# - The default for `portion` is `NoGhost()`, wich filters out all ghost cells, except +# Note on distributed triangulations: +# +# - We allow for more one argument, `portion`, which allows the user to filter +# some of the cells/faces. In particular, this is used to remove ghosts from the +# local triangulations. +# - The default for `portion` is `NoGhost()`, wich filters out all ghost cells, except # when we have the argument `in_or_out`. function Triangulation( @@ -66,7 +66,7 @@ function Triangulation( Triangulation(WithGhost(),cutgeo,in_or_out,args...) end -for TT in (:Triangulation,:SkeletonTriangulation,:BoundaryTriangulation,:EmbeddedBoundary) +for TT in (:Triangulation,:SkeletonTriangulation,:BoundaryTriangulation,:EmbeddedBoundary,:GhostSkeleton) @eval begin function $TT(cutgeo::DistributedEmbeddedDiscretization,args...) $TT(NoGhost(),cutgeo,args...) @@ -122,9 +122,9 @@ end # isconsistent_bgcell_to_inoutcut(cut::DistributedEmbeddedDiscretization) # isconsistent_bgcell_to_inoutcut(cuts::AbstractArray{<:AbstractEmbeddedDiscretization},indices) -# -# Returns true if the local `ls_to_bgcell_to_inoutcut` arrays are consistent -# accross processors. +# +# Returns true if the local `ls_to_bgcell_to_inoutcut` arrays are consistent +# accross processors. function isconsistent_bgcell_to_inoutcut( cut::DistributedEmbeddedDiscretization{Dc} ) where Dc @@ -189,7 +189,7 @@ function compute_bgfacet_to_inoutcut(cutgeo::DistributedEmbeddedDiscretization,a end end -# AMR +# AMR function compute_redistribute_wights( cut::DistributedEmbeddedDiscretization, From 432891abbfc8862cc157827345ce8f03b2ea15ff Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 26 Nov 2024 09:25:07 +1100 Subject: [PATCH 041/120] included results (comments) for k=0 and k=2 --- bulk_ghost_penalty_canvas_div.jl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bulk_ghost_penalty_canvas_div.jl b/bulk_ghost_penalty_canvas_div.jl index eac4503a..e3f35f87 100644 --- a/bulk_ghost_penalty_canvas_div.jl +++ b/bulk_ghost_penalty_canvas_div.jl @@ -9,7 +9,7 @@ include("fields_and_blocks_tools.jl") include("BulkGhostPenaltyAssembleMaps.jl") # Manufactured solution -order = 0 +order = 2 uex(x) = -VectorValue(2*x[1],2*x[2]) pex(x) = (x[1]^2 + x[2]^2) divuex(x) = -4.0 @@ -230,9 +230,9 @@ edivuh_upstab = divuex-(∇⋅uh_upstab) norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩcut) norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩcut) norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩcut) -# k=0 yields euh = 6.3e-31, eph = 0.00055, edivuh = 2.4e-28, κ= 11492 -# k=2 yields euh = 5.3e-22, eph = 3.0e-18, edivuh = 3.0e-18, κ= 1.7e11 - +# No stabilization (k=0) κ = 1.1e35 vs (k=2) κ = Inf +# k=0 (n=10) yields euh = 3.0e-28, eph = 0.00055, edivuh = 1.3e-30, κ = 1.4e5 +# k=2 (n=10) yields euh = 1.8e-18, eph = 1.7e-28, edivuh = 7.4e-21, κ= 1.7e13 ## Now add div stabilization to A push!(wrc[1], wdivu...) @@ -251,4 +251,6 @@ eph_withstab = pex-ph_withstab edivuh_withstab = divuex-(∇⋅uh_withstab) norm_euh_withstab = sum(∫(euh_withstab⋅euh_withstab)*dΩcut) norm_eph_withstab = sum(∫(eph_withstab*eph_withstab)*dΩcut) -norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) \ No newline at end of file +norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) +# k=0 (n=10) yields euh = 1.2e-26, eph = 0.00055, edivuh = 7.0e-29, κ = 1.7e6 +# k=2 (n=10) yields euh = 1.6e-15, eph = 1.7e-28, edivuh = 7.1e-19, κ= 1.8e14 \ No newline at end of file From 6a60233dd485ec4823bbbccd3150fe0a47f49e4a Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Thu, 28 Nov 2024 10:22:02 +1100 Subject: [PATCH 042/120] replaced copy by deepcopy so that aggregate_to_cells does not get changed in the canvas --- aggregates_bounding_boxes_tools.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl index 13f5284f..fff83b5d 100644 --- a/aggregates_bounding_boxes_tools.jl +++ b/aggregates_bounding_boxes_tools.jl @@ -112,7 +112,7 @@ function setup_agg_cells_to_aggregate(aggregate_to_cells) end function setup_aggregate_to_local_cells(aggregate_to_cells) - aggregate_to_local_cells=copy(aggregate_to_cells) + aggregate_to_local_cells=deepcopy(aggregate_to_cells) current_local_cell=1 for (i,cells) in enumerate(aggregate_to_local_cells) for j in 1:length(cells) From d82cd53894b4d5946e40628c23d56ec86f8264c8 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 29 Nov 2024 09:21:33 +1100 Subject: [PATCH 043/120] fixed missing argument in set_up_bulk_ghost_penalty_lhs --- bulk_ghost_penalty_canvas.jl | 6 +++--- bulk_ghost_penalty_canvas_div.jl | 5 +++-- bulk_ghost_penalty_stab_tools.jl | 4 +++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 3ef8553a..0a31b4fd 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -234,7 +234,7 @@ for (i,cells) in enumerate(aggregate_to_local_cells) end end -function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, +function set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, @@ -262,14 +262,14 @@ function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, lazy_map(ass_lhs_map,aggregate_to_local_cells) end -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, pbb, qbb) -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, diff --git a/bulk_ghost_penalty_canvas_div.jl b/bulk_ghost_penalty_canvas_div.jl index e3f35f87..4565484c 100644 --- a/bulk_ghost_penalty_canvas_div.jl +++ b/bulk_ghost_penalty_canvas_div.jl @@ -13,6 +13,7 @@ order = 2 uex(x) = -VectorValue(2*x[1],2*x[2]) pex(x) = (x[1]^2 + x[2]^2) divuex(x) = -4.0 + # Select geometry R = 0.2 geom = disk(R, x0=Point(0.5,0.5)) @@ -84,14 +85,14 @@ vbb=get_fe_basis(Vbb) aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, pbb, qbb) -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl index 6af1e4ec..c56248ee 100644 --- a/bulk_ghost_penalty_stab_tools.jl +++ b/bulk_ghost_penalty_stab_tools.jl @@ -112,6 +112,8 @@ function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, U_agg_cells_to_aggregate_dof_ids, h_U, γ) + Ωagg_cells=dΩagg_cells.quad.trian + ## +DIVU STABILIZATION ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) # Manually set up the arrays that collect_cell_matrix would return automatically @@ -212,7 +214,7 @@ function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, w,r,c end -function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, +function set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, From dc5355177ab05dbb064b3b649130e32a22089bb8 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 29 Nov 2024 15:27:05 +1100 Subject: [PATCH 044/120] stabilization on cut cells only (so not on root cells) --- aggregates_bounding_boxes_tools.jl | 134 ++++++- bulk_ghost_penalty_canvas_div_on_cut_cells.jl | 248 +++++++++++++ ...host_penalty_canvas_selecting_cut_cells.jl | 349 ------------------ bulk_ghost_penalty_stab_tools.jl | 185 ++++++++++ 4 files changed, 566 insertions(+), 350 deletions(-) create mode 100644 bulk_ghost_penalty_canvas_div_on_cut_cells.jl delete mode 100644 bulk_ghost_penalty_canvas_selecting_cut_cells.jl diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl index fff83b5d..6f3e2bd6 100644 --- a/aggregates_bounding_boxes_tools.jl +++ b/aggregates_bounding_boxes_tools.jl @@ -36,6 +36,48 @@ function setup_aggregate_to_cells(aggregates) end end aggregate_to_cells +end + +""" + Creates an array of arrays with as many entries + as interior cells that are not part of any aggegrate. + For each interior cell, the array + contains the global cell IDs of that cells in the background + model that belong to the same interior cell + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_int_nonagg_cell_to_cells(aggregates) + + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + interior_cell_to_cells=Vector{Vector{Int}}() + current_interior_cell=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]==1) + if !haskey(touched,agg) + push!(interior_cell_to_cells,[i]) + touched[agg]=current_interior_cell + current_interior_cell+=1 + else + push!(interior_cell_to_cells[touched[agg]],i) + end + end + end + end + interior_cell_to_cells end function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) @@ -97,6 +139,52 @@ function setup_agg_cells(aggregate_to_cells) end return agg_cells end + +function setup_int_nonagg_cells(int_nonagg_cell_to_cells) + # Generate an array with the global IDs of the cells + # that belong to the interior, yet do not belong to the + # aggregate. We will use "int_nonagg_cells" to refer to those + # cells of the background model that belong to the interior + # but are not part of any of the aggregates. Thus, all interior + # cells but not including the root cells of the aggregates. + int_nonagg_cells=Vector{Int}() + for cell in int_nonagg_cell_to_cells + append!(int_nonagg_cells,cell) + end + return int_nonagg_cells +end + +function setup_root_cells(int_cells, int_nonagg_cells) + # Generate an array with the global IDs of the cells + # that are the root cells of the aggregrates. + root_cells=Vector{Int}() + tester_int_nonagg_cells=Vector{Int}() + for cell in int_cells + if cell ∈ int_nonagg_cells + append!(tester_int_nonagg_cells,cell) + else + append!(root_cells,cell) + end + end + @assert(tester_int_nonagg_cells==int_nonagg_cells) + return root_cells +end + +function setup_cut_cells(agg_cells, root_cells) + # Generate an array with the global IDs of the cells + # that are the cut cells of the aggregrates. + cut_cells=Vector{Int}() + tester_root_cells=Vector{Int}() + for cell in agg_cells + if cell ∈ root_cells + append!(tester_root_cells,cell) + else + append!(cut_cells,cell) + end + end + @assert(tester_root_cells==root_cells) + cut_cells +end function setup_agg_cells_to_aggregate(aggregate_to_cells) # Generate an array that given the local ID of an "agg_cell" @@ -109,8 +197,52 @@ function setup_agg_cells_to_aggregate(aggregate_to_cells) end end agg_cells_to_aggregate +end + +function setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) + # Generate an array that given the local ID of an "agg_cell" + # returns the ID of the aggregate to which it belongs + # (i.e., flattened version of aggregate_to_cut_cells) + cut_cells_in_agg_cells_to_aggregate=Vector{Int}() + for (i,cells) in enumerate(aggregate_to_cut_cells) + for _ in cells + push!(cut_cells_in_agg_cells_to_aggregate,i) + end + end + cut_cells_in_agg_cells_to_aggregate end - + +function setup_aggregate_to_cut_cells(aggregates, root_cells) + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cut_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]>1) && i ∉ root_cells + if !haskey(touched,agg) + push!(aggregate_to_cut_cells,[i]) + touched[agg]=current_aggregate + current_aggregate+=1 + else + push!(aggregate_to_cut_cells[touched[agg]],i) + end + end + end + end + aggregate_to_cut_cells +end + function setup_aggregate_to_local_cells(aggregate_to_cells) aggregate_to_local_cells=deepcopy(aggregate_to_cells) current_local_cell=1 diff --git a/bulk_ghost_penalty_canvas_div_on_cut_cells.jl b/bulk_ghost_penalty_canvas_div_on_cut_cells.jl new file mode 100644 index 00000000..66872cd0 --- /dev/null +++ b/bulk_ghost_penalty_canvas_div_on_cut_cells.jl @@ -0,0 +1,248 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 + +# Select geometry +R = 0.2 +geom = disk(R, x0=Point(0.5,0.5)) + +# Setup background model +n=16 +partition = (n,n) +box = get_metadata(geom) +bgmodel = CartesianDiscreteModel((0,1,0,1),partition) +dp = box.pmax - box.pmin +h = dp[1]/n + +# Cut the background model with the mesh +cutgeo = cut(bgmodel,geom) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# Triangulations +Ωbg = Triangulation(bgmodel) +Ωact = Triangulation(cutgeo,ACTIVE) + +# Physical domain +Ω = Triangulation(cutgeo,PHYSICAL) +degree=2*(order+1) +dΩ = Measure(Ω,degree) + +# Set up global spaces +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +U = TrialFESpace(V) +P = TrialFESpace(Q) +Y = MultiFieldFESpace([V, Q]) +X = MultiFieldFESpace([U, P]) +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +# Aggregate cells and triangulation +agg_cells =setup_agg_cells(aggregate_to_cells) +Ωbg_agg_cells=view(Ωbg,agg_cells) + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) +agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) +ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate) + +# Spaces on bounding boxes +reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) +reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + +# Numerical integration (Measures) +degree=2*(order+1) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) + +# LHS of L2 projection on bounding boxes. +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + ubb, + vbb) + +# Selecting relevant global dofs ids of aggregate cells (from background mesh) +Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) +U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) +P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) + +# Computing local (per aggregate) dof ids +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) + +# Compute global dofs ids per aggregate and reindex these +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) +P_Ωbg_agg_cell_dof_ids + +# parameters +γ = 10.0 # Interior bulk-penalty stabilization parameter +h_U = 1.0 + +########################################### +### STABILIZATION ON Ωagg\Troot ### +########################################### + +## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) + +## (2) FIND THE INTERIOR CELLS +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface + +## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS +root_cells = setup_root_cells(int_cells, int_nonagg_cells) +cut_cells = setup_cut_cells(agg_cells, root_cells) + +## (4) CUT CELLS AND MEASURE +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) + +# (5) DOF IDS related to cut cells +Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) +U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) +P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) + +# (6) Defining cut_cells_to_aggregate_dof_ids +aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) +cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) + +# (7) Compute stabilization terms for u and p +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +## TEST WITH MANUFACTURED SOLUTIONS +a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +assem=SparseMatrixAssembler(X,Y) +A_nostab = assemble_matrix(assem, wrc) +l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ +b = assemble_vector(l, Y) + +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) + +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) + +A_stabup = assemble_matrix(assem, wrc) +cond_nostab = cond(Array(A_nostab)) +cond_stabup = cond(Array(A_stabup)) + +# CHECK errors when only the p and u stabilization terms are included. +global_l2_proj_dofs_upstab = A_stabup\b +xh_upstab = FEFunction(X, global_l2_proj_dofs_upstab) +uh_upstab,ph_upstab = xh_upstab +euh_upstab = uex-uh_upstab +eph_upstab = pex-ph_upstab +edivuh_upstab = divuex-(∇⋅uh_upstab) +norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩ) +norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩ) +norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩ) +# No stabilization (n=16) (k=0) κ = 2.3e9 vs (k=2) κ = 2.8e29 +# k=0 (n=16) yields euh = 2.0e-28, eph = 0.00015, edivuh = 1.9e-30, κ = 9.2e5 +# k=2 (n=16) yields euh = 2.0e-18, eph = 4.0e-29, edivuh = 1.7e-19, κ = 4.4e15 + +#DIV stabilization part +wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) + +A_stab = assemble_matrix(assem, wrc) +cond_stab = cond(Array(A_stab)) + +global_l2_proj_dofs_stab = A_stab\b +xh_stab = FEFunction(X, global_l2_proj_dofs_stab) +uh_stab,ph_stab = xh_stab +euh_stab = uex-uh_stab +eph_stab = pex-ph_stab +edivuh_stab = divuex-(∇⋅uh_stab) +norm_euh_stab = sum(∫(euh_stab⋅euh_stab)*dΩ) +norm_eph_stab = sum(∫(eph_stab*eph_stab)*dΩ) +norm_edivuh_stab = sum(∫(edivuh_stab⋅edivuh_stab)*dΩ) +# k=0 (n=16) yields euh = 1.6e-26, eph = 0.00015, edivuh = 4.2e-29, κ = 7.6e6 +# k=2 (n=16) yields euh = 3.1e-14, eph = 4.1e-29, edivuh = 1.8e-17, κ = 4.7e16 \ No newline at end of file diff --git a/bulk_ghost_penalty_canvas_selecting_cut_cells.jl b/bulk_ghost_penalty_canvas_selecting_cut_cells.jl deleted file mode 100644 index 1d4d7235..00000000 --- a/bulk_ghost_penalty_canvas_selecting_cut_cells.jl +++ /dev/null @@ -1,349 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 0 -uex(x) = -VectorValue(2*x[1],2*x[2]) -divuex(x) = -4.0 - -# Select geometry -R = 0.2 -geom = disk(R, x0=Point(0.5,0.5)) - -# Setup background model -n=16 -partition = (n,n) -box = get_metadata(geom) -bgmodel = CartesianDiscreteModel((0,1,0,1),partition) -dp = box.pmax - box.pmin -h = dp[1]/n - -# Cut the background model with the mesh -cutgeo = cut(bgmodel,geom) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -#INVESTIGATING: Number of aggregates, cells and bg cells. -@assert length(aggregates) == n*n -num_cell = length(aggregates) -using StatsBase -counts = countmap(aggregates,alg=:dict) -agg_counts = filter(((k,v),) -> v > 1 && k != 0, counts) -num_aggregates = length(agg_counts) -num_cells_in_aggregates = 0 -for (k,v) in agg_counts - println(v) - num_cells_in_aggregates +=v -end -num_cells_not_in_aggregates = counts[0] -non_agg_counts = filter(((k,v),) -> v <= 1 || k==0, counts) -num_cells_not_in_aggregates = 0 -for (k,v) in non_agg_counts - println(v) - num_cells_not_in_aggregates +=v -end -num_ext_cells = counts[0] -@assert num_cells_in_aggregates + num_cells_not_in_aggregates == num_cell -println("Out of the $num_cell cells, $num_cells_in_aggregates belong to aggregates and $num_cells_not_in_aggregates are not part of aggregates. Note that we have $num_ext_cells exterior cells") -println("Assuming that there is one root per aggregate, we have $(num_cells_in_aggregates-num_aggregates) cut cells and $num_aggregates roots in the $num_aggregates aggregates cotntaining $num_cells_in_aggregates in total.") - -""" - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains the global cell IDs of that cells in the background - model that belong to the same aggregate - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_aggregate_to_cells(aggregates) - - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]>1) - if !haskey(touched,agg) - push!(aggregate_to_cells,[i]) - touched[agg]=current_aggregate - current_aggregate+=1 - else - push!(aggregate_to_cells[touched[agg]],i) - end - end - end - end - aggregate_to_cells -end - -""" - Creates an array of arrays with as many entries - as interior cells that are not part of any aggegrate. - For each interior cell, the array - contains the global cell IDs of that cells in the background - model that belong to the same interior cell - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_int_nonagg_cell_to_cells(aggregates) - - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - interior_cell_to_cells=Vector{Vector{Int}}() - current_interior_cell=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]==1) - if !haskey(touched,agg) - push!(interior_cell_to_cells,[i]) - touched[agg]=current_interior_cell - current_interior_cell+=1 - else - push!(interior_cell_to_cells[touched[agg]],i) - end - end - end - end - interior_cell_to_cells -end - - -function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) - g=get_grid(bgmodel) - cell_coords=get_cell_coordinates(g) - D=num_dims(bgmodel) - xmin=Vector{Float64}(undef,D) - xmax=Vector{Float64}(undef,D) - - # Compute coordinates of the nodes defining the bounding boxes - bounding_box_node_coords= - Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) - ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] - data = collect(1:length(bounding_box_node_coords)) - bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) - for (agg,cells) in enumerate(aggregate_to_cells) - p=first(cell_coords[cells[1]]) - for i in 1:D - xmin[i]=p[i] - xmax[i]=p[i] - end - for cell in cells - for p in cell_coords[cell] - for i in 1:D - xmin[i]=min(xmin[i],p[i]) - xmax[i]=max(xmax[i],p[i]) - end - end - end - bounds = [(xmin[i], xmax[i]) for i in 1:D] - point_iterator = Iterators.product(bounds...) - bounding_box_node_coords[bounding_box_node_ids[agg]] = - reshape([Point(p...) for p in point_iterator],2^D) - end - - # Set up the discrete model of bounding boxes - HEX_AXIS=1 - polytope=Polytope(Fill(HEX_AXIS,D)...) - scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) - cell_types=fill(1,length(bounding_box_node_ids)) - cell_reffes=[scalar_reffe] - grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, - bounding_box_node_ids, - cell_reffes, - cell_types, - Gridap.Geometry.Oriented()) - Gridap.Geometry.UnstructuredDiscreteModel(grid) -end - -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# colors = color_aggregates(aggregates,bgmodel) -# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) -# writevtk(aggregates_bounding_box_model, "bb_model") -# writevtk(bgmodel, "bg_model") - -""" - Changes the domain of a trial/test basis defined on - the reference space of bounding boxes to the reference - space of the agg cells - - TO-DO: in the future, for system of PDEs (MultiField) we should - also take care of blocks (BlockMap) -""" -function change_domain_bb_to_agg_cells(basis_bb, - ref_agg_cell_to_ref_bb_map, - Ω_agg_cells, - agg_cells_to_aggregate) - @assert num_cells(Ω_agg_cells)==length(ref_agg_cell_to_ref_bb_map) - @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() - bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) - bb_basis_array = Gridap.CellData.get_data(basis_bb) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Remove transpose map; we will add it later - @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) - @assert isa(bb_basis_array.maps,Fill) - @assert isa(bb_basis_array.maps.value,typeof(transpose)) - bb_basis_array=bb_basis_array.args[1] - end - - bb_basis_array_to_Ω_agg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) - bb_basis_array_to_Ω_agg_cells_array = lazy_map(Broadcasting(∘), - bb_basis_array_to_Ω_agg_cells_array, - ref_agg_cell_to_ref_bb_map) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Add transpose - bb_basis_array_to_Ω_agg_cells_array=lazy_map(transpose, bb_basis_array_to_Ω_agg_cells_array) - end - - Gridap.CellData.GenericCellField(bb_basis_array_to_Ω_agg_cells_array, - Ω_agg_cells, - ReferenceDomain()) -end - -# Generate an array with the global IDs of the cells -# that belong to an aggregrate. From now on, we will -# use the terminology "agg_cells" to refer to those -# cells of the background model that belong to an aggregate -# (i.e., they can be either cut or interior cells) -agg_cells=Vector{Int}() -for cells in aggregate_to_cells - append!(agg_cells,cells) -end - -# Generate an array with the global IDs of the cells -# that belong to the interior, yet do not belong to the -# aggregate. We will use "int_nonagg_cells" to refer to those -# cells of the background model that belong to the interior -# but are not part of any of the aggregates. -int_nonagg_cells=Vector{Int}() -for cell in int_nonagg_cell_to_cells - append!(int_nonagg_cells,cell) -end - -#INSPECTION -# agg_cells -# int_nonagg_cells -# aggregates - -## Triangulation -Ωbg = Triangulation(bgmodel) -Ω = Triangulation(cutgeo,PHYSICAL) -Ωact = Triangulation(cutgeo,ACTIVE) -Ωcut = Triangulation(cutgeo) - -# Interior cells -Ωbg_agg_cells = view(Ωbg,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface -# construct the interior aggregate cells, in other words the root cells -root_cells=Vector{Int}() -tester_int_nonagg_cells=Vector{Int}() -for cell in int_cells - if cell ∈ int_nonagg_cells - append!(tester_int_nonagg_cells,cell) - else - append!(root_cells,cell) - end -end -@assert(tester_int_nonagg_cells==int_nonagg_cells) -# Cut cells -cut_cells=Vector{Int}() -tester_root_cells=Vector{Int}() -for cell in agg_cells - if cell ∈ root_cells - append!(tester_root_cells,cell) - else - append!(cut_cells,cell) - end -end -@assert(tester_root_cells==root_cells) - - -# TODO Potentially useful?: -# Ω_agg_cells.parent.a.subgrid.cell_node_ids.data == Ω.a.subgrid.cell_node_ids.data # vector containing cell ids - -# Subdomains in background mesh (aggegrate cells are already defined) -Ωbg_int_cells = view(Ωbg,int_cells) # cells in interior -Ωbg_int_nonagg_cells = view(Ωbg,int_nonagg_cells) # cells in interior but not in aggregate -Ωbg_root_cells = view(Ωbg,root_cells) # root cells: in interior and part of aggregate -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) - -# Subdomains in physical mesh -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -Ω_int_cells = view(Ω,int_cells) # cells in interior -Ω_int_nonagg_cells = view(Ω,int_nonagg_cells) # cells in interior but not in aggregate -Ω_root_cells = view(Ω,root_cells) # root cells: in interior and part of aggregate -Ω_cut_cells = view(Ω,cut_cells) # cut cells (part of aggregate) - -## VISUALISATION: -writevtk(Ωbg,"trian_bg") -writevtk(Ωbg_agg_cells,"trian_bg_agg_cells") -writevtk(Ωbg_int_cells,"trian_bg_int_cells") -writevtk(Ωbg_int_nonagg_cells,"trian_bg_int_nonagg_cells") -writevtk(Ωbg_root_cells,"trian_bg_root_cells") -writevtk(Ωbg_cut_cells,"trian_bg_cut_cells") - -writevtk(Ωact,"trian_act") -writevtk(Ω,"trian_phys") -#TODO: WHY DOESN'T THIS WORK? -# writevtk(Ω_agg_cells,"trian_phys_agg_cells") -# writevtk(Ω_int_cells,"trian_phys_int_cells") -# writevtk(Ω_int_nonagg_cells,"trian_phys_int_nonagg_cells") -# writevtk(Ω_root_cells,"trian_phys_root_cells") -# writevtk(Ω_cut_cells,"trian_phys_cut_coot_cells") -degree = 2*2*order -dΩ = Measure(Ω,degree) -dΩact = Measure(Ωact,degree) -dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) -dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) -dΩbg_root_cells = Measure(Ωbg_root_cells,degree) - - -dΩ_agg_cells = Measure(Ω_agg_cells,degree) -dΩcut_cells = Measure(Ω_cut_cells,degree) -dΩroot_cells = Measure(Ω_root_cells,degree) - -# TESTING -area_phys_domain = sum(∫(1.0)dΩ) -area_act_domain = sum(∫(1.0)dΩact) -area_agg_cells = sum(∫(1.0)dΩbg_agg_cells) -area_cut_cells = sum(∫(1.0)dΩbg_cut_cells) -area_root_cells = sum(∫(1.0)dΩbg_root_cells) -@assert(area_agg_cells ≈ area_cut_cells + area_root_cells) - -# TODO: not possible to integrate over the physical part of the domain, e.g. -area_phys_agg_cells = sum(∫(1.0)dΩ_agg_cells) -area_phys_cut_cells = sum(∫(1.0)dΩ_cut_cells) -area_phys_root_cells = sum(∫(1.0)dΩ_root_cells) \ No newline at end of file diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl index c56248ee..a4e0e65f 100644 --- a/bulk_ghost_penalty_stab_tools.jl +++ b/bulk_ghost_penalty_stab_tools.jl @@ -100,6 +100,108 @@ function bulk_ghost_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggre w, r, c end +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells (long version) + # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells (simplified, equivalent version) +""" +function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωbg_cut_cell_dof_ids, + agg_cells_local_dof_ids, + cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωbg_agg_cells⋅du_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩbg_cut_cells) + + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωbg_cut_cell_dof_ids) + end + push!(w, dv_du_mat_contribs) + push!(r, Ωbg_cut_cell_dof_ids) + push!(c, Ωbg_cut_cell_dof_ids) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωbg_agg_cells,ReferenceDomain()) + + proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),cut_cells_to_aggregate_dof_ids) + end + + push!(w, proj_dv_du_mat_contribs) + push!(r, Ωbg_cut_cell_dof_ids) + push!(c, cut_cells_to_aggregate_dof_ids) + + w, r, c +end + function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, @@ -214,6 +316,89 @@ function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, w,r,c end + +function div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩbg_cut_cells + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + ## (I) Let's set up the div_dv_div_du_mat_contribs + # (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩbg_cut_cells + div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) + push!(w, div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + ## (II) Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩbg_cut_cells + div_du=∇⋅(_get_single_field_fe_basis(du)) + + # Compute Π_Q_bb(div_du) + dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) + + div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) + div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(du) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(dv) + div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) + end + + div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + # dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + + proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_cut_cells_to_aggregate_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) + end + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) # test + push!(c, U_cut_cells_to_aggregate_dof_ids) # trial + w,r,c +end + function set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, From aa1d314dba8a2b673531ed93c71aada63e9d6461 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 29 Nov 2024 15:27:53 +1100 Subject: [PATCH 045/120] cleaning files --- bulk_ghost_penalty_canvas_towardsdiv.jl | 558 -------------- bulk_ghost_penalty_canvas_u-only.jl | 922 ------------------------ 2 files changed, 1480 deletions(-) delete mode 100644 bulk_ghost_penalty_canvas_towardsdiv.jl delete mode 100644 bulk_ghost_penalty_canvas_u-only.jl diff --git a/bulk_ghost_penalty_canvas_towardsdiv.jl b/bulk_ghost_penalty_canvas_towardsdiv.jl deleted file mode 100644 index 126f3a0f..00000000 --- a/bulk_ghost_penalty_canvas_towardsdiv.jl +++ /dev/null @@ -1,558 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 0 -uex(x) = -VectorValue(2*x[1],2*x[2]) -pex(x) = (x[1]^2 + x[2]^2) -divuex(x) = -4.0 -# Select geometry -R = 0.2 -geom = disk(R, x0=Point(0.5,0.5)) - -# Setup background model -n=10 -partition = (n,n) -box = get_metadata(geom) -bgmodel = CartesianDiscreteModel((0,1,0,1),partition) -dp = box.pmax - box.pmin -h = dp[1]/n - -# Cut the background model with the mesh -cutdisk = cut(bgmodel,geom) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutdisk) - -""" - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains the global cell IDs of that cells in the background - model that belong to the same aggregate - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_aggregate_to_cells(aggregates) - - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]>1) - if !haskey(touched,agg) - push!(aggregate_to_cells,[i]) - touched[agg]=current_aggregate - current_aggregate+=1 - else - push!(aggregate_to_cells[touched[agg]],i) - end - end - end - end - aggregate_to_cells -end - -function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) - g=get_grid(bgmodel) - cell_coords=get_cell_coordinates(g) - D=num_dims(bgmodel) - xmin=Vector{Float64}(undef,D) - xmax=Vector{Float64}(undef,D) - - # Compute coordinates of the nodes defining the bounding boxes - bounding_box_node_coords= - Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) - ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] - data = collect(1:length(bounding_box_node_coords)) - bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) - for (agg,cells) in enumerate(aggregate_to_cells) - p=first(cell_coords[cells[1]]) - for i in 1:D - xmin[i]=p[i] - xmax[i]=p[i] - end - for cell in cells - for p in cell_coords[cell] - for i in 1:D - xmin[i]=min(xmin[i],p[i]) - xmax[i]=max(xmax[i],p[i]) - end - end - end - bounds = [(xmin[i], xmax[i]) for i in 1:D] - point_iterator = Iterators.product(bounds...) - bounding_box_node_coords[bounding_box_node_ids[agg]] = - reshape([Point(p...) for p in point_iterator],2^D) - end - - # Set up the discrete model of bounding boxes - HEX_AXIS=1 - polytope=Polytope(Fill(HEX_AXIS,D)...) - scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) - cell_types=fill(1,length(bounding_box_node_ids)) - cell_reffes=[scalar_reffe] - grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, - bounding_box_node_ids, - cell_reffes, - cell_types, - Gridap.Geometry.Oriented()) - Gridap.Geometry.UnstructuredDiscreteModel(grid) -end - -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# colors = color_aggregates(aggregates,bgmodel) -# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) -# writevtk(aggregates_bounding_box_model, "bb_model") -# writevtk(bgmodel, "bg_model") - -""" - Changes the domain of a trial/test basis defined on - the reference space of bounding boxes to the reference - space of the agg cells - - TO-DO: in the future, for system of PDEs (MultiField) we should - also take care of blocks (BlockMap) -""" -function change_domain_bb_to_agg_cells(basis_bb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) - @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() - bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) - bb_basis_array = Gridap.CellData.get_data(basis_bb) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Remove transpose map; we will add it later - @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) - @assert isa(bb_basis_array.maps,Fill) - @assert isa(bb_basis_array.maps.value,typeof(transpose)) - bb_basis_array=bb_basis_array.args[1] - end - - bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) - bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), - bb_basis_array_to_Ωagg_cells_array, - ref_agg_cell_to_ref_bb_map) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Add transpose - bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) - end - - Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, - Ωagg_cells, - ReferenceDomain()) -end - -# Set up global spaces -Ωhact = Triangulation(cutdisk,ACTIVE) -degree=2*(order+1) -dΩhact = Measure(Ωhact,degree) - -V = FESpace(Ωhact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -Q = FESpace(Ωhact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -U = TrialFESpace(V) -P = TrialFESpace(Q) -Y = MultiFieldFESpace([V, Q]) -X = MultiFieldFESpace([U, P]) -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -# Generate an array with the global IDs of the cells -# that belong to an aggregrate. From now on, we will -# use the terminology "agg_cells" to refer to those -# cells of the background model that belong to an aggregate -# (i.e., they can be either cut or interior cells) -agg_cells=Vector{Int}() -for cells in aggregate_to_cells - append!(agg_cells,cells) -end - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -Ω=Triangulation(bgmodel) -Ωagg_cells=view(Ω,agg_cells) -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) - -# Generate an array that given the local ID of an "agg_cell" -# returns the ID of the aggregate to which it belongs -# (i.e., flattened version of aggregate_to_cells) -agg_cells_to_aggregate=Vector{Int}() -for (i,cells) in enumerate(aggregate_to_cells) - for _ in cells - push!(agg_cells_to_aggregate,i) - end -end - -# ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} -bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) -bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) -ref_agg_cell_to_ref_bb_map= - lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) - -# Compute LHS of L2 projection -dΩagg_cells = Measure(Ωagg_cells,degree) -reffe =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) - -reffe=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - -aggregate_to_local_cells=copy(aggregate_to_cells) -current_local_cell=1 -for (i,cells) in enumerate(aggregate_to_local_cells) - for j in 1:length(cells) - cells[j]=current_local_cell - current_local_cell+=1 - end -end - -function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - # Change domain of ubb (trial) from Ωbb to Ωagg_cells - ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - # Compute contributions to LHS of L2 projection - agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) - - # Finally assemble LHS contributions - ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) - lazy_map(ass_lhs_map,aggregate_to_local_cells) -end - -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) - - -function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) - map=cell_dof_ids.maps.value - @assert length(map.size)==1 - @assert blockid >= 1 - @assert blockid <= map.size[1] - cell_dof_ids.args[blockid] -end - -Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) -P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) - -function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - agg_cells_local_dof_ids=copy(agg_cells_dof_ids) - current_cell=1 - for agg_cells in aggregate_to_agg_cells - g2l=Dict{Int32,Int32}() - current_local_dof=1 - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in keys(g2l)) - g2l[dof]=current_local_dof - agg_cells_local_dof_ids[current_cell][j]=current_local_dof - current_local_dof+=1 - else - agg_cells_local_dof_ids[current_cell][j]=g2l[dof] - end - end - current_cell+=1 - println(agg_cells_local_dof_ids) - end - end - agg_cells_local_dof_ids -end - -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωagg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωagg_cell_dof_ids, aggregate_to_local_cells) - - -function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) - current_aggregate=1 - current_cell=1 - for agg_cells in aggregate_to_agg_cells - current_aggregate_dof_ids=Int[] - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in current_aggregate_dof_ids) - push!(current_aggregate_dof_ids, dof) - end - end - current_cell+=1 - end - aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids - current_aggregate+=1 - end - aggregate_dof_ids -end - -function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.single_field -end -function _get_single_field_fe_basis(a) - a -end -function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) - true -end -function _is_multifield_fe_basis_component(a) - false -end -function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.nfields -end -function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.fieldid -end - -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) -""" -function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωagg_cell_dof_ids, - agg_cells_local_dof_ids, - agg_cells_to_aggregate_dof_ids, - γ) - - - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, - dΩagg_cells.quad.trian, - ReferenceDomain()) - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) - end - push!(w, dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, Ωagg_cell_dof_ids) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - - proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) - end - - push!(w, proj_dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, agg_cells_to_aggregate_dof_ids) - - w, r, c -end - -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) - -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) - -## TESTING THE PROJECTION of a FE function - - -# writevtk(Ωhact,"output" , cellfields=["div_u"=>∇⋅uh,"pproj"=>testFEfunction]) - -function divergence_in_pressure_space_fe_function(uh::Gridap.FESpaces.SingleFieldFEFunction,P,dq) - dq_data = Gridap.CellData.get_data(_get_single_field_fe_basis(dq)) - div_dv = ∇⋅(uh) ## We should be fine here. - pdofs=Gridap.FESpaces.get_fe_dof_basis(P) - - # DoFs of the FEFunction cell-wise - div_dv_pdofs_values_cell_wise=pdofs(div_dv) - - # Gather cell-wise DoFs into global DoFs vector - div_dv_pdofs_values=Vector{Float64}(undef, num_free_dofs(P)) - Gridap.FESpaces.gather_free_values!(div_dv_pdofs_values,P,div_dv_pdofs_values_cell_wise) - - # free_dof_values is actually a global DoFs vector (!!!) - FEFunction(P,div_dv_pdofs_values) -end - -uex(x)=VectorValue(x[1],x[2]) -pex(x)=x[1] - -testxh=interpolate(X,[uex,pex]) -testuh,testph = testxh -testdivuh_pressure = divergence_in_pressure_space_fe_function(testuh,P, dq) -eh = testdivuh_pressure-(∇⋅testuh) -@assert sum(∫(eh⋅eh)dΩhact) < 1.0e-12 - -# TODO: the following functions should be tested and can then replace the lines below these commented lines. -# function divergence_in_pressure_space_basis(uh::FEBasis,P,dq) -# dq_data = Gridap.CellData.get_data(_get_single_field_fe_basis(dq)) -# div_dv = ∇⋅(_get_single_field_fe_basis(uh)) -# pdofs=Gridap.FESpaces.get_fe_dof_basis(P) -# div_dv_pdofs_values=pdofs(div_dv) -# div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, -# div_dv_pdofs_values, -# dq_data) -# if (Gridap.FESpaces.BasisStyle(uh)==Gridap.FESpaces.TrialBasis()) -# div_dv_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) -# end -# div_dv_in_pressure_space_single_field= -# Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, -# get_triangulation(P), -# BasisStyle(uh), -# Gridap.CellData.ReferenceDomain()) -# div_dv_in_pressure_space= -# Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) -# end -div_dv=∇⋅(_get_single_field_fe_basis(dv)) -pdofs=Gridap.FESpaces.get_fe_dof_basis(P) -div_dv_pdofs_values=pdofs(div_dv) -div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_pdofs_values, - Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) -div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, - get_triangulation(P), - Gridap.FESpaces.TestBasis(), - Gridap.CellData.ReferenceDomain()) -### Compute Π_Q_bb(div_du) -dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) - -# OLD ROUTINE: -# agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) -# ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) ## TODO: prep to assemble vectors -# rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) -test_agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅testdivuh_pressure)dΩagg_cells) -test_ass_rhs_map=BulkGhostPenaltyAssembleRhsFEFunctionMap(test_agg_cells_rhs_contribs) -test_rhs=lazy_map(test_ass_rhs_map,aggregate_to_local_cells) - -test_div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,test_rhs) - -test_div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - test_div_dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(qbb)) -test_div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(test_div_dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) -div_uh_proj_bb=Gridap.CellData.GenericCellField(test_div_dv_l2_proj_bb_array_agg_cells, - dΩagg_cells.quad.trian, - ReferenceDomain()) - -x=get_cell_points(dΩagg_cells.quad.trian) -div_uh_proj_bb(x)[8] -testdivuh_pressure(x)[7] - -res = testdivuh_pressure - div_uh_proj_bb -@assert sum(∫(res*res)*dΩagg_cells) < 1.0e-12 \ No newline at end of file diff --git a/bulk_ghost_penalty_canvas_u-only.jl b/bulk_ghost_penalty_canvas_u-only.jl deleted file mode 100644 index 4a985f34..00000000 --- a/bulk_ghost_penalty_canvas_u-only.jl +++ /dev/null @@ -1,922 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 0 -uex(x) = -VectorValue(2*x[1],2*x[2]) -divuex(x) = -4.0 - -# Select geometry -R = 0.2 -geom = disk(R, x0=Point(0.5,0.5)) - -# Setup background model -n=16 -partition = (n,n) -box = get_metadata(geom) -bgmodel = CartesianDiscreteModel((0,1,0,1),partition) -dp = box.pmax - box.pmin -h = dp[1]/n - -# Cut the background model with the mesh -cutgeo = cut(bgmodel,geom) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -#INVESTIGATING: Number of aggregates, cells and bg cells. -@assert length(aggregates) == n*n -num_cell = length(aggregates) -using StatsBase -counts = countmap(aggregates,alg=:dict) -agg_counts = filter(((k,v),) -> v > 1 && k != 0, counts) -num_aggregates = length(agg_counts) -num_cells_in_aggregates = 0 -for (k,v) in agg_counts - println(v) - num_cells_in_aggregates +=v -end -num_cells_not_in_aggregates = counts[0] -non_agg_counts = filter(((k,v),) -> v <= 1 || k==0, counts) -num_cells_not_in_aggregates = 0 -for (k,v) in non_agg_counts - println(v) - num_cells_not_in_aggregates +=v -end -num_ext_cells = counts[0] -@assert num_cells_in_aggregates + num_cells_not_in_aggregates == num_cell -println("Out of the $num_cell cells, $num_cells_in_aggregates belong to aggregates and $num_cells_not_in_aggregates are not part of aggregates. Note that we have $num_ext_cells exterior cells") -println("Assuming that there is one root per aggregate, we have $(num_cells_in_aggregates-num_aggregates) cut cells and $num_aggregates roots in the $num_aggregates aggregates cotntaining $num_cells_in_aggregates in total.") - -""" - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains the global cell IDs of that cells in the background - model that belong to the same aggregate - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_aggregate_to_cells(aggregates) - - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]>1) - if !haskey(touched,agg) - push!(aggregate_to_cells,[i]) - touched[agg]=current_aggregate - current_aggregate+=1 - else - push!(aggregate_to_cells[touched[agg]],i) - end - end - end - end - aggregate_to_cells -end - -""" - Creates an array of arrays with as many entries - as interior cells that are not part of any aggegrate. - For each interior cell, the array - contains the global cell IDs of that cells in the background - model that belong to the same interior cell - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_int_nonagg_cell_to_cells(aggregates) - - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - interior_cell_to_cells=Vector{Vector{Int}}() - current_interior_cell=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]==1) - if !haskey(touched,agg) - push!(interior_cell_to_cells,[i]) - touched[agg]=current_interior_cell - current_interior_cell+=1 - else - push!(interior_cell_to_cells[touched[agg]],i) - end - end - end - end - interior_cell_to_cells -end - - -function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) - g=get_grid(bgmodel) - cell_coords=get_cell_coordinates(g) - D=num_dims(bgmodel) - xmin=Vector{Float64}(undef,D) - xmax=Vector{Float64}(undef,D) - - # Compute coordinates of the nodes defining the bounding boxes - bounding_box_node_coords= - Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) - ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] - data = collect(1:length(bounding_box_node_coords)) - bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) - for (agg,cells) in enumerate(aggregate_to_cells) - p=first(cell_coords[cells[1]]) - for i in 1:D - xmin[i]=p[i] - xmax[i]=p[i] - end - for cell in cells - for p in cell_coords[cell] - for i in 1:D - xmin[i]=min(xmin[i],p[i]) - xmax[i]=max(xmax[i],p[i]) - end - end - end - bounds = [(xmin[i], xmax[i]) for i in 1:D] - point_iterator = Iterators.product(bounds...) - bounding_box_node_coords[bounding_box_node_ids[agg]] = - reshape([Point(p...) for p in point_iterator],2^D) - end - - # Set up the discrete model of bounding boxes - HEX_AXIS=1 - polytope=Polytope(Fill(HEX_AXIS,D)...) - scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) - cell_types=fill(1,length(bounding_box_node_ids)) - cell_reffes=[scalar_reffe] - grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, - bounding_box_node_ids, - cell_reffes, - cell_types, - Gridap.Geometry.Oriented()) - Gridap.Geometry.UnstructuredDiscreteModel(grid) -end - -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# colors = color_aggregates(aggregates,bgmodel) -# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) -# writevtk(aggregates_bounding_box_model, "bb_model") -# writevtk(bgmodel, "bg_model") - -""" - Changes the domain of a trial/test basis defined on - the reference space of bounding boxes to the reference - space of the agg cells - - TO-DO: in the future, for system of PDEs (MultiField) we should - also take care of blocks (BlockMap) -""" -function change_domain_bb_to_agg_cells(basis_bb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) - @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() - bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) - bb_basis_array = Gridap.CellData.get_data(basis_bb) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Remove transpose map; we will add it later - @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) - @assert isa(bb_basis_array.maps,Fill) - @assert isa(bb_basis_array.maps.value,typeof(transpose)) - bb_basis_array=bb_basis_array.args[1] - end - - bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) - bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), - bb_basis_array_to_Ωagg_cells_array, - ref_agg_cell_to_ref_bb_map) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Add transpose - bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) - end - - Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, - Ωagg_cells, - ReferenceDomain()) -end - -# Generate an array with the global IDs of the cells -# that belong to an aggregrate. From now on, we will -# use the terminology "agg_cells" to refer to those -# cells of the background model that belong to an aggregate -# (i.e., they can be either cut or interior cells) -agg_cells=Vector{Int}() -for cells in aggregate_to_cells - append!(agg_cells,cells) -end - -# Generate an array with the global IDs of the cells -# that belong to the interior, yet do not belong to the -# aggregate. We will use "int_nonagg_cells" to refer to those -# cells of the background model that belong to the interior -# but are not part of any of the aggregates. -int_nonagg_cells=Vector{Int}() -for cell in int_nonagg_cell_to_cells - append!(int_nonagg_cells,cell) -end - -#INSPECTION -# agg_cells -# int_nonagg_cells -# aggregates - -## Triangulation -Ωbg = Triangulation(bgmodel) -Ω = Triangulation(cutgeo,PHYSICAL) -Ωact = Triangulation(cutgeo,ACTIVE) -Ωcut = Triangulation(cutgeo) - -# Interior cells -Ωbg_agg_cells = view(Ωbg,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface -# construct the interior aggregate cells, in other words the root cells -root_cells=Vector{Int}() -tester_int_nonagg_cells=Vector{Int}() -for cell in int_cells - if cell ∈ int_nonagg_cells - append!(tester_int_nonagg_cells,cell) - else - append!(root_cells,cell) - end -end -@assert(tester_int_nonagg_cells==int_nonagg_cells) -# Cut cells -cut_cells=Vector{Int}() -tester_root_cells=Vector{Int}() -for cell in agg_cells - if cell ∈ root_cells - append!(tester_root_cells,cell) - else - append!(cut_cells,cell) - end -end -@assert(tester_root_cells==root_cells) - - -# TODO Potentially useful?: -# Ω_agg_cells.parent.a.subgrid.cell_node_ids.data == Ω.a.subgrid.cell_node_ids.data # vector containing cell ids - -# Subdomains in background mesh (aggegrate cells are already defined) -Ωbg_int_cells = view(Ωbg,int_cells) # cells in interior -Ωbg_int_nonagg_cells = view(Ωbg,int_nonagg_cells) # cells in interior but not in aggregate -Ωbg_root_cells = view(Ωbg,root_cells) # root cells: in interior and part of aggregate -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) - -# Subdomains in physical mesh -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -Ω_int_cells = view(Ω,int_cells) # cells in interior -Ω_int_nonagg_cells = view(Ω,int_nonagg_cells) # cells in interior but not in aggregate -Ω_root_cells = view(Ω,root_cells) # root cells: in interior and part of aggregate -Ω_cut_cells = view(Ω,cut_cells) # cut cells (part of aggregate) - -## VISUALISATION: -writevtk(Ωbg,"trian_bg") -writevtk(Ωbg_agg_cells,"trian_bg_agg_cells") -writevtk(Ωbg_int_cells,"trian_bg_int_cells") -writevtk(Ωbg_int_nonagg_cells,"trian_bg_int_nonagg_cells") -writevtk(Ωbg_root_cells,"trian_bg_root_cells") -writevtk(Ωbg_cut_cells,"trian_bg_cut_cells") - -writevtk(Ωact,"trian_act") -writevtk(Ω,"trian_phys") -#TODO: WHY DOESN'T THIS WORK? -# writevtk(Ω_agg_cells,"trian_phys_agg_cells") -# writevtk(Ω_int_cells,"trian_phys_int_cells") -# writevtk(Ω_int_nonagg_cells,"trian_phys_int_nonagg_cells") -# writevtk(Ω_root_cells,"trian_phys_root_cells") -# writevtk(Ω_cut_cells,"trian_phys_cut_coot_cells") -degree = 2*2*order -dΩ = Measure(Ω,degree) -dΩact = Measure(Ωact,degree) -dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) -dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) -dΩbg_root_cells = Measure(Ωbg_root_cells,degree) - - -dΩagg_cells = Measure(Ω_agg_cells,degree) -dΩcut_cells = Measure(Ω_cut_cells,degree) -dΩroot_cells = Measure(Ω_root_cells,degree) - -# TESTING -area_phys_domain = sum(∫(1.0)dΩ) -area_act_domain = sum(∫(1.0)dΩact) -area_agg_cells = sum(∫(1.0)dΩbg_agg_cells) -area_cut_cells = sum(∫(1.0)dΩbg_cut_cells) -area_root_cells = sum(∫(1.0)dΩbg_root_cells) -@assert(area_agg_cells ≈ area_cut_cells + area_root_cells) - -# TODO: not possible to integrate over the physical part of the domain, e.g. -area_phys_agg_cells = sum(∫(1.0)dΩ_agg_cells) -area_phys_cut_cells = sum(∫(1.0)dΩ_cut_cells) -area_phys_root_cells = sum(∫(1.0)dΩ_root_cells) - -# colors = color_aggregates(aggregates,bgmodel) -# TODO: (Q1) WHEN WE DEFINE dΩagg_cells are we intergrating over the entire aggregate or only up to the physical part of it? That is, when we add the stabilization what do we intend to do? - -## Set up global spaces -Ωact = Triangulation(cutgeo,ACTIVE) -V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -# Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -U = TrialFESpace(V) -# P = TrialFESpace(Q) -# Y = MultiFieldFESpace([V, Q]) -# X = MultiFieldFESpace([U, P]) - -## MAPS - - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) - -# Generate an array that given the local ID of an "agg_cell" -# returns the ID of the aggregate to which it belongs -# (i.e., flattened version of aggregate_to_cells) -agg_cells_to_aggregate=Vector{Int}() -for (i,cells) in enumerate(aggregate_to_cells) - for _ in cells - push!(agg_cells_to_aggregate,i) - end -end - -# ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} -bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) -bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) -ref_agg_cell_to_ref_bb_map= - lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) - -# Compute LHS of L2 projection -degree=2*(order+1) -dΩagg_cells = Measure(Ωagg_cells,degree) -reffe =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) - -reffe=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - - -aggregate_to_local_cells=copy(aggregate_to_cells) -current_local_cell=1 -for (i,cells) in enumerate(aggregate_to_local_cells) - for j in 1:length(cells) - cells[j]=current_local_cell - current_local_cell+=1 - end -end - -function set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - # Change domain of ubb (trial) from Ωbb to Ωagg_cells - ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - # Compute contributions to LHS of L2 projection - agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) - - # Finally assemble LHS contributions - ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) - lazy_map(ass_lhs_map,aggregate_to_local_cells) -end - -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregates_bounding_box_model, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) - -# Compute contributions to the RHS of the L2 projection -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) - map=cell_dof_ids.maps.value - @assert length(map.size)==1 - @assert blockid >= 1 - @assert blockid <= map.size[1] - cell_dof_ids.args[blockid] -end - -Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) -P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) -# Ωagg_cell_dof_ids[1][1] # cell 1, velo dof -# Ωagg_cell_dof_ids[1][2] # cell 1, pressure dofs - -### BEGIN TESTING CODE -# This code is just for testing purposes, so I have commented it out -# It allows to evaluate the LHS of the L2 projection corresponding to a -# particular FE function, instead of a basis -# uhex=interpolate(uex,Ustd) -# agg_cells_lhs_contribs_uhex=get_array(∫(vbb_Ωagg_cells*uhex)dΩagg_cells) -# ass_lhs_map_uhex=AssembleLhsMap(agg_cells_lhs_contribs_uhex) -# lhs_uhex=lazy_map(ass_lhs_map_uhex,aggregate_to_local_cells) -### END TESTING CODE - -function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - agg_cells_local_dof_ids=copy(agg_cells_dof_ids) - current_cell=1 - for agg_cells in aggregate_to_agg_cells - g2l=Dict{Int32,Int32}() - current_local_dof=1 - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in keys(g2l)) - g2l[dof]=current_local_dof - agg_cells_local_dof_ids[current_cell][j]=current_local_dof - current_local_dof+=1 - else - agg_cells_local_dof_ids[current_cell][j]=g2l[dof] - end - end - current_cell+=1 - println(agg_cells_local_dof_ids) - end - end - agg_cells_local_dof_ids -end - -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωagg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωagg_cell_dof_ids, aggregate_to_local_cells) - - -function set_up_h_U(aggregates_bounding_box_model, - agg_cells_to_aggregate, - Ωagg_cells) - degree = 0 # We are integrating a constant function - # Thus, degree=0 is enough for exact integration - Ωbb = Triangulation(aggregates_bounding_box_model) - dΩbb = Measure(Ωbb, degree) - h_U_array = get_array(∫(1.0)dΩbb) - h_U_array = lazy_map(Reindex(h_U_array), agg_cells_to_aggregate) - CellField(h_U_array, Ωagg_cells) -end - - -function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) - current_aggregate=1 - current_cell=1 - for agg_cells in aggregate_to_agg_cells - current_aggregate_dof_ids=Int[] - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in current_aggregate_dof_ids) - push!(current_aggregate_dof_ids, dof) - end - end - current_cell+=1 - end - aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids - current_aggregate+=1 - end - aggregate_dof_ids -end - -function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.single_field -end -function _get_single_field_fe_basis(a) - a -end -function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) - true -end -function _is_multifield_fe_basis_component(a) - false -end -function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.nfields -end -function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.fieldid -end - -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) -""" -function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωagg_cell_dof_ids, - agg_cells_local_dof_ids, - agg_cells_to_aggregate_dof_ids, - h_U, - γ) - - - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, - dΩagg_cells.quad.trian, - ReferenceDomain()) - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) - end - push!(w, dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, Ωagg_cell_dof_ids) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - - proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) - end - - push!(w, proj_dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, agg_cells_to_aggregate_dof_ids) - - w, r, c -end - -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) - -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) - -γ = 10.0 # Interior bulk-penalty stabilization parameter - # (@amartinhuertas no idea what a reasonable value is) - -h_U = set_up_h_U(aggregates_bounding_box_model, agg_cells_to_aggregate, Ωagg_cells) - -# Manually set up the arrays that collect_cell_matrix would return automatically -wp,rp,cp=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωagg_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - -wu,ru,cu=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωagg_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - -Ωcut = Triangulation(cutgeo,PHYSICAL) -dΩcut = Measure(Ωcut,degree) -# # Set up global projection matrix -# Ωcut = Triangulation(cutgeo,PHYSICAL) -# dΩcut = Measure(Ωcut,degree) -# a_nodiv((u,p),(v,q))=∫(v⋅u+q*p)dΩcut -# wrc_nodiv=Gridap.FESpaces.collect_cell_matrix(X,Y,a_nodiv(dx,dy)) - -# assem_nodiv=SparseMatrixAssembler(X,Y) -# Anostab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) -# cond(Array(Anostab_nodiv)) - -# # Add the bulk penalty stabilization term to wrc_nodiv -# push!(wrc_nodiv[1], wp...) -# push!(wrc_nodiv[2], rp...) -# push!(wrc_nodiv[3], cp...) - -# push!(wrc_nodiv[1], wu...) -# push!(wrc_nodiv[2], ru...) -# push!(wrc_nodiv[3], cu...) - -# Awithstab_nodiv=assemble_matrix(assem_nodiv, wrc_nodiv) -# cond(Array(Awithstab_nodiv)) - -# # Set up rhs global projection -# l_nodiv((v,q))=∫(v⋅uex+q*pex)dΩcut -# b_nodiv = assemble_vector(l_nodiv, Y) - -# global_l2_proj_dofs_nodiv = Awithstab_nodiv\b_nodiv -# xh_nodiv = FEFunction(X, global_l2_proj_dofs_nodiv) -# uh_nodiv,ph_nodiv = xh_nodiv - -# euh_nodiv = uex-uh_nodiv -# # @assert sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) < 1.0e-12 - -# eph_nodiv = pex-ph_nodiv -# # @assert sum(∫(eph_nodiv*eph_nodiv)*dΩcut) < 1.0e-12 -# eph_nodiv_norm = sum(∫(eph_nodiv*eph_nodiv)*dΩcut) -# euh_nodiv_norm = sum(∫(euh_nodiv⋅euh_nodiv)*dΩcut) -# # k=0 yields eph = 0.00012 and euh = 5.5e-30 -# edivuh_nodiv = divuex-(∇⋅uh_nodiv) -# edivuh_nodiv_norm = sum(∫(edivuh_nodiv⋅edivuh_nodiv)*dΩcut) - -## TEST 1 -a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩcut -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) - -assem=SparseMatrixAssembler(X,Y) -Anostab=assemble_matrix(assem, wrc) -cond_nostab = cond(Array(Anostab)) - -# Set up rhs global projection -l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩcut -b = assemble_vector(l, Y) - -## NO STABILIZATION -if cond_nostab<1e35 - global_l2_proj_dofs_nostab = Anostab\b - xh_nostab = FEFunction(X, global_l2_proj_dofs_nostab) - uh_nostab,ph_nostab = xh_nostab - euh_nostab = uex-uh_nostab - eph_nostab = pex-ph_nostab - edivuh_nostab = divuex-(∇⋅uh_nostab) - norm_euh_nostab = sum(∫(euh_nostab⋅euh_nostab)*dΩcut) - norm_eph_nostab = sum(∫(eph_nostab*eph_nostab)*dΩcut) - edivuh_nostab = sum(∫(edivuh_nostab⋅edivuh_nostab)*dΩcut) -else - println("Singular exception is raised as error when solving the system (as cond= $cond_nostab is high?)") -end -# k=0 yields euh = 1.2e-32, eph = 0.00017, edivuh = 6.8e-30, κ= 3.15e32 -# k=0 yields euh = ?, eph = ?, edivuh = ?, κ= 4.3e36 - -## U + P STABILIZATION -# Add the bulk penalty stabilization terms for u and p to wrc -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) - -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) - -# Check the condition number when only the p and u stabilization terms are included. -Aupstab=assemble_matrix(assem, wrc) -cond_upstab = cond(Array(Aupstab)) - -# CHECK errors when only the p and u stabilization terms are included. -global_l2_proj_dofs_upstab = Aupstab\b -xh_upstab = FEFunction(X, global_l2_proj_dofs_upstab) -uh_upstab,ph_upstab = xh_upstab -euh_upstab = uex-uh_upstab -eph_upstab = pex-ph_upstab -edivuh_upstab = divuex-(∇⋅uh_upstab) -norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩcut) -norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩcut) -norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩcut) -# k=0 yields euh = 6.3e-31, eph = 0.00055, edivuh = 2.4e-28, κ= 11492 -# k=2 yields euh = 5.3e-22, eph = 3.0e-18, edivuh = 3.0e-18, κ= 1.7e11 - -## +DIVU STABILIZATION -## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) -# Manually set up the arrays that collect_cell_matrix would return automatically -w_divu = [] -r_divu = [] -c_divu = [] - -## (I) Let's set up the div_dv_div_du_mat_contribs (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells -div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) -if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) -end - -push!(w_divu, div_dv_div_du_mat_contribs) -push!(r_divu, U_Ωagg_cell_dof_ids) -push!(c_divu, U_Ωagg_cell_dof_ids) - -## Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩ_agg_cells -div_dv=∇⋅(_get_single_field_fe_basis(dv)) -pdofs=Gridap.FESpaces.get_fe_dof_basis(P) -div_dv_pdofs_values=pdofs(div_dv) -div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_pdofs_values, - Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) -div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, - get_triangulation(P), - Gridap.FESpaces.TestBasis(), - Gridap.CellData.ReferenceDomain()) -div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) - -div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) -div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, - get_triangulation(P), - Gridap.FESpaces.TrialBasis(), - Gridap.CellData.ReferenceDomain()) -div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) - -div_dv_div_du_in_pressure_space_mat_contribs=get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? -div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs - -### Compute Π_Q_bb(div_du) -dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) -agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du_in_pressure_space_single_field)dΩagg_cells) -# agg_cells_rhs_contribs[1] -ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) -rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) -div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - -# Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate -div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(qbb)) - -div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - -div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - -if (_is_multifield_fe_basis_component(dp)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - div_du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - div_du_l2_proj_bb_array_agg_cells) -end - -div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) - -# In the MultiField case, I have had to add this change domain -# call before setting up the term right below. Otherwise, we get an error -# when trying to multiply the fields. Not sure why this is happening -# dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) -div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) - -proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) - -P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) - -if (_is_multifield_fe_basis_component(dp)) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - P_agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_agg_cells_to_aggregate_dof_ids) -end - -push!(w_divu, proj_div_dv_div_du_mat_contribs) -push!(r_divu, U_Ωagg_cell_dof_ids) # test -push!(c_divu, P_agg_cells_to_aggregate_dof_ids) # trial - -## Now add div stabilization to A -push!(wrc[1], w_divu...) -push!(wrc[2], r_divu...) -push!(wrc[3], c_divu...) - -# Assembly -Awithstab=assemble_matrix(assem, wrc) -cond_withstab = cond(Array(Awithstab)) - -global_l2_proj_dofs_withstab = Awithstab\b -xh_withstab = FEFunction(X, global_l2_proj_dofs_withstab) -uh_withstab,ph_withstab = xh_withstab -euh_withstab = uex-uh_withstab -eph_withstab = pex-ph_withstab -edivuh_withstab = divuex-(∇⋅uh_withstab) -norm_euh_withstab = sum(∫(euh_withstab⋅euh_withstab)*dΩcut) -norm_eph_withstab = sum(∫(eph_withstab*eph_withstab)*dΩcut) -norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) -# k=0 yields euh = 0.0014, eph = 0.47, edivuh = 0.47, κ= 8.51e11 -# k=2 yields euh = 0.00013, eph = 0.088, edivuh = 0.088, κ= 2.9e14 \ No newline at end of file From c816a973fde2a2e99b384c488090dc0cacec7123 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Sat, 30 Nov 2024 17:43:44 +1100 Subject: [PATCH 046/120] added documentation --- aggregates_bounding_boxes_tools.jl | 162 ++++++++++++++++++++--------- 1 file changed, 110 insertions(+), 52 deletions(-) diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl index 6f3e2bd6..2af6c0cd 100644 --- a/aggregates_bounding_boxes_tools.jl +++ b/aggregates_bounding_boxes_tools.jl @@ -38,6 +38,46 @@ function setup_aggregate_to_cells(aggregates) aggregate_to_cells end +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cut cells in + the background model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_aggregate_to_cut_cells(aggregates, root_cells) + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cut_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]>1) && i ∉ root_cells + if !haskey(touched,agg) + push!(aggregate_to_cut_cells,[i]) + touched[agg]=current_aggregate + current_aggregate+=1 + else + push!(aggregate_to_cut_cells[touched[agg]],i) + end + end + end + end + aggregate_to_cut_cells +end + """ Creates an array of arrays with as many entries as interior cells that are not part of any aggegrate. @@ -127,12 +167,16 @@ function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) Gridap.Geometry.UnstructuredDiscreteModel(grid) end +""" + Generate an array with the global IDs of the cells + that belong to an aggregrate. From now on, we will + use the terminology "agg_cells" to refer to those + cells of the background model that belong to an aggregate + (i.e., they can be either cut or interior cells) + + TO-DO: perhaps merge this function with setup_int_nonagg_cells +""" function setup_agg_cells(aggregate_to_cells) - # Generate an array with the global IDs of the cells - # that belong to an aggregrate. From now on, we will - # use the terminology "agg_cells" to refer to those - # cells of the background model that belong to an aggregate - # (i.e., they can be either cut or interior cells) agg_cells=Vector{Int}() for cells in aggregate_to_cells append!(agg_cells,cells) @@ -140,13 +184,17 @@ function setup_agg_cells(aggregate_to_cells) return agg_cells end +""" + Generate an array with the global IDs of the cells + that belong to the interior, yet do not belong to the + aggregate. We will use "int_nonagg_cells" to refer to those + cells of the background model that belong to the interior + but are not part of any of the aggregates. Thus, all interior + cells but not including the root cells of the aggregates. + + TO-DO: perhaps merge this function with setup_agg_cells +""" function setup_int_nonagg_cells(int_nonagg_cell_to_cells) - # Generate an array with the global IDs of the cells - # that belong to the interior, yet do not belong to the - # aggregate. We will use "int_nonagg_cells" to refer to those - # cells of the background model that belong to the interior - # but are not part of any of the aggregates. Thus, all interior - # cells but not including the root cells of the aggregates. int_nonagg_cells=Vector{Int}() for cell in int_nonagg_cell_to_cells append!(int_nonagg_cells,cell) @@ -154,9 +202,15 @@ function setup_int_nonagg_cells(int_nonagg_cell_to_cells) return int_nonagg_cells end +""" + Generate an array with the global IDs of the cells + that are the root cells of the aggregrates. + + TO-DO: perhaps merge this function with setup_cut_cells, + e.g. as a function that selects cells from list A which + are not part of a list B. +""" function setup_root_cells(int_cells, int_nonagg_cells) - # Generate an array with the global IDs of the cells - # that are the root cells of the aggregrates. root_cells=Vector{Int}() tester_int_nonagg_cells=Vector{Int}() for cell in int_cells @@ -170,9 +224,15 @@ function setup_root_cells(int_cells, int_nonagg_cells) return root_cells end +""" + Generate an array with the global IDs of the cells + that are the cut cells of the aggregrates. + + TO-DO: perhaps merge this function with setup_cut_cells, + e.g. as a function that selects cells from list A which + are not part of a list B. +""" function setup_cut_cells(agg_cells, root_cells) - # Generate an array with the global IDs of the cells - # that are the cut cells of the aggregrates. cut_cells=Vector{Int}() tester_root_cells=Vector{Int}() for cell in agg_cells @@ -185,11 +245,18 @@ function setup_cut_cells(agg_cells, root_cells) @assert(tester_root_cells==root_cells) cut_cells end + +""" + Generate an array that given the local ID of an "agg_cell" + returns the ID of the aggregate to which it belongs + (i.e., flattened version of aggregate_to_cells) + + TO-DO: perhaps merge this function with , + setup_cut_cells_in_agg_cells_to_aggregate + +""" function setup_agg_cells_to_aggregate(aggregate_to_cells) - # Generate an array that given the local ID of an "agg_cell" - # returns the ID of the aggregate to which it belongs - # (i.e., flattened version of aggregate_to_cells) agg_cells_to_aggregate=Vector{Int}() for (i,cells) in enumerate(aggregate_to_cells) for _ in cells @@ -199,10 +266,15 @@ function setup_agg_cells_to_aggregate(aggregate_to_cells) agg_cells_to_aggregate end +""" + Generate an array that given the local ID of an cut "agg_cell" + returns the ID of the aggregate to which it belongs + (i.e., flattened version of aggregate_to_cut_cells) + + TO-DO: perhaps merge this function with , + setup_agg_cells_to_aggregate +""" function setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) - # Generate an array that given the local ID of an "agg_cell" - # returns the ID of the aggregate to which it belongs - # (i.e., flattened version of aggregate_to_cut_cells) cut_cells_in_agg_cells_to_aggregate=Vector{Int}() for (i,cells) in enumerate(aggregate_to_cut_cells) for _ in cells @@ -212,37 +284,15 @@ function setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) cut_cells_in_agg_cells_to_aggregate end -function setup_aggregate_to_cut_cells(aggregates, root_cells) - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cut_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]>1) && i ∉ root_cells - if !haskey(touched,agg) - push!(aggregate_to_cut_cells,[i]) - touched[agg]=current_aggregate - current_aggregate+=1 - else - push!(aggregate_to_cut_cells[touched[agg]],i) - end - end - end - end - aggregate_to_cut_cells -end +""" + Renumbers the global cell IDs to local cell IDs in the array of arrays + with as many entries as aggregates. For each aggregate, the array + now contains the local cell IDs of that cells in the background + model that belong to the same aggregate + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" function setup_aggregate_to_local_cells(aggregate_to_cells) aggregate_to_local_cells=deepcopy(aggregate_to_cells) current_local_cell=1 @@ -293,14 +343,19 @@ function change_domain_bb_to_agg_cells(basis_bb, ReferenceDomain()) end +""" + Define mapping ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} +""" function setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model,agg_cells_to_aggregate) - # ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) ref_agg_cell_to_ref_bb_map= lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) end +""" + Compute local dof ids of the aggregated cells +""" function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) agg_cells_local_dof_ids=copy(agg_cells_dof_ids) current_cell=1 @@ -325,6 +380,9 @@ function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cel agg_cells_local_dof_ids end +""" + Returns the dof ids for the aggregates +""" function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) current_aggregate=1 From 157fc765cf10383e3f753737470c9ce4a19d24a0 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Sun, 1 Dec 2024 10:19:11 +1100 Subject: [PATCH 047/120] fixed documentation error --- aggregates_bounding_boxes_tools.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl index 2af6c0cd..68f11cf6 100644 --- a/aggregates_bounding_boxes_tools.jl +++ b/aggregates_bounding_boxes_tools.jl @@ -344,7 +344,7 @@ function change_domain_bb_to_agg_cells(basis_bb, end """ - Define mapping ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} + Define mapping ref_agg_cell_to_ref_bb_map: K_ref -> K -> bb -> bb_ref """ function setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model,agg_cells_to_aggregate) bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) From eed1b3fab07afe9dc5e18c85cf9b60100e294f57 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Sun, 1 Dec 2024 22:27:45 +1100 Subject: [PATCH 048/120] added full terms + test --- ...iv_on_cut_cells _exploration_full-terms.jl | 543 ++++++++++++++++++ bulk_ghost_penalty_stab_tools.jl | 254 +++++++- 2 files changed, 794 insertions(+), 3 deletions(-) create mode 100644 bulk_ghost_penalty_canvas_div_on_cut_cells _exploration_full-terms.jl diff --git a/bulk_ghost_penalty_canvas_div_on_cut_cells _exploration_full-terms.jl b/bulk_ghost_penalty_canvas_div_on_cut_cells _exploration_full-terms.jl new file mode 100644 index 00000000..8c4f892f --- /dev/null +++ b/bulk_ghost_penalty_canvas_div_on_cut_cells _exploration_full-terms.jl @@ -0,0 +1,543 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 + +# Select geometry +R = 0.2 +geom = disk(R, x0=Point(0.5,0.5)) + +# Setup background model +n=16 +partition = (n,n) +box = get_metadata(geom) +bgmodel = CartesianDiscreteModel((0,1,0,1),partition) +dp = box.pmax - box.pmin +h = dp[1]/n + +# Cut the background model with the mesh +cutgeo = cut(bgmodel,geom) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# Triangulations +Ωbg = Triangulation(bgmodel) +Ωact = Triangulation(cutgeo,ACTIVE) + +# Physical domain +Ω = Triangulation(cutgeo,PHYSICAL) +degree=2*(order+1) +dΩ = Measure(Ω,degree) + +# Set up global spaces +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +U = TrialFESpace(V) +P = TrialFESpace(Q) +Y = MultiFieldFESpace([V, Q]) +X = MultiFieldFESpace([U, P]) +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +# Aggregate cells and triangulation +agg_cells =setup_agg_cells(aggregate_to_cells) +Ωbg_agg_cells=view(Ωbg,agg_cells) + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) +agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) +ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate) + +# Spaces on bounding boxes +reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) +reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + +# Numerical integration (Measures) +degree=2*(order+1) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) + +# LHS of L2 projection on bounding boxes. +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + ubb, + vbb) + +# Selecting relevant global dofs ids of aggregate cells (from background mesh) +Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) +U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) +P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) + +# Computing local (per aggregate) dof ids +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) + +# Compute global dofs ids per aggregate and reindex these +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) +P_Ωbg_agg_cell_dof_ids + +# parameters +γ = 10.0 # Interior bulk-penalty stabilization parameter +h_U = 1.0 + +########################################### +### STABILIZATION ON Ωagg\Troot ### +########################################### + +## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) + +## (2) FIND THE INTERIOR CELLS +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface + +## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS +root_cells = setup_root_cells(int_cells, int_nonagg_cells) +cut_cells = setup_cut_cells(agg_cells, root_cells) + +## (4) CUT CELLS AND MEASURE +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) + +# (5) DOF IDS related to cut cells +Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) +U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) +P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) + +# (6) Defining cut_cells_to_aggregate_dof_ids +aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) +cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) + +# (7) Compute stabilization terms for u and p +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +#DIV stabilization part +wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +## FULL stabilization terms: +wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis +# (k=0,n=16) 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +## TEST WITH MANUFACTURED SOLUTIONS +a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ +# wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +assem=SparseMatrixAssembler(X,Y) +l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ +b = assemble_vector(l, Y) + +function compute_quantities(A,b,dΩ) + cond_A = cond(Array(A)) + norm_A = norm(A) + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + norm_euh = sum(∫(euh⋅euh)*dΩ) + norm_eph = sum(∫(eph*eph)*dΩ) + norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) + return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) +end + +############## (k=0,n=16) ##################################################################### +# (k=0,n=16) 2.31e9, 6040.0, 1.20e-27, 7.71e-5, 1.77e-30 # -- NO STAB -- +# (k=0,n=16) 3.58e8, 6040.0, 2.0 e-28, 7.71e-5, 1.93e-30 # U +# (k=0,n=16) 3.58e8, 6050.0, 1.67e-27, 7.71e-5, 4.26e-30 # U_FULL +# (k=0,n=16) 7.59e6, 55500.0, 1.64e-26, 1.46e-4, 4.20e-29 # U + P + DIVU +# (k=0,n=16) 7.59e6, 55500.0, 6.17e-26, 1.45e-4, 9.62e-29 # U_FULL + P + DIVU +# (k=0,n=16) 7.64e6, 54500.0, 8.79e-26, 1.46e-4, 1.98e-28 # U_FULL + P + DIVU_FULL (*) +# (k=0,n=16) 1.28e7, 55500.0, 1.64e-26, 1.16e-4, 4.20e-29 # U + P_FULL + DIVU +# (k=0,n=16) 1.28e7, 55500.0, 6.17e-26, 1.16e-4, 9.62e-29 # U_FULL + P_FULL + DIVU +# (k=0,n=16) 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL +# (k=0,n=16) 7.64e6, 54500.0, 2.75e-26, 1.46e-4, 1.14e-28 # U + P + DIVU_FULL (*) +############################################################################################### + +############## (k=2,n=16) ##################################################################### +# (k=0,n=16) 2.82e29, 9.21e8, 4.0e-12, 7.79e-28, 2.34e-13 # -- NO STAB -- +# (k=0,n=16) 2.82e29, 9.21e8, 2.05e-18, 7.79e-28, 1.66e-19 # U +# (k=0,n=16) 2.82e29, 9.21e8, 1.23e-16, 7.79e-28, 1.39e-18 # U_FULL +# (k=0,n=16) 4.72e16, 9.45e9, 3.08e-14, 4.07e-29, 1.76e-17 # U + P + DIVU +# (k=0,n=16) 4.72e16, 9.45e9, 2.52e-11, 4.07e-29, 3.17e-16 # U_FULL + P + DIVU +# (k=0,n=16) 3.00e18, 9.45e9, 3.08e-14, 1.65e-28, 1.76e-17 # U + P_FULL + DIVU +# (k=0,n=16) 3.00e18, 9.45e9, 2.52e-11, 1.65e-28, 3.17e-16 # U_FULL + P_FULL + DIVU +############################################################################################### + +# CONCLUSION (k=0): lowest κ for stab u, p and divu. For u it does not matter whether it is full or not full. P__full would increase the order of κ by 1. +# (*)NOTE THAT U(_FUL)L + P + DIVU_FULL does not outperform U(_FULL) + P + DIVU, with κ=7.64e6 and κ=7.59e6, respectively. + +res_nostab +res_stab_u +res_stab_ufull +res_stab_updivu +res_stab_ufullpdivu +res_stab_ufullpdivufull +res_stab_upfulldivu +res_stab_ufullpfulldivu + +# NO STAB +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +A = assemble_matrix(assem, wrc) +res_nostab = compute_quantities(A,b,dΩ) +# (k=0,n=16) 2.31e9, 6040.0, 1.20e-27, 7.71e-5, 1.77e-30 # NO STAB + +# ONLY U +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +A = assemble_matrix(assem, wrc) +res_stab_u = compute_quantities(A,b,dΩ) +# (k=0,n=16) 3.58e8, 6040.0, 2.0 e-28, 7.71e-5, 1.93e-30 # STAB U + +# ONLY U FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufull = compute_quantities(A,b,dΩ) +# (k=0,n=16) 3.58e8, 6050.0, 1.67e-27, 7.71e-5, 4.26e-30 # STAB U_FULL + +# U + P + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_updivu = compute_quantities(A,b,dΩ) +# (k=0,n=16) 7.59e6, 55500.0, 1.64e-26, 1.46e-4, 4.20e-29 # U + P + DIVU + +# U_FULL + P + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpdivu = compute_quantities(A,b,dΩ) +# (k=0,n=16) 7.59e6, 55500.0, 6.17e-26, 1.45e-4, 9.62e-29 # U_FULL + P + DIVU + +# U_FULL + P + DIVU_FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpdivufull = compute_quantities(A,b,dΩ) +# (k=0,n=16) 7.64e6, 54500.0, 8.79e-26, 1.46e-4, 1.98e-28 # U_FULL + P + DIVU_FULL + +# U + P_FULL + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_upfulldivu = compute_quantities(A,b,dΩ) +# (k=0,n=16) 1.28e7, 55500.0, 1.64e-26, 1.16e-4, 4.20e-29 # U + P_FULL + DIVU + +# U_FULL + P_FULL + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpfulldivu = compute_quantities(A,b,dΩ) +# (k=0,n=16) 1.28e7, 55500.0, 6.17e-26, 1.16e-4, 9.62e-29 # U_FULL + P_FULL + DIVU + +# U_FULL + P_FULL + DIVU_FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ) +# (k=0,n=16) 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL + +# U + P + DIVU_FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_updivufull = compute_quantities(A,b,dΩ) +# (k=0,n=16) 7.64e6, 54500.0, 2.75e-26, 1.46e-4, 1.14e-28 # U + P + DIVU_FULL + + + +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv-div_dv_l2_proj_agg_cells)*(div_du-div_du_l2_proj_agg_cells))*dΩ_cut_cells +""" +function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections div_dv_l2_proj_agg_cells & div_du_l2_proj_agg_cells + + div_du=∇⋅(_get_single_field_fe_basis(du)) + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) + div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(du) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(dv) + div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) + end + + if (_is_multifield_fe_basis_component(dv)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + div_dv_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + div_dv_l2_proj_bb_array_agg_cells) + end + + div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + div_dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_dv_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + + # # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) div_dv*div_du term + div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) + push!(w, div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + ## (2) div_dv*proj_div_du term + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, U_cut_cells_to_aggregate_dof_ids) + + ## (3) proj_div_dv*proj_div_du + proj_div_dv_proj_div_du_mat_contribs=get_array(∫(γ*div_dv_l2_proj_agg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, proj_div_dv_proj_div_du_mat_contribs) + push!(r, U_cut_cells_to_aggregate_dof_ids) + push!(c, U_cut_cells_to_aggregate_dof_ids) + + ## (4) proj_div_dv*div_du + div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) + proj_div_dv_div_du_mat_contribs=get_array(∫(-γ*div_dv_l2_proj_agg_cells⋅div_du_Ωagg_cells)*dΩbg_cut_cells) + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_cut_cells_to_aggregate_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + w, r, c +end + +wdiv_full, rdiv_full, cdiv_full= div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl index a4e0e65f..0b7eef99 100644 --- a/bulk_ghost_penalty_stab_tools.jl +++ b/bulk_ghost_penalty_stab_tools.jl @@ -105,8 +105,7 @@ end dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells (long version) - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells (simplified, equivalent version) + # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells """ function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, @@ -202,6 +201,138 @@ function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_c w, r, c end +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells +""" +function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωbg_cut_cell_dof_ids, + agg_cells_local_dof_ids, + cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections dv_l2_proj_agg_cells & du_l2_proj_agg_cells + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωbg_agg_cells⋅du_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + if (_is_multifield_fe_basis_component(dv)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + dv_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + dv_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dv_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),cut_cells_to_aggregate_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) dv*du term + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩbg_cut_cells) + + push!(w, dv_du_mat_contribs) + push!(r, Ωbg_cut_cell_dof_ids) + push!(c, Ωbg_cut_cell_dof_ids) + + ## (2) dv*proj_du term + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωbg_agg_cells,ReferenceDomain()) + + dv_proj_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, dv_proj_du_mat_contribs) + push!(r, Ωbg_cut_cell_dof_ids) + push!(c, cut_cells_to_aggregate_dof_ids) + + ## (3) proj_dv*proj_du + proj_dv_proj_du_mat_contribs=get_array(∫(γ*dv_l2_proj_agg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, proj_dv_proj_du_mat_contribs) + push!(r, cut_cells_to_aggregate_dof_ids) + push!(c, cut_cells_to_aggregate_dof_ids) + + ## (4) proj_dv*du + duΩagg_cells=Gridap.CellData.change_domain(du,Ωbg_agg_cells,ReferenceDomain()) + proj_dv_du_mat_contribs=get_array(∫(-γ*dv_l2_proj_agg_cells⋅duΩagg_cells)*dΩbg_cut_cells) + + push!(w, proj_dv_du_mat_contribs) + push!(r, cut_cells_to_aggregate_dof_ids) + push!(c, Ωbg_cut_cell_dof_ids) + + w, r, c +end + function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, @@ -425,4 +556,121 @@ agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg # Finally assemble LHS contributions ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) lazy_map(ass_lhs_map,aggregate_to_local_cells) -end \ No newline at end of file +end + +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv-div_dv_l2_proj_agg_cells)*(div_du-div_du_l2_proj_agg_cells))*dΩ_cut_cells +""" +function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections div_dv_l2_proj_agg_cells & div_du_l2_proj_agg_cells + + div_du=∇⋅(_get_single_field_fe_basis(du)) + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) + div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(du) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(dv) + div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) + end + + if (_is_multifield_fe_basis_component(dv)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + div_dv_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + div_dv_l2_proj_bb_array_agg_cells) + end + + div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + div_dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_dv_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + + # # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) div_dv*div_du term + div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) + push!(w, div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + ## (2) div_dv*proj_div_du term + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, U_cut_cells_to_aggregate_dof_ids) + + ## (3) proj_div_dv*proj_div_du + proj_div_dv_proj_div_du_mat_contribs=get_array(∫(γ*div_dv_l2_proj_agg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, proj_div_dv_proj_div_du_mat_contribs) + push!(r, U_cut_cells_to_aggregate_dof_ids) + push!(c, U_cut_cells_to_aggregate_dof_ids) + + ## (4) proj_div_dv*div_du + div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) + proj_div_dv_div_du_mat_contribs=get_array(∫(-γ*div_dv_l2_proj_agg_cells⋅div_du_Ωagg_cells)*dΩbg_cut_cells) + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_cut_cells_to_aggregate_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + w, r, c +end \ No newline at end of file From 7fa5b5819d3926f2a3d3eb774a8924b2d2b82e1f Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 3 Dec 2024 12:36:56 +1100 Subject: [PATCH 049/120] added manufactured sol test - to check stab terms --- TEST0.jl | 469 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 469 insertions(+) create mode 100644 TEST0.jl diff --git a/TEST0.jl b/TEST0.jl new file mode 100644 index 00000000..9a2151e4 --- /dev/null +++ b/TEST0.jl @@ -0,0 +1,469 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 + +# Select geometry +R = 0.2 +geom = disk(R, x0=Point(0.5,0.5)) + +# Setup background model +n=16 +partition = (n,n) +box = get_metadata(geom) +bgmodel = CartesianDiscreteModel((0,1,0,1),partition) +dp = box.pmax - box.pmin +h = dp[1]/n + +# Cut the background model with the mesh +cutgeo = cut(bgmodel,geom) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# Triangulations +Ωbg = Triangulation(bgmodel) +Ωact = Triangulation(cutgeo,ACTIVE) + +# Physical domain +Ω = Triangulation(cutgeo,PHYSICAL) +degree=2*2*(order+1) +dΩ = Measure(Ω,degree) + +# Set up global spaces +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +U = TrialFESpace(V) +P = TrialFESpace(Q) +Y = MultiFieldFESpace([V, Q]) +X = MultiFieldFESpace([U, P]) +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +# Aggregate cells and triangulation +agg_cells =setup_agg_cells(aggregate_to_cells) +Ωbg_agg_cells=view(Ωbg,agg_cells) + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) +agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) +ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate) + +# Spaces on bounding boxes +reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) +reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + +# Numerical integration (Measures) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) + +# LHS of L2 projection on bounding boxes. +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + ubb, + vbb) + +# Selecting relevant global dofs ids of aggregate cells (from background mesh) +Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) +U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) +P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) + +# Computing local (per aggregate) dof ids +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) + +# Compute global dofs ids per aggregate and reindex these +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) +P_Ωbg_agg_cell_dof_ids + +# parameters +γ = 10.0 # Interior bulk-penalty stabilization parameter +h_U = 1.0 + +########################################### +### STABILIZATION ON Ωagg\Troot ### +########################################### + +## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) + +## (2) FIND THE INTERIOR CELLS +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface + +## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS +root_cells = setup_root_cells(int_cells, int_nonagg_cells) +cut_cells = setup_cut_cells(agg_cells, root_cells) + +## (4) CUT CELLS AND MEASURE +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) + +# (5) DOF IDS related to cut cells +Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) +U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) +P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) + +# (6) Defining cut_cells_to_aggregate_dof_ids +aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) +cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) + +# (7) Compute stabilization terms for u and p +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +#DIV stabilization part +wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +## FULL stabilization terms: +wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +# MIXED STAB TERMS +wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + dv) + +wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + du) + +function compute_quantities(A,b,dΩ) + cond_A = cond(Array(A)) + norm_A = norm(A) + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + norm_euh = sum(∫(euh⋅euh)*dΩ) + norm_eph = sum(∫(eph*eph)*dΩ) + norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) + return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) +end + +function plot_quantities(A,b,Ω,dΩ;filename="results") + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) +end + +## TEST WITH MANUFACTURED SOLUTIONS +a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ +assem=SparseMatrixAssembler(X,Y) +l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ +b = assemble_vector(l, Y) + +# NO STAB +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +A = assemble_matrix(assem, wrc) +res_nostab = compute_quantities(A,b,dΩ) + +# ONLY U +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +A = assemble_matrix(assem, wrc) +res_stab_u = compute_quantities(A,b,dΩ) + +# ONLY U FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufull = compute_quantities(A,b,dΩ) + +# ONLY P +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +A = assemble_matrix(assem, wrc) +res_stab_p = compute_quantities(A,b,dΩ) + +# ONLY PFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +A = assemble_matrix(assem, wrc) +res_stab_pfull = compute_quantities(A,b,dΩ) + +# ONLY DIV +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_div = compute_quantities(A,b,dΩ) + +# ONLY DIVU FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_divfull = compute_quantities(A,b,dΩ) + +# ONLY PMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +A = assemble_matrix(assem, wrc) +res_stab_pmix = compute_quantities(A,b,dΩ) + +# ONLY DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_dmix = compute_quantities(A,b,dΩ) + +# U + P + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_updivu = compute_quantities(A,b,dΩ) + +# UFULL + PFULL + DIVUFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ) + +# U + DIVU + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_udivupmixdmix = compute_quantities(A,b,dΩ) + +# UFULL + DIVUFULL + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_ufulldivufullpmixdmix = compute_quantities(A,b,dΩ) + +## PRINT DATA: +# print(res_nostab, res_stab_u, res_stab_ufull, res_stab_p, res_stab_pfull, res_stab_div, res_stab_divfull, res_stab_pmix, res_stab_dmix, res_stab_updivu, res_stab_ufullpfulldivufull, res_stab_udivupmixdmix, res_stab_ufulldivufullpmixdmix) +res_nostab +res_stab_u +res_stab_ufull +res_stab_p +res_stab_pfull +res_stab_div +res_stab_divfull +res_stab_pmix +res_stab_dmix +res_stab_updivu +res_stab_ufullpfulldivufull +res_stab_udivupmixdmix +res_stab_ufulldivufullpmixdmix + +# OLD: + +############## (k=0,n=16) ##################################################################### +# 2.31e9, 6040.0, 1.20e-27, 7.71e-5, 1.77e-30 # -- NO STAB -- +# 3.58e8, 6040.0, 2.0 e-28, 7.71e-5, 1.93e-30 # U +# 3.58e8, 6050.0, 9.85e-28, 7.71e-5, 4.32e-30 # U_FULL +# 7.59e6, 55500.0, 1.14e-26, 1.46e-4, 1.38e-29 # U + P + DIVU +# 7.59e6, 55500.0, 6.17e-26, 1.45e-4, 9.62e-29 # U_FULL + P + DIVU +# 7.64e6, 54500.0, 8.79e-26, 1.46e-4, 1.98e-28 # U_FULL + P + DIVU_FULL (*) +# 1.28e7, 55500.0, 1.64e-26, 1.16e-4, 4.20e-29 # U + P_FULL + DIVU +# 1.28e7, 55500.0, 6.17e-26, 1.16e-4, 9.62e-29 # U_FULL + P_FULL + DIVU +# 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL +# 7.64e6, 54500.0, 2.75e-26, 1.46e-4, 1.14e-28 # U + P + DIVU_FULL (*) +############################################################################################### + +############## (k=2,n=16) ##################################################################### +# 2.82e29, 9.21e8, 4.0e-12, 7.79e-28, 2.34e-13 # -- NO STAB -- +# 2.82e29, 9.21e8, 2.05e-18, 7.79e-28, 1.66e-19 # U +# 2.82e29, 9.21e8, 1.23e-16, 7.79e-28, 1.39e-18 # U_FULL +# 4.72e16, 9.45e9, 3.08e-14, 4.07e-29, 1.76e-17 # U + P + DIVU +# 4.72e16, 9.45e9, 2.52e-11, 4.07e-29, 3.17e-16 # U_FULL + P + DIVU +# 3.00e18, 9.45e9, 3.08e-14, 1.65e-28, 1.76e-17 # U + P_FULL + DIVU +# 3.00e18, 9.45e9, 2.52e-11, 1.65e-28, 3.17e-16 # U_FULL + P_FULL + DIVU +############################################################################################### \ No newline at end of file From 9a0c7e6306de797e34efc8552df344873136a34b Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 3 Dec 2024 12:41:55 +1100 Subject: [PATCH 050/120] added mixed stab terms --- bulk_ghost_penalty_stab_tools.jl | 281 +++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl index 0b7eef99..09c92baf 100644 --- a/bulk_ghost_penalty_stab_tools.jl +++ b/bulk_ghost_penalty_stab_tools.jl @@ -672,5 +672,286 @@ function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cel push!(r, U_cut_cells_to_aggregate_dof_ids) push!(c, U_Ωbg_cut_cell_dof_ids) + w, r, c +end + +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) + ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) + +""" +function pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + dqbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + dv) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells + # Change domain of qbb (test) from Ωbb to Ωagg_cells + dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + dp_single_field=_get_single_field_fe_basis(dp) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dq_l2_proj_bb_dofs, + Gridap.CellData.get_data(dqbb)) + + # # Change domain of dq_l2_proj_bb_array from bb to agg_cells + dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + dp_l2_proj_bb_array_agg_cells=lazy_map(transpose, dq_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(dp)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + dp_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + dp_l2_proj_bb_array_agg_cells) + end + + # if (_is_multifield_fe_basis_component(dq)) + # @assert _is_multifield_fe_basis_component(dq) + # @assert _nfields(dp)==_nfields(dq) + # nfields=_nfields(dq) + # fieldid=_fieldid(dq) + # dq_l2_proj_bb_array_agg_cells=lazy_map( + # Gridap.Fields.BlockMap(nfields,fieldid), + # dq_l2_proj_bb_array_agg_cells) + # end + + dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + # dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) + end + + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) div_dv*dp term + # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) + div_dv_dp_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅dp)*dΩbg_cut_cells) + + push!(w, div_dv_dp_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, P_Ωbg_cut_cell_dof_ids) + + ## (2) div_dv*proj_dp term + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + div_dv_proj_dp_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, div_dv_proj_dp_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, P_cut_cells_to_aggregate_dof_ids) + + # ## (3) proj_dq*proj_dp + # proj_dq_proj_dp_mat_contribs=get_array(∫(γ*dq_l2_proj_agg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) + + # push!(w, proj_dq_proj_dp_mat_contribs) + # push!(r, cut_cells_to_aggregate_dof_ids) + # push!(c, cut_cells_to_aggregate_dof_ids) + + # ## (4) proj_dq*dp + # dpΩagg_cells=Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) + # proj_dq_dp_mat_contribs=get_array(∫(-γ*dq_l2_proj_agg_cells⋅dpΩagg_cells)*dΩbg_cut_cells) + + # push!(w, proj_dq_dp_mat_contribs) + # push!(r, cut_cells_to_aggregate_dof_ids) + # push!(c, Ωbg_cut_cell_dof_ids) + + w, r, c +end + +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) + ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) + +""" +function dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + dqbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + du) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells + # Change domain of qbb (test) from Ωbb to Ωagg_cells + dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + dp_single_field=_get_single_field_fe_basis(dp) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dq_l2_proj_bb_dofs, + Gridap.CellData.get_data(dqbb)) + + # # Change domain of dq_l2_proj_bb_array from bb to agg_cells + dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + # dp_l2_proj_bb_array_agg_cells=lazy_map(transpose, dq_l2_proj_bb_array_agg_cells) + + # if (_is_multifield_fe_basis_component(dp)) + # @assert _is_multifield_fe_basis_component(dq) + # @assert _nfields(dp)==_nfields(dq) + # nfields=_nfields(dp) + # fieldid=_fieldid(dp) + # dp_l2_proj_bb_array_agg_cells=lazy_map( + # Gridap.Fields.BlockMap((1,nfields),fieldid), + # dp_l2_proj_bb_array_agg_cells) + # end + + if (_is_multifield_fe_basis_component(dq)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + dq_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + dq_l2_proj_bb_array_agg_cells) + end + + # dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) + end + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) div_du*dq term + # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) + div_dv_dp_mat_contribs=get_array(∫(γ*(∇⋅du)⋅dq)*dΩbg_cut_cells) + + push!(w, div_dv_dp_mat_contribs) + push!(r, P_Ωbg_cut_cell_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + ## (2) div_du*proj_dq term + div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) + div_dv_proj_dp_mat_contribs=get_array(∫(γ*(-1.0)*div_du_Ωagg_cells⋅(dq_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, div_dv_proj_dp_mat_contribs) + push!(r, P_cut_cells_to_aggregate_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + + # ## (3) proj_dq*proj_dp + # proj_dq_proj_dp_mat_contribs=get_array(∫(γ*dq_l2_proj_agg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) + + # push!(w, proj_dq_proj_dp_mat_contribs) + # push!(r, cut_cells_to_aggregate_dof_ids) + # push!(c, cut_cells_to_aggregate_dof_ids) + + # ## (4) proj_dq*dp + # dpΩagg_cells=Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) + # proj_dq_dp_mat_contribs=get_array(∫(-γ*dq_l2_proj_agg_cells⋅dpΩagg_cells)*dΩbg_cut_cells) + + # push!(w, proj_dq_dp_mat_contribs) + # push!(r, cut_cells_to_aggregate_dof_ids) + # push!(c, Ωbg_cut_cell_dof_ids) + w, r, c end \ No newline at end of file From 4bea53c693e0786d2c1593c23cd55c74f6ff63ed Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Wed, 4 Dec 2024 21:04:54 +1100 Subject: [PATCH 051/120] added rhs contribution for one of the mixed stabilization terms. TOSORT: allow function g to be passed along. --- bulk_ghost_penalty_stab_tools.jl | 117 +++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl index 09c92baf..28c076c4 100644 --- a/bulk_ghost_penalty_stab_tools.jl +++ b/bulk_ghost_penalty_stab_tools.jl @@ -954,4 +954,121 @@ function dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_t # push!(c, Ωbg_cut_cell_dof_ids) w, r, c +end + +## Create collect function on cut cells only for rhs +## TODO: rhs_g_func does not seem to work when function is passed on +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) + ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) + +""" +function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + dqbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + rhs_g_func) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells + # Change domain of qbb (test) from Ωbb to Ωagg_cells + dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + dp_single_field=_get_single_field_fe_basis(dp) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dq_l2_proj_bb_dofs, + Gridap.CellData.get_data(dqbb)) + + # # Change domain of dq_l2_proj_bb_array from bb to agg_cells + dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + # dp_l2_proj_bb_array_agg_cells=lazy_map(transpose, dq_l2_proj_bb_array_agg_cells) + + # if (_is_multifield_fe_basis_component(dp)) + # @assert _is_multifield_fe_basis_component(dq) + # @assert _nfields(dp)==_nfields(dq) + # nfields=_nfields(dp) + # fieldid=_fieldid(dp) + # dp_l2_proj_bb_array_agg_cells=lazy_map( + # Gridap.Fields.BlockMap((1,nfields),fieldid), + # dp_l2_proj_bb_array_agg_cells) + # end + + if (_is_multifield_fe_basis_component(dq)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + dq_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + dq_l2_proj_bb_array_agg_cells) + end + + # dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) + end + + # Manually set up the arrays that collect_cell_vector would return automatically + w = [] + r = [] + + ## (1) rhs_g*dq term + # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) + #TODO: γ*(rhs_g_func) does not work + rhs_g_dp_mat_contribs=get_array(∫((rhs_g_func)⋅dq*γ)*dΩbg_cut_cells) + + push!(w, rhs_g_dp_mat_contribs) + push!(r, P_Ωbg_cut_cell_dof_ids) + + # (2) div_du*proj_dq term + rhs_g_proj_dp_mat_contribs=get_array(∫((rhs_g_func)⋅(dq_l2_proj_agg_cells)*γ*(-1.0))*dΩbg_cut_cells) + # # rhs_g_proj_dp_mat_contribs=get_array(∫((dq_l2_proj_agg_cells)*γ*(-1.0))*dΩbg_cut_cells) + + push!(w, rhs_g_proj_dp_mat_contribs) + push!(r, P_cut_cells_to_aggregate_dof_ids) + + w, r end \ No newline at end of file From 04e20e1de53a13b620d425f94e8a9d9e0fc70cdb Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Wed, 4 Dec 2024 21:05:15 +1100 Subject: [PATCH 052/120] test problem on cutsquare --- TEST0-cutsquare.jl | 536 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 536 insertions(+) create mode 100644 TEST0-cutsquare.jl diff --git a/TEST0-cutsquare.jl b/TEST0-cutsquare.jl new file mode 100644 index 00000000..7cfd4126 --- /dev/null +++ b/TEST0-cutsquare.jl @@ -0,0 +1,536 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 + +# Select geometry +nint = 2 + +# cut length +# ε = 0.2 # not so small cut +ε = 0.2e-2 # smaller cut +# ε = 0.2e-6 # smallest cut + +pmin = Point(0.0,0.0) +pmax = Point(1.0,1.0) +function setup_geometry(nint, ε, pmin, pmax) + nbg = nint + 2 + 2 # number of elements in the background mesh (2 from cut, 2 dummy) + dp = pmax - pmin + h = dp[1]/nint + bgpmin = pmin - Point(2*h,2*h) + bgpmax = pmax + Point(2*h,2*h) + bgdp = bgpmax - bgpmin + partition = (nbg,nbg) + bgmodel = CartesianDiscreteModel(bgpmin,bgpmax,partition) + hbg = bgdp[1]/nbg + @assert abs(hbg - h) < 10e-10 + @assert abs(ε/h) < 0.5 + + # The following is based on square (part of GridapEmbedded): + e1 = VectorValue(1,0) + e2 = VectorValue(0,1) + x0 = pmin + Point(0.5*dp[1],0.5*dp[2]) + L1 = dp[1] + 2*ε + L2 = dp[2] + 2*ε + plane1 = plane(x0=x0-0.5*L2*e2,v=-e2,name="bottom") + plane2 = plane(x0=x0+0.5*L1*e1,v= e1,name="right") + plane3 = plane(x0=x0+0.5*L2*e2,v= e2,name="top") + plane4 = plane(x0=x0-0.5*L1*e1,v=-e1,name="left") + + geo12 = intersect(plane1,plane2) + geo34 = intersect(plane3,plane4) + + square = intersect(geo12,geo34) + cutgeo = cut(bgmodel, square) + + # TODO: not necessary to export square as no cuts.. + bgmodel, cutgeo, h +end +bgmodel, cutgeo, h = setup_geometry(nint, ε, pmin, pmax) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# Triangulations +Ωbg = Triangulation(bgmodel) +Ωact = Triangulation(cutgeo,ACTIVE) + +# Physical domain +Ω = Triangulation(cutgeo,PHYSICAL) +degree=2*2*(order+1) +dΩ = Measure(Ω,degree) + +# Set up global spaces +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +U = TrialFESpace(V) +P = TrialFESpace(Q) +Y = MultiFieldFESpace([V, Q]) +X = MultiFieldFESpace([U, P]) +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +# Aggregate cells and triangulation +agg_cells =setup_agg_cells(aggregate_to_cells) +Ωbg_agg_cells=view(Ωbg,agg_cells) + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) +agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) +ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate) + +# Spaces on bounding boxes +reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) +reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + +# Numerical integration (Measures) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) + +# LHS of L2 projection on bounding boxes. +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + ubb, + vbb) + +# Selecting relevant global dofs ids of aggregate cells (from background mesh) +Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) +U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) +P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) + +# Computing local (per aggregate) dof ids +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) + +# Compute global dofs ids per aggregate and reindex these +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +# parameters +γ = 10.0 # Interior bulk-penalty stabilization parameter +h_U = 1.0 + +########################################### +### STABILIZATION ON Ωagg\Troot ### +########################################### + +## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) + +## (2) FIND THE INTERIOR CELLS +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface + +## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS +root_cells = setup_root_cells(int_cells, int_nonagg_cells) +cut_cells = setup_cut_cells(agg_cells, root_cells) + +## (4) CUT CELLS AND MEASURE +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) + +# (5) DOF IDS related to cut cells +Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) +U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) +P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) + +# (6) Defining cut_cells_to_aggregate_dof_ids +aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) +cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) + +# (7) Compute stabilization terms for u and p +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) +#DIV stabilization part +wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +## FULL stabilization terms: +wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +# MIXED STAB TERMS +wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + dv) + +wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + du) + +########################################### +### VISUALIZATION ### +########################################### +writevtk(Ωbg,"trian-bg") +writevtk(Ωbg_cut_cells,"trian-bg-cut-cells") +colors = color_aggregates(aggregates,bgmodel) +writevtk(Ωbg,"trian-bg-with-coloured-aggregates", celldata=["aggregate"=>aggregates,"color"=>colors]) +writevtk(Ωbg_agg_cells,"trian-bg-agg-cells") +Ωbg_int_cells=view(Ωbg,int_cells) +Ωbg_root_cells=view(Ωbg,root_cells) +writevtk(Ωbg_int_cells,"trian-bg-int-cells") +writevtk(Ωbg_root_cells,"trian-bg-root-cells") +writevtk(Ω,"trian-phys") +writevtk(Ωact,"trian-act") + +function compute_quantities(A,b,dΩ) + cond_A = cond(Array(A)) + norm_A = norm(A) + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + norm_euh = sum(∫(euh⋅euh)*dΩ) + norm_eph = sum(∫(eph*eph)*dΩ) + norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) + return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) +end + +function plot_quantities(A,b,Ω;filename="results") + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) +end + +## RHS STAB +# rhs_g = divuex # TODO: pass function on rather than constant value!!!!! +vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + divuex(1.0)) + +## TEST WITH MANUFACTURED SOLUTIONS +a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ +assem=SparseMatrixAssembler(X,Y) +l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ +b = assemble_vector(l, Y) + +#RHS_DMIX +vec_wr=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) +push!(vec_wr[1],vecw_dmix...) +push!(vec_wr[2],vecr_dmix...) +vec_b = assemble_vector(assem, vec_wr) +# res_nostab = compute_quantities(A,vec_b,dΩ) + +# NO STAB +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +A = assemble_matrix(assem, wrc) +res_nostab = compute_quantities(A,b,dΩ) + +# ONLY U +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +A = assemble_matrix(assem, wrc) +res_stab_u = compute_quantities(A,b,dΩ) + +# ONLY U FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufull = compute_quantities(A,b,dΩ) + +# ONLY P +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +A = assemble_matrix(assem, wrc) +res_stab_p = compute_quantities(A,b,dΩ) + +# ONLY PFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +A = assemble_matrix(assem, wrc) +res_stab_pfull = compute_quantities(A,b,dΩ) + +# ONLY DIV +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_div = compute_quantities(A,b,dΩ) + +# ONLY DIVU FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_divfull = compute_quantities(A,b,dΩ) + +# ONLY PMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +A = assemble_matrix(assem, wrc) +# res_stab_pmix = compute_quantities(A,b,dΩ) +res_stab_pmix = compute_quantities(A,b,dΩ) + +# ONLY DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_dmix = compute_quantities(A,vec_b,dΩ) + +# U + P + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_updivu = compute_quantities(A,b,dΩ) + +# UFULL + PFULL + DIVUFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ) + +# U + DIVU + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_udivupmixdmix = compute_quantities(A,vec_b,dΩ) + +# UFULL + DIVUFULL + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_ufulldivufullpmixdmix = compute_quantities(A,vec_b,dΩ) + +## PRINT DATA: +# print(res_nostab, res_stab_u, res_stab_ufull, res_stab_p, res_stab_pfull, res_stab_div, res_stab_divfull, res_stab_pmix, res_stab_dmix, res_stab_updivu, res_stab_ufullpfulldivufull, res_stab_udivupmixdmix, res_stab_ufulldivufullpmixdmix) +res_nostab +res_stab_u +res_stab_ufull +res_stab_p +res_stab_pfull +res_stab_div +res_stab_divfull +res_stab_pmix +res_stab_dmix +res_stab_updivu +res_stab_ufullpfulldivufull +res_stab_udivupmixdmix +res_stab_ufulldivufullpmixdmix + +# OLD: + +############## (k=0,n=16) ##################################################################### +# 2.31e9, 6040.0, 1.20e-27, 7.71e-5, 1.77e-30 # -- NO STAB -- +# 3.58e8, 6040.0, 2.0 e-28, 7.71e-5, 1.93e-30 # U +# 3.58e8, 6050.0, 9.85e-28, 7.71e-5, 4.32e-30 # U_FULL +# 7.59e6, 55500.0, 1.14e-26, 1.46e-4, 1.38e-29 # U + P + DIVU +# 7.59e6, 55500.0, 6.17e-26, 1.45e-4, 9.62e-29 # U_FULL + P + DIVU +# 7.64e6, 54500.0, 8.79e-26, 1.46e-4, 1.98e-28 # U_FULL + P + DIVU_FULL (*) +# 1.28e7, 55500.0, 1.64e-26, 1.16e-4, 4.20e-29 # U + P_FULL + DIVU +# 1.28e7, 55500.0, 6.17e-26, 1.16e-4, 9.62e-29 # U_FULL + P_FULL + DIVU +# 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL +# 7.64e6, 54500.0, 2.75e-26, 1.46e-4, 1.14e-28 # U + P + DIVU_FULL (*) +############################################################################################### + +############## (k=2,n=16) ##################################################################### +# 2.82e29, 9.21e8, 4.0e-12, 7.79e-28, 2.34e-13 # -- NO STAB -- +# 2.82e29, 9.21e8, 2.05e-18, 7.79e-28, 1.66e-19 # U +# 2.82e29, 9.21e8, 1.23e-16, 7.79e-28, 1.39e-18 # U_FULL +# 4.72e16, 9.45e9, 3.08e-14, 4.07e-29, 1.76e-17 # U + P + DIVU +# 4.72e16, 9.45e9, 2.52e-11, 4.07e-29, 3.17e-16 # U_FULL + P + DIVU +# 3.00e18, 9.45e9, 3.08e-14, 1.65e-28, 1.76e-17 # U + P_FULL + DIVU +# 3.00e18, 9.45e9, 2.52e-11, 1.65e-28, 3.17e-16 # U_FULL + P_FULL + DIVU +############################################################################################### \ No newline at end of file From 628510769a2ba19ce8e823eb20a50daad867e6b9 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Mon, 20 Jan 2025 11:13:58 +1100 Subject: [PATCH 053/120] added revised_setup_aggregate_to_cut_cells that fixes the issues related to going from nint2 to nint3 (TEST0 ) --- TEST0-cutsquare-nint3.jl | 521 +++++++++++++++++++++++++++++ aggregates_bounding_boxes_tools.jl | 50 +++ 2 files changed, 571 insertions(+) create mode 100644 TEST0-cutsquare-nint3.jl diff --git a/TEST0-cutsquare-nint3.jl b/TEST0-cutsquare-nint3.jl new file mode 100644 index 00000000..e14321ee --- /dev/null +++ b/TEST0-cutsquare-nint3.jl @@ -0,0 +1,521 @@ +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 2 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 + +# Select geometry +nint = 3 + +# cut length +# ε = 0.2/2.0 # not so small cut +ε = 0.2e-2/2.0 # smaller cut +# ε = 0.2e-6/2.0 # smallest cut + +pmin = Point(0.0,0.0) +pmax = Point(1.0,1.0) +function setup_geometry(nint, ε, pmin, pmax) + nbg = nint + 2 + 2 # number of elements in the background mesh (2 from cut, 2 dummy) + dp = pmax - pmin + h = dp[1]/nint + bgpmin = pmin - Point(2*h,2*h) + bgpmax = pmax + Point(2*h,2*h) + bgdp = bgpmax - bgpmin + partition = (nbg,nbg) + bgmodel = CartesianDiscreteModel(bgpmin,bgpmax,partition) + hbg = bgdp[1]/nbg + @assert abs(hbg - h) < 10e-10 + @assert abs(ε/h) < 0.5 + + # The following is based on square (part of GridapEmbedded): + e1 = VectorValue(1,0) + e2 = VectorValue(0,1) + x0 = pmin + Point(0.5*dp[1],0.5*dp[2]) + L1 = dp[1] + 2*ε + L2 = dp[2] + 2*ε + plane1 = plane(x0=x0-0.5*L2*e2,v=-e2,name="bottom") + plane2 = plane(x0=x0+0.5*L1*e1,v= e1,name="right") + plane3 = plane(x0=x0+0.5*L2*e2,v= e2,name="top") + plane4 = plane(x0=x0-0.5*L1*e1,v=-e1,name="left") + + geo12 = intersect(plane1,plane2) + geo34 = intersect(plane3,plane4) + + square = intersect(geo12,geo34) + cutgeo = cut(bgmodel, square) + + # TODO: not necessary to export square as no cuts.. + bgmodel, cutgeo, h +end +bgmodel, cutgeo, h = setup_geometry(nint, ε, pmin, pmax) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# Triangulations +Ωbg = Triangulation(bgmodel) +Ωact = Triangulation(cutgeo,ACTIVE) + +# Physical domain +Ω = Triangulation(cutgeo,PHYSICAL) +degree=2*2*(order+1) +dΩ = Measure(Ω,degree) + +# Set up global spaces +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +U = TrialFESpace(V) +P = TrialFESpace(Q) +Y = MultiFieldFESpace([V, Q]) +X = MultiFieldFESpace([U, P]) +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +# Aggregate cells and triangulation +agg_cells =setup_agg_cells(aggregate_to_cells) +Ωbg_agg_cells=view(Ωbg,agg_cells) + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) +agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) +ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate) + +# Spaces on bounding boxes +reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) +reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + +# Numerical integration (Measures) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) + +# LHS of L2 projection on bounding boxes. +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + ubb, + vbb) + +# Selecting relevant global dofs ids of aggregate cells (from background mesh) +Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) +U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) +P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) + +# Computing local (per aggregate) dof ids +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) + +# Compute global dofs ids per aggregate and reindex these +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +# parameters +γ = 10.0 # Interior bulk-penalty stabilization parameter +h_U = 1.0 + +########################################### +### STABILIZATION ON Ωagg\Troot ### +########################################### + +## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) + +## (2) FIND THE INTERIOR CELLS +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface + +## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS +root_cells = setup_root_cells(int_cells, int_nonagg_cells) +cut_cells = setup_cut_cells(agg_cells, root_cells) + +## (4) CUT CELLS AND MEASURE +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) + +# (5) DOF IDS related to cut cells +Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) +U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) +P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) + +# (6) Defining cut_cells_to_aggregate_dof_ids +# aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) +aggregate_to_cut_cells = revised_setup_aggregate_to_cut_cells(aggregates, root_cells) +cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) + +# (7) Compute stabilization terms for u and p +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) +#DIV stabilization part +wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basisr + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +## FULL stabilization terms: +wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +# MIXED STAB TERMS +wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + dv) + +wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + du) + +########################################### +### VISUALIZATION ### +########################################### +# writevtk(Ωbg,"trian-bg") +# writevtk(Ωbg_cut_cells,"trian-bg-cut-cells") +colors = color_aggregates(aggregates,bgmodel) +writevtk(Ωbg,"trian-bg-with-coloured-aggregates", celldata=["aggregate"=>aggregates,"color"=>colors]) +# writevtk(Ωbg_agg_cells,"trian-bg-agg-cells") +# Ωbg_int_cells=view(Ωbg,int_cells) +# Ωbg_root_cells=view(Ωbg,root_cells) +# writevtk(Ωbg_int_cells,"trian-bg-int-cells") +# writevtk(Ωbg_root_cells,"trian-bg-root-cells") +writevtk(Ω,"trian-phys") +# writevtk(Ωact,"trian-act") + +function compute_quantities(A,b,dΩ) + cond_A = cond(Array(A)) + norm_A = norm(A) + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + norm_euh = sum(∫(euh⋅euh)*dΩ) + norm_eph = sum(∫(eph*eph)*dΩ) + norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) + return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) +end + +function plot_quantities(A,b,Ω;filename="results") + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) +end + +## RHS STAB +# rhs_g = divuex # TODO: pass function on rather than constant value!!!!! +vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + divuex(1.0)) + +## TEST WITH MANUFACTURED SOLUTIONS +a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ +assem=SparseMatrixAssembler(X,Y) +l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ +b = assemble_vector(l, Y) + +#RHS_DMIX +vec_wr=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) +push!(vec_wr[1],vecw_dmix...) +push!(vec_wr[2],vecr_dmix...) +vec_b = assemble_vector(assem, vec_wr) +# res_nostab = compute_quantities(A,vec_b,dΩ) + +# NO STAB +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +A = assemble_matrix(assem, wrc) +res_nostab = compute_quantities(A,b,dΩ) + +# ONLY U +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +A = assemble_matrix(assem, wrc) +res_stab_u = compute_quantities(A,b,dΩ) + +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp[1]) +push!(wrc[2], rp[1]) +push!(wrc[3], cp[1]) +A = assemble_matrix(assem, wrc) +res_stab_p1 = compute_quantities(A,b,dΩ) + +# ONLY U FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufull = compute_quantities(A,b,dΩ) + +# ONLY P +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +A = assemble_matrix(assem, wrc) +res_stab_p = compute_quantities(A,b,dΩ) + +# ONLY PFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +A = assemble_matrix(assem, wrc) +res_stab_pfull = compute_quantities(A,b,dΩ) + +# ONLY DIV +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_div = compute_quantities(A,b,dΩ) + +# ONLY DIVU FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_divfull = compute_quantities(A,b,dΩ) + +# ONLY PMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +A = assemble_matrix(assem, wrc) +# res_stab_pmix = compute_quantities(A,b,dΩ) +res_stab_pmix = compute_quantities(A,b,dΩ) + +# ONLY DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_dmix = compute_quantities(A,vec_b,dΩ) + +# U + P + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_updivu = compute_quantities(A,b,dΩ) + +# UFULL + PFULL + DIVUFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ) + +# U + DIVU + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_udivupmixdmix = compute_quantities(A,vec_b,dΩ) + +# UFULL + DIVUFULL + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_ufulldivufullpmixdmix = compute_quantities(A,vec_b,dΩ) + +## PRINT DATA: +# print(res_nostab, res_stab_u, res_stab_ufull, res_stab_p, res_stab_pfull, res_stab_div, res_stab_divfull, res_stab_pmix, res_stab_dmix, res_stab_updivu, res_stab_ufullpfulldivufull, res_stab_udivupmixdmix, res_stab_ufulldivufullpmixdmix) +print("results") +res_nostab +res_stab_u +res_stab_ufull +res_stab_p +res_stab_pfull +res_stab_div +res_stab_divfull +res_stab_pmix +res_stab_dmix +print("") +res_stab_updivu +res_stab_ufullpfulldivufull +res_stab_udivupmixdmix +res_stab_ufulldivufullpmixdmix \ No newline at end of file diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl index 68f11cf6..9bbccd89 100644 --- a/aggregates_bounding_boxes_tools.jl +++ b/aggregates_bounding_boxes_tools.jl @@ -78,6 +78,56 @@ function setup_aggregate_to_cut_cells(aggregates, root_cells) aggregate_to_cut_cells end +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cut cells in + the background model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function revised_setup_aggregate_to_cut_cells(aggregates, root_cells) + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cut_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + # println("i=$i, agg=$agg") + if agg>0 + if (size_aggregates[agg]>1) + if !haskey(touched,agg) + if i ∉ root_cells + push!(aggregate_to_cut_cells,[i]) + else + push!(aggregate_to_cut_cells,[]) + end + touched[agg]=current_aggregate + current_aggregate+=1 + else + if i ∉ root_cells + push!(aggregate_to_cut_cells[touched[agg]],i) + end + end + end + end + # println("touched = $touched") + # println("current agg = $current_aggregate, $aggregate_to_cut_cells") + end + aggregate_to_cut_cells +end + + """ Creates an array of arrays with as many entries as interior cells that are not part of any aggegrate. From 53fc97f317dbfcc37ea6d5825944260328ca01dd Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 21 Jan 2025 08:54:07 +1100 Subject: [PATCH 054/120] cleaned up some lines --- TEST0-cutsquare-nint3.jl | 8 -------- 1 file changed, 8 deletions(-) diff --git a/TEST0-cutsquare-nint3.jl b/TEST0-cutsquare-nint3.jl index e14321ee..c5f7e2b4 100644 --- a/TEST0-cutsquare-nint3.jl +++ b/TEST0-cutsquare-nint3.jl @@ -361,7 +361,6 @@ vec_wr=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) push!(vec_wr[1],vecw_dmix...) push!(vec_wr[2],vecr_dmix...) vec_b = assemble_vector(assem, vec_wr) -# res_nostab = compute_quantities(A,vec_b,dΩ) # NO STAB wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) @@ -376,13 +375,6 @@ push!(wrc[3], cu...) A = assemble_matrix(assem, wrc) res_stab_u = compute_quantities(A,b,dΩ) -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp[1]) -push!(wrc[2], rp[1]) -push!(wrc[3], cp[1]) -A = assemble_matrix(assem, wrc) -res_stab_p1 = compute_quantities(A,b,dΩ) - # ONLY U FULL wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) push!(wrc[1], wu_full...) From 0715cb2ff7eb32693d48baa3fb7bf80ac5096f14 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 21 Jan 2025 08:55:00 +1100 Subject: [PATCH 055/120] Test 1 (Darcy problem) possible error in constraining dof (via cell id) --- TEST1-cutsquare-nint3.jl | 544 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 544 insertions(+) create mode 100644 TEST1-cutsquare-nint3.jl diff --git a/TEST1-cutsquare-nint3.jl b/TEST1-cutsquare-nint3.jl new file mode 100644 index 00000000..a2e7dc67 --- /dev/null +++ b/TEST1-cutsquare-nint3.jl @@ -0,0 +1,544 @@ +# TEST1: Darcy test case solved using a zero mean pressure space. In the postprocessing procedure, the solution is corrected for this, so that the mean pressure from the exact solution is matched. +using Gridap +using GridapEmbedded +using FillArrays +using LinearAlgebra + +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") +include("BulkGhostPenaltyAssembleMaps.jl") + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 + +# Select geometry +nint = 3 + +# cut length +# ε = 0.2/2.0 # not so small cut +ε = 0.2e-2/2.0 # smaller cut +# ε = 0.2e-6/2.0 # smallest cut + +pmin = Point(0.0,0.0) +pmax = Point(1.0,1.0) +function setup_geometry(nint, ε, pmin, pmax) + nbg = nint + 2 + 2 # number of elements in the background mesh (2 from cut, 2 dummy) + dp = pmax - pmin + h = dp[1]/nint + bgpmin = pmin - Point(2*h,2*h) + bgpmax = pmax + Point(2*h,2*h) + bgdp = bgpmax - bgpmin + partition = (nbg,nbg) + bgmodel = CartesianDiscreteModel(bgpmin,bgpmax,partition) + hbg = bgdp[1]/nbg + @assert abs(hbg - h) < 10e-10 + @assert abs(ε/h) < 0.5 + + # The following is based on square (part of GridapEmbedded): + e1 = VectorValue(1,0) + e2 = VectorValue(0,1) + x0 = pmin + Point(0.5*dp[1],0.5*dp[2]) + L1 = dp[1] + 2*ε + L2 = dp[2] + 2*ε + plane1 = plane(x0=x0-0.5*L2*e2,v=-e2,name="bottom") + plane2 = plane(x0=x0+0.5*L1*e1,v= e1,name="right") + plane3 = plane(x0=x0+0.5*L2*e2,v= e2,name="top") + plane4 = plane(x0=x0-0.5*L1*e1,v=-e1,name="left") + + geo12 = intersect(plane1,plane2) + geo34 = intersect(plane3,plane4) + + square = intersect(geo12,geo34) + cutgeo = cut(bgmodel, square) + + # TODO: not necessary to export square as no cuts.. + bgmodel, cutgeo, h +end +bgmodel, cutgeo, h = setup_geometry(nint, ε, pmin, pmax) + +# Compute mapping among background model +# cut cells and interior cells +strategy = AggregateAllCutCells() +aggregates = aggregate(strategy,cutgeo) + +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# Triangulations +Ωbg = Triangulation(bgmodel) +Ωact = Triangulation(cutgeo,ACTIVE) + +# Physical domain +Ω = Triangulation(cutgeo,PHYSICAL) +degree=2*2*(order+1) +dΩ = Measure(Ω,degree) + +## NEWLY ADDED FOR ZM PRESSURE SPACE +# Define root and cut cells. +## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) +@assert length(int_nonagg_cells)>0 # otherwise we can not constrain a dof +# TO DO: check if this works for order =2! + +# Set up zero-mean pressure space, with fixed interior dof +Qnzm = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +int_nonagg_dof_to_fix = int_nonagg_cells[1] # pick the first interior cell that is not part of an aggregate to be contrained by the zero mean pressure condition. +spaceWithConstantFixed = Gridap.FESpaces.FESpaceWithConstantFixed(Qnzm,true,int_nonagg_dof_to_fix) +Qzm_vol_i = assemble_vector(v->∫(v)*dΩ,Qnzm) +Qzm_vol = sum(Qzm_vol_i) +Qzm = Gridap.FESpaces.ZeroMeanFESpace(spaceWithConstantFixed,Qzm_vol_i,Qzm_vol) +Pzm = TrialFESpace(Qzm) + +# Set up global spaces +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +U = TrialFESpace(V) +Xzm = MultiFieldFESpace([U, Pzm]) +Yzm = MultiFieldFESpace([V, Qzm]) +dx_zm = get_trial_fe_basis(Xzm) +dy_zm = get_fe_basis(Yzm) +du_zm,dp_zm = dx_zm +dv_zm,dq_zm = dy_zm + +# Aggregate cells and triangulation +agg_cells =setup_agg_cells(aggregate_to_cells) +Ωbg_agg_cells=view(Ωbg,agg_cells) + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) +agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) +ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate) + +# Spaces on bounding boxes +reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) +Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) +reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + +# Numerical integration (Measures) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) + +# LHS of L2 projection on bounding boxes. +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) +p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + pbb, + qbb) + +u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + ubb, + vbb) + +# Selecting relevant global dofs ids of aggregate cells (from background mesh) +Ωbg_agg_cell_dof_ids = get_cell_dof_ids(Xzm,Ωbg_agg_cells) +U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) +P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) + +# Computing local (per aggregate) dof ids +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) + +# Compute global dofs ids per aggregate and reindex these +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +# parameters +γ = 10.0 # Interior bulk-penalty stabilization parameter +h_U = 1.0 + +########################################### +### STABILIZATION ON Ωagg\Troot ### +########################################### + +# ## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE +# int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +# int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) + +## (2) FIND THE INTERIOR CELLS +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface + +## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS +root_cells = setup_root_cells(int_cells, int_nonagg_cells) +cut_cells = setup_cut_cells(agg_cells, root_cells) + +## (4) CUT CELLS AND MEASURE +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) + +# (5) DOF IDS related to cut cells +Ωbg_cut_cell_dof_ids = get_cell_dof_ids(Xzm,Ωbg_cut_cells) +U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) +P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) + +# (6) Defining cut_cells_to_aggregate_dof_ids +# aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) +aggregate_to_cut_cells = revised_setup_aggregate_to_cut_cells(aggregates, root_cells) +cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) + +# (7) Compute stabilization terms for u and p +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv_zm, # Test basis + du_zm, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq_zm, # Test basis + dp_zm, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) +#DIV stabilization part +wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv_zm, # Test basisr + du_zm, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +## FULL stabilization terms: +wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv_zm, # Test basis + du_zm, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq_zm, # Test basis + dp_zm, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv_zm, # Test basis + du_zm, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +# MIXED STAB TERMS +wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq_zm, # Test basis + dp_zm, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + dv_zm) + +wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq_zm, # Test basis + dp_zm, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + du_zm) + +########################################### +### VISUALIZATION ### +########################################### +# # writevtk(Ωbg,"trian-bg") +# # writevtk(Ωbg_cut_cells,"trian-bg-cut-cells") +# colors = color_aggregates(aggregates,bgmodel) +# writevtk(Ωbg,"trian-bg-with-coloured-aggregates", celldata=["aggregate"=>aggregates,"color"=>colors]) +# # writevtk(Ωbg_agg_cells,"trian-bg-agg-cells") +# # Ωbg_int_cells=view(Ωbg,int_cells) +# # Ωbg_root_cells=view(Ωbg,root_cells) +# # writevtk(Ωbg_int_cells,"trian-bg-int-cells") +# # writevtk(Ωbg_root_cells,"trian-bg-root-cells") +# writevtk(Ω,"trian-phys") +# # writevtk(Ωact,"trian-act") + +function compute_quantities(A,b,dΩ,pex,X) + cond_A = cond(Array(A)) + norm_A = norm(A) + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph_zm = xh + area = sum(∫(1.0)dΩ) + mean_p = sum(∫(pex)dΩ)/area # mean presure exact sol + ph = ph_zm + mean_p + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + norm_euh = sum(∫(euh⋅euh)*dΩ) + norm_eph = sum(∫(eph*eph)*dΩ) + norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) + print("zeromean pressure $(sum(∫(ph_zm)dΩ)/area) and corrected mean pressure $(sum(∫(ph)dΩ)/area)") + return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) +end + +# to update +# function plot_quantities(A,b,Ω;filename="results") +# sol_x = A\b +# xh = FEFunction(X, sol_x) +# uh,ph = xh +# euh = uex-uh +# eph = pex-ph +# edivuh = divuex-(∇⋅uh) +# writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) +# end + +## RHS STAB +# rhs_g = divuex # TODO: pass function on rather than constant value!!!!! +vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq_zm, # Test basis + dp_zm, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + divuex(1.0)) + +## DARCY TEST +ΓN = EmbeddedBoundary(cutgeo) +dΓN = Measure(ΓN,degree) +nN = get_normal_vector(ΓN) +s = -1 +β₀ = 1e3 +β = β₀*h.^(s) +m =1 +uNeu = uex +g = divuex +a((u,p), (v,q)) = ∫(v⋅u - (∇⋅v)*p - (∇⋅u)*q)dΩ + ∫(β*(u⋅nN)*(v⋅nN) + (v⋅nN)*p + m*(u⋅nN)*q)dΓN +l((v,q)) = ∫(- q*g)dΩ + ∫(β*(v⋅nN)*(uNeu⋅nN) + m*q*(uNeu⋅nN))dΓN +b = assemble_vector(l, Yzm) +#AssertionError: Your are trying to integrate a CellField using a CellQuadrature defined on incompatible triangulations. Verify that either the two objects are defined in the same triangulation or that the triangulaiton of the CellField is the background triangulation of the CellQuadrature. +assem=SparseMatrixAssembler(Xzm,Yzm) + +#RHS_DMIX +vec_wr=Gridap.FESpaces.collect_cell_vector(Yzm,l(dy_zm)) +push!(vec_wr[1],vecw_dmix...) +push!(vec_wr[2],vecr_dmix...) +vec_b = assemble_vector(assem, vec_wr) + +# NO STAB +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +A = assemble_matrix(assem, wrc) +res_nostab = compute_quantities(A,b,dΩ,pex,Xzm) + +# ONLY U +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +A = assemble_matrix(assem, wrc) +res_stab_u = compute_quantities(A,b,dΩ,pex,Xzm) + +# ONLY U FULL +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufull = compute_quantities(A,b,dΩ,pex,Xzm) + +# ONLY P +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +A = assemble_matrix(assem, wrc) +res_stab_p = compute_quantities(A,b,dΩ,pex,Xzm) + +# ONLY PFULL +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +A = assemble_matrix(assem, wrc) +res_stab_pfull = compute_quantities(A,b,dΩ,pex,Xzm) + +# ONLY DIV +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_div = compute_quantities(A,b,dΩ,pex,Xzm) + +# ONLY DIVU FULL +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_divfull = compute_quantities(A,b,dΩ,pex,Xzm) + +# ONLY PMIX +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +A = assemble_matrix(assem, wrc) +# res_stab_pmix = compute_quantities(A,b,dΩ,pex,Xzm) +res_stab_pmix = compute_quantities(A,b,dΩ,pex,Xzm) + +# ONLY DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_dmix = compute_quantities(A,vec_b,dΩ,pex,Xzm) + +# U + P + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_updivu = compute_quantities(A,b,dΩ,pex,Xzm) + +# UFULL + PFULL + DIVUFULL +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ,pex,Xzm) + +# U + DIVU + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_udivupmixdmix = compute_quantities(A,vec_b,dΩ,pex,Xzm) + +# UFULL + DIVUFULL + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_ufulldivufullpmixdmix = compute_quantities(A,vec_b,dΩ,pex,Xzm) + +## PRINT DATA: +# print(res_nostab, res_stab_u, res_stab_ufull, res_stab_p, res_stab_pfull, res_stab_div, res_stab_divfull, res_stab_pmix, res_stab_dmix, res_stab_updivu, res_stab_ufullpfulldivufull, res_stab_udivupmixdmix, res_stab_ufulldivufullpmixdmix) +print("results") +res_nostab +res_stab_u +res_stab_ufull +res_stab_p +res_stab_pfull +res_stab_div +res_stab_divfull +res_stab_pmix +res_stab_dmix +print("") +res_stab_updivu +res_stab_ufullpfulldivufull +res_stab_udivupmixdmix +res_stab_ufulldivufullpmixdmix \ No newline at end of file From 5762de3ebf6ebea8acba87f57f8dbda5da02f4be Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Wed, 29 Jan 2025 12:30:44 +1100 Subject: [PATCH 056/120] removed older canvases in repo and combined tests (1 = l2-like projection, 2=darcy problem) in single canvas --- TEST0-cutsquare-nint3.jl | 513 --------- TEST0-cutsquare.jl | 536 ---------- TEST0.jl | 469 --------- TEST1-cutsquare-nint3.jl | 544 ---------- bulk_ghost_penalty_canvas.jl | 973 +++++++++--------- bulk_ghost_penalty_canvas_div.jl | 257 ----- ...iv_on_cut_cells _exploration_full-terms.jl | 543 ---------- bulk_ghost_penalty_canvas_div_on_cut_cells.jl | 248 ----- 8 files changed, 465 insertions(+), 3618 deletions(-) delete mode 100644 TEST0-cutsquare-nint3.jl delete mode 100644 TEST0-cutsquare.jl delete mode 100644 TEST0.jl delete mode 100644 TEST1-cutsquare-nint3.jl delete mode 100644 bulk_ghost_penalty_canvas_div.jl delete mode 100644 bulk_ghost_penalty_canvas_div_on_cut_cells _exploration_full-terms.jl delete mode 100644 bulk_ghost_penalty_canvas_div_on_cut_cells.jl diff --git a/TEST0-cutsquare-nint3.jl b/TEST0-cutsquare-nint3.jl deleted file mode 100644 index c5f7e2b4..00000000 --- a/TEST0-cutsquare-nint3.jl +++ /dev/null @@ -1,513 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("aggregates_bounding_boxes_tools.jl") -include("bulk_ghost_penalty_stab_tools.jl") -include("fields_and_blocks_tools.jl") -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 2 -uex(x) = -VectorValue(2*x[1],2*x[2]) -pex(x) = (x[1]^2 + x[2]^2) -divuex(x) = -4.0 - -# Select geometry -nint = 3 - -# cut length -# ε = 0.2/2.0 # not so small cut -ε = 0.2e-2/2.0 # smaller cut -# ε = 0.2e-6/2.0 # smallest cut - -pmin = Point(0.0,0.0) -pmax = Point(1.0,1.0) -function setup_geometry(nint, ε, pmin, pmax) - nbg = nint + 2 + 2 # number of elements in the background mesh (2 from cut, 2 dummy) - dp = pmax - pmin - h = dp[1]/nint - bgpmin = pmin - Point(2*h,2*h) - bgpmax = pmax + Point(2*h,2*h) - bgdp = bgpmax - bgpmin - partition = (nbg,nbg) - bgmodel = CartesianDiscreteModel(bgpmin,bgpmax,partition) - hbg = bgdp[1]/nbg - @assert abs(hbg - h) < 10e-10 - @assert abs(ε/h) < 0.5 - - # The following is based on square (part of GridapEmbedded): - e1 = VectorValue(1,0) - e2 = VectorValue(0,1) - x0 = pmin + Point(0.5*dp[1],0.5*dp[2]) - L1 = dp[1] + 2*ε - L2 = dp[2] + 2*ε - plane1 = plane(x0=x0-0.5*L2*e2,v=-e2,name="bottom") - plane2 = plane(x0=x0+0.5*L1*e1,v= e1,name="right") - plane3 = plane(x0=x0+0.5*L2*e2,v= e2,name="top") - plane4 = plane(x0=x0-0.5*L1*e1,v=-e1,name="left") - - geo12 = intersect(plane1,plane2) - geo34 = intersect(plane3,plane4) - - square = intersect(geo12,geo34) - cutgeo = cut(bgmodel, square) - - # TODO: not necessary to export square as no cuts.. - bgmodel, cutgeo, h -end -bgmodel, cutgeo, h = setup_geometry(nint, ε, pmin, pmax) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# Triangulations -Ωbg = Triangulation(bgmodel) -Ωact = Triangulation(cutgeo,ACTIVE) - -# Physical domain -Ω = Triangulation(cutgeo,PHYSICAL) -degree=2*2*(order+1) -dΩ = Measure(Ω,degree) - -# Set up global spaces -V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -U = TrialFESpace(V) -P = TrialFESpace(Q) -Y = MultiFieldFESpace([V, Q]) -X = MultiFieldFESpace([U, P]) -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -# Aggregate cells and triangulation -agg_cells =setup_agg_cells(aggregate_to_cells) -Ωbg_agg_cells=view(Ωbg,agg_cells) - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) -agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) -ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, - agg_cells_to_aggregate) - -# Spaces on bounding boxes -reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) -reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - -# Numerical integration (Measures) -dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) - -# LHS of L2 projection on bounding boxes. -aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - ubb, - vbb) - -# Selecting relevant global dofs ids of aggregate cells (from background mesh) -Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) -U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) -P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) - -# Computing local (per aggregate) dof ids -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) - -# Compute global dofs ids per aggregate and reindex these -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) - -# parameters -γ = 10.0 # Interior bulk-penalty stabilization parameter -h_U = 1.0 - -########################################### -### STABILIZATION ON Ωagg\Troot ### -########################################### - -## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) - -## (2) FIND THE INTERIOR CELLS -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface - -## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS -root_cells = setup_root_cells(int_cells, int_nonagg_cells) -cut_cells = setup_cut_cells(agg_cells, root_cells) - -## (4) CUT CELLS AND MEASURE -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) -dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) - -# (5) DOF IDS related to cut cells -Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) -U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) -P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) - -# (6) Defining cut_cells_to_aggregate_dof_ids -# aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) -aggregate_to_cut_cells = revised_setup_aggregate_to_cut_cells(aggregates, root_cells) -cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) -U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) -P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) - -# (7) Compute stabilization terms for u and p -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) -#DIV stabilization part -wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basisr - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -## FULL stabilization terms: -wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -# MIXED STAB TERMS -wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - dv) - -wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - du) - -########################################### -### VISUALIZATION ### -########################################### -# writevtk(Ωbg,"trian-bg") -# writevtk(Ωbg_cut_cells,"trian-bg-cut-cells") -colors = color_aggregates(aggregates,bgmodel) -writevtk(Ωbg,"trian-bg-with-coloured-aggregates", celldata=["aggregate"=>aggregates,"color"=>colors]) -# writevtk(Ωbg_agg_cells,"trian-bg-agg-cells") -# Ωbg_int_cells=view(Ωbg,int_cells) -# Ωbg_root_cells=view(Ωbg,root_cells) -# writevtk(Ωbg_int_cells,"trian-bg-int-cells") -# writevtk(Ωbg_root_cells,"trian-bg-root-cells") -writevtk(Ω,"trian-phys") -# writevtk(Ωact,"trian-act") - -function compute_quantities(A,b,dΩ) - cond_A = cond(Array(A)) - norm_A = norm(A) - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - norm_euh = sum(∫(euh⋅euh)*dΩ) - norm_eph = sum(∫(eph*eph)*dΩ) - norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) - return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) -end - -function plot_quantities(A,b,Ω;filename="results") - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) -end - -## RHS STAB -# rhs_g = divuex # TODO: pass function on rather than constant value!!!!! -vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - divuex(1.0)) - -## TEST WITH MANUFACTURED SOLUTIONS -a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ -assem=SparseMatrixAssembler(X,Y) -l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ -b = assemble_vector(l, Y) - -#RHS_DMIX -vec_wr=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) -push!(vec_wr[1],vecw_dmix...) -push!(vec_wr[2],vecr_dmix...) -vec_b = assemble_vector(assem, vec_wr) - -# NO STAB -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -A = assemble_matrix(assem, wrc) -res_nostab = compute_quantities(A,b,dΩ) - -# ONLY U -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -A = assemble_matrix(assem, wrc) -res_stab_u = compute_quantities(A,b,dΩ) - -# ONLY U FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufull = compute_quantities(A,b,dΩ) - -# ONLY P -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -A = assemble_matrix(assem, wrc) -res_stab_p = compute_quantities(A,b,dΩ) - -# ONLY PFULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -A = assemble_matrix(assem, wrc) -res_stab_pfull = compute_quantities(A,b,dΩ) - -# ONLY DIV -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_div = compute_quantities(A,b,dΩ) - -# ONLY DIVU FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_divfull = compute_quantities(A,b,dΩ) - -# ONLY PMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -A = assemble_matrix(assem, wrc) -# res_stab_pmix = compute_quantities(A,b,dΩ) -res_stab_pmix = compute_quantities(A,b,dΩ) - -# ONLY DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_dmix = compute_quantities(A,vec_b,dΩ) - -# U + P + DIVU -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_updivu = compute_quantities(A,b,dΩ) - -# UFULL + PFULL + DIVUFULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ) - -# U + DIVU + PMIX + DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_udivupmixdmix = compute_quantities(A,vec_b,dΩ) - -# UFULL + DIVUFULL + PMIX + DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_ufulldivufullpmixdmix = compute_quantities(A,vec_b,dΩ) - -## PRINT DATA: -# print(res_nostab, res_stab_u, res_stab_ufull, res_stab_p, res_stab_pfull, res_stab_div, res_stab_divfull, res_stab_pmix, res_stab_dmix, res_stab_updivu, res_stab_ufullpfulldivufull, res_stab_udivupmixdmix, res_stab_ufulldivufullpmixdmix) -print("results") -res_nostab -res_stab_u -res_stab_ufull -res_stab_p -res_stab_pfull -res_stab_div -res_stab_divfull -res_stab_pmix -res_stab_dmix -print("") -res_stab_updivu -res_stab_ufullpfulldivufull -res_stab_udivupmixdmix -res_stab_ufulldivufullpmixdmix \ No newline at end of file diff --git a/TEST0-cutsquare.jl b/TEST0-cutsquare.jl deleted file mode 100644 index 7cfd4126..00000000 --- a/TEST0-cutsquare.jl +++ /dev/null @@ -1,536 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("aggregates_bounding_boxes_tools.jl") -include("bulk_ghost_penalty_stab_tools.jl") -include("fields_and_blocks_tools.jl") -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 0 -uex(x) = -VectorValue(2*x[1],2*x[2]) -pex(x) = (x[1]^2 + x[2]^2) -divuex(x) = -4.0 - -# Select geometry -nint = 2 - -# cut length -# ε = 0.2 # not so small cut -ε = 0.2e-2 # smaller cut -# ε = 0.2e-6 # smallest cut - -pmin = Point(0.0,0.0) -pmax = Point(1.0,1.0) -function setup_geometry(nint, ε, pmin, pmax) - nbg = nint + 2 + 2 # number of elements in the background mesh (2 from cut, 2 dummy) - dp = pmax - pmin - h = dp[1]/nint - bgpmin = pmin - Point(2*h,2*h) - bgpmax = pmax + Point(2*h,2*h) - bgdp = bgpmax - bgpmin - partition = (nbg,nbg) - bgmodel = CartesianDiscreteModel(bgpmin,bgpmax,partition) - hbg = bgdp[1]/nbg - @assert abs(hbg - h) < 10e-10 - @assert abs(ε/h) < 0.5 - - # The following is based on square (part of GridapEmbedded): - e1 = VectorValue(1,0) - e2 = VectorValue(0,1) - x0 = pmin + Point(0.5*dp[1],0.5*dp[2]) - L1 = dp[1] + 2*ε - L2 = dp[2] + 2*ε - plane1 = plane(x0=x0-0.5*L2*e2,v=-e2,name="bottom") - plane2 = plane(x0=x0+0.5*L1*e1,v= e1,name="right") - plane3 = plane(x0=x0+0.5*L2*e2,v= e2,name="top") - plane4 = plane(x0=x0-0.5*L1*e1,v=-e1,name="left") - - geo12 = intersect(plane1,plane2) - geo34 = intersect(plane3,plane4) - - square = intersect(geo12,geo34) - cutgeo = cut(bgmodel, square) - - # TODO: not necessary to export square as no cuts.. - bgmodel, cutgeo, h -end -bgmodel, cutgeo, h = setup_geometry(nint, ε, pmin, pmax) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# Triangulations -Ωbg = Triangulation(bgmodel) -Ωact = Triangulation(cutgeo,ACTIVE) - -# Physical domain -Ω = Triangulation(cutgeo,PHYSICAL) -degree=2*2*(order+1) -dΩ = Measure(Ω,degree) - -# Set up global spaces -V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -U = TrialFESpace(V) -P = TrialFESpace(Q) -Y = MultiFieldFESpace([V, Q]) -X = MultiFieldFESpace([U, P]) -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -# Aggregate cells and triangulation -agg_cells =setup_agg_cells(aggregate_to_cells) -Ωbg_agg_cells=view(Ωbg,agg_cells) - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) -agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) -ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, - agg_cells_to_aggregate) - -# Spaces on bounding boxes -reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) -reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - -# Numerical integration (Measures) -dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) - -# LHS of L2 projection on bounding boxes. -aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - ubb, - vbb) - -# Selecting relevant global dofs ids of aggregate cells (from background mesh) -Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) -U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) -P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) - -# Computing local (per aggregate) dof ids -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) - -# Compute global dofs ids per aggregate and reindex these -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) - -# parameters -γ = 10.0 # Interior bulk-penalty stabilization parameter -h_U = 1.0 - -########################################### -### STABILIZATION ON Ωagg\Troot ### -########################################### - -## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) - -## (2) FIND THE INTERIOR CELLS -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface - -## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS -root_cells = setup_root_cells(int_cells, int_nonagg_cells) -cut_cells = setup_cut_cells(agg_cells, root_cells) - -## (4) CUT CELLS AND MEASURE -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) -dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) - -# (5) DOF IDS related to cut cells -Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) -U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) -P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) - -# (6) Defining cut_cells_to_aggregate_dof_ids -aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) -cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) -U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) -P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) - -# (7) Compute stabilization terms for u and p -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) -#DIV stabilization part -wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -## FULL stabilization terms: -wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -# MIXED STAB TERMS -wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - dv) - -wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - du) - -########################################### -### VISUALIZATION ### -########################################### -writevtk(Ωbg,"trian-bg") -writevtk(Ωbg_cut_cells,"trian-bg-cut-cells") -colors = color_aggregates(aggregates,bgmodel) -writevtk(Ωbg,"trian-bg-with-coloured-aggregates", celldata=["aggregate"=>aggregates,"color"=>colors]) -writevtk(Ωbg_agg_cells,"trian-bg-agg-cells") -Ωbg_int_cells=view(Ωbg,int_cells) -Ωbg_root_cells=view(Ωbg,root_cells) -writevtk(Ωbg_int_cells,"trian-bg-int-cells") -writevtk(Ωbg_root_cells,"trian-bg-root-cells") -writevtk(Ω,"trian-phys") -writevtk(Ωact,"trian-act") - -function compute_quantities(A,b,dΩ) - cond_A = cond(Array(A)) - norm_A = norm(A) - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - norm_euh = sum(∫(euh⋅euh)*dΩ) - norm_eph = sum(∫(eph*eph)*dΩ) - norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) - return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) -end - -function plot_quantities(A,b,Ω;filename="results") - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) -end - -## RHS STAB -# rhs_g = divuex # TODO: pass function on rather than constant value!!!!! -vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - divuex(1.0)) - -## TEST WITH MANUFACTURED SOLUTIONS -a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ -assem=SparseMatrixAssembler(X,Y) -l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ -b = assemble_vector(l, Y) - -#RHS_DMIX -vec_wr=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) -push!(vec_wr[1],vecw_dmix...) -push!(vec_wr[2],vecr_dmix...) -vec_b = assemble_vector(assem, vec_wr) -# res_nostab = compute_quantities(A,vec_b,dΩ) - -# NO STAB -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -A = assemble_matrix(assem, wrc) -res_nostab = compute_quantities(A,b,dΩ) - -# ONLY U -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -A = assemble_matrix(assem, wrc) -res_stab_u = compute_quantities(A,b,dΩ) - -# ONLY U FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufull = compute_quantities(A,b,dΩ) - -# ONLY P -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -A = assemble_matrix(assem, wrc) -res_stab_p = compute_quantities(A,b,dΩ) - -# ONLY PFULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -A = assemble_matrix(assem, wrc) -res_stab_pfull = compute_quantities(A,b,dΩ) - -# ONLY DIV -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_div = compute_quantities(A,b,dΩ) - -# ONLY DIVU FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_divfull = compute_quantities(A,b,dΩ) - -# ONLY PMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -A = assemble_matrix(assem, wrc) -# res_stab_pmix = compute_quantities(A,b,dΩ) -res_stab_pmix = compute_quantities(A,b,dΩ) - -# ONLY DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_dmix = compute_quantities(A,vec_b,dΩ) - -# U + P + DIVU -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_updivu = compute_quantities(A,b,dΩ) - -# UFULL + PFULL + DIVUFULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ) - -# U + DIVU + PMIX + DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_udivupmixdmix = compute_quantities(A,vec_b,dΩ) - -# UFULL + DIVUFULL + PMIX + DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_ufulldivufullpmixdmix = compute_quantities(A,vec_b,dΩ) - -## PRINT DATA: -# print(res_nostab, res_stab_u, res_stab_ufull, res_stab_p, res_stab_pfull, res_stab_div, res_stab_divfull, res_stab_pmix, res_stab_dmix, res_stab_updivu, res_stab_ufullpfulldivufull, res_stab_udivupmixdmix, res_stab_ufulldivufullpmixdmix) -res_nostab -res_stab_u -res_stab_ufull -res_stab_p -res_stab_pfull -res_stab_div -res_stab_divfull -res_stab_pmix -res_stab_dmix -res_stab_updivu -res_stab_ufullpfulldivufull -res_stab_udivupmixdmix -res_stab_ufulldivufullpmixdmix - -# OLD: - -############## (k=0,n=16) ##################################################################### -# 2.31e9, 6040.0, 1.20e-27, 7.71e-5, 1.77e-30 # -- NO STAB -- -# 3.58e8, 6040.0, 2.0 e-28, 7.71e-5, 1.93e-30 # U -# 3.58e8, 6050.0, 9.85e-28, 7.71e-5, 4.32e-30 # U_FULL -# 7.59e6, 55500.0, 1.14e-26, 1.46e-4, 1.38e-29 # U + P + DIVU -# 7.59e6, 55500.0, 6.17e-26, 1.45e-4, 9.62e-29 # U_FULL + P + DIVU -# 7.64e6, 54500.0, 8.79e-26, 1.46e-4, 1.98e-28 # U_FULL + P + DIVU_FULL (*) -# 1.28e7, 55500.0, 1.64e-26, 1.16e-4, 4.20e-29 # U + P_FULL + DIVU -# 1.28e7, 55500.0, 6.17e-26, 1.16e-4, 9.62e-29 # U_FULL + P_FULL + DIVU -# 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL -# 7.64e6, 54500.0, 2.75e-26, 1.46e-4, 1.14e-28 # U + P + DIVU_FULL (*) -############################################################################################### - -############## (k=2,n=16) ##################################################################### -# 2.82e29, 9.21e8, 4.0e-12, 7.79e-28, 2.34e-13 # -- NO STAB -- -# 2.82e29, 9.21e8, 2.05e-18, 7.79e-28, 1.66e-19 # U -# 2.82e29, 9.21e8, 1.23e-16, 7.79e-28, 1.39e-18 # U_FULL -# 4.72e16, 9.45e9, 3.08e-14, 4.07e-29, 1.76e-17 # U + P + DIVU -# 4.72e16, 9.45e9, 2.52e-11, 4.07e-29, 3.17e-16 # U_FULL + P + DIVU -# 3.00e18, 9.45e9, 3.08e-14, 1.65e-28, 1.76e-17 # U + P_FULL + DIVU -# 3.00e18, 9.45e9, 2.52e-11, 1.65e-28, 3.17e-16 # U_FULL + P_FULL + DIVU -############################################################################################### \ No newline at end of file diff --git a/TEST0.jl b/TEST0.jl deleted file mode 100644 index 9a2151e4..00000000 --- a/TEST0.jl +++ /dev/null @@ -1,469 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("aggregates_bounding_boxes_tools.jl") -include("bulk_ghost_penalty_stab_tools.jl") -include("fields_and_blocks_tools.jl") -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 0 -uex(x) = -VectorValue(2*x[1],2*x[2]) -pex(x) = (x[1]^2 + x[2]^2) -divuex(x) = -4.0 - -# Select geometry -R = 0.2 -geom = disk(R, x0=Point(0.5,0.5)) - -# Setup background model -n=16 -partition = (n,n) -box = get_metadata(geom) -bgmodel = CartesianDiscreteModel((0,1,0,1),partition) -dp = box.pmax - box.pmin -h = dp[1]/n - -# Cut the background model with the mesh -cutgeo = cut(bgmodel,geom) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# Triangulations -Ωbg = Triangulation(bgmodel) -Ωact = Triangulation(cutgeo,ACTIVE) - -# Physical domain -Ω = Triangulation(cutgeo,PHYSICAL) -degree=2*2*(order+1) -dΩ = Measure(Ω,degree) - -# Set up global spaces -V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -U = TrialFESpace(V) -P = TrialFESpace(Q) -Y = MultiFieldFESpace([V, Q]) -X = MultiFieldFESpace([U, P]) -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -# Aggregate cells and triangulation -agg_cells =setup_agg_cells(aggregate_to_cells) -Ωbg_agg_cells=view(Ωbg,agg_cells) - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) -agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) -ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, - agg_cells_to_aggregate) - -# Spaces on bounding boxes -reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) -reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - -# Numerical integration (Measures) -dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) - -# LHS of L2 projection on bounding boxes. -aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - ubb, - vbb) - -# Selecting relevant global dofs ids of aggregate cells (from background mesh) -Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) -U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) -P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) - -# Computing local (per aggregate) dof ids -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) - -# Compute global dofs ids per aggregate and reindex these -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) -P_Ωbg_agg_cell_dof_ids - -# parameters -γ = 10.0 # Interior bulk-penalty stabilization parameter -h_U = 1.0 - -########################################### -### STABILIZATION ON Ωagg\Troot ### -########################################### - -## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) - -## (2) FIND THE INTERIOR CELLS -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface - -## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS -root_cells = setup_root_cells(int_cells, int_nonagg_cells) -cut_cells = setup_cut_cells(agg_cells, root_cells) - -## (4) CUT CELLS AND MEASURE -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) -dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) - -# (5) DOF IDS related to cut cells -Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) -U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) -P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) - -# (6) Defining cut_cells_to_aggregate_dof_ids -aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) -cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) -U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) -P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) - -# (7) Compute stabilization terms for u and p -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -#DIV stabilization part -wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -## FULL stabilization terms: -wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -# MIXED STAB TERMS -wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - dv) - -wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - du) - -function compute_quantities(A,b,dΩ) - cond_A = cond(Array(A)) - norm_A = norm(A) - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - norm_euh = sum(∫(euh⋅euh)*dΩ) - norm_eph = sum(∫(eph*eph)*dΩ) - norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) - return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) -end - -function plot_quantities(A,b,Ω,dΩ;filename="results") - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) -end - -## TEST WITH MANUFACTURED SOLUTIONS -a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ -assem=SparseMatrixAssembler(X,Y) -l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ -b = assemble_vector(l, Y) - -# NO STAB -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -A = assemble_matrix(assem, wrc) -res_nostab = compute_quantities(A,b,dΩ) - -# ONLY U -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -A = assemble_matrix(assem, wrc) -res_stab_u = compute_quantities(A,b,dΩ) - -# ONLY U FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufull = compute_quantities(A,b,dΩ) - -# ONLY P -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -A = assemble_matrix(assem, wrc) -res_stab_p = compute_quantities(A,b,dΩ) - -# ONLY PFULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -A = assemble_matrix(assem, wrc) -res_stab_pfull = compute_quantities(A,b,dΩ) - -# ONLY DIV -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_div = compute_quantities(A,b,dΩ) - -# ONLY DIVU FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_divfull = compute_quantities(A,b,dΩ) - -# ONLY PMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -A = assemble_matrix(assem, wrc) -res_stab_pmix = compute_quantities(A,b,dΩ) - -# ONLY DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_dmix = compute_quantities(A,b,dΩ) - -# U + P + DIVU -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_updivu = compute_quantities(A,b,dΩ) - -# UFULL + PFULL + DIVUFULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ) - -# U + DIVU + PMIX + DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_udivupmixdmix = compute_quantities(A,b,dΩ) - -# UFULL + DIVUFULL + PMIX + DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_ufulldivufullpmixdmix = compute_quantities(A,b,dΩ) - -## PRINT DATA: -# print(res_nostab, res_stab_u, res_stab_ufull, res_stab_p, res_stab_pfull, res_stab_div, res_stab_divfull, res_stab_pmix, res_stab_dmix, res_stab_updivu, res_stab_ufullpfulldivufull, res_stab_udivupmixdmix, res_stab_ufulldivufullpmixdmix) -res_nostab -res_stab_u -res_stab_ufull -res_stab_p -res_stab_pfull -res_stab_div -res_stab_divfull -res_stab_pmix -res_stab_dmix -res_stab_updivu -res_stab_ufullpfulldivufull -res_stab_udivupmixdmix -res_stab_ufulldivufullpmixdmix - -# OLD: - -############## (k=0,n=16) ##################################################################### -# 2.31e9, 6040.0, 1.20e-27, 7.71e-5, 1.77e-30 # -- NO STAB -- -# 3.58e8, 6040.0, 2.0 e-28, 7.71e-5, 1.93e-30 # U -# 3.58e8, 6050.0, 9.85e-28, 7.71e-5, 4.32e-30 # U_FULL -# 7.59e6, 55500.0, 1.14e-26, 1.46e-4, 1.38e-29 # U + P + DIVU -# 7.59e6, 55500.0, 6.17e-26, 1.45e-4, 9.62e-29 # U_FULL + P + DIVU -# 7.64e6, 54500.0, 8.79e-26, 1.46e-4, 1.98e-28 # U_FULL + P + DIVU_FULL (*) -# 1.28e7, 55500.0, 1.64e-26, 1.16e-4, 4.20e-29 # U + P_FULL + DIVU -# 1.28e7, 55500.0, 6.17e-26, 1.16e-4, 9.62e-29 # U_FULL + P_FULL + DIVU -# 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL -# 7.64e6, 54500.0, 2.75e-26, 1.46e-4, 1.14e-28 # U + P + DIVU_FULL (*) -############################################################################################### - -############## (k=2,n=16) ##################################################################### -# 2.82e29, 9.21e8, 4.0e-12, 7.79e-28, 2.34e-13 # -- NO STAB -- -# 2.82e29, 9.21e8, 2.05e-18, 7.79e-28, 1.66e-19 # U -# 2.82e29, 9.21e8, 1.23e-16, 7.79e-28, 1.39e-18 # U_FULL -# 4.72e16, 9.45e9, 3.08e-14, 4.07e-29, 1.76e-17 # U + P + DIVU -# 4.72e16, 9.45e9, 2.52e-11, 4.07e-29, 3.17e-16 # U_FULL + P + DIVU -# 3.00e18, 9.45e9, 3.08e-14, 1.65e-28, 1.76e-17 # U + P_FULL + DIVU -# 3.00e18, 9.45e9, 2.52e-11, 1.65e-28, 3.17e-16 # U_FULL + P_FULL + DIVU -############################################################################################### \ No newline at end of file diff --git a/TEST1-cutsquare-nint3.jl b/TEST1-cutsquare-nint3.jl deleted file mode 100644 index a2e7dc67..00000000 --- a/TEST1-cutsquare-nint3.jl +++ /dev/null @@ -1,544 +0,0 @@ -# TEST1: Darcy test case solved using a zero mean pressure space. In the postprocessing procedure, the solution is corrected for this, so that the mean pressure from the exact solution is matched. -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("aggregates_bounding_boxes_tools.jl") -include("bulk_ghost_penalty_stab_tools.jl") -include("fields_and_blocks_tools.jl") -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 0 -uex(x) = -VectorValue(2*x[1],2*x[2]) -pex(x) = (x[1]^2 + x[2]^2) -divuex(x) = -4.0 - -# Select geometry -nint = 3 - -# cut length -# ε = 0.2/2.0 # not so small cut -ε = 0.2e-2/2.0 # smaller cut -# ε = 0.2e-6/2.0 # smallest cut - -pmin = Point(0.0,0.0) -pmax = Point(1.0,1.0) -function setup_geometry(nint, ε, pmin, pmax) - nbg = nint + 2 + 2 # number of elements in the background mesh (2 from cut, 2 dummy) - dp = pmax - pmin - h = dp[1]/nint - bgpmin = pmin - Point(2*h,2*h) - bgpmax = pmax + Point(2*h,2*h) - bgdp = bgpmax - bgpmin - partition = (nbg,nbg) - bgmodel = CartesianDiscreteModel(bgpmin,bgpmax,partition) - hbg = bgdp[1]/nbg - @assert abs(hbg - h) < 10e-10 - @assert abs(ε/h) < 0.5 - - # The following is based on square (part of GridapEmbedded): - e1 = VectorValue(1,0) - e2 = VectorValue(0,1) - x0 = pmin + Point(0.5*dp[1],0.5*dp[2]) - L1 = dp[1] + 2*ε - L2 = dp[2] + 2*ε - plane1 = plane(x0=x0-0.5*L2*e2,v=-e2,name="bottom") - plane2 = plane(x0=x0+0.5*L1*e1,v= e1,name="right") - plane3 = plane(x0=x0+0.5*L2*e2,v= e2,name="top") - plane4 = plane(x0=x0-0.5*L1*e1,v=-e1,name="left") - - geo12 = intersect(plane1,plane2) - geo34 = intersect(plane3,plane4) - - square = intersect(geo12,geo34) - cutgeo = cut(bgmodel, square) - - # TODO: not necessary to export square as no cuts.. - bgmodel, cutgeo, h -end -bgmodel, cutgeo, h = setup_geometry(nint, ε, pmin, pmax) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# Triangulations -Ωbg = Triangulation(bgmodel) -Ωact = Triangulation(cutgeo,ACTIVE) - -# Physical domain -Ω = Triangulation(cutgeo,PHYSICAL) -degree=2*2*(order+1) -dΩ = Measure(Ω,degree) - -## NEWLY ADDED FOR ZM PRESSURE SPACE -# Define root and cut cells. -## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) -@assert length(int_nonagg_cells)>0 # otherwise we can not constrain a dof -# TO DO: check if this works for order =2! - -# Set up zero-mean pressure space, with fixed interior dof -Qnzm = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -int_nonagg_dof_to_fix = int_nonagg_cells[1] # pick the first interior cell that is not part of an aggregate to be contrained by the zero mean pressure condition. -spaceWithConstantFixed = Gridap.FESpaces.FESpaceWithConstantFixed(Qnzm,true,int_nonagg_dof_to_fix) -Qzm_vol_i = assemble_vector(v->∫(v)*dΩ,Qnzm) -Qzm_vol = sum(Qzm_vol_i) -Qzm = Gridap.FESpaces.ZeroMeanFESpace(spaceWithConstantFixed,Qzm_vol_i,Qzm_vol) -Pzm = TrialFESpace(Qzm) - -# Set up global spaces -V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -U = TrialFESpace(V) -Xzm = MultiFieldFESpace([U, Pzm]) -Yzm = MultiFieldFESpace([V, Qzm]) -dx_zm = get_trial_fe_basis(Xzm) -dy_zm = get_fe_basis(Yzm) -du_zm,dp_zm = dx_zm -dv_zm,dq_zm = dy_zm - -# Aggregate cells and triangulation -agg_cells =setup_agg_cells(aggregate_to_cells) -Ωbg_agg_cells=view(Ωbg,agg_cells) - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) -agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) -ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, - agg_cells_to_aggregate) - -# Spaces on bounding boxes -reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) -reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - -# Numerical integration (Measures) -dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) - -# LHS of L2 projection on bounding boxes. -aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - ubb, - vbb) - -# Selecting relevant global dofs ids of aggregate cells (from background mesh) -Ωbg_agg_cell_dof_ids = get_cell_dof_ids(Xzm,Ωbg_agg_cells) -U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) -P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) - -# Computing local (per aggregate) dof ids -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) - -# Compute global dofs ids per aggregate and reindex these -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) - -# parameters -γ = 10.0 # Interior bulk-penalty stabilization parameter -h_U = 1.0 - -########################################### -### STABILIZATION ON Ωagg\Troot ### -########################################### - -# ## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE -# int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -# int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) - -## (2) FIND THE INTERIOR CELLS -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface - -## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS -root_cells = setup_root_cells(int_cells, int_nonagg_cells) -cut_cells = setup_cut_cells(agg_cells, root_cells) - -## (4) CUT CELLS AND MEASURE -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) -dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) - -# (5) DOF IDS related to cut cells -Ωbg_cut_cell_dof_ids = get_cell_dof_ids(Xzm,Ωbg_cut_cells) -U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) -P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) - -# (6) Defining cut_cells_to_aggregate_dof_ids -# aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) -aggregate_to_cut_cells = revised_setup_aggregate_to_cut_cells(aggregates, root_cells) -cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) -U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) -P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) - -# (7) Compute stabilization terms for u and p -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv_zm, # Test basis - du_zm, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq_zm, # Test basis - dp_zm, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) -#DIV stabilization part -wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv_zm, # Test basisr - du_zm, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -## FULL stabilization terms: -wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv_zm, # Test basis - du_zm, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq_zm, # Test basis - dp_zm, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv_zm, # Test basis - du_zm, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -# MIXED STAB TERMS -wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq_zm, # Test basis - dp_zm, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - dv_zm) - -wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq_zm, # Test basis - dp_zm, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - du_zm) - -########################################### -### VISUALIZATION ### -########################################### -# # writevtk(Ωbg,"trian-bg") -# # writevtk(Ωbg_cut_cells,"trian-bg-cut-cells") -# colors = color_aggregates(aggregates,bgmodel) -# writevtk(Ωbg,"trian-bg-with-coloured-aggregates", celldata=["aggregate"=>aggregates,"color"=>colors]) -# # writevtk(Ωbg_agg_cells,"trian-bg-agg-cells") -# # Ωbg_int_cells=view(Ωbg,int_cells) -# # Ωbg_root_cells=view(Ωbg,root_cells) -# # writevtk(Ωbg_int_cells,"trian-bg-int-cells") -# # writevtk(Ωbg_root_cells,"trian-bg-root-cells") -# writevtk(Ω,"trian-phys") -# # writevtk(Ωact,"trian-act") - -function compute_quantities(A,b,dΩ,pex,X) - cond_A = cond(Array(A)) - norm_A = norm(A) - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph_zm = xh - area = sum(∫(1.0)dΩ) - mean_p = sum(∫(pex)dΩ)/area # mean presure exact sol - ph = ph_zm + mean_p - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - norm_euh = sum(∫(euh⋅euh)*dΩ) - norm_eph = sum(∫(eph*eph)*dΩ) - norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) - print("zeromean pressure $(sum(∫(ph_zm)dΩ)/area) and corrected mean pressure $(sum(∫(ph)dΩ)/area)") - return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) -end - -# to update -# function plot_quantities(A,b,Ω;filename="results") -# sol_x = A\b -# xh = FEFunction(X, sol_x) -# uh,ph = xh -# euh = uex-uh -# eph = pex-ph -# edivuh = divuex-(∇⋅uh) -# writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) -# end - -## RHS STAB -# rhs_g = divuex # TODO: pass function on rather than constant value!!!!! -vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq_zm, # Test basis - dp_zm, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - divuex(1.0)) - -## DARCY TEST -ΓN = EmbeddedBoundary(cutgeo) -dΓN = Measure(ΓN,degree) -nN = get_normal_vector(ΓN) -s = -1 -β₀ = 1e3 -β = β₀*h.^(s) -m =1 -uNeu = uex -g = divuex -a((u,p), (v,q)) = ∫(v⋅u - (∇⋅v)*p - (∇⋅u)*q)dΩ + ∫(β*(u⋅nN)*(v⋅nN) + (v⋅nN)*p + m*(u⋅nN)*q)dΓN -l((v,q)) = ∫(- q*g)dΩ + ∫(β*(v⋅nN)*(uNeu⋅nN) + m*q*(uNeu⋅nN))dΓN -b = assemble_vector(l, Yzm) -#AssertionError: Your are trying to integrate a CellField using a CellQuadrature defined on incompatible triangulations. Verify that either the two objects are defined in the same triangulation or that the triangulaiton of the CellField is the background triangulation of the CellQuadrature. -assem=SparseMatrixAssembler(Xzm,Yzm) - -#RHS_DMIX -vec_wr=Gridap.FESpaces.collect_cell_vector(Yzm,l(dy_zm)) -push!(vec_wr[1],vecw_dmix...) -push!(vec_wr[2],vecr_dmix...) -vec_b = assemble_vector(assem, vec_wr) - -# NO STAB -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -A = assemble_matrix(assem, wrc) -res_nostab = compute_quantities(A,b,dΩ,pex,Xzm) - -# ONLY U -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -A = assemble_matrix(assem, wrc) -res_stab_u = compute_quantities(A,b,dΩ,pex,Xzm) - -# ONLY U FULL -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufull = compute_quantities(A,b,dΩ,pex,Xzm) - -# ONLY P -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -A = assemble_matrix(assem, wrc) -res_stab_p = compute_quantities(A,b,dΩ,pex,Xzm) - -# ONLY PFULL -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -A = assemble_matrix(assem, wrc) -res_stab_pfull = compute_quantities(A,b,dΩ,pex,Xzm) - -# ONLY DIV -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_div = compute_quantities(A,b,dΩ,pex,Xzm) - -# ONLY DIVU FULL -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_divfull = compute_quantities(A,b,dΩ,pex,Xzm) - -# ONLY PMIX -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -A = assemble_matrix(assem, wrc) -# res_stab_pmix = compute_quantities(A,b,dΩ,pex,Xzm) -res_stab_pmix = compute_quantities(A,b,dΩ,pex,Xzm) - -# ONLY DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_dmix = compute_quantities(A,vec_b,dΩ,pex,Xzm) - -# U + P + DIVU -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_updivu = compute_quantities(A,b,dΩ,pex,Xzm) - -# UFULL + PFULL + DIVUFULL -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ,pex,Xzm) - -# U + DIVU + PMIX + DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_udivupmixdmix = compute_quantities(A,vec_b,dΩ,pex,Xzm) - -# UFULL + DIVUFULL + PMIX + DMIX -wrc=Gridap.FESpaces.collect_cell_matrix(Xzm,Yzm,a(dx_zm,dy_zm)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) -A = assemble_matrix(assem, wrc) -res_stab_ufulldivufullpmixdmix = compute_quantities(A,vec_b,dΩ,pex,Xzm) - -## PRINT DATA: -# print(res_nostab, res_stab_u, res_stab_ufull, res_stab_p, res_stab_pfull, res_stab_div, res_stab_divfull, res_stab_pmix, res_stab_dmix, res_stab_updivu, res_stab_ufullpfulldivufull, res_stab_udivupmixdmix, res_stab_ufulldivufullpmixdmix) -print("results") -res_nostab -res_stab_u -res_stab_ufull -res_stab_p -res_stab_pfull -res_stab_div -res_stab_divfull -res_stab_pmix -res_stab_dmix -print("") -res_stab_updivu -res_stab_ufullpfulldivufull -res_stab_udivupmixdmix -res_stab_ufulldivufullpmixdmix \ No newline at end of file diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 0a31b4fd..7b489f4c 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -3,593 +3,550 @@ using GridapEmbedded using FillArrays using LinearAlgebra +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") include("BulkGhostPenaltyAssembleMaps.jl") +# Problem selection +problem = 1 # 0 = Manufactured solution (L2-like projection), 1 = Darcy problem + # Manufactured solution -order = 1 -uex(x) = VectorValue(x[1],x[2]) -pex(x) = x[1]^order + x[2]^order +order = 2 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 # Select geometry -R = 0.2 -geom = disk(R, x0=Point(0.5,0.5)) - -# Setup background model -n=20 -partition = (n,n) -box = get_metadata(geom) -bgmodel = CartesianDiscreteModel((0,1,0,1),partition) -dp = box.pmax - box.pmin -h = dp[1]/n - -# Cut the background model with the mesh -cutdisk = cut(bgmodel,geom) +nint = 3 # number of (uncut) interior elements along single direction +# cut length +ε = 0.2/2.0 # not so small cut (nint = 3) +# ε = 0.2e-2/2.0 # smaller cut (nint = 3) +# ε = 0.2e-6/2.0 # smallest cut (nint = 3) +pmin = Point(0.0,0.0) +pmax = Point(1.0,1.0) +function setup_geometry(nint, ε, pmin, pmax) + nbg = nint + 2 + 2 # number of elements in the background mesh (2 from cut, 2 dummy) + dp = pmax - pmin + h = dp[1]/nint + bgpmin = pmin - Point(2*h,2*h) + bgpmax = pmax + Point(2*h,2*h) + bgdp = bgpmax - bgpmin + partition = (nbg,nbg) + bgmodel = CartesianDiscreteModel(bgpmin,bgpmax,partition) + hbg = bgdp[1]/nbg + @assert abs(hbg - h) < 10e-10 + @assert abs(ε/h) < 0.5 + + # The following is based on square (part of GridapEmbedded): + e1 = VectorValue(1,0) + e2 = VectorValue(0,1) + x0 = pmin + Point(0.5*dp[1],0.5*dp[2]) + L1 = dp[1] + 2*ε + L2 = dp[2] + 2*ε + plane1 = plane(x0=x0-0.5*L2*e2,v=-e2,name="bottom") + plane2 = plane(x0=x0+0.5*L1*e1,v= e1,name="right") + plane3 = plane(x0=x0+0.5*L2*e2,v= e2,name="top") + plane4 = plane(x0=x0-0.5*L1*e1,v=-e1,name="left") + + geo12 = intersect(plane1,plane2) + geo34 = intersect(plane3,plane4) + + square = intersect(geo12,geo34) + cutgeo = cut(bgmodel, square) + + bgmodel, cutgeo, h +end +bgmodel, cutgeo, h = setup_geometry(nint, ε, pmin, pmax) # Compute mapping among background model # cut cells and interior cells strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutdisk) - -""" - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains the global cell IDs of that cells in the background - model that belong to the same aggregate - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_aggregate_to_cells(aggregates) - - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]>1) - if !haskey(touched,agg) - push!(aggregate_to_cells,[i]) - touched[agg]=current_aggregate - current_aggregate+=1 - else - push!(aggregate_to_cells[touched[agg]],i) - end - end - end - end - aggregate_to_cells -end - -function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) - g=get_grid(bgmodel) - cell_coords=get_cell_coordinates(g) - D=num_dims(bgmodel) - xmin=Vector{Float64}(undef,D) - xmax=Vector{Float64}(undef,D) - - # Compute coordinates of the nodes defining the bounding boxes - bounding_box_node_coords= - Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) - ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] - data = collect(1:length(bounding_box_node_coords)) - bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) - for (agg,cells) in enumerate(aggregate_to_cells) - p=first(cell_coords[cells[1]]) - for i in 1:D - xmin[i]=p[i] - xmax[i]=p[i] - end - for cell in cells - for p in cell_coords[cell] - for i in 1:D - xmin[i]=min(xmin[i],p[i]) - xmax[i]=max(xmax[i],p[i]) - end - end - end - bounds = [(xmin[i], xmax[i]) for i in 1:D] - point_iterator = Iterators.product(bounds...) - bounding_box_node_coords[bounding_box_node_ids[agg]] = - reshape([Point(p...) for p in point_iterator],2^D) - end - - # Set up the discrete model of bounding boxes - HEX_AXIS=1 - polytope=Polytope(Fill(HEX_AXIS,D)...) - scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) - cell_types=fill(1,length(bounding_box_node_ids)) - cell_reffes=[scalar_reffe] - grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, - bounding_box_node_ids, - cell_reffes, - cell_types, - Gridap.Geometry.Oriented()) - Gridap.Geometry.UnstructuredDiscreteModel(grid) -end +aggregates = aggregate(strategy,cutgeo) aggregate_to_cells=setup_aggregate_to_cells(aggregates) aggregates_bounding_box_model= setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) -colors = color_aggregates(aggregates,bgmodel) -writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) -writevtk(aggregates_bounding_box_model, "bb_model") -writevtk(bgmodel, "bg_model") - -""" - Changes the domain of a trial/test basis defined on - the reference space of bounding boxes to the reference - space of the agg cells - - TO-DO: in the future, for system of PDEs (MultiField) we should - also take care of blocks (BlockMap) -""" -function change_domain_bb_to_agg_cells(basis_bb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) - @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() - bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) - bb_basis_array = Gridap.CellData.get_data(basis_bb) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Remove transpose map; we will add it later - @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) - @assert isa(bb_basis_array.maps,Fill) - @assert isa(bb_basis_array.maps.value,typeof(transpose)) - bb_basis_array=bb_basis_array.args[1] - end - - bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) - bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), - bb_basis_array_to_Ωagg_cells_array, - ref_agg_cell_to_ref_bb_map) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Add transpose - bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) - end - - Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, - Ωagg_cells, - ReferenceDomain()) +# Triangulations +Ωbg = Triangulation(bgmodel) +Ωact = Triangulation(cutgeo,ACTIVE) + +# Physical domain +Ω = Triangulation(cutgeo,PHYSICAL) +degree=2*2*(order+1) +dΩ = Measure(Ω,degree) + +## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE +int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) +int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) +@assert length(int_nonagg_cells)>0 # otherwise we can not constrain a dof + +# Pressure space +if problem==0 + Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +elseif problem==1 + # Set up zero-mean pressure space, with fixed interior dof + Qnzm = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) + @assert nint>2 + int_nonagg_dof_to_fix = int_nonagg_cells[1] # pick the first interior cell that is not part of an aggregate to be constrained by the zero mean pressure condition. + spaceWithConstantFixed = Gridap.FESpaces.FESpaceWithConstantFixed(Qnzm,true,int_nonagg_dof_to_fix) + Qzm_vol_i = assemble_vector(v->∫(v)*dΩ,Qnzm) + Qzm_vol = sum(Qzm_vol_i) + Q = Gridap.FESpaces.ZeroMeanFESpace(spaceWithConstantFixed,Qzm_vol_i,Qzm_vol) end - -# Set up objects required to compute both LHS and RHS of the L2 projection - # Set up global spaces -Ωhact = Triangulation(cutdisk,ACTIVE) - -V = FESpace(Ωhact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -Q = FESpace(Ωhact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) U = TrialFESpace(V) P = TrialFESpace(Q) Y = MultiFieldFESpace([V, Q]) X = MultiFieldFESpace([U, P]) +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy -# Generate an array with the global IDs of the cells -# that belong to an aggregrate. From now on, we will -# use the terminology "agg_cells" to refer to those -# cells of the background model that belong to an aggregate -# (i.e., they can be either cut or interior cells) -agg_cells=Vector{Int}() -for cells in aggregate_to_cells - append!(agg_cells,cells) -end +# Aggregate cells and triangulation +agg_cells =setup_agg_cells(aggregate_to_cells) +Ωbg_agg_cells=view(Ωbg,agg_cells) # ref_agg_cell_to_agg_cell_map: \hat{K} -> K -Ω=Triangulation(bgmodel) -Ωagg_cells=view(Ω,agg_cells) -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) - -# Generate an array that given the local ID of an "agg_cell" -# returns the ID of the aggregate to which it belongs -# (i.e., flattened version of aggregate_to_cells) -agg_cells_to_aggregate=Vector{Int}() -for (i,cells) in enumerate(aggregate_to_cells) - for _ in cells - push!(agg_cells_to_aggregate,i) - end -end - -# ref_agg_cell_to_ref_bb_map: \hat{K} -> K -> bb -> \hat{bb} -bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) -bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) -ref_agg_cell_to_ref_bb_map= - lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) - -# Compute LHS of L2 projection -degree=2*(order+1) -dΩagg_cells = Measure(Ωagg_cells,degree) -reffe =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) # We need a DG space to represent the L2 projection +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) +agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) +ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate) + +# Spaces on bounding boxes +reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) +Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection Pbb=TrialFESpace(Qbb) pbb=get_trial_fe_basis(Pbb) qbb=get_fe_basis(Qbb) - -reffe=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) +reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) Ubb=TrialFESpace(Vbb) ubb=get_trial_fe_basis(Ubb) vbb=get_fe_basis(Vbb) +# Numerical integration (Measures) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) -aggregate_to_local_cells=copy(aggregate_to_cells) -current_local_cell=1 -for (i,cells) in enumerate(aggregate_to_local_cells) - for j in 1:length(cells) - cells[j]=current_local_cell - current_local_cell+=1 - end -end - -function set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - # Change domain of ubb (trial) from Ωbb to Ωagg_cells - ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - # Compute contributions to LHS of L2 projection - agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) - - # Finally assemble LHS contributions - ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) - lazy_map(ass_lhs_map,aggregate_to_local_cells) -end - +# LHS of L2 projection on bounding boxes. +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, - dΩagg_cells, + dΩbg_agg_cells, pbb, qbb) u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, - dΩagg_cells, + dΩbg_agg_cells, ubb, - vbb) + vbb) -# Compute contributions to the RHS of the L2 projection -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) - map=cell_dof_ids.maps.value - @assert length(map.size)==1 - @assert blockid >= 1 - @assert blockid <= map.size[1] - cell_dof_ids.args[blockid] -end - -Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) -P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) - - -### BEGIN TESTING CODE -# This code is just for testing purposes, so I have commented it out -# It allows to evaluate the LHS of the L2 projection corresponding to a -# particular FE function, instead of a basis -# uhex=interpolate(uex,Ustd) -# agg_cells_lhs_contribs_uhex=get_array(∫(vbb_Ωagg_cells*uhex)dΩagg_cells) -# ass_lhs_map_uhex=AssembleLhsMap(agg_cells_lhs_contribs_uhex) -# lhs_uhex=lazy_map(ass_lhs_map_uhex,aggregate_to_local_cells) -### END TESTING CODE - -function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - agg_cells_local_dof_ids=copy(agg_cells_dof_ids) - current_cell=1 - for agg_cells in aggregate_to_agg_cells - g2l=Dict{Int32,Int32}() - current_local_dof=1 - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in keys(g2l)) - g2l[dof]=current_local_dof - agg_cells_local_dof_ids[current_cell][j]=current_local_dof - current_local_dof+=1 - else - agg_cells_local_dof_ids[current_cell][j]=g2l[dof] - end - end - current_cell+=1 - println(agg_cells_local_dof_ids) - end - end - agg_cells_local_dof_ids -end +# Selecting relevant global dofs ids of aggregate cells (from background mesh) +Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) +U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) +P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) +# Computing local (per aggregate) dof ids U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωagg_cell_dof_ids, aggregate_to_local_cells) + compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωagg_cell_dof_ids, aggregate_to_local_cells) - - -function set_up_h_U(aggregates_bounding_box_model, - agg_cells_to_aggregate, - Ωagg_cells) - degree = 0 # We are integrating a constant function - # Thus, degree=0 is enough for exact integration - Ωbb = Triangulation(aggregates_bounding_box_model) - dΩbb = Measure(Ωbb, degree) - h_U_array = get_array(∫(1.0)dΩbb) - h_U_array = lazy_map(Reindex(h_U_array), agg_cells_to_aggregate) - CellField(h_U_array, Ωagg_cells) -end - - -function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) - current_aggregate=1 - current_cell=1 - for agg_cells in aggregate_to_agg_cells - current_aggregate_dof_ids=Int[] - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in current_aggregate_dof_ids) - push!(current_aggregate_dof_ids, dof) - end - end - current_cell+=1 - end - aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids - current_aggregate+=1 - end - aggregate_dof_ids -end + compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) -function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.single_field -end -function _get_single_field_fe_basis(a) - a -end -function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) - true -end -function _is_multifield_fe_basis_component(a) - false -end -function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.nfields -end -function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.fieldid -end - -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) -""" -function interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωagg_cell_dof_ids, - agg_cells_local_dof_ids, - agg_cells_to_aggregate_dof_ids, - h_U, - γ) - - - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, - dΩagg_cells.quad.trian, - ReferenceDomain()) - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - dv_du_mat_contribs=get_array(∫(γ*(1.0/h_U*h_U)*dv⋅du)*dΩagg_cells) - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) - end - push!(w, dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, Ωagg_cell_dof_ids) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - - proj_dv_du_mat_contribs=get_array(∫(γ*(1.0/h_U*h_U)*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) - end - - push!(w, proj_dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, agg_cells_to_aggregate_dof_ids) - - w, r, c -end - -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) +# Compute global dofs ids per aggregate and reindex these +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) - -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) +# parameters γ = 10.0 # Interior bulk-penalty stabilization parameter - # (@amartinhuertas no idea what a reasonable value is) - -h_U = set_up_h_U(aggregates_bounding_box_model, agg_cells_to_aggregate, Ωagg_cells) +h_U = 1.0 + +########################################### +### STABILIZATION ON Ωagg\Troot ### +########################################### + +## (2) FIND THE INTERIOR CELLS +Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates +int_cells = Ω_agg_cells.parent.b.tface_to_mface + +## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS +root_cells = setup_root_cells(int_cells, int_nonagg_cells) +cut_cells = setup_cut_cells(agg_cells, root_cells) + +## (4) CUT CELLS AND MEASURE +Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) + +# (5) DOF IDS related to cut cells +Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) +U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) +P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) + +# (6) Defining cut_cells_to_aggregate_dof_ids +# aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) +aggregate_to_cut_cells = revised_setup_aggregate_to_cut_cells(aggregates, root_cells) +cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) + +# (7) Compute stabilization terms for u and p +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) -# Manually set up the arrays that collect_cell_matrix would return automatically -wp,rp,cp=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, - dΩagg_cells, + dΩbg_agg_cells, dq, # Test basis dp, # Trial basis (to project) qbb, # Bounding box space test basis p_lhs, - P_Ωagg_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, P_agg_cells_local_dof_ids, - P_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - -wu,ru,cu=interior_bulk_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) +#DIV stabilization part +wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basisr + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +## FULL stabilization terms: +wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, - dΩagg_cells, + dΩbg_agg_cells, dv, # Test basis du, # Trial basis (to project) vbb, # Bounding box space test basis u_lhs, - U_Ωagg_cell_dof_ids, + U_Ωbg_cut_cell_dof_ids, U_agg_cells_local_dof_ids, - U_agg_cells_to_aggregate_dof_ids, - h_U, - γ) + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) +wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + +# MIXED STAB TERMS +wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + dv) + +wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + du) + +########################################### +### VISUALIZATION ### +########################################### +# writevtk(Ωbg,"trian-bg") +# writevtk(Ωbg_cut_cells,"trian-bg-cut-cells") +# colors = color_aggregates(aggregates,bgmodel) +# writevtk(Ωbg,"trian-bg-with-coloured-aggregates", celldata=["aggregate"=>aggregates,"color"=>colors]) +# writevtk(Ωbg_agg_cells,"trian-bg-agg-cells") +# Ωbg_int_cells=view(Ωbg,int_cells) +# Ωbg_root_cells=view(Ωbg,root_cells) +# writevtk(Ωbg_int_cells,"trian-bg-int-cells") +# writevtk(Ωbg_root_cells,"trian-bg-root-cells") +# writevtk(Ω,"trian-phys") +# writevtk(Ωact,"trian-act") + +function compute_quantities(problem,A,b,dΩ) + cond_A = cond(Array(A)) + norm_A = norm(A) + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + if problem==1 + area = sum(∫(1.0)dΩ) + mean_p = sum(∫(pex)dΩ)/area # mean presure exact sol + ph = ph + mean_p + end + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + norm_euh = sum(∫(euh⋅euh)*dΩ) + norm_eph = sum(∫(eph*eph)*dΩ) + norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) + return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) +end -# Set up global projection matrix -Ωcut = Triangulation(cutdisk,PHYSICAL) -dΩcut = Measure(Ωcut,degree) -a((u,p),(v,q))=∫(v⋅u+q*p)dΩcut -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +function plot_quantities(problem,A,b,Ω;filename="results") + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + if problem==1 + area = sum(∫(1.0)dΩ) + mean_p = sum(∫(pex)dΩ)/area # mean presure exact sol + ph = ph_zm + mean_p + end + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) +end +## RHS STAB +# rhs_g = divuex # TODO: pass function on rather than constant value!!!!! +vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + divuex(1.0)) + +## WEAK FORM +if problem==0 + a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ + l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ +elseif problem==1 + ΓN = EmbeddedBoundary(cutgeo) + dΓN = Measure(ΓN,degree) + nN = get_normal_vector(ΓN) + s = -1 + β₀ = 1e3 + β = β₀*h.^(s) + m =1 + uNeu = uex + g = divuex + a((u,p), (v,q)) = ∫(v⋅u - (∇⋅v)*p - (∇⋅u)*q)dΩ + ∫(β*(u⋅nN)*(v⋅nN) + (v⋅nN)*p + m*(u⋅nN)*q)dΓN + l((v,q)) = ∫(- q*g)dΩ + ∫(β*(v⋅nN)*(uNeu⋅nN) + m*q*(uNeu⋅nN))dΓN +else + print("Problem not implemented. Try again with problem=0 (L2-like projection test) or problem=1 (Darcy test)") +end assem=SparseMatrixAssembler(X,Y) -Anostab=assemble_matrix(assem, wrc) -cond(Array(Anostab)) +b = assemble_vector(l, Y) -# Add the bulk penalty stabilization term to wrc -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) +#RHS_DMIX +vec_wr=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) +push!(vec_wr[1],vecw_dmix...) +push!(vec_wr[2],vecr_dmix...) +vec_b = assemble_vector(assem, vec_wr) +# NO STAB +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +A = assemble_matrix(assem, wrc) +res_nostab = compute_quantities(problem,A,b,dΩ) + +# ONLY U +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) push!(wrc[1], wu...) push!(wrc[2], ru...) push!(wrc[3], cu...) +A = assemble_matrix(assem, wrc) +res_stab_u = compute_quantities(problem,A,b,dΩ) -Awithstab=assemble_matrix(assem, wrc) -cond(Array(Awithstab)) - -# Set up rhs global projection -l((v,q))=∫(v⋅uex+q*pex)dΩcut -b = assemble_vector(l, Y) - -global_l2_proj_dofs = Awithstab\b -xh = FEFunction(X, global_l2_proj_dofs) -uh,ph = xh - -euh = uex-uh -@assert sum(∫(euh⋅euh)*dΩcut) < 1.0e-12 +# ONLY U FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufull = compute_quantities(problem,A,b,dΩ) -eph = pex-ph -@assert sum(∫(eph*eph)*dΩcut) < 1.0e-12 +# ONLY P +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +A = assemble_matrix(assem, wrc) +res_stab_p = compute_quantities(problem,A,b,dΩ) +# ONLY PFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +A = assemble_matrix(assem, wrc) +res_stab_pfull = compute_quantities(problem,A,b,dΩ) -# Piece of code to generate the divergence of the -# velocity space basis in the pressure space in the -# same format as returned by dv and du +# ONLY DIV +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_div = compute_quantities(problem,A,b,dΩ) -div_dv=∇⋅(_get_single_field_fe_basis(dv)) -pdofs=Gridap.FESpaces.get_fe_dof_basis(P) -div_dv_pdofs_values=pdofs(div_dv) -div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_pdofs_values, - Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) +# ONLY DIVU FULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_divfull = compute_quantities(problem,A,b,dΩ) -div_dv_in_pressure_space= - Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, - get_triangulation(P), - Gridap.FESpaces.TestBasis(), - Gridap.CellData.ReferenceDomain()) +# ONLY PMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +A = assemble_matrix(assem, wrc) +res_stab_pmix = compute_quantities(problem,A,b,dΩ) -div_dv_in_pressure_space= - Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space,1,2) +# ONLY DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_dmix = compute_quantities(problem,A,vec_b,dΩ) -div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) +# U + P + DIVU +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wp...) +push!(wrc[2], rp...) +push!(wrc[3], cp...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +A = assemble_matrix(assem, wrc) +res_stab_updivu = compute_quantities(problem,A,b,dΩ) -div_du_in_pressure_space=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, - get_triangulation(P), - Gridap.FESpaces.TrialBasis(), - Gridap.CellData.ReferenceDomain()) -div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space,1,2) \ No newline at end of file +# UFULL + PFULL + DIVUFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) +push!(wrc[1], wp_full...) +push!(wrc[2], rp_full...) +push!(wrc[3], cp_full...) +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +A = assemble_matrix(assem, wrc) +res_stab_ufullpfulldivufull = compute_quantities(problem,A,b,dΩ) + +# U + DIVU + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu...) +push!(wrc[2], ru...) +push!(wrc[3], cu...) +push!(wrc[1], wdiv...) +push!(wrc[2], rdiv...) +push!(wrc[3], cdiv...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_udivupmixdmix = compute_quantities(problem,A,vec_b,dΩ) + +# UFULL + DIVUFULL + PMIX + DMIX +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], wu_full...) +push!(wrc[2], ru_full...) +push!(wrc[3], cu_full...) + +push!(wrc[1], wdiv_full...) +push!(wrc[2], rdiv_full...) +push!(wrc[3], cdiv_full...) +push!(wrc[1], wpmix...) +push!(wrc[2], rpmix...) +push!(wrc[3], cpmix...) +push!(wrc[1], wdmix...) +push!(wrc[2], rdmix...) +push!(wrc[3], cdmix...) +A = assemble_matrix(assem, wrc) +res_stab_ufulldivufullpmixdmix = compute_quantities(problem,A,vec_b,dΩ) + +## PRINT DATA: +print("results") +res_nostab +res_stab_u +res_stab_ufull +res_stab_p +res_stab_pfull +res_stab_div +res_stab_divfull +res_stab_pmix +res_stab_dmix +print("") +res_stab_updivu +res_stab_ufullpfulldivufull +res_stab_udivupmixdmix +res_stab_ufulldivufullpmixdmix \ No newline at end of file diff --git a/bulk_ghost_penalty_canvas_div.jl b/bulk_ghost_penalty_canvas_div.jl deleted file mode 100644 index 4565484c..00000000 --- a/bulk_ghost_penalty_canvas_div.jl +++ /dev/null @@ -1,257 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("aggregates_bounding_boxes_tools.jl") -include("bulk_ghost_penalty_stab_tools.jl") -include("fields_and_blocks_tools.jl") -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 2 -uex(x) = -VectorValue(2*x[1],2*x[2]) -pex(x) = (x[1]^2 + x[2]^2) -divuex(x) = -4.0 - -# Select geometry -R = 0.2 -geom = disk(R, x0=Point(0.5,0.5)) - -# Setup background model -n=10 -partition = (n,n) -box = get_metadata(geom) -bgmodel = CartesianDiscreteModel((0,1,0,1),partition) -dp = box.pmax - box.pmin -h = dp[1]/n - -# Cut the background model with the mesh -cutdisk = cut(bgmodel,geom) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutdisk) - - -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# colors = color_aggregates(aggregates,bgmodel) -# writevtk(Triangulation(bgmodel),"trian",celldata=["cellin"=>aggregates,"color"=>colors]) -# writevtk(aggregates_bounding_box_model, "bb_model") -# writevtk(bgmodel, "bg_model") - -# Set up objects required to compute both LHS and RHS of the L2 projection - -# Set up global spaces -Ωhact = Triangulation(cutdisk,ACTIVE) - -V = FESpace(Ωhact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -Q = FESpace(Ωhact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -U = TrialFESpace(V) -P = TrialFESpace(Q) -Y = MultiFieldFESpace([V, Q]) -X = MultiFieldFESpace([U, P]) - -agg_cells=setup_agg_cells(aggregate_to_cells) - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -Ω=Triangulation(bgmodel) -Ωagg_cells=view(Ω,agg_cells) -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωagg_cells) - -agg_cells_to_aggregate=setup_agg_cells_to_aggregate(aggregate_to_cells) - -ref_agg_cell_to_ref_bb_map=setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, - agg_cells_to_aggregate) - -# Compute LHS of L2 projection -degree=2*(order+1) -dΩagg_cells = Measure(Ωagg_cells,degree) -reffe =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) - -reffe=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffe,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - -aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) - -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) - -# Compute contributions to the RHS of the L2 projection -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -Ωagg_cell_dof_ids = get_cell_dof_ids(X,Ωagg_cells) -U_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 1) -P_Ωagg_cell_dof_ids = _restrict_to_block(Ωagg_cell_dof_ids, 2) -# Ωagg_cell_dof_ids[1][1] # cell 1, velo dof -# Ωagg_cell_dof_ids[1][2] # cell 1, pressure dofs - -### BEGIN TESTING CODE -# This code is just for testing purposes, so I have commented it out -# It allows to evaluate the LHS of the L2 projection corresponding to a -# particular FE function, instead of a basis -# uhex=interpolate(uex,Ustd) -# agg_cells_lhs_contribs_uhex=get_array(∫(vbb_Ωagg_cells*uhex)dΩagg_cells) -# ass_lhs_map_uhex=AssembleLhsMap(agg_cells_lhs_contribs_uhex) -# lhs_uhex=lazy_map(ass_lhs_map_uhex,aggregate_to_local_cells) -### END TESTING CODE - - -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωagg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωagg_cell_dof_ids, aggregate_to_local_cells) - - -function set_up_h_U(aggregates_bounding_box_model, - agg_cells_to_aggregate, - Ωagg_cells) - degree = 0 # We are integrating a constant function - # Thus, degree=0 is enough for exact integration - Ωbb = Triangulation(aggregates_bounding_box_model) - dΩbb = Measure(Ωbb, degree) - h_U_array = get_array(∫(1.0)dΩbb) - h_U_array = lazy_map(Reindex(h_U_array), agg_cells_to_aggregate) - CellField(h_U_array, Ωagg_cells) -end - -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωagg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) - -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωagg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) - -γ = 10.0 # Interior bulk-penalty stabilization parameter - # (@amartinhuertas no idea what a reasonable value is) - -h_U = set_up_h_U(aggregates_bounding_box_model, agg_cells_to_aggregate, Ωagg_cells) - -# Manually set up the arrays that collect_cell_matrix would return automatically -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωagg_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωagg_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - -wdivu,rdivu,cdivu=div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωagg_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - -Ωcut = Triangulation(cutdisk,PHYSICAL) -dΩcut = Measure(Ωcut,degree) - - -## TEST 1 -a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩcut -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) - -assem=SparseMatrixAssembler(X,Y) -Anostab=assemble_matrix(assem, wrc) -cond_nostab = cond(Array(Anostab)) - -# Set up rhs global projection -l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩcut -b = assemble_vector(l, Y) - -## U + P STABILIZATION -# Add the bulk penalty stabilization terms for u and p to wrc -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) - -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) - -# Check the condition number when only the p and u stabilization terms are included. -Aupstab=assemble_matrix(assem, wrc) -cond_upstab = cond(Array(Aupstab)) - -# CHECK errors when only the p and u stabilization terms are included. -global_l2_proj_dofs_upstab = Aupstab\b -xh_upstab = FEFunction(X, global_l2_proj_dofs_upstab) -uh_upstab,ph_upstab = xh_upstab -euh_upstab = uex-uh_upstab -eph_upstab = pex-ph_upstab -edivuh_upstab = divuex-(∇⋅uh_upstab) -norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩcut) -norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩcut) -norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩcut) -# No stabilization (k=0) κ = 1.1e35 vs (k=2) κ = Inf -# k=0 (n=10) yields euh = 3.0e-28, eph = 0.00055, edivuh = 1.3e-30, κ = 1.4e5 -# k=2 (n=10) yields euh = 1.8e-18, eph = 1.7e-28, edivuh = 7.4e-21, κ= 1.7e13 - -## Now add div stabilization to A -push!(wrc[1], wdivu...) -push!(wrc[2], rdivu...) -push!(wrc[3], cdivu...) - -# Assembly -Awithstab=assemble_matrix(assem, wrc) -cond_withstab = cond(Array(Awithstab)) - -global_l2_proj_dofs_withstab = Awithstab\b -xh_withstab = FEFunction(X, global_l2_proj_dofs_withstab) -uh_withstab,ph_withstab = xh_withstab -euh_withstab = uex-uh_withstab -eph_withstab = pex-ph_withstab -edivuh_withstab = divuex-(∇⋅uh_withstab) -norm_euh_withstab = sum(∫(euh_withstab⋅euh_withstab)*dΩcut) -norm_eph_withstab = sum(∫(eph_withstab*eph_withstab)*dΩcut) -norm_edivuh_withstab = sum(∫(edivuh_withstab⋅edivuh_withstab)*dΩcut) -# k=0 (n=10) yields euh = 1.2e-26, eph = 0.00055, edivuh = 7.0e-29, κ = 1.7e6 -# k=2 (n=10) yields euh = 1.6e-15, eph = 1.7e-28, edivuh = 7.1e-19, κ= 1.8e14 \ No newline at end of file diff --git a/bulk_ghost_penalty_canvas_div_on_cut_cells _exploration_full-terms.jl b/bulk_ghost_penalty_canvas_div_on_cut_cells _exploration_full-terms.jl deleted file mode 100644 index 8c4f892f..00000000 --- a/bulk_ghost_penalty_canvas_div_on_cut_cells _exploration_full-terms.jl +++ /dev/null @@ -1,543 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("aggregates_bounding_boxes_tools.jl") -include("bulk_ghost_penalty_stab_tools.jl") -include("fields_and_blocks_tools.jl") -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 0 -uex(x) = -VectorValue(2*x[1],2*x[2]) -pex(x) = (x[1]^2 + x[2]^2) -divuex(x) = -4.0 - -# Select geometry -R = 0.2 -geom = disk(R, x0=Point(0.5,0.5)) - -# Setup background model -n=16 -partition = (n,n) -box = get_metadata(geom) -bgmodel = CartesianDiscreteModel((0,1,0,1),partition) -dp = box.pmax - box.pmin -h = dp[1]/n - -# Cut the background model with the mesh -cutgeo = cut(bgmodel,geom) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# Triangulations -Ωbg = Triangulation(bgmodel) -Ωact = Triangulation(cutgeo,ACTIVE) - -# Physical domain -Ω = Triangulation(cutgeo,PHYSICAL) -degree=2*(order+1) -dΩ = Measure(Ω,degree) - -# Set up global spaces -V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -U = TrialFESpace(V) -P = TrialFESpace(Q) -Y = MultiFieldFESpace([V, Q]) -X = MultiFieldFESpace([U, P]) -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -# Aggregate cells and triangulation -agg_cells =setup_agg_cells(aggregate_to_cells) -Ωbg_agg_cells=view(Ωbg,agg_cells) - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) -agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) -ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, - agg_cells_to_aggregate) - -# Spaces on bounding boxes -reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) -reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - -# Numerical integration (Measures) -degree=2*(order+1) -dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) - -# LHS of L2 projection on bounding boxes. -aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - ubb, - vbb) - -# Selecting relevant global dofs ids of aggregate cells (from background mesh) -Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) -U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) -P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) - -# Computing local (per aggregate) dof ids -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) - -# Compute global dofs ids per aggregate and reindex these -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) -P_Ωbg_agg_cell_dof_ids - -# parameters -γ = 10.0 # Interior bulk-penalty stabilization parameter -h_U = 1.0 - -########################################### -### STABILIZATION ON Ωagg\Troot ### -########################################### - -## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) - -## (2) FIND THE INTERIOR CELLS -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface - -## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS -root_cells = setup_root_cells(int_cells, int_nonagg_cells) -cut_cells = setup_cut_cells(agg_cells, root_cells) - -## (4) CUT CELLS AND MEASURE -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) -dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) - -# (5) DOF IDS related to cut cells -Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) -U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) -P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) - -# (6) Defining cut_cells_to_aggregate_dof_ids -aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) -cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) -U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) -P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) - -# (7) Compute stabilization terms for u and p -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -#DIV stabilization part -wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -## FULL stabilization terms: -wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis -# (k=0,n=16) 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -## TEST WITH MANUFACTURED SOLUTIONS -a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ -# wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -assem=SparseMatrixAssembler(X,Y) -l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ -b = assemble_vector(l, Y) - -function compute_quantities(A,b,dΩ) - cond_A = cond(Array(A)) - norm_A = norm(A) - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - norm_euh = sum(∫(euh⋅euh)*dΩ) - norm_eph = sum(∫(eph*eph)*dΩ) - norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) - return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) -end - -############## (k=0,n=16) ##################################################################### -# (k=0,n=16) 2.31e9, 6040.0, 1.20e-27, 7.71e-5, 1.77e-30 # -- NO STAB -- -# (k=0,n=16) 3.58e8, 6040.0, 2.0 e-28, 7.71e-5, 1.93e-30 # U -# (k=0,n=16) 3.58e8, 6050.0, 1.67e-27, 7.71e-5, 4.26e-30 # U_FULL -# (k=0,n=16) 7.59e6, 55500.0, 1.64e-26, 1.46e-4, 4.20e-29 # U + P + DIVU -# (k=0,n=16) 7.59e6, 55500.0, 6.17e-26, 1.45e-4, 9.62e-29 # U_FULL + P + DIVU -# (k=0,n=16) 7.64e6, 54500.0, 8.79e-26, 1.46e-4, 1.98e-28 # U_FULL + P + DIVU_FULL (*) -# (k=0,n=16) 1.28e7, 55500.0, 1.64e-26, 1.16e-4, 4.20e-29 # U + P_FULL + DIVU -# (k=0,n=16) 1.28e7, 55500.0, 6.17e-26, 1.16e-4, 9.62e-29 # U_FULL + P_FULL + DIVU -# (k=0,n=16) 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL -# (k=0,n=16) 7.64e6, 54500.0, 2.75e-26, 1.46e-4, 1.14e-28 # U + P + DIVU_FULL (*) -############################################################################################### - -############## (k=2,n=16) ##################################################################### -# (k=0,n=16) 2.82e29, 9.21e8, 4.0e-12, 7.79e-28, 2.34e-13 # -- NO STAB -- -# (k=0,n=16) 2.82e29, 9.21e8, 2.05e-18, 7.79e-28, 1.66e-19 # U -# (k=0,n=16) 2.82e29, 9.21e8, 1.23e-16, 7.79e-28, 1.39e-18 # U_FULL -# (k=0,n=16) 4.72e16, 9.45e9, 3.08e-14, 4.07e-29, 1.76e-17 # U + P + DIVU -# (k=0,n=16) 4.72e16, 9.45e9, 2.52e-11, 4.07e-29, 3.17e-16 # U_FULL + P + DIVU -# (k=0,n=16) 3.00e18, 9.45e9, 3.08e-14, 1.65e-28, 1.76e-17 # U + P_FULL + DIVU -# (k=0,n=16) 3.00e18, 9.45e9, 2.52e-11, 1.65e-28, 3.17e-16 # U_FULL + P_FULL + DIVU -############################################################################################### - -# CONCLUSION (k=0): lowest κ for stab u, p and divu. For u it does not matter whether it is full or not full. P__full would increase the order of κ by 1. -# (*)NOTE THAT U(_FUL)L + P + DIVU_FULL does not outperform U(_FULL) + P + DIVU, with κ=7.64e6 and κ=7.59e6, respectively. - -res_nostab -res_stab_u -res_stab_ufull -res_stab_updivu -res_stab_ufullpdivu -res_stab_ufullpdivufull -res_stab_upfulldivu -res_stab_ufullpfulldivu - -# NO STAB -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -A = assemble_matrix(assem, wrc) -res_nostab = compute_quantities(A,b,dΩ) -# (k=0,n=16) 2.31e9, 6040.0, 1.20e-27, 7.71e-5, 1.77e-30 # NO STAB - -# ONLY U -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -A = assemble_matrix(assem, wrc) -res_stab_u = compute_quantities(A,b,dΩ) -# (k=0,n=16) 3.58e8, 6040.0, 2.0 e-28, 7.71e-5, 1.93e-30 # STAB U - -# ONLY U FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufull = compute_quantities(A,b,dΩ) -# (k=0,n=16) 3.58e8, 6050.0, 1.67e-27, 7.71e-5, 4.26e-30 # STAB U_FULL - -# U + P + DIVU -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_updivu = compute_quantities(A,b,dΩ) -# (k=0,n=16) 7.59e6, 55500.0, 1.64e-26, 1.46e-4, 4.20e-29 # U + P + DIVU - -# U_FULL + P + DIVU -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_ufullpdivu = compute_quantities(A,b,dΩ) -# (k=0,n=16) 7.59e6, 55500.0, 6.17e-26, 1.45e-4, 9.62e-29 # U_FULL + P + DIVU - -# U_FULL + P + DIVU_FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufullpdivufull = compute_quantities(A,b,dΩ) -# (k=0,n=16) 7.64e6, 54500.0, 8.79e-26, 1.46e-4, 1.98e-28 # U_FULL + P + DIVU_FULL - -# U + P_FULL + DIVU -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_upfulldivu = compute_quantities(A,b,dΩ) -# (k=0,n=16) 1.28e7, 55500.0, 1.64e-26, 1.16e-4, 4.20e-29 # U + P_FULL + DIVU - -# U_FULL + P_FULL + DIVU -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -A = assemble_matrix(assem, wrc) -res_stab_ufullpfulldivu = compute_quantities(A,b,dΩ) -# (k=0,n=16) 1.28e7, 55500.0, 6.17e-26, 1.16e-4, 9.62e-29 # U_FULL + P_FULL + DIVU - -# U_FULL + P_FULL + DIVU_FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_ufullpfulldivufull = compute_quantities(A,b,dΩ) -# (k=0,n=16) 1.29e7, 54500.0, 8.79e-26, 1.16e-4, 1.98e-28 # U_FULL + P_FULL + DIVU_FULL - -# U + P + DIVU_FULL -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -A = assemble_matrix(assem, wrc) -res_stab_updivufull = compute_quantities(A,b,dΩ) -# (k=0,n=16) 7.64e6, 54500.0, 2.75e-26, 1.46e-4, 1.14e-28 # U + P + DIVU_FULL - - - -## Create collect function on cut cells only -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv-div_dv_l2_proj_agg_cells)*(div_du-div_du_l2_proj_agg_cells))*dΩ_cut_cells -""" -function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## (I) Compute projections div_dv_l2_proj_agg_cells & div_du_l2_proj_agg_cells - - div_du=∇⋅(_get_single_field_fe_basis(du)) - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) - div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(du) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(dv) - div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) - end - - if (_is_multifield_fe_basis_component(dv)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - div_dv_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - div_dv_l2_proj_bb_array_agg_cells) - end - - div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - div_dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_dv_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - - # # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) - end - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - ## (1) div_dv*div_du term - div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) - push!(w, div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - ## (2) div_dv*proj_div_du term - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, U_cut_cells_to_aggregate_dof_ids) - - ## (3) proj_div_dv*proj_div_du - proj_div_dv_proj_div_du_mat_contribs=get_array(∫(γ*div_dv_l2_proj_agg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, proj_div_dv_proj_div_du_mat_contribs) - push!(r, U_cut_cells_to_aggregate_dof_ids) - push!(c, U_cut_cells_to_aggregate_dof_ids) - - ## (4) proj_div_dv*div_du - div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) - proj_div_dv_div_du_mat_contribs=get_array(∫(-γ*div_dv_l2_proj_agg_cells⋅div_du_Ωagg_cells)*dΩbg_cut_cells) - - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_cut_cells_to_aggregate_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - w, r, c -end - -wdiv_full, rdiv_full, cdiv_full= div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) diff --git a/bulk_ghost_penalty_canvas_div_on_cut_cells.jl b/bulk_ghost_penalty_canvas_div_on_cut_cells.jl deleted file mode 100644 index 66872cd0..00000000 --- a/bulk_ghost_penalty_canvas_div_on_cut_cells.jl +++ /dev/null @@ -1,248 +0,0 @@ -using Gridap -using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("aggregates_bounding_boxes_tools.jl") -include("bulk_ghost_penalty_stab_tools.jl") -include("fields_and_blocks_tools.jl") -include("BulkGhostPenaltyAssembleMaps.jl") - -# Manufactured solution -order = 0 -uex(x) = -VectorValue(2*x[1],2*x[2]) -pex(x) = (x[1]^2 + x[2]^2) -divuex(x) = -4.0 - -# Select geometry -R = 0.2 -geom = disk(R, x0=Point(0.5,0.5)) - -# Setup background model -n=16 -partition = (n,n) -box = get_metadata(geom) -bgmodel = CartesianDiscreteModel((0,1,0,1),partition) -dp = box.pmax - box.pmin -h = dp[1]/n - -# Cut the background model with the mesh -cutgeo = cut(bgmodel,geom) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) - -aggregate_to_cells=setup_aggregate_to_cells(aggregates) -aggregates_bounding_box_model= - setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) - -# Triangulations -Ωbg = Triangulation(bgmodel) -Ωact = Triangulation(cutgeo,ACTIVE) - -# Physical domain -Ω = Triangulation(cutgeo,PHYSICAL) -degree=2*(order+1) -dΩ = Measure(Ω,degree) - -# Set up global spaces -V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) -Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) -U = TrialFESpace(V) -P = TrialFESpace(Q) -Y = MultiFieldFESpace([V, Q]) -X = MultiFieldFESpace([U, P]) -dx = get_trial_fe_basis(X) -dy = get_fe_basis(Y) -du,dp = dx -dv,dq = dy - -# Aggregate cells and triangulation -agg_cells =setup_agg_cells(aggregate_to_cells) -Ωbg_agg_cells=view(Ωbg,agg_cells) - -# ref_agg_cell_to_agg_cell_map: \hat{K} -> K -ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) -agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) -ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, - agg_cells_to_aggregate) - -# Spaces on bounding boxes -reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) # Here we MUST use a Q space (not a P space!) -Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection -Pbb=TrialFESpace(Qbb) -pbb=get_trial_fe_basis(Pbb) -qbb=get_fe_basis(Qbb) -reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) -Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) -Ubb=TrialFESpace(Vbb) -ubb=get_trial_fe_basis(Ubb) -vbb=get_fe_basis(Vbb) - -# Numerical integration (Measures) -degree=2*(order+1) -dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) - -# LHS of L2 projection on bounding boxes. -aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - ubb, - vbb) - -# Selecting relevant global dofs ids of aggregate cells (from background mesh) -Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) -U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) -P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) - -# Computing local (per aggregate) dof ids -U_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) -P_agg_cells_local_dof_ids= - compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) - -# Compute global dofs ids per aggregate and reindex these -U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) -P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) -P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) -P_Ωbg_agg_cell_dof_ids - -# parameters -γ = 10.0 # Interior bulk-penalty stabilization parameter -h_U = 1.0 - -########################################### -### STABILIZATION ON Ωagg\Troot ### -########################################### - -## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) - -## (2) FIND THE INTERIOR CELLS -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface - -## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS -root_cells = setup_root_cells(int_cells, int_nonagg_cells) -cut_cells = setup_cut_cells(agg_cells, root_cells) - -## (4) CUT CELLS AND MEASURE -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) -dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) - -# (5) DOF IDS related to cut cells -Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) -U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) -P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) - -# (6) Defining cut_cells_to_aggregate_dof_ids -aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) -cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) -U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) -P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) - -# (7) Compute stabilization terms for u and p -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -## TEST WITH MANUFACTURED SOLUTIONS -a((u,p),(v,q))=∫(v⋅u+q*p+(∇⋅u)*(∇⋅v))dΩ -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -assem=SparseMatrixAssembler(X,Y) -A_nostab = assemble_matrix(assem, wrc) -l((v,q))=∫(v⋅uex+q*pex+(∇⋅v)*divuex)dΩ -b = assemble_vector(l, Y) - -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) - -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) - -A_stabup = assemble_matrix(assem, wrc) -cond_nostab = cond(Array(A_nostab)) -cond_stabup = cond(Array(A_stabup)) - -# CHECK errors when only the p and u stabilization terms are included. -global_l2_proj_dofs_upstab = A_stabup\b -xh_upstab = FEFunction(X, global_l2_proj_dofs_upstab) -uh_upstab,ph_upstab = xh_upstab -euh_upstab = uex-uh_upstab -eph_upstab = pex-ph_upstab -edivuh_upstab = divuex-(∇⋅uh_upstab) -norm_euh_upstab = sum(∫(euh_upstab⋅euh_upstab)*dΩ) -norm_eph_upstab = sum(∫(eph_upstab*eph_upstab)*dΩ) -norm_edivuh_upstab = sum(∫(edivuh_upstab⋅edivuh_upstab)*dΩ) -# No stabilization (n=16) (k=0) κ = 2.3e9 vs (k=2) κ = 2.8e29 -# k=0 (n=16) yields euh = 2.0e-28, eph = 0.00015, edivuh = 1.9e-30, κ = 9.2e5 -# k=2 (n=16) yields euh = 2.0e-18, eph = 4.0e-29, edivuh = 1.7e-19, κ = 4.4e15 - -#DIV stabilization part -wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) - -A_stab = assemble_matrix(assem, wrc) -cond_stab = cond(Array(A_stab)) - -global_l2_proj_dofs_stab = A_stab\b -xh_stab = FEFunction(X, global_l2_proj_dofs_stab) -uh_stab,ph_stab = xh_stab -euh_stab = uex-uh_stab -eph_stab = pex-ph_stab -edivuh_stab = divuex-(∇⋅uh_stab) -norm_euh_stab = sum(∫(euh_stab⋅euh_stab)*dΩ) -norm_eph_stab = sum(∫(eph_stab*eph_stab)*dΩ) -norm_edivuh_stab = sum(∫(edivuh_stab⋅edivuh_stab)*dΩ) -# k=0 (n=16) yields euh = 1.6e-26, eph = 0.00015, edivuh = 4.2e-29, κ = 7.6e6 -# k=2 (n=16) yields euh = 3.1e-14, eph = 4.1e-29, edivuh = 1.8e-17, κ = 4.7e16 \ No newline at end of file From 6d65126db903f59316862668b89552609ebb3463 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Wed, 29 Jan 2025 13:42:57 +1100 Subject: [PATCH 057/120] revised parenthesis so that rhs_g_func can be correctly passed and used as function when collecting the dmix stabilization terms --- bulk_ghost_penalty_canvas.jl | 11 +++++------ bulk_ghost_penalty_stab_tools.jl | 23 +++-------------------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 7b489f4c..c228eaa8 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -12,7 +12,7 @@ include("BulkGhostPenaltyAssembleMaps.jl") problem = 1 # 0 = Manufactured solution (L2-like projection), 1 = Darcy problem # Manufactured solution -order = 2 +order = 0 uex(x) = -VectorValue(2*x[1],2*x[2]) pex(x) = (x[1]^2 + x[2]^2) divuex(x) = -4.0 @@ -20,9 +20,9 @@ divuex(x) = -4.0 # Select geometry nint = 3 # number of (uncut) interior elements along single direction # cut length -ε = 0.2/2.0 # not so small cut (nint = 3) -# ε = 0.2e-2/2.0 # smaller cut (nint = 3) -# ε = 0.2e-6/2.0 # smallest cut (nint = 3) +ε = 0.2/2.0 # not so small cut +# ε = 0.2e-2/2.0 # smaller cut +# ε = 0.2e-6/2.0 # smallest cut pmin = Point(0.0,0.0) pmax = Point(1.0,1.0) function setup_geometry(nint, ε, pmin, pmax) @@ -372,7 +372,7 @@ vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cel P_cut_cells_to_aggregate_dof_ids, γ, dΩbg_cut_cells, - divuex(1.0)) + divuex) ## WEAK FORM if problem==0 @@ -521,7 +521,6 @@ wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) push!(wrc[1], wu_full...) push!(wrc[2], ru_full...) push!(wrc[3], cu_full...) - push!(wrc[1], wdiv_full...) push!(wrc[2], rdiv_full...) push!(wrc[3], cdiv_full...) diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl index 28c076c4..31057e07 100644 --- a/bulk_ghost_penalty_stab_tools.jl +++ b/bulk_ghost_penalty_stab_tools.jl @@ -983,7 +983,7 @@ function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_t Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells + ## Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells # Change domain of qbb (test) from Ωbb to Ωagg_cells dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, ref_agg_cell_to_ref_bb_map, @@ -1011,18 +1011,6 @@ function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_t lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) - # dp_l2_proj_bb_array_agg_cells=lazy_map(transpose, dq_l2_proj_bb_array_agg_cells) - - # if (_is_multifield_fe_basis_component(dp)) - # @assert _is_multifield_fe_basis_component(dq) - # @assert _nfields(dp)==_nfields(dq) - # nfields=_nfields(dp) - # fieldid=_fieldid(dp) - # dp_l2_proj_bb_array_agg_cells=lazy_map( - # Gridap.Fields.BlockMap((1,nfields),fieldid), - # dp_l2_proj_bb_array_agg_cells) - # end - if (_is_multifield_fe_basis_component(dq)) @assert _is_multifield_fe_basis_component(dq) @assert _nfields(dp)==_nfields(dq) @@ -1033,7 +1021,6 @@ function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_t dq_l2_proj_bb_array_agg_cells) end - # dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) # BlockMap preparatory steps for the dof ids @@ -1055,17 +1042,13 @@ function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_t r = [] ## (1) rhs_g*dq term - # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) - #TODO: γ*(rhs_g_func) does not work - rhs_g_dp_mat_contribs=get_array(∫((rhs_g_func)⋅dq*γ)*dΩbg_cut_cells) + rhs_g_dp_mat_contribs=get_array(∫((rhs_g_func⋅dq)*γ)*dΩbg_cut_cells) push!(w, rhs_g_dp_mat_contribs) push!(r, P_Ωbg_cut_cell_dof_ids) # (2) div_du*proj_dq term - rhs_g_proj_dp_mat_contribs=get_array(∫((rhs_g_func)⋅(dq_l2_proj_agg_cells)*γ*(-1.0))*dΩbg_cut_cells) - # # rhs_g_proj_dp_mat_contribs=get_array(∫((dq_l2_proj_agg_cells)*γ*(-1.0))*dΩbg_cut_cells) + rhs_g_proj_dp_mat_contribs=get_array(∫((rhs_g_func⋅dq_l2_proj_agg_cells)*γ*(-1.0))*dΩbg_cut_cells) push!(w, rhs_g_proj_dp_mat_contribs) push!(r, P_cut_cells_to_aggregate_dof_ids) From 7cb90987d096a332265b828e0a78a1332dda266b Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 31 Jan 2025 10:42:07 +1100 Subject: [PATCH 058/120] revised and merged functions that allow for selection of (aggregated) cells, e.g. cut,interior, exterior. --- aggregates_bounding_boxes_tools.jl | 255 +++++------------------------ bulk_ghost_penalty_canvas.jl | 58 +++---- 2 files changed, 60 insertions(+), 253 deletions(-) diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl index 9bbccd89..9e854750 100644 --- a/aggregates_bounding_boxes_tools.jl +++ b/aggregates_bounding_boxes_tools.jl @@ -39,136 +39,47 @@ function setup_aggregate_to_cells(aggregates) end """ - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains the global cell IDs of that cut cells in - the background model that belong to the same aggregate + Creates an array containing the cell IDs of a selection of the background cells. The cell type filter IN (-1) selects the interior cells, OUT (1) the exterior cells, and GridapEmbedded.Interfaces.CUT (0) the cut cells. + TO-DO: publish CUT, so that GridapEmbedded.Interfaces.CUT can be shortened to CUT? + TO-DO: be careful with using restrict_cells(cutgeo,GridapEmbedded.Interfaces.CUT) to replace flatten(restrict_aggregate_to_cells(cutgeo,aggregate_to_cells,GridapEmbedded.Interfaces.CUT)) - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. """ -function setup_aggregate_to_cut_cells(aggregates, root_cells) - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cut_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]>1) && i ∉ root_cells - if !haskey(touched,agg) - push!(aggregate_to_cut_cells,[i]) - touched[agg]=current_aggregate - current_aggregate+=1 - else - push!(aggregate_to_cut_cells[touched[agg]],i) - end - end - end +function restrict_cells(cutgeo,cell_type_filter) + restricted_cells=Int64[] + cell_to_inoutcut=compute_bgcell_to_inoutcut(cutgeo,cutgeo.geo) + for cell in 1:length(cell_to_inoutcut) + if cell_to_inoutcut[cell] == cell_type_filter + push!(restricted_cells, cell) end - aggregate_to_cut_cells -end + end + restricted_cells +end """ Creates an array of arrays with as many entries as aggregates. For each aggregate, the array - contains the global cell IDs of that cut cells in - the background model that belong to the same aggregate - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function revised_setup_aggregate_to_cut_cells(aggregates, root_cells) - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cut_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - # println("i=$i, agg=$agg") - if agg>0 - if (size_aggregates[agg]>1) - if !haskey(touched,agg) - if i ∉ root_cells - push!(aggregate_to_cut_cells,[i]) - else - push!(aggregate_to_cut_cells,[]) - end - touched[agg]=current_aggregate - current_aggregate+=1 - else - if i ∉ root_cells - push!(aggregate_to_cut_cells[touched[agg]],i) - end - end - end - end - # println("touched = $touched") - # println("current agg = $current_aggregate, $aggregate_to_cut_cells") - end - aggregate_to_cut_cells -end - - -""" - Creates an array of arrays with as many entries - as interior cells that are not part of any aggegrate. - For each interior cell, the array - contains the global cell IDs of that cells in the background - model that belong to the same interior cell - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. + contains a selection of the global cell IDs of + the cells in the background model that belong to + the same aggregate. The cell type filter IN (-1) + selects the interior cells, OUT (1) the exterior + cells, and GridapEmbedded.Interfaces.CUT (0) the + cut cells. + TO-DO: publish CUT, so that GridapEmbedded.Interfaces.CUT can be shortened to CUT? """ -function setup_int_nonagg_cell_to_cells(aggregates) - - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 +function restrict_aggregate_to_cells(cutgeo,aggregate_to_cells,cell_type_filter) + aggregate_to_restricted_cells=Vector{Int}[] + cell_to_inoutcut=compute_bgcell_to_inoutcut(cutgeo,cutgeo.geo) + for agg in aggregate_to_cells + restricted_cells = Int64[] + for cell in agg + if cell_to_inoutcut[cell] == cell_type_filter + push!(restricted_cells, cell) end end - end - - touched=Dict{Int,Int}() - interior_cell_to_cells=Vector{Vector{Int}}() - current_interior_cell=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]==1) - if !haskey(touched,agg) - push!(interior_cell_to_cells,[i]) - touched[agg]=current_interior_cell - current_interior_cell+=1 - else - push!(interior_cell_to_cells[touched[agg]],i) - end - end - end + push!(aggregate_to_restricted_cells,restricted_cells) end - interior_cell_to_cells -end + aggregate_to_restricted_cells +end function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) g=get_grid(bgmodel) @@ -218,83 +129,11 @@ function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) end """ - Generate an array with the global IDs of the cells - that belong to an aggregrate. From now on, we will - use the terminology "agg_cells" to refer to those - cells of the background model that belong to an aggregate - (i.e., they can be either cut or interior cells) - - TO-DO: perhaps merge this function with setup_int_nonagg_cells -""" -function setup_agg_cells(aggregate_to_cells) - agg_cells=Vector{Int}() - for cells in aggregate_to_cells - append!(agg_cells,cells) - end - return agg_cells -end - -""" - Generate an array with the global IDs of the cells - that belong to the interior, yet do not belong to the - aggregate. We will use "int_nonagg_cells" to refer to those - cells of the background model that belong to the interior - but are not part of any of the aggregates. Thus, all interior - cells but not including the root cells of the aggregates. - - TO-DO: perhaps merge this function with setup_agg_cells -""" -function setup_int_nonagg_cells(int_nonagg_cell_to_cells) - int_nonagg_cells=Vector{Int}() - for cell in int_nonagg_cell_to_cells - append!(int_nonagg_cells,cell) - end - return int_nonagg_cells -end - -""" - Generate an array with the global IDs of the cells - that are the root cells of the aggregrates. - - TO-DO: perhaps merge this function with setup_cut_cells, - e.g. as a function that selects cells from list A which - are not part of a list B. -""" -function setup_root_cells(int_cells, int_nonagg_cells) - root_cells=Vector{Int}() - tester_int_nonagg_cells=Vector{Int}() - for cell in int_cells - if cell ∈ int_nonagg_cells - append!(tester_int_nonagg_cells,cell) - else - append!(root_cells,cell) - end - end - @assert(tester_int_nonagg_cells==int_nonagg_cells) - return root_cells -end - -""" - Generate an array with the global IDs of the cells - that are the cut cells of the aggregrates. - - TO-DO: perhaps merge this function with setup_cut_cells, - e.g. as a function that selects cells from list A which - are not part of a list B. + Flattens an array of arrays """ -function setup_cut_cells(agg_cells, root_cells) - cut_cells=Vector{Int}() - tester_root_cells=Vector{Int}() - for cell in agg_cells - if cell ∈ root_cells - append!(tester_root_cells,cell) - else - append!(cut_cells,cell) - end - end - @assert(tester_root_cells==root_cells) - cut_cells -end +function flatten(array_of_arrays) + vcat(array_of_arrays...) + end """ Generate an array that given the local ID of an "agg_cell" @@ -306,34 +145,16 @@ end setup_cut_cells_in_agg_cells_to_aggregate """ -function setup_agg_cells_to_aggregate(aggregate_to_cells) - agg_cells_to_aggregate=Vector{Int}() +function setup_cells_to_aggregate(aggregate_to_cells) + cells_to_aggregate=Vector{Int}() for (i,cells) in enumerate(aggregate_to_cells) for _ in cells - push!(agg_cells_to_aggregate,i) + push!(cells_to_aggregate,i) end end - agg_cells_to_aggregate + cells_to_aggregate end -""" - Generate an array that given the local ID of an cut "agg_cell" - returns the ID of the aggregate to which it belongs - (i.e., flattened version of aggregate_to_cut_cells) - - TO-DO: perhaps merge this function with , - setup_agg_cells_to_aggregate -""" -function setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) - cut_cells_in_agg_cells_to_aggregate=Vector{Int}() - for (i,cells) in enumerate(aggregate_to_cut_cells) - for _ in cells - push!(cut_cells_in_agg_cells_to_aggregate,i) - end - end - cut_cells_in_agg_cells_to_aggregate -end - """ Renumbers the global cell IDs to local cell IDs in the array of arrays with as many entries as aggregates. For each aggregate, the array diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index c228eaa8..8b55f581 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -57,13 +57,11 @@ function setup_geometry(nint, ε, pmin, pmax) bgmodel, cutgeo, h end -bgmodel, cutgeo, h = setup_geometry(nint, ε, pmin, pmax) - -# Compute mapping among background model -# cut cells and interior cells -strategy = AggregateAllCutCells() -aggregates = aggregate(strategy,cutgeo) +bgmodel, cutgeo, h= setup_geometry(nint, ε, pmin, pmax) +# Setup aggregates +strategy = AggregateAllCutCells() +aggregates= aggregate(strategy,cutgeo) aggregate_to_cells=setup_aggregate_to_cells(aggregates) aggregates_bounding_box_model= setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) @@ -77,10 +75,9 @@ aggregates_bounding_box_model= degree=2*2*(order+1) dΩ = Measure(Ω,degree) -## (1) FIND ALL INTERIOR CELLS WHICH ARE NOT PART OF AN AGGREGATE -int_nonagg_cell_to_cells = setup_int_nonagg_cell_to_cells(aggregates) -int_nonagg_cells = setup_int_nonagg_cells(int_nonagg_cell_to_cells) -@assert length(int_nonagg_cells)>0 # otherwise we can not constrain a dof +# Setup agg cells and triangulation +agg_cells =flatten(aggregate_to_cells) #[CLEAN]: replaced setup_agg_cells +Ωbg_agg_cells=view(Ωbg,agg_cells) # Pressure space if problem==0 @@ -88,9 +85,9 @@ if problem==0 elseif problem==1 # Set up zero-mean pressure space, with fixed interior dof Qnzm = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) - @assert nint>2 - int_nonagg_dof_to_fix = int_nonagg_cells[1] # pick the first interior cell that is not part of an aggregate to be constrained by the zero mean pressure condition. - spaceWithConstantFixed = Gridap.FESpaces.FESpaceWithConstantFixed(Qnzm,true,int_nonagg_dof_to_fix) + int_cells = restrict_cells(cutgeo,IN) #TODO: this dof may belong to an aggregate (root cell) + nonagg_int_cell = int_cells[findfirst(!in(agg_cells),int_cells)] + spaceWithConstantFixed = Gridap.FESpaces.FESpaceWithConstantFixed(Qnzm,true,nonagg_int_cell) Qzm_vol_i = assemble_vector(v->∫(v)*dΩ,Qnzm) Qzm_vol = sum(Qzm_vol_i) Q = Gridap.FESpaces.ZeroMeanFESpace(spaceWithConstantFixed,Qzm_vol_i,Qzm_vol) @@ -107,13 +104,9 @@ dy = get_fe_basis(Y) du,dp = dx dv,dq = dy -# Aggregate cells and triangulation -agg_cells =setup_agg_cells(aggregate_to_cells) -Ωbg_agg_cells=view(Ωbg,agg_cells) - # ref_agg_cell_to_agg_cell_map: \hat{K} -> K ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) -agg_cells_to_aggregate =setup_agg_cells_to_aggregate(aggregate_to_cells) +agg_cells_to_aggregate =setup_cells_to_aggregate(aggregate_to_cells) ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, agg_cells_to_aggregate) @@ -173,31 +166,24 @@ h_U = 1.0 ### STABILIZATION ON Ωagg\Troot ### ########################################### -## (2) FIND THE INTERIOR CELLS -Ω_agg_cells = view(Ω,agg_cells) # cells in aggregates -int_cells = Ω_agg_cells.parent.b.tface_to_mface - -## (3) FIND THE INTERIOR AGGREGATE (/ROOT) CELLS AND CUT CELLS -root_cells = setup_root_cells(int_cells, int_nonagg_cells) -cut_cells = setup_cut_cells(agg_cells, root_cells) - -## (4) CUT CELLS AND MEASURE -Ωbg_cut_cells = view(Ωbg,cut_cells) # cut cells (part of aggregate) +# Setup cut cells and triangulation +aggregate_to_cut_cells = restrict_aggregate_to_cells(cutgeo,aggregate_to_cells,GridapEmbedded.Interfaces.CUT) +cut_cells = flatten(aggregate_to_cut_cells) +#TO-DO: look into why cut_cells = restrict_cells(cutgeo,GridapEmbedded.Interfaces.CUT) can not be used instead of the above +Ωbg_cut_cells = view(Ωbg,cut_cells) dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) -# (5) DOF IDS related to cut cells +# Selecting relevant global dofs ids of cut cells (from background mesh) Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) -# (6) Defining cut_cells_to_aggregate_dof_ids -# aggregate_to_cut_cells = setup_aggregate_to_cut_cells(aggregates, root_cells) -aggregate_to_cut_cells = revised_setup_aggregate_to_cut_cells(aggregates, root_cells) -cut_cells_in_agg_cells_to_aggregate = setup_cut_cells_in_agg_cells_to_aggregate(aggregate_to_cut_cells) -U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) -P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_in_agg_cells_to_aggregate) +# Compute global dofs ids per aggregate and reindex these +cut_cells_to_aggregate = setup_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_to_aggregate) -# (7) Compute stabilization terms for u and p +# Compute stabilization terms for u and p wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, From 571e1b6a53d363dc5415d5414318f51d68515154 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 11 Feb 2025 09:39:39 +1100 Subject: [PATCH 059/120] correcting error in fixing dof of zero mean pressure space. Tested for order=0,2. --- bulk_ghost_penalty_canvas.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 8b55f581..2a9fad57 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -85,9 +85,11 @@ if problem==0 elseif problem==1 # Set up zero-mean pressure space, with fixed interior dof Qnzm = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) - int_cells = restrict_cells(cutgeo,IN) #TODO: this dof may belong to an aggregate (root cell) - nonagg_int_cell = int_cells[findfirst(!in(agg_cells),int_cells)] - spaceWithConstantFixed = Gridap.FESpaces.FESpaceWithConstantFixed(Qnzm,true,nonagg_int_cell) + int_cells = restrict_cells(cutgeo,IN) # global (background mesh') cell identifiers of interior cells + nonagg_int_cell = int_cells[findfirst(!in(agg_cells),int_cells)] # cell identifier (background mesh) of first interior cell not in aggregate + local_id = findfirst(isequal(nonagg_int_cell),Ωact.tface_to_mface) # local (active mesh') cell id of interior cell not in aggregate + dof_to_fix = get_cell_dof_ids(Qnzm)[local_id][1] + spaceWithConstantFixed = Gridap.FESpaces.FESpaceWithConstantFixed(Qnzm,true,Int64(dof_to_fix)) Qzm_vol_i = assemble_vector(v->∫(v)*dΩ,Qnzm) Qzm_vol = sum(Qzm_vol_i) Q = Gridap.FESpaces.ZeroMeanFESpace(spaceWithConstantFixed,Qzm_vol_i,Qzm_vol) From b2a16edf1ba918054fc59261c9480cd9d05a5681 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 11 Feb 2025 13:43:46 +1100 Subject: [PATCH 060/120] fixed missing argument in setup_ref_agg_cell_to_ref_bb_map --- aggregates_bounding_boxes_tools.jl | 2 +- bulk_ghost_penalty_canvas.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl index 9e854750..1a2c4d8a 100644 --- a/aggregates_bounding_boxes_tools.jl +++ b/aggregates_bounding_boxes_tools.jl @@ -217,7 +217,7 @@ end """ Define mapping ref_agg_cell_to_ref_bb_map: K_ref -> K -> bb -> bb_ref """ -function setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model,agg_cells_to_aggregate) +function setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model,agg_cells_to_aggregate,ref_agg_cell_to_agg_cell_map) bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) ref_agg_cell_to_ref_bb_map= diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 2a9fad57..4cd09e8f 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -110,7 +110,7 @@ dv,dq = dy ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) agg_cells_to_aggregate =setup_cells_to_aggregate(aggregate_to_cells) ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, - agg_cells_to_aggregate) + agg_cells_to_aggregate,ref_agg_cell_to_agg_cell_map) # Spaces on bounding boxes reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) From d95861c54d9391d3dcec815a6c6991458e14b008 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 11 Feb 2025 14:15:10 +1100 Subject: [PATCH 061/120] fixed missing argument aggregate_to_local_cells in functions that collect stabilization contributions --- bulk_ghost_penalty_canvas.jl | 26 ++++++++----- bulk_ghost_penalty_stab_tools.jl | 64 +++++++++----------------------- 2 files changed, 35 insertions(+), 55 deletions(-) diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 4cd09e8f..2227354f 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -186,7 +186,8 @@ U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_to_aggregate) # Compute stabilization terms for u and p -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dv, # Test basis @@ -199,7 +200,8 @@ wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_c γ, dΩbg_cut_cells) -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dq, # Test basis @@ -212,7 +214,8 @@ wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_c γ, dΩbg_cut_cells) #DIV stabilization part -wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dv, # Test basisr @@ -226,7 +229,8 @@ wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(ag dΩbg_cut_cells) ## FULL stabilization terms: -wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, +wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dv, # Test basis @@ -239,7 +243,8 @@ wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_ γ, dΩbg_cut_cells) -wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, +wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dq, # Test basis @@ -252,7 +257,8 @@ wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_ γ, dΩbg_cut_cells) -wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, +wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dv, # Test basis @@ -266,7 +272,8 @@ wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_ dΩbg_cut_cells) # MIXED STAB TERMS -wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dq, # Test basis @@ -281,7 +288,8 @@ wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cell dΩbg_cut_cells, dv) -wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dq, # Test basis @@ -348,7 +356,7 @@ end ## RHS STAB # rhs_g = divuex # TODO: pass function on rather than constant value!!!!! -vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, +vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(aggregate_to_local_cells,agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dq, # Test basis diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl index 31057e07..e620a5ef 100644 --- a/bulk_ghost_penalty_stab_tools.jl +++ b/bulk_ghost_penalty_stab_tools.jl @@ -5,7 +5,8 @@ # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) """ -function bulk_ghost_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, +function bulk_ghost_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, dv, # Test basis @@ -107,7 +108,8 @@ end # Compute and assemble the bulk penalty stabilization term # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells """ -function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dv, # Test basis @@ -208,7 +210,8 @@ end # Compute and assemble the bulk penalty stabilization term # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells """ -function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, +function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dv, # Test basis @@ -333,7 +336,8 @@ function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full( w, r, c end -function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, +function div_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩagg_cells, dv, # Test basis @@ -366,31 +370,6 @@ function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, push!(w, div_dv_div_du_mat_contribs) push!(r, U_Ωagg_cell_dof_ids) push!(c, U_Ωagg_cell_dof_ids) - - ## Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩ_agg_cells - # div_dv=∇⋅(_get_single_field_fe_basis(dv)) - # pdofs=Gridap.FESpaces.get_fe_dof_basis(P) - # div_dv_pdofs_values=pdofs(div_dv) - # div_dv_in_pressure_space_cell_array=lazy_map(Gridap.Fields.linear_combination, - # div_dv_pdofs_values, - # Gridap.CellData.get_data(_get_single_field_fe_basis(dq))) - # div_dv_in_pressure_space_single_field= Gridap.FESpaces.SingleFieldFEBasis(div_dv_in_pressure_space_cell_array, - # get_triangulation(P), - # Gridap.FESpaces.TestBasis(), - # Gridap.CellData.ReferenceDomain()) - # div_dv_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_dv_in_pressure_space_single_field,1,2) - - # div_du_in_pressure_space_cell_array=lazy_map(transpose,div_dv_in_pressure_space_cell_array) - # div_du_in_pressure_space_single_field=Gridap.FESpaces.SingleFieldFEBasis(div_du_in_pressure_space_cell_array, - # get_triangulation(P), - # Gridap.FESpaces.TrialBasis(), - # Gridap.CellData.ReferenceDomain()) - # div_du_in_pressure_space=Gridap.MultiField.MultiFieldFEBasisComponent(div_du_in_pressure_space_single_field,1,2) - - # div_dv_div_du_in_pressure_space_mat_contribs= - # get_array(∫(γ*div_dv_in_pressure_space⋅div_du_in_pressure_space)*dΩagg_cells) #not sure if neccesary? - # div_dv_div_du_mat_contribs ≈ div_dv_div_du_in_pressure_space_mat_contribs - div_du=∇⋅(_get_single_field_fe_basis(du)) ### Compute Π_Q_bb(div_du) @@ -448,7 +427,8 @@ function div_penalty_stabilization_collect_cell_matrix(agg_cells_to_aggregate, end -function div_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +function div_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dv, # Test basis @@ -564,7 +544,8 @@ end # Compute and assemble the bulk penalty stabilization term # ∫( (div_dv-div_dv_l2_proj_agg_cells)*(div_du-div_du_l2_proj_agg_cells))*dΩ_cut_cells """ -function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(agg_cells_to_aggregate, +function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dv, # Test basis @@ -684,7 +665,8 @@ end ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) """ -function pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +function pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dq, # Test basis @@ -824,7 +806,8 @@ end ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) """ -function dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_to_aggregate, +function dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dq, # Test basis @@ -870,18 +853,6 @@ function dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(agg_cells_t lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) - # dp_l2_proj_bb_array_agg_cells=lazy_map(transpose, dq_l2_proj_bb_array_agg_cells) - - # if (_is_multifield_fe_basis_component(dp)) - # @assert _is_multifield_fe_basis_component(dq) - # @assert _nfields(dp)==_nfields(dq) - # nfields=_nfields(dp) - # fieldid=_fieldid(dp) - # dp_l2_proj_bb_array_agg_cells=lazy_map( - # Gridap.Fields.BlockMap((1,nfields),fieldid), - # dp_l2_proj_bb_array_agg_cells) - # end - if (_is_multifield_fe_basis_component(dq)) @assert _is_multifield_fe_basis_component(dq) @assert _nfields(dp)==_nfields(dq) @@ -966,7 +937,8 @@ end ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) """ -function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(agg_cells_to_aggregate, +function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, ref_agg_cell_to_ref_bb_map, dΩbg_agg_cells, dq, # Test basis From 2d21a5a6e5335dcfe5daf1090377d4d8a8de570b Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 11 Feb 2025 14:47:26 +1100 Subject: [PATCH 062/120] removed print statement --- aggregates_bounding_boxes_tools.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl index 1a2c4d8a..bde8087c 100644 --- a/aggregates_bounding_boxes_tools.jl +++ b/aggregates_bounding_boxes_tools.jl @@ -245,7 +245,6 @@ function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cel end end current_cell+=1 - println(agg_cells_local_dof_ids) end end agg_cells_local_dof_ids From b22f9544c379559ced7483ca60291a149c711326 Mon Sep 17 00:00:00 2001 From: "Alberto F. Martin" Date: Mon, 24 Feb 2025 23:28:14 +1100 Subject: [PATCH 063/120] Added darcy preconditioner --- bulk_ghost_penalty_canvas.jl | 32 ++++++++++ darcy_preconditioning_tools.jl | 105 +++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 darcy_preconditioning_tools.jl diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 2227354f..25331a53 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -7,6 +7,7 @@ include("aggregates_bounding_boxes_tools.jl") include("bulk_ghost_penalty_stab_tools.jl") include("fields_and_blocks_tools.jl") include("BulkGhostPenaltyAssembleMaps.jl") +include("darcy_preconditioning_tools.jl") # Problem selection problem = 1 # 0 = Manufactured solution (L2-like projection), 1 = Darcy problem @@ -495,6 +496,37 @@ push!(wrc[3], cdiv_full...) A = assemble_matrix(assem, wrc) res_stab_ufullpfulldivufull = compute_quantities(problem,A,b,dΩ) +if problem==1 + P=assemble_darcy_preconditioner_matrix(cutgeo, degree, X, Y, s, h, β₀, + aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dΩbg_cut_cells, + # FLUX-RELATED DATA + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + # PRESSURE-RELATED DATA + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + # DIV-RELATED DbTA + γ) + evals = eigvals(Array(A),Array(P)) + println("Preconditioned condition number: ", abs(evals[end])/abs(evals[1])) +end + # U + DIVU + PMIX + DMIX wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) push!(wrc[1], wu...) diff --git a/darcy_preconditioning_tools.jl b/darcy_preconditioning_tools.jl new file mode 100644 index 00000000..2fd4955a --- /dev/null +++ b/darcy_preconditioning_tools.jl @@ -0,0 +1,105 @@ +function assemble_darcy_preconditioner_matrix(cutgeo, degree, X, Y, s, h, β₀, + aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dΩbg_cut_cells, + # FLUX-RELATED DATA + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ_u, + # PRESSURE-RELATED DATA + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ_p, + + γ_div) + + + # Physical domain + Ω = Triangulation(cutgeo,PHYSICAL) + dΩ = Measure(Ω,degree) + + # Bounadary + ΓN = EmbeddedBoundary(cutgeo) + dΓN = Measure(ΓN,degree) + nN = get_normal_vector(ΓN) + β = β₀*h.^(s) + a((u,p), (v,q)) = ∫(v⋅u)dΩ + ∫(p⋅q)dΩ + ∫(β*(u⋅nN)*(v⋅nN))dΓN + + dx = get_trial_fe_basis(X) + dy = get_fe_basis(Y) + + + ## FULL stabilization terms: + wu_full,ru_full,cu_full= + bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ_u, + dΩbg_cut_cells) + + wp_full,rp_full,cp_full= + bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ_p, + dΩbg_cut_cells) + + wdiv_full, rdiv_full, cdiv_full = + div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ_div, + dΩbg_cut_cells) + + assem=SparseMatrixAssembler(X,Y) + wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) + push!(wrc[1], wu_full...) + push!(wrc[2], ru_full...) + push!(wrc[3], cu_full...) + + push!(wrc[1], wp_full...) + push!(wrc[2], rp_full...) + push!(wrc[3], cp_full...) + + push!(wrc[1], wdiv_full...) + push!(wrc[2], rdiv_full...) + push!(wrc[3], cdiv_full...) + + assemble_matrix(assem, wrc) +end \ No newline at end of file From 12adbb7bf65a65ea9637ce8dba134cd2f2b14594 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 25 Feb 2025 16:52:15 +1100 Subject: [PATCH 064/120] copied code into src --- src/BGP/BGP.jl | 10 + src/BGP/BulkGhostPenaltyAssembleMaps.jl | 86 ++ src/BGP/aggregates_bounding_boxes_tools.jl | 275 ++++++ src/BGP/bulk_ghost_penalty_stab_tools.jl | 1029 ++++++++++++++++++++ src/BGP/darcy_preconditioning_tools.jl | 105 ++ src/BGP/fields_and_blocks_tools.jl | 26 + src/GridapEmbedded.jl | 2 + 7 files changed, 1533 insertions(+) create mode 100644 src/BGP/BGP.jl create mode 100644 src/BGP/BulkGhostPenaltyAssembleMaps.jl create mode 100644 src/BGP/aggregates_bounding_boxes_tools.jl create mode 100644 src/BGP/bulk_ghost_penalty_stab_tools.jl create mode 100644 src/BGP/darcy_preconditioning_tools.jl create mode 100644 src/BGP/fields_and_blocks_tools.jl diff --git a/src/BGP/BGP.jl b/src/BGP/BGP.jl new file mode 100644 index 00000000..96cbee6e --- /dev/null +++ b/src/BGP/BGP.jl @@ -0,0 +1,10 @@ +using Gridap +using FillArrays +using LinearAlgebra + +include("aggregates_bounding_boxes_tools.jl") +include("bulk_ghost_penalty_stab_tools.jl") +include("fields_and_blocks_tools.jl") +include("BulkGhostPenaltyAssembleMaps.jl") +include("darcy_preconditioning_tools.jl") + diff --git a/src/BGP/BulkGhostPenaltyAssembleMaps.jl b/src/BGP/BulkGhostPenaltyAssembleMaps.jl new file mode 100644 index 00000000..9c85630e --- /dev/null +++ b/src/BGP/BulkGhostPenaltyAssembleMaps.jl @@ -0,0 +1,86 @@ +# TO-DO: Better name? +struct BulkGhostPenaltyAssembleLhsMap{A} <: Gridap.Fields.Map + agg_cells_lhs_contribs::A +end + +function _get_rank(::Type{Array{T,N}}) where {T,N} + N +end + +function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleLhsMap,cells) + cache_unassembled_lhs=array_cache(m.agg_cells_lhs_contribs) + T=eltype(m.agg_cells_lhs_contribs) + evaluate_result=Gridap.Arrays.CachedArray(eltype(T),_get_rank(T)) + cache_unassembled_lhs,evaluate_result +end + +function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleLhsMap,cells) + cache_unassembled_lhs,result=cache + contrib = getindex!(cache_unassembled_lhs,m.agg_cells_lhs_contribs,1) + + Gridap.Arrays.setsize!(result,size(contrib)) + result.array .= 0.0 + for (i,cell) in enumerate(cells) + contrib = getindex!(cache_unassembled_lhs,m.agg_cells_lhs_contribs,cell) + result.array .+= contrib + end + result.array +end +struct BulkGhostPenaltyAssembleRhsMap{A,B} <: Gridap.Fields.Map + agg_cells_local_dof_ids::A + agg_cells_rhs_contribs::B +end + +function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleRhsMap,aggregate_local_cells) + cache_agg_cells_local_dof_ids=array_cache(m.agg_cells_local_dof_ids) + cache_unassembled_rhs=array_cache(m.agg_cells_rhs_contribs) + evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),2) + cache_agg_cells_local_dof_ids,cache_unassembled_rhs,evaluate_result +end + +function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleRhsMap,aggregate_local_cells) + cache_agg_cells_local_dof_ids,cache_unassembled_rhs,result=cache + contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,1) + + max_local_dof_id=-1 + for (i,cell) in enumerate(aggregate_local_cells) + current_cell_local_dof_ids = getindex!(cache_agg_cells_local_dof_ids,m.agg_cells_local_dof_ids,cell) + for local_dof in current_cell_local_dof_ids + max_local_dof_id=max(max_local_dof_id,local_dof) + end + end + + Gridap.Arrays.setsize!(result,(size(contrib,1),max_local_dof_id)) + + result.array .= 0.0 + for (i,cell) in enumerate(aggregate_local_cells) + current_cell_local_dof_ids = getindex!(cache_agg_cells_local_dof_ids,m.agg_cells_local_dof_ids,cell) + contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,cell) + for (j,local_dof) in enumerate(current_cell_local_dof_ids) + result.array[:,local_dof] += contrib[:,j] + end + end + result.array +end + +struct BulkGhostPenaltyAssembleRhsFEFunctionMap{A} <: Gridap.Fields.Map + agg_cells_rhs_contribs::A +end + +function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleRhsFEFunctionMap,aggregate_local_cells) + cache_unassembled_rhs=array_cache(m.agg_cells_rhs_contribs) + evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),1) + cache_unassembled_rhs,evaluate_result +end + +function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleRhsFEFunctionMap,aggregate_local_cells) + cache_unassembled_rhs,result=cache + contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,1) + Gridap.Arrays.setsize!(result,(size(contrib,1),)) + result.array .= 0.0 + for (i,cell) in enumerate(aggregate_local_cells) + contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,cell) + result.array .+= contrib + end + result.array +end \ No newline at end of file diff --git a/src/BGP/aggregates_bounding_boxes_tools.jl b/src/BGP/aggregates_bounding_boxes_tools.jl new file mode 100644 index 00000000..bde8087c --- /dev/null +++ b/src/BGP/aggregates_bounding_boxes_tools.jl @@ -0,0 +1,275 @@ +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains the global cell IDs of that cells in the background + model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_aggregate_to_cells(aggregates) + size_aggregates=Dict{Int,Int}() + for (i,agg) in enumerate(aggregates) + if agg>0 + if !haskey(size_aggregates,agg) + size_aggregates[agg]=1 + else + size_aggregates[agg]+=1 + end + end + end + + touched=Dict{Int,Int}() + aggregate_to_cells=Vector{Vector{Int}}() + current_aggregate=1 + for (i,agg) in enumerate(aggregates) + if agg>0 + if (size_aggregates[agg]>1) + if !haskey(touched,agg) + push!(aggregate_to_cells,[i]) + touched[agg]=current_aggregate + current_aggregate+=1 + else + push!(aggregate_to_cells[touched[agg]],i) + end + end + end + end + aggregate_to_cells +end + +""" + Creates an array containing the cell IDs of a selection of the background cells. The cell type filter IN (-1) selects the interior cells, OUT (1) the exterior cells, and GridapEmbedded.Interfaces.CUT (0) the cut cells. + TO-DO: publish CUT, so that GridapEmbedded.Interfaces.CUT can be shortened to CUT? + TO-DO: be careful with using restrict_cells(cutgeo,GridapEmbedded.Interfaces.CUT) to replace flatten(restrict_aggregate_to_cells(cutgeo,aggregate_to_cells,GridapEmbedded.Interfaces.CUT)) + +""" +function restrict_cells(cutgeo,cell_type_filter) + restricted_cells=Int64[] + cell_to_inoutcut=compute_bgcell_to_inoutcut(cutgeo,cutgeo.geo) + for cell in 1:length(cell_to_inoutcut) + if cell_to_inoutcut[cell] == cell_type_filter + push!(restricted_cells, cell) + end + end + restricted_cells +end + +""" + Creates an array of arrays with as many entries + as aggregates. For each aggregate, the array + contains a selection of the global cell IDs of + the cells in the background model that belong to + the same aggregate. The cell type filter IN (-1) + selects the interior cells, OUT (1) the exterior + cells, and GridapEmbedded.Interfaces.CUT (0) the + cut cells. + TO-DO: publish CUT, so that GridapEmbedded.Interfaces.CUT can be shortened to CUT? +""" +function restrict_aggregate_to_cells(cutgeo,aggregate_to_cells,cell_type_filter) + aggregate_to_restricted_cells=Vector{Int}[] + cell_to_inoutcut=compute_bgcell_to_inoutcut(cutgeo,cutgeo.geo) + for agg in aggregate_to_cells + restricted_cells = Int64[] + for cell in agg + if cell_to_inoutcut[cell] == cell_type_filter + push!(restricted_cells, cell) + end + end + push!(aggregate_to_restricted_cells,restricted_cells) + end + aggregate_to_restricted_cells +end + +function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) + g=get_grid(bgmodel) + cell_coords=get_cell_coordinates(g) + D=num_dims(bgmodel) + xmin=Vector{Float64}(undef,D) + xmax=Vector{Float64}(undef,D) + + # Compute coordinates of the nodes defining the bounding boxes + bounding_box_node_coords= + Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) + ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] + data = collect(1:length(bounding_box_node_coords)) + bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) + for (agg,cells) in enumerate(aggregate_to_cells) + p=first(cell_coords[cells[1]]) + for i in 1:D + xmin[i]=p[i] + xmax[i]=p[i] + end + for cell in cells + for p in cell_coords[cell] + for i in 1:D + xmin[i]=min(xmin[i],p[i]) + xmax[i]=max(xmax[i],p[i]) + end + end + end + bounds = [(xmin[i], xmax[i]) for i in 1:D] + point_iterator = Iterators.product(bounds...) + bounding_box_node_coords[bounding_box_node_ids[agg]] = + reshape([Point(p...) for p in point_iterator],2^D) + end + + # Set up the discrete model of bounding boxes + HEX_AXIS=1 + polytope=Polytope(Fill(HEX_AXIS,D)...) + scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) + cell_types=fill(1,length(bounding_box_node_ids)) + cell_reffes=[scalar_reffe] + grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, + bounding_box_node_ids, + cell_reffes, + cell_types, + Gridap.Geometry.Oriented()) + Gridap.Geometry.UnstructuredDiscreteModel(grid) +end + +""" + Flattens an array of arrays +""" +function flatten(array_of_arrays) + vcat(array_of_arrays...) + end + +""" + Generate an array that given the local ID of an "agg_cell" + returns the ID of the aggregate to which it belongs + (i.e., flattened version of aggregate_to_cells) + + + TO-DO: perhaps merge this function with , + setup_cut_cells_in_agg_cells_to_aggregate + +""" +function setup_cells_to_aggregate(aggregate_to_cells) + cells_to_aggregate=Vector{Int}() + for (i,cells) in enumerate(aggregate_to_cells) + for _ in cells + push!(cells_to_aggregate,i) + end + end + cells_to_aggregate +end + +""" + Renumbers the global cell IDs to local cell IDs in the array of arrays + with as many entries as aggregates. For each aggregate, the array + now contains the local cell IDs of that cells in the background + model that belong to the same aggregate + + TO-DO: with efficiency in mind we may want to store this + array of arrays as a Gridap.Arrays.Table. +""" +function setup_aggregate_to_local_cells(aggregate_to_cells) + aggregate_to_local_cells=deepcopy(aggregate_to_cells) + current_local_cell=1 + for (i,cells) in enumerate(aggregate_to_local_cells) + for j in 1:length(cells) + cells[j]=current_local_cell + current_local_cell+=1 + end + end + aggregate_to_local_cells +end + +""" + Changes the domain of a trial/test basis defined on + the reference space of bounding boxes to the reference + space of the agg cells + + TO-DO: in the future, for system of PDEs (MultiField) we should + also take care of blocks (BlockMap) +""" +function change_domain_bb_to_agg_cells(basis_bb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) + @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() + bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) + bb_basis_array = Gridap.CellData.get_data(basis_bb) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Remove transpose map; we will add it later + @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) + @assert isa(bb_basis_array.maps,Fill) + @assert isa(bb_basis_array.maps.value,typeof(transpose)) + bb_basis_array=bb_basis_array.args[1] + end + + bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) + bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), + bb_basis_array_to_Ωagg_cells_array, + ref_agg_cell_to_ref_bb_map) + if (bb_basis_style==Gridap.FESpaces.TrialBasis()) + # Add transpose + bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) + end + + Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, + Ωagg_cells, + ReferenceDomain()) +end + +""" + Define mapping ref_agg_cell_to_ref_bb_map: K_ref -> K -> bb -> bb_ref +""" +function setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model,agg_cells_to_aggregate,ref_agg_cell_to_agg_cell_map) + bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) + bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) + ref_agg_cell_to_ref_bb_map= + lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) +end + +""" + Compute local dof ids of the aggregated cells +""" +function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + agg_cells_local_dof_ids=copy(agg_cells_dof_ids) + current_cell=1 + for agg_cells in aggregate_to_agg_cells + g2l=Dict{Int32,Int32}() + current_local_dof=1 + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in keys(g2l)) + g2l[dof]=current_local_dof + agg_cells_local_dof_ids[current_cell][j]=current_local_dof + current_local_dof+=1 + else + agg_cells_local_dof_ids[current_cell][j]=g2l[dof] + end + end + current_cell+=1 + end + end + agg_cells_local_dof_ids +end + +""" + Returns the dof ids for the aggregates +""" +function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) + aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) + current_aggregate=1 + current_cell=1 + for agg_cells in aggregate_to_agg_cells + current_aggregate_dof_ids=Int[] + for (i,_) in enumerate(agg_cells) + current_cell_dof_ids=agg_cells_dof_ids[current_cell] + for (j, dof) in enumerate(current_cell_dof_ids) + if !(dof in current_aggregate_dof_ids) + push!(current_aggregate_dof_ids, dof) + end + end + current_cell+=1 + end + aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids + current_aggregate+=1 + end + aggregate_dof_ids +end \ No newline at end of file diff --git a/src/BGP/bulk_ghost_penalty_stab_tools.jl b/src/BGP/bulk_ghost_penalty_stab_tools.jl new file mode 100644 index 00000000..e620a5ef --- /dev/null +++ b/src/BGP/bulk_ghost_penalty_stab_tools.jl @@ -0,0 +1,1029 @@ +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) + # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) +""" +function bulk_ghost_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωagg_cell_dof_ids, + agg_cells_local_dof_ids, + agg_cells_to_aggregate_dof_ids, + h_U, + γ) + + + Ωagg_cells=dΩagg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, + dΩagg_cells.quad.trian, + ReferenceDomain()) + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) + end + push!(w, dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, Ωagg_cell_dof_ids) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + + proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) + end + + push!(w, proj_dv_du_mat_contribs) + push!(r, Ωagg_cell_dof_ids) + push!(c, agg_cells_to_aggregate_dof_ids) + + w, r, c +end + +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells +""" +function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωbg_cut_cell_dof_ids, + agg_cells_local_dof_ids, + cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωbg_agg_cells⋅du_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩbg_cut_cells) + + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωbg_cut_cell_dof_ids) + end + push!(w, dv_du_mat_contribs) + push!(r, Ωbg_cut_cell_dof_ids) + push!(c, Ωbg_cut_cell_dof_ids) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωbg_agg_cells,ReferenceDomain()) + + proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),cut_cells_to_aggregate_dof_ids) + end + + push!(w, proj_dv_du_mat_contribs) + push!(r, Ωbg_cut_cell_dof_ids) + push!(c, cut_cells_to_aggregate_dof_ids) + + w, r, c +end + +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells +""" +function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + dvbb, # Bounding box space test basis + lhs, + Ωbg_cut_cell_dof_ids, + agg_cells_local_dof_ids, + cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections dv_l2_proj_agg_cells & du_l2_proj_agg_cells + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dvbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dvbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + du_single_field=_get_single_field_fe_basis(du) + agg_cells_rhs_contribs=get_array(∫(dvbb_Ωbg_agg_cells⋅du_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(dvbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(du) + du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + du_l2_proj_bb_array_agg_cells) + end + + if (_is_multifield_fe_basis_component(dv)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + dv_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + dv_l2_proj_bb_array_agg_cells) + end + + du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dv_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),cut_cells_to_aggregate_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) dv*du term + dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩbg_cut_cells) + + push!(w, dv_du_mat_contribs) + push!(r, Ωbg_cut_cell_dof_ids) + push!(c, Ωbg_cut_cell_dof_ids) + + ## (2) dv*proj_du term + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωbg_agg_cells,ReferenceDomain()) + + dv_proj_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, dv_proj_du_mat_contribs) + push!(r, Ωbg_cut_cell_dof_ids) + push!(c, cut_cells_to_aggregate_dof_ids) + + ## (3) proj_dv*proj_du + proj_dv_proj_du_mat_contribs=get_array(∫(γ*dv_l2_proj_agg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, proj_dv_proj_du_mat_contribs) + push!(r, cut_cells_to_aggregate_dof_ids) + push!(c, cut_cells_to_aggregate_dof_ids) + + ## (4) proj_dv*du + duΩagg_cells=Gridap.CellData.change_domain(du,Ωbg_agg_cells,ReferenceDomain()) + proj_dv_du_mat_contribs=get_array(∫(-γ*dv_l2_proj_agg_cells⋅duΩagg_cells)*dΩbg_cut_cells) + + push!(w, proj_dv_du_mat_contribs) + push!(r, cut_cells_to_aggregate_dof_ids) + push!(c, Ωbg_cut_cell_dof_ids) + + w, r, c +end + +function div_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωagg_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_agg_cells_to_aggregate_dof_ids, + h_U, + γ) + Ωagg_cells=dΩagg_cells.quad.trian + + ## +DIVU STABILIZATION + ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) + end + + ## (I) Let's set up the div_dv_div_du_mat_contribs + # (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells + div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) + push!(w, div_dv_div_du_mat_contribs) + push!(r, U_Ωagg_cell_dof_ids) + push!(c, U_Ωagg_cell_dof_ids) + div_du=∇⋅(_get_single_field_fe_basis(du)) + + ### Compute Π_Q_bb(div_du) + dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩagg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + div_dv_l2_proj_bb_dofs, + Gridap.CellData.get_data(qbb)) + + div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(du) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(dv) + div_du_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((fieldid,nfields),fieldid), + div_du_l2_proj_bb_array_agg_cells) + end + + div_du_l2_proj_agg_cells = + Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + # dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) + + proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_agg_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_agg_cells_to_aggregate_dof_ids) + end + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_Ωagg_cell_dof_ids) # test + push!(c, U_agg_cells_to_aggregate_dof_ids) # trial + w,r,c +end + + +function div_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩbg_cut_cells + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + ## (I) Let's set up the div_dv_div_du_mat_contribs + # (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩbg_cut_cells + div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) + push!(w, div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + ## (II) Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩbg_cut_cells + div_du=∇⋅(_get_single_field_fe_basis(du)) + + # Compute Π_Q_bb(div_du) + dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) + + div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) + div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(du) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(dv) + div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) + end + + div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + # dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + + proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_cut_cells_to_aggregate_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) + end + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) # test + push!(c, U_cut_cells_to_aggregate_dof_ids) # trial + w,r,c +end + +function set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩagg_cells, + ubb, + vbb) +Ωagg_cells=dΩagg_cells.quad.trian + +# Change domain of vbb (test) from Ωbb to Ωagg_cells +vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + +# Change domain of ubb (trial) from Ωbb to Ωagg_cells +ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, + ref_agg_cell_to_ref_bb_map, + Ωagg_cells, + agg_cells_to_aggregate) + +# Compute contributions to LHS of L2 projection +agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) + +# Finally assemble LHS contributions +ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) +lazy_map(ass_lhs_map,aggregate_to_local_cells) +end + +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv-div_dv_l2_proj_agg_cells)*(div_du-div_du_l2_proj_agg_cells))*dΩ_cut_cells +""" +function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells) + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections div_dv_l2_proj_agg_cells & div_du_l2_proj_agg_cells + + div_du=∇⋅(_get_single_field_fe_basis(du)) + + # Change domain of vbb (test) from Ωbb to Ωagg_cells + dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in du + # restricted to the cells included in the bounding box of the aggregate + div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) + + # # Change domain of dv_l2_proj_bb_array from bb to agg_cells + div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) + div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(du)) + @assert _is_multifield_fe_basis_component(du) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(du) + fieldid=_fieldid(dv) + div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) + end + + if (_is_multifield_fe_basis_component(dv)) + @assert _is_multifield_fe_basis_component(dv) + @assert _nfields(du)==_nfields(dv) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + div_dv_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + div_dv_l2_proj_bb_array_agg_cells) + end + + div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + div_dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_dv_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + + # # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) div_dv*div_du term + div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) + push!(w, div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + ## (2) div_dv*proj_div_du term + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, U_cut_cells_to_aggregate_dof_ids) + + ## (3) proj_div_dv*proj_div_du + proj_div_dv_proj_div_du_mat_contribs=get_array(∫(γ*div_dv_l2_proj_agg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, proj_div_dv_proj_div_du_mat_contribs) + push!(r, U_cut_cells_to_aggregate_dof_ids) + push!(c, U_cut_cells_to_aggregate_dof_ids) + + ## (4) proj_div_dv*div_du + div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) + proj_div_dv_div_du_mat_contribs=get_array(∫(-γ*div_dv_l2_proj_agg_cells⋅div_du_Ωagg_cells)*dΩbg_cut_cells) + + push!(w, proj_div_dv_div_du_mat_contribs) + push!(r, U_cut_cells_to_aggregate_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + w, r, c +end + +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) + ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) + +""" +function pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + dqbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + dv) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells + # Change domain of qbb (test) from Ωbb to Ωagg_cells + dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + dp_single_field=_get_single_field_fe_basis(dp) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dq_l2_proj_bb_dofs, + Gridap.CellData.get_data(dqbb)) + + # # Change domain of dq_l2_proj_bb_array from bb to agg_cells + dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + dp_l2_proj_bb_array_agg_cells=lazy_map(transpose, dq_l2_proj_bb_array_agg_cells) + + if (_is_multifield_fe_basis_component(dp)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + dp_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap((1,nfields),fieldid), + dp_l2_proj_bb_array_agg_cells) + end + + # if (_is_multifield_fe_basis_component(dq)) + # @assert _is_multifield_fe_basis_component(dq) + # @assert _nfields(dp)==_nfields(dq) + # nfields=_nfields(dq) + # fieldid=_fieldid(dq) + # dq_l2_proj_bb_array_agg_cells=lazy_map( + # Gridap.Fields.BlockMap(nfields,fieldid), + # dq_l2_proj_bb_array_agg_cells) + # end + + dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + # dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) + end + + if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) div_dv*dp term + # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) + div_dv_dp_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅dp)*dΩbg_cut_cells) + + push!(w, div_dv_dp_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, P_Ωbg_cut_cell_dof_ids) + + ## (2) div_dv*proj_dp term + div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + div_dv_proj_dp_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, div_dv_proj_dp_mat_contribs) + push!(r, U_Ωbg_cut_cell_dof_ids) + push!(c, P_cut_cells_to_aggregate_dof_ids) + + # ## (3) proj_dq*proj_dp + # proj_dq_proj_dp_mat_contribs=get_array(∫(γ*dq_l2_proj_agg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) + + # push!(w, proj_dq_proj_dp_mat_contribs) + # push!(r, cut_cells_to_aggregate_dof_ids) + # push!(c, cut_cells_to_aggregate_dof_ids) + + # ## (4) proj_dq*dp + # dpΩagg_cells=Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) + # proj_dq_dp_mat_contribs=get_array(∫(-γ*dq_l2_proj_agg_cells⋅dpΩagg_cells)*dΩbg_cut_cells) + + # push!(w, proj_dq_dp_mat_contribs) + # push!(r, cut_cells_to_aggregate_dof_ids) + # push!(c, Ωbg_cut_cell_dof_ids) + + w, r, c +end + +## Create collect function on cut cells only +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) + ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) + +""" +function dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + dqbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + du) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells + # Change domain of qbb (test) from Ωbb to Ωagg_cells + dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + dp_single_field=_get_single_field_fe_basis(dp) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dq_l2_proj_bb_dofs, + Gridap.CellData.get_data(dqbb)) + + # # Change domain of dq_l2_proj_bb_array from bb to agg_cells + dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + if (_is_multifield_fe_basis_component(dq)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + dq_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + dq_l2_proj_bb_array_agg_cells) + end + + # dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) + end + + if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) + end + + # Manually set up the arrays that collect_cell_matrix would return automatically + w = [] + r = [] + c = [] + + ## (1) div_du*dq term + # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) + # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) + div_dv_dp_mat_contribs=get_array(∫(γ*(∇⋅du)⋅dq)*dΩbg_cut_cells) + + push!(w, div_dv_dp_mat_contribs) + push!(r, P_Ωbg_cut_cell_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + ## (2) div_du*proj_dq term + div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) + div_dv_proj_dp_mat_contribs=get_array(∫(γ*(-1.0)*div_du_Ωagg_cells⋅(dq_l2_proj_agg_cells))*dΩbg_cut_cells) + + push!(w, div_dv_proj_dp_mat_contribs) + push!(r, P_cut_cells_to_aggregate_dof_ids) + push!(c, U_Ωbg_cut_cell_dof_ids) + + + # ## (3) proj_dq*proj_dp + # proj_dq_proj_dp_mat_contribs=get_array(∫(γ*dq_l2_proj_agg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) + + # push!(w, proj_dq_proj_dp_mat_contribs) + # push!(r, cut_cells_to_aggregate_dof_ids) + # push!(c, cut_cells_to_aggregate_dof_ids) + + # ## (4) proj_dq*dp + # dpΩagg_cells=Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) + # proj_dq_dp_mat_contribs=get_array(∫(-γ*dq_l2_proj_agg_cells⋅dpΩagg_cells)*dΩbg_cut_cells) + + # push!(w, proj_dq_dp_mat_contribs) + # push!(r, cut_cells_to_aggregate_dof_ids) + # push!(c, Ωbg_cut_cell_dof_ids) + + w, r, c +end + +## Create collect function on cut cells only for rhs +## TODO: rhs_g_func does not seem to work when function is passed on +""" + dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + + # Compute and assemble the bulk penalty stabilization term + # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) + ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) + +""" +function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + dqbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ, + dΩbg_cut_cells, + rhs_g_func) + + + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + ## Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells + # Change domain of qbb (test) from Ωbb to Ωagg_cells + dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + + dp_single_field=_get_single_field_fe_basis(dp) + agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) + rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + + # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) + + # Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of all basis functions in dp + # restricted to the cells included in the bounding box of the aggregate + dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, + dq_l2_proj_bb_dofs, + Gridap.CellData.get_data(dqbb)) + + # # Change domain of dq_l2_proj_bb_array from bb to agg_cells + dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + + if (_is_multifield_fe_basis_component(dq)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + dq_l2_proj_bb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + dq_l2_proj_bb_array_agg_cells) + end + + dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) + + # BlockMap preparatory steps for the dof ids + if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) + end + + if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) + end + + # Manually set up the arrays that collect_cell_vector would return automatically + w = [] + r = [] + + ## (1) rhs_g*dq term + rhs_g_dp_mat_contribs=get_array(∫((rhs_g_func⋅dq)*γ)*dΩbg_cut_cells) + + push!(w, rhs_g_dp_mat_contribs) + push!(r, P_Ωbg_cut_cell_dof_ids) + + # (2) div_du*proj_dq term + rhs_g_proj_dp_mat_contribs=get_array(∫((rhs_g_func⋅dq_l2_proj_agg_cells)*γ*(-1.0))*dΩbg_cut_cells) + + push!(w, rhs_g_proj_dp_mat_contribs) + push!(r, P_cut_cells_to_aggregate_dof_ids) + + w, r +end \ No newline at end of file diff --git a/src/BGP/darcy_preconditioning_tools.jl b/src/BGP/darcy_preconditioning_tools.jl new file mode 100644 index 00000000..2fd4955a --- /dev/null +++ b/src/BGP/darcy_preconditioning_tools.jl @@ -0,0 +1,105 @@ +function assemble_darcy_preconditioner_matrix(cutgeo, degree, X, Y, s, h, β₀, + aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dΩbg_cut_cells, + # FLUX-RELATED DATA + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ_u, + # PRESSURE-RELATED DATA + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ_p, + + γ_div) + + + # Physical domain + Ω = Triangulation(cutgeo,PHYSICAL) + dΩ = Measure(Ω,degree) + + # Bounadary + ΓN = EmbeddedBoundary(cutgeo) + dΓN = Measure(ΓN,degree) + nN = get_normal_vector(ΓN) + β = β₀*h.^(s) + a((u,p), (v,q)) = ∫(v⋅u)dΩ + ∫(p⋅q)dΩ + ∫(β*(u⋅nN)*(v⋅nN))dΓN + + dx = get_trial_fe_basis(X) + dy = get_fe_basis(Y) + + + ## FULL stabilization terms: + wu_full,ru_full,cu_full= + bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + vbb, # Bounding box space test basis + u_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ_u, + dΩbg_cut_cells) + + wp_full,rp_full,cp_full= + bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dq, # Test basis + dp, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + P_Ωbg_cut_cell_dof_ids, + P_agg_cells_local_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + γ_p, + dΩbg_cut_cells) + + wdiv_full, rdiv_full, cdiv_full = + div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, + agg_cells_to_aggregate, + ref_agg_cell_to_ref_bb_map, + dΩbg_agg_cells, + dv, # Test basis + du, # Trial basis (to project) + qbb, # Bounding box space test basis + p_lhs, + U_Ωbg_cut_cell_dof_ids, + U_agg_cells_local_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + γ_div, + dΩbg_cut_cells) + + assem=SparseMatrixAssembler(X,Y) + wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) + push!(wrc[1], wu_full...) + push!(wrc[2], ru_full...) + push!(wrc[3], cu_full...) + + push!(wrc[1], wp_full...) + push!(wrc[2], rp_full...) + push!(wrc[3], cp_full...) + + push!(wrc[1], wdiv_full...) + push!(wrc[2], rdiv_full...) + push!(wrc[3], cdiv_full...) + + assemble_matrix(assem, wrc) +end \ No newline at end of file diff --git a/src/BGP/fields_and_blocks_tools.jl b/src/BGP/fields_and_blocks_tools.jl new file mode 100644 index 00000000..ff40c7f6 --- /dev/null +++ b/src/BGP/fields_and_blocks_tools.jl @@ -0,0 +1,26 @@ +function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) + map=cell_dof_ids.maps.value + @assert length(map.size)==1 + @assert blockid >= 1 + @assert blockid <= map.size[1] + cell_dof_ids.args[blockid] +end + +function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.single_field +end +function _get_single_field_fe_basis(a) + a +end +function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) + true +end +function _is_multifield_fe_basis_component(a) + false +end +function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.nfields +end +function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) + a.fieldid +end diff --git a/src/GridapEmbedded.jl b/src/GridapEmbedded.jl index 545ae5fd..8fbbde6a 100644 --- a/src/GridapEmbedded.jl +++ b/src/GridapEmbedded.jl @@ -14,6 +14,8 @@ include("AlgoimUtils/AlgoimUtils.jl") include("Distributed/Distributed.jl") +include("BGP/BGP.jl") + include("Exports.jl") end # module From a8bb48d051be7f0b49f1e4da09cc6d1b817a3435 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 27 Feb 2025 17:09:49 +1100 Subject: [PATCH 065/120] Minor --- src/Distributed/DistributedDiscretizations.jl | 8 ++++---- src/Interfaces/EmbeddedDiscretizations.jl | 4 ++-- .../EmbeddedFacetDiscretizations.jl | 2 +- src/LevelSetCutters/CutTriangulations.jl | 20 +++++++++---------- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index 5d6a22ba..0a43c2f6 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -1,14 +1,14 @@ -struct DistributedEmbeddedDiscretization{Dc,Dp,A,B} <: GridapType +struct DistributedEmbeddedDiscretization{A,B} <: GridapType discretizations::A model::B function DistributedEmbeddedDiscretization( - discretizations::AbstractArray{<:AbstractEmbeddedDiscretization{Dc,Dp}}, + discretizations::AbstractArray{<:AbstractEmbeddedDiscretization}, model::DistributedDiscreteModel - ) where {Dc,Dp} + ) A = typeof(discretizations) B = typeof(model) - new{Dc,Dp,A,B}(discretizations,model) + new{A,B}(discretizations,model) end end diff --git a/src/Interfaces/EmbeddedDiscretizations.jl b/src/Interfaces/EmbeddedDiscretizations.jl index 61d2e759..5a6a14b3 100644 --- a/src/Interfaces/EmbeddedDiscretizations.jl +++ b/src/Interfaces/EmbeddedDiscretizations.jl @@ -1,7 +1,7 @@ -abstract type AbstractEmbeddedDiscretization{Dc,Dp} <: GridapType end +abstract type AbstractEmbeddedDiscretization <: GridapType end -struct EmbeddedDiscretization{Dc,T} <: AbstractEmbeddedDiscretization{Dc,Dc} +struct EmbeddedDiscretization{Dc,T} <: AbstractEmbeddedDiscretization bgmodel::DiscreteModel ls_to_bgcell_to_inoutcut::Vector{Vector{Int8}} subcells::SubCellData{Dc,Dc,T} diff --git a/src/Interfaces/EmbeddedFacetDiscretizations.jl b/src/Interfaces/EmbeddedFacetDiscretizations.jl index b521906c..4086fb69 100644 --- a/src/Interfaces/EmbeddedFacetDiscretizations.jl +++ b/src/Interfaces/EmbeddedFacetDiscretizations.jl @@ -1,5 +1,5 @@ -struct EmbeddedFacetDiscretization{Dc,Dp,T} <: AbstractEmbeddedDiscretization{Dc,Dp} +struct EmbeddedFacetDiscretization{Dc,Dp,T} <: AbstractEmbeddedDiscretization bgmodel::DiscreteModel{Dp,Dp} ls_to_facet_to_inoutcut::Vector{Vector{Int8}} subfacets::SubCellData{Dc,Dp,T} diff --git a/src/LevelSetCutters/CutTriangulations.jl b/src/LevelSetCutters/CutTriangulations.jl index f1bd1f69..17068706 100644 --- a/src/LevelSetCutters/CutTriangulations.jl +++ b/src/LevelSetCutters/CutTriangulations.jl @@ -149,10 +149,14 @@ function cut_sub_triangulation(m::CutTriangulation, mpoint_to_value) end function count_sub_triangulation(m,mpoint_to_value) - n_scells = 0 - n_spoints = 0 mcell_to_mpoints = get_cell_to_points(m) table = get_lookup_table(m) + count_sub_triangulation(table,mcell_to_mpoints,mpoint_to_value) +end + +function count_sub_triangulation(table,mcell_to_mpoints,mpoint_to_value) + n_scells = 0 + n_spoints = 0 for mcell in 1:length(mcell_to_mpoints) case = compute_case(mcell_to_mpoints,mpoint_to_value,mcell) n_scells += length(table.case_to_subcell_to_inout[case]) @@ -444,24 +448,18 @@ end function initial_sub_triangulation(grid::Grid,geom::DiscreteGeometry) ugrid = UnstructuredGrid(grid) - tree = get_tree(geom) - ls_to_point_to_value, oid_to_ls = _find_unique_leaves(tree) + ls_to_point_to_value, oid_to_ls = _find_unique_leaves(get_tree(geom)) out = _initial_sub_triangulation(ugrid,ls_to_point_to_value) out[1], out[2], out[3], oid_to_ls end function _initial_sub_triangulation(grid::UnstructuredGrid,ls_to_point_to_value) - cutgrid, ls_to_cutpoint_to_value, ls_to_bgcell_to_inoutcut = _extract_grid_of_cut_cells(grid,ls_to_point_to_value) - subtrian, ls_to_subpoint_to_value = _simplexify_and_isolate_cells_in_cutgrid(cutgrid,ls_to_cutpoint_to_value) - - subtrian, ls_to_subpoint_to_value, ls_to_bgcell_to_inoutcut + return subtrian, ls_to_subpoint_to_value, ls_to_bgcell_to_inoutcut end function _extract_grid_of_cut_cells(grid,ls_to_point_to_value) - - p = _check_and_get_polytope(grid) table = LookupTable(p) cell_to_points = get_cell_node_ids(grid) @@ -682,4 +680,4 @@ function _ensure_positive_jacobians_facets_work!(tcell_to_tpoints,c1,c2,tjac_q, tcell_to_tpoints.data[p+2] = p1 end end -end \ No newline at end of file +end From 1f50d3019d463602955863af607d2146a01588e9 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 28 Feb 2025 12:05:03 +1100 Subject: [PATCH 066/120] put the BGP files into the src and exported things properly --- BulkGhostPenaltyAssembleMaps.jl | 86 --- aggregates_bounding_boxes_tools.jl | 275 -------- bulk_ghost_penalty_canvas.jl | 10 +- bulk_ghost_penalty_stab_tools.jl | 1029 ---------------------------- darcy_preconditioning_tools.jl | 105 --- fields_and_blocks_tools.jl | 26 - src/BGP/BGP.jl | 24 +- src/GridapEmbedded.jl | 4 +- 8 files changed, 27 insertions(+), 1532 deletions(-) delete mode 100644 BulkGhostPenaltyAssembleMaps.jl delete mode 100644 aggregates_bounding_boxes_tools.jl delete mode 100644 bulk_ghost_penalty_stab_tools.jl delete mode 100644 darcy_preconditioning_tools.jl delete mode 100644 fields_and_blocks_tools.jl diff --git a/BulkGhostPenaltyAssembleMaps.jl b/BulkGhostPenaltyAssembleMaps.jl deleted file mode 100644 index 9c85630e..00000000 --- a/BulkGhostPenaltyAssembleMaps.jl +++ /dev/null @@ -1,86 +0,0 @@ -# TO-DO: Better name? -struct BulkGhostPenaltyAssembleLhsMap{A} <: Gridap.Fields.Map - agg_cells_lhs_contribs::A -end - -function _get_rank(::Type{Array{T,N}}) where {T,N} - N -end - -function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleLhsMap,cells) - cache_unassembled_lhs=array_cache(m.agg_cells_lhs_contribs) - T=eltype(m.agg_cells_lhs_contribs) - evaluate_result=Gridap.Arrays.CachedArray(eltype(T),_get_rank(T)) - cache_unassembled_lhs,evaluate_result -end - -function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleLhsMap,cells) - cache_unassembled_lhs,result=cache - contrib = getindex!(cache_unassembled_lhs,m.agg_cells_lhs_contribs,1) - - Gridap.Arrays.setsize!(result,size(contrib)) - result.array .= 0.0 - for (i,cell) in enumerate(cells) - contrib = getindex!(cache_unassembled_lhs,m.agg_cells_lhs_contribs,cell) - result.array .+= contrib - end - result.array -end -struct BulkGhostPenaltyAssembleRhsMap{A,B} <: Gridap.Fields.Map - agg_cells_local_dof_ids::A - agg_cells_rhs_contribs::B -end - -function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleRhsMap,aggregate_local_cells) - cache_agg_cells_local_dof_ids=array_cache(m.agg_cells_local_dof_ids) - cache_unassembled_rhs=array_cache(m.agg_cells_rhs_contribs) - evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),2) - cache_agg_cells_local_dof_ids,cache_unassembled_rhs,evaluate_result -end - -function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleRhsMap,aggregate_local_cells) - cache_agg_cells_local_dof_ids,cache_unassembled_rhs,result=cache - contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,1) - - max_local_dof_id=-1 - for (i,cell) in enumerate(aggregate_local_cells) - current_cell_local_dof_ids = getindex!(cache_agg_cells_local_dof_ids,m.agg_cells_local_dof_ids,cell) - for local_dof in current_cell_local_dof_ids - max_local_dof_id=max(max_local_dof_id,local_dof) - end - end - - Gridap.Arrays.setsize!(result,(size(contrib,1),max_local_dof_id)) - - result.array .= 0.0 - for (i,cell) in enumerate(aggregate_local_cells) - current_cell_local_dof_ids = getindex!(cache_agg_cells_local_dof_ids,m.agg_cells_local_dof_ids,cell) - contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,cell) - for (j,local_dof) in enumerate(current_cell_local_dof_ids) - result.array[:,local_dof] += contrib[:,j] - end - end - result.array -end - -struct BulkGhostPenaltyAssembleRhsFEFunctionMap{A} <: Gridap.Fields.Map - agg_cells_rhs_contribs::A -end - -function Gridap.Fields.return_cache(m::BulkGhostPenaltyAssembleRhsFEFunctionMap,aggregate_local_cells) - cache_unassembled_rhs=array_cache(m.agg_cells_rhs_contribs) - evaluate_result=Gridap.Arrays.CachedArray(eltype(eltype(m.agg_cells_rhs_contribs)),1) - cache_unassembled_rhs,evaluate_result -end - -function Gridap.Fields.evaluate!(cache,m::BulkGhostPenaltyAssembleRhsFEFunctionMap,aggregate_local_cells) - cache_unassembled_rhs,result=cache - contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,1) - Gridap.Arrays.setsize!(result,(size(contrib,1),)) - result.array .= 0.0 - for (i,cell) in enumerate(aggregate_local_cells) - contrib = getindex!(cache_unassembled_rhs,m.agg_cells_rhs_contribs,cell) - result.array .+= contrib - end - result.array -end \ No newline at end of file diff --git a/aggregates_bounding_boxes_tools.jl b/aggregates_bounding_boxes_tools.jl deleted file mode 100644 index bde8087c..00000000 --- a/aggregates_bounding_boxes_tools.jl +++ /dev/null @@ -1,275 +0,0 @@ -""" - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains the global cell IDs of that cells in the background - model that belong to the same aggregate - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_aggregate_to_cells(aggregates) - size_aggregates=Dict{Int,Int}() - for (i,agg) in enumerate(aggregates) - if agg>0 - if !haskey(size_aggregates,agg) - size_aggregates[agg]=1 - else - size_aggregates[agg]+=1 - end - end - end - - touched=Dict{Int,Int}() - aggregate_to_cells=Vector{Vector{Int}}() - current_aggregate=1 - for (i,agg) in enumerate(aggregates) - if agg>0 - if (size_aggregates[agg]>1) - if !haskey(touched,agg) - push!(aggregate_to_cells,[i]) - touched[agg]=current_aggregate - current_aggregate+=1 - else - push!(aggregate_to_cells[touched[agg]],i) - end - end - end - end - aggregate_to_cells -end - -""" - Creates an array containing the cell IDs of a selection of the background cells. The cell type filter IN (-1) selects the interior cells, OUT (1) the exterior cells, and GridapEmbedded.Interfaces.CUT (0) the cut cells. - TO-DO: publish CUT, so that GridapEmbedded.Interfaces.CUT can be shortened to CUT? - TO-DO: be careful with using restrict_cells(cutgeo,GridapEmbedded.Interfaces.CUT) to replace flatten(restrict_aggregate_to_cells(cutgeo,aggregate_to_cells,GridapEmbedded.Interfaces.CUT)) - -""" -function restrict_cells(cutgeo,cell_type_filter) - restricted_cells=Int64[] - cell_to_inoutcut=compute_bgcell_to_inoutcut(cutgeo,cutgeo.geo) - for cell in 1:length(cell_to_inoutcut) - if cell_to_inoutcut[cell] == cell_type_filter - push!(restricted_cells, cell) - end - end - restricted_cells -end - -""" - Creates an array of arrays with as many entries - as aggregates. For each aggregate, the array - contains a selection of the global cell IDs of - the cells in the background model that belong to - the same aggregate. The cell type filter IN (-1) - selects the interior cells, OUT (1) the exterior - cells, and GridapEmbedded.Interfaces.CUT (0) the - cut cells. - TO-DO: publish CUT, so that GridapEmbedded.Interfaces.CUT can be shortened to CUT? -""" -function restrict_aggregate_to_cells(cutgeo,aggregate_to_cells,cell_type_filter) - aggregate_to_restricted_cells=Vector{Int}[] - cell_to_inoutcut=compute_bgcell_to_inoutcut(cutgeo,cutgeo.geo) - for agg in aggregate_to_cells - restricted_cells = Int64[] - for cell in agg - if cell_to_inoutcut[cell] == cell_type_filter - push!(restricted_cells, cell) - end - end - push!(aggregate_to_restricted_cells,restricted_cells) - end - aggregate_to_restricted_cells -end - -function setup_aggregates_bounding_box_model(bgmodel, aggregate_to_cells) - g=get_grid(bgmodel) - cell_coords=get_cell_coordinates(g) - D=num_dims(bgmodel) - xmin=Vector{Float64}(undef,D) - xmax=Vector{Float64}(undef,D) - - # Compute coordinates of the nodes defining the bounding boxes - bounding_box_node_coords= - Vector{Point{D,Float64}}(undef,length(aggregate_to_cells)*2^D) - ptr = [ (((i-1)*2^D)+1) for i in 1:length(aggregate_to_cells)+1 ] - data = collect(1:length(bounding_box_node_coords)) - bounding_box_node_ids = Gridap.Arrays.Table(data,ptr) - for (agg,cells) in enumerate(aggregate_to_cells) - p=first(cell_coords[cells[1]]) - for i in 1:D - xmin[i]=p[i] - xmax[i]=p[i] - end - for cell in cells - for p in cell_coords[cell] - for i in 1:D - xmin[i]=min(xmin[i],p[i]) - xmax[i]=max(xmax[i],p[i]) - end - end - end - bounds = [(xmin[i], xmax[i]) for i in 1:D] - point_iterator = Iterators.product(bounds...) - bounding_box_node_coords[bounding_box_node_ids[agg]] = - reshape([Point(p...) for p in point_iterator],2^D) - end - - # Set up the discrete model of bounding boxes - HEX_AXIS=1 - polytope=Polytope(Fill(HEX_AXIS,D)...) - scalar_reffe=ReferenceFE(polytope,lagrangian,Float64,1) - cell_types=fill(1,length(bounding_box_node_ids)) - cell_reffes=[scalar_reffe] - grid = Gridap.Geometry.UnstructuredGrid(bounding_box_node_coords, - bounding_box_node_ids, - cell_reffes, - cell_types, - Gridap.Geometry.Oriented()) - Gridap.Geometry.UnstructuredDiscreteModel(grid) -end - -""" - Flattens an array of arrays -""" -function flatten(array_of_arrays) - vcat(array_of_arrays...) - end - -""" - Generate an array that given the local ID of an "agg_cell" - returns the ID of the aggregate to which it belongs - (i.e., flattened version of aggregate_to_cells) - - - TO-DO: perhaps merge this function with , - setup_cut_cells_in_agg_cells_to_aggregate - -""" -function setup_cells_to_aggregate(aggregate_to_cells) - cells_to_aggregate=Vector{Int}() - for (i,cells) in enumerate(aggregate_to_cells) - for _ in cells - push!(cells_to_aggregate,i) - end - end - cells_to_aggregate -end - -""" - Renumbers the global cell IDs to local cell IDs in the array of arrays - with as many entries as aggregates. For each aggregate, the array - now contains the local cell IDs of that cells in the background - model that belong to the same aggregate - - TO-DO: with efficiency in mind we may want to store this - array of arrays as a Gridap.Arrays.Table. -""" -function setup_aggregate_to_local_cells(aggregate_to_cells) - aggregate_to_local_cells=deepcopy(aggregate_to_cells) - current_local_cell=1 - for (i,cells) in enumerate(aggregate_to_local_cells) - for j in 1:length(cells) - cells[j]=current_local_cell - current_local_cell+=1 - end - end - aggregate_to_local_cells -end - -""" - Changes the domain of a trial/test basis defined on - the reference space of bounding boxes to the reference - space of the agg cells - - TO-DO: in the future, for system of PDEs (MultiField) we should - also take care of blocks (BlockMap) -""" -function change_domain_bb_to_agg_cells(basis_bb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - @assert num_cells(Ωagg_cells)==length(ref_agg_cell_to_ref_bb_map) - @assert Gridap.CellData.DomainStyle(basis_bb)==ReferenceDomain() - bb_basis_style = Gridap.FESpaces.BasisStyle(basis_bb) - bb_basis_array = Gridap.CellData.get_data(basis_bb) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Remove transpose map; we will add it later - @assert isa(bb_basis_array,Gridap.Arrays.LazyArray) - @assert isa(bb_basis_array.maps,Fill) - @assert isa(bb_basis_array.maps.value,typeof(transpose)) - bb_basis_array=bb_basis_array.args[1] - end - - bb_basis_array_to_Ωagg_cells_array = lazy_map(Reindex(bb_basis_array),agg_cells_to_aggregate) - bb_basis_array_to_Ωagg_cells_array = lazy_map(Broadcasting(∘), - bb_basis_array_to_Ωagg_cells_array, - ref_agg_cell_to_ref_bb_map) - if (bb_basis_style==Gridap.FESpaces.TrialBasis()) - # Add transpose - bb_basis_array_to_Ωagg_cells_array=lazy_map(transpose, bb_basis_array_to_Ωagg_cells_array) - end - - Gridap.CellData.GenericCellField(bb_basis_array_to_Ωagg_cells_array, - Ωagg_cells, - ReferenceDomain()) -end - -""" - Define mapping ref_agg_cell_to_ref_bb_map: K_ref -> K -> bb -> bb_ref -""" -function setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model,agg_cells_to_aggregate,ref_agg_cell_to_agg_cell_map) - bb_to_ref_bb=lazy_map(Gridap.Fields.inverse_map,get_cell_map(aggregates_bounding_box_model)) - bb_to_ref_bb_agg_cells=lazy_map(Reindex(bb_to_ref_bb),agg_cells_to_aggregate) - ref_agg_cell_to_ref_bb_map= - lazy_map(Broadcasting(∘),bb_to_ref_bb_agg_cells,ref_agg_cell_to_agg_cell_map) -end - -""" - Compute local dof ids of the aggregated cells -""" -function compute_agg_cells_local_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - agg_cells_local_dof_ids=copy(agg_cells_dof_ids) - current_cell=1 - for agg_cells in aggregate_to_agg_cells - g2l=Dict{Int32,Int32}() - current_local_dof=1 - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in keys(g2l)) - g2l[dof]=current_local_dof - agg_cells_local_dof_ids[current_cell][j]=current_local_dof - current_local_dof+=1 - else - agg_cells_local_dof_ids[current_cell][j]=g2l[dof] - end - end - current_cell+=1 - end - end - agg_cells_local_dof_ids -end - -""" - Returns the dof ids for the aggregates -""" -function compute_aggregate_dof_ids(agg_cells_dof_ids, aggregate_to_agg_cells) - aggregate_dof_ids=Vector{Vector{Int}}(undef, length(aggregate_to_agg_cells)) - current_aggregate=1 - current_cell=1 - for agg_cells in aggregate_to_agg_cells - current_aggregate_dof_ids=Int[] - for (i,_) in enumerate(agg_cells) - current_cell_dof_ids=agg_cells_dof_ids[current_cell] - for (j, dof) in enumerate(current_cell_dof_ids) - if !(dof in current_aggregate_dof_ids) - push!(current_aggregate_dof_ids, dof) - end - end - current_cell+=1 - end - aggregate_dof_ids[current_aggregate]=current_aggregate_dof_ids - current_aggregate+=1 - end - aggregate_dof_ids -end \ No newline at end of file diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 25331a53..90b73d8e 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -1,13 +1,7 @@ using Gridap using GridapEmbedded -using FillArrays -using LinearAlgebra - -include("aggregates_bounding_boxes_tools.jl") -include("bulk_ghost_penalty_stab_tools.jl") -include("fields_and_blocks_tools.jl") -include("BulkGhostPenaltyAssembleMaps.jl") -include("darcy_preconditioning_tools.jl") + +include("./src/BGP/BGP.jl") # Problem selection problem = 1 # 0 = Manufactured solution (L2-like projection), 1 = Darcy problem diff --git a/bulk_ghost_penalty_stab_tools.jl b/bulk_ghost_penalty_stab_tools.jl deleted file mode 100644 index e620a5ef..00000000 --- a/bulk_ghost_penalty_stab_tools.jl +++ /dev/null @@ -1,1029 +0,0 @@ -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) -""" -function bulk_ghost_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωagg_cell_dof_ids, - agg_cells_local_dof_ids, - agg_cells_to_aggregate_dof_ids, - h_U, - γ) - - - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, - dΩagg_cells.quad.trian, - ReferenceDomain()) - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) - end - push!(w, dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, Ωagg_cell_dof_ids) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - - proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) - end - - push!(w, proj_dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, agg_cells_to_aggregate_dof_ids) - - w, r, c -end - -## Create collect function on cut cells only -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells -""" -function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωbg_cut_cell_dof_ids, - agg_cells_local_dof_ids, - cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dvbb, - ref_agg_cell_to_ref_bb_map, - Ωbg_agg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωbg_agg_cells⋅du_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩbg_cut_cells) - - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωbg_cut_cell_dof_ids) - end - push!(w, dv_du_mat_contribs) - push!(r, Ωbg_cut_cell_dof_ids) - push!(c, Ωbg_cut_cell_dof_ids) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωbg_agg_cells,ReferenceDomain()) - - proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),cut_cells_to_aggregate_dof_ids) - end - - push!(w, proj_dv_du_mat_contribs) - push!(r, Ωbg_cut_cell_dof_ids) - push!(c, cut_cells_to_aggregate_dof_ids) - - w, r, c -end - -## Create collect function on cut cells only -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells -""" -function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωbg_cut_cell_dof_ids, - agg_cells_local_dof_ids, - cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## (I) Compute projections dv_l2_proj_agg_cells & du_l2_proj_agg_cells - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dvbb, - ref_agg_cell_to_ref_bb_map, - Ωbg_agg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωbg_agg_cells⋅du_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - if (_is_multifield_fe_basis_component(dv)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - dv_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - dv_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dv_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),cut_cells_to_aggregate_dof_ids) - end - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - ## (1) dv*du term - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩbg_cut_cells) - - push!(w, dv_du_mat_contribs) - push!(r, Ωbg_cut_cell_dof_ids) - push!(c, Ωbg_cut_cell_dof_ids) - - ## (2) dv*proj_du term - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωbg_agg_cells,ReferenceDomain()) - - dv_proj_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, dv_proj_du_mat_contribs) - push!(r, Ωbg_cut_cell_dof_ids) - push!(c, cut_cells_to_aggregate_dof_ids) - - ## (3) proj_dv*proj_du - proj_dv_proj_du_mat_contribs=get_array(∫(γ*dv_l2_proj_agg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, proj_dv_proj_du_mat_contribs) - push!(r, cut_cells_to_aggregate_dof_ids) - push!(c, cut_cells_to_aggregate_dof_ids) - - ## (4) proj_dv*du - duΩagg_cells=Gridap.CellData.change_domain(du,Ωbg_agg_cells,ReferenceDomain()) - proj_dv_du_mat_contribs=get_array(∫(-γ*dv_l2_proj_agg_cells⋅duΩagg_cells)*dΩbg_cut_cells) - - push!(w, proj_dv_du_mat_contribs) - push!(r, cut_cells_to_aggregate_dof_ids) - push!(c, Ωbg_cut_cell_dof_ids) - - w, r, c -end - -function div_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωagg_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_agg_cells_to_aggregate_dof_ids, - h_U, - γ) - Ωagg_cells=dΩagg_cells.quad.trian - - ## +DIVU STABILIZATION - ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) - end - - ## (I) Let's set up the div_dv_div_du_mat_contribs - # (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells - div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) - push!(w, div_dv_div_du_mat_contribs) - push!(r, U_Ωagg_cell_dof_ids) - push!(c, U_Ωagg_cell_dof_ids) - div_du=∇⋅(_get_single_field_fe_basis(du)) - - ### Compute Π_Q_bb(div_du) - dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩagg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(qbb)) - - div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(du) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(dv) - div_du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((fieldid,nfields),fieldid), - div_du_l2_proj_bb_array_agg_cells) - end - - div_du_l2_proj_agg_cells = - Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - # dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) - - proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_agg_cells_to_aggregate_dof_ids) - end - - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_Ωagg_cell_dof_ids) # test - push!(c, U_agg_cells_to_aggregate_dof_ids) # trial - w,r,c -end - - -function div_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩbg_cut_cells - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end - - ## (I) Let's set up the div_dv_div_du_mat_contribs - # (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩbg_cut_cells - div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) - push!(w, div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - ## (II) Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩbg_cut_cells - div_du=∇⋅(_get_single_field_fe_basis(du)) - - # Compute Π_Q_bb(div_du) - dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) - - div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) - div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(du) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(dv) - div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) - end - - div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - # dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - - proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_cut_cells_to_aggregate_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) - end - - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) # test - push!(c, U_cut_cells_to_aggregate_dof_ids) # trial - w,r,c -end - -function set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) -Ωagg_cells=dΩagg_cells.quad.trian - -# Change domain of vbb (test) from Ωbb to Ωagg_cells -vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - -# Change domain of ubb (trial) from Ωbb to Ωagg_cells -ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - -# Compute contributions to LHS of L2 projection -agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) - -# Finally assemble LHS contributions -ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) -lazy_map(ass_lhs_map,aggregate_to_local_cells) -end - -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv-div_dv_l2_proj_agg_cells)*(div_du-div_du_l2_proj_agg_cells))*dΩ_cut_cells -""" -function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## (I) Compute projections div_dv_l2_proj_agg_cells & div_du_l2_proj_agg_cells - - div_du=∇⋅(_get_single_field_fe_basis(du)) - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) - div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(du) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(dv) - div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) - end - - if (_is_multifield_fe_basis_component(dv)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - div_dv_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - div_dv_l2_proj_bb_array_agg_cells) - end - - div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - div_dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_dv_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - - # # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) - end - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - ## (1) div_dv*div_du term - div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) - push!(w, div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - ## (2) div_dv*proj_div_du term - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, U_cut_cells_to_aggregate_dof_ids) - - ## (3) proj_div_dv*proj_div_du - proj_div_dv_proj_div_du_mat_contribs=get_array(∫(γ*div_dv_l2_proj_agg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, proj_div_dv_proj_div_du_mat_contribs) - push!(r, U_cut_cells_to_aggregate_dof_ids) - push!(c, U_cut_cells_to_aggregate_dof_ids) - - ## (4) proj_div_dv*div_du - div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) - proj_div_dv_div_du_mat_contribs=get_array(∫(-γ*div_dv_l2_proj_agg_cells⋅div_du_Ωagg_cells)*dΩbg_cut_cells) - - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_cut_cells_to_aggregate_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - w, r, c -end - -## Create collect function on cut cells only -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) - ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) - -""" -function pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - dqbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - dv) - - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells - # Change domain of qbb (test) from Ωbb to Ωagg_cells - dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, - ref_agg_cell_to_ref_bb_map, - Ωbg_agg_cells, - agg_cells_to_aggregate) - - dp_single_field=_get_single_field_fe_basis(dp) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dq_l2_proj_bb_dofs, - Gridap.CellData.get_data(dqbb)) - - # # Change domain of dq_l2_proj_bb_array from bb to agg_cells - dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - dp_l2_proj_bb_array_agg_cells=lazy_map(transpose, dq_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(dp)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - dp_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - dp_l2_proj_bb_array_agg_cells) - end - - # if (_is_multifield_fe_basis_component(dq)) - # @assert _is_multifield_fe_basis_component(dq) - # @assert _nfields(dp)==_nfields(dq) - # nfields=_nfields(dq) - # fieldid=_fieldid(dq) - # dq_l2_proj_bb_array_agg_cells=lazy_map( - # Gridap.Fields.BlockMap(nfields,fieldid), - # dq_l2_proj_bb_array_agg_cells) - # end - - dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - # dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(dp)) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - P_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) - end - - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - ## (1) div_dv*dp term - # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) - div_dv_dp_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅dp)*dΩbg_cut_cells) - - push!(w, div_dv_dp_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, P_Ωbg_cut_cell_dof_ids) - - ## (2) div_dv*proj_dp term - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - div_dv_proj_dp_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, div_dv_proj_dp_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, P_cut_cells_to_aggregate_dof_ids) - - # ## (3) proj_dq*proj_dp - # proj_dq_proj_dp_mat_contribs=get_array(∫(γ*dq_l2_proj_agg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) - - # push!(w, proj_dq_proj_dp_mat_contribs) - # push!(r, cut_cells_to_aggregate_dof_ids) - # push!(c, cut_cells_to_aggregate_dof_ids) - - # ## (4) proj_dq*dp - # dpΩagg_cells=Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) - # proj_dq_dp_mat_contribs=get_array(∫(-γ*dq_l2_proj_agg_cells⋅dpΩagg_cells)*dΩbg_cut_cells) - - # push!(w, proj_dq_dp_mat_contribs) - # push!(r, cut_cells_to_aggregate_dof_ids) - # push!(c, Ωbg_cut_cell_dof_ids) - - w, r, c -end - -## Create collect function on cut cells only -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) - ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) - -""" -function dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - dqbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - du) - - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells - # Change domain of qbb (test) from Ωbb to Ωagg_cells - dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, - ref_agg_cell_to_ref_bb_map, - Ωbg_agg_cells, - agg_cells_to_aggregate) - - dp_single_field=_get_single_field_fe_basis(dp) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dq_l2_proj_bb_dofs, - Gridap.CellData.get_data(dqbb)) - - # # Change domain of dq_l2_proj_bb_array from bb to agg_cells - dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - if (_is_multifield_fe_basis_component(dq)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - dq_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - dq_l2_proj_bb_array_agg_cells) - end - - # dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(dp)) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - P_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) - end - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - ## (1) div_du*dq term - # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) - div_dv_dp_mat_contribs=get_array(∫(γ*(∇⋅du)⋅dq)*dΩbg_cut_cells) - - push!(w, div_dv_dp_mat_contribs) - push!(r, P_Ωbg_cut_cell_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - ## (2) div_du*proj_dq term - div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) - div_dv_proj_dp_mat_contribs=get_array(∫(γ*(-1.0)*div_du_Ωagg_cells⋅(dq_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, div_dv_proj_dp_mat_contribs) - push!(r, P_cut_cells_to_aggregate_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - - # ## (3) proj_dq*proj_dp - # proj_dq_proj_dp_mat_contribs=get_array(∫(γ*dq_l2_proj_agg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) - - # push!(w, proj_dq_proj_dp_mat_contribs) - # push!(r, cut_cells_to_aggregate_dof_ids) - # push!(c, cut_cells_to_aggregate_dof_ids) - - # ## (4) proj_dq*dp - # dpΩagg_cells=Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) - # proj_dq_dp_mat_contribs=get_array(∫(-γ*dq_l2_proj_agg_cells⋅dpΩagg_cells)*dΩbg_cut_cells) - - # push!(w, proj_dq_dp_mat_contribs) - # push!(r, cut_cells_to_aggregate_dof_ids) - # push!(c, Ωbg_cut_cell_dof_ids) - - w, r, c -end - -## Create collect function on cut cells only for rhs -## TODO: rhs_g_func does not seem to work when function is passed on -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) - ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) - -""" -function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - dqbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - rhs_g_func) - - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells - # Change domain of qbb (test) from Ωbb to Ωagg_cells - dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, - ref_agg_cell_to_ref_bb_map, - Ωbg_agg_cells, - agg_cells_to_aggregate) - - dp_single_field=_get_single_field_fe_basis(dp) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dq_l2_proj_bb_dofs, - Gridap.CellData.get_data(dqbb)) - - # # Change domain of dq_l2_proj_bb_array from bb to agg_cells - dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - if (_is_multifield_fe_basis_component(dq)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - dq_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - dq_l2_proj_bb_array_agg_cells) - end - - dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - P_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) - end - - # Manually set up the arrays that collect_cell_vector would return automatically - w = [] - r = [] - - ## (1) rhs_g*dq term - rhs_g_dp_mat_contribs=get_array(∫((rhs_g_func⋅dq)*γ)*dΩbg_cut_cells) - - push!(w, rhs_g_dp_mat_contribs) - push!(r, P_Ωbg_cut_cell_dof_ids) - - # (2) div_du*proj_dq term - rhs_g_proj_dp_mat_contribs=get_array(∫((rhs_g_func⋅dq_l2_proj_agg_cells)*γ*(-1.0))*dΩbg_cut_cells) - - push!(w, rhs_g_proj_dp_mat_contribs) - push!(r, P_cut_cells_to_aggregate_dof_ids) - - w, r -end \ No newline at end of file diff --git a/darcy_preconditioning_tools.jl b/darcy_preconditioning_tools.jl deleted file mode 100644 index 2fd4955a..00000000 --- a/darcy_preconditioning_tools.jl +++ /dev/null @@ -1,105 +0,0 @@ -function assemble_darcy_preconditioner_matrix(cutgeo, degree, X, Y, s, h, β₀, - aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dΩbg_cut_cells, - # FLUX-RELATED DATA - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ_u, - # PRESSURE-RELATED DATA - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ_p, - - γ_div) - - - # Physical domain - Ω = Triangulation(cutgeo,PHYSICAL) - dΩ = Measure(Ω,degree) - - # Bounadary - ΓN = EmbeddedBoundary(cutgeo) - dΓN = Measure(ΓN,degree) - nN = get_normal_vector(ΓN) - β = β₀*h.^(s) - a((u,p), (v,q)) = ∫(v⋅u)dΩ + ∫(p⋅q)dΩ + ∫(β*(u⋅nN)*(v⋅nN))dΓN - - dx = get_trial_fe_basis(X) - dy = get_fe_basis(Y) - - - ## FULL stabilization terms: - wu_full,ru_full,cu_full= - bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ_u, - dΩbg_cut_cells) - - wp_full,rp_full,cp_full= - bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ_p, - dΩbg_cut_cells) - - wdiv_full, rdiv_full, cdiv_full = - div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ_div, - dΩbg_cut_cells) - - assem=SparseMatrixAssembler(X,Y) - wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) - push!(wrc[1], wu_full...) - push!(wrc[2], ru_full...) - push!(wrc[3], cu_full...) - - push!(wrc[1], wp_full...) - push!(wrc[2], rp_full...) - push!(wrc[3], cp_full...) - - push!(wrc[1], wdiv_full...) - push!(wrc[2], rdiv_full...) - push!(wrc[3], cdiv_full...) - - assemble_matrix(assem, wrc) -end \ No newline at end of file diff --git a/fields_and_blocks_tools.jl b/fields_and_blocks_tools.jl deleted file mode 100644 index ff40c7f6..00000000 --- a/fields_and_blocks_tools.jl +++ /dev/null @@ -1,26 +0,0 @@ -function _restrict_to_block(cell_dof_ids::Gridap.Arrays.LazyArray{<:Fill{<:Gridap.Fields.BlockMap}}, blockid) - map=cell_dof_ids.maps.value - @assert length(map.size)==1 - @assert blockid >= 1 - @assert blockid <= map.size[1] - cell_dof_ids.args[blockid] -end - -function _get_single_field_fe_basis(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.single_field -end -function _get_single_field_fe_basis(a) - a -end -function _is_multifield_fe_basis_component(a::Gridap.MultiField.MultiFieldFEBasisComponent) - true -end -function _is_multifield_fe_basis_component(a) - false -end -function _nfields(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.nfields -end -function _fieldid(a::Gridap.MultiField.MultiFieldFEBasisComponent) - a.fieldid -end diff --git a/src/BGP/BGP.jl b/src/BGP/BGP.jl index 96cbee6e..9a87a1a2 100644 --- a/src/BGP/BGP.jl +++ b/src/BGP/BGP.jl @@ -3,8 +3,30 @@ using FillArrays using LinearAlgebra include("aggregates_bounding_boxes_tools.jl") + +export setup_aggregate_to_cells +export setup_aggregates_bounding_box_model +export flatten +export restrict_cells +export setup_cells_to_aggregate +export setup_ref_agg_cell_to_ref_bb_map +export setup_aggregate_to_local_cells +export compute_agg_cells_local_dof_ids +export compute_aggregate_dof_ids + include("bulk_ghost_penalty_stab_tools.jl") +export set_up_bulk_ghost_penalty_lhs +export bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells, bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full +export div_penalty_stabilization_collect_cell_matrix_on_cut_cells, div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full +export pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells, dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells, dmix_penalty_stabilization_collect_cell_vector_on_cut_cells + include("fields_and_blocks_tools.jl") +export _restrict_to_block +# export _restrict_to_block, _get_single_field_fe_basis, _get_single_field_fe_basis, _is_multifield_fe_basis_component, _is_multifield_fe_basis_component, _nfields, _fieldid + include("BulkGhostPenaltyAssembleMaps.jl") -include("darcy_preconditioning_tools.jl") + +# include("darcy_preconditioning_tools.jl") +# export assemble_darcy_preconditioner_matrix + diff --git a/src/GridapEmbedded.jl b/src/GridapEmbedded.jl index 8fbbde6a..458700cf 100644 --- a/src/GridapEmbedded.jl +++ b/src/GridapEmbedded.jl @@ -14,8 +14,8 @@ include("AlgoimUtils/AlgoimUtils.jl") include("Distributed/Distributed.jl") -include("BGP/BGP.jl") - include("Exports.jl") +include("BGP/BGP.jl") + end # module From dd60dfc4faedef84d97b9855e4e66f5089eeaf43 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Mon, 3 Mar 2025 18:46:58 +1100 Subject: [PATCH 067/120] included export for restrict_aggregate_to_cells --- src/BGP/BGP.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BGP/BGP.jl b/src/BGP/BGP.jl index 9a87a1a2..5bc7697a 100644 --- a/src/BGP/BGP.jl +++ b/src/BGP/BGP.jl @@ -8,6 +8,7 @@ export setup_aggregate_to_cells export setup_aggregates_bounding_box_model export flatten export restrict_cells +export restrict_aggregates_to_cells export setup_cells_to_aggregate export setup_ref_agg_cell_to_ref_bb_map export setup_aggregate_to_local_cells From e16c7bdd96aa03e10af4975c21b1fa16e357a1ed Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Mon, 3 Mar 2025 19:33:38 +1100 Subject: [PATCH 068/120] corrected typo in export --- src/BGP/BGP.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BGP/BGP.jl b/src/BGP/BGP.jl index 5bc7697a..91cfa122 100644 --- a/src/BGP/BGP.jl +++ b/src/BGP/BGP.jl @@ -8,7 +8,7 @@ export setup_aggregate_to_cells export setup_aggregates_bounding_box_model export flatten export restrict_cells -export restrict_aggregates_to_cells +export restrict_aggregate_to_cells export setup_cells_to_aggregate export setup_ref_agg_cell_to_ref_bb_map export setup_aggregate_to_local_cells From c305cfb6099d875cd0d6d4396e56af2a17564437 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 5 Mar 2025 09:33:21 +1100 Subject: [PATCH 069/120] Update CI actions --- .github/dependabot.yml | 7 ++++++ .github/workflows/ci.yml | 49 +++++++++------------------------------- 2 files changed, 18 insertions(+), 38 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..d60f0707 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" # Location of package manifests + schedule: + interval: "monthly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f316fd1c..441df67b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,21 +14,12 @@ jobs: arch: - x64 steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v1 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 - uses: julia-actions/julia-processcoverage@v1 @@ -48,21 +39,12 @@ jobs: arch: - x64 steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v1 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - run: | julia --color=yes --project=. --check-bounds=yes --depwarn=error -e ' @@ -83,21 +65,12 @@ jobs: arch: - x64 steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v1 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - run: | julia --color=yes --project=. --check-bounds=yes --depwarn=error -e ' @@ -109,8 +82,8 @@ jobs: name: Documentation runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: '1.8' - run: | From 28d4404efe000407be018af9fbc36ab9b5186620 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 5 Mar 2025 09:37:52 +1100 Subject: [PATCH 070/120] Update x86 CI actions --- .github/workflows/ci_x86.yml | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci_x86.yml b/.github/workflows/ci_x86.yml index 03ca2ab1..4415f5a5 100644 --- a/.github/workflows/ci_x86.yml +++ b/.github/workflows/ci_x86.yml @@ -20,20 +20,11 @@ jobs: arch: - x86 steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v1 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- + - uses: julia-actions/cache@v2 - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 From 921a96c156ca0cc6338aa366102b00f8e84abe91 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 5 Mar 2025 14:57:06 +1100 Subject: [PATCH 071/120] Added temp dirs --- .github/workflows/ci.yml | 8 ++++---- test/AgFEMTests/PeriodicAgFEMSpacesTests.jl | 3 ++- test/AlgoimUtilsTests/VisualizationTests.jl | 5 +++-- test/DistributedTests/AggregationTests.jl | 9 ++++----- .../DistributedDiscreteGeometryPoissonTest.jl | 7 ++++--- .../DistributedLSDiscreteGeometryPoissonTest.jl | 7 ++++--- ...eriodicDistributedDiscreteGeometryPoissonTest.jl | 7 ++++--- test/DistributedTests/PoissonTests.jl | 7 ++++--- test/DistributedTests/mpi/runtests.jl | 10 +++++----- test/DistributedTests/testing_remote_no_aggs.jl | 13 +++++++------ .../EmbeddedBimaterialPoissonCutFEMTests.jl | 5 +++-- test/GridapEmbeddedTests/TraceFEMTests.jl | 2 -- 12 files changed, 44 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 441df67b..d116b290 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: fail-fast: false matrix: version: - - '1.8' + - '1.10' os: - ubuntu-latest arch: @@ -33,7 +33,7 @@ jobs: fail-fast: false matrix: version: - - '1.8' + - '1.10' os: - ubuntu-latest arch: @@ -59,7 +59,7 @@ jobs: fail-fast: false matrix: version: - - '1.8' + - '1.10' os: - ubuntu-latest arch: @@ -85,7 +85,7 @@ jobs: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 with: - version: '1.8' + version: '1.10' - run: | julia --project=docs -e ' using Pkg diff --git a/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl index 26b34bae..9627e598 100644 --- a/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl +++ b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl @@ -40,7 +40,8 @@ U = TrialFESpace(Vagg) v(x) = (x[1]-0.5)^2 + (x[2]-0.5)^2 vhagg = interpolate(v,Vagg) -writevtk(Ω_ac,"test",cellfields=["v"=>vhagg]) +path = mktempdir() +writevtk(Ω_ac,joinpath(path,"test"),cellfields=["v"=>vhagg]) tol = 10e-7 @test sum( ∫(abs2(v-vhagg))dΩ ) < tol diff --git a/test/AlgoimUtilsTests/VisualizationTests.jl b/test/AlgoimUtilsTests/VisualizationTests.jl index 91181789..d0b52930 100644 --- a/test/AlgoimUtilsTests/VisualizationTests.jl +++ b/test/AlgoimUtilsTests/VisualizationTests.jl @@ -37,7 +37,8 @@ module VisualizationTests vquad = Quadrature(algoim,phi,degree,phase=IN) _,dΩ = TriangulationAndMeasure(Ω,vquad) - writevtk(dΓ,"res_sur",cellfields=["f"=>fₕ],qhulltype=convexhull) - writevtk([dΩ,dΓ],"res_vol",cellfields=["f"=>fₕ]) + path = mktempdir() + writevtk(dΓ,joinpath(path,"res_sur"),cellfields=["f"=>fₕ],qhulltype=convexhull) + writevtk([dΩ,dΓ],joinpath("res_vol"),cellfields=["f"=>fₕ]) end # module \ No newline at end of file diff --git a/test/DistributedTests/AggregationTests.jl b/test/DistributedTests/AggregationTests.jl index 0dff75cf..7175232b 100644 --- a/test/DistributedTests/AggregationTests.jl +++ b/test/DistributedTests/AggregationTests.jl @@ -38,8 +38,6 @@ bgf_to_ioc = compute_bgfacet_to_inoutcut(bgmodel,geo) Ω = Triangulation(cutgeo) -writevtk(Ω,"trian") - strategy = AggregateCutCellsByThreshold(1.0) aggregates,aggregate_owner,aggregate_neig = distributed_aggregate( strategy,cutgeo,geo,IN) @@ -74,9 +72,10 @@ end Ωin = Triangulation(cutgeo,IN) Γ = EmbeddedBoundary(cutgeo) -writevtk(Ωin,"trian_in") -writevtk(Γ,"bnd") -writevtk(Ωbg,"bgtrian",celldata= +path = mktempdir() +writevtk(Ωin,joinpath(path,"trian_in")) +writevtk(Γ,joinpath(path,"bnd")) +writevtk(Ωbg,joinpath(path,"bgtrian"),celldata= ["aggregate"=>oaggregates, "aggregate_owner"=>oaggregate_owner]) diff --git a/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl index 10a99591..9388124d 100644 --- a/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl +++ b/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl @@ -98,15 +98,16 @@ function main(distribute,parts; map(Reindex(col),oid) end - writevtk(Ω_bg,"trian", + path = mktempdir() + writevtk(Ω_bg,joinpath(path,"trian"), celldata=[ "aggregate"=>own_aggregates, "color"=>own_colors, "gid"=>own_to_global(gids)])#, # cellfields=["uh"=>uh]) - writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) - writevtk(Γ,"trian_G") + writevtk(Ω,joinpath(path,"trian_O"),cellfields=["uh"=>uh]) + writevtk(Γ,joinpath(path,"trian_G")) @test el2/ul2 < 1.e-8 @test eh1/uh1 < 1.e-7 diff --git a/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl index 68bbf39f..d27d8f7c 100644 --- a/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl +++ b/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl @@ -93,15 +93,16 @@ function main(distribute,parts; map(Reindex(col),oid) end - writevtk(Ω_bg,"trian", + path = mktempdir() + writevtk(Ω_bg,joinpath(path,"trian"), celldata=[ "aggregate"=>own_aggregates, "color"=>own_colors, "gid"=>own_to_global(gids)])#, # cellfields=["uh"=>uh]) - writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) - writevtk(Γ,"trian_G") + writevtk(Ω,joinpath(path,"trian_O"),cellfields=["uh"=>uh]) + writevtk(Γ,joinpath(path,"trian_G")) @test el2/ul2 < 1.e-8 @test eh1/uh1 < 1.e-7 diff --git a/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl index 26cde8c3..2c7de035 100644 --- a/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl +++ b/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl @@ -151,15 +151,16 @@ function main(distribute,parts; map(Reindex(col),oid) end - writevtk(Ω_bg,"trian", + path = mktempdir() + writevtk(Ω_bg,joinpath(path,"trian"), celldata=[ "aggregate"=>own_aggregates, "color"=>own_colors, "gid"=>own_to_global(gids)])#, # cellfields=["uh"=>uh]) - writevtk(Ω,"trian_O",cellfields=["uh"=>uh]) - writevtk(Γ,"trian_G") + writevtk(Ω,joinpath(path,"trian_O"),cellfields=["uh"=>uh]) + writevtk(Γ,joinpath(path,"trian_G")) @test el2/ul2 < 1.e-8 @test eh1/uh1 < 1.e-7 diff --git a/test/DistributedTests/PoissonTests.jl b/test/DistributedTests/PoissonTests.jl index feb6e9b2..d5ece5b9 100644 --- a/test/DistributedTests/PoissonTests.jl +++ b/test/DistributedTests/PoissonTests.jl @@ -96,15 +96,16 @@ function main(distribute,parts; map(Reindex(col),oid) end - writevtk(Ω_bg,"trian", + path = mktempdir() + writevtk(Ω_bg,joinpath(path,"trian"), celldata=[ "aggregate"=>own_aggregates, "color"=>own_colors, "gid"=>own_to_global(gids)])#, # cellfields=["uh"=>uh]) - writevtk(Ω,"trian_O",cellfields=["uh"=>uh,"eh"=>e]) - writevtk(Γ,"trian_G") + writevtk(Ω,joinpath(path,"trian_O"),cellfields=["uh"=>uh,"eh"=>e]) + writevtk(Γ,joinpath(path,"trian_G")) @test el2/ul2 < 1.e-8 @test eh1/uh1 < 1.e-7 diff --git a/test/DistributedTests/mpi/runtests.jl b/test/DistributedTests/mpi/runtests.jl index 4f2c40c9..44a1968b 100644 --- a/test/DistributedTests/mpi/runtests.jl +++ b/test/DistributedTests/mpi/runtests.jl @@ -6,8 +6,8 @@ using MPI #Sysimage sysimage=nothing if length(ARGS)==1 - @assert isfile(ARGS[1]) "$(ARGS[1]) must be a valid Julia sysimage file" - sysimage=ARGS[1] + @assert isfile(ARGS[1]) "$(ARGS[1]) must be a valid Julia sysimage file" + sysimage=ARGS[1] end mpidir = @__DIR__ @@ -17,10 +17,10 @@ repodir = joinpath(testdir,"..","..") function run_driver(procs,file,sysimage) mpiexec() do cmd if sysimage!=nothing - extra_args="-J$(sysimage)" - run(`$cmd -n $procs $(Base.julia_cmd()) $(extra_args) --project=$repodir $(joinpath(mpidir,file))`) + extra_args="-J$(sysimage)" + run(`$cmd -n $procs $(Base.julia_cmd()) $(extra_args) --project=$repodir $(joinpath(mpidir,file))`) else - run(`$cmd -n $procs $(Base.julia_cmd()) --project=$repodir $(joinpath(mpidir,file))`) + run(`$cmd -n $procs $(Base.julia_cmd()) --project=$repodir $(joinpath(mpidir,file))`) end @test true end diff --git a/test/DistributedTests/testing_remote_no_aggs.jl b/test/DistributedTests/testing_remote_no_aggs.jl index 87e5d1aa..0bee27bd 100644 --- a/test/DistributedTests/testing_remote_no_aggs.jl +++ b/test/DistributedTests/testing_remote_no_aggs.jl @@ -133,18 +133,19 @@ uh1 = h1(uh) Γ = EmbeddedBoundary(cutgeo) Ωbg = Triangulation(bgmodel) -writevtk(Ω,"trian"); -writevtk(Γ,"bnd"); -writevtk(Ωbg,"bg_trian"); -writevtk(Ω_act,"act_trian"); +path = mktempdir() +writevtk(Ω,joinpath(path,"trian")); +writevtk(Γ,joinpath(path,"bnd")); +writevtk(Ωbg,joinpath(path,"bg_trian")); +writevtk(Ω_act,joinpath(path,"act_trian")); -writevtk(Ω,"trian", +writevtk(Ω,joinpath(path,"trian"), cellfields=["uh"=>uh,"u"=>u,"e"=>e],); map(local_views(uh),local_views(bgmodel),ranks) do uh,m,p trian = Triangulation(m) - writevtk(trian,"ltrian_$p",cellfields=["uh"=>uh]) + writevtk(trian,joinpath(path,"ltrian_$p"),cellfields=["uh"=>uh]) end end # module diff --git a/test/GridapEmbeddedTests/EmbeddedBimaterialPoissonCutFEMTests.jl b/test/GridapEmbeddedTests/EmbeddedBimaterialPoissonCutFEMTests.jl index 3d3e718d..138857b5 100644 --- a/test/GridapEmbeddedTests/EmbeddedBimaterialPoissonCutFEMTests.jl +++ b/test/GridapEmbeddedTests/EmbeddedBimaterialPoissonCutFEMTests.jl @@ -103,10 +103,11 @@ uh1, uh2 = solve(op) uh = (uh1,uh2) # Postprocess +path = mktempdir() qh1 = α1*∇(uh1) qh2 = α2*∇(uh2) -writevtk(Ω1,"results1",cellfields=["uh"=>uh1,"qh"=>qh1]) -writevtk(Ω2,"results2",cellfields=["uh"=>uh2,"qh"=>qh2]) +writevtk(Ω1,joinpath(path,"results1"),cellfields=["uh"=>uh1,"qh"=>qh1]) +writevtk(Ω2,joinpath(path,"results2"),cellfields=["uh"=>uh2,"qh"=>qh2]) #writevtk(model1,"model1") #writevtk(model2,"model2") diff --git a/test/GridapEmbeddedTests/TraceFEMTests.jl b/test/GridapEmbeddedTests/TraceFEMTests.jl index 7953e8f0..0e46c7d2 100644 --- a/test/GridapEmbeddedTests/TraceFEMTests.jl +++ b/test/GridapEmbeddedTests/TraceFEMTests.jl @@ -26,8 +26,6 @@ cutgeom = cut(bgmodel,geom) Γ = EmbeddedBoundary(cutgeom,geom) Γg = GhostSkeleton(cutgeom,CUT,geom) -writevtk(Γg,"Γg") - order=1 V = TestFESpace(Ωc,ReferenceFE(lagrangian,Float64,order),conformity=:H1) U = TrialFESpace(V) From fd4893e4c11f80a452e270f83068e64e7725a288 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 04:32:19 +0000 Subject: [PATCH 072/120] Bump codecov/codecov-action from 1 to 5 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 1 to 5. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v1...v5) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d116b290..c015fee3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v5 with: file: lcov.info drivers: From 7274c837eab42ffbaefb5e67e36d8d0d40881ae9 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Wed, 5 Mar 2025 15:35:53 +1100 Subject: [PATCH 073/120] Swapped LightGraphs for Graphs --- Project.toml | 4 ++-- src/AgFEM/AgFEM.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index 08903581..f651a887 100644 --- a/Project.toml +++ b/Project.toml @@ -9,9 +9,9 @@ Algoim = "0eb9048c-21de-4c7a-bfac-056de1940b74" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" +Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" Gridap = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" GridapDistributed = "f9701e48-63b3-45aa-9a63-9bc6c271f355" -LightGraphs = "093fc24a-ae57-5d10-9952-331d41423f4d" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" MiniQhull = "978d7f02-9e05-4691-894f-ae31a51d76ca" @@ -26,9 +26,9 @@ Algoim = "0.2.2" Combinatorics = "1" CxxWrap = "0.16" FillArrays = "0.10, 0.11, 0.12, 0.13, 1" +Graphs = "1.12.0" Gridap = "0.17, 0.18" GridapDistributed = "0.3, 0.4" -LightGraphs = "1.3.3" MPI = "0.20" MiniQhull = "0.1.0, 0.2, 0.3, 0.4" PartitionedArrays = "0.3.4" diff --git a/src/AgFEM/AgFEM.jl b/src/AgFEM/AgFEM.jl index 72fed372..187f1162 100644 --- a/src/AgFEM/AgFEM.jl +++ b/src/AgFEM/AgFEM.jl @@ -1,6 +1,6 @@ module AgFEM -using LightGraphs +using Graphs using LinearAlgebra using Gridap From 23c57241fa0253b8c4ad648a968c87bbd5492cf3 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Wed, 19 Mar 2025 09:27:52 +1100 Subject: [PATCH 074/120] removed old unused argument (h_U) --- src/BGP/bulk_ghost_penalty_stab_tools.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/BGP/bulk_ghost_penalty_stab_tools.jl b/src/BGP/bulk_ghost_penalty_stab_tools.jl index e620a5ef..b81334c3 100644 --- a/src/BGP/bulk_ghost_penalty_stab_tools.jl +++ b/src/BGP/bulk_ghost_penalty_stab_tools.jl @@ -16,7 +16,6 @@ function bulk_ghost_penalty_stabilization_collect_cell_matrix(aggregate_to_local Ωagg_cell_dof_ids, agg_cells_local_dof_ids, agg_cells_to_aggregate_dof_ids, - h_U, γ) @@ -347,7 +346,6 @@ function div_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, U_Ωagg_cell_dof_ids, U_agg_cells_local_dof_ids, U_agg_cells_to_aggregate_dof_ids, - h_U, γ) Ωagg_cells=dΩagg_cells.quad.trian From abf88f05c9adbfeacd38df696c770edd29b858d9 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Thu, 3 Apr 2025 10:00:32 +1100 Subject: [PATCH 075/120] updated the bulk ghost stab tools to allow for more general use. Validated the canvas with earlier results. All working except for qdivu term --- bulk_ghost_penalty_canvas.jl | 656 ++++++----- src/BGP/BGP.jl | 12 +- src/BGP/bulk_ghost_penalty_stab_tools.jl | 1259 ++++++---------------- 3 files changed, 642 insertions(+), 1285 deletions(-) diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index 90b73d8e..e44fc255 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -122,21 +122,7 @@ vbb=get_fe_basis(Vbb) # Numerical integration (Measures) dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) -# LHS of L2 projection on bounding boxes. -aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) -p_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - pbb, - qbb) - -u_lhs=set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - ubb, - vbb) +# # LHS of L2 projection on bounding boxes. # Selecting relevant global dofs ids of aggregate cells (from background mesh) Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) @@ -144,6 +130,7 @@ U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) # Computing local (per aggregate) dof ids +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) U_agg_cells_local_dof_ids= compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) P_agg_cells_local_dof_ids= @@ -157,7 +144,6 @@ P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells # parameters γ = 10.0 # Interior bulk-penalty stabilization parameter -h_U = 1.0 ########################################### ### STABILIZATION ON Ωagg\Troot ### @@ -180,190 +166,229 @@ cut_cells_to_aggregate = setup_cells_to_aggregate(aggregate_to_cut_cells) U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_to_aggregate) P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_to_aggregate) -# Compute stabilization terms for u and p -wu,ru,cu=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp,rp,cp=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) -#DIV stabilization part -wdiv, rdiv, cdiv = div_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basisr - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -## FULL stabilization terms: -wu_full,ru_full,cu_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wp_full,rp_full,cp_full=bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -wdiv_full, rdiv_full, cdiv_full = div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - -# MIXED STAB TERMS -wpmix, rpmix, cpmix = pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - dv) - -wdmix, rdmix, cdmix = dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - du) - ########################################### -### VISUALIZATION ### +### Setup projections ########################################### -# writevtk(Ωbg,"trian-bg") -# writevtk(Ωbg_cut_cells,"trian-bg-cut-cells") -# colors = color_aggregates(aggregates,bgmodel) -# writevtk(Ωbg,"trian-bg-with-coloured-aggregates", celldata=["aggregate"=>aggregates,"color"=>colors]) -# writevtk(Ωbg_agg_cells,"trian-bg-agg-cells") -# Ωbg_int_cells=view(Ωbg,int_cells) -# Ωbg_root_cells=view(Ωbg,root_cells) -# writevtk(Ωbg_int_cells,"trian-bg-int-cells") -# writevtk(Ωbg_root_cells,"trian-bg-root-cells") -# writevtk(Ω,"trian-phys") -# writevtk(Ωact,"trian-act") -function compute_quantities(problem,A,b,dΩ) - cond_A = cond(Array(A)) - norm_A = norm(A) - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - if problem==1 - area = sum(∫(1.0)dΩ) - mean_p = sum(∫(pex)dΩ)/area # mean presure exact sol - ph = ph + mean_p - end - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - norm_euh = sum(∫(euh⋅euh)*dΩ) - norm_eph = sum(∫(eph*eph)*dΩ) - norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) - return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) +du_proj_Vbb, dv_proj_Vbb = setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + du, # Trial basis (to project) + dv, # Test basis + ubb, # Trial basis of bounding box space Vbb + vbb, # Test basis of bounding box space Vbb + identity, # operation to be applied to u and v + U_agg_cells_local_dof_ids) # aggregates local dof ids for space U + +dp_proj_Qbb, dq_proj_Qbb = setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + dp, # Trial basis (to project) + dq, # Test basis + pbb, # Trial basis of bounding box space Qbb + qbb, # Test basis of bounding box space Qbb + identity, # operation to be applied to u and v + P_agg_cells_local_dof_ids) # aggregates local dof ids for space P + +div_du_proj_Vbb, div_dv_proj_Vbb = setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + du, # Trial basis (to project) + dv, # Test basis + pbb, # Trial basis of bounding box space Vbb + qbb, # Test basis of bounding box space Vbb + divergence, # operation to be applied to u and v + U_agg_cells_local_dof_ids) # aggregates local dof ids for space U + +# ########################################### +# ### BlockMap PREP STEPS #TODO MOVE INTO collect_cell_matrix_on_D? +# ########################################### +if (_is_multifield_fe_basis_component(dv)) + nfields=_nfields(dv) + fieldid=_fieldid(dv) + U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) end -function plot_quantities(problem,A,b,Ω;filename="results") - sol_x = A\b - xh = FEFunction(X, sol_x) - uh,ph = xh - if problem==1 - area = sum(∫(1.0)dΩ) - mean_p = sum(∫(pex)dΩ)/area # mean presure exact sol - ph = ph_zm + mean_p - end - euh = uex-uh - eph = pex-ph - edivuh = divuex-(∇⋅uh) - writevtk(Ω,filename,cellfields=["uh"=>uh,"ph"=>ph,"divuh"=>(∇⋅uh),"euh"=>euh,"eph"=>eph,"edivuh"=>edivuh]) +if (_is_multifield_fe_basis_component(du)) + nfields=_nfields(du) + fieldid=_fieldid(du) + U_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) +end + +if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) end -## RHS STAB -# rhs_g = divuex # TODO: pass function on rather than constant value!!!!! -vecw_dmix, vecr_dmix = dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(aggregate_to_local_cells,agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, +if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) +end + +########################################## +### Setup stabilization terms (DIFF) ### +########################################## +w_u_diff, r_u_diff, c_u_diff = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + du, + dv, + du_proj_Vbb, + dv_proj_Vbb, + U_Ωbg_cut_cell_dof_ids, + U_Ωbg_cut_cell_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + identity, + identity) + +w_p_diff, r_p_diff, c_p_diff = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + dp, + dq, + dp_proj_Qbb, + dq_proj_Qbb, + P_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + identity, + identity) + +w_divu_diff, r_divu_diff, c_divu_diff = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + du, + dv, + div_du_proj_Vbb, + div_dv_proj_Vbb, + U_Ωbg_cut_cell_dof_ids, + U_Ωbg_cut_cell_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + divergence, + divergence) + +w_divuq_diff, r_divuq_diff, c_divuq_diff = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + du, + dq, + div_du_proj_Vbb, + dq_proj_Qbb, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + divergence, + identity) + +w_pdivv_diff, r_pdivv_diff, c_pdivv_diff = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + dp, + dv, + dp_proj_Qbb, + div_dv_proj_Vbb, P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, + U_Ωbg_cut_cell_dof_ids, P_cut_cells_to_aggregate_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + identity, + divergence) + +########################################## +### Setup stabilization terms (FULL) ### +########################################## +w_u_full, r_u_full, c_u_full = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, γ, - dΩbg_cut_cells, - divuex) + du, + dv, + du_proj_Vbb, + U_Ωbg_cut_cell_dof_ids, + U_Ωbg_cut_cell_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + identity, + identity) + +w_p_full, r_p_full, c_p_full = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + dp, + dq, + dp_proj_Qbb, + P_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + identity, + identity) + +w_divu_full, r_divu_full, c_divu_full = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + du, + dv, + div_du_proj_Vbb, + U_Ωbg_cut_cell_dof_ids, + U_Ωbg_cut_cell_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + divergence, + divergence) + +w_divuq_full, r_divuq_full, c_divuq_full = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + du, + dq, + div_du_proj_Vbb, + U_Ωbg_cut_cell_dof_ids, + P_Ωbg_cut_cell_dof_ids, + U_cut_cells_to_aggregate_dof_ids, + divergence, + identity) + +w_pdivv_full, r_pdivv_full, c_pdivv_full = bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dΩbg_cut_cells, + Ωbg_agg_cells, + γ, + dp, + dv, + dp_proj_Qbb, + P_Ωbg_cut_cell_dof_ids, + U_Ωbg_cut_cell_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + identity, + divergence) + +########################################## +### Setup rhs stabilization ### +########################################## +w_rhsq_diff, r_rhsq_diff = bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dΩbg_cut_cells, + γ, + dq, + dq_proj_Qbb, + P_Ωbg_cut_cell_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + identity, + divuex) + +w_rhsq_full, r_rhsq_full = bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dΩbg_cut_cells, + γ, + dq, + P_Ωbg_cut_cell_dof_ids, + identity, + divuex) ## WEAK FORM if problem==0 @@ -387,187 +412,146 @@ end assem=SparseMatrixAssembler(X,Y) b = assemble_vector(l, Y) -#RHS_DMIX -vec_wr=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) -push!(vec_wr[1],vecw_dmix...) -push!(vec_wr[2],vecr_dmix...) -vec_b = assemble_vector(assem, vec_wr) +# RHS +vec_rhsq_diff=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) +push!(vec_rhsq_diff[1],w_rhsq_diff...) +push!(vec_rhsq_diff[2],r_rhsq_diff...) +b_rhsq_diff = assemble_vector(assem, vec_rhsq_diff) -# NO STAB -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -A = assemble_matrix(assem, wrc) -res_nostab = compute_quantities(problem,A,b,dΩ) +vec_rhsq_full=Gridap.FESpaces.collect_cell_vector(Y,l(dy)) +push!(vec_rhsq_full[1],w_rhsq_full...) +push!(vec_rhsq_full[2],r_rhsq_full...) +b_rhsq_full = assemble_vector(assem, vec_rhsq_full) -# ONLY U -wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -A = assemble_matrix(assem, wrc) -res_stab_u = compute_quantities(problem,A,b,dΩ) +function compute_quantities(problem,A,b,dΩ) + cond_A = cond(Array(A)) + norm_A = norm(A) + sol_x = A\b + xh = FEFunction(X, sol_x) + uh,ph = xh + if problem==1 + area = sum(∫(1.0)dΩ) + mean_p = sum(∫(pex)dΩ)/area # mean presure exact sol + ph = ph + mean_p + end + euh = uex-uh + eph = pex-ph + edivuh = divuex-(∇⋅uh) + norm_euh = sum(∫(euh⋅euh)*dΩ) + norm_eph = sum(∫(eph*eph)*dΩ) + norm_edivuh = sum(∫(edivuh⋅edivuh)*dΩ) + return round(cond_A,sigdigits=3), round(norm_A,sigdigits=3), round(norm_euh,sigdigits=3), round(norm_eph,sigdigits=3), round(norm_edivuh,sigdigits=3) +end -# ONLY U FULL +####### SOLVING TEST PROBLEMS (DIFF) + +# NO STAB DIFF wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) A = assemble_matrix(assem, wrc) -res_stab_ufull = compute_quantities(problem,A,b,dΩ) +res_nostab = compute_quantities(problem,A,b,dΩ) -# ONLY P +# ONLY U DIFF wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) +push!(wrc[1], w_u_diff...) +push!(wrc[2], r_u_diff...) +push!(wrc[3], c_u_diff...) A = assemble_matrix(assem, wrc) -res_stab_p = compute_quantities(problem,A,b,dΩ) +res_stab_u_diff = compute_quantities(problem,A,b,dΩ) -# ONLY PFULL +# ONLY P DIFF wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) +push!(wrc[1], w_p_diff...) +push!(wrc[2], r_p_diff...) +push!(wrc[3], c_p_diff...) A = assemble_matrix(assem, wrc) -res_stab_pfull = compute_quantities(problem,A,b,dΩ) +res_stab_p_diff = compute_quantities(problem,A,b,dΩ) -# ONLY DIV +# ONLY DIVU DIFF wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) +push!(wrc[1], w_divu_diff...) +push!(wrc[2], r_divu_diff...) +push!(wrc[3], c_divu_diff...) A = assemble_matrix(assem, wrc) -res_stab_div = compute_quantities(problem,A,b,dΩ) +res_stab_divu_diff = compute_quantities(problem,A,b,dΩ) -# ONLY DIVU FULL +# ONLY DIVUQ DIFF wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) +push!(wrc[1], w_divuq_diff...) +push!(wrc[2], r_divuq_diff...) +push!(wrc[3], c_divuq_diff...) A = assemble_matrix(assem, wrc) -res_stab_divfull = compute_quantities(problem,A,b,dΩ) +res_stab_divuq_diff = compute_quantities(problem,A,b,dΩ) +res_stab_divuq_diff_rhs = compute_quantities(problem,A,b_rhsq_diff,dΩ) -# ONLY PMIX +# ONLY PDIVV DIFF wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) +push!(wrc[1], w_pdivv_diff...) +push!(wrc[2], r_pdivv_diff...) +push!(wrc[3], c_pdivv_diff...) A = assemble_matrix(assem, wrc) -res_stab_pmix = compute_quantities(problem,A,b,dΩ) +res_stab_pdivv_diff = compute_quantities(problem,A,b,dΩ) + +####### SOLVING TEST PROBLEMS (FULL) -# ONLY DMIX +# ONLY U FULL wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) +push!(wrc[1], w_u_full...) +push!(wrc[2], r_u_full...) +push!(wrc[3], c_u_full...) A = assemble_matrix(assem, wrc) -res_stab_dmix = compute_quantities(problem,A,vec_b,dΩ) +res_stab_u_full = compute_quantities(problem,A,b,dΩ) -# U + P + DIVU +# ONLY P FULL wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wp...) -push!(wrc[2], rp...) -push!(wrc[3], cp...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) +push!(wrc[1], w_p_full...) +push!(wrc[2], r_p_full...) +push!(wrc[3], c_p_full...) A = assemble_matrix(assem, wrc) -res_stab_updivu = compute_quantities(problem,A,b,dΩ) +res_stab_p_full = compute_quantities(problem,A,b,dΩ) -# UFULL + PFULL + DIVUFULL +# ONLY DIVU FULL wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wp_full...) -push!(wrc[2], rp_full...) -push!(wrc[3], cp_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) +push!(wrc[1], w_divu_full...) +push!(wrc[2], r_divu_full...) +push!(wrc[3], c_divu_full...) A = assemble_matrix(assem, wrc) -res_stab_ufullpfulldivufull = compute_quantities(problem,A,b,dΩ) - -if problem==1 - P=assemble_darcy_preconditioner_matrix(cutgeo, degree, X, Y, s, h, β₀, - aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dΩbg_cut_cells, - # FLUX-RELATED DATA - dv, # Test basis - du, # Trial basis (to project) - vbb, # Bounding box space test basis - u_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - # PRESSURE-RELATED DATA - dq, # Test basis - dp, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - # DIV-RELATED DbTA - γ) - evals = eigvals(Array(A),Array(P)) - println("Preconditioned condition number: ", abs(evals[end])/abs(evals[1])) -end +res_stab_divu_full = compute_quantities(problem,A,b,dΩ) -# U + DIVU + PMIX + DMIX +# ONLY DIVUQ FULL wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu...) -push!(wrc[2], ru...) -push!(wrc[3], cu...) -push!(wrc[1], wdiv...) -push!(wrc[2], rdiv...) -push!(wrc[3], cdiv...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) +push!(wrc[1], w_divuq_full...) +push!(wrc[2], r_divuq_full...) +push!(wrc[3], c_divuq_full...) A = assemble_matrix(assem, wrc) -res_stab_udivupmixdmix = compute_quantities(problem,A,vec_b,dΩ) +res_stab_divuq_full = compute_quantities(problem,A,b,dΩ) +res_stab_divuq_full_rhs = compute_quantities(problem,A,b_rhsq_full,dΩ) -# UFULL + DIVUFULL + PMIX + DMIX +# ONLY PDIVV FULL wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) -push!(wrc[1], wu_full...) -push!(wrc[2], ru_full...) -push!(wrc[3], cu_full...) -push!(wrc[1], wdiv_full...) -push!(wrc[2], rdiv_full...) -push!(wrc[3], cdiv_full...) -push!(wrc[1], wpmix...) -push!(wrc[2], rpmix...) -push!(wrc[3], cpmix...) -push!(wrc[1], wdmix...) -push!(wrc[2], rdmix...) -push!(wrc[3], cdmix...) +push!(wrc[1], w_pdivv_full...) +push!(wrc[2], r_pdivv_full...) +push!(wrc[3], c_pdivv_full...) A = assemble_matrix(assem, wrc) -res_stab_ufulldivufullpmixdmix = compute_quantities(problem,A,vec_b,dΩ) +res_stab_pdivv_full = compute_quantities(problem,A,b,dΩ) -## PRINT DATA: +## GENERATE EXCEL SHEET RESULTS`` print("results") res_nostab -res_stab_u -res_stab_ufull -res_stab_p -res_stab_pfull -res_stab_div -res_stab_divfull -res_stab_pmix -res_stab_dmix -print("") -res_stab_updivu -res_stab_ufullpfulldivufull -res_stab_udivupmixdmix -res_stab_ufulldivufullpmixdmix \ No newline at end of file +res_stab_u_full +res_stab_u_diff +res_stab_p_full +res_stab_p_diff +res_stab_divu_full +res_stab_divu_diff +res_stab_pdivv_full # THIS IS OK. +res_stab_divuq_full_rhs #THIS SEEMS TO BE INCORRECT + +# Alternatives for res_stab_divuq_full_rhs +res_stab_divuq_full #THIS SEEMS BETTER +res_stab_divuq_diff #not too relevant +res_stab_divuq_full_rhs # seems incorrect +res_stab_divuq_diff_rhs # seems incorrect + +# Lastly compare these: +res_stab_pdivv_full +res_stab_pdivv_diff \ No newline at end of file diff --git a/src/BGP/BGP.jl b/src/BGP/BGP.jl index 91cfa122..c1ef960a 100644 --- a/src/BGP/BGP.jl +++ b/src/BGP/BGP.jl @@ -16,18 +16,12 @@ export compute_agg_cells_local_dof_ids export compute_aggregate_dof_ids include("bulk_ghost_penalty_stab_tools.jl") -export set_up_bulk_ghost_penalty_lhs -export bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells, bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full -export div_penalty_stabilization_collect_cell_matrix_on_cut_cells, div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full -export pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells, dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells, dmix_penalty_stabilization_collect_cell_vector_on_cut_cells +export setup_L2_proj_in_bb_space +export bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D +export bulk_ghost_penalty_stabilization_collect_cell_vector_on_D include("fields_and_blocks_tools.jl") export _restrict_to_block -# export _restrict_to_block, _get_single_field_fe_basis, _get_single_field_fe_basis, _is_multifield_fe_basis_component, _is_multifield_fe_basis_component, _nfields, _fieldid include("BulkGhostPenaltyAssembleMaps.jl") -# include("darcy_preconditioning_tools.jl") -# export assemble_darcy_preconditioner_matrix - - diff --git a/src/BGP/bulk_ghost_penalty_stab_tools.jl b/src/BGP/bulk_ghost_penalty_stab_tools.jl index b81334c3..286739fc 100644 --- a/src/BGP/bulk_ghost_penalty_stab_tools.jl +++ b/src/BGP/bulk_ghost_penalty_stab_tools.jl @@ -1,1027 +1,406 @@ """ - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + returns the L2 projection in the bounding box space of the trial `u` and test `v` functions after `operation` (e.g. identity or divergence) has been applied. That is, the L2 projection is defined through - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (long version) - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) + ∫ (operation(u) - Π_{Zbb}(operation(u)) zbb dΩbg_agg_cells = 0 ∀ zbb ∈ Zbb(T), + + with T ∈ T_agg and `Zbb` the bounding box space. Note that Ωbg_agg_cells ⊆ Ωbg_bb. Additionally, Π_{Zbb}(operation(u)) appears on the lhs as the trial function wbb ∈ Zbb. """ -function bulk_ghost_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωagg_cell_dof_ids, - agg_cells_local_dof_ids, - agg_cells_to_aggregate_dof_ids, - γ) - - - Ωagg_cells=dΩagg_cells.quad.trian - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωagg_cells=change_domain_bb_to_agg_cells(dvbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωagg_cells⋅du_single_field)dΩagg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, - dΩagg_cells.quad.trian, - ReferenceDomain()) - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩagg_cells) - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωagg_cell_dof_ids) - end - push!(w, dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, Ωagg_cell_dof_ids) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - - proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩagg_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),agg_cells_to_aggregate_dof_ids) - end +function setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + u, # Trial basis (to project) + v, # Test basis + wbb, # Trial basis of bounding box space Zbb + zbb, # Test basis of bounding box space Zbb + operation, # operation to be applied to u and v + U_agg_cells_local_dof_ids) # aggregates local dof ids for space U - push!(w, proj_dv_du_mat_contribs) - push!(r, Ωagg_cell_dof_ids) - push!(c, agg_cells_to_aggregate_dof_ids) - - w, r, c -end - -## Create collect function on cut cells only -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells -""" -function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωbg_cut_cell_dof_ids, - agg_cells_local_dof_ids, - cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - + # (0) Obtain triangulation of aggregate cell domain from its measure Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dvbb, + # (1) Change domain of zbb (test function of Zbb) from Ωbb to Ωbg_agg_cells + zbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(zbb, ref_agg_cell_to_ref_bb_map, Ωbg_agg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωbg_agg_cells⋅du_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) + agg_cells_to_aggregate) - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩbg_cut_cells) - - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωbg_cut_cell_dof_ids) - end - push!(w, dv_du_mat_contribs) - push!(r, Ωbg_cut_cell_dof_ids) - push!(c, Ωbg_cut_cell_dof_ids) - - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωbg_agg_cells,ReferenceDomain()) - - proj_dv_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),cut_cells_to_aggregate_dof_ids) - end - - push!(w, proj_dv_du_mat_contribs) - push!(r, Ωbg_cut_cell_dof_ids) - push!(c, cut_cells_to_aggregate_dof_ids) - - w, r, c -end - -## Create collect function on cut cells only -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (dv-dv_l2_proj_agg_cells)*(du-du_l2_proj_agg_cells))*dΩ_cut_cells -""" -function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - dvbb, # Bounding box space test basis - lhs, - Ωbg_cut_cell_dof_ids, - agg_cells_local_dof_ids, - cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## (I) Compute projections dv_l2_proj_agg_cells & du_l2_proj_agg_cells - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dvbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dvbb, + # (2) Change domain of wbb (trial function of Zbb) from Ωbb to Ωbg_agg_cells + wbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(wbb, ref_agg_cell_to_ref_bb_map, Ωbg_agg_cells, - agg_cells_to_aggregate) - - du_single_field=_get_single_field_fe_basis(du) - agg_cells_rhs_contribs=get_array(∫(dvbb_Ωbg_agg_cells⋅du_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(agg_cells_local_dof_ids,agg_cells_rhs_contribs) + agg_cells_to_aggregate) + # (3) TODO: Compute & assemble contributions to LHS of L2 projection + agg_cells_to_lhs_contribs=get_array(∫(zbb_Ωbg_agg_cells⋅wbb_Ωbg_agg_cells)dΩbg_agg_cells) + ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) + lhs = lazy_map(ass_lhs_map,aggregate_to_local_cells) + + # (4) Compute & assemble contributions to RHS of L2 projection + op_u_single_field = operation(_get_single_field_fe_basis(u)) + agg_cells_rhs_contribs=get_array(∫(zbb_Ωbg_agg_cells⋅op_u_single_field)dΩbg_agg_cells) + ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - # TO-DO: optimize using our own optimized version Gridap.Fields.Map + # (5) TO-DO: optimize using our own optimized version Gridap.Fields.Map # of backslash that re-uses storage for lu factors among cells, etc. - dv_l2_proj_bb_dofs=lazy_map(\,lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(dvbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dv_l2_proj_bb_array),agg_cells_to_aggregate), + op_v_proj_Zbb_dofs=lazy_map(\,lhs,rhs) + + # (6) Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of operation(u) restricted to the cells + # included in the bounding box of the aggregate. + op_v_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, + op_v_proj_Zbb_dofs, + Gridap.CellData.get_data(zbb)) + + # (7) Change domain of proj_op_u and proj_op_v from Ωbb to Ωbg_agg_cells + op_v_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(op_v_proj_Zbb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) - - du_l2_proj_bb_array_agg_cells=lazy_map(transpose, dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(du) - du_l2_proj_bb_array_agg_cells=lazy_map( + op_u_proj_Zbb_array_agg_cells=lazy_map(transpose, op_v_proj_Zbb_array_agg_cells) + if (_is_multifield_fe_basis_component(u)) + @assert _is_multifield_fe_basis_component(v) + @assert _nfields(u)==_nfields(v) + nfields=_nfields(u) + fieldid=_fieldid(u) + op_u_proj_Zbb_array_agg_cells=lazy_map( Gridap.Fields.BlockMap((1,nfields),fieldid), - du_l2_proj_bb_array_agg_cells) + op_u_proj_Zbb_array_agg_cells) end + op_u_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(op_u_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + + if (_is_multifield_fe_basis_component(v)) + @assert _is_multifield_fe_basis_component(v) + @assert _nfields(u)==_nfields(v) + nfields=_nfields(v) + fieldid=_fieldid(v) + op_v_proj_Zbb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + op_v_proj_Zbb_array_agg_cells) + end - if (_is_multifield_fe_basis_component(dv)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - dv_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - dv_l2_proj_bb_array_agg_cells) - end - - du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(du_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dv_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),cut_cells_to_aggregate_dof_ids) - end - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - ## (1) dv*du term - dv_du_mat_contribs=get_array(∫(γ*dv⋅du)*dΩbg_cut_cells) - - push!(w, dv_du_mat_contribs) - push!(r, Ωbg_cut_cell_dof_ids) - push!(c, Ωbg_cut_cell_dof_ids) - - ## (2) dv*proj_du term - # In the MultiField case, I have had to add this change domain - # call before setting up the term right below. Otherwise, we get an error - # when trying to multiply the fields. Not sure why this is happening - dvΩagg_cells=Gridap.CellData.change_domain(dv,Ωbg_agg_cells,ReferenceDomain()) - - dv_proj_du_mat_contribs=get_array(∫(γ*(-1.0)*dvΩagg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, dv_proj_du_mat_contribs) - push!(r, Ωbg_cut_cell_dof_ids) - push!(c, cut_cells_to_aggregate_dof_ids) - - ## (3) proj_dv*proj_du - proj_dv_proj_du_mat_contribs=get_array(∫(γ*dv_l2_proj_agg_cells⋅(du_l2_proj_agg_cells))*dΩbg_cut_cells) + op_v_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(op_v_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - push!(w, proj_dv_proj_du_mat_contribs) - push!(r, cut_cells_to_aggregate_dof_ids) - push!(c, cut_cells_to_aggregate_dof_ids) + op_u_proj_Zbb_agg_cells, op_v_proj_Zbb_agg_cells +end - ## (4) proj_dv*du - duΩagg_cells=Gridap.CellData.change_domain(du,Ωbg_agg_cells,ReferenceDomain()) - proj_dv_du_mat_contribs=get_array(∫(-γ*dv_l2_proj_agg_cells⋅duΩagg_cells)*dΩbg_cut_cells) +# TODO: the following is not working yet: +# """ +# returns the L2 projection in the bounding box space of a function `f`. That is, the L2 projection is defined through + +# ∫ (f - Π_{Zbb}(f) zbb dΩbg_agg_cells = 0 ∀ zbb ∈ Zbb(T), + +# with T ∈ T_agg and `Zbb` the bounding box space. Note that Ωbg_agg_cells ⊆ Ωbg_bb. Additionally, Π_{Zbb}(f) appears on the lhs as the trial function wbb ∈ Zbb. +# """ +# function setup_L2_proj_in_bb_space( +# dΩbg_agg_cells, # measure of aggregated cells in background domain +# ref_agg_cell_to_ref_bb_map, # map +# agg_cells_to_aggregate, # +# aggregate_to_local_cells, # +# f, +# u, # Trial basis (to project) +# v, # Test basis +# wbb, # Trial basis of bounding box space Zbb +# zbb, # Test basis of bounding box space Zbb +# operation, # operation to be applied to u and v +# U_agg_cells_local_dof_ids) # aggregates local dof ids for space U + +# # (0) Obtain triangulation of aggregate cell domain from its measure +# Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + +# # (1) Change domain of zbb (test function of Zbb) from Ωbb to Ωbg_agg_cells +# zbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(zbb, +# ref_agg_cell_to_ref_bb_map, +# Ωbg_agg_cells, +# agg_cells_to_aggregate) + +# # (2) Change domain of wbb (trial function of Zbb) from Ωbb to Ωbg_agg_cells +# wbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(wbb, +# ref_agg_cell_to_ref_bb_map, +# Ωbg_agg_cells, +# agg_cells_to_aggregate) +# # (3) TODO: Compute & assemble contributions to LHS of L2 projection +# agg_cells_to_lhs_contribs=get_array(∫(zbb_Ωbg_agg_cells⋅wbb_Ωbg_agg_cells)dΩbg_agg_cells) +# ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) +# lhs = lazy_map(ass_lhs_map,aggregate_to_local_cells) + +# # (4) Compute & assemble contributions to RHS of L2 projection +# op_u_single_field = operation(_get_single_field_fe_basis(u)) +# agg_cells_rhs_contribs=get_array(∫(zbb_Ωbg_agg_cells⋅op_u_single_field)dΩbg_agg_cells) +# ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) +# rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) + +# # (5) TO-DO: optimize using our own optimized version Gridap.Fields.Map +# # of backslash that re-uses storage for lu factors among cells, etc. +# op_v_proj_Zbb_dofs=lazy_map(\,lhs,rhs) + +# # (6) Generate bb-wise array of fields. For each aggregate's bounding box, +# # it provides the l2 projection of operation(u) restricted to the cells +# # included in the bounding box of the aggregate. +# op_v_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, +# op_v_proj_Zbb_dofs, +# Gridap.CellData.get_data(zbb)) + +# # (7) Change domain of proj_op_u and proj_op_v from Ωbb to Ωbg_agg_cells +# op_v_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), +# lazy_map(Reindex(op_v_proj_Zbb_array),agg_cells_to_aggregate), +# ref_agg_cell_to_ref_bb_map) +# op_u_proj_Zbb_array_agg_cells=lazy_map(transpose, op_v_proj_Zbb_array_agg_cells) +# if (_is_multifield_fe_basis_component(u)) +# @assert _is_multifield_fe_basis_component(v) +# @assert _nfields(u)==_nfields(v) +# nfields=_nfields(u) +# fieldid=_fieldid(u) +# op_u_proj_Zbb_array_agg_cells=lazy_map( +# Gridap.Fields.BlockMap((1,nfields),fieldid), +# op_u_proj_Zbb_array_agg_cells) +# end +# op_u_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(op_u_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + +# if (_is_multifield_fe_basis_component(v)) +# @assert _is_multifield_fe_basis_component(v) +# @assert _nfields(u)==_nfields(v) +# nfields=_nfields(v) +# fieldid=_fieldid(v) +# op_v_proj_Zbb_array_agg_cells=lazy_map( +# Gridap.Fields.BlockMap(nfields,fieldid), +# op_v_proj_Zbb_array_agg_cells) +# end + +# op_v_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(op_v_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + +# op_u_proj_Zbb_agg_cells, op_v_proj_Zbb_agg_cells +# end - push!(w, proj_dv_du_mat_contribs) - push!(r, cut_cells_to_aggregate_dof_ids) - push!(c, Ωbg_cut_cell_dof_ids) +""" + Compute and assemble the bulk penalty stabilization term - w, r, c -end + γ ∫( (operation_u(u) - proj_op_u)⊙(operation_v(v) - proj_op_v) )*dD -function div_penalty_stabilization_collect_cell_matrix(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωagg_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_agg_cells_to_aggregate_dof_ids, - γ) - Ωagg_cells=dΩagg_cells.quad.trian + with `u` and `v` the trial and test basis functions (which may be components of a MultiField) and do not have to belong to the same space. The operations `operation_u` and `operation_v` (e.g. identity or divergence) are applied to u and v, respectively. The L2 projections `proj_op_u` and `proj_op_v` can be computed via `setup_L2_proj_in_bb_space` and are to be passed as arguments. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. +""" +function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dD, + Ωbg_agg_cells, + γ, + u, + v, + proj_op_u, + proj_op_v, + dof_ids_u, + dof_ids_v, + dof_ids_proj_u, + dof_ids_proj_v, + operation_u, + operation_v) + + # # BlockMap preparatory steps for the dof ids + # if (_is_multifield_fe_basis_component(u)) + # nfields=_nfields(u) + # fieldid=_fieldid(u) + # dof_ids_u=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_u) + # end + # if (_is_multifield_fe_basis_component(v)) + # nfields=_nfields(v) + # fieldid=_fieldid(v) + # dof_ids_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_v) + # end + # if (_is_multifield_fe_basis_component(u)) + # nfields=_nfields(u) + # fieldid=_fieldid(u) + # dof_ids_proj_u=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_proj_u) + # end + # if (_is_multifield_fe_basis_component(v)) + # nfields=_nfields(v) + # fieldid=_fieldid(v) + # dof_ids_proj_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_proj_v) + # end - ## +DIVU STABILIZATION - ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩ_agg_cells (simplified, equivalent version) # Manually set up the arrays that collect_cell_matrix would return automatically w = [] r = [] c = [] - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωagg_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωagg_cell_dof_ids) - end - - ## (I) Let's set up the div_dv_div_du_mat_contribs - # (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩ_agg_cells - div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩagg_cells) - push!(w, div_dv_div_du_mat_contribs) - push!(r, U_Ωagg_cell_dof_ids) - push!(c, U_Ωagg_cell_dof_ids) - div_du=∇⋅(_get_single_field_fe_basis(du)) - - ### Compute Π_Q_bb(div_du) - dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωagg_cells,agg_cells_to_aggregate) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩagg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - div_dv_l2_proj_bb_dofs, - Gridap.CellData.get_data(qbb)) - - div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) + # (1) op_u⊙op_v term + op_u_op_v_mat_contribs=get_array(∫(γ*operation_u(u)⊙operation_v(v))*dD) + push!(w, op_u_op_v_mat_contribs) + push!(r, dof_ids_v) + push!(c, dof_ids_u) - div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(du) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(dv) - div_du_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((fieldid,nfields),fieldid), - div_du_l2_proj_bb_array_agg_cells) - end - - div_du_l2_proj_agg_cells = - Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells, dΩagg_cells.quad.trian,ReferenceDomain()) + # (2) proj_op_u⊙op_v term # In the MultiField case, I have had to add this change domain # call before setting up the term right below. Otherwise, we get an error # when trying to multiply the fields. Not sure why this is happening - # dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωagg_cells,ReferenceDomain()) - - proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩagg_cells) + op_v_on_Ωbg_agg_cells = Gridap.CellData.change_domain(operation_v(v),Ωbg_agg_cells,ReferenceDomain()) - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_agg_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_agg_cells_to_aggregate_dof_ids) - end + proj_op_u_op_v_mat_contribs=get_array(∫(γ*(-1.0)*(proj_op_u⊙op_v_on_Ωbg_agg_cells))*dD) + push!(w, proj_op_u_op_v_mat_contribs) + push!(r, dof_ids_v) + push!(c, dof_ids_proj_u) - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_Ωagg_cell_dof_ids) # test - push!(c, U_agg_cells_to_aggregate_dof_ids) # trial - w,r,c -end + # (3) proj_op_u⊙proj_op_v + proj_op_u_proj_op_v_mat_contribs=get_array(∫(γ*(proj_op_u⊙proj_op_v))*dD) + push!(w, proj_op_u_proj_op_v_mat_contribs) + push!(r, dof_ids_proj_v) + push!(c, dof_ids_proj_u) + # (4) op_u⊙proj_op_v -function div_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## Compute ∫( (div_dv)*(div_du-div_du_l2_proj_agg_cells))*dΩbg_cut_cells - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end - - ## (I) Let's set up the div_dv_div_du_mat_contribs - # (first part of the integral, that is ∫( (div_dv)*(div_du)*dΩbg_cut_cells - div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) - push!(w, div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - ## (II) Set up ∫( (div_dv)*(-div_du_l2_proj_agg_cells))*dΩbg_cut_cells - div_du=∇⋅(_get_single_field_fe_basis(du)) - - # Compute Π_Q_bb(div_du) - dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) - - div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) - div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(du) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(dv) - div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) - end - - div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - # In the MultiField case, I have had to add this change domain # call before setting up the term right below. Otherwise, we get an error # when trying to multiply the fields. Not sure why this is happening - # dv_Ωagg_cells=Gridap.CellData.change_domain(dv,Ωagg_cells,ReferenceDomain()) - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - - proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells*(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_cut_cells_to_aggregate_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) - end - - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) # test - push!(c, U_cut_cells_to_aggregate_dof_ids) # trial - w,r,c -end - -function set_up_bulk_ghost_penalty_lhs(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩagg_cells, - ubb, - vbb) -Ωagg_cells=dΩagg_cells.quad.trian - -# Change domain of vbb (test) from Ωbb to Ωagg_cells -vbb_Ωagg_cells=change_domain_bb_to_agg_cells(vbb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - -# Change domain of ubb (trial) from Ωbb to Ωagg_cells -ubb_Ωagg_cells=change_domain_bb_to_agg_cells(ubb, - ref_agg_cell_to_ref_bb_map, - Ωagg_cells, - agg_cells_to_aggregate) - -# Compute contributions to LHS of L2 projection -agg_cells_to_lhs_contribs=get_array(∫(vbb_Ωagg_cells⋅ubb_Ωagg_cells)dΩagg_cells) - -# Finally assemble LHS contributions -ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) -lazy_map(ass_lhs_map,aggregate_to_local_cells) -end - -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv-div_dv_l2_proj_agg_cells)*(div_du-div_du_l2_proj_agg_cells))*dΩ_cut_cells -""" -function div_penalty_stabilization_collect_cell_matrix_on_cut_cells_full(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dv, # Test basis - du, # Trial basis (to project) - qbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - U_agg_cells_local_dof_ids, - U_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells) - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## (I) Compute projections div_dv_l2_proj_agg_cells & div_du_l2_proj_agg_cells - - div_du=∇⋅(_get_single_field_fe_basis(du)) - - # Change domain of vbb (test) from Ωbb to Ωagg_cells - dqbb_Ωagg_cells =change_domain_bb_to_agg_cells(qbb,ref_agg_cell_to_ref_bb_map,Ωbg_agg_cells,agg_cells_to_aggregate) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωagg_cells⋅div_du)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - div_dv_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in du - # restricted to the cells included in the bounding box of the aggregate - div_dv_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, div_dv_l2_proj_bb_dofs, Gridap.CellData.get_data(qbb)) - - # # Change domain of dv_l2_proj_bb_array from bb to agg_cells - div_dv_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘),lazy_map(Reindex(div_dv_l2_proj_bb_array),agg_cells_to_aggregate),ref_agg_cell_to_ref_bb_map) - div_du_l2_proj_bb_array_agg_cells=lazy_map(transpose, div_dv_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(du)) - @assert _is_multifield_fe_basis_component(du) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(du) - fieldid=_fieldid(dv) - div_du_l2_proj_bb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((fieldid,nfields),fieldid),div_du_l2_proj_bb_array_agg_cells) - end - - if (_is_multifield_fe_basis_component(dv)) - @assert _is_multifield_fe_basis_component(dv) - @assert _nfields(du)==_nfields(dv) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - div_dv_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - div_dv_l2_proj_bb_array_agg_cells) - end - - div_du_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_du_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - div_dv_l2_proj_agg_cells = Gridap.CellData.GenericCellField(div_dv_l2_proj_bb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - - # # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_cut_cells_to_aggregate_dof_ids) - end - - # Manually set up the arrays that collect_cell_matrix would return automatically - w = [] - r = [] - c = [] - - ## (1) div_dv*div_du term - div_dv_div_du_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅(∇⋅du))*dΩbg_cut_cells) - push!(w, div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - ## (2) div_dv*proj_div_du term - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - proj_div_dv_div_du_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, U_cut_cells_to_aggregate_dof_ids) - - ## (3) proj_div_dv*proj_div_du - proj_div_dv_proj_div_du_mat_contribs=get_array(∫(γ*div_dv_l2_proj_agg_cells⋅(div_du_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, proj_div_dv_proj_div_du_mat_contribs) - push!(r, U_cut_cells_to_aggregate_dof_ids) - push!(c, U_cut_cells_to_aggregate_dof_ids) - - ## (4) proj_div_dv*div_du - div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) - proj_div_dv_div_du_mat_contribs=get_array(∫(-γ*div_dv_l2_proj_agg_cells⋅div_du_Ωagg_cells)*dΩbg_cut_cells) + op_u_on_Ωbg_agg_cells = Gridap.CellData.change_domain(operation_u(u),Ωbg_agg_cells,ReferenceDomain()) - push!(w, proj_div_dv_div_du_mat_contribs) - push!(r, U_cut_cells_to_aggregate_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) + op_u_proj_op_v_mat_contribs=get_array(∫(-γ*op_u_on_Ωbg_agg_cells⊙proj_op_v)*dD) + push!(w, op_u_proj_op_v_mat_contribs) + push!(r, dof_ids_proj_v) + push!(c, dof_ids_u) w, r, c end -## Create collect function on cut cells only """ - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + Compute and assemble the bulk penalty stabilization term - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) - ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) - -""" -function pmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - dqbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - dv) - - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells - # Change domain of qbb (test) from Ωbb to Ωagg_cells - dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, - ref_agg_cell_to_ref_bb_map, - Ωbg_agg_cells, - agg_cells_to_aggregate) + γ ∫( (operation_u(u) - proj_op_u)⊙(operation_v(v)) )*dD - dp_single_field=_get_single_field_fe_basis(dp) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dq_l2_proj_bb_dofs, - Gridap.CellData.get_data(dqbb)) - - # # Change domain of dq_l2_proj_bb_array from bb to agg_cells - dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - dp_l2_proj_bb_array_agg_cells=lazy_map(transpose, dq_l2_proj_bb_array_agg_cells) - - if (_is_multifield_fe_basis_component(dp)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - dp_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap((1,nfields),fieldid), - dp_l2_proj_bb_array_agg_cells) - end - - # if (_is_multifield_fe_basis_component(dq)) - # @assert _is_multifield_fe_basis_component(dq) - # @assert _nfields(dp)==_nfields(dq) - # nfields=_nfields(dq) - # fieldid=_fieldid(dq) - # dq_l2_proj_bb_array_agg_cells=lazy_map( - # Gridap.Fields.BlockMap(nfields,fieldid), - # dq_l2_proj_bb_array_agg_cells) - # end - - dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - # dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(dp)) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - P_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) - end + with `u` and `v` the trial and test basis functions (which may be components of a MultiField). The operations `operation_u` and `operation_v` (e.g. identity or divergence) are applied to u and v, respectively. The L2 projections `proj_op_u` and `proj_op_v` can be computed via `setup_L2_proj_in_bb_space` and are to be passed as arguments. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. - if (_is_multifield_fe_basis_component(dv)) - nfields=_nfields(dv) - fieldid=_fieldid(dv) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end +""" +function bulk_ghost_penalty_stabilization_collect_cell_matrix_on_D(dD, + Ωbg_agg_cells, + γ, + u, + v, + proj_op_u, + dof_ids_u, + dof_ids_v, + dof_ids_proj_u, + operation_u, + operation_v) + + # # BlockMap preparatory steps for the dof ids + # if (_is_multifield_fe_basis_component(u)) + # nfields=_nfields(u) + # fieldid=_fieldid(u) + # dof_ids_u=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_u) + # end + # if (_is_multifield_fe_basis_component(v)) + # nfields=_nfields(v) + # fieldid=_fieldid(v) + # dof_ids_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_v) + # end + # if (_is_multifield_fe_basis_component(u)) + # nfields=_nfields(u) + # fieldid=_fieldid(u) + # dof_ids_proj_u=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_proj_u) + # end # Manually set up the arrays that collect_cell_matrix would return automatically w = [] r = [] c = [] - ## (1) div_dv*dp term - # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) - div_dv_dp_mat_contribs=get_array(∫(γ*(∇⋅dv)⋅dp)*dΩbg_cut_cells) - - push!(w, div_dv_dp_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, P_Ωbg_cut_cell_dof_ids) - - ## (2) div_dv*proj_dp term - div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - div_dv_proj_dp_mat_contribs=get_array(∫(γ*(-1.0)*div_dv_Ωagg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, div_dv_proj_dp_mat_contribs) - push!(r, U_Ωbg_cut_cell_dof_ids) - push!(c, P_cut_cells_to_aggregate_dof_ids) + # (1) op_u⊙op_v term + op_u_op_v_mat_contribs=get_array(∫(γ*operation_u(u)⊙operation_v(v))*dD) + push!(w, op_u_op_v_mat_contribs) + push!(r, dof_ids_v) + push!(c, dof_ids_u) - # ## (3) proj_dq*proj_dp - # proj_dq_proj_dp_mat_contribs=get_array(∫(γ*dq_l2_proj_agg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) + # (2) proj_op_u⊙op_v term - # push!(w, proj_dq_proj_dp_mat_contribs) - # push!(r, cut_cells_to_aggregate_dof_ids) - # push!(c, cut_cells_to_aggregate_dof_ids) - - # ## (4) proj_dq*dp - # dpΩagg_cells=Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) - # proj_dq_dp_mat_contribs=get_array(∫(-γ*dq_l2_proj_agg_cells⋅dpΩagg_cells)*dΩbg_cut_cells) + # In the MultiField case, I have had to add this change domain + # call before setting up the term right below. Otherwise, we get an error + # when trying to multiply the fields. Not sure why this is happening + op_v_on_Ωbg_agg_cells = Gridap.CellData.change_domain(operation_v(v),Ωbg_agg_cells,ReferenceDomain()) - # push!(w, proj_dq_dp_mat_contribs) - # push!(r, cut_cells_to_aggregate_dof_ids) - # push!(c, Ωbg_cut_cell_dof_ids) + proj_op_u_op_v_mat_contribs=get_array(∫(γ*(-1.0)*(proj_op_u⊙op_v_on_Ωbg_agg_cells))*dD) + push!(w, proj_op_u_op_v_mat_contribs) + push!(r, dof_ids_v) + push!(c, dof_ids_proj_u) w, r, c end -## Create collect function on cut cells only """ - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField + Compute and assemble the bulk penalty stabilization term - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) - ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) + γ ∫( (operation_v(v) - proj_op_v)⊙(rhs_function) )*dD -""" -function dmix_penalty_stabilization_collect_cell_matrix_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - dqbb, # Bounding box space test basis - p_lhs, - U_Ωbg_cut_cell_dof_ids, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - du) - - - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + with `v` the test basis functions (which may be components of a MultiField). The operation `operation_v` (e.g. identity or divergence) is applied to v. The L2 projections `proj_op_u` can be computed via `setup_L2_proj_in_bb_space`. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. The function `rhs_function` is the forcing term appearing on the right hand-side of the PDE. - ## (I) Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells - # Change domain of qbb (test) from Ωbb to Ωagg_cells - dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, - ref_agg_cell_to_ref_bb_map, - Ωbg_agg_cells, - agg_cells_to_aggregate) - - dp_single_field=_get_single_field_fe_basis(dp) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dq_l2_proj_bb_dofs, - Gridap.CellData.get_data(dqbb)) - - # # Change domain of dq_l2_proj_bb_array from bb to agg_cells - dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - if (_is_multifield_fe_basis_component(dq)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - dq_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - dq_l2_proj_bb_array_agg_cells) - end - - # dp_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dp_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(dp)) - nfields=_nfields(dp) - fieldid=_fieldid(dp) - P_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) - end - - if (_is_multifield_fe_basis_component(du)) - nfields=_nfields(du) - fieldid=_fieldid(du) - U_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),U_Ωbg_cut_cell_dof_ids) - end +""" +function bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dD, + γ, + v, + proj_op_v, + dof_ids_v, + dof_ids_proj_v, + operation_v, + rhs_function) + # # BlockMap preparatory steps for the dof ids + # if (_is_multifield_fe_basis_component(v)) + # nfields=_nfields(v) + # fieldid=_fieldid(v) + # dof_ids_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_v) + # end + # if (_is_multifield_fe_basis_component(v)) + # nfields=_nfields(v) + # fieldid=_fieldid(v) + # dof_ids_proj_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_proj_v) + # end - # Manually set up the arrays that collect_cell_matrix would return automatically + # Manually set up the arrays that collect_cell_vector would return automatically w = [] r = [] - c = [] - - ## (1) div_du*dq term - # div_dv_Ωagg_cells=Gridap.CellData.change_domain(∇⋅dv,Ωbg_agg_cells,ReferenceDomain()) - # div_dv_dp_mat_contribs=get_array(∫(γ*div_dv_Ωagg_cells⋅dp)*dΩbg_cut_cells) - div_dv_dp_mat_contribs=get_array(∫(γ*(∇⋅du)⋅dq)*dΩbg_cut_cells) - - push!(w, div_dv_dp_mat_contribs) - push!(r, P_Ωbg_cut_cell_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) - - ## (2) div_du*proj_dq term - div_du_Ωagg_cells=Gridap.CellData.change_domain(∇⋅du,Ωbg_agg_cells,ReferenceDomain()) - div_dv_proj_dp_mat_contribs=get_array(∫(γ*(-1.0)*div_du_Ωagg_cells⋅(dq_l2_proj_agg_cells))*dΩbg_cut_cells) - - push!(w, div_dv_proj_dp_mat_contribs) - push!(r, P_cut_cells_to_aggregate_dof_ids) - push!(c, U_Ωbg_cut_cell_dof_ids) + # (1) op_v⊙rhs_function term + op_v_rhs_vec_contribs=get_array(∫(γ*operation_v(v)⊙(rhs_function))*dD) + push!(w, op_v_rhs_vec_contribs) + push!(r, dof_ids_v) - # ## (3) proj_dq*proj_dp - # proj_dq_proj_dp_mat_contribs=get_array(∫(γ*dq_l2_proj_agg_cells⋅(dp_l2_proj_agg_cells))*dΩbg_cut_cells) + # (2) proj_op_v⊙rhs_function + proj_op_v_rhs_vec_contribs=get_array(∫(γ*(-1.0)*(proj_op_v⊙(rhs_function)))*dD) + push!(w, proj_op_v_rhs_vec_contribs) + push!(r, dof_ids_proj_v) - # push!(w, proj_dq_proj_dp_mat_contribs) - # push!(r, cut_cells_to_aggregate_dof_ids) - # push!(c, cut_cells_to_aggregate_dof_ids) - - # ## (4) proj_dq*dp - # dpΩagg_cells=Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) - # proj_dq_dp_mat_contribs=get_array(∫(-γ*dq_l2_proj_agg_cells⋅dpΩagg_cells)*dΩbg_cut_cells) - - # push!(w, proj_dq_dp_mat_contribs) - # push!(r, cut_cells_to_aggregate_dof_ids) - # push!(c, Ωbg_cut_cell_dof_ids) - - w, r, c + w, r end -## Create collect function on cut cells only for rhs -## TODO: rhs_g_func does not seem to work when function is passed on -""" - dv, du: Test and trial basis functions. They may be components of a MultiFieldCellField - - # Compute and assemble the bulk penalty stabilization term - # ∫( (div_dv)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (reduced) - ##### ∫( (div_dv-div_dv_l2_proj_agg_cells)*(dp-dp_l2_proj_agg_cells))*dΩ_cut_cells (full form, not implented here) - """ -function dmix_penalty_stabilization_collect_cell_vector_on_cut_cells(aggregate_to_local_cells, - agg_cells_to_aggregate, - ref_agg_cell_to_ref_bb_map, - dΩbg_agg_cells, - dq, # Test basis - dp, # Trial basis (to project) - dqbb, # Bounding box space test basis - p_lhs, - P_Ωbg_cut_cell_dof_ids, - P_agg_cells_local_dof_ids, - P_cut_cells_to_aggregate_dof_ids, - γ, - dΩbg_cut_cells, - rhs_g_func) + Compute and assemble the bulk penalty stabilization term + γ ∫( (operation_v(v))⊙(rhs_function) )*dD - Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - - ## Compute projections dq_l2_proj_agg_cells & dp_l2_proj_agg_cells - # Change domain of qbb (test) from Ωbb to Ωagg_cells - dqbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(dqbb, - ref_agg_cell_to_ref_bb_map, - Ωbg_agg_cells, - agg_cells_to_aggregate) + with `v` the test basis functions (which may be components of a MultiField). The operation `operation_v` (e.g. identity or divergence) is applied to v. The L2 projections `proj_op_u` can be computed via `setup_L2_proj_in_bb_space`. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. The function `rhs_function` is the forcing term appearing on the right hand-side of the PDE. - dp_single_field=_get_single_field_fe_basis(dp) - agg_cells_rhs_contribs=get_array(∫(dqbb_Ωbg_agg_cells⋅dp_single_field)dΩbg_agg_cells) - ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,agg_cells_rhs_contribs) - rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - - # TO-DO: optimize using our own optimized version Gridap.Fields.Map - # of backslash that re-uses storage for lu factors among cells, etc. - dq_l2_proj_bb_dofs=lazy_map(\,p_lhs,rhs) - - # Generate bb-wise array of fields. For each aggregate's bounding box, - # it provides the l2 projection of all basis functions in dp - # restricted to the cells included in the bounding box of the aggregate - dq_l2_proj_bb_array=lazy_map(Gridap.Fields.linear_combination, - dq_l2_proj_bb_dofs, - Gridap.CellData.get_data(dqbb)) - - # # Change domain of dq_l2_proj_bb_array from bb to agg_cells - dq_l2_proj_bb_array_agg_cells=lazy_map(Broadcasting(∘), - lazy_map(Reindex(dq_l2_proj_bb_array),agg_cells_to_aggregate), - ref_agg_cell_to_ref_bb_map) - - if (_is_multifield_fe_basis_component(dq)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - dq_l2_proj_bb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - dq_l2_proj_bb_array_agg_cells) - end - - dq_l2_proj_agg_cells = Gridap.CellData.GenericCellField(dq_l2_proj_bb_array_agg_cells, Ωbg_agg_cells,ReferenceDomain()) - - # BlockMap preparatory steps for the dof ids - if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - P_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) - end - - if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - P_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) - end +""" +function bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dD, + γ, + v, + dof_ids_v, + operation_v, + rhs_function) + # # BlockMap preparatory steps for the dof ids + # if (_is_multifield_fe_basis_component(v)) + # nfields=_nfields(v) + # fieldid=_fieldid(v) + # dof_ids_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_v) + # end + # if (_is_multifield_fe_basis_component(v)) + # nfields=_nfields(v) + # fieldid=_fieldid(v) + # dof_ids_proj_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_proj_v) + # end # Manually set up the arrays that collect_cell_vector would return automatically w = [] r = [] - ## (1) rhs_g*dq term - rhs_g_dp_mat_contribs=get_array(∫((rhs_g_func⋅dq)*γ)*dΩbg_cut_cells) - - push!(w, rhs_g_dp_mat_contribs) - push!(r, P_Ωbg_cut_cell_dof_ids) - - # (2) div_du*proj_dq term - rhs_g_proj_dp_mat_contribs=get_array(∫((rhs_g_func⋅dq_l2_proj_agg_cells)*γ*(-1.0))*dΩbg_cut_cells) - - push!(w, rhs_g_proj_dp_mat_contribs) - push!(r, P_cut_cells_to_aggregate_dof_ids) + # (1) op_v⊙rhs_function term + op_v_rhs_vec_contribs=get_array(∫(γ*operation_v(v)⊙(rhs_function))*dD) + push!(w, op_v_rhs_vec_contribs) + push!(r, dof_ids_v) w, r end \ No newline at end of file From b7a730fd0af33447ae23ac555fe0639a942fdd07 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Thu, 3 Apr 2025 17:32:56 +1100 Subject: [PATCH 076/120] DEBUG ME: the projected rhs term is a cell_matrix, whereas it should return the weights of a cell_vector. --- test_proj_rhs_func.jl | 389 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 test_proj_rhs_func.jl diff --git a/test_proj_rhs_func.jl b/test_proj_rhs_func.jl new file mode 100644 index 00000000..51c6403a --- /dev/null +++ b/test_proj_rhs_func.jl @@ -0,0 +1,389 @@ +using Gridap +using GridapEmbedded + +include("./src/BGP/BGP.jl") + +# Problem selection +problem = 0 # 0 = Manufactured solution (L2-like projection), 1 = Darcy problem + +# Manufactured solution +order = 0 +uex(x) = -VectorValue(2*x[1],2*x[2]) +pex(x) = (x[1]^2 + x[2]^2) +divuex(x) = -4.0 + +# Select geometry +nint = 3 # number of (uncut) interior elements along single direction +# cut length +ε = 0.2/2.0 # not so small cut +# ε = 0.2e-2/2.0 # smaller cut +# ε = 0.2e-6/2.0 # smallest cut +pmin = Point(0.0,0.0) +pmax = Point(1.0,1.0) +function setup_geometry(nint, ε, pmin, pmax) + nbg = nint + 2 + 2 # number of elements in the background mesh (2 from cut, 2 dummy) + dp = pmax - pmin + h = dp[1]/nint + bgpmin = pmin - Point(2*h,2*h) + bgpmax = pmax + Point(2*h,2*h) + bgdp = bgpmax - bgpmin + partition = (nbg,nbg) + bgmodel = CartesianDiscreteModel(bgpmin,bgpmax,partition) + hbg = bgdp[1]/nbg + @assert abs(hbg - h) < 10e-10 + @assert abs(ε/h) < 0.5 + + # The following is based on square (part of GridapEmbedded): + e1 = VectorValue(1,0) + e2 = VectorValue(0,1) + x0 = pmin + Point(0.5*dp[1],0.5*dp[2]) + L1 = dp[1] + 2*ε + L2 = dp[2] + 2*ε + plane1 = plane(x0=x0-0.5*L2*e2,v=-e2,name="bottom") + plane2 = plane(x0=x0+0.5*L1*e1,v= e1,name="right") + plane3 = plane(x0=x0+0.5*L2*e2,v= e2,name="top") + plane4 = plane(x0=x0-0.5*L1*e1,v=-e1,name="left") + + geo12 = intersect(plane1,plane2) + geo34 = intersect(plane3,plane4) + + square = intersect(geo12,geo34) + cutgeo = cut(bgmodel, square) + + bgmodel, cutgeo, h +end +bgmodel, cutgeo, h= setup_geometry(nint, ε, pmin, pmax) + +# Setup aggregates +strategy = AggregateAllCutCells() +aggregates= aggregate(strategy,cutgeo) +aggregate_to_cells=setup_aggregate_to_cells(aggregates) +aggregates_bounding_box_model= + setup_aggregates_bounding_box_model(bgmodel,aggregate_to_cells) + +# Triangulations +Ωbg = Triangulation(bgmodel) +Ωact = Triangulation(cutgeo,ACTIVE) + +# Physical domain +Ω = Triangulation(cutgeo,PHYSICAL) +degree=2*2*(order+1) +dΩ = Measure(Ω,degree) + +# Setup agg cells and triangulation +agg_cells =flatten(aggregate_to_cells) #[CLEAN]: replaced setup_agg_cells +Ωbg_agg_cells=view(Ωbg,agg_cells) + +# Pressure space +if problem==0 + Q = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) +elseif problem==1 + # Set up zero-mean pressure space, with fixed interior dof + Qnzm = FESpace(Ωact, ReferenceFE(lagrangian,Float64,order), conformity=:L2) + int_cells = restrict_cells(cutgeo,IN) # global (background mesh') cell identifiers of interior cells + nonagg_int_cell = int_cells[findfirst(!in(agg_cells),int_cells)] # cell identifier (background mesh) of first interior cell not in aggregate + local_id = findfirst(isequal(nonagg_int_cell),Ωact.tface_to_mface) # local (active mesh') cell id of interior cell not in aggregate + dof_to_fix = get_cell_dof_ids(Qnzm)[local_id][1] + spaceWithConstantFixed = Gridap.FESpaces.FESpaceWithConstantFixed(Qnzm,true,Int64(dof_to_fix)) + Qzm_vol_i = assemble_vector(v->∫(v)*dΩ,Qnzm) + Qzm_vol = sum(Qzm_vol_i) + Q = Gridap.FESpaces.ZeroMeanFESpace(spaceWithConstantFixed,Qzm_vol_i,Qzm_vol) +end + +# Set up global spaces +V = FESpace(Ωact, ReferenceFE(raviart_thomas,Float64,order),conformity=:HDiv) +U = TrialFESpace(V) +P = TrialFESpace(Q) +Y = MultiFieldFESpace([V, Q]) +X = MultiFieldFESpace([U, P]) +dx = get_trial_fe_basis(X) +dy = get_fe_basis(Y) +du,dp = dx +dv,dq = dy + +# ref_agg_cell_to_agg_cell_map: \hat{K} -> K +ref_agg_cell_to_agg_cell_map=get_cell_map(Ωbg_agg_cells) +agg_cells_to_aggregate =setup_cells_to_aggregate(aggregate_to_cells) +ref_agg_cell_to_ref_bb_map =setup_ref_agg_cell_to_ref_bb_map(aggregates_bounding_box_model, + agg_cells_to_aggregate,ref_agg_cell_to_agg_cell_map) + +# Spaces on bounding boxes +reffeₚ_bb =ReferenceFE(lagrangian,Float64,order) + +Qbb=FESpace(aggregates_bounding_box_model,reffeₚ_bb,conformity=:L2) # We need a DG space to represent the L2 projection +Pbb=TrialFESpace(Qbb) +pbb=get_trial_fe_basis(Pbb) +qbb=get_fe_basis(Qbb) +reffeᵤ_bb=ReferenceFE(raviart_thomas,Float64,order) +Vbb=FESpace(aggregates_bounding_box_model,reffeᵤ_bb,conformity=:L2) +Ubb=TrialFESpace(Vbb) +ubb=get_trial_fe_basis(Ubb) +vbb=get_fe_basis(Vbb) + + +# Numerical integration (Measures) +dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) + +# # LHS of L2 projection on bounding boxes. + +# Selecting relevant global dofs ids of aggregate cells (from background mesh) +Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) +U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) +P_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 2) + +# Computing local (per aggregate) dof ids +aggregate_to_local_cells=setup_aggregate_to_local_cells(aggregate_to_cells) +U_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(U_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) +P_agg_cells_local_dof_ids= + compute_agg_cells_local_dof_ids(P_Ωbg_agg_cell_dof_ids, aggregate_to_local_cells) + +# Compute global dofs ids per aggregate and reindex these +U_aggregate_dof_ids=compute_aggregate_dof_ids(U_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +U_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),agg_cells_to_aggregate) +P_aggregate_dof_ids=compute_aggregate_dof_ids(P_Ωbg_agg_cell_dof_ids,aggregate_to_cells) +P_agg_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),agg_cells_to_aggregate) + +# parameters +γ = 10.0 # Interior bulk-penalty stabilization parameter + +########################################### +### STABILIZATION ON Ωagg\Troot ### +########################################### + +# Setup cut cells and triangulation +aggregate_to_cut_cells = restrict_aggregate_to_cells(cutgeo,aggregate_to_cells,GridapEmbedded.Interfaces.CUT) +cut_cells = flatten(aggregate_to_cut_cells) +#TO-DO: look into why cut_cells = restrict_cells(cutgeo,GridapEmbedded.Interfaces.CUT) can not be used instead of the above +Ωbg_cut_cells = view(Ωbg,cut_cells) +dΩbg_cut_cells = Measure(Ωbg_cut_cells,degree) + +# Selecting relevant global dofs ids of cut cells (from background mesh) +Ωbg_cut_cell_dof_ids = get_cell_dof_ids(X,Ωbg_cut_cells) +U_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 1) +P_Ωbg_cut_cell_dof_ids = _restrict_to_block(Ωbg_cut_cell_dof_ids, 2) + +# Compute global dofs ids per aggregate and reindex these +cut_cells_to_aggregate = setup_cells_to_aggregate(aggregate_to_cut_cells) +U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_to_aggregate) +P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_to_aggregate) + +########################################### +### Setup projections +########################################### + +du_proj_Vbb, dv_proj_Vbb = setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + du, # Trial basis (to project) + dv, # Test basis + ubb, # Trial basis of bounding box space Vbb + vbb, # Test basis of bounding box space Vbb + identity, # operation to be applied to u and v + U_agg_cells_local_dof_ids) # aggregates local dof ids for space U + +dp_proj_Qbb, dq_proj_Qbb = setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + dp, # Trial basis (to project) + dq, # Test basis + pbb, # Trial basis of bounding box space Qbb + qbb, # Test basis of bounding box space Qbb + identity, # operation to be applied to u and v + P_agg_cells_local_dof_ids) # aggregates local dof ids for space P + +div_du_proj_Vbb, div_dv_proj_Vbb = setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + du, # Trial basis (to project) + dv, # Test basis + pbb, # Trial basis of bounding box space Vbb + qbb, # Test basis of bounding box space Vbb + divergence, # operation to be applied to u and v + U_agg_cells_local_dof_ids) # aggregates local dof ids for space U + +#### ---------------------- #### +if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + testP_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) +end + +# Manually set up the arrays that collect_cell_vector would return automatically +test_w = [] +test_r = [] + +######################## (1) int (rhs_function)*dq) ######################### +#rhs_func(x) = 10.0*x[1]^2 + sin(x[2]) +rhs_func(x) = 10.0*x[1] +#rhs_func(x) = 1000.0 +test_f = rhs_func +test_rhs_vec_contribs1=get_array(∫((rhs_func)*dq)*dΩbg_cut_cells) +push!(test_w, test_rhs_vec_contribs1) +push!(test_r, testP_Ωbg_cut_cell_dof_ids) + +######################## (2) proj_rhs_function*dq ######################### (2) +test_wbb = pbb +test_zbb = qbb + +test_wbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(test_wbb, ref_agg_cell_to_ref_bb_map, Ωbg_agg_cells, agg_cells_to_aggregate) # trial +test_zbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(test_zbb, ref_agg_cell_to_ref_bb_map, Ωbg_agg_cells, agg_cells_to_aggregate) # test + +test_agg_cells_to_lhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells⋅test_wbb_Ωbg_agg_cells)dΩbg_agg_cells) + +test_ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(test_agg_cells_to_lhs_contribs) +test_lhs = lazy_map(test_ass_lhs_map,aggregate_to_local_cells) +test_agg_cells_rhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells*test_f)dΩbg_agg_cells) + + +evaluate(Gridap.CellData.get_data(test_zbb_Ωbg_agg_cells)[1],[Point(0.0,0.0)]) +evaluate(Gridap.CellData.get_data(qbb)[8],[Point(0.0,0.0)]) +evaluate(Gridap.CellData.get_data(qbb)[8],[Point(0.0,0.0)]) +test_lhs[1] +# Gridap.CellData.get_triangulation(dΩbg_agg_cells.quad) === Gridap.CellData.get_triangulation(test_zbb_Ωbg_agg_cells) + + +test_ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,test_agg_cells_rhs_contribs) # (!) No need to apply BlockMap! +test_rhs=lazy_map(test_ass_rhs_map,aggregate_to_local_cells) +test_f_proj_Zbb_dofs=lazy_map(\,test_lhs,test_rhs) +test_f_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, test_f_proj_Zbb_dofs, Gridap.CellData.get_data(test_zbb)) + +Gridap.CellData.get_data(test_zbb) + + +evaluate((test_f_proj_Zbb_array)[1],[Point(0.0,0.0)]) + + +test_rhs[1] +test_rhs[1] +test_f_proj_Zbb_dofs[1] # dofs belonging to the four cells in the first aggregate +test_f_proj_Zbb_array[1] # 4 x linear combinations of four cells in aggregate + +# (7) Change domain of proj_op_u and proj_op_v from Ωbb to Ωbg_agg_cells +test_f_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), lazy_map(Reindex(test_f_proj_Zbb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) +# contains 24 entries, with nr of operation fields equal to the nr of cells in that aggregate. + +# .... +test_fT_proj_Zbb_array_agg_cells=lazy_map(transpose, test_f_proj_Zbb_array_agg_cells) +if (_is_multifield_fe_basis_component(dp)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dq) + fieldid=_fieldid(dp) +test_fT_proj_Zbb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((1,nfields),fieldid), + test_fT_proj_Zbb_array_agg_cells) +end +test_fT_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(test_fT_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + +if (_is_multifield_fe_basis_component(dq)) + @assert _is_multifield_fe_basis_component(dq) + @assert _nfields(dp)==_nfields(dq) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + test_f_proj_Zbb_array_agg_cells=lazy_map( + Gridap.Fields.BlockMap(nfields,fieldid), + test_f_proj_Zbb_array_agg_cells) +end +test_f_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(test_f_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + +dq_on_Ωbg_agg_cells = Gridap.CellData.change_domain(dq,Ωbg_agg_cells,ReferenceDomain()) +dp_on_Ωbg_agg_cells = Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) + +## ANOTHER TEST ## +testarray_dp_test_f = get_array(∫(dp_on_Ωbg_agg_cells⊙test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) #matrix + +testarray_dq_test_f = get_array(∫(dq_on_Ωbg_agg_cells*test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) + +testarray_test_f_dq = get_array(∫(test_f_proj_Zbb_agg_cells⊙dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) +testarray_dq_test_fT = get_array(∫(dq_on_Ωbg_agg_cells⊙test_fT_proj_Zbb_agg_cells)*dΩbg_cut_cells) +testarray_test_fT_dq = get_array(∫(test_fT_proj_Zbb_agg_cells⊙dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) + +testarray_dq_test_f[1] +testarray_test_f_dq[1] +testarray_dq_test_fT[1] +testarray_test_fT_dq[1] + +### ---- START TEST ## +## THE FOLLOWING SEEMS TO IMPLY THAT test_fT_proj_Zbb_agg_cells is the projected rhs_func. +# NOTE that for (lowest order Pbb) a rhs_func which takes on a constant value everywhere, the different/error = machine precision, whereas for higher order functions this is not the case (as expected) +sum_cut_cells = sum([sum(get_array(∫(test_fT_proj_Zbb_agg_cells)dΩbg_cut_cells)[i][2]) for i=1:16]) +sum((get_array(∫(rhs_func)*dΩbg_cut_cells))) +@assert abs(sum_cut_cells - sum((get_array(∫(rhs_func)*dΩbg_cut_cells)))) <1e-12 +difference = abs(sum_cut_cells - sum((get_array(∫(rhs_func)*dΩbg_cut_cells)))) +### ---- END TEST ## + +# push contributions to rhs_vec +# test_rhs_vec_contribs2=get_array(∫((-1.0)*(test_fT_proj_Zbb_agg_cells)⋅(dq_on_Ωbg_agg_cells))*dΩbg_cut_cells) + +test_rhs_vec_contribs2 = get_array(∫((-1.0)*(test_fT_proj_Zbb_agg_cells)⋅dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) +#DEBUG ME: here output is cell matrix and should be cell vector + + + +push!(test_w, test_rhs_vec_contribs2) +if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + test_P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) +end +push!(test_r, test_P_cut_cells_to_aggregate_dof_ids) + +test_w[2][1] + +#### -- PROBLEM -- #### +test_a((u,p),(v,q))=∫(u⋅v+q*p)dΩ +uex(x) = -VectorValue(2.0,2.0) +test_l((v,q))=∫(uex⋅v+1.0⋅q)dΩ + +test_mat_A=Gridap.FESpaces.collect_cell_matrix(X,Y,test_a(dx,dy)) +test_vec_b=Gridap.FESpaces.collect_cell_vector(Y,test_l(dy)) + +# test_vec_b[1][1][25][1] #uvals +# test_vec_b[1][1][25][2] #pvals +# test_vec_b[2][1][25][1] #udofs +# test_vec_b[2][1][25][2] #pvals + +push!(test_vec_b[1], test_w...) +push!(test_vec_b[2], test_r...) + +# test_w = [] +# test_r = [] +# push!(test_w, test_rhs_vec_contribs1) +# push!(test_r, testP_Ωbg_cut_cell_dof_ids) +# push!(test_w, test_rhs_vec_contribs2) +# push!(test_r, test_P_cut_cells_to_aggregate_dof_ids) + +# +# push!(test_mat_A[1], test_rhs_vec_contribs2...) +# push!(test_mat_A[2], test_P_cut_cells_to_aggregate_dof_ids...) + +# I AM CREATING MATRIX BLOCKS WHEN USING +# test_rhs_vec_contribs2=get_array(∫((-1.0)*(test_fT_proj_Zbb_agg_cells)⋅(dq_on_Ωbg_agg_cells))*dΩbg_cut_cells) + + + +assem=SparseMatrixAssembler(X,Y) + +test_A = assemble_matrix(assem, test_mat_A) +test_b = assemble_vector(assem, test_vec_b) + +test_sol = test_A\test_b + +test_sol_FE = FEFunction(X, test_sol) +test_sol_u, test_sol_p = test_sol_FE +area = sum(∫(1.0)dΩ) + +norm_sol_u = (sum(∫(test_sol_u⋅test_sol_u)*dΩ)) +norm_sol_p = (sum(∫(test_sol_p)*dΩ)) + +err_sol_u = uex - test_sol_u +err_sol_p = 0.0 - test_sol_p +L2error_sol_u = (sum(∫(err_sol_u⋅err_sol_u)*dΩ)) +L2error_sol_p = (sum(∫(err_sol_p⋅err_sol_p)*dΩ)) \ No newline at end of file From d58901d3c73a8e0a5d0850fbc4b3693d706fc872 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Fri, 4 Apr 2025 13:00:52 +1100 Subject: [PATCH 077/120] included additional comments for the TODEBUG rhs proj --- test_proj_rhs_func.jl | 185 +++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 118 deletions(-) diff --git a/test_proj_rhs_func.jl b/test_proj_rhs_func.jl index 51c6403a..24fb4c13 100644 --- a/test_proj_rhs_func.jl +++ b/test_proj_rhs_func.jl @@ -168,108 +168,86 @@ cut_cells_to_aggregate = setup_cells_to_aggregate(aggregate_to_cut_cells) U_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(U_aggregate_dof_ids),cut_cells_to_aggregate) P_cut_cells_to_aggregate_dof_ids=lazy_map(Reindex(P_aggregate_dof_ids),cut_cells_to_aggregate) -########################################### -### Setup projections -########################################### +##==============================================================================## +# OBJECTIVE +##==============================================================================## +#= + Compute and assemble the bulk penalty stabilization term -du_proj_Vbb, dv_proj_Vbb = setup_L2_proj_in_bb_space( - dΩbg_agg_cells, # measure of aggregated cells in background domain - ref_agg_cell_to_ref_bb_map, # map - agg_cells_to_aggregate, # - aggregate_to_local_cells, # - du, # Trial basis (to project) - dv, # Test basis - ubb, # Trial basis of bounding box space Vbb - vbb, # Test basis of bounding box space Vbb - identity, # operation to be applied to u and v - U_agg_cells_local_dof_ids) # aggregates local dof ids for space U - -dp_proj_Qbb, dq_proj_Qbb = setup_L2_proj_in_bb_space( - dΩbg_agg_cells, # measure of aggregated cells in background domain - ref_agg_cell_to_ref_bb_map, # map - agg_cells_to_aggregate, # - aggregate_to_local_cells, # - dp, # Trial basis (to project) - dq, # Test basis - pbb, # Trial basis of bounding box space Qbb - qbb, # Test basis of bounding box space Qbb - identity, # operation to be applied to u and v - P_agg_cells_local_dof_ids) # aggregates local dof ids for space P - -div_du_proj_Vbb, div_dv_proj_Vbb = setup_L2_proj_in_bb_space( - dΩbg_agg_cells, # measure of aggregated cells in background domain - ref_agg_cell_to_ref_bb_map, # map - agg_cells_to_aggregate, # - aggregate_to_local_cells, # - du, # Trial basis (to project) - dv, # Test basis - pbb, # Trial basis of bounding box space Vbb - qbb, # Test basis of bounding box space Vbb - divergence, # operation to be applied to u and v - U_agg_cells_local_dof_ids) # aggregates local dof ids for space U - -#### ---------------------- #### -if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - testP_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) -end + γ ∫( (v)⊙(rhs_function - proj_rhs_function) )*dD + + with `v` the test basis functions (which may be components of a MultiField). The L2 projections `proj_rhs_function` can be computed via `setup_L2_proj_in_bb_space`. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. The function `rhs_function` is the forcing term appearing on the right hand-side of the PDE. + + Here, we are interested in using the pressure basis functions for the test space, thus v = dq. In addition, dD = dΩbg_cut_cells. +=# # Manually set up the arrays that collect_cell_vector would return automatically test_w = [] test_r = [] -######################## (1) int (rhs_function)*dq) ######################### +# Pick a rhs function #rhs_func(x) = 10.0*x[1]^2 + sin(x[2]) rhs_func(x) = 10.0*x[1] #rhs_func(x) = 1000.0 -test_f = rhs_func -test_rhs_vec_contribs1=get_array(∫((rhs_func)*dq)*dΩbg_cut_cells) + +##==============================================================================## +# First term: γ ∫( (v)⊙(rhs_function) )*dD +##==============================================================================## +test_rhs_vec_contribs1=get_array(∫((rhs_func)*dq)*dΩbg_cut_cells) # 16-element array, one entry per T ∈ Ωbg_cut_cells, with 1-element Vector (for pressure) per cell T. push!(test_w, test_rhs_vec_contribs1) + +if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + testP_Ωbg_cut_cell_dof_ids=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_Ωbg_cut_cell_dof_ids) +end push!(test_r, testP_Ωbg_cut_cell_dof_ids) -######################## (2) proj_rhs_function*dq ######################### (2) -test_wbb = pbb -test_zbb = qbb +##==============================================================================## +# Second term: γ ∫( (v)⊙(proj_rhs_function) )*dD +##==============================================================================## + +## (1) Set-up proj_rhs_function using +#= + +returns the L2 projection in the bounding box space of the rhs function. That is, the L2 projection is defined through + + ∫ (rhs_func - Π_{Zbb}(operation(u)) zbb dΩbg_agg_cells = 0 ∀ zbb ∈ Zbb(T), + +with T ∈ T_agg and `Zbb` the bounding box space. Note that Ωbg_agg_cells ⊆ Ωbg_bb. Additionally, Π_{Zbb}(operation(u)) appears in the lhs as the trial function wbb ∈ Zbb. + +=# +test_wbb = pbb # Bounding box trial space (for pressure) +test_zbb = qbb # Bounding box test space (for pressure) +# evaluate(Gridap.CellData.get_data(qbb)[1],[Point(0.0,0.0)]) test_wbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(test_wbb, ref_agg_cell_to_ref_bb_map, Ωbg_agg_cells, agg_cells_to_aggregate) # trial test_zbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(test_zbb, ref_agg_cell_to_ref_bb_map, Ωbg_agg_cells, agg_cells_to_aggregate) # test +# evaluate(Gridap.CellData.get_data(test_zbb_Ωbg_agg_cells)[1],[Point(0.0,0.0)]) test_agg_cells_to_lhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells⋅test_wbb_Ωbg_agg_cells)dΩbg_agg_cells) -test_ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(test_agg_cells_to_lhs_contribs) -test_lhs = lazy_map(test_ass_lhs_map,aggregate_to_local_cells) -test_agg_cells_rhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells*test_f)dΩbg_agg_cells) - +test_ass_lhs_map= BulkGhostPenaltyAssembleLhsMap(test_agg_cells_to_lhs_contribs) +test_lhs = lazy_map(test_ass_lhs_map,aggregate_to_local_cells) +test_agg_cells_rhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells*rhs_func)dΩbg_agg_cells) -evaluate(Gridap.CellData.get_data(test_zbb_Ωbg_agg_cells)[1],[Point(0.0,0.0)]) -evaluate(Gridap.CellData.get_data(qbb)[8],[Point(0.0,0.0)]) -evaluate(Gridap.CellData.get_data(qbb)[8],[Point(0.0,0.0)]) -test_lhs[1] +# test_lhs[1] # Gridap.CellData.get_triangulation(dΩbg_agg_cells.quad) === Gridap.CellData.get_triangulation(test_zbb_Ωbg_agg_cells) - test_ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,test_agg_cells_rhs_contribs) # (!) No need to apply BlockMap! test_rhs=lazy_map(test_ass_rhs_map,aggregate_to_local_cells) test_f_proj_Zbb_dofs=lazy_map(\,test_lhs,test_rhs) test_f_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, test_f_proj_Zbb_dofs, Gridap.CellData.get_data(test_zbb)) -Gridap.CellData.get_data(test_zbb) - - -evaluate((test_f_proj_Zbb_array)[1],[Point(0.0,0.0)]) - - -test_rhs[1] -test_rhs[1] +# Gridap.CellData.get_data(test_zbb) +# evaluate((test_f_proj_Zbb_array)[1],[Point(0.0,0.0)]) test_f_proj_Zbb_dofs[1] # dofs belonging to the four cells in the first aggregate test_f_proj_Zbb_array[1] # 4 x linear combinations of four cells in aggregate -# (7) Change domain of proj_op_u and proj_op_v from Ωbb to Ωbg_agg_cells +# Change domain of proj_op_u and proj_op_v from Ωbb to Ωbg_agg_cells test_f_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), lazy_map(Reindex(test_f_proj_Zbb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) # contains 24 entries, with nr of operation fields equal to the nr of cells in that aggregate. -# .... test_fT_proj_Zbb_array_agg_cells=lazy_map(transpose, test_f_proj_Zbb_array_agg_cells) if (_is_multifield_fe_basis_component(dp)) @assert _is_multifield_fe_basis_component(dq) @@ -292,52 +270,39 @@ if (_is_multifield_fe_basis_component(dq)) end test_f_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(test_f_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) +## (2) Define γ ∫( (v)⊙(proj_rhs_function) )*dD dq_on_Ωbg_agg_cells = Gridap.CellData.change_domain(dq,Ωbg_agg_cells,ReferenceDomain()) dp_on_Ωbg_agg_cells = Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) -## ANOTHER TEST ## -testarray_dp_test_f = get_array(∫(dp_on_Ωbg_agg_cells⊙test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) #matrix - -testarray_dq_test_f = get_array(∫(dq_on_Ωbg_agg_cells*test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) +test_rhs_vec_contribs2 = get_array(∫((-1.0)*(test_fT_proj_Zbb_agg_cells)⋅dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) #DEBUG ME: here output is cell matrix and should be cell vector +test_rhs_vec_contribs2[2][2,2] # this should be a 4-element vector? +push!(test_w, test_rhs_vec_contribs2) +if (_is_multifield_fe_basis_component(dq)) + nfields=_nfields(dq) + fieldid=_fieldid(dq) + test_P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) +end +push!(test_r, test_P_cut_cells_to_aggregate_dof_ids) +test_P_cut_cells_to_aggregate_dof_ids[1][2] -testarray_test_f_dq = get_array(∫(test_f_proj_Zbb_agg_cells⊙dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) +## TESTING OTHER CONTRIBS TERMS: +testarray_dp_test_f = get_array(∫(dp_on_Ωbg_agg_cells⊙test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) #matrix +testarray_dq_test_f = get_array(∫(dq_on_Ωbg_agg_cells*test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) # AssertionError: A check failed. +testarray_test_f_dq = get_array(∫(test_f_proj_Zbb_agg_cells⊙dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) # AssertionError: A check failed. testarray_dq_test_fT = get_array(∫(dq_on_Ωbg_agg_cells⊙test_fT_proj_Zbb_agg_cells)*dΩbg_cut_cells) testarray_test_fT_dq = get_array(∫(test_fT_proj_Zbb_agg_cells⊙dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) -testarray_dq_test_f[1] -testarray_test_f_dq[1] -testarray_dq_test_fT[1] -testarray_test_fT_dq[1] - -### ---- START TEST ## +### START TEST ### ## THE FOLLOWING SEEMS TO IMPLY THAT test_fT_proj_Zbb_agg_cells is the projected rhs_func. # NOTE that for (lowest order Pbb) a rhs_func which takes on a constant value everywhere, the different/error = machine precision, whereas for higher order functions this is not the case (as expected) sum_cut_cells = sum([sum(get_array(∫(test_fT_proj_Zbb_agg_cells)dΩbg_cut_cells)[i][2]) for i=1:16]) sum((get_array(∫(rhs_func)*dΩbg_cut_cells))) @assert abs(sum_cut_cells - sum((get_array(∫(rhs_func)*dΩbg_cut_cells)))) <1e-12 difference = abs(sum_cut_cells - sum((get_array(∫(rhs_func)*dΩbg_cut_cells)))) -### ---- END TEST ## - -# push contributions to rhs_vec -# test_rhs_vec_contribs2=get_array(∫((-1.0)*(test_fT_proj_Zbb_agg_cells)⋅(dq_on_Ωbg_agg_cells))*dΩbg_cut_cells) - -test_rhs_vec_contribs2 = get_array(∫((-1.0)*(test_fT_proj_Zbb_agg_cells)⋅dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) -#DEBUG ME: here output is cell matrix and should be cell vector - - - -push!(test_w, test_rhs_vec_contribs2) -if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - test_P_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) -end -push!(test_r, test_P_cut_cells_to_aggregate_dof_ids) - -test_w[2][1] +### END TEST ### -#### -- PROBLEM -- #### +#### -- TEST PROBLEM -- #### test_a((u,p),(v,q))=∫(u⋅v+q*p)dΩ uex(x) = -VectorValue(2.0,2.0) test_l((v,q))=∫(uex⋅v+1.0⋅q)dΩ @@ -353,22 +318,6 @@ test_vec_b=Gridap.FESpaces.collect_cell_vector(Y,test_l(dy)) push!(test_vec_b[1], test_w...) push!(test_vec_b[2], test_r...) -# test_w = [] -# test_r = [] -# push!(test_w, test_rhs_vec_contribs1) -# push!(test_r, testP_Ωbg_cut_cell_dof_ids) -# push!(test_w, test_rhs_vec_contribs2) -# push!(test_r, test_P_cut_cells_to_aggregate_dof_ids) - -# -# push!(test_mat_A[1], test_rhs_vec_contribs2...) -# push!(test_mat_A[2], test_P_cut_cells_to_aggregate_dof_ids...) - -# I AM CREATING MATRIX BLOCKS WHEN USING -# test_rhs_vec_contribs2=get_array(∫((-1.0)*(test_fT_proj_Zbb_agg_cells)⋅(dq_on_Ωbg_agg_cells))*dΩbg_cut_cells) - - - assem=SparseMatrixAssembler(X,Y) test_A = assemble_matrix(assem, test_mat_A) From f2ea75b603bd97c102ac6962b540cf598b7dd699 Mon Sep 17 00:00:00 2001 From: "Alberto F. Martin" Date: Thu, 10 Apr 2025 21:33:15 +1000 Subject: [PATCH 078/120] My solution approach to the bb projection of the mass conservation rhs function --- test_proj_rhs_func.jl | 49 ++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/test_proj_rhs_func.jl b/test_proj_rhs_func.jl index 24fb4c13..324bd2a8 100644 --- a/test_proj_rhs_func.jl +++ b/test_proj_rhs_func.jl @@ -233,49 +233,34 @@ test_agg_cells_rhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells*rhs_func)dΩbg # test_lhs[1] # Gridap.CellData.get_triangulation(dΩbg_agg_cells.quad) === Gridap.CellData.get_triangulation(test_zbb_Ωbg_agg_cells) +# test_ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,test_agg_cells_rhs_contribs) +# test_rhs=lazy_map(sum,aggregate_to_local_cells) +test_rhs = lazy_map(sum, + lazy_map(Broadcasting(Reindex(test_agg_cells_rhs_contribs)), + aggregate_to_local_cells)) -test_ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,test_agg_cells_rhs_contribs) # (!) No need to apply BlockMap! -test_rhs=lazy_map(test_ass_rhs_map,aggregate_to_local_cells) test_f_proj_Zbb_dofs=lazy_map(\,test_lhs,test_rhs) -test_f_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, test_f_proj_Zbb_dofs, Gridap.CellData.get_data(test_zbb)) +test_f_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, + test_f_proj_Zbb_dofs, + Gridap.CellData.get_data(test_zbb)) # Gridap.CellData.get_data(test_zbb) -# evaluate((test_f_proj_Zbb_array)[1],[Point(0.0,0.0)]) -test_f_proj_Zbb_dofs[1] # dofs belonging to the four cells in the first aggregate -test_f_proj_Zbb_array[1] # 4 x linear combinations of four cells in aggregate +test_f_proj_Zbb_dofs[2] +test_f_proj_Zbb_array[1] # Change domain of proj_op_u and proj_op_v from Ωbb to Ωbg_agg_cells -test_f_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), lazy_map(Reindex(test_f_proj_Zbb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) +test_f_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(test_f_proj_Zbb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) # contains 24 entries, with nr of operation fields equal to the nr of cells in that aggregate. - -test_fT_proj_Zbb_array_agg_cells=lazy_map(transpose, test_f_proj_Zbb_array_agg_cells) -if (_is_multifield_fe_basis_component(dp)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dq) - fieldid=_fieldid(dp) -test_fT_proj_Zbb_array_agg_cells=lazy_map(Gridap.Fields.BlockMap((1,nfields),fieldid), - test_fT_proj_Zbb_array_agg_cells) -end -test_fT_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(test_fT_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - -if (_is_multifield_fe_basis_component(dq)) - @assert _is_multifield_fe_basis_component(dq) - @assert _nfields(dp)==_nfields(dq) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - test_f_proj_Zbb_array_agg_cells=lazy_map( - Gridap.Fields.BlockMap(nfields,fieldid), - test_f_proj_Zbb_array_agg_cells) -end -test_f_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(test_f_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) +test_f_proj_Zbb_agg_cells = + Gridap.CellData.GenericCellField(test_f_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) ## (2) Define γ ∫( (v)⊙(proj_rhs_function) )*dD dq_on_Ωbg_agg_cells = Gridap.CellData.change_domain(dq,Ωbg_agg_cells,ReferenceDomain()) dp_on_Ωbg_agg_cells = Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) -test_rhs_vec_contribs2 = get_array(∫((-1.0)*(test_fT_proj_Zbb_agg_cells)⋅dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) #DEBUG ME: here output is cell matrix and should be cell vector -test_rhs_vec_contribs2[2][2,2] # this should be a 4-element vector? +test_rhs_vec_contribs2 = get_array(∫((-1.0)*(test_f_proj_Zbb_agg_cells)⋅dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) #DEBUG ME: here output is cell matrix and should be cell vector +test_rhs_vec_contribs2[2][2] push!(test_w, test_rhs_vec_contribs2) if (_is_multifield_fe_basis_component(dq)) nfields=_nfields(dq) @@ -290,8 +275,6 @@ test_P_cut_cells_to_aggregate_dof_ids[1][2] testarray_dp_test_f = get_array(∫(dp_on_Ωbg_agg_cells⊙test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) #matrix testarray_dq_test_f = get_array(∫(dq_on_Ωbg_agg_cells*test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) # AssertionError: A check failed. testarray_test_f_dq = get_array(∫(test_f_proj_Zbb_agg_cells⊙dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) # AssertionError: A check failed. -testarray_dq_test_fT = get_array(∫(dq_on_Ωbg_agg_cells⊙test_fT_proj_Zbb_agg_cells)*dΩbg_cut_cells) -testarray_test_fT_dq = get_array(∫(test_fT_proj_Zbb_agg_cells⊙dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) ### START TEST ### ## THE FOLLOWING SEEMS TO IMPLY THAT test_fT_proj_Zbb_agg_cells is the projected rhs_func. From be5d2f78fbe347c97b74400688105fbcf0514f7f Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 14 Apr 2025 11:53:52 +1000 Subject: [PATCH 079/120] Bump julia version for x86 tests --- .github/workflows/ci_x86.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_x86.yml b/.github/workflows/ci_x86.yml index 4415f5a5..c3b5744c 100644 --- a/.github/workflows/ci_x86.yml +++ b/.github/workflows/ci_x86.yml @@ -14,7 +14,7 @@ jobs: fail-fast: false matrix: version: - - '1.8' + - '1.10' os: - ubuntu-latest arch: From ed64edb792e29be8b9a97dab8adc0ce39a68471c Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 14 Apr 2025 12:09:58 +1000 Subject: [PATCH 080/120] Updated NEWS.md --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 325955f8..e01661ba 100644 --- a/NEWS.md +++ b/NEWS.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for distributed level-set geometries. Since PR[#99](https://github.com/gridap/GridapEmbedded.jl/pull/99). - Refactored the distributed code to allow for ghosted/unghosted geometries and triangulations. Since PR[#100](https://github.com/gridap/GridapEmbedded.jl/pull/100). +### Changed + +- Swapped `LightGraphs.jl` dependency to `Graphs.jl`, due to the former being deprecated. Since PR[#108](https://github.com/gridap/GridapEmbedded.jl/pull/108). + ## [0.9.5] - 2024-10-18 ### Added From 8b239144f52c53ce02a50972cca4681250b562be Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 14 Apr 2025 15:50:21 +1000 Subject: [PATCH 081/120] Added compute_active_model for SubFacetTriangulations --- .../EmbeddedFacetDiscretizations.jl | 14 +++-- src/Interfaces/Interfaces.jl | 3 ++ src/Interfaces/SubFacetTriangulations.jl | 51 ++++++++++++++++--- .../EmbeddedFacetDiscretizationsTests.jl | 30 +++++++---- 4 files changed, 73 insertions(+), 25 deletions(-) diff --git a/src/Interfaces/EmbeddedFacetDiscretizations.jl b/src/Interfaces/EmbeddedFacetDiscretizations.jl index 4086fb69..aff4d52a 100644 --- a/src/Interfaces/EmbeddedFacetDiscretizations.jl +++ b/src/Interfaces/EmbeddedFacetDiscretizations.jl @@ -126,10 +126,9 @@ function BoundaryTriangulation( in_or_out::Tuple, geo::CSG.Geometry) - trian1 = BoundaryTriangulation(facets,cut,in_or_out[1],geo) - trian2 = BoundaryTriangulation(facets,cut,in_or_out[2],geo) - num_cells(trian1) == 0 ? trian2 : lazy_append(trian1,trian2) - + a = BoundaryTriangulation(facets,cut,in_or_out[1],geo) + b = BoundaryTriangulation(facets,cut,in_or_out[2],geo) + iszero(num_cells(a)) ? b : lazy_append(a,b) end function BoundaryTriangulation( @@ -139,7 +138,7 @@ function BoundaryTriangulation( geo::CSG.Geometry) bgfacet_to_inoutcut = compute_bgfacet_to_inoutcut(cut,geo) - bgfacet_to_mask = lazy_map( a->a==in_or_out, bgfacet_to_inoutcut) + bgfacet_to_mask = lazy_map(isequal(in_or_out), bgfacet_to_inoutcut) _restrict_boundary_triangulation(cut.bgmodel,facets,bgfacet_to_mask) end @@ -161,7 +160,7 @@ function BoundaryTriangulation( geo::CSG.Geometry) bgfacet_to_inoutcut = compute_bgfacet_to_inoutcut(cut,geo) - bgfacet_to_mask = lazy_map( a->a==CUT, bgfacet_to_inoutcut) + bgfacet_to_mask = lazy_map(isequal(CUT), bgfacet_to_inoutcut) facets = _restrict_boundary_triangulation(cut.bgmodel,_facets,bgfacet_to_mask) facet_to_bgfacet = facets.glue.face_to_bgface @@ -173,7 +172,7 @@ function BoundaryTriangulation( _subfacet_to_facet = lazy_map(Reindex(bgfacet_to_facet),cut.subfacets.cell_to_bgcell) subfacet_to_inout = compute_subfacet_to_inout(cut,geo) - pred(a,b,c) = c != 0 && a==CUT && b==in_or_out.in_or_out + pred(a,b,c) = !iszero(c) && a==CUT && b==in_or_out.in_or_out mask = lazy_map( pred, subfacet_to_inoutcut, subfacet_to_inout, _subfacet_to_facet ) newsubfacets = findall(mask) subfacets = SubCellData(cut.subfacets,newsubfacets) @@ -183,7 +182,6 @@ function BoundaryTriangulation( end function _restrict_boundary_triangulation(model,facets,bgfacet_to_mask) - facet_to_bgfacet = facets.glue.face_to_bgface facet_to_mask = lazy_map(Reindex(bgfacet_to_mask),facet_to_bgfacet) n_bgfacets = length(bgfacet_to_mask) diff --git a/src/Interfaces/Interfaces.jl b/src/Interfaces/Interfaces.jl index 8f351d66..93466bc6 100644 --- a/src/Interfaces/Interfaces.jl +++ b/src/Interfaces/Interfaces.jl @@ -1,5 +1,6 @@ module Interfaces +using Gridap using Gridap.Helpers using Gridap.Arrays using Gridap.Fields @@ -21,12 +22,14 @@ import Gridap.Geometry: get_reffes import Gridap.Geometry: get_cell_type import Gridap.Geometry: get_background_model import Gridap.Geometry: get_active_model +import Gridap.Geometry: compute_active_model import Gridap.Geometry: get_glue import Gridap.Geometry: get_grid import Gridap.Geometry: FaceToFaceGlue import Gridap.Geometry: get_facet_normal import Gridap.Geometry: move_contributions using Gridap.Geometry: GenericTriangulation +using Gridap.Geometry: CompositeTriangulation using GridapEmbedded.CSG diff --git a/src/Interfaces/SubFacetTriangulations.jl b/src/Interfaces/SubFacetTriangulations.jl index 39ae92e2..cad6d6c0 100644 --- a/src/Interfaces/SubFacetTriangulations.jl +++ b/src/Interfaces/SubFacetTriangulations.jl @@ -39,14 +39,6 @@ function get_background_model(a::SubFacetTriangulation) a.bgmodel end -function get_active_model(a::SubFacetTriangulation) - msg = """ - This is not implemented, but also not needed in practice. - Embedded Grids implemented for integration, not interpolation. - """ - @notimplemented msg -end - function get_grid(a::SubFacetTriangulation) a.subgrid end @@ -88,6 +80,49 @@ function move_contributions(scell_to_val::AbstractArray,strian::SubFacetTriangul acell_to_val, Ωa end +# Compute the active model +# To do this, we need to glue together the subfacets, which unfortunately requires comparing +# the point coordinates... +function compute_active_model(trian::SubFacetTriangulation) + subgrid = trian.subgrid + subfacets = trian.subfacets + facet_to_uids, uid_to_point = consistent_facet_to_points( + subfacets.facet_to_points, subfacets.point_to_coords + ) + topo = UnstructuredGridTopology( + subgrid, facet_to_uids, uid_to_point + ) + return UnstructuredDiscreteModel(subgrid,topo,FaceLabeling(topo)) +end + +function consistent_facet_to_points( + facet_to_points::Table, point_to_coords::Vector +) + f(pt::VectorValue) = VectorValue(round.(pt.data;sigdigits=12)) + f(id::Integer) = f(point_to_coords[id]) + + # Create a list of the unique points composing the facets + npts = length(point_to_coords) + nfaces = length(facet_to_points) + touched = zeros(Bool,npts) + for face in 1:nfaces + pts = view(facet_to_points,face) + touched[pts] .= true + end + touched_ids = findall(touched) + unique_ids = unique(f,touched_ids) + + # Create a mapping from the old point ids to the new ones + touched_to_uid = collect(Int32,indexin(f.(touched_ids),f.(unique_ids))) + point_to_uid = extend(touched_to_uid,PosNegPartition(touched_ids,npts)) + + facet_to_uids = Table( + collect(Int32,lazy_map(Reindex(point_to_uid),facet_to_points.data)), + facet_to_points.ptrs + ) + return facet_to_uids, unique_ids +end + # API function UnstructuredGrid(st::SubFacetData{Dp}) where Dp diff --git a/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl b/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl index 7e6c9416..959f07b5 100644 --- a/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl +++ b/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl @@ -8,6 +8,9 @@ using Gridap.Geometry using GridapEmbedded.Interfaces using GridapEmbedded.LevelSetCutters +########################################## +# 2D tests + n = 10 partition = (n,n) domain = (0,1,0,1) @@ -37,6 +40,8 @@ u = interpolate(x->x[1]+x[2],V) Γ = lazy_append(Γu,Γf) Λ = SkeletonTriangulation(cutgeo_facets,PHYSICAL) +face_model = get_active_model(Γu) + test_triangulation(Ω) test_triangulation(Γ) test_triangulation(Λ) @@ -69,16 +74,20 @@ celldata_Λ = [ "bgcell_right"=>collect(Int,get_glue(Λ.⁻,Val(D)).tface_to_mface)] cellfields_Λ = ["normal"=> n_Λ.⁺,"jump_v"=>jump(v),"jump_u"=>jump(u)] -d = mktempdir() +d = "./dev"#mktempdir() try - writevtk(Ωbg,joinpath(d,"trian")) - writevtk(Ω,joinpath(d,"trian_O"),celldata=celldata_Ω,cellfields=cellfields_Ω) - writevtk(Γ,joinpath(d,"trian_G"),celldata=celldata_Γ,cellfields=cellfields_Γ) - writevtk(Λ,joinpath(d,"trian_sO"),celldata=celldata_Λ,cellfields=cellfields_Λ) + writevtk(Ωbg,joinpath(d,"trian"),append=false) + writevtk(Ω,joinpath(d,"trian_O"),celldata=celldata_Ω,cellfields=cellfields_Ω,append=false) + writevtk(Γ,joinpath(d,"trian_G"),celldata=celldata_Γ,cellfields=cellfields_Γ,append=false) + writevtk(Λ,joinpath(d,"trian_sO"),celldata=celldata_Λ,cellfields=cellfields_Λ,append=false) + writevtk(Γf,joinpath(d,"trian_Gf"),append=false) finally - rm(d,recursive=true) + #rm(d,recursive=true) end +########################################## +# 3D tests + n = 10 partition = (n,n,n) domain = (0,1,0,1,0,1) @@ -95,11 +104,14 @@ trian_s = SkeletonTriangulation(bgmodel) trian_sΩ = SkeletonTriangulation(trian_s,cutgeo_facets,PHYSICAL_IN,geo) trian_sΩo = SkeletonTriangulation(trian_s,cutgeo_facets,PHYSICAL_OUT,geo) +Γu = EmbeddedBoundary(cutgeo) +face_model = get_active_model(Γu) + d = mktempdir() try -writevtk(trian_s,joinpath(d,"trian_s")) -writevtk(trian_sΩ,joinpath(d,"trian_sO")) -writevtk(trian_sΩo,joinpath(d,"trian_sOo")) + writevtk(trian_s,joinpath(d,"trian_s")) + writevtk(trian_sΩ,joinpath(d,"trian_sO")) + writevtk(trian_sΩo,joinpath(d,"trian_sOo")) finally rm(d,recursive=true) end From 2bf31243e6f41a8ef4d11556fe53a316df537735 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 14 Apr 2025 15:52:27 +1000 Subject: [PATCH 082/120] Fixed remove_ghost_cells for empty parts and AppendedTriangulations --- src/Distributed/DistributedDiscretizations.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index a49fd25c..5d873558 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -92,7 +92,9 @@ end function remove_ghost_cells(trian::AppendedTriangulation,gids) a = remove_ghost_cells(trian.a,gids) b = remove_ghost_cells(trian.b,gids) - lazy_append(a,b) + iszero(num_cells(a)) && return b + iszero(num_cells(b)) && return a + return lazy_append(a,b) end function remove_ghost_cells(trian::SubFacetTriangulation{Df,Dc},gids) where {Df,Dc} From 55715ec3d58d546ba3baebe2105151c682ce5dd5 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 14 Apr 2025 16:45:20 +1000 Subject: [PATCH 083/120] Added CutFaceBoundaryTriangulations --- .../CutFaceBoundaryTriangulations.jl | 455 ++++++++++++++++++ .../EmbeddedFacetDiscretizations.jl | 15 + src/Interfaces/Interfaces.jl | 11 + .../EmbeddedFacetDiscretizationsTests.jl | 2 + 4 files changed, 483 insertions(+) create mode 100644 src/Interfaces/CutFaceBoundaryTriangulations.jl diff --git a/src/Interfaces/CutFaceBoundaryTriangulations.jl b/src/Interfaces/CutFaceBoundaryTriangulations.jl new file mode 100644 index 00000000..d30ada3a --- /dev/null +++ b/src/Interfaces/CutFaceBoundaryTriangulations.jl @@ -0,0 +1,455 @@ + +# Ghost triangulations + +function generate_ghost_trian( + trian::CompositeTriangulation, bgmodel +) + Dc = num_cell_dims(bgmodel) + cell_glue = get_glue(trian,Val(Dc)) + return generate_ghost_trian(trian,bgmodel,cell_glue) +end + +function generate_ghost_trian( + trian::CompositeTriangulation, bgmodel, cell_glue::SkeletonPair{<:FaceToFaceGlue} +) + Dc = num_cell_dims(bgmodel) + topo = get_grid_topology(bgmodel) + face_to_cell = get_faces(topo,Dc-1,Dc) + cell_to_face = get_faces(topo,Dc,Dc-1) + + n_bgfaces = num_faces(bgmodel,Dc-1) + n_faces = num_cells(trian) + ghost_faces = zeros(Int32,n_faces) + p_lcell = ones(Int8,n_bgfaces) + m_lcell = ones(Int8,n_bgfaces) + for (i,(p_cell, m_cell)) in enumerate(zip(cell_glue.plus.tface_to_mface,cell_glue.minus.tface_to_mface)) + inter = intersect(cell_to_face[p_cell],cell_to_face[m_cell]) + @assert length(inter) == 1 + face = first(inter) + ghost_faces[i] = face + + nbors = face_to_cell[ghost_faces[i]] + p_lcell[face] = findfirst(==(p_cell),nbors) + m_lcell[face] = findfirst(==(m_cell),nbors) + end + + plus = BoundaryTriangulation(bgmodel,ghost_faces,p_lcell) + minus = BoundaryTriangulation(bgmodel,ghost_faces,m_lcell) + return SkeletonTriangulation(plus,minus) +end + +function generate_ghost_trian( + trian::CompositeTriangulation, bgmodel, cell_glue::FaceToFaceGlue +) + Dc = num_cell_dims(bgmodel) + topo = get_grid_topology(bgmodel) + face_to_cell = get_faces(topo,Dc-1,Dc) + cell_to_face = get_faces(topo,Dc,Dc-1) + is_boundary(f) = isone(length(view(face_to_cell,f))) + + n_faces = num_cells(trian) + ghost_faces = zeros(Int32,n_faces) + for (i,cell) in enumerate(cell_glue.tface_to_mface) + faces = filter(is_boundary,view(cell_to_face,cell)) + @assert length(faces) == 1 # TODO: This will break if we are in a corner + face = first(faces) + ghost_faces[i] = face + end + + # NOTE: lcell is always 1 for boundary facets + return BoundaryTriangulation(bgmodel,ghost_faces) +end + +""" + get_ghost_mask( + face_trian::SubFacetTriangulation{Df,Dc}, + face_model = get_active_model(face_trian) + ) where {Df,Dc} + +Returns a mask for ghost faces. We define ghost faces as the interfaces between two +different cut facets that are located in different background cells. + +The second condition is important: In 3D, some cuts subcells may not be simplices. +In this case, we simplexify the subcell. This creates extra cut interfaces that are +interior to a background cell. These are not considered ghost faces. + +- In 2D: Dc = 2, Df = 1 -> Ghost faces have dimension 0 (i.e interface points) +- In 3D: Dc = 3, Df = 2 -> Ghost faces have dimension 1 (i.e interface edges) +""" +function get_ghost_mask( + face_trian::SubFacetTriangulation{Df,Dc}, + face_model = get_active_model(face_trian) +) where {Df,Dc} + topo = get_grid_topology(face_model) + face_to_facets = get_faces(topo,Df-1,Df) + + subfacets = face_trian.subfacets + facet_to_bgcell = subfacets.facet_to_bgcell + + n_faces = num_faces(topo,Df-1) + face_is_ghost = zeros(Bool,n_faces) + for face in 1:n_faces + facets = view(face_to_facets,face) + is_boundary = isone(length(facets)) + if !is_boundary + @assert length(facets) == 2 + bgcells = view(facet_to_bgcell,facets) + is_ghost = (bgcells[1] != bgcells[2]) + face_is_ghost[face] = is_ghost + end + end + + return face_is_ghost +end + +""" + struct CutFaceBoundaryTriangulation{Di,Df,Dp} <: Triangulation{Di,Dp} + +Triangulation containing the interfaces between subfacets. We always have dimensions + + - Dc :: Dimension of the background mesh + - Df = Dc-1 :: Dimension of the cut subfacets + - Di = Dc-2 :: Dimension of the subfacet interfaces + +Description of the different components: + +- `face_trian` :: Original SubFacetTriangulation, built on top of the background mesh. +- `face_model` :: Subfacet model. Active model for `face_trian`. +- `face_boundary` :: Triangulation of the interfaces between subfacets. It is glued to the `face_model`. +- `cell_boundary` :: Conceptually the same as `face_boundary`, but it is glued to the + background mesh cells. Created as a CompositeTriangulation between `face_trian` and `face_boundary`. +- `ghost_boundary` :: Triangulation of the background facets that contain each interface. + +The "real" triangulation is `cell_boundary`, but we require the other triangulations to +perform complex changes of domain. Most of the `Triangulation` API is delegated to `cell_boundary`. + +## Constructors + + Boundary(face_trian::SubFacetTriangulation) + Skeleton(face_trian::SubFacetTriangulation) + +""" +struct CutFaceBoundaryTriangulation{Di,Df,Dp} <: Triangulation{Di,Dp} + face_model :: UnstructuredDiscreteModel{Df,Dp} + face_trian :: SubFacetTriangulation{Df,Dp} # Cut Facet -> BG Cell + cell_boundary :: CompositeTriangulation{Di,Dp} # Interface -> BG Cell + face_boundary :: BoundaryTriangulation{Di,Dp} # Interface -> Cut Facet + ghost_boundary :: BoundaryTriangulation{Df,Dp} # Ghost Facet -> BG Cell + interface_sign :: AbstractArray{<:Number} +end + +function BoundaryTriangulation(face_trian::SubFacetTriangulation) + bgmodel = get_background_model(face_trian) + face_model = get_active_model(face_trian) + + face_boundary = BoundaryTriangulation(face_model) + cell_boundary = CompositeTriangulation(face_trian,face_boundary) + ghost_boundary = generate_ghost_trian(cell_boundary,bgmodel) + interface_sign = get_interface_sign(cell_boundary,face_trian,ghost_boundary) + + return CutFaceBoundaryTriangulation( + face_model,face_trian,cell_boundary,face_boundary,ghost_boundary,interface_sign + ) +end + +function get_background_model(t::CutFaceBoundaryTriangulation) + get_background_model(t.cell_boundary) +end + +function get_active_model(t::CutFaceBoundaryTriangulation) + get_active_model(t.cell_boundary) +end + +function get_grid(t::CutFaceBoundaryTriangulation) + get_grid(t.cell_boundary) +end + +# Domain changes + +function get_glue(ttrian::CutFaceBoundaryTriangulation{Di,Df,Dp},::Val{D}) where {D,Di,Df,Dp} + get_glue(ttrian.cell_boundary,Val(D)) +end + +function is_change_possible( + strian::SubFacetTriangulation,ttrian::CutFaceBoundaryTriangulation +) + return strian === ttrian.face_trian +end + +function CellData.change_domain( + a::CellField,ttrian::CutFaceBoundaryTriangulation,tdomain::DomainStyle +) + strian = get_triangulation(a) + if strian === ttrian + # 1) CellField defined on the skeleton + return change_domain(a,DomainStyle(a),tdomain) + end + + if is_change_possible(strian,ttrian.cell_boundary) + # 2) CellField defined on the bgmodel + b = change_domain(a,ttrian.cell_boundary,tdomain) + elseif strian === ttrian.face_trian + # 3) CellField defined on the cut facets + itrian = Triangulation(ttrian.face_model) + _a = CellData.similar_cell_field(a,CellData.get_data(a),itrian,DomainStyle(a)) + b = change_domain(_a,ttrian.face_boundary,tdomain) + else + @notimplemented + end + return CellData.similar_cell_field(b,CellData.get_data(b),ttrian,DomainStyle(b)) +end + +function CellData.change_domain( + f::CellData.OperationCellField,ttrian::CutFaceBoundaryTriangulation,tdomain::DomainStyle +) + args = map(i->change_domain(i,ttrian,tdomain),f.args) + CellData.OperationCellField(f.op,args...) +end + +# Normal vector to the cut facets , n_∂Ω +function get_subfacet_normal_vector(trian::CutFaceBoundaryTriangulation) + n_∂Ω = get_subfacet_facet_normal(trian.cell_boundary,trian.face_trian) + return GenericCellField(n_∂Ω,trian,ReferenceDomain()) +end + +# Normal vector to the ghost facets, n_k +function get_ghost_normal_vector(trian::CutFaceBoundaryTriangulation) + n = get_ghost_facet_normal(trian.cell_boundary,trian.ghost_boundary) + return GenericCellField(n,trian,ReferenceDomain()) +end + +# Orientation of the interface +function get_interface_sign(trian::CutFaceBoundaryTriangulation) + data = lazy_map(constant_field,trian.interface_sign) + return GenericCellField(data,trian,ReferenceDomain()) +end + +# TODO: This is only valid when dealing with linear meshes (where normals are constant over facets). +# If we wanted to use higher-order meshes, we would need to generate the geometric map +# going from the facets to the interfaces. +# However, having a high-order background mesh seems quite silly. +function get_ghost_facet_normal( + itrian::CompositeTriangulation{Di,Dc}, # Interface -> BG Cell + gtrian::BoundaryTriangulation{Df,Dc} # Ghost Facet -> BG Cell +) where {Di,Df,Dc} + n_g = get_facet_normal(gtrian) + n_i = lazy_map(evaluate,n_g,Fill(zero(VectorValue{Df,Float64}),num_cells(itrian))) + return lazy_map(constant_field,n_i) +end + +# This one would be fine for higher-order meshes. +function get_subfacet_facet_normal( + itrian::CompositeTriangulation{Di,Dc}, # Interface -> BG Cell + ftrian::SubFacetTriangulation{Df,Dc}, # Cut Facet -> BG Cell +) where {Di,Df,Dc} + glue = get_glue(itrian.dtrian,Val(Df)) + i_to_f_ids = glue.tface_to_mface + i_to_f_map = glue.tface_to_mface_map + n_f = lazy_map(Reindex(get_facet_normal(ftrian)),i_to_f_ids) + n_i = lazy_map(Broadcasting(∘),n_f,i_to_f_map) + return n_i +end + +# There is still something sweaty about this... +# Why do we apply the sign change but at the same time call `get_edge_tangents` in the +# creation of conormal vectors in 3D? It's like we are cancelling the sign change... +# There is more to think about here. +function get_interface_sign( + itrian::CompositeTriangulation{Di,Dc}, # Interface -> BG Cell + ftrian::SubFacetTriangulation{Df,Dc}, # Cut Facet -> BG Cell + gtrian::BoundaryTriangulation{Df,Dc}, # Ghost Facet -> BG Cell +) where {Di,Df,Dc} + function signdot(a,b) + s = sign(dot(a,b)) + return ifelse(iszero(s),1,s) + end + n_∂Ω = get_subfacet_facet_normal(itrian,ftrian) + n_k = get_ghost_facet_normal(itrian,gtrian) + if Di == 0 + cross2D(n) = VectorValue(-n[2],n[1]) + n_S = lazy_map(Operation(cross2D),n_k) + else + t_S = get_edge_tangents(itrian.dtrian) + n_S = lazy_map(Operation(cross),n_k,t_S) + end + sgn = lazy_map(Operation(signdot),n_∂Ω,n_S) + return collect(lazy_map(evaluate,sgn,Fill(zero(VectorValue{Di,Float64}),num_cells(itrian)))) +end + +function get_edge_tangents(trian::BoundaryTriangulation{1}) + function t(c) + @assert length(c) == 2 + t = c[2] - c[1] + return t/norm(t) + end + return lazy_map(constant_field,lazy_map(t,get_cell_coordinates(trian))) +end + +function get_edge_tangents(trian::CutFaceBoundaryTriangulation{1}) + data = get_edge_tangents(trian.face_boundary) + return GenericCellField(data,trian,ReferenceDomain()) +end + +# Normal vector to the cut interface, n_S +function get_normal_vector(trian::CutFaceBoundaryTriangulation{Di}) where {Di} + n_k = get_ghost_normal_vector(trian) + isign = get_interface_sign(trian) + if Di == 0 # 2D + cross2D(n) = VectorValue(-n[2],n[1]) + n_S = Operation(cross2D)(n_k) # nS = nk x tS and tS = ±e₃ in 2D + elseif Di == 1 # 3D + t_S = get_edge_tangents(trian) + n_S = Operation(cross)(n_k,t_S) # nk = tS x nS -> nS = nk x tS (eq 6.25) + else + @notimplemented + end + return n_S * isign +end + +get_facet_normal(trian::CutFaceBoundaryTriangulation) = get_data(get_normal_vector(trian)) + +# Tangent vector to the cut interface, t_S = n_S x n_k +function get_tangent_vector(trian::CutFaceBoundaryTriangulation{Di}) where {Di} + @notimplementedif Di != 1 + n_S = get_normal_vector(trian) + n_k = get_ghost_normal_vector(trian) + return Operation(cross)(n_S,n_k) +end + +# Conormal vectors, m_k = t_S x n_∂Ω +function get_conormal_vector(trian::CutFaceBoundaryTriangulation{Di}) where {Di} + n_∂Ω = get_subfacet_normal_vector(trian) + isign = get_interface_sign(trian) + if Di == 0 # 2D + cross2D(n) = VectorValue(n[2],-n[1]) + m_k = Operation(cross2D)(n_∂Ω) + elseif Di == 1 # 3D + t_S = get_edge_tangents(trian) + m_k = Operation(cross)(t_S,n_∂Ω) # m_k = t_S x n_∂Ω (eq 6.26) + else + @notimplemented + end + return m_k * isign +end + +# CutFaceSkeletonTriangulation & CutFaceBoundaryTriangulationView +const CutFaceBoundaryTriangulationView{Di,Df,Dp} = TriangulationView{Di,Dp,CutFaceBoundaryTriangulation{Di,Df,Dp}} +const CutFaceSkeletonTriangulation{Di,Df,Dp} = SkeletonTriangulation{Di,Dp,<:Union{ + CutFaceBoundaryTriangulation{Di,Df,Dp}, + CutFaceBoundaryTriangulationView{Di,Df,Dp} + } +} + +function SkeletonTriangulation(face_trian::SubFacetTriangulation) + bgmodel = get_background_model(face_trian) + face_model = get_active_model(face_trian) + + ghost_mask = get_ghost_mask(face_trian,face_model) + face_skeleton = SkeletonTriangulation(face_model,ghost_mask) + cell_skeleton = CompositeTriangulation(face_trian,face_skeleton) + ghost_skeleton = generate_ghost_trian(cell_skeleton,bgmodel) + + ctrian_plus = CompositeTriangulation(face_trian,face_skeleton.plus) + ctrian_minus = CompositeTriangulation(face_trian,face_skeleton.minus) + isign_plus = get_interface_sign(ctrian_plus,face_trian,ghost_skeleton.plus) + isign_minus = get_interface_sign(ctrian_plus,face_trian,ghost_skeleton.minus) + + plus = CutFaceBoundaryTriangulation( + face_model,face_trian,ctrian_plus, + face_skeleton.plus,ghost_skeleton.plus,isign_plus + ) + minus = CutFaceBoundaryTriangulation( + face_model,face_trian,ctrian_minus, + face_skeleton.minus,ghost_skeleton.minus,isign_minus + ) + return SkeletonTriangulation(plus,minus) +end + +for func in (:get_subfacet_normal_vector,:get_ghost_normal_vector,:get_conormal_vector) + @eval begin + function $func(trian::CutFaceSkeletonTriangulation) + plus = GenericCellField(CellData.get_data($func(trian.plus)),trian,ReferenceDomain()) + minus = GenericCellField(CellData.get_data($func(trian.minus)),trian,ReferenceDomain()) + return SkeletonPair(plus,minus) + end + end +end + +for func in (:get_normal_vector,:get_tangent_vector) + @eval begin + function $func(trian::CutFaceSkeletonTriangulation) + return GenericCellField(CellData.get_data($func(trian.plus)),trian,ReferenceDomain()) + end + end +end + +for func in (:get_tangent_vector,:get_subfacet_normal_vector,:get_ghost_normal_vector,:get_conormal_vector) + @eval begin + function $func(trian::CutFaceBoundaryTriangulationView) + data = CellData.get_data($func(trian.parent)) + restricted_data = restrict(data,trian.cell_to_parent_cell) + return GenericCellField(restricted_data,trian,ReferenceDomain()) + end + end +end + +# Distributed +# Until we merge, we need changes in +# - GridapDistributed#master +# - GridapEmbedded#distributed + +# function GridapDistributed.remove_ghost_cells( +# trian::Union{<:CutFaceBoundaryTriangulation,<:CutFaceSkeletonTriangulation},gids +# ) +# model = get_background_model(trian) +# Dm = num_cell_dims(model) +# glue = get_glue(trian,Val(Dm)) +# GridapDistributed.remove_ghost_cells(glue,trian,gids) +# end +# +# for func in (:get_subfacet_normal_vector,:get_ghost_normal_vector,:get_conormal_vector,:get_tangent_vector) +# @eval begin +# function $func(a::DistributedTriangulation) +# fields = map($func,local_views(a)) +# DistributedCellField(fields,a) +# end +# end +# end + +############################################################################################ +# This will go to Gridap + +function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField}) + plus = k(a.plus) + minus = k(a.minus) + SkeletonPair(plus,minus) +end + +function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField}) + plus = k(a.plus,b.plus) + minus = k(a.minus,b.minus) + SkeletonPair(plus,minus) +end + +import Gridap.TensorValues: inner, outer +import LinearAlgebra: dot +import Base: abs, *, +, -, / + +for op in (:/,) + @eval begin + ($op)(a::CellField,b::SkeletonPair{<:CellField}) = Operation($op)(a,b) + ($op)(a::SkeletonPair{<:CellField},b::CellField) = Operation($op)(a,b) + end +end + +for op in (:outer,:*,:dot,:/) + @eval begin + ($op)(a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField}) = Operation($op)(a,b) + end +end + +function CellData.change_domain(a::SkeletonPair, ::ReferenceDomain, ::PhysicalDomain) + plus = change_domain(a.plus,ReferenceDomain(),PhysicalDomain()) + minus = change_domain(a.minus,ReferenceDomain(),PhysicalDomain()) + return SkeletonPair(plus,minus) +end diff --git a/src/Interfaces/EmbeddedFacetDiscretizations.jl b/src/Interfaces/EmbeddedFacetDiscretizations.jl index aff4d52a..56ece473 100644 --- a/src/Interfaces/EmbeddedFacetDiscretizations.jl +++ b/src/Interfaces/EmbeddedFacetDiscretizations.jl @@ -223,6 +223,21 @@ function compute_subfacet_to_inout(cut::EmbeddedFacetDiscretization,geo::CSG.Geo compute_inoutcut(newtree) end +""" + struct SubFacetBoundaryTriangulation{Dc,Dp,T} <: Triangulation{Dc,Dp} + +Triangulation of cut facets from the background mesh, i.e each of the facets +in this triangulation is part of a background facet that has been cut by the geometry. + +This differs from the the `SubFacetTriangulation` in that the facets in the `SubFacetTriangulation` +are not cut background facets, but rather subfacets on the interior of a background cell. + +They result from calling `Boundary` or `Skeleton` on an `EmbeddedFacetDiscretization` object, +for instance: + + BoundaryTriangulation(cut::EmbeddedFacetDiscretization,in_or_out,geo;tags=nothing) + +""" struct SubFacetBoundaryTriangulation{Dc,Dp,T} <: Triangulation{Dc,Dp} facets::BoundaryTriangulation{Dc,Dp} subfacets::SubCellData{Dc,Dp,T} diff --git a/src/Interfaces/Interfaces.jl b/src/Interfaces/Interfaces.jl index 93466bc6..c46961dd 100644 --- a/src/Interfaces/Interfaces.jl +++ b/src/Interfaces/Interfaces.jl @@ -1,5 +1,7 @@ module Interfaces +using FillArrays + using Gridap using Gridap.Helpers using Gridap.Arrays @@ -28,8 +30,15 @@ import Gridap.Geometry: get_grid import Gridap.Geometry: FaceToFaceGlue import Gridap.Geometry: get_facet_normal import Gridap.Geometry: move_contributions +import Gridap.Geometry: is_change_possible using Gridap.Geometry: GenericTriangulation using Gridap.Geometry: CompositeTriangulation +using Gridap.Geometry: TriangulationView +using Gridap.Geometry: restrict + +import Gridap.CellData: get_normal_vector +import Gridap.CellData: get_tangent_vector +import Gridap.Geometry: get_facet_normal using GridapEmbedded.CSG @@ -87,6 +96,8 @@ include("EmbeddedDiscretizations.jl") include("EmbeddedFacetDiscretizations.jl") +include("CutFaceBoundaryTriangulations.jl") + include("Cutters.jl") function Simplex(p::Polytope) diff --git a/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl b/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl index 959f07b5..bb51bcd3 100644 --- a/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl +++ b/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl @@ -41,6 +41,8 @@ u = interpolate(x->x[1]+x[2],V) Λ = SkeletonTriangulation(cutgeo_facets,PHYSICAL) face_model = get_active_model(Γu) +Σb = BoundaryTriangulation(Γu) +Σi = SkeletonTriangulation(Γu) test_triangulation(Ω) test_triangulation(Γ) From cb903a4410f2ecad7889b23cd22c2c9be186c0cf Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 14 Apr 2025 16:46:29 +1000 Subject: [PATCH 084/120] Minor --- test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl b/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl index bb51bcd3..04e7f527 100644 --- a/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl +++ b/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl @@ -108,6 +108,8 @@ trian_sΩo = SkeletonTriangulation(trian_s,cutgeo_facets,PHYSICAL_OUT,geo) Γu = EmbeddedBoundary(cutgeo) face_model = get_active_model(Γu) +Σb = BoundaryTriangulation(Γu) +Σi = SkeletonTriangulation(Γu) d = mktempdir() try From 02c9f8a98d618e9b70e44e095775430ea9218c5c Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Mon, 14 Apr 2025 16:52:31 +1000 Subject: [PATCH 085/120] Added Differentiable triangulations --- .../DifferentiableTriangulations.jl | 540 ++++++++++++++++++ src/LevelSetCutters/LevelSetCutters.jl | 3 + 2 files changed, 543 insertions(+) create mode 100644 src/LevelSetCutters/DifferentiableTriangulations.jl diff --git a/src/LevelSetCutters/DifferentiableTriangulations.jl b/src/LevelSetCutters/DifferentiableTriangulations.jl new file mode 100644 index 00000000..226e7fa8 --- /dev/null +++ b/src/LevelSetCutters/DifferentiableTriangulations.jl @@ -0,0 +1,540 @@ + + +""" + mutable struct DifferentiableTriangulation{Dc,Dp} <: Triangulation{Dc,Dp} + +A DifferentiableTriangulation is a wrapper around an embedded triangulation +(i.e SubCellTriangulation or SubFacetTriangulation) implementing all the necessary +methods to compute derivatives w.r.t. deformations of the embedded mesh. + +To do so, it propagates dual numbers into the geometric maps mapping cut subcells/subfacets +to the background mesh. + +## Constructor: + + DifferentiableTriangulation(trian::Triangulation,fe_space::FESpace) + +where `trian` must be an embedded triangulation and `fe_space` is the `FESpace` where +the level-set function lives. + +""" +mutable struct DifferentiableTriangulation{Dc,Dp,A,B} <: Triangulation{Dc,Dp} + trian :: A + fe_space :: B + cell_values + caches + function DifferentiableTriangulation( + trian :: Triangulation{Dc,Dp}, + fe_space :: FESpace, + cell_values,caches + ) where {Dc,Dp} + A = typeof(trian) + B = typeof(fe_space) + new{Dc,Dp,A,B}(trian,fe_space,cell_values,caches) + end +end + +# Constructors + +DifferentiableTriangulation(trian::Triangulation,fe_space) = trian + +function DifferentiableTriangulation( + trian::Union{<:SubCellTriangulation,<:SubFacetTriangulation}, + fe_space::FESpace +) + caches = precompute_autodiff_caches(trian) + return DifferentiableTriangulation(trian,fe_space,nothing,caches) +end + +# Update cell values + +(t::DifferentiableTriangulation)(φh) = update_trian!(t,get_fe_space(φh),φh) + +update_trian!(trian::Triangulation,U,φh) = trian + +function update_trian!(trian::DifferentiableTriangulation,space::FESpace,φh) + (trian.fe_space !== space) && return trian + trian.cell_values = extract_dualized_cell_values(trian.trian,φh) + return trian +end + +function update_trian!(trian::DifferentiableTriangulation,::FESpace,::Nothing) + trian.cell_values = nothing + return trian +end + +# Autodiff + +function FESpaces._change_argument( + op,f,trian::DifferentiableTriangulation,uh +) + U = get_fe_space(uh) + function g(cell_u) + cf = CellField(U,cell_u) + update_trian!(trian,U,cf) + cell_grad = f(cf) + update_trian!(trian,U,nothing) # TODO: experimental + get_contribution(cell_grad,trian) + end + g +end + +function FESpaces._compute_cell_ids(uh,ttrian::DifferentiableTriangulation) + FESpaces._compute_cell_ids(uh,ttrian.trian) +end + +function Geometry.get_background_model(t::DifferentiableTriangulation) + get_background_model(t.trian) +end + +function Geometry.get_grid(t::DifferentiableTriangulation) + get_grid(t.trian) +end + +function Geometry.get_cell_reffe(t::DifferentiableTriangulation) + get_cell_reffe(t.trian) +end + +# TODO: Do we ever need to dualize the cell points? +# I think its not necessary, since all the dual numbers are propagated through the cellmaps... +# Also: The current version dualizes only the phys points... +# If we want to indeed dualize this, we should probably also dualize the ref points +# in the case where ttrian.trian is a SubCellTriangulation (but not in the case of a SubFacetTriangulation) +# Anyway, I don't think this matters for now... +function CellData.get_cell_points(ttrian::DifferentiableTriangulation) + pts = get_cell_points(ttrian.trian) + cell_ref_point = pts.cell_ref_point + if isnothing(ttrian.cell_values) || isempty(ttrian.cell_values) + cell_phys_point = pts.cell_phys_point + else + c = ttrian.caches + cell_phys_point = lazy_map( + DualizeCoordsMap(),c.face_to_coords,c.face_to_bgcoords, + ttrian.cell_values,c.face_to_edges,c.face_to_edge_lists + ) + end + return CellPoint(cell_ref_point, cell_phys_point, ttrian, DomainStyle(pts)) +end + +function Geometry.get_cell_map(ttrian::DifferentiableTriangulation) + if isnothing(ttrian.cell_values) || isempty(ttrian.cell_values) + return get_cell_map(ttrian.trian) + end + c = ttrian.caches + cell_values = ttrian.cell_values + cell_to_coords = lazy_map( + DualizeCoordsMap(),c.face_to_coords,c.face_to_bgcoords, + cell_values,c.face_to_edges,c.face_to_edge_lists + ) + cell_reffe = get_cell_reffe(ttrian) + cell_map = compute_cell_maps(cell_to_coords,cell_reffe) + return cell_map +end + +function face_normal(face_coords::Vector{<:Point},orientation::Int8) + n = face_normal(face_coords) + return n*orientation +end +function face_normal(face_coords::Vector{<:Point{2}}) + p1, p2 = face_coords[1:2] + LevelSetCutters._normal_vector(p2-p1) +end +function face_normal(face_coords::Vector{<:Point{3}}) + p1, p2, p3 = face_coords[1:3] + LevelSetCutters._normal_vector(p2-p1,p3-p1) +end + +function Geometry.get_facet_normal( + ttrian::DifferentiableTriangulation{Dc,Dp,<:SubFacetTriangulation} +) where {Dc,Dp} + if isnothing(ttrian.cell_values) || isempty(ttrian.cell_values) + return get_facet_normal(ttrian.trian) + end + c = ttrian.caches + cell_values = ttrian.cell_values + cell_to_coords = lazy_map( + DualizeCoordsMap(),c.face_to_coords,c.face_to_bgcoords, + cell_values,c.face_to_edges,c.face_to_edge_lists + ) + facet_normals = lazy_map(face_normal,cell_to_coords,c.orientations) + return lazy_map(constant_field,facet_normals) +end + +function Geometry.get_glue(ttrian::DifferentiableTriangulation,val::Val{D}) where {D} + glue = get_glue(ttrian.trian,val) + if isnothing(glue) || isnothing(ttrian.cell_values) || isempty(ttrian.cell_values) + return glue + end + + # New reference maps + c = ttrian.caches + cell_values = ttrian.cell_values + cell_to_rcoords = lazy_map( + DualizeCoordsMap(),c.face_to_rcoords,c.face_to_bgrcoords, + cell_values,c.face_to_edges,c.face_to_edge_lists + ) + cell_reffe = get_cell_reffe(ttrian) + ref_cell_map = compute_cell_maps(cell_to_rcoords,cell_reffe) + + return FaceToFaceGlue( + glue.tface_to_mface, + ref_cell_map, + glue.mface_to_tface, + ) +end + +function Geometry.is_change_possible( + strian::A,ttrian::DifferentiableTriangulation{Dc,Dp,A} +) where {Dc,Dp,A <: Union{SubCellTriangulation,SubFacetTriangulation}} + return strian === ttrian.trian +end + +function Geometry.best_target( + strian::A,ttrian::DifferentiableTriangulation{Dc,Dp,A} +) where {Dc,Dp,A <: Union{SubCellTriangulation,SubFacetTriangulation}} + return ttrian +end + +for tdomain in (:ReferenceDomain,:PhysicalDomain) + for sdomain in (:ReferenceDomain,:PhysicalDomain) + @eval begin + function CellData.change_domain( + a::CellField,strian::A,::$sdomain,ttrian::DifferentiableTriangulation{Dc,Dp,A},::$tdomain + ) where {Dc,Dp,A <: Union{SubCellTriangulation,SubFacetTriangulation}} + @assert is_change_possible(strian,ttrian) + b = change_domain(a,$(tdomain)()) + return CellData.similar_cell_field(a,CellData.get_data(b),ttrian,$(tdomain)()) + end + end + end +end + +function FESpaces.get_cell_fe_data(fun,f,ttrian::DifferentiableTriangulation) + FESpaces.get_cell_fe_data(fun,f,ttrian.trian) +end + +function compute_cell_maps(cell_coords,cell_reffes) + cell_shapefuns = lazy_map(get_shapefuns,cell_reffes) + default_cell_map = lazy_map(linear_combination,cell_coords,cell_shapefuns) + default_cell_grad = lazy_map(∇,default_cell_map) + cell_poly = lazy_map(get_polytope,cell_reffes) + cell_q0 = lazy_map(p->zero(first(get_vertex_coordinates(p))),cell_poly) + origins = lazy_map(evaluate,default_cell_map,cell_q0) + gradients = lazy_map(evaluate,default_cell_grad,cell_q0) + cell_map = lazy_map(Gridap.Fields.affine_map,gradients,origins) + return cell_map +end + +# DualizeCoordsMap + +struct DualizeCoordsMap <: Map end + +function Arrays.return_cache( + k::DualizeCoordsMap, + coords::Vector{<:Point{Dp,Tp}}, + bg_coords::Vector{<:Point{Dp,Tp}}, + values::Vector{Tv}, + edges::Vector{Int8}, + edge_list::Vector{Vector{Int8}} +) where {Dp,Tp,Tv} + T = Point{Dp,Tv} + return CachedArray(zeros(T, length(coords))) +end + +function Arrays.evaluate!( + cache, + k::DualizeCoordsMap, + coords::Vector{<:Point{Dp,Tp}}, + bg_coords::Vector{<:Point{Dp,Tp}}, + values::Vector{Tv}, + edges::Vector{Int8}, + edge_list::Vector{Vector{Int8}} +) where {Dp,Tp,Tv} + setsize!(cache,(length(coords),)) + new_coords = cache.array + for (i,e) in enumerate(edges) + if e == -1 + new_coords[i] = coords[i] + else + n1, n2 = edge_list[e] + q1, q2 = bg_coords[n1], bg_coords[n2] + v1, v2 = abs(values[n1]), abs(values[n2]) + λ = v1/(v1+v2) + new_coords[i] = q1 + λ*(q2-q1) + end + end + return new_coords +end + +""" + precompute_cut_edge_ids(rcoords,bg_rcoords,edge_list) + +Given + - `rcoords`: the node ref coordinates of the cut subcell/subfacet, + - `bg_rcoords`: the node ref coordinates of the background cell containing it, + - `edge_list`: the list of nodes defining each edge of the background cell, + +this function returns a vector that for each node of the cut subcell/subfacet contains + - `-1` if the node is also a node of the background cell, + - the id of the edge containing the node otherwise. +""" +function precompute_cut_edge_ids( + rcoords::Vector{<:Point{Dp,Tp}}, + bg_rcoords::Vector{<:Point{Dp,Tp}}, + edge_list::Vector{<:Vector{<:Integer}} +) where {Dp,Tp} + tol = 10*eps(Tp) + edges = Vector{Int8}(undef,length(rcoords)) + for (i,p) in enumerate(rcoords) + if any(q -> norm(q-p) < tol, bg_rcoords) + edges[i] = Int8(-1) + else + e = findfirst(edge -> belongs_to_edge(p,edge,bg_rcoords), edge_list) + edges[i] = Int8(e) + end + end + return edges +end + +function get_edge_list(poly::Polytope) + ltcell_to_lpoints, simplex = simplexify(poly) + simplex_edges = get_faces(simplex,1,0) + ltcell_to_edges = map(pts -> map(e -> pts[e], simplex_edges), ltcell_to_lpoints) + return collect(Vector{Int8},unique(sort,vcat(ltcell_to_edges...))) +end + +function belongs_to_edge( + p::Point{D,T},edge::Vector{<:Integer},bgpts::Vector{Point{D,T}} +) where {D,T} + tol = 10*eps(T) + p1, p2 = bgpts[edge] + return norm(cross(p-p1,p2-p1)) < tol +end + +function precompute_autodiff_caches( + trian::SubCellTriangulation +) + bgmodel = get_background_model(trian) + subcells = trian.subcells + + precompute_autodiff_caches( + bgmodel, + subcells.cell_to_bgcell, + subcells.cell_to_points, + subcells.point_to_rcoords, + subcells.point_to_coords, + ) +end + +function precompute_autodiff_caches( + trian::SubFacetTriangulation +) + bgmodel = get_background_model(trian) + subfacets = trian.subfacets + + caches = precompute_autodiff_caches( + bgmodel, + subfacets.facet_to_bgcell, + subfacets.facet_to_points, + subfacets.point_to_rcoords, + subfacets.point_to_coords, + ) + + # Precompute orientations + orientations = collect(lazy_map(orient,subfacets.facet_to_normal,caches.face_to_coords)) + + cache = (; caches..., orientations) + return cache +end + +orient(n,fcoords) = round(Int8,dot(n,face_normal(fcoords))) +Arrays.return_value(::typeof(orient),n,face_coords) = zero(Int8) + +function precompute_autodiff_caches( + bgmodel, + face_to_bgcell, + face_to_points, + point_to_rcoords, + point_to_coords, +) + bg_ctypes = get_cell_type(bgmodel) + bgcell_to_polys = expand_cell_data(get_polytopes(bgmodel),bg_ctypes) + bgcell_to_coords = get_cell_coordinates(bgmodel) + bgcell_to_rcoords = lazy_map(get_vertex_coordinates,bgcell_to_polys) + + face_to_bgcoords = lazy_map(Reindex(bgcell_to_coords),face_to_bgcell) + face_to_bgrcoords = lazy_map(Reindex(bgcell_to_rcoords),face_to_bgcell) + face_to_rcoords = lazy_map(Broadcasting(Reindex(point_to_rcoords)),face_to_points) + face_to_coords = lazy_map(Broadcasting(Reindex(point_to_coords)),face_to_points) + + bgcell_to_edge_lists = lazy_map(get_edge_list,bgcell_to_polys) + face_to_edge_lists = lazy_map(Reindex(bgcell_to_edge_lists),face_to_bgcell) + face_to_edges = collect(lazy_map(precompute_cut_edge_ids,face_to_rcoords,face_to_bgrcoords,face_to_edge_lists)) + + cache = (; + face_to_rcoords, + face_to_coords, + face_to_bgrcoords, + face_to_bgcoords, + face_to_edges, + face_to_edge_lists + ) + return cache +end + +function extract_dualized_cell_values( + trian::SubCellTriangulation, + φh::CellField, +) + @assert isa(DomainStyle(φh),ReferenceDomain) + bgmodel = get_background_model(trian) + bgcell_to_values = extract_dualized_cell_values(bgmodel,φh) + + subcells = trian.subcells + cell_to_bgcell = subcells.cell_to_bgcell + cell_to_values = lazy_map(Reindex(bgcell_to_values),cell_to_bgcell) + return cell_to_values +end + +function extract_dualized_cell_values( + trian::SubFacetTriangulation, + φh::CellField, +) + @assert isa(DomainStyle(φh),ReferenceDomain) + bgmodel = get_background_model(trian) + bgcell_to_values = extract_dualized_cell_values(bgmodel,φh) + + subfacets = trian.subfacets + facet_to_bgcell = subfacets.facet_to_bgcell + facet_to_values = lazy_map(Reindex(bgcell_to_values),facet_to_bgcell) + return facet_to_values +end + +function extract_dualized_cell_values( + bgmodel::DiscreteModel, + φh::CellField, +) + @assert isa(DomainStyle(φh),ReferenceDomain) + bg_ctypes = get_cell_type(bgmodel) + bgcell_to_polys = expand_cell_data(get_polytopes(bgmodel),bg_ctypes) + bgcell_to_rcoords = lazy_map(get_vertex_coordinates,bgcell_to_polys) + bgcell_to_fields = CellData.get_data(φh) + bgcell_to_values = lazy_map(evaluate,bgcell_to_fields,bgcell_to_rcoords) + return bgcell_to_values +end + +# AppendedTriangulation +# +# When cutting an embedded domain, we will usually end up with an AppendedTriangulation +# containing +# a) a regular triangulation with the IN/OUT cells +# b) a SubCell/SubFacetTriangulation with the CUT cells +# We only need to propagate the dual numbers to the CUT cells, which is what the +# following implementation does: + +const DifferentiableAppendedTriangulation{Dc,Dp,A} = AppendedTriangulation{Dc,Dp,<:DifferentiableTriangulation} + +function DifferentiableTriangulation( + trian::AppendedTriangulation, fe_space::FESpace +) + a = DifferentiableTriangulation(trian.a,fe_space) + b = DifferentiableTriangulation(trian.b,fe_space) + return AppendedTriangulation(a,b) +end + +function update_trian!(trian::DifferentiableAppendedTriangulation,U,φh) + update_trian!(trian.a,U,φh) + update_trian!(trian.b,U,φh) + return trian +end + +function FESpaces._change_argument( + op,f,trian::DifferentiableAppendedTriangulation,uh +) + U = get_fe_space(uh) + function g(cell_u) + cf = CellField(U,cell_u) + update_trian!(trian,U,cf) + cell_grad = f(cf) + update_trian!(trian,U,nothing) + get_contribution(cell_grad,trian) + end + g +end + +# TODO: Move to Gridap +function FESpaces._compute_cell_ids(uh,ttrian::AppendedTriangulation) + ids_a = FESpaces._compute_cell_ids(uh,ttrian.a) + ids_b = FESpaces._compute_cell_ids(uh,ttrian.b) + lazy_append(ids_a,ids_b) +end + +# TriangulationView +# This is mostly used in distributed, where we remove ghost cells by taking a view +# of the local triangulations. + +function DifferentiableTriangulation( + trian :: Geometry.TriangulationView, + fe_space :: FESpace +) + parent = DifferentiableTriangulation(trian.parent,fe_space) + return Geometry.TriangulationView(parent,trian.cell_to_parent_cell) +end + +function update_trian!(trian::Geometry.TriangulationView,U,φh) + update_trian!(trian.parent,U,φh) + return trian +end + +function FESpaces._change_argument( + op,f,trian::Geometry.TriangulationView,uh +) + U = get_fe_space(uh) + function g(cell_u) + cf = CellField(U,cell_u) + update_trian!(trian,U,cf) + cell_grad = f(cf) + update_trian!(trian,U,nothing) + get_contribution(cell_grad,trian) + end + g +end + +#### DistributedTriangulations + +# function DifferentiableTriangulation(trian::DistributedTriangulation,fe_space) +# model = get_background_model(trian) +# trians = map(DifferentiableTriangulation,local_views(trian),local_views(fe_space)) +# return DistributedTriangulation(trians,model) +# end +# +# function FESpaces._change_argument( +# op,f, +# local_trians::AbstractArray{<:Union{<:DifferentiableTriangulation,<:DifferentiableAppendedTriangulation,<:TriangulationView}}, +# uh::GridapDistributed.DistributedADTypes +# ) +# function dist_cf(uh::DistributedCellField,cfs) +# DistributedCellField(cfs,get_triangulation(uh)) +# end +# function dist_cf(uh::DistributedMultiFieldCellField,cfs) +# sf_cfs = map(DistributedCellField, +# [tuple_of_arrays(map(cf -> Tuple(cf.single_fields),cfs))...], +# map(get_triangulation,uh) +# ) +# DistributedMultiFieldCellField(sf_cfs,cfs) +# end +# +# uhs = local_views(uh) +# spaces = map(get_fe_space,uhs) +# function g(cell_u) +# cfs = map(CellField,spaces,cell_u) +# cf = dist_cf(uh,cfs) +# map(update_trian!,local_trians,spaces,local_views(cf)) +# cg = f(cf) +# map(local_trians,spaces) do Ω, V +# update_trian!(Ω,V,nothing) +# end +# map(get_contribution,local_views(cg),local_trians) +# end +# g +# end diff --git a/src/LevelSetCutters/LevelSetCutters.jl b/src/LevelSetCutters/LevelSetCutters.jl index ac7caf57..5b6e0f7c 100644 --- a/src/LevelSetCutters/LevelSetCutters.jl +++ b/src/LevelSetCutters/LevelSetCutters.jl @@ -15,6 +15,7 @@ import GridapEmbedded.Interfaces: compute_bgfacet_to_inoutcut using GridapEmbedded.Interfaces: Simplex using GridapEmbedded.Interfaces: merge_sub_face_data using GridapEmbedded.Interfaces: compute_inoutcut +using GridapEmbedded.Interfaces: SubCellTriangulation, SubFacetTriangulation using LinearAlgebra using MiniQhull @@ -55,6 +56,8 @@ include("LookupTables.jl") include("CutTriangulations.jl") +include("DifferentiableTriangulations.jl") + struct LevelSetCutter <: Cutter end function cut(cutter::LevelSetCutter,background::DiscreteModel,geom) From afde95392800394880079f9e46b7f98d33790481 Mon Sep 17 00:00:00 2001 From: Anne Boschman Date: Tue, 15 Apr 2025 15:21:59 +1000 Subject: [PATCH 086/120] updated rhs func canvas: seems to all work now --- src/BGP/bulk_ghost_penalty_stab_tools.jl | 175 +++++++++------------ test_proj_rhs_func.jl | 190 ++++++++++++++++------- 2 files changed, 204 insertions(+), 161 deletions(-) diff --git a/src/BGP/bulk_ghost_penalty_stab_tools.jl b/src/BGP/bulk_ghost_penalty_stab_tools.jl index 286739fc..b3186a34 100644 --- a/src/BGP/bulk_ghost_penalty_stab_tools.jl +++ b/src/BGP/bulk_ghost_penalty_stab_tools.jl @@ -84,93 +84,64 @@ function setup_L2_proj_in_bb_space( op_u_proj_Zbb_agg_cells, op_v_proj_Zbb_agg_cells end -# TODO: the following is not working yet: -# """ -# returns the L2 projection in the bounding box space of a function `f`. That is, the L2 projection is defined through +""" + returns the L2 projection in the bounding box space of a function. That is, the L2 projection is defined through -# ∫ (f - Π_{Zbb}(f) zbb dΩbg_agg_cells = 0 ∀ zbb ∈ Zbb(T), + ∫ (function - Π_{Zbb}(operation(u)) zbb dΩbg_agg_cells = 0 ∀ zbb ∈ Zbb(T), -# with T ∈ T_agg and `Zbb` the bounding box space. Note that Ωbg_agg_cells ⊆ Ωbg_bb. Additionally, Π_{Zbb}(f) appears on the lhs as the trial function wbb ∈ Zbb. -# """ -# function setup_L2_proj_in_bb_space( -# dΩbg_agg_cells, # measure of aggregated cells in background domain -# ref_agg_cell_to_ref_bb_map, # map -# agg_cells_to_aggregate, # -# aggregate_to_local_cells, # -# f, -# u, # Trial basis (to project) -# v, # Test basis -# wbb, # Trial basis of bounding box space Zbb -# zbb, # Test basis of bounding box space Zbb -# operation, # operation to be applied to u and v -# U_agg_cells_local_dof_ids) # aggregates local dof ids for space U + with T ∈ T_agg and `Zbb` the bounding box space. Note that Ωbg_agg_cells ⊆ Ωbg_bb. Additionally, Π_{Zbb}(operation(u)) appears on the lhs as the trial function wbb ∈ Zbb. +""" +function setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + func, # Function to be projected + wbb, # Trial basis of bounding box space Zbb + zbb) # Test basis of bounding box space Zbb -# # (0) Obtain triangulation of aggregate cell domain from its measure -# Ωbg_agg_cells=dΩbg_agg_cells.quad.trian - -# # (1) Change domain of zbb (test function of Zbb) from Ωbb to Ωbg_agg_cells -# zbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(zbb, -# ref_agg_cell_to_ref_bb_map, -# Ωbg_agg_cells, -# agg_cells_to_aggregate) + # (0) Obtain triangulation of aggregate cell domain from its measure + Ωbg_agg_cells=dΩbg_agg_cells.quad.trian + + # (1) Change domain of zbb (test function of Zbb) from Ωbb to Ωbg_agg_cells + zbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(zbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) -# # (2) Change domain of wbb (trial function of Zbb) from Ωbb to Ωbg_agg_cells -# wbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(wbb, -# ref_agg_cell_to_ref_bb_map, -# Ωbg_agg_cells, -# agg_cells_to_aggregate) -# # (3) TODO: Compute & assemble contributions to LHS of L2 projection -# agg_cells_to_lhs_contribs=get_array(∫(zbb_Ωbg_agg_cells⋅wbb_Ωbg_agg_cells)dΩbg_agg_cells) -# ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) -# lhs = lazy_map(ass_lhs_map,aggregate_to_local_cells) - -# # (4) Compute & assemble contributions to RHS of L2 projection -# op_u_single_field = operation(_get_single_field_fe_basis(u)) -# agg_cells_rhs_contribs=get_array(∫(zbb_Ωbg_agg_cells⋅op_u_single_field)dΩbg_agg_cells) -# ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(U_agg_cells_local_dof_ids,agg_cells_rhs_contribs) -# rhs=lazy_map(ass_rhs_map,aggregate_to_local_cells) - -# # (5) TO-DO: optimize using our own optimized version Gridap.Fields.Map -# # of backslash that re-uses storage for lu factors among cells, etc. -# op_v_proj_Zbb_dofs=lazy_map(\,lhs,rhs) - -# # (6) Generate bb-wise array of fields. For each aggregate's bounding box, -# # it provides the l2 projection of operation(u) restricted to the cells -# # included in the bounding box of the aggregate. -# op_v_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, -# op_v_proj_Zbb_dofs, -# Gridap.CellData.get_data(zbb)) - -# # (7) Change domain of proj_op_u and proj_op_v from Ωbb to Ωbg_agg_cells -# op_v_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), -# lazy_map(Reindex(op_v_proj_Zbb_array),agg_cells_to_aggregate), -# ref_agg_cell_to_ref_bb_map) -# op_u_proj_Zbb_array_agg_cells=lazy_map(transpose, op_v_proj_Zbb_array_agg_cells) -# if (_is_multifield_fe_basis_component(u)) -# @assert _is_multifield_fe_basis_component(v) -# @assert _nfields(u)==_nfields(v) -# nfields=_nfields(u) -# fieldid=_fieldid(u) -# op_u_proj_Zbb_array_agg_cells=lazy_map( -# Gridap.Fields.BlockMap((1,nfields),fieldid), -# op_u_proj_Zbb_array_agg_cells) -# end -# op_u_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(op_u_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - -# if (_is_multifield_fe_basis_component(v)) -# @assert _is_multifield_fe_basis_component(v) -# @assert _nfields(u)==_nfields(v) -# nfields=_nfields(v) -# fieldid=_fieldid(v) -# op_v_proj_Zbb_array_agg_cells=lazy_map( -# Gridap.Fields.BlockMap(nfields,fieldid), -# op_v_proj_Zbb_array_agg_cells) -# end - -# op_v_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(op_v_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) - -# op_u_proj_Zbb_agg_cells, op_v_proj_Zbb_agg_cells -# end + # (2) Change domain of wbb (trial function of Zbb) from Ωbb to Ωbg_agg_cells + wbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(wbb, + ref_agg_cell_to_ref_bb_map, + Ωbg_agg_cells, + agg_cells_to_aggregate) + # (3) Compute & assemble contributions to LHS of L2 projection + agg_cells_to_lhs_contribs=get_array(∫(zbb_Ωbg_agg_cells⋅wbb_Ωbg_agg_cells)dΩbg_agg_cells) + ass_lhs_map=BulkGhostPenaltyAssembleLhsMap(agg_cells_to_lhs_contribs) + lhs = lazy_map(ass_lhs_map,aggregate_to_local_cells) + + # (4) Compute & assemble contributions to RHS of L2 projection + agg_cells_rhs_contribs=get_array(∫(zbb_Ωbg_agg_cells⋅func)dΩbg_agg_cells) + rhs=lazy_map(sum,lazy_map(Broadcasting(Reindex(agg_cells_rhs_contribs)), aggregate_to_local_cells)) + + # (5) TO-DO: optimize using our own optimized version Gridap.Fields.Map + # of backslash that re-uses storage for lu factors among cells, etc. + func_proj_Zbb_dofs=lazy_map(\,lhs,rhs) + + # (6) Generate bb-wise array of fields. For each aggregate's bounding box, + # it provides the l2 projection of func restricted to the cells + # included in the bounding box of the aggregate. + func_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, + func_proj_Zbb_dofs, + Gridap.CellData.get_data(zbb)) + + # (7) Change domain of proj_op_u and proj_func from Ωbb to Ωbg_agg_cells + func_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), + lazy_map(Reindex(func_proj_Zbb_array),agg_cells_to_aggregate), + ref_agg_cell_to_ref_bb_map) + func_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(func_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) + + func_proj_Zbb_agg_cells +end """ Compute and assemble the bulk penalty stabilization term @@ -325,9 +296,9 @@ end """ Compute and assemble the bulk penalty stabilization term - γ ∫( (operation_v(v) - proj_op_v)⊙(rhs_function) )*dD + γ ∫( (operation_v(v) - proj_op_v)⊙(func - proj_func) )*dD - with `v` the test basis functions (which may be components of a MultiField). The operation `operation_v` (e.g. identity or divergence) is applied to v. The L2 projections `proj_op_u` can be computed via `setup_L2_proj_in_bb_space`. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. The function `rhs_function` is the forcing term appearing on the right hand-side of the PDE. + with `v` the test basis functions (which may be components of a MultiField). The operation `operation_v` (e.g. identity or divergence) is applied to v. The L2 projections `proj_op_u` and `proj_func` can be computed via `setup_L2_proj_in_bb_space`. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. The function `func` is the forcing term appearing on the right hand-side of the PDE. """ function bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dD, @@ -337,7 +308,8 @@ function bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dD, dof_ids_v, dof_ids_proj_v, operation_v, - rhs_function) + func, + proj_func) # # BlockMap preparatory steps for the dof ids # if (_is_multifield_fe_basis_component(v)) # nfields=_nfields(v) @@ -354,14 +326,14 @@ function bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dD, w = [] r = [] - # (1) op_v⊙rhs_function term - op_v_rhs_vec_contribs=get_array(∫(γ*operation_v(v)⊙(rhs_function))*dD) - push!(w, op_v_rhs_vec_contribs) + # (1) op_v⊙(func-proj_func) term + op_v_diff_func_contribs=get_array(∫(γ*operation_v(v)⊙(func - proj_func))*dD) + push!(w, op_v_diff_func_contribs) push!(r, dof_ids_v) - # (2) proj_op_v⊙rhs_function - proj_op_v_rhs_vec_contribs=get_array(∫(γ*(-1.0)*(proj_op_v⊙(rhs_function)))*dD) - push!(w, proj_op_v_rhs_vec_contribs) + # (2) proj_op_v⊙(func-proj_func) + proj_op_v_diff_func_vec_contribs=get_array(∫(γ*(-1.0)*(proj_op_v⊙(func - proj_func)))*dD) + push!(w, proj_op_v_diff_func_vec_contribs) push!(r, dof_ids_proj_v) w, r @@ -370,9 +342,10 @@ end """ Compute and assemble the bulk penalty stabilization term - γ ∫( (operation_v(v))⊙(rhs_function) )*dD + γ ∫( (operation_v(v))⊙(func - proj_func) )*dD - with `v` the test basis functions (which may be components of a MultiField). The operation `operation_v` (e.g. identity or divergence) is applied to v. The L2 projections `proj_op_u` can be computed via `setup_L2_proj_in_bb_space`. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. The function `rhs_function` is the forcing term appearing on the right hand-side of the PDE. + with `v` the test basis functions (which may be components of a MultiField). The operation `operation_v` (e.g. identity or divergence) is applied to v. The L2 projection of `func`, stored as `proj_func`, can be computed via + `setup_L2_proj_in_bb_space`. `dD` is the measure of the cut cells or full aggregate, that is `dΩbg_cut_cells` or `dΩbg_agg_cells`. The function `func` is the forcing term appearing on the right hand-side of the PDE. """ function bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dD, @@ -380,26 +353,22 @@ function bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dD, v, dof_ids_v, operation_v, - rhs_function) + func, + proj_func) # # BlockMap preparatory steps for the dof ids # if (_is_multifield_fe_basis_component(v)) # nfields=_nfields(v) # fieldid=_fieldid(v) # dof_ids_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_v) # end - # if (_is_multifield_fe_basis_component(v)) - # nfields=_nfields(v) - # fieldid=_fieldid(v) - # dof_ids_proj_v=lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),dof_ids_proj_v) - # end # Manually set up the arrays that collect_cell_vector would return automatically w = [] r = [] - # (1) op_v⊙rhs_function term - op_v_rhs_vec_contribs=get_array(∫(γ*operation_v(v)⊙(rhs_function))*dD) - push!(w, op_v_rhs_vec_contribs) + # (1) op_v⊙(func-proj_func) + op_v_diff_func_vec_contribs=get_array(∫(γ*operation_v(v)⊙(func - proj_func))*dD) + push!(w, op_v_diff_func_vec_contribs) push!(r, dof_ids_v) w, r diff --git a/test_proj_rhs_func.jl b/test_proj_rhs_func.jl index 324bd2a8..98e05f84 100644 --- a/test_proj_rhs_func.jl +++ b/test_proj_rhs_func.jl @@ -7,7 +7,7 @@ include("./src/BGP/BGP.jl") problem = 0 # 0 = Manufactured solution (L2-like projection), 1 = Darcy problem # Manufactured solution -order = 0 +order = 1 uex(x) = -VectorValue(2*x[1],2*x[2]) pex(x) = (x[1]^2 + x[2]^2) divuex(x) = -4.0 @@ -186,14 +186,14 @@ test_w = [] test_r = [] # Pick a rhs function -#rhs_func(x) = 10.0*x[1]^2 + sin(x[2]) +# rhs_func(x) = 10.0*x[1]^2 + sin(x[2]) rhs_func(x) = 10.0*x[1] -#rhs_func(x) = 1000.0 +# rhs_func(x) = 1000.0 ##==============================================================================## # First term: γ ∫( (v)⊙(rhs_function) )*dD ##==============================================================================## -test_rhs_vec_contribs1=get_array(∫((rhs_func)*dq)*dΩbg_cut_cells) # 16-element array, one entry per T ∈ Ωbg_cut_cells, with 1-element Vector (for pressure) per cell T. +test_rhs_vec_contribs1=get_array(∫(γ*(rhs_func⊙dq))*dΩbg_cut_cells) # 16-element array, one entry per T ∈ Ωbg_cut_cells, with 1-element Vector (for pressure) per cell T. push!(test_w, test_rhs_vec_contribs1) if (_is_multifield_fe_basis_component(dq)) @@ -204,7 +204,7 @@ end push!(test_r, testP_Ωbg_cut_cell_dof_ids) ##==============================================================================## -# Second term: γ ∫( (v)⊙(proj_rhs_function) )*dD +# Second term: - γ ∫( (v)⊙(proj_rhs_function) )*dD ##==============================================================================## ## (1) Set-up proj_rhs_function using @@ -219,85 +219,53 @@ with T ∈ T_agg and `Zbb` the bounding box space. Note that Ωbg_agg_cells ⊆ =# test_wbb = pbb # Bounding box trial space (for pressure) test_zbb = qbb # Bounding box test space (for pressure) -# evaluate(Gridap.CellData.get_data(qbb)[1],[Point(0.0,0.0)]) test_wbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(test_wbb, ref_agg_cell_to_ref_bb_map, Ωbg_agg_cells, agg_cells_to_aggregate) # trial test_zbb_Ωbg_agg_cells=change_domain_bb_to_agg_cells(test_zbb, ref_agg_cell_to_ref_bb_map, Ωbg_agg_cells, agg_cells_to_aggregate) # test -# evaluate(Gridap.CellData.get_data(test_zbb_Ωbg_agg_cells)[1],[Point(0.0,0.0)]) - test_agg_cells_to_lhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells⋅test_wbb_Ωbg_agg_cells)dΩbg_agg_cells) - test_ass_lhs_map= BulkGhostPenaltyAssembleLhsMap(test_agg_cells_to_lhs_contribs) test_lhs = lazy_map(test_ass_lhs_map,aggregate_to_local_cells) -test_agg_cells_rhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells*rhs_func)dΩbg_agg_cells) - -# test_lhs[1] -# Gridap.CellData.get_triangulation(dΩbg_agg_cells.quad) === Gridap.CellData.get_triangulation(test_zbb_Ωbg_agg_cells) -# test_ass_rhs_map=BulkGhostPenaltyAssembleRhsMap(P_agg_cells_local_dof_ids,test_agg_cells_rhs_contribs) -# test_rhs=lazy_map(sum,aggregate_to_local_cells) +test_agg_cells_rhs_contribs=get_array(∫(test_zbb_Ωbg_agg_cells⋅rhs_func)dΩbg_agg_cells) test_rhs = lazy_map(sum, lazy_map(Broadcasting(Reindex(test_agg_cells_rhs_contribs)), - aggregate_to_local_cells)) - + aggregate_to_local_cells)) test_f_proj_Zbb_dofs=lazy_map(\,test_lhs,test_rhs) test_f_proj_Zbb_array=lazy_map(Gridap.Fields.linear_combination, - test_f_proj_Zbb_dofs, + test_f_proj_Zbb_dofs, Gridap.CellData.get_data(test_zbb)) -# Gridap.CellData.get_data(test_zbb) -test_f_proj_Zbb_dofs[2] -test_f_proj_Zbb_array[1] - # Change domain of proj_op_u and proj_op_v from Ωbb to Ωbg_agg_cells test_f_proj_Zbb_array_agg_cells=lazy_map(Broadcasting(∘), lazy_map(Reindex(test_f_proj_Zbb_array),agg_cells_to_aggregate), ref_agg_cell_to_ref_bb_map) -# contains 24 entries, with nr of operation fields equal to the nr of cells in that aggregate. test_f_proj_Zbb_agg_cells = Gridap.CellData.GenericCellField(test_f_proj_Zbb_array_agg_cells,Ωbg_agg_cells,ReferenceDomain()) ## (2) Define γ ∫( (v)⊙(proj_rhs_function) )*dD dq_on_Ωbg_agg_cells = Gridap.CellData.change_domain(dq,Ωbg_agg_cells,ReferenceDomain()) -dp_on_Ωbg_agg_cells = Gridap.CellData.change_domain(dp,Ωbg_agg_cells,ReferenceDomain()) - -test_rhs_vec_contribs2 = get_array(∫((-1.0)*(test_f_proj_Zbb_agg_cells)⋅dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) #DEBUG ME: here output is cell matrix and should be cell vector -test_rhs_vec_contribs2[2][2] +test_rhs_vec_contribs2 = get_array(∫((-1.0)*γ*(test_f_proj_Zbb_agg_cells)⋅dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) push!(test_w, test_rhs_vec_contribs2) -if (_is_multifield_fe_basis_component(dq)) - nfields=_nfields(dq) - fieldid=_fieldid(dq) - test_P_cut_cells_to_aggregate_dof_ids= - lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) -end -push!(test_r, test_P_cut_cells_to_aggregate_dof_ids) -test_P_cut_cells_to_aggregate_dof_ids[1][2] - -## TESTING OTHER CONTRIBS TERMS: -testarray_dp_test_f = get_array(∫(dp_on_Ωbg_agg_cells⊙test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) #matrix -testarray_dq_test_f = get_array(∫(dq_on_Ωbg_agg_cells*test_f_proj_Zbb_agg_cells)*dΩbg_cut_cells) # AssertionError: A check failed. -testarray_test_f_dq = get_array(∫(test_f_proj_Zbb_agg_cells⊙dq_on_Ωbg_agg_cells)*dΩbg_cut_cells) # AssertionError: A check failed. - -### START TEST ### -## THE FOLLOWING SEEMS TO IMPLY THAT test_fT_proj_Zbb_agg_cells is the projected rhs_func. -# NOTE that for (lowest order Pbb) a rhs_func which takes on a constant value everywhere, the different/error = machine precision, whereas for higher order functions this is not the case (as expected) -sum_cut_cells = sum([sum(get_array(∫(test_fT_proj_Zbb_agg_cells)dΩbg_cut_cells)[i][2]) for i=1:16]) -sum((get_array(∫(rhs_func)*dΩbg_cut_cells))) -@assert abs(sum_cut_cells - sum((get_array(∫(rhs_func)*dΩbg_cut_cells)))) <1e-12 -difference = abs(sum_cut_cells - sum((get_array(∫(rhs_func)*dΩbg_cut_cells)))) -### END TEST ### +push!(test_r, testP_Ωbg_cut_cell_dof_ids) # same dofs as as contr1? TOCHECK! + +# ### TEST FOR INDIVIDUAL CONTRIBUTIONS: I expect these to cancel out +# for i= 1:16 +# println("===== i: $i") +# println("contr1: $(test_rhs_vec_contribs1[i][2])") +# println("contr2: $(test_rhs_vec_contribs2[i][2])") +# end + +# ### TEST FOR SUM OF CONTRIBUTIONS: I expect these to cancel out +# ([sum(get_array(∫(test_f_proj_Zbb_agg_cells)dΩbg_cut_cells)[i]) for i=1:16]) +# sum_cut_cells_rhs = sum([sum(get_array(∫(test_f_proj_Zbb_agg_cells)dΩbg_cut_cells)[i]) for i=1:16]) +# sum((get_array(∫(rhs_func)*dΩbg_cut_cells))) +# difference = abs(sum_cut_cells_rhs - sum((get_array(∫(rhs_func)*dΩbg_cut_cells)))) #### -- TEST PROBLEM -- #### test_a((u,p),(v,q))=∫(u⋅v+q*p)dΩ uex(x) = -VectorValue(2.0,2.0) -test_l((v,q))=∫(uex⋅v+1.0⋅q)dΩ +test_l((v,q))=∫(uex⋅v+0.0⋅q)dΩ test_mat_A=Gridap.FESpaces.collect_cell_matrix(X,Y,test_a(dx,dy)) test_vec_b=Gridap.FESpaces.collect_cell_vector(Y,test_l(dy)) - -# test_vec_b[1][1][25][1] #uvals -# test_vec_b[1][1][25][2] #pvals -# test_vec_b[2][1][25][1] #udofs -# test_vec_b[2][1][25][2] #pvals - push!(test_vec_b[1], test_w...) push!(test_vec_b[2], test_r...) @@ -310,10 +278,116 @@ test_sol = test_A\test_b test_sol_FE = FEFunction(X, test_sol) test_sol_u, test_sol_p = test_sol_FE -area = sum(∫(1.0)dΩ) norm_sol_u = (sum(∫(test_sol_u⋅test_sol_u)*dΩ)) -norm_sol_p = (sum(∫(test_sol_p)*dΩ)) +norm_sol_p = (sum(∫(test_sol_p*test_sol_p)*dΩ)) + +err_sol_u = uex - test_sol_u +err_sol_p = 0.0 - test_sol_p +L2error_sol_u = (sum(∫(err_sol_u⋅err_sol_u)*dΩ)) +L2error_sol_p = (sum(∫(err_sol_p⋅err_sol_p)*dΩ)) + +##################### TRY TO DEFINE FUNCTIONS TO COLLECT VEC_STAB +proj_rhs_func = setup_L2_proj_in_bb_space(dΩbg_agg_cells, + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + rhs_func, # Function to be projected + pbb, # Trial basis of bounding box space Zbb + qbb) +# #THIS TEST SEEMS TO IMPLY THAT ALL IS FINE. +# for i=1:16 +# println(get_array(∫(proj_rhs_func)dΩbg_cut_cells)[i]) +# println(get_array(∫(proj_rhs_func)dΩbg_cut_cells)[i]-get_array(∫(test_f_proj_Zbb_agg_cells)dΩbg_cut_cells)[i]) +# end + +wvec, rvec = bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dΩbg_cut_cells, + γ, + dq, + testP_Ωbg_cut_cell_dof_ids, + identity, + rhs_func, + proj_rhs_func) + +#### -- TEST PROBLEM -- #### MET wvec +test_a((u,p),(v,q))=∫(u⋅v+q*p)dΩ +uex(x) = -VectorValue(2.0,2.0) +test_l((v,q))=∫(uex⋅v+0.0⋅q)dΩ + +test_mat_A=Gridap.FESpaces.collect_cell_matrix(X,Y,test_a(dx,dy)) +test_vec_b=Gridap.FESpaces.collect_cell_vector(Y,test_l(dy)) +push!(test_vec_b[1], wvec...) +push!(test_vec_b[2], rvec...) + +assem=SparseMatrixAssembler(X,Y) + +test_A = assemble_matrix(assem, test_mat_A) +test_b = assemble_vector(assem, test_vec_b) + +test_sol = test_A\test_b + +test_sol_FE = FEFunction(X, test_sol) +test_sol_u, test_sol_p = test_sol_FE + +norm_sol_u = (sum(∫(test_sol_u⋅test_sol_u)*dΩ)) +norm_sol_p = (sum(∫(test_sol_p*test_sol_p)*dΩ)) + +err_sol_u = uex - test_sol_u +err_sol_p = 0.0 - test_sol_p +L2error_sol_u = (sum(∫(err_sol_u⋅err_sol_u)*dΩ)) +L2error_sol_p = (sum(∫(err_sol_p⋅err_sol_p)*dΩ)) + +#### +dp_proj_Qbb, dq_proj_Qbb = setup_L2_proj_in_bb_space( + dΩbg_agg_cells, # measure of aggregated cells in background domain + ref_agg_cell_to_ref_bb_map, # map + agg_cells_to_aggregate, # + aggregate_to_local_cells, # + dp, # Trial basis (to project) + dq, # Test basis + pbb, # Trial basis of bounding box space Qbb + qbb, # Test basis of bounding box space Qbb + identity, # operation to be applied to u and v + P_agg_cells_local_dof_ids) # aggregates local dof ids for space P + +if (_is_multifield_fe_basis_component(dp)) + nfields=_nfields(dp) + fieldid=_fieldid(dp) + P_cut_cells_to_aggregate_dof_ids= + lazy_map(Gridap.Fields.BlockMap(nfields,fieldid),P_cut_cells_to_aggregate_dof_ids) +end +wvec2, rvec2 = bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dΩbg_cut_cells, + γ, + dq, + dq_proj_Qbb, + testP_Ωbg_cut_cell_dof_ids, + P_cut_cells_to_aggregate_dof_ids, + identity, + rhs_func, + proj_rhs_func) + +#### -- TEST PROBLEM -- #### MET wvec2 +test_a((u,p),(v,q))=∫(u⋅v+q*p)dΩ +uex(x) = -VectorValue(2.0,2.0) +test_l((v,q))=∫(uex⋅v+0.0⋅q)dΩ + +test_mat_A=Gridap.FESpaces.collect_cell_matrix(X,Y,test_a(dx,dy)) +test_vec_b=Gridap.FESpaces.collect_cell_vector(Y,test_l(dy)) +push!(test_vec_b[1], wvec2...) +push!(test_vec_b[2], rvec2...) + +assem=SparseMatrixAssembler(X,Y) + +test_A = assemble_matrix(assem, test_mat_A) +test_b = assemble_vector(assem, test_vec_b) + +test_sol = test_A\test_b + +test_sol_FE = FEFunction(X, test_sol) +test_sol_u, test_sol_p = test_sol_FE + +norm_sol_u = (sum(∫(test_sol_u⋅test_sol_u)*dΩ)) +norm_sol_p = (sum(∫(test_sol_p*test_sol_p)*dΩ)) err_sol_u = uex - test_sol_u err_sol_p = 0.0 - test_sol_p From a2f88679d0291f2f03b1c6838fe91f2b23d2eabb Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 17 Apr 2025 16:20:47 +1000 Subject: [PATCH 087/120] Added Geometrical differentiation tests --- Project.toml | 6 +- .../DifferentiableTriangulations.jl | 2 +- .../GeometricalDifferentiationTests.jl | 513 ++++++++++++++++++ test/LevelSetCuttersTests/runtests.jl | 2 + 4 files changed, 521 insertions(+), 2 deletions(-) create mode 100644 test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl diff --git a/Project.toml b/Project.toml index f651a887..a020b212 100644 --- a/Project.toml +++ b/Project.toml @@ -9,6 +9,7 @@ Algoim = "0eb9048c-21de-4c7a-bfac-056de1940b74" Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6" Gridap = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" GridapDistributed = "f9701e48-63b3-45aa-9a63-9bc6c271f355" @@ -26,6 +27,8 @@ Algoim = "0.2.2" Combinatorics = "1" CxxWrap = "0.16" FillArrays = "0.10, 0.11, 0.12, 0.13, 1" +FiniteDiff = "2.27.0" +ForwardDiff = "0.10.38" Graphs = "1.12.0" Gridap = "0.17, 0.18" GridapDistributed = "0.3, 0.4" @@ -35,7 +38,8 @@ PartitionedArrays = "0.3.4" julia = "1.3" [extras] +FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test"] +test = ["Test","FiniteDiff"] diff --git a/src/LevelSetCutters/DifferentiableTriangulations.jl b/src/LevelSetCutters/DifferentiableTriangulations.jl index 226e7fa8..74e39dbe 100644 --- a/src/LevelSetCutters/DifferentiableTriangulations.jl +++ b/src/LevelSetCutters/DifferentiableTriangulations.jl @@ -221,7 +221,7 @@ function compute_cell_maps(cell_coords,cell_reffes) cell_q0 = lazy_map(p->zero(first(get_vertex_coordinates(p))),cell_poly) origins = lazy_map(evaluate,default_cell_map,cell_q0) gradients = lazy_map(evaluate,default_cell_grad,cell_q0) - cell_map = lazy_map(Gridap.Fields.affine_map,gradients,origins) + cell_map = lazy_map(Fields.affine_map,gradients,origins) return cell_map end diff --git a/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl b/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl new file mode 100644 index 00000000..721f4623 --- /dev/null +++ b/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl @@ -0,0 +1,513 @@ +module GeometricalDifferentiationTests +############################################################################################ +# These tests are meant to verify the correctness differentiation of functionals w.r.t the +# level set defining the cut domain. +# They are based on the following work: +# "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation" +# by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis, CMAME (2025) +############################################################################################ +using Test, FiniteDiff + +using Gridap, Gridap.Geometry, Gridap.Adaptivity, Gridap.Arrays +using GridapEmbedded, GridapEmbedded.LevelSetCutters, GridapEmbedded.Interfaces + +using GridapEmbedded.Interfaces: get_conormal_vector +using GridapEmbedded.Interfaces: get_subfacet_normal_vector +using GridapEmbedded.Interfaces: get_ghost_normal_vector + +using GridapEmbedded.LevelSetCutters: DifferentiableTriangulation + + +using Gridap.Fields, Gridap.Polynomials +function Arrays.return_cache( + fg::Fields.FieldGradientArray{1,Polynomials.MonomialBasis{D,V}}, + x::AbstractVector{<:Point}) where {D,V} + xi = testitem(x) + T = gradient_type(V,xi) + Polynomials._return_cache(fg,x,T,Val(false)) +end + +function Arrays.evaluate!( + cache, + fg::Fields.FieldGradientArray{1,Polynomials.MonomialBasis{D,V}}, + x::AbstractVector{<:Point}) where {D,V} + Polynomials._evaluate!(cache,fg,x,Val(false)) +end + +# We general a simplicial model where the simplices are created in a symmetric way using +# varycentric refinement of QUADs and HEXs. +function generate_model(D,n) + domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) + cell_partition = (D==2) ? (n,n) : (n,n,n) + base_model = UnstructuredDiscreteModel((CartesianDiscreteModel(domain,cell_partition))) + ref_model = refine(base_model, refinement_method = "barycentric") + model = ref_model.model + return model +end + +function level_set(shape::Symbol;N=4) + if shape == :square + x -> max(abs(x[1]-0.5),abs(x[2]-0.5))-0.25 # Square + elseif shape == :corner_2d + x -> ((x[1]-0.5)^N+(x[2]-0.5)^N)^(1/N)-0.25 # Curved corner + elseif shape == :diamond + x -> abs(x[1]-0.5)+abs(x[2]-0.5)-0.25-0/n/10 # Diamond + elseif shape == :circle + x -> sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.5223 # Circle + elseif shape == :circle_2 + x -> sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.23 # Circle + elseif shape == :square_prism + x -> max(abs(x[1]-0.5),abs(x[2]-0.5),abs(x[3]-0.5))-0.25 # Square prism + elseif shape == :corner_3d + x -> ((x[1]-0.5)^N+(x[2]-0.5)^N+(x[3]-0.5)^N)^(1/N)-0.25 # Curved corner + elseif shape == :diamond_prism + x -> abs(x[1]-0.5)+abs(x[2]-0.5)+abs(x[3]-0.5)-0.25-0/n/10 # Diamond prism + elseif shape == :sphere + x -> sqrt((x[1]-0.5)^2+(x[2]-0.5)^2+(x[3]-0.5)^2)-0.53 # Sphere + elseif shape == :sphere_2 + x -> sqrt((x[1]-0.5)^2+(x[2]-0.5)^2+(x[3]-0.5)^2)-0.23 # Sphere + elseif shape == :regular_2d + x -> cos(2π*x[1])*cos(2π*x[2])-0.11 # "Regular" LSF + elseif shape == :regular_3d + x -> cos(2π*x[1])*cos(2π*x[2])*cos(2π*x[3])-0.11 # "Regular" LSF + else + error("Unknown shape") + end +end + +function main( + model,ls::Function,f::Function; + vtk=false, + name="embedded", + verbose=false, + fdm=false +) + order = 1 + reffe = ReferenceFE(lagrangian,Float64,order) + V_φ = TestFESpace(model,reffe) + + U = TestFESpace(model,reffe) + + φh = interpolate(ls,V_φ) + fh = interpolate(f,V_φ) + uh = interpolate(x->x[1]+x[2],U) + + # Correction if level set is on top of a node + x_φ = get_free_dof_values(φh) + idx = findall(isapprox(0.0;atol=10^-10),x_φ) + !isempty(idx) && @info "Correcting level values!" + x_φ[idx] .+= 100*eps(eltype(x_φ)) + + geo = DiscreteGeometry(φh,model) + cutgeo = cut(model,geo) + + # A.1) Volume integral + + Ω = Triangulation(cutgeo,PHYSICAL_IN) + Ω_AD = DifferentiableTriangulation(Ω,V_φ) + dΩ = Measure(Ω_AD,2*order) + + Γ = EmbeddedBoundary(cutgeo) + n_Γ = get_normal_vector(Γ) + dΓ = Measure(Γ,2*order) + + J_bulk(φ) = ∫(fh)dΩ + dJ_bulk_AD = gradient(J_bulk,φh) + dJ_bulk_AD_vec = assemble_vector(dJ_bulk_AD,V_φ) + + dJ_bulk_exact(q) = ∫(-fh*q/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJ_bulk_exact_vec = assemble_vector(dJ_bulk_exact,V_φ) + + abs_error = norm(dJ_bulk_AD_vec - dJ_bulk_exact_vec,Inf) + + if fdm + function J_fdm_bulk(φ) + φh = FEFunction(V_φ,φ) + cutgeo = cut(model,DiscreteGeometry(φh,model)) + Ω = Triangulation(cutgeo,PHYSICAL_IN) + dΩ = Measure(Ω,2*order) + sum(∫(fh)dΩ) + end + dJ_FD = FiniteDiff.finite_difference_gradient(J_fdm_bulk,get_free_dof_values(φh)) + + abs_error_fdm = norm(dJ_bulk_AD_vec - dJ_FD,Inf) + end + + if verbose + println("A.1) Volume integral:") + println(" - norm(dJ_AD - dJ_exact,Inf) = ",abs_error) + fdm && println(" - norm(dJ_AD - dJ_FDM,Inf) = ",abs_error_fdm) + end + + @test abs_error < 1e-10 + + # A.1.1) Volume integral with another field + + J_bulk_1(u,φ) = ∫(u+fh)dΩ + dJ_bulk_1_AD = gradient(φ->J_bulk_1(uh,φ),φh) + dJ_bulk_1_AD_vec = assemble_vector(dJ_bulk_1_AD,V_φ) + + dJ_bulk_1_exact(q,u) = ∫(-(u+fh)*q/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJ_bulk_1_exact_vec = assemble_vector(q->dJ_bulk_1_exact(q,uh),V_φ) + @test norm(dJ_bulk_1_AD_vec - dJ_bulk_1_exact_vec) < 1e-10 + + dJ_bulk_1_AD_in_u = gradient(u->J_bulk_1(u,φh),uh) + dJ_bulk_1_AD_in_u_vec = assemble_vector(dJ_bulk_1_AD_in_u,U) + dJ_bulk_1_exact_in_u(q,u) = ∫(q)dΩ + dJ_bulk_1_exact_in_u_vec = assemble_vector(q->dJ_bulk_1_exact_in_u(q,uh),U) + + abs_error = norm(dJ_bulk_1_AD_in_u_vec - dJ_bulk_1_exact_in_u_vec,Inf) + if verbose + println("A.1.1) Volume integral with another field:") + println(" - norm(dJ_AD - dJ_exact,Inf) = ",abs_error) + end + @test abs_error < 1e-10 + + # A.2) Volume integral + + g(fh) = ∇(fh)⋅∇(fh) + J_bulk2(φ) = ∫(g(fh))dΩ + dJ_bulk_AD2 = gradient(J_bulk2,φh) + dJ_bulk_AD_vec2 = assemble_vector(dJ_bulk_AD2,V_φ) + + dJ_bulk_exact2(q) = ∫(-g(fh)*q/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJ_bulk_exact_vec2 = assemble_vector(dJ_bulk_exact2,V_φ) + + abs_error = norm(dJ_bulk_AD_vec2 - dJ_bulk_exact_vec2,Inf) + + if verbose + println("A.2) Volume integral with grad of fields:") + println(" - norm(dJ_AD - dJ_exact,Inf) = ",abs_error) + end + + @test abs_error < 1e-10 + + # B.1) Facet integral + + Γ = EmbeddedBoundary(cutgeo) + Γ_AD = DifferentiableTriangulation(Γ,V_φ) + Λ = Skeleton(Γ) + Σ = Boundary(Γ) + + dΓ = Measure(Γ,2*order) + dΛ = Measure(Λ,2*order) + dΣ = Measure(Σ,2*order) + + n_Γ = get_normal_vector(Γ) + + n_S_Λ = get_normal_vector(Λ) + m_k_Λ = get_conormal_vector(Λ) + ∇ˢφ_Λ = Operation(abs)(n_S_Λ ⋅ ∇(φh).plus) + + n_S_Σ = get_normal_vector(Σ) + m_k_Σ = get_conormal_vector(Σ) + ∇ˢφ_Σ = Operation(abs)(n_S_Σ ⋅ ∇(φh)) + + dΓ_AD = Measure(Γ_AD,2*order) + J_int(φ) = ∫(fh)dΓ_AD + dJ_int_AD = gradient(J_int,φh) + dJ_int_AD_vec = assemble_vector(dJ_int_AD,V_φ) + + dJ_int_exact(w) = ∫((-n_Γ⋅∇(fh))*w/(abs(n_Γ ⋅ ∇(φh))))dΓ + + ∫(-n_S_Λ ⋅ (jump(fh*m_k_Λ) * mean(w) / ∇ˢφ_Λ))dΛ + + ∫(-n_S_Σ ⋅ (fh*m_k_Σ * w / ∇ˢφ_Σ))dΣ + dJ_int_exact_vec = assemble_vector(dJ_int_exact,V_φ) + + abs_error = norm(dJ_int_AD_vec - dJ_int_exact_vec,Inf) + + if fdm + Ω_data = EmbeddedCollection(model,φh) do cutgeo,_,_ + Γ_AD = DifferentiableTriangulation(EmbeddedBoundary(cutgeo),V_φ) + (;:dΓ_AD => Measure(Γ_AD,2*order)) + end + function J_fdm_surf(φ) + sum(∫(fh)Ω_data.dΓ_AD) + end + dJ_surf_FD = FiniteDiff.finite_difference_gradient(J_fdm_surf,get_free_dof_values(φh)) + + abs_error_fdm = norm(dJ_int_AD_vec - dJ_surf_FD,Inf) + end + + if verbose + println("B.1) Surface integral:") + println(" - norm(dJ_AD - dJ_exact,Inf) = ",abs_error) + fdm && println(" - norm(dJ_AD - dJ_FDM,Inf) = ",abs_error_fdm) + end + @test abs_error < 1e-10 + + # B.2) Facet integral + g(fh) = ∇(fh)⋅∇(fh) + ∇g(∇∇f,∇f) = ∇∇f⋅∇f + ∇f⋅∇∇f + + J_int2(φ) = ∫(g(fh))dΓ_AD + dJ_int_AD2 = gradient(J_int2,φh) + dJ_int_AD_vec2 = assemble_vector(dJ_int_AD2,V_φ) + + dJ_int_exact2(w) = ∫((-n_Γ⋅ (∇g ∘ (∇∇(fh),∇(fh))))*w/(abs(n_Γ ⋅ ∇(φh))))dΓ + + ∫(-n_S_Λ ⋅ (jump(g(fh)*m_k_Λ) * mean(w) / ∇ˢφ_Λ))dΛ + + ∫(-n_S_Σ ⋅ (g(fh)*m_k_Σ * w / ∇ˢφ_Σ))dΣ + dJ_int_exact_vec2 = assemble_vector(dJ_int_exact2,V_φ) + + abs_error = norm(dJ_int_AD_vec2 - dJ_int_exact_vec2,Inf) + if verbose + println("B.2) Surface integral with grad of other fields:") + println(" - norm(dJ_AD - dJ_exact,Inf) = ",abs_error) + end + @test abs_error < 1e-10 + + if vtk + path = "results/$(name)/" + mkpath(path) + Ω_bg = Triangulation(model) + writevtk( + Ω_bg,"$(path)results", + cellfields = [ + "φh" => φh,"∇φh" => ∇(φh), + "dJ_bulk_AD" => FEFunction(V_φ,dJ_bulk_AD_vec), + "dJ_bulk_exact" => FEFunction(V_φ,dJ_bulk_exact_vec), + "dJ_int_AD" => FEFunction(V_φ,dJ_int_AD_vec), + "dJ_int_exact" => FEFunction(V_φ,dJ_int_exact_vec) + ], + celldata = [ + "inoutcut" => GridapEmbedded.Interfaces.compute_bgcell_to_inoutcut(model,geo) + ]; + append = false + ) + + writevtk( + Ω, "$(path)omega"; append = false + ) + writevtk( + Γ, "$(path)gamma"; append = false + ) + + n_∂Ω_Λ = get_subfacet_normal_vector(Λ) + n_k_Λ = get_ghost_normal_vector(Λ) + writevtk( + Λ, "$(path)_lambda", + cellfields = [ + "n_∂Ω.plus" => n_∂Ω_Λ.plus,"n_∂Ω.minus" => n_∂Ω_Λ.minus, + "n_k.plus" => n_k_Λ.plus,"n_k.minus" => n_k_Λ.minus, + "n_S" => n_S_Λ, + "m_k.plus" => m_k_Λ.plus,"m_k.minus" => m_k_Λ.minus, + "∇ˢφ" => ∇ˢφ_Λ, + "∇φh_Γs_plus" => ∇(φh).plus,"∇φh_Γs_minus" => ∇(φh).minus, + "jump(fh*m_k)" => jump(fh*m_k_Λ) + ]; + append = false + ) + + if num_cells(Σ) > 0 + n_∂Ω_Σ = get_subfacet_normal_vector(Σ) + n_k_Σ = get_ghost_normal_vector(Σ) + writevtk( + Σ, "$(path)_sigma", + cellfields = [ + "n_∂Ω" => n_∂Ω_Σ, "n_k" => n_k_Σ, + "n_S" => n_S_Σ, "m_k" => m_k_Σ, + "∇ˢφ" => ∇ˢφ_Σ, "∇φh_Γs" => ∇(φh), + ]; + append = false + ) + end + end +end + +## Concering integrals of the form `φ->∫(f ⋅ n(φ))dΓ(φ)` +function main_normal( + model,ls::Function,f_vec::Function; + vtk=false, + name="flux integrals", + run_test=true, + verbose=false, + fdm=false +) + order = 1 + reffe = ReferenceFE(lagrangian,Float64,order) + V_φ = TestFESpace(model,reffe) + + φh = interpolate(ls,V_φ) + + # Correction if level set is on top of a node + x_φ = get_free_dof_values(φh) + idx = findall(isapprox(0.0;atol=10^-10),x_φ) + !isempty(idx) && @info "Correcting level values!" + x_φ[idx] .+= 100*eps(eltype(x_φ)) + + geo = DiscreteGeometry(φh,model) + cutgeo = cut(model,geo) + + Γ = EmbeddedBoundary(cutgeo) + n_Γ = get_normal_vector(Γ) + Γ_AD = DifferentiableTriangulation(Γ,V_φ) + dΓ_AD = Measure(Γ_AD,2*order) + dΓ = Measure(Γ,2*order) + + fh_Γ = CellField(f_vec,Γ) + fh_Γ_AD = CellField(f_vec,Γ_AD) + + function J_int(φ) + n = get_normal_vector(Γ_AD) + ∫(fh_Γ_AD⋅n)dΓ_AD + end + dJ_int_AD = gradient(J_int,φh) + dJ_int_AD_vec = assemble_vector(dJ_int_AD,V_φ) + + _n(∇φ) = ∇φ/(10^-20+norm(∇φ)) + dJ_int_phi = ∇(φ->∫(fh_Γ_AD ⋅ (_n ∘ (∇(φ))))dΓ_AD,φh) + dJh_int_phi = assemble_vector(dJ_int_phi,V_φ) + + run_test && @test norm(dJ_int_AD_vec - dJh_int_phi) < 1e-10 + + # Analytic + # Note: currently, the analytic result is only valid on closed domains thanks + # to the divergence theorem. I think it would take significant work to compute + # the analytic derivative generally as we can't rely on divergence theorem to + # rewrite it in a convenient way. As a result, we don't have an analytic result + # for general cases such as ∫( f(n(φ)) )dΓ(φ), nor the case when Γ intersects + # ∂D. Thankfully, we have AD instead ;) + # Note 2: For the case that Γ does intersect the surface, the result is correct + # everywhere except on the intersection. + + fh_Γ = CellField(f_vec,Γ) + fh_Γ_AD = CellField(f_vec,Γ_AD) + + # Note: this comes from rewriting via the divergence theorem: + # ∫(f ⋅ n(φ))dΓ(φ) = ∫(∇⋅f)dΩ(φ) + dJ_int_exact3(w) = ∫(-(∇⋅(fh_Γ))*w/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJh_int_exact3 = assemble_vector(dJ_int_exact3,V_φ) + + # Finite diff + if fdm + function J_fdm_surf(φ) + φh = FEFunction(V_φ,φ) + cutgeo = cut(model,DiscreteGeometry(φh,model)) + Γ = EmbeddedBoundary(cutgeo) + dΓ = Measure(Γ,2*order) + n = get_normal_vector(Γ) + f = CellField(f_vec,Γ) + n = get_normal_vector(Γ) + sum(∫(f⋅n)dΓ) + end + dJ_FD = FiniteDiff.finite_difference_gradient(J_fdm_surf,get_free_dof_values(φh)) + + abs_error_fdm = norm(dJ_int_AD_vec - dJ_FD,Inf) + end + abs_error = norm(dJh_int_exact3 - dJ_int_AD_vec,Inf) + + if verbose + println("C) Flux integral:") + println(" - norm(dJ_AD - dJ_exact,Inf) = ",abs_error) + fdm && println(" - norm(dJ_AD - dJ_FDM,Inf) = ",abs_error_fdm) + end + + run_test && @test abs_error < 1e-10 + + if vtk + path = "results/$(name)/" + mkpath(path) + Ω_bg = Triangulation(model) + writevtk(Ω_bg,path*"Results",cellfields=[ + "dJ_AD"=>FEFunction(V_φ,dJ_int_AD_vec), + "dJ_AD_with_phi"=>FEFunction(V_φ,dJh_int_phi), + "dJ_exact"=>FEFunction(V_φ,dJh_int_exact3) + ]) + writevtk(Γ,path*"Gamma") + end +end + +# Finite difference verification of gradients of integrals of the form `φ->∫(f(n))dΓ(φ)` and Hessian's. +# Both of these do not currently have rigorous mathematical counterparts so we verify them +# with finite differences. +function main_fdm_only_verif(model,ls::Function; + verbose=false,compute_hess=false,fdm=false +) + order = 1 + reffe = ReferenceFE(lagrangian,Float64,order) + V_φ = TestFESpace(model,reffe) + φh = interpolate(ls,V_φ) + + # Correction if level set is on top of a node + x_φ = get_free_dof_values(φh) + idx = findall(isapprox(0.0;atol=10^-10),x_φ) + !isempty(idx) && @info "Correcting level values!" + x_φ[idx] .+= 100*eps(eltype(x_φ)) + + geo = DiscreteGeometry(φh,model) + cutgeo = cut(model,geo) + + Γ = EmbeddedBoundary(cutgeo) + Γ_AD = DifferentiableTriangulation(Γ,V_φ) + dΓ_AD = Measure(Γ_AD,2*order) + + # Sec 6.2 - 10.1007/s00466-017-1383-6 + g((x,y)) = x - 1/10*sin(2π*y/6) + gh = interpolate(g,V_φ) + _n_g(∇g) = ∇g/(10^-20+norm(∇g)) + n_g = _n_g ∘ ∇(gh) + j(x) = norm(x)^2 + + function J_int(φ) + n = get_normal_vector(Γ_AD) + ∫(j ∘ (n-n_g))dΓ_AD + end + dJ_int_AD = gradient(J_int,φh) + dJ_int_AD_vec = assemble_vector(dJ_int_AD,V_φ) + hess = hessian(J_int,φh) + d²J = assemble_matrix(hess,V_φ,V_φ) + + # Finite diff + if fdm + function J_fdm_surf(φ) + φh = FEFunction(V_φ,φ) + cutgeo = cut(model,DiscreteGeometry(φh,model)) + Γ = EmbeddedBoundary(cutgeo) + dΓ = Measure(Γ,2*order) + n = get_normal_vector(Γ) + sum(∫(j ∘ (n-n_g))dΓ) + end + dJ_FD = FiniteDiff.finite_difference_gradient(J_fdm_surf,get_free_dof_values(φh)) + d²J_FD = compute_hess ? FiniteDiff.finite_difference_hessian(J_fdm_surf,get_free_dof_values(φh)) : nothing + + abs_error_fdm = norm(dJ_int_AD_vec - dJ_FD,Inf) + abs_error_fdm_hess = compute_hess ? norm(d²J - d²J_FD,Inf) : nothing + + if verbose + println("D) g(n) surf integral:") + println(" - norm(dJ_AD - dJ_exact,Inf) = ","N/A") + println(" - norm(dJ_AD - dJ_FDM,Inf) = ",abs_error_fdm) + compute_hess && println(" - norm(d²J_AD - d²J_FDM,Inf) = ",abs_error_fdm_hess) + end + end +end + +####################### + +# FDM is quite expensive, so we only run if required. + +D = 2 +n = 10 +model = generate_model(D,n) +f(x) = x[1]+x[2] +fvec((x,y)) = VectorValue((1-x)^2,(1-y)^2) +main(model,level_set(:circle_2),f;vtk=false,verbose=true,name="2D_circle/")#,fdm=true) +main(model,level_set(:regular_2d),f;vtk=false,verbose=true,name="2D_reg/")#,fdm=true) +main_normal(model,level_set(:circle_2),fvec;vtk=false,verbose=true,name="2D_circle_flux/",run_test=true)#,fdm=true) +main_normal(model,level_set(:regular_2d),fvec;vtk=false,verbose=true,name="2D_reg_flux/",run_test=false)#,fdm=true) # This will fail as expected +main_fdm_only_verif(model,level_set(:circle_2),verbose=true)#,fdm=true) +main_fdm_only_verif(model,level_set(:regular_2d),verbose=true,compute_hess=true)#,fdm=true) + +D = 3 +n = 4 +model = generate_model(D,n) +φ = level_set(:regular_3d) +f(x) = x[1]+x[2] +fvec2((x,y,z)) = VectorValue((1-x)^2,(1-y)^2,0) +main(model,level_set(:sphere_2),f;vtk=false,verbose=true,name="3D_circle/")#,fdm=true) +main(model,level_set(:regular_3d),f;vtk=false,verbose=true,name="3D_reg/")#,fdm=true) +main_normal(model,level_set(:sphere_2),fvec2;vtk=false,verbose=true,name="3D_circle_flux/",run_test=true)#,fdm=true) +main_normal(model,level_set(:regular_3d),fvec2;vtk=false,verbose=true,name="3D_reg_flux/",run_test=false,)#fdm=true) # This will fail as expected +main_fdm_only_verif(model,level_set(:sphere_2),verbose=true)#,fdm=true) +main_fdm_only_verif(model,level_set(:regular_3d),verbose=true)#,fdm=true) + +end \ No newline at end of file diff --git a/test/LevelSetCuttersTests/runtests.jl b/test/LevelSetCuttersTests/runtests.jl index c108a65e..548e1149 100644 --- a/test/LevelSetCuttersTests/runtests.jl +++ b/test/LevelSetCuttersTests/runtests.jl @@ -12,4 +12,6 @@ using Test @testset "LevelSetCutters" begin include("LevelSetCuttersTests.jl") end +@testset "GeometricalDifferentiation" begin include("GeometricalDifferentiationTests.jl") end + end # module From 07aee710a5c009e5a68b4fbaad50a00c0e438c46 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 17 Apr 2025 16:26:58 +1000 Subject: [PATCH 088/120] Minor --- test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl b/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl index 04e7f527..aa6bbec0 100644 --- a/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl +++ b/test/InterfacesTests/EmbeddedFacetDiscretizationsTests.jl @@ -76,7 +76,7 @@ celldata_Λ = [ "bgcell_right"=>collect(Int,get_glue(Λ.⁻,Val(D)).tface_to_mface)] cellfields_Λ = ["normal"=> n_Λ.⁺,"jump_v"=>jump(v),"jump_u"=>jump(u)] -d = "./dev"#mktempdir() +d = mktempdir() try writevtk(Ωbg,joinpath(d,"trian"),append=false) writevtk(Ω,joinpath(d,"trian_O"),celldata=celldata_Ω,cellfields=cellfields_Ω,append=false) @@ -84,7 +84,7 @@ try writevtk(Λ,joinpath(d,"trian_sO"),celldata=celldata_Λ,cellfields=cellfields_Λ,append=false) writevtk(Γf,joinpath(d,"trian_Gf"),append=false) finally - #rm(d,recursive=true) + rm(d,recursive=true) end ########################################## From 9c22c37eed9e499f69a6e9ea19a952fb3ae36d22 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Thu, 17 Apr 2025 17:24:52 +1000 Subject: [PATCH 089/120] Started documenting the library --- src/Interfaces/Cutters.jl | 43 ++++++++++++++++++++ src/Interfaces/EmbeddedDiscretizations.jl | 44 ++++++++++++++++++++- src/LevelSetCutters/AnalyticalGeometries.jl | 33 +++++++++++++++- src/LevelSetCutters/DiscreteGeometries.jl | 17 ++++++++ src/LevelSetCutters/LevelSetCutters.jl | 13 ++++++ 5 files changed, 147 insertions(+), 3 deletions(-) diff --git a/src/Interfaces/Cutters.jl b/src/Interfaces/Cutters.jl index 5104430d..2fca363e 100644 --- a/src/Interfaces/Cutters.jl +++ b/src/Interfaces/Cutters.jl @@ -1,17 +1,60 @@ + +""" + abstract type Cutter <: GridapType end + +Abstract type for all mesh cutters. Has to be paired with a [`CSG.Geometry`](@ref) to +cut the background mesh. + +## Methods + +- [`cut(cutter::Cutter,background,geom)`](@ref) +- [`cut_facets(cutter::Cutter,background,geom)`](@ref) +- [`compute_bgcell_to_inoutcut(cutter::Cutter,background,geom)`](@ref) +- [`compute_bgfacet_to_inoutcut(cutter::Cutter,background,geom)`](@ref) + +Generally `cut` and `cut_facets` dispatch based on the geometry provided, so it is +generally more convennient to call the following methods instead: + +- [`cut(background,geom)`](@ref) +- [`cut_facets(background,geom)`](@ref) + +""" abstract type Cutter <: GridapType end +""" + cut(cutter::Cutter,background,geom) + +Cut the background mesh with the provided cutter and geometry, returnning the cut cells. +The cut cells are returned as an [`EmbeddedDiscretization`](@ref) object. +""" function cut(cutter::Cutter,background,geom) @abstractmethod end +""" + compute_bgcell_to_inoutcut(cutter::Cutter,background,geom) + +Returns an array of IN/OUT/CUT states for each cell in the background mesh. +""" function compute_bgcell_to_inoutcut(cutter::Cutter,background,geom) @abstractmethod end +""" + cut_facets(cutter::Cutter,background,geom) + +Cut the background mesh with the provided cutter and geometry, returning the cut facets. +The cut facets are returned as an [`EmbeddedFacetDiscretization`](@ref) object. +""" function cut_facets(cutter::Cutter,background,geom) @abstractmethod end +""" + compute_bgfacet_to_inoutcut(cutter::Cutter,background,geom) + +Returns an array of IN/OUT/CUT states for each facet in the background mesh. +""" function compute_bgfacet_to_inoutcut(cutter::Cutter,background,geom) @abstractmethod end diff --git a/src/Interfaces/EmbeddedDiscretizations.jl b/src/Interfaces/EmbeddedDiscretizations.jl index 5a6a14b3..b8ee0ee0 100644 --- a/src/Interfaces/EmbeddedDiscretizations.jl +++ b/src/Interfaces/EmbeddedDiscretizations.jl @@ -1,6 +1,42 @@ - +""" + abstract type EmbeddedDiscretization <: GridapType end +""" abstract type AbstractEmbeddedDiscretization <: GridapType end +""" + struct EmbeddedDiscretization{Dc,T} <: AbstractEmbeddedDiscretization + bgmodel::DiscreteModel + ls_to_bgcell_to_inoutcut::Vector{Vector{Int8}} + subcells::SubCellData{Dc,Dc,T} + ls_to_subcell_to_inout::Vector{Vector{Int8}} + subfacets::SubFacetData{Dc,T} + ls_to_subfacet_to_inout::Vector{Vector{Int8}} + oid_to_ls::Dict{UInt,Int} + geo::CSG.Geometry + end + +This structure contains all the required information to build integration `Triangulation`s +for a cut model. + +## Constructors + + EmbeddedDiscretization(cutter::Cutter,background,geom) + +## Properties + +- `bgmodel::DiscreteModel`: the background mesh +- `geo::CSG.Geometry`: the geometry used to cut the background mesh +- `subcells::SubCellData`: collection of cut subcells, attached to the background mesh +- `subfacets::SubFacetData`: collection of cut facets, attached to the background mesh +- `ls_to_X_to_inoutcut::Vector{Vector{Int8}}`: list of IN/OUT/CUT states for each cell/facet + in the background mesh, for each node in the geometry tree. + +## Methods + +- [`Triangulation(cut::EmbeddedDiscretization,in_or_out)`](@ref) +- [`EmbeddedBoundary(cut::EmbeddedDiscretization)`](@ref) + +""" struct EmbeddedDiscretization{Dc,T} <: AbstractEmbeddedDiscretization bgmodel::DiscreteModel ls_to_bgcell_to_inoutcut::Vector{Vector{Int8}} @@ -224,6 +260,9 @@ function Triangulation(cut::EmbeddedDiscretization) Triangulation(cut,PHYSICAL_IN,cut.geo) end +""" + Triangulation(cut::EmbeddedDiscretization[,in_or_out=PHYSICAL_IN]) +""" function Triangulation(cut::EmbeddedDiscretization,in_or_out) Triangulation(cut,in_or_out,cut.geo) end @@ -355,6 +394,9 @@ function _compute_inout_complementary(inout_1) end end +""" + EmbeddedBoundary(cut::EmbeddedDiscretization) +""" function EmbeddedBoundary(cut::EmbeddedDiscretization) EmbeddedBoundary(cut,cut.geo) end diff --git a/src/LevelSetCutters/AnalyticalGeometries.jl b/src/LevelSetCutters/AnalyticalGeometries.jl index 48485ed5..a34103a3 100644 --- a/src/LevelSetCutters/AnalyticalGeometries.jl +++ b/src/LevelSetCutters/AnalyticalGeometries.jl @@ -1,4 +1,33 @@ +""" + struct AnalyticalGeometry <: CSG.Geometry + tree::Node + end + +A structure to represent analytical geometries, used to cut background meshes. + +## Constructor + + AnalyticalGeometry(f::Function;name=string(nameof(f))) + +where `f: Ω -> R ` is a function that, similiarly to a level set function, is negative inside the +geometry and positive outside. + +## Predefined geometries + + doughnut(R,r;x0=zero(Point{3,typeof(R)}),name="doughnut") + popcorn(r0=0.6, σ=0.2, A=2, x0=zero(Point{3,typeof(r0)}), name="popcorn") + sphere(R;x0=zero(Point{3,eltype(R)}),name="sphere") + disk(R;x0=zero(Point{2,eltype(R)}),name="disk") + cylinder(R;x0=zero(Point{3,eltype(R)}),v=VectorValue(1,0,0),name="cylinder") + plane(x0=Point(0,0,0),v=VectorValue(1,0,0),name="plane") + square(L=1,x0=Point(0,0),name="square",edges=["edge_i" for i in 1:4]) + quadrilateral(x0=Point(0,0),d1=VectorValue(1,0),d2=VectorValue(0,1),name="quadrilateral") + cube(L=1,x0=Point(0,0,0),name="cube") + tube(R,L;x0=zero(Point{3,typeof(R)}),v=VectorValue(1,0,0),name="tube") + olympic_rings(R,r,name="olympic_rings") + +""" struct AnalyticalGeometry <: CSG.Geometry tree::Node end @@ -14,8 +43,8 @@ struct BoundingBox{D,T} pmax::Point{D,T} end -function AnalyticalGeometry(f::Function) - tree = Leaf((f,string(nameof(f)),nothing)) +function AnalyticalGeometry(f::Function;name=string(nameof(f))) + tree = Leaf((f,name,nothing)) AnalyticalGeometry(tree) end diff --git a/src/LevelSetCutters/DiscreteGeometries.jl b/src/LevelSetCutters/DiscreteGeometries.jl index 472fa278..8ad1f024 100644 --- a/src/LevelSetCutters/DiscreteGeometries.jl +++ b/src/LevelSetCutters/DiscreteGeometries.jl @@ -1,4 +1,16 @@ +""" + struct DiscreteGeometry{D,T} <: CSG.Geometry + tree::Node + point_to_coords::Vector{Point{D,T}} + end + +## Constructors + + DiscreteGeometry(φh::FEFunction,model::DiscreteModel;name::String="") + DiscreteGeometry(f::Function,model::DiscreteModel;name::String="") + +""" struct DiscreteGeometry{D,T} <: CSG.Geometry tree::Node point_to_coords::Vector{Point{D,T}} @@ -61,6 +73,11 @@ function _find_unique_leaves(tree) j_to_fun, oid_to_j end +function DiscreteGeometry(f::Function,model::DiscreteModel;name::String="") + geo = AnalyticalGeometry(f;name=name) + discretize(geo,model) +end + function DiscreteGeometry( point_to_value::AbstractVector,point_to_coords::AbstractVector;name::String="") data = (point_to_value,name,nothing) diff --git a/src/LevelSetCutters/LevelSetCutters.jl b/src/LevelSetCutters/LevelSetCutters.jl index 5b6e0f7c..30592287 100644 --- a/src/LevelSetCutters/LevelSetCutters.jl +++ b/src/LevelSetCutters/LevelSetCutters.jl @@ -58,6 +58,19 @@ include("CutTriangulations.jl") include("DifferentiableTriangulations.jl") +""" + struct LevelSetCutter <: Cutter end + +Cutter for `DiscreteGeometry` and `AnalyticalGeometry`. + +## Usage + + cut(background::DiscreteModel,geom::AnalyticalGeometry) + cut(background::DiscreteModel,geom::DiscreteGeometry) + cut_facets(background::DiscreteModel,geom::AnalyticalGeometry) + cut_facets(background::DiscreteModel,geom::DiscreteGeometry) + +""" struct LevelSetCutter <: Cutter end function cut(cutter::LevelSetCutter,background::DiscreteModel,geom) From 2977507ef1056dd5954273515b15c7bc255f6cf2 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 18 Apr 2025 10:55:12 +1000 Subject: [PATCH 090/120] Added documentation skeleton --- docs/Project.toml | 1 + docs/make.jl | 26 +++++++++++----- docs/src/AggregatedFEM.md | 16 ++++++++++ docs/src/CSGCutters.md | 15 +++++++++ docs/src/Distributed.md | 11 +++++++ docs/src/Interfaces.md | 48 +++++++++++++++++++++++++++++ docs/src/LevelSetCutters.md | 16 ++++++++++ docs/src/MomentFittedQuadratures.md | 11 +++++++ docs/src/index.md | 18 ++++++++--- 9 files changed, 150 insertions(+), 12 deletions(-) create mode 100644 docs/src/AggregatedFEM.md create mode 100644 docs/src/CSGCutters.md create mode 100644 docs/src/Distributed.md create mode 100644 docs/src/Interfaces.md create mode 100644 docs/src/LevelSetCutters.md create mode 100644 docs/src/MomentFittedQuadratures.md diff --git a/docs/Project.toml b/docs/Project.toml index dfa65cd1..bb0510fc 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,2 +1,3 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +GridapEmbedded = "8838a6a3-0006-4405-b874-385995508d5d" diff --git a/docs/make.jl b/docs/make.jl index 3bad67a4..d335684c 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,14 +1,24 @@ using Documenter, GridapEmbedded +pages = [ + "Home" => "index.md", + "Interfaces" => "Interfaces.md", + "Constructive Solid Geometry (CSG)" => "CSGCutters.md", + "Level Sets" => "LevelSetCutters.md", + "Aggregated FEM" => "AggregatedFEM.md", + "Moment-Fitted Quadratures" => "MomentFittedQuadratures.md", + "Distributed computing" => "Distributed.md", +], + makedocs(; - modules=[GridapEmbedded], - format=Documenter.HTML(), - pages=[ - "Home" => "index.md", - ], - repo="https://github.com/gridap/GridapEmbedded.jl/blob/{commit}{path}#L{line}", - sitename="GridapEmbedded.jl", - authors="Francesc Verdugo , Eric Neiva and Santiago Badia ", + modules = [GridapEmbedded], + format = Documenter.HTML( + size_threshold=nothing + ), + sitename = "GridapEmbedded.jl", + authors = "Francesc Verdugo , Eric Neiva and Santiago Badia ", + pages = pages, + warnonly = true, ) deploydocs(; diff --git a/docs/src/AggregatedFEM.md b/docs/src/AggregatedFEM.md new file mode 100644 index 00000000..a2d7be88 --- /dev/null +++ b/docs/src/AggregatedFEM.md @@ -0,0 +1,16 @@ + +# Aggregated FEM + +```@meta +CurrentModule = GridapEmbedded.AgFEM +``` + +```@autodocs +Modules = [AgFEM,] +Order = [:type, :constant, :macro, :function] +Pages = [ + "/AgFEM.jl", + "/AgFEMSpaces.jl", + "CellAggregation.jl" +] +``` diff --git a/docs/src/CSGCutters.md b/docs/src/CSGCutters.md new file mode 100644 index 00000000..72dd78dd --- /dev/null +++ b/docs/src/CSGCutters.md @@ -0,0 +1,15 @@ + +# Constructive Solid Geometry (CSG) Cutters + +```@meta +CurrentModule = GridapEmbedded.CSG +``` + +```@autodocs +Modules = [CSG,] +Order = [:type, :constant, :macro, :function] +Pages = [ + "/Nodes.jl", + "/Geometries.jl", +] +``` diff --git a/docs/src/Distributed.md b/docs/src/Distributed.md new file mode 100644 index 00000000..56a17b59 --- /dev/null +++ b/docs/src/Distributed.md @@ -0,0 +1,11 @@ + +# Distributed computing + +```@meta +CurrentModule = GridapEmbedded.Distributed +``` + +```@autodocs +Modules = [Distributed,] +Order = [:type, :constant, :macro, :function] +``` diff --git a/docs/src/Interfaces.md b/docs/src/Interfaces.md new file mode 100644 index 00000000..72d763d2 --- /dev/null +++ b/docs/src/Interfaces.md @@ -0,0 +1,48 @@ + +# Embedded Interfaces + +```@meta +CurrentModule = GridapEmbedded.Interfaces +``` + +## Cutters + +Cutters are used to cut the background mesh according to a provided geometry. + +```@autodocs +Modules = [Interfaces,] +Order = [:type, :constant, :macro, :function] +Pages = [ + "/Cutters.jl", +] +``` + +We provide several types of cutters, including: + +- **CSG Cutters**: Constructive Solid Geometry (CSG) Cutters. See [Constructive Solid Geometry (CSG) Cutters](@ref). +- **Level-Set Cutters**: Level-Set Cutters. See [Level-Set Cutters](@ref). +- **STL Cutters**: Cutters for STL based geometries. Provided by [STLCutters.jl](https://github.com/gridap/STLCutters.jl). + +## Embedded Discretizations + +After cutting the background mesh, you will be returned an `EmbeddedDiscretization` object. These contain all the information you need to generate the integration meshes for embedded methods. + +```@autodocs +Modules = [Interfaces,] +Order = [:type, :constant, :macro, :function] +Pages = [ + "/EmbeddedDiscretizations.jl", + "/EmbeddedFacetDiscretizations.jl", +] +``` + +## Embedded Triangulations + +```@autodocs +Modules = [Interfaces,] +Order = [:type, :constant, :macro, :function] +Pages = [ + "/SubCellTriangulations", + "/SubFacetTriangulations.jl" +] +``` diff --git a/docs/src/LevelSetCutters.md b/docs/src/LevelSetCutters.md new file mode 100644 index 00000000..8980ddc6 --- /dev/null +++ b/docs/src/LevelSetCutters.md @@ -0,0 +1,16 @@ + +# Level-Set Cutters + +```@meta +CurrentModule = GridapEmbedded.LevelSetCutters +``` + +```@autodocs +Modules = [LevelSetCutters,] +Order = [:type, :constant, :macro, :function] +Pages = [ + "/AnalyticalGeometries.jl", + "/DiscreteGeometries.jl", + "LevelSetCutters.jl", +] +``` diff --git a/docs/src/MomentFittedQuadratures.md b/docs/src/MomentFittedQuadratures.md new file mode 100644 index 00000000..5f076ddd --- /dev/null +++ b/docs/src/MomentFittedQuadratures.md @@ -0,0 +1,11 @@ + +# Moment-Fitted Quadratures + +```@meta +CurrentModule = GridapEmbedded.MomentFittedQuadratures +``` + +```@autodocs +Modules = [MomentFittedQuadratures,] +Order = [:type, :constant, :macro, :function] +``` diff --git a/docs/src/index.md b/docs/src/index.md index 84432dfd..21aa5a50 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,8 +1,18 @@ # GridapEmbedded.jl -```@index -``` +## Introduction + +GridapEmbedded.jl is a package for the simulation of PDEs on embedded domains within the Gridap.jl ecosystem. Please refer to the [Gridap.jl documentation](https://gridap.github.io/Gridap.jl/stable/) for information on the core capabilities of the Gridap.jl library. + +## Manual -```@autodocs -Modules = [GridapEmbedded] +```@contents +Pages = [ + "Interfaces.md", + "CSGCutters.md", + "LevelSetCutters.md", + "AggregatedFEM.md", + "MomentFittedQuadratures.md", + "Distributed.md", +] ``` From 3a60103044ec0bc2b3cbb110c1599c396d4cde0d Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 18 Apr 2025 11:45:31 +1000 Subject: [PATCH 091/120] More docs --- docs/make.jl | 2 +- docs/src/Interfaces.md | 66 +++++++++++++++---- .../CutFaceBoundaryTriangulations.jl | 2 +- src/Interfaces/EmbeddedDiscretizations.jl | 23 ++++--- .../EmbeddedFacetDiscretizations.jl | 38 ++++++++++- 5 files changed, 100 insertions(+), 31 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index d335684c..c5e20ca3 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -8,7 +8,7 @@ pages = [ "Aggregated FEM" => "AggregatedFEM.md", "Moment-Fitted Quadratures" => "MomentFittedQuadratures.md", "Distributed computing" => "Distributed.md", -], +] makedocs(; modules = [GridapEmbedded], diff --git a/docs/src/Interfaces.md b/docs/src/Interfaces.md index 72d763d2..e9927a89 100644 --- a/docs/src/Interfaces.md +++ b/docs/src/Interfaces.md @@ -5,6 +5,45 @@ CurrentModule = GridapEmbedded.Interfaces ``` +## Domain Nomenclature + +Throughout this documentation, many methods accept arguments that select different parts of the cut domain. We split the domain into the following parts: + +The background mesh entities (cells, facets, nodes) are classified as `IN`, `OUT` or `CUT`. The `IN` and `OUT` background cells are uncut, i.e completely inside or outside the geometry, respectively. These states are internally defined as constants: + +```julia + const IN = -1 + const OUT = 1 + const CUT = 0 +``` + +The `CUT` background cells are cut by the embedded boundary, and split into subcells/subfacets. The subcells/subfacets are classified as `IN` or `OUT` depending on whether they are inside or outside the geometry. `CUT-IN` and `CUT-OUT` subentities can be accessed using the `CutInOrOut` objects: + +```julia + struct CutInOrOut + in_or_out::Int + end + const CUT_IN = CutInOrOut(IN) + const CUT_OUT = CutInOrOut(OUT) +``` + +For FEM, we generally want to get sets of uncut and cut cells together, for a given state `IN/OUT`. These are referred as `PHYSICAL` parts of the domain. Moreover, FE spaces are generally defined over the background mesh and need to span both `IN/OUT` and `CUT` background cells. These are referred as `ACTIVE` parts of the domain. You can extract the `PHYSICAL` and `ACTIVE` parts of the domain using the following constants: + +```julia +const PHYSICAL_IN = (CUT_IN,IN) +const PHYSICAL_OUT = (CUT_OUT,OUT) +const PHYSICAL = PHYSICAL_IN +``` + +```julia +struct ActiveInOrOut + in_or_out::Int +end +const ACTIVE_IN = ActiveInOrOut(IN) +const ACTIVE_OUT = ActiveInOrOut(OUT) +const ACTIVE = ACTIVE_IN +``` + ## Cutters Cutters are used to cut the background mesh according to a provided geometry. @@ -27,22 +66,21 @@ We provide several types of cutters, including: After cutting the background mesh, you will be returned an `EmbeddedDiscretization` object. These contain all the information you need to generate the integration meshes for embedded methods. -```@autodocs -Modules = [Interfaces,] -Order = [:type, :constant, :macro, :function] -Pages = [ - "/EmbeddedDiscretizations.jl", - "/EmbeddedFacetDiscretizations.jl", -] +```@docs +AbstractEmbeddedDiscretization +EmbeddedDiscretization +EmbeddedFacetDiscretization ``` ## Embedded Triangulations -```@autodocs -Modules = [Interfaces,] -Order = [:type, :constant, :macro, :function] -Pages = [ - "/SubCellTriangulations", - "/SubFacetTriangulations.jl" -] +From `EmbeddedDiscretization` objects, you can extract all the triangulations you need to perform integration for embedded methods. We currently provide the following methods: + +```@docs +Gridap.Geometry.Triangulation(::EmbeddedDiscretization,::Any) +EmbeddedBoundary(::EmbeddedDiscretization) +GhostSkeleton(::EmbeddedDiscretization) +Gridap.Geometry.BoundaryTriangulation(::EmbeddedFacetDiscretization,::Any) +Gridap.Geometry.SkeletonTriangulation(::EmbeddedFacetDiscretization,::Any) +SubFacetBoundaryTriangulation ``` diff --git a/src/Interfaces/CutFaceBoundaryTriangulations.jl b/src/Interfaces/CutFaceBoundaryTriangulations.jl index d30ada3a..e85e70cc 100644 --- a/src/Interfaces/CutFaceBoundaryTriangulations.jl +++ b/src/Interfaces/CutFaceBoundaryTriangulations.jl @@ -111,7 +111,7 @@ Triangulation containing the interfaces between subfacets. We always have dimens - Df = Dc-1 :: Dimension of the cut subfacets - Di = Dc-2 :: Dimension of the subfacet interfaces -Description of the different components: +# Properties - `face_trian` :: Original SubFacetTriangulation, built on top of the background mesh. - `face_model` :: Subfacet model. Active model for `face_trian`. diff --git a/src/Interfaces/EmbeddedDiscretizations.jl b/src/Interfaces/EmbeddedDiscretizations.jl index b8ee0ee0..95b6ccc2 100644 --- a/src/Interfaces/EmbeddedDiscretizations.jl +++ b/src/Interfaces/EmbeddedDiscretizations.jl @@ -1,26 +1,17 @@ """ - abstract type EmbeddedDiscretization <: GridapType end + abstract type EmbeddedDiscretization <: GridapType """ abstract type AbstractEmbeddedDiscretization <: GridapType end """ struct EmbeddedDiscretization{Dc,T} <: AbstractEmbeddedDiscretization - bgmodel::DiscreteModel - ls_to_bgcell_to_inoutcut::Vector{Vector{Int8}} - subcells::SubCellData{Dc,Dc,T} - ls_to_subcell_to_inout::Vector{Vector{Int8}} - subfacets::SubFacetData{Dc,T} - ls_to_subfacet_to_inout::Vector{Vector{Int8}} - oid_to_ls::Dict{UInt,Int} - geo::CSG.Geometry - end This structure contains all the required information to build integration `Triangulation`s for a cut model. ## Constructors - EmbeddedDiscretization(cutter::Cutter,background,geom) + cut(cutter::Cutter,background,geom) ## Properties @@ -28,13 +19,18 @@ for a cut model. - `geo::CSG.Geometry`: the geometry used to cut the background mesh - `subcells::SubCellData`: collection of cut subcells, attached to the background mesh - `subfacets::SubFacetData`: collection of cut facets, attached to the background mesh -- `ls_to_X_to_inoutcut::Vector{Vector{Int8}}`: list of IN/OUT/CUT states for each cell/facet +- `ls_to_bgcell_to_inoutcut::Vector{Vector{Int8}}`: list of IN/OUT/CUT states for each cell in the background mesh, for each node in the geometry tree. +- `ls_to_subcell_to_inoutcut::Vector{Vector{Int8}}`: list of IN/OUT/CUT states for each subcell + in the cut part of the mesh, for each node in the geometry tree. +- `ls_to_subfacet_to_inoutcut::Vector{Vector{Int8}}`: list of IN/OUT/CUT states for each subfacet + in the cut part of the mesh, for each node in the geometry tree. ## Methods - [`Triangulation(cut::EmbeddedDiscretization,in_or_out)`](@ref) - [`EmbeddedBoundary(cut::EmbeddedDiscretization)`](@ref) +- [`GhostSkeleton(cut::EmbeddedDiscretization)`](@ref) """ struct EmbeddedDiscretization{Dc,T} <: AbstractEmbeddedDiscretization @@ -456,6 +452,9 @@ function EmbeddedBoundary(cut::EmbeddedDiscretization,geo1::CSG.Geometry,geo2::C end +""" + GhostSkeleton(cut::EmbeddedDiscretization[,in_or_out=ACTIVE_IN]) +""" function GhostSkeleton(cut::EmbeddedDiscretization) GhostSkeleton(cut,ACTIVE_IN) end diff --git a/src/Interfaces/EmbeddedFacetDiscretizations.jl b/src/Interfaces/EmbeddedFacetDiscretizations.jl index 56ece473..1f5476cc 100644 --- a/src/Interfaces/EmbeddedFacetDiscretizations.jl +++ b/src/Interfaces/EmbeddedFacetDiscretizations.jl @@ -1,4 +1,30 @@ +""" + struct EmbeddedFacetDiscretization{Dc,Dp,T} <: AbstractEmbeddedDiscretization + +This structure contains all the required information to build integration `Triangulations` +for a cut model boundary. + +## Constructors + + cut_facets(cutter::Cutter,background,geom) + +## Properties + +- `bgmodel::DiscreteModel`: the background mesh +- `geo::CSG.Geometry`: the geometry used to cut the background mesh +- `subfacets::SubFacetData`: collection of cut facets, attached to the background mesh +- `ls_to_facet_to_inoutcut::Vector{Vector{Int8}}`: list of IN/OUT/CUT states for each facet + in the background mesh, for each node in the geometry tree. +- `ls_to_subfacet_to_inoutcut::Vector{Vector{Int8}}`: list of IN/OUT/CUT states for each subfacet + in the cut part of the mesh, for each node in the geometry tree. + +## Methods + +- [`BoundaryTriangulation(cut::EmbeddedFacetDiscretization,in_or_out)`](@ref) +- [`SkeletonTriangulation(cut::EmbeddedFacetDiscretization,in_or_out)`](@ref) + +""" struct EmbeddedFacetDiscretization{Dc,Dp,T} <: AbstractEmbeddedDiscretization bgmodel::DiscreteModel{Dp,Dp} ls_to_facet_to_inoutcut::Vector{Vector{Int8}} @@ -20,6 +46,9 @@ function SkeletonTriangulation(cut::EmbeddedFacetDiscretization) SkeletonTriangulation(cut,PHYSICAL_IN) end +""" + SkeletonTriangulation(cut::EmbeddedFacetDiscretization[, in_or_out=PHYSICAL_IN]) +""" function SkeletonTriangulation( cut::EmbeddedFacetDiscretization, in_or_out) @@ -75,6 +104,9 @@ function BoundaryTriangulation( BoundaryTriangulation(cut,PHYSICAL_IN;tags=tags) end +""" + BoundaryTriangulation(cut::EmbeddedFacetDiscretization[, in_or_out=PHYSICAL_IN; tags=nothing]) +""" function BoundaryTriangulation( cut::EmbeddedFacetDiscretization, in_or_out; @@ -232,10 +264,10 @@ in this triangulation is part of a background facet that has been cut by the geo This differs from the the `SubFacetTriangulation` in that the facets in the `SubFacetTriangulation` are not cut background facets, but rather subfacets on the interior of a background cell. -They result from calling `Boundary` or `Skeleton` on an `EmbeddedFacetDiscretization` object, -for instance: +They result from calling `Boundary` or `Skeleton` on an `EmbeddedFacetDiscretization` object. - BoundaryTriangulation(cut::EmbeddedFacetDiscretization,in_or_out,geo;tags=nothing) + BoundaryTriangulation(cut::EmbeddedFacetDiscretization,in_or_out;tags=nothing) + SkeletonTriangulation(cut::EmbeddedFacetDiscretization,in_or_out) """ struct SubFacetBoundaryTriangulation{Dc,Dp,T} <: Triangulation{Dc,Dp} From 56e159fc4b6c33c51ac07c8a460e42c04d9f4c8b Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 18 Apr 2025 12:07:38 +1000 Subject: [PATCH 092/120] More docs --- docs/make.jl | 6 ++-- docs/src/{CSGCutters.md => CSG.md} | 2 +- docs/src/Interfaces.md | 7 ++--- docs/src/index.md | 2 +- src/CSG/Geometries.jl | 35 +++++++++++++++++++++-- src/Interfaces/EmbeddedDiscretizations.jl | 19 ++++++++++-- src/Interfaces/SubCellTriangulations.jl | 5 ++++ src/Interfaces/SubFacetTriangulations.jl | 5 ++++ 8 files changed, 68 insertions(+), 13 deletions(-) rename docs/src/{CSGCutters.md => CSG.md} (80%) diff --git a/docs/make.jl b/docs/make.jl index c5e20ca3..2c5569a6 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -2,9 +2,9 @@ using Documenter, GridapEmbedded pages = [ "Home" => "index.md", - "Interfaces" => "Interfaces.md", - "Constructive Solid Geometry (CSG)" => "CSGCutters.md", - "Level Sets" => "LevelSetCutters.md", + "Constructive Solid Geometry (CSG)" => "CSG.md", + "Embedded Interfaces" => "Interfaces.md", + "Level Set Cutters" => "LevelSetCutters.md", "Aggregated FEM" => "AggregatedFEM.md", "Moment-Fitted Quadratures" => "MomentFittedQuadratures.md", "Distributed computing" => "Distributed.md", diff --git a/docs/src/CSGCutters.md b/docs/src/CSG.md similarity index 80% rename from docs/src/CSGCutters.md rename to docs/src/CSG.md index 72dd78dd..d801c34e 100644 --- a/docs/src/CSGCutters.md +++ b/docs/src/CSG.md @@ -1,5 +1,5 @@ -# Constructive Solid Geometry (CSG) Cutters +# Constructive Solid Geometry (CSG) ```@meta CurrentModule = GridapEmbedded.CSG diff --git a/docs/src/Interfaces.md b/docs/src/Interfaces.md index e9927a89..dadc981a 100644 --- a/docs/src/Interfaces.md +++ b/docs/src/Interfaces.md @@ -9,7 +9,7 @@ CurrentModule = GridapEmbedded.Interfaces Throughout this documentation, many methods accept arguments that select different parts of the cut domain. We split the domain into the following parts: -The background mesh entities (cells, facets, nodes) are classified as `IN`, `OUT` or `CUT`. The `IN` and `OUT` background cells are uncut, i.e completely inside or outside the geometry, respectively. These states are internally defined as constants: +**The background mesh entities** (cells, facets, nodes) are classified as `IN`, `OUT` or `CUT`. The `IN` and `OUT` background cells are uncut, i.e completely inside or outside the geometry, respectively. These states are internally defined as constants: ```julia const IN = -1 @@ -17,7 +17,7 @@ The background mesh entities (cells, facets, nodes) are classified as `IN`, `OUT const CUT = 0 ``` -The `CUT` background cells are cut by the embedded boundary, and split into subcells/subfacets. The subcells/subfacets are classified as `IN` or `OUT` depending on whether they are inside or outside the geometry. `CUT-IN` and `CUT-OUT` subentities can be accessed using the `CutInOrOut` objects: +**The `CUT` background cells** are cut by the embedded boundary, and split into subcells/subfacets. The subcells/subfacets are classified as `IN` or `OUT` depending on whether they are inside or outside the geometry. `CUT_IN` and `CUT_OUT` subentities can be accessed using the `CutInOrOut` objects: ```julia struct CutInOrOut @@ -58,8 +58,7 @@ Pages = [ We provide several types of cutters, including: -- **CSG Cutters**: Constructive Solid Geometry (CSG) Cutters. See [Constructive Solid Geometry (CSG) Cutters](@ref). -- **Level-Set Cutters**: Level-Set Cutters. See [Level-Set Cutters](@ref). +- **Level-Set Cutters**: Cutters for Level-Set and function-defined geometries. See [Level-Set Cutters](@ref). - **STL Cutters**: Cutters for STL based geometries. Provided by [STLCutters.jl](https://github.com/gridap/STLCutters.jl). ## Embedded Discretizations diff --git a/docs/src/index.md b/docs/src/index.md index 21aa5a50..4ba7959e 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -8,8 +8,8 @@ GridapEmbedded.jl is a package for the simulation of PDEs on embedded domains wi ```@contents Pages = [ + "CSG.md", "Interfaces.md", - "CSGCutters.md", "LevelSetCutters.md", "AggregatedFEM.md", "MomentFittedQuadratures.md", diff --git a/src/CSG/Geometries.jl b/src/CSG/Geometries.jl index 38c39080..f37ee04b 100644 --- a/src/CSG/Geometries.jl +++ b/src/CSG/Geometries.jl @@ -1,14 +1,35 @@ +""" + abstract type Geometry + +Abstract type for the definition of a geometry. + +## Interface + +- `get_tree(geo::Geometry)` +- `similar_geometry(a::Geometry,tree::Node)` +- `compatible_geometries(a::Geometry,b::Geometry)` + +""" abstract type Geometry end +""" + get_tree(geo::Geometry) +""" function get_tree(geo::Geometry) @abstractmethod end +""" + similar_geometry(a::Geometry,tree::Node) +""" function similar_geometry(a::Geometry,tree::Node) @abstractmethod end +""" + compatible_geometries(a::Geometry,b::Geometry) +""" function compatible_geometries(a::Geometry,b::Geometry) @abstractmethod end @@ -51,24 +72,36 @@ function _replace_metadata(tree::Leaf,meta) Leaf(data) end +""" + Base.union(a::Geometry,b::Geometry;name::String="",meta=nothing) +""" function Base.union(a::Geometry,b::Geometry;name::String="",meta=nothing) _a, _b = compatible_geometries(a,b) tree = union(get_tree(_a),get_tree(_b),name,meta) similar_geometry(_a,tree) end +""" + Base.intersect(a::Geometry,b::Geometry;name::String="",meta=nothing) +""" function Base.intersect(a::Geometry,b::Geometry;name::String="",meta=nothing) _a, _b = compatible_geometries(a,b) tree = intersect(get_tree(_a),get_tree(_b),name,meta) similar_geometry(_a,tree) end +""" + Base.setdiff(a::Geometry,b::Geometry;name::String="",meta=nothing) +""" function Base.setdiff(a::Geometry,b::Geometry;name::String="",meta=nothing) _a, _b = compatible_geometries(a,b) tree = setdiff(get_tree(_a),get_tree(_b),name,meta) similar_geometry(_a,tree) end +""" + Base.:!(a::Geometry;name::String="",meta=nothing) +""" function Base.:!(a::Geometry;name::String="",meta=nothing) tree = !(get_tree(a),name,meta) similar_geometry(a,tree) @@ -119,5 +152,3 @@ function get_geometry_node(a::Node,name::String) end @unreachable "There is no entity called $name" end - - diff --git a/src/Interfaces/EmbeddedDiscretizations.jl b/src/Interfaces/EmbeddedDiscretizations.jl index 95b6ccc2..82c9486b 100644 --- a/src/Interfaces/EmbeddedDiscretizations.jl +++ b/src/Interfaces/EmbeddedDiscretizations.jl @@ -258,6 +258,15 @@ end """ Triangulation(cut::EmbeddedDiscretization[,in_or_out=PHYSICAL_IN]) + +Creates a triangulation containing the cell and subcells of the embedded domain selected by +`in_or_out`. + +- If only background cells are selected, the result will be a regular Gridap triangulation. +- If only subcells are selected, the result will be a [`SubCellTriangulation`](@ref). +- If both background cells and subcells are selected, the result will be an `AppendedTriangulation`, + containing a [`SubCellTriangulation`](@ref) and a regular Gridap triangulation. + """ function Triangulation(cut::EmbeddedDiscretization,in_or_out) Triangulation(cut,in_or_out,cut.geo) @@ -392,6 +401,9 @@ end """ EmbeddedBoundary(cut::EmbeddedDiscretization) + +Creates a triangulation containing the cut facets of the embedded domain boundary. +The result is a [`SubFacetTriangulation`](@ref). """ function EmbeddedBoundary(cut::EmbeddedDiscretization) EmbeddedBoundary(cut,cut.geo) @@ -419,7 +431,6 @@ function EmbeddedBoundary(cut::EmbeddedDiscretization,geo::CSG.Geometry) neworientation = orientation[newsubfacets] fst = SubFacetData(cut.subfacets,newsubfacets,neworientation) SubFacetTriangulation(fst,cut.bgmodel) - end function EmbeddedBoundary(cut::EmbeddedDiscretization,name1::String,name2::String) @@ -449,11 +460,15 @@ function EmbeddedBoundary(cut::EmbeddedDiscretization,geo1::CSG.Geometry,geo2::C neworientation = orientation[newsubfacets] fst = SubFacetData(cut.subfacets,newsubfacets,neworientation) SubFacetTriangulation(fst,cut.bgmodel) - end """ GhostSkeleton(cut::EmbeddedDiscretization[,in_or_out=ACTIVE_IN]) + +Creates a triangulation containing the ghost facets. Ghosts facets are defined as the facets +of the **background mesh** that are adjacent to at least one `CUT` background cell. + +Mostly used for CUT-FEM stabilisation. """ function GhostSkeleton(cut::EmbeddedDiscretization) GhostSkeleton(cut,ACTIVE_IN) diff --git a/src/Interfaces/SubCellTriangulations.jl b/src/Interfaces/SubCellTriangulations.jl index aa5139ce..dbcf2404 100644 --- a/src/Interfaces/SubCellTriangulations.jl +++ b/src/Interfaces/SubCellTriangulations.jl @@ -18,6 +18,11 @@ end # Implementation of Triangulation interface +""" + struct SubCellTriangulation{Dc,Dp} <: Triangulation{Dc,Dp} + +A triangulation for subcells. +""" struct SubCellTriangulation{Dc,Dp,T,A} <: Triangulation{Dc,Dp} subcells::SubCellData{Dc,Dp,T} bgmodel::A diff --git a/src/Interfaces/SubFacetTriangulations.jl b/src/Interfaces/SubFacetTriangulations.jl index cad6d6c0..3cc1bbb2 100644 --- a/src/Interfaces/SubFacetTriangulations.jl +++ b/src/Interfaces/SubFacetTriangulations.jl @@ -22,6 +22,11 @@ end # Implementation of the Gridap.Triangulation interface +""" + struct SubFacetTriangulation{Dc,Dp,T,A} <: Triangulation{Dc,Dp} + +A triangulation for subfacets. +""" struct SubFacetTriangulation{Dc,Dp,T,A} <: Triangulation{Dc,Dp} subfacets::SubFacetData{Dp,T} bgmodel::A From 42e77edea4716b88eca6ac89274d701b19fbbe24 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 18 Apr 2025 13:02:36 +1000 Subject: [PATCH 093/120] Finished documentation --- docs/make.jl | 3 ++- docs/src/Distributed.md | 12 +++++++++++ docs/src/GeometricalDerivatives.md | 33 ++++++++++++++++++++++++++++++ docs/src/Interfaces.md | 2 ++ docs/src/index.md | 1 + 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 docs/src/GeometricalDerivatives.md diff --git a/docs/make.jl b/docs/make.jl index 2c5569a6..fd3e61bc 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -7,6 +7,7 @@ pages = [ "Level Set Cutters" => "LevelSetCutters.md", "Aggregated FEM" => "AggregatedFEM.md", "Moment-Fitted Quadratures" => "MomentFittedQuadratures.md", + "Geometrical Derivatives" => "GeometricalDerivatives.md", "Distributed computing" => "Distributed.md", ] @@ -18,7 +19,7 @@ makedocs(; sitename = "GridapEmbedded.jl", authors = "Francesc Verdugo , Eric Neiva and Santiago Badia ", pages = pages, - warnonly = true, + warnonly = false, ) deploydocs(; diff --git a/docs/src/Distributed.md b/docs/src/Distributed.md index 56a17b59..740e228b 100644 --- a/docs/src/Distributed.md +++ b/docs/src/Distributed.md @@ -5,6 +5,18 @@ CurrentModule = GridapEmbedded.Distributed ``` +We support distributed computing through [GridapDistributed.jl](https://github.com/gridap/GridapDistributed.jl). As per usual, we design our libraries so that the high-level API is unchanged when using distributed computing. This means that for most users, the changes to your driver will be minimal. + +The following features are currently supported: + +- Level-Set Cutters +- STL Cutters + +The folowing features are not yet supported: + +- Aggregated FEM +- Moment-Fitted Quadratures + ```@autodocs Modules = [Distributed,] Order = [:type, :constant, :macro, :function] diff --git a/docs/src/GeometricalDerivatives.md b/docs/src/GeometricalDerivatives.md new file mode 100644 index 00000000..059e80da --- /dev/null +++ b/docs/src/GeometricalDerivatives.md @@ -0,0 +1,33 @@ +# Geometrical Derivatives + +```@meta +CurrentModule = GridapEmbedded +``` + +The geometrical differentiation capabilities are based on the following work: + +!!! note "Reference" + "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation", + by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis, CMAME (2025) + +To see examples of usage, please refer to the tests in `test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl`. + +## Discretize then differentiate + +```@autodocs +Modules = [GridapEmbedded.Interfaces] +Order = [:type, :constant, :macro, :function] +Pages = [ + "/CutFaceBoundaryTriangulations.jl", +] +``` + +## Autodiff + +```@autodocs +Modules = [GridapEmbedded.LevelSetCutters] +Order = [:type, :constant, :macro, :function] +Pages = [ + "/DifferentiableTriangulations.jl", +] +``` diff --git a/docs/src/Interfaces.md b/docs/src/Interfaces.md index dadc981a..a41c22cf 100644 --- a/docs/src/Interfaces.md +++ b/docs/src/Interfaces.md @@ -81,5 +81,7 @@ EmbeddedBoundary(::EmbeddedDiscretization) GhostSkeleton(::EmbeddedDiscretization) Gridap.Geometry.BoundaryTriangulation(::EmbeddedFacetDiscretization,::Any) Gridap.Geometry.SkeletonTriangulation(::EmbeddedFacetDiscretization,::Any) +SubCellTriangulation +SubFacetTriangulation SubFacetBoundaryTriangulation ``` diff --git a/docs/src/index.md b/docs/src/index.md index 4ba7959e..7287c762 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -13,6 +13,7 @@ Pages = [ "LevelSetCutters.md", "AggregatedFEM.md", "MomentFittedQuadratures.md", + "GeometricalDerivatives.md", "Distributed.md", ] ``` From e60324300d8e7932988a40ed3719203eaa1777b2 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 18 Apr 2025 13:04:22 +1000 Subject: [PATCH 094/120] UPdated NEWS.md --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index e01661ba..5b201d6d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for distributed level-set geometries. Since PR[#99](https://github.com/gridap/GridapEmbedded.jl/pull/99). - Refactored the distributed code to allow for ghosted/unghosted geometries and triangulations. Since PR[#100](https://github.com/gridap/GridapEmbedded.jl/pull/100). +- Implemented geometrical derivatives. Since PR[#109](https://github.com/gridap/GridapEmbedded.jl/pull/109). +- Added a proper documentation. Since PR[#109](https://github.com/gridap/GridapEmbedded.jl/pull/109). ### Changed From 11421bfe99dfa805257b8f0fd6b4f5bd6f1a9971 Mon Sep 17 00:00:00 2001 From: JordiManyer Date: Fri, 18 Apr 2025 13:08:48 +1000 Subject: [PATCH 095/120] Added documentation to the README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77d0b637..d7b3c765 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Embedded finite element methods, level set surface descriptions and constructive solid geometry. +[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://gridap.github.io/GridapEmbedded.jl/stable) [![Build Status](https://github.com/gridap/GridapEmbedded.jl/workflows/CI/badge.svg?branch=master)](https://github.com/gridap/GridapEmbedded.jl/actions?query=workflow%3ACI) [![Codecov](https://codecov.io/gh/gridap/GridapEmbedded.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/gridap/GridapEmbedded.jl) @@ -40,4 +41,3 @@ julia> BimaterialLinElastCutFEM.main(n=4,outputfile="results3") ``` - From 0c59722bae54b57c1b04cd52137233a7b260e50f Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Sat, 19 Apr 2025 14:03:24 +1000 Subject: [PATCH 096/120] Updated Gridap version --- Project.toml | 4 ++-- docs/src/GeometricalDerivatives.md | 2 +- .../GeometricalDifferentiationTests.jl | 19 +------------------ 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/Project.toml b/Project.toml index a020b212..049bcc05 100644 --- a/Project.toml +++ b/Project.toml @@ -30,7 +30,7 @@ FillArrays = "0.10, 0.11, 0.12, 0.13, 1" FiniteDiff = "2.27.0" ForwardDiff = "0.10.38" Graphs = "1.12.0" -Gridap = "0.17, 0.18" +Gridap = "0.18.12" GridapDistributed = "0.3, 0.4" MPI = "0.20" MiniQhull = "0.1.0, 0.2, 0.3, 0.4" @@ -42,4 +42,4 @@ FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Test","FiniteDiff"] +test = ["Test", "FiniteDiff"] diff --git a/docs/src/GeometricalDerivatives.md b/docs/src/GeometricalDerivatives.md index 059e80da..82298b40 100644 --- a/docs/src/GeometricalDerivatives.md +++ b/docs/src/GeometricalDerivatives.md @@ -8,7 +8,7 @@ The geometrical differentiation capabilities are based on the following work: !!! note "Reference" "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation", - by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis, CMAME (2025) + by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis (2025) To see examples of usage, please refer to the tests in `test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl`. diff --git a/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl b/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl index 721f4623..8a90387f 100644 --- a/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl +++ b/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl @@ -4,7 +4,7 @@ module GeometricalDifferentiationTests # level set defining the cut domain. # They are based on the following work: # "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation" -# by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis, CMAME (2025) +# by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis (2025) ############################################################################################ using Test, FiniteDiff @@ -17,23 +17,6 @@ using GridapEmbedded.Interfaces: get_ghost_normal_vector using GridapEmbedded.LevelSetCutters: DifferentiableTriangulation - -using Gridap.Fields, Gridap.Polynomials -function Arrays.return_cache( - fg::Fields.FieldGradientArray{1,Polynomials.MonomialBasis{D,V}}, - x::AbstractVector{<:Point}) where {D,V} - xi = testitem(x) - T = gradient_type(V,xi) - Polynomials._return_cache(fg,x,T,Val(false)) -end - -function Arrays.evaluate!( - cache, - fg::Fields.FieldGradientArray{1,Polynomials.MonomialBasis{D,V}}, - x::AbstractVector{<:Point}) where {D,V} - Polynomials._evaluate!(cache,fg,x,Val(false)) -end - # We general a simplicial model where the simplices are created in a symmetric way using # varycentric refinement of QUADs and HEXs. function generate_model(D,n) From 471264157844765fb78315c258a72596f9d20039 Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Sat, 19 Apr 2025 14:06:03 +1000 Subject: [PATCH 097/120] Bumped version --- NEWS.md | 2 +- Project.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5b201d6d..7cfea949 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,7 +4,7 @@ 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). -## [Unreleased] +## [0.9.6] - 2025-04-19 ### Added diff --git a/Project.toml b/Project.toml index 049bcc05..f7dc5034 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GridapEmbedded" uuid = "8838a6a3-0006-4405-b874-385995508d5d" authors = ["Francesc Verdugo ", "Eric Neiva ", "Pere Antoni Martorell ", "Santiago Badia "] -version = "0.9.5" +version = "0.9.6" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" From 86da7ef5b50915d81fe6c4448959b6a49525fb5c Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Sat, 19 Apr 2025 15:01:20 +1000 Subject: [PATCH 098/120] Added distributed implementation and tests --- src/Distributed/Distributed.jl | 10 + src/Distributed/DistributedDiscretizations.jl | 6 + src/Distributed/GeometricalDerivatives.jl | 56 ++++ .../CutFaceBoundaryTriangulations.jl | 23 -- .../DifferentiableTriangulations.jl | 43 +-- .../GeometricalDifferentiationTests.jl | 281 ++++++++++++++++++ test/DistributedTests/mpi/runtests_body.jl | 2 + 7 files changed, 358 insertions(+), 63 deletions(-) create mode 100644 src/Distributed/GeometricalDerivatives.jl create mode 100644 test/DistributedTests/GeometricalDifferentiationTests.jl diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index b4cf0b8e..89816e94 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -23,9 +23,14 @@ using GridapEmbedded.Interfaces: SubFacetTriangulation using GridapEmbedded.Interfaces: SubCellData using GridapEmbedded.Interfaces: SubFacetData using GridapEmbedded.Interfaces: AbstractEmbeddedDiscretization +using GridapEmbedded.Interfaces: CutFaceBoundaryTriangulation +using GridapEmbedded.Interfaces: CutFaceSkeletonTriangulation using GridapEmbedded.AgFEM: _touch_aggregated_cells! using GridapEmbedded.AgFEM: AggregateCutCellsByThreshold using GridapEmbedded.MomentFittedQuadratures: MomentFitted +using GridapEmbedded.LevelSetCutters: DifferentiableTriangulation +using GridapEmbedded.LevelSetCutters: DifferentiableAppendedTriangulation +using GridapEmbedded.LevelSetCutters: DifferentiableTriangulationView using Gridap.Geometry: AppendedTriangulation, TriangulationView using Gridap.Geometry: get_face_to_parent_face using Gridap.Arrays: find_inverse_index_map, testitem, return_type @@ -34,6 +39,7 @@ using Gridap.FESpaces: _dof_to_DOF, _DOF_to_dof using GridapDistributed: DistributedDiscreteModel, DistributedTriangulation, DistributedMeasure using GridapDistributed: DistributedFESpace, DistributedSingleFieldFESpace +using GridapDistributed: DistributedCellField, DistributedMultiFieldCellField using GridapDistributed: NoGhost, WithGhost, filter_cells_when_needed, add_ghost_cells using GridapDistributed: generate_gids, generate_cell_gids using GridapDistributed: _find_vector_type @@ -46,12 +52,14 @@ import GridapEmbedded.Interfaces: EmbeddedBoundary import GridapEmbedded.Interfaces: compute_bgfacet_to_inoutcut import GridapEmbedded.Interfaces: compute_bgcell_to_inoutcut import GridapEmbedded.Interfaces: GhostSkeleton +import GridapEmbedded.Interfaces: get_subfacet_normal_vector, get_ghost_normal_vector, get_conormal_vector import GridapEmbedded.CSG: get_geometry import GridapEmbedded.LevelSetCutters: discretize, DiscreteGeometry import Gridap.Geometry: Triangulation import Gridap.Geometry: SkeletonTriangulation import Gridap.Geometry: BoundaryTriangulation import Gridap.Geometry: get_background_model +import Gridap.CellData: get_tangent_vector import GridapDistributed: local_views import GridapDistributed: remove_ghost_cells @@ -65,4 +73,6 @@ include("DistributedAgFEM.jl") include("DistributedQuadratures.jl") +include("GeometricalDerivatives.jl") + end # module diff --git a/src/Distributed/DistributedDiscretizations.jl b/src/Distributed/DistributedDiscretizations.jl index 5d873558..c8939060 100644 --- a/src/Distributed/DistributedDiscretizations.jl +++ b/src/Distributed/DistributedDiscretizations.jl @@ -88,6 +88,12 @@ for TT in (:Triangulation,:SkeletonTriangulation,:BoundaryTriangulation,:Embedde end end +# TODO: This should go to GridapDistributed +function get_tangent_vector(a::DistributedTriangulation) + fields = map(get_tangent_vector,local_views(a)) + DistributedCellField(fields,a) +end + # TODO: This should go to GridapDistributed function remove_ghost_cells(trian::AppendedTriangulation,gids) a = remove_ghost_cells(trian.a,gids) diff --git a/src/Distributed/GeometricalDerivatives.jl b/src/Distributed/GeometricalDerivatives.jl new file mode 100644 index 00000000..d6450be5 --- /dev/null +++ b/src/Distributed/GeometricalDerivatives.jl @@ -0,0 +1,56 @@ + + +function remove_ghost_cells( + trian::Union{<:CutFaceBoundaryTriangulation,<:CutFaceSkeletonTriangulation},gids +) + model = get_background_model(trian) + Dm = num_cell_dims(model) + glue = get_glue(trian,Val(Dm)) + remove_ghost_cells(glue,trian,gids) +end + +for func in (:get_subfacet_normal_vector,:get_ghost_normal_vector,:get_conormal_vector) + @eval begin + function $func(a::DistributedTriangulation) + fields = map($func,local_views(a)) + DistributedCellField(fields,a) + end + end +end + +function LevelSetCutters.DifferentiableTriangulation(trian::DistributedTriangulation,fe_space) + model = get_background_model(trian) + trians = map(DifferentiableTriangulation,local_views(trian),local_views(fe_space)) + return DistributedTriangulation(trians,model) +end + +function FESpaces._change_argument( + op,f, + local_trians::AbstractArray{<:Union{<:DifferentiableTriangulation,<:DifferentiableAppendedTriangulation,<:DifferentiableTriangulationView}}, + uh::GridapDistributed.DistributedADTypes +) + function dist_cf(uh::DistributedCellField,cfs) + DistributedCellField(cfs,get_triangulation(uh)) + end + function dist_cf(uh::DistributedMultiFieldCellField,cfs) + sf_cfs = map(DistributedCellField, + [tuple_of_arrays(map(cf -> Tuple(cf.single_fields),cfs))...], + map(get_triangulation,uh) + ) + DistributedMultiFieldCellField(sf_cfs,cfs) + end + + uhs = local_views(uh) + spaces = map(get_fe_space,uhs) + function g(cell_u) + cfs = map(CellField,spaces,cell_u) + cf = dist_cf(uh,cfs) + map(update_trian!,local_trians,spaces,local_views(cf)) + cg = f(cf) + map(local_trians,spaces) do Ω, V + update_trian!(Ω,V,nothing) + end + map(get_contribution,local_views(cg),local_trians) + end + g +end diff --git a/src/Interfaces/CutFaceBoundaryTriangulations.jl b/src/Interfaces/CutFaceBoundaryTriangulations.jl index e85e70cc..63f7b2ca 100644 --- a/src/Interfaces/CutFaceBoundaryTriangulations.jl +++ b/src/Interfaces/CutFaceBoundaryTriangulations.jl @@ -393,29 +393,6 @@ for func in (:get_tangent_vector,:get_subfacet_normal_vector,:get_ghost_normal_v end end -# Distributed -# Until we merge, we need changes in -# - GridapDistributed#master -# - GridapEmbedded#distributed - -# function GridapDistributed.remove_ghost_cells( -# trian::Union{<:CutFaceBoundaryTriangulation,<:CutFaceSkeletonTriangulation},gids -# ) -# model = get_background_model(trian) -# Dm = num_cell_dims(model) -# glue = get_glue(trian,Val(Dm)) -# GridapDistributed.remove_ghost_cells(glue,trian,gids) -# end -# -# for func in (:get_subfacet_normal_vector,:get_ghost_normal_vector,:get_conormal_vector,:get_tangent_vector) -# @eval begin -# function $func(a::DistributedTriangulation) -# fields = map($func,local_views(a)) -# DistributedCellField(fields,a) -# end -# end -# end - ############################################################################################ # This will go to Gridap diff --git a/src/LevelSetCutters/DifferentiableTriangulations.jl b/src/LevelSetCutters/DifferentiableTriangulations.jl index 74e39dbe..af6baa97 100644 --- a/src/LevelSetCutters/DifferentiableTriangulations.jl +++ b/src/LevelSetCutters/DifferentiableTriangulations.jl @@ -473,6 +473,8 @@ end # This is mostly used in distributed, where we remove ghost cells by taking a view # of the local triangulations. +const DifferentiableTriangulationView{Dc,Dp} = Geometry.TriangulationView{Dc,Dp,<:Union{<:DifferentiableTriangulation,<:DifferentiableAppendedTriangulation}} + function DifferentiableTriangulation( trian :: Geometry.TriangulationView, fe_space :: FESpace @@ -487,7 +489,7 @@ function update_trian!(trian::Geometry.TriangulationView,U,φh) end function FESpaces._change_argument( - op,f,trian::Geometry.TriangulationView,uh + op,f,trian::DifferentiableTriangulationView,uh ) U = get_fe_space(uh) function g(cell_u) @@ -499,42 +501,3 @@ function FESpaces._change_argument( end g end - -#### DistributedTriangulations - -# function DifferentiableTriangulation(trian::DistributedTriangulation,fe_space) -# model = get_background_model(trian) -# trians = map(DifferentiableTriangulation,local_views(trian),local_views(fe_space)) -# return DistributedTriangulation(trians,model) -# end -# -# function FESpaces._change_argument( -# op,f, -# local_trians::AbstractArray{<:Union{<:DifferentiableTriangulation,<:DifferentiableAppendedTriangulation,<:TriangulationView}}, -# uh::GridapDistributed.DistributedADTypes -# ) -# function dist_cf(uh::DistributedCellField,cfs) -# DistributedCellField(cfs,get_triangulation(uh)) -# end -# function dist_cf(uh::DistributedMultiFieldCellField,cfs) -# sf_cfs = map(DistributedCellField, -# [tuple_of_arrays(map(cf -> Tuple(cf.single_fields),cfs))...], -# map(get_triangulation,uh) -# ) -# DistributedMultiFieldCellField(sf_cfs,cfs) -# end -# -# uhs = local_views(uh) -# spaces = map(get_fe_space,uhs) -# function g(cell_u) -# cfs = map(CellField,spaces,cell_u) -# cf = dist_cf(uh,cfs) -# map(update_trian!,local_trians,spaces,local_views(cf)) -# cg = f(cf) -# map(local_trians,spaces) do Ω, V -# update_trian!(Ω,V,nothing) -# end -# map(get_contribution,local_views(cg),local_trians) -# end -# g -# end diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl new file mode 100644 index 00000000..2eebf1e8 --- /dev/null +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -0,0 +1,281 @@ +module DistributedGeometricalDifferentitationTests +############################################################################################ +# These tests are meant to verify the correctness differentiation of functionals w.r.t the +# level set defining the cut domain. +# They are based on the following work: +# "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation" +# by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis (2025) +############################################################################################ +using Test + +using Gridap, Gridap.Geometry, Gridap.Adaptivity +using GridapEmbedded, GridapEmbedded.Interfaces, GridapEmbedded.LevelSetCutters + +using GridapDistributed, PartitionedArrays + +using Gridap.Arrays: Operation +using GridapTopOpt: get_conormal_vector,get_subfacet_normal_vector,get_ghost_normal_vector + +function generate_model(D,n,ranks,mesh_partition) + domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) + cell_partition = (D==2) ? (n,n) : (n,n,n) + base_model = UnstructuredDiscreteModel(CartesianDiscreteModel(ranks,mesh_partition,domain,cell_partition)) + ref_model = refine(base_model, refinement_method = "barycentric") + model = Adaptivity.get_model(ref_model) + return model +end + +function level_set(shape::Symbol;N=4) + if shape == :square + x -> max(abs(x[1]-0.5),abs(x[2]-0.5))-0.25 # Square + elseif shape == :corner_2d + x -> ((x[1]-0.5)^N+(x[2]-0.5)^N)^(1/N)-0.25 # Curved corner + elseif shape == :diamond + x -> abs(x[1]-0.5)+abs(x[2]-0.5)-0.25-0/n/10 # Diamond + elseif shape == :circle + x -> sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.5223 # Circle + elseif shape == :circle_2 + x -> sqrt((x[1]-0.5)^2+(x[2]-0.5)^2)-0.23 # Circle + elseif shape == :square_prism + x -> max(abs(x[1]-0.5),abs(x[2]-0.5),abs(x[3]-0.5))-0.25 # Square prism + elseif shape == :corner_3d + x -> ((x[1]-0.5)^N+(x[2]-0.5)^N+(x[3]-0.5)^N)^(1/N)-0.25 # Curved corner + elseif shape == :diamond_prism + x -> abs(x[1]-0.5)+abs(x[2]-0.5)+abs(x[3]-0.5)-0.25-0/n/10 # Diamond prism + elseif shape == :sphere + x -> sqrt((x[1]-0.5)^2+(x[2]-0.5)^2+(x[3]-0.5)^2)-0.53 # Sphere + elseif shape == :regular_2d + x -> cos(2π*x[1])*cos(2π*x[2])-0.11 # "Regular" LSF + elseif shape == :regular_3d + x -> cos(2π*x[1])*cos(2π*x[2])*cos(2π*x[3])-0.11 # "Regular" LSF + else + error("Unknown shape") + end +end + +function main_generic( + model,φ::Function,f::Function +) + order = 1 + reffe = ReferenceFE(lagrangian,Float64,order) + V_φ = TestFESpace(model,reffe) + + U = TestFESpace(model,reffe) + + φh = interpolate(φ,V_φ) + fh = interpolate(f,V_φ) + uh = interpolate(x->x[1]+x[2],U) + + geo = DiscreteGeometry(φh,model) + cutgeo = cut(model,geo) + + # A.1) Volume integral + + Ω = Triangulation(cutgeo,PHYSICAL_IN) + Ω_AD = DifferentiableTriangulation(Ω,V_φ) + dΩ = Measure(Ω_AD,2*order) + + Γ = EmbeddedBoundary(cutgeo) + n_Γ = get_normal_vector(Γ) + dΓ = Measure(Γ,2*order) + + J_bulk(φ) = ∫(fh)dΩ + dJ_bulk_AD = gradient(J_bulk,φh) + dJ_bulk_AD_vec = assemble_vector(dJ_bulk_AD,V_φ) + + dJ_bulk_exact(q) = ∫(-fh*q/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJ_bulk_exact_vec = assemble_vector(dJ_bulk_exact,V_φ) + + @test norm(dJ_bulk_AD_vec - dJ_bulk_exact_vec) < 1e-10 + + # A.1.1) Volume integral with another field + + J_bulk_1(u,φ) = ∫(u+fh)dΩ + dJ_bulk_1_AD = gradient(φ->J_bulk_1(uh,φ),φh) + dJ_bulk_1_AD_vec = assemble_vector(dJ_bulk_1_AD,V_φ) + + dJ_bulk_1_exact(q,u) = ∫(-(u+fh)*q/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJ_bulk_1_exact_vec = assemble_vector(q->dJ_bulk_1_exact(q,uh),V_φ) + + @test norm(dJ_bulk_1_AD_vec - dJ_bulk_1_exact_vec) < 1e-10 + + J_bulk_1(u,φ) = ∫(u+fh)dΩ + dJ_bulk_1_AD_in_u = gradient(u->J_bulk_1(u,φh),uh) + dJ_bulk_1_AD_in_u_vec = assemble_vector(dJ_bulk_1_AD_in_u,U) + + dJ_bulk_1_exact_in_u(q,u) = ∫(q)dΩ + dJ_bulk_1_exact_in_u_vec = assemble_vector(q->dJ_bulk_1_exact_in_u(q,uh),U) + + @test norm(dJ_bulk_1_AD_in_u_vec - dJ_bulk_1_exact_in_u_vec) < 1e-10 + + # A.2) Volume integral + + g(fh) = ∇(fh)⋅∇(fh) + J_bulk2(φ) = ∫(g(fh))dΩ + dJ_bulk_AD2 = gradient(J_bulk2,φh) + dJ_bulk_AD_vec2 = assemble_vector(dJ_bulk_AD2,V_φ) + + dJ_bulk_exact2(q) = ∫(-g(fh)*q/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJ_bulk_exact_vec2 = assemble_vector(dJ_bulk_exact2,V_φ) + + @test norm(dJ_bulk_AD_vec2 - dJ_bulk_exact_vec2) < 1e-10 + + # B.1) Facet integral + + Γ = EmbeddedBoundary(cutgeo) + n_Γ = get_normal_vector(Γ) + Γ_AD = DifferentiableTriangulation(Γ,V_φ) + Λ = Skeleton(Γ) + Σ = Boundary(Γ) + + dΓ = Measure(Γ,2*order) + dΛ = Measure(Λ,2*order) + dΣ = Measure(Σ,2*order) + + n_Γ = get_normal_vector(Γ) + + n_S_Λ = get_normal_vector(Λ) + m_k_Λ = get_conormal_vector(Λ) + ∇ˢφ_Λ = Operation(abs)(n_S_Λ ⋅ ∇(φh).plus) + + n_S_Σ = get_normal_vector(Σ) + m_k_Σ = get_conormal_vector(Σ) + ∇ˢφ_Σ = Operation(abs)(n_S_Σ ⋅ ∇(φh)) + + dΓ_AD = Measure(Γ_AD,2*order) + J_int(φ) = ∫(fh)dΓ_AD + dJ_int_AD = gradient(J_int,φh) + dJ_int_AD_vec = assemble_vector(dJ_int_AD,V_φ) + + dJ_int_exact(w) = ∫((-n_Γ⋅∇(fh))*w/(abs(n_Γ ⋅ ∇(φh))))dΓ + + ∫(-n_S_Λ ⋅ (jump(fh*m_k_Λ) * mean(w) / ∇ˢφ_Λ))dΛ + + ∫(-n_S_Σ ⋅ (fh*m_k_Σ * w / ∇ˢφ_Σ))dΣ + dJ_int_exact_vec = assemble_vector(dJ_int_exact,V_φ) + + @test norm(dJ_int_AD_vec - dJ_int_exact_vec) < 1e-10 + + # B.2) Facet integral + g(fh) = ∇(fh)⋅∇(fh) + + J_int2(φ) = ∫(g(fh))dΓ_AD + dJ_int_AD2 = gradient(J_int2,φh) + dJ_int_AD_vec2 = assemble_vector(dJ_int_AD2,V_φ) + + ∇g(∇∇f,∇f) = ∇∇f⋅∇f + ∇f⋅∇∇f + dJ_int_exact2(w) = ∫((-n_Γ⋅ (∇g ∘ (∇∇(fh),∇(fh))))*w/(abs(n_Γ ⋅ ∇(φh))))dΓ + + ∫(-n_S_Λ ⋅ (jump(g(fh)*m_k_Λ) * mean(w) / ∇ˢφ_Λ))dΛ + + ∫(-n_S_Σ ⋅ (g(fh)*m_k_Σ * w / ∇ˢφ_Σ))dΣ + dJ_int_exact_vec2 = assemble_vector(dJ_int_exact2,V_φ) + + @test norm(dJ_int_AD_vec2 - dJ_int_exact_vec2) < 1e-10 + +end + +## Concering integrals of the form `φ->∫(f ⋅ n(φ))dΓ(φ)` +function main_normal( + model,φ::Function,f::Function; + vtk=false, + name="embedded", + run_test=true +) + order = 1 + reffe = ReferenceFE(lagrangian,Float64,order) + V_φ = TestFESpace(model,reffe) + + φh = interpolate(φ,V_φ) + + geo = DiscreteGeometry(φh,model) + cutgeo = cut(model,geo) + + Γ = EmbeddedBoundary(cutgeo) + n_Γ = get_normal_vector(Γ) + Γ_AD = DifferentiableTriangulation(Γ,V_φ) + dΓ_AD = Measure(Γ_AD,2*order) + dΓ = Measure(Γ,2*order) + + fh_Γ = CellField(f,Γ) + fh_Γ_AD = CellField(f,Γ_AD) + + function J_int(φ) + n = get_normal_vector(Γ_AD) + ∫(fh_Γ_AD⋅n)dΓ_AD + end + dJ_int_AD = gradient(J_int,φh) + dJ_int_AD_vec = assemble_vector(dJ_int_AD,V_φ) + + _n(∇φ) = ∇φ/(10^-20+norm(∇φ)) + dJ_int_phi = ∇(φ->∫(fh_Γ_AD ⋅ (_n ∘ (∇(φ))))dΓ_AD,φh) + dJh_int_phi = assemble_vector(dJ_int_phi,V_φ) + + run_test && @test norm(dJ_int_AD_vec - dJh_int_phi) < 1e-10 + + # Analytic + # Note: currently, the analytic result is only valid on closed domains thanks + # to the divergence theorem. I think it would take significant work to compute + # the analytic derivative generally as we can't rely on divergence theorem to + # rewrite it in a convenient way. As a result, we don't have an analytic result + # for general cases such as ∫( f(n(φ)) )dΓ(φ), nor the case when Γ intersects + # ∂D. Thankfully, we have AD instead ;) + # Note 2: For the case that Γ does intersect the surface, the result is correct + # everywhere except on the intersection. + + fh2(x) = VectorValue((1-x[1])^2,(1-x[2])^2) + fh_Γ = CellField(fh2,Γ) + fh_Γ_AD = CellField(fh2,Γ_AD) + + # Note: this comes from rewriting via the divergence theorem: + # ∫(f ⋅ n(φ))dΓ(φ) = ∫(∇⋅f)dΩ(φ) + dJ_int_exact3(w) = ∫(-(∇⋅(fh_Γ))*w/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJh_int_exact3 = assemble_vector(dJ_int_exact3,V_φ) + + run_test && @test norm(dJh_int_exact3 - dJ_int_AD_vec) < 1e-10 + + if vtk + path = "results/$(name)" + Ω_bg = Triangulation(model) + writevtk(Ω_bg,path,cellfields=[ + "dJ_AD"=>FEFunction(V_φ,dJ_int_AD_vec), + "dJ_AD_with_phi"=>FEFunction(V_φ,dJh_int_phi), + "dJ_exact"=>FEFunction(V_φ,dJh_int_exact3) + ]) + end +end + +####################### + +function main(distribute,np) + @assert np == 4 + + # 2D + mesh_partition = (2,2) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + D = 2 + n = 10 + model = generate_model(D,n,ranks,mesh_partition) + + φ0 = level_set(:circle_2) + f0((x,y)) = VectorValue((1-x)^2,(1-y)^2) + main_normal(model,φ0,f0;vtk=true) + + φ1 = level_set(:circle) + f1 = x -> 1.0 + main_generic(model,φ1,f1) + + model = generate_model(D,n,ranks,mesh_partition) + φ2 = level_set(:circle) + f2 = x -> x[1]+x[2] + main_generic(model,φ2,f2) + + # 3D + mesh_partition = (2,2,1) + ranks = distribute(LinearIndices((prod(mesh_partition),))) + D = 3 + n = 8 + model = generate_model(D,n,ranks,mesh_partition) + + φ3 = level_set(:regular_3d) + f3 = x -> x[1]+x[2] + main_generic(model,φ3,f3) +end + +end \ No newline at end of file diff --git a/test/DistributedTests/mpi/runtests_body.jl b/test/DistributedTests/mpi/runtests_body.jl index d0510c01..ddce7ee4 100644 --- a/test/DistributedTests/mpi/runtests_body.jl +++ b/test/DistributedTests/mpi/runtests_body.jl @@ -9,6 +9,7 @@ include("../AggregatesTests.jl") include("../DistributedDiscreteGeometryPoissonTest.jl") include("../DistributedLSDiscreteGeometryPoissonTest.jl") include("../PeriodicDistributedDiscreteGeometryPoissonTest.jl") +include("../GeometricalDifferentiationTests.jl") if ! MPI.Initialized() MPI.Init() @@ -41,6 +42,7 @@ function all_tests(distribute,parts) if prod(parts) == 4 DistributedAggregatesTests.main(distribute,parts) + DistributedGeometricalDifferentitationTests.main(distribute,4) end PArrays.toc!(t,"Aggregates") From 23bea0d1f0ba51b9135a4dbd3c1019236791a927 Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Sat, 19 Apr 2025 15:27:28 +1000 Subject: [PATCH 099/120] Minor --- test/DistributedTests/GeometricalDifferentiationTests.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index 2eebf1e8..30b6c506 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -14,7 +14,8 @@ using GridapEmbedded, GridapEmbedded.Interfaces, GridapEmbedded.LevelSetCutters using GridapDistributed, PartitionedArrays using Gridap.Arrays: Operation -using GridapTopOpt: get_conormal_vector,get_subfacet_normal_vector,get_ghost_normal_vector +using Gridap.CellData: get_tangent_vector, get_normal_vector +using GridapEmbedded.Interfaces: get_conormal_vector, get_subfacet_normal_vector, get_ghost_normal_vector function generate_model(D,n,ranks,mesh_partition) domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) From 224d06beeef5b1bb545645a0b0348ed6428d3d57 Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Sat, 19 Apr 2025 16:10:46 +1000 Subject: [PATCH 100/120] Minor --- test/DistributedTests/GeometricalDifferentiationTests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index 30b6c506..4e4dbe91 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -17,6 +17,8 @@ using Gridap.Arrays: Operation using Gridap.CellData: get_tangent_vector, get_normal_vector using GridapEmbedded.Interfaces: get_conormal_vector, get_subfacet_normal_vector, get_ghost_normal_vector +using GridapEmbedded.LevelSetCutters: DifferentiableTriangulation + function generate_model(D,n,ranks,mesh_partition) domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) cell_partition = (D==2) ? (n,n) : (n,n,n) From f89f6be040c54355c0beffb6754df3c9e03b4558 Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Sat, 19 Apr 2025 17:37:31 +1000 Subject: [PATCH 101/120] Minor --- src/Distributed/Distributed.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index 89816e94..44ec7802 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -31,6 +31,7 @@ using GridapEmbedded.MomentFittedQuadratures: MomentFitted using GridapEmbedded.LevelSetCutters: DifferentiableTriangulation using GridapEmbedded.LevelSetCutters: DifferentiableAppendedTriangulation using GridapEmbedded.LevelSetCutters: DifferentiableTriangulationView +using GridapEmbedded.LevelSetCutters: update_trian! using Gridap.Geometry: AppendedTriangulation, TriangulationView using Gridap.Geometry: get_face_to_parent_face using Gridap.Arrays: find_inverse_index_map, testitem, return_type From 2e20ac5b166f64ba86e2f2444994d38162a79535 Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Fri, 2 May 2025 17:32:58 +1000 Subject: [PATCH 102/120] Bugfixes --- .gitignore | 1 + Project.toml | 35 +++++----- src/Distributed/Distributed.jl | 1 + .../DistributedSubFacetTriangulations.jl | 19 +++++ .../DifferentiableTriangulations.jl | 69 ++++++++++--------- .../GeometricalDifferentiationTests.jl | 26 ++++--- 6 files changed, 89 insertions(+), 62 deletions(-) diff --git a/.gitignore b/.gitignore index 97dd38a8..1c9b9a66 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ /docs/build/ /docs/site/ Manifest.toml +LocalPreferences.toml .vscode/ *.swp diff --git a/Project.toml b/Project.toml index f7dc5034..8bb35cc1 100644 --- a/Project.toml +++ b/Project.toml @@ -1,8 +1,24 @@ +authors = ["Francesc Verdugo ", "Eric Neiva ", "Pere Antoni Martorell ", "Santiago Badia "] name = "GridapEmbedded" uuid = "8838a6a3-0006-4405-b874-385995508d5d" -authors = ["Francesc Verdugo ", "Eric Neiva ", "Pere Antoni Martorell ", "Santiago Badia "] version = "0.9.6" +[compat] +AbstractTrees = "0.3.3, 0.4" +Algoim = "0.2.2" +Combinatorics = "1" +CxxWrap = "0.16" +FillArrays = "0.10, 0.11, 0.12, 0.13, 1" +FiniteDiff = "2.27.0" +ForwardDiff = "0.10.38, 1" +Graphs = "1.12.0" +Gridap = "0.18.12" +GridapDistributed = "0.3, 0.4" +MPI = "0.20" +MiniQhull = "0.1.0, 0.2, 0.3, 0.4" +PartitionedArrays = "0.3.4" +julia = "1.3" + [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" Algoim = "0eb9048c-21de-4c7a-bfac-056de1940b74" @@ -21,24 +37,9 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" algoimWrapper_jll = "3c43aa7b-5398-51f3-8d75-8f051e6faa4d" -[compat] -AbstractTrees = "0.3.3, 0.4" -Algoim = "0.2.2" -Combinatorics = "1" -CxxWrap = "0.16" -FillArrays = "0.10, 0.11, 0.12, 0.13, 1" -FiniteDiff = "2.27.0" -ForwardDiff = "0.10.38" -Graphs = "1.12.0" -Gridap = "0.18.12" -GridapDistributed = "0.3, 0.4" -MPI = "0.20" -MiniQhull = "0.1.0, 0.2, 0.3, 0.4" -PartitionedArrays = "0.3.4" -julia = "1.3" - [extras] FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" +MPIPreferences = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index 44ec7802..97d6e7ba 100644 --- a/src/Distributed/Distributed.jl +++ b/src/Distributed/Distributed.jl @@ -60,6 +60,7 @@ import Gridap.Geometry: Triangulation import Gridap.Geometry: SkeletonTriangulation import Gridap.Geometry: BoundaryTriangulation import Gridap.Geometry: get_background_model +import Gridap.Geometry: num_cells import Gridap.CellData: get_tangent_vector import GridapDistributed: local_views import GridapDistributed: remove_ghost_cells diff --git a/src/Distributed/DistributedSubFacetTriangulations.jl b/src/Distributed/DistributedSubFacetTriangulations.jl index d47c3501..b9ffaa46 100644 --- a/src/Distributed/DistributedSubFacetTriangulations.jl +++ b/src/Distributed/DistributedSubFacetTriangulations.jl @@ -61,3 +61,22 @@ function GridapDistributed.add_ghost_cells( end return ghosted_trian end + +function num_cells(trian::DistributedSubFacetTriangulation) + model = get_background_model(trian) + Dc = num_cell_dims(model) + gids = get_face_gids(model,Dc) + n_loc_ocells = map(local_views(trian),partition(gids)) do trian, gids + glue = get_glue(trian,Val(Dc)) + @assert isa(glue,FaceToFaceGlue) + tcell_to_mcell = glue.tface_to_mface + if isa(tcell_to_mcell,IdentityVector) + own_length(gids) + else + mcell_to_owned = local_to_own(gids) + is_owned(mcell) = !iszero(mcell_to_owned[mcell]) + sum(is_owned,tcell_to_mcell;init=0) + end + end + return sum(n_loc_ocells) +end diff --git a/src/LevelSetCutters/DifferentiableTriangulations.jl b/src/LevelSetCutters/DifferentiableTriangulations.jl index af6baa97..19ef9238 100644 --- a/src/LevelSetCutters/DifferentiableTriangulations.jl +++ b/src/LevelSetCutters/DifferentiableTriangulations.jl @@ -423,6 +423,39 @@ function extract_dualized_cell_values( return bgcell_to_values end +# TriangulationView +# This is mostly used in distributed, where we remove ghost cells by taking a view +# of the local triangulations. + +const DifferentiableTriangulationView{Dc,Dp} = Geometry.TriangulationView{Dc,Dp,<:DifferentiableTriangulation} + +function DifferentiableTriangulation( + trian :: Geometry.TriangulationView, + fe_space :: FESpace +) + parent = DifferentiableTriangulation(trian.parent,fe_space) + return Geometry.TriangulationView(parent,trian.cell_to_parent_cell) +end + +function update_trian!(trian::Geometry.TriangulationView,U,φh) + update_trian!(trian.parent,U,φh) + return trian +end + +function FESpaces._change_argument( + op,f,trian::DifferentiableTriangulationView,uh +) + U = get_fe_space(uh) + function g(cell_u) + cf = CellField(U,cell_u) + update_trian!(trian,U,cf) + cell_grad = f(cf) + update_trian!(trian,U,nothing) + get_contribution(cell_grad,trian) + end + g +end + # AppendedTriangulation # # When cutting an embedded domain, we will usually end up with an AppendedTriangulation @@ -432,7 +465,8 @@ end # We only need to propagate the dual numbers to the CUT cells, which is what the # following implementation does: -const DifferentiableAppendedTriangulation{Dc,Dp,A} = AppendedTriangulation{Dc,Dp,<:DifferentiableTriangulation} +const DifferentiableAppendedTriangulation{Dc,Dp,A} = + AppendedTriangulation{Dc,Dp,<:Union{<:DifferentiableTriangulation,<:DifferentiableTriangulationView{Dc,Dp}}} function DifferentiableTriangulation( trian::AppendedTriangulation, fe_space::FESpace @@ -468,36 +502,3 @@ function FESpaces._compute_cell_ids(uh,ttrian::AppendedTriangulation) ids_b = FESpaces._compute_cell_ids(uh,ttrian.b) lazy_append(ids_a,ids_b) end - -# TriangulationView -# This is mostly used in distributed, where we remove ghost cells by taking a view -# of the local triangulations. - -const DifferentiableTriangulationView{Dc,Dp} = Geometry.TriangulationView{Dc,Dp,<:Union{<:DifferentiableTriangulation,<:DifferentiableAppendedTriangulation}} - -function DifferentiableTriangulation( - trian :: Geometry.TriangulationView, - fe_space :: FESpace -) - parent = DifferentiableTriangulation(trian.parent,fe_space) - return Geometry.TriangulationView(parent,trian.cell_to_parent_cell) -end - -function update_trian!(trian::Geometry.TriangulationView,U,φh) - update_trian!(trian.parent,U,φh) - return trian -end - -function FESpaces._change_argument( - op,f,trian::DifferentiableTriangulationView,uh -) - U = get_fe_space(uh) - function g(cell_u) - cf = CellField(U,cell_u) - update_trian!(trian,U,cf) - cell_grad = f(cf) - update_trian!(trian,U,nothing) - get_contribution(cell_grad,trian) - end - g -end diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index 4e4dbe91..a1739e72 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -18,6 +18,7 @@ using Gridap.CellData: get_tangent_vector, get_normal_vector using GridapEmbedded.Interfaces: get_conormal_vector, get_subfacet_normal_vector, get_ghost_normal_vector using GridapEmbedded.LevelSetCutters: DifferentiableTriangulation +using GridapDistributed: i_am_main function generate_model(D,n,ranks,mesh_partition) domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) @@ -69,6 +70,12 @@ function main_generic( fh = interpolate(f,V_φ) uh = interpolate(x->x[1]+x[2],U) + map(partition(get_free_dof_values(φh))) do x_φ + idx = findall(isapprox(0.0;atol=10^-10),x_φ) + !isempty(idx) && @info "Correcting level values!" + x_φ[idx] .+= 100*eps(eltype(x_φ)) + end + geo = DiscreteGeometry(φh,model) cutgeo = cut(model,geo) @@ -102,7 +109,6 @@ function main_generic( @test norm(dJ_bulk_1_AD_vec - dJ_bulk_1_exact_vec) < 1e-10 - J_bulk_1(u,φ) = ∫(u+fh)dΩ dJ_bulk_1_AD_in_u = gradient(u->J_bulk_1(u,φh),uh) dJ_bulk_1_AD_in_u_vec = assemble_vector(dJ_bulk_1_AD_in_u,U) @@ -158,20 +164,19 @@ function main_generic( @test norm(dJ_int_AD_vec - dJ_int_exact_vec) < 1e-10 # B.2) Facet integral - g(fh) = ∇(fh)⋅∇(fh) - J_int2(φ) = ∫(g(fh))dΓ_AD + h(fh) = ∇(fh)⋅∇(fh) + J_int2(φ) = ∫(h(fh))dΓ_AD dJ_int_AD2 = gradient(J_int2,φh) dJ_int_AD_vec2 = assemble_vector(dJ_int_AD2,V_φ) ∇g(∇∇f,∇f) = ∇∇f⋅∇f + ∇f⋅∇∇f dJ_int_exact2(w) = ∫((-n_Γ⋅ (∇g ∘ (∇∇(fh),∇(fh))))*w/(abs(n_Γ ⋅ ∇(φh))))dΓ + - ∫(-n_S_Λ ⋅ (jump(g(fh)*m_k_Λ) * mean(w) / ∇ˢφ_Λ))dΛ + - ∫(-n_S_Σ ⋅ (g(fh)*m_k_Σ * w / ∇ˢφ_Σ))dΣ + ∫(-n_S_Λ ⋅ (jump(h(fh)*m_k_Λ) * mean(w) / ∇ˢφ_Λ))dΛ + + ∫(-n_S_Σ ⋅ (h(fh)*m_k_Σ * w / ∇ˢφ_Σ))dΣ dJ_int_exact_vec2 = assemble_vector(dJ_int_exact2,V_φ) @test norm(dJ_int_AD_vec2 - dJ_int_exact_vec2) < 1e-10 - end ## Concering integrals of the form `φ->∫(f ⋅ n(φ))dΓ(φ)` @@ -258,15 +263,14 @@ function main(distribute,np) φ0 = level_set(:circle_2) f0((x,y)) = VectorValue((1-x)^2,(1-y)^2) - main_normal(model,φ0,f0;vtk=true) + main_normal(model,φ0,f0) φ1 = level_set(:circle) - f1 = x -> 1.0 + f1(x) = 1.0 main_generic(model,φ1,f1) - model = generate_model(D,n,ranks,mesh_partition) φ2 = level_set(:circle) - f2 = x -> x[1]+x[2] + f2(x) = x[1] + x[2] main_generic(model,φ2,f2) # 3D @@ -277,7 +281,7 @@ function main(distribute,np) model = generate_model(D,n,ranks,mesh_partition) φ3 = level_set(:regular_3d) - f3 = x -> x[1]+x[2] + f3(x) = x[1] + x[2] + x[3] main_generic(model,φ3,f3) end From d5ed89efe825026072ec011f3fa10f1e7617e34d Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Sat, 3 May 2025 09:10:15 +1000 Subject: [PATCH 103/120] Minor --- .../DistributedSubFacetTriangulations.jl | 13 +++++++++++++ .../GeometricalDifferentiationTests.jl | 10 +++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Distributed/DistributedSubFacetTriangulations.jl b/src/Distributed/DistributedSubFacetTriangulations.jl index b9ffaa46..efb3e8b0 100644 --- a/src/Distributed/DistributedSubFacetTriangulations.jl +++ b/src/Distributed/DistributedSubFacetTriangulations.jl @@ -24,6 +24,19 @@ function GridapDistributed.generate_cell_gids( return PRange(fgids) end +# function GridapDistributed.generate_cell_gids( +# trian::DistributedSubFacetTriangulation{Df,Dc}, +# ) where {Df,Dc} +# model = get_background_model(trian) +# ctrians = map(local_views(trian),local_views(model)) do trian, model +# glue = get_glue(trian,Val(Dc)) # Glue from cut facets to background cells +# facet_to_bgcell = glue.tface_to_mface +# Triangulation(model,facet_to_bgcell) +# end +# ctrian = GridapDistributed.DistributedTriangulation(ctrians,model) +# return GridapDistributed.generate_cell_gids(ctrian) +# end + function GridapDistributed.add_ghost_cells( trian::DistributedSubFacetTriangulation{Df,Dc}, ) where {Df,Dc} diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index a1739e72..28a8ebc6 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -258,18 +258,21 @@ function main(distribute,np) mesh_partition = (2,2) ranks = distribute(LinearIndices((prod(mesh_partition),))) D = 2 - n = 10 + n = 12 model = generate_model(D,n,ranks,mesh_partition) + i_am_main(ranks) && println(" >> Case 0") φ0 = level_set(:circle_2) f0((x,y)) = VectorValue((1-x)^2,(1-y)^2) main_normal(model,φ0,f0) - φ1 = level_set(:circle) + i_am_main(ranks) && println(" >> Case 1") + φ1 = level_set(:circle_2) f1(x) = 1.0 main_generic(model,φ1,f1) - φ2 = level_set(:circle) + i_am_main(ranks) && println(" >> Case 2") + φ2 = level_set(:circle_2) f2(x) = x[1] + x[2] main_generic(model,φ2,f2) @@ -280,6 +283,7 @@ function main(distribute,np) n = 8 model = generate_model(D,n,ranks,mesh_partition) + i_am_main(ranks) && println(" >> Case 3") φ3 = level_set(:regular_3d) f3(x) = x[1] + x[2] + x[3] main_generic(model,φ3,f3) From bbd20ef04f1a80feaf70b0ed0c5f2736355d7a4b Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Mon, 5 May 2025 23:09:51 +1000 Subject: [PATCH 104/120] Bugfix --- .../DistributedSubFacetTriangulations.jl | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/Distributed/DistributedSubFacetTriangulations.jl b/src/Distributed/DistributedSubFacetTriangulations.jl index efb3e8b0..51c0099a 100644 --- a/src/Distributed/DistributedSubFacetTriangulations.jl +++ b/src/Distributed/DistributedSubFacetTriangulations.jl @@ -8,34 +8,33 @@ function GridapDistributed.generate_cell_gids( ) where {Df,Dc} model = get_background_model(trian) cgids = get_cell_gids(model) - - n_lfacets = map(num_cells,local_views(trian)) - first_gid = scan(+,n_lfacets,type=:exclusive,init=one(eltype(n_lfacets))) - n_facets = reduce(+,n_lfacets,init=zero(eltype(n_lfacets))) - fgids = map(local_views(trian),partition(cgids),first_gid,n_lfacets) do trian, cgids, first_gid, n_lfacets - glue = get_glue(trian,Val(Dc)) # Glue from cut facets to background cells - facet_to_bgcell = glue.tface_to_mface + n_lfacets, bgcell_to_lfacets = map(local_views(trian)) do trian + model = get_background_model(trian) + lfacet_to_bgcell = get_glue(trian,Val(Dc)).tface_to_mface + n_lfacets = length(lfacet_to_bgcell) - facet_to_gid = collect(first_gid:(first_gid+n_lfacets-1)) - facet_to_owner = local_to_owner(cgids)[facet_to_bgcell] - LocalIndices(n_facets,part_id(cgids),facet_to_gid,facet_to_owner) - end - return PRange(fgids) -end + ptrs = zeros(Int32,num_cells(model)+1) + for bgcell in lfacet_to_bgcell + ptrs[bgcell+1] += 1 + end + Arrays.length_to_ptrs!(ptrs) + @assert ptrs[end] == n_lfacets+1 + + data = zeros(Int32,n_lfacets) + for (lfacet,bgcell) in enumerate(lfacet_to_bgcell) + data[ptrs[bgcell]] = lfacet + ptrs[bgcell] += 1 + end + Arrays.rewind_ptrs!(ptrs) + + return n_lfacets, Table(data,ptrs) + end |> tuple_of_arrays -# function GridapDistributed.generate_cell_gids( -# trian::DistributedSubFacetTriangulation{Df,Dc}, -# ) where {Df,Dc} -# model = get_background_model(trian) -# ctrians = map(local_views(trian),local_views(model)) do trian, model -# glue = get_glue(trian,Val(Dc)) # Glue from cut facets to background cells -# facet_to_bgcell = glue.tface_to_mface -# Triangulation(model,facet_to_bgcell) -# end -# ctrian = GridapDistributed.DistributedTriangulation(ctrians,model) -# return GridapDistributed.generate_cell_gids(ctrian) -# end + return GridapDistributed.generate_gids( + cgids, bgcell_to_lfacets, n_lfacets + ) +end function GridapDistributed.add_ghost_cells( trian::DistributedSubFacetTriangulation{Df,Dc}, From 8ff022a03368496005053479434eea2d439cd73b Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Fri, 9 May 2025 22:33:37 +1000 Subject: [PATCH 105/120] Minor --- test/DistributedTests/GeometricalDifferentiationTests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index 28a8ebc6..47fefcc3 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -267,12 +267,12 @@ function main(distribute,np) main_normal(model,φ0,f0) i_am_main(ranks) && println(" >> Case 1") - φ1 = level_set(:circle_2) + φ1 = level_set(:circle) f1(x) = 1.0 main_generic(model,φ1,f1) i_am_main(ranks) && println(" >> Case 2") - φ2 = level_set(:circle_2) + φ2 = level_set(:circle) f2(x) = x[1] + x[2] main_generic(model,φ2,f2) From 7e5162414f397d5d7c6b2cd25ed9b01e0170ef2e Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Fri, 9 May 2025 23:25:19 +1000 Subject: [PATCH 106/120] Minor --- test/DistributedTests/GeometricalDifferentiationTests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index 47fefcc3..aad65908 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -284,8 +284,8 @@ function main(distribute,np) model = generate_model(D,n,ranks,mesh_partition) i_am_main(ranks) && println(" >> Case 3") - φ3 = level_set(:regular_3d) - f3(x) = x[1] + x[2] + x[3] + φ3 = level_set(:sphere) + f3(x) = x[1] + x[2] main_generic(model,φ3,f3) end From 5ff3fb01e20128206d9acb1db8fe4578164e9cf1 Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Fri, 16 May 2025 23:40:00 +1000 Subject: [PATCH 107/120] Minor --- .../GeometricalDifferentiationTests.jl | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index aad65908..855f695f 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -261,17 +261,14 @@ function main(distribute,np) n = 12 model = generate_model(D,n,ranks,mesh_partition) - i_am_main(ranks) && println(" >> Case 0") φ0 = level_set(:circle_2) f0((x,y)) = VectorValue((1-x)^2,(1-y)^2) main_normal(model,φ0,f0) - i_am_main(ranks) && println(" >> Case 1") φ1 = level_set(:circle) f1(x) = 1.0 main_generic(model,φ1,f1) - i_am_main(ranks) && println(" >> Case 2") φ2 = level_set(:circle) f2(x) = x[1] + x[2] main_generic(model,φ2,f2) @@ -283,10 +280,9 @@ function main(distribute,np) n = 8 model = generate_model(D,n,ranks,mesh_partition) - i_am_main(ranks) && println(" >> Case 3") - φ3 = level_set(:sphere) - f3(x) = x[1] + x[2] - main_generic(model,φ3,f3) + # φ3 = level_set(:sphere) + # f3(x) = x[1] + x[2] + # main_generic(model,φ3,f3) end end \ No newline at end of file From 17a63b9fbb8da33728406ed772b618fbbe74331d Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Tue, 3 Jun 2025 22:40:23 +1000 Subject: [PATCH 108/120] Minor --- src/Interfaces/EmbeddedFacetDiscretizations.jl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Interfaces/EmbeddedFacetDiscretizations.jl b/src/Interfaces/EmbeddedFacetDiscretizations.jl index 1f5476cc..eb71d9df 100644 --- a/src/Interfaces/EmbeddedFacetDiscretizations.jl +++ b/src/Interfaces/EmbeddedFacetDiscretizations.jl @@ -215,12 +215,15 @@ end function _restrict_boundary_triangulation(model,facets,bgfacet_to_mask) facet_to_bgfacet = facets.glue.face_to_bgface - facet_to_mask = lazy_map(Reindex(bgfacet_to_mask),facet_to_bgfacet) + n_bgfacets = length(bgfacet_to_mask) - bgfacet_to_mask2 = fill(false,n_bgfacets) - bgfacet_to_mask2[facet_to_bgfacet] .= facet_to_mask + new_bgfacet_to_mask = fill(false,n_bgfacets) + new_bgfacet_to_mask[facet_to_bgfacet] .= view(bgfacet_to_mask,facet_to_bgfacet) - BoundaryTriangulation(model,bgfacet_to_mask2,facets.glue.bgface_to_lcell) + new_bgfacet_to_lcell = fill(Int8(1),n_bgfacets) + new_bgfacet_to_lcell[facet_to_bgfacet] .= facets.glue.face_to_lcell + + BoundaryTriangulation(model,new_bgfacet_to_mask,new_bgfacet_to_lcell) end function compute_bgfacet_to_inoutcut(cut::EmbeddedFacetDiscretization,geo::CSG.Geometry) From 48b66a0c9b844b718a5208b91c405d219d42e9af Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Wed, 11 Jun 2025 09:19:10 +1000 Subject: [PATCH 109/120] Updated compats --- Project.toml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Project.toml b/Project.toml index 8bb35cc1..a0a0e1a7 100644 --- a/Project.toml +++ b/Project.toml @@ -1,24 +1,8 @@ -authors = ["Francesc Verdugo ", "Eric Neiva ", "Pere Antoni Martorell ", "Santiago Badia "] name = "GridapEmbedded" uuid = "8838a6a3-0006-4405-b874-385995508d5d" +authors = ["Francesc Verdugo ", "Eric Neiva ", "Pere Antoni Martorell ", "Santiago Badia "] version = "0.9.6" -[compat] -AbstractTrees = "0.3.3, 0.4" -Algoim = "0.2.2" -Combinatorics = "1" -CxxWrap = "0.16" -FillArrays = "0.10, 0.11, 0.12, 0.13, 1" -FiniteDiff = "2.27.0" -ForwardDiff = "0.10.38, 1" -Graphs = "1.12.0" -Gridap = "0.18.12" -GridapDistributed = "0.3, 0.4" -MPI = "0.20" -MiniQhull = "0.1.0, 0.2, 0.3, 0.4" -PartitionedArrays = "0.3.4" -julia = "1.3" - [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" Algoim = "0eb9048c-21de-4c7a-bfac-056de1940b74" @@ -37,6 +21,22 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" algoimWrapper_jll = "3c43aa7b-5398-51f3-8d75-8f051e6faa4d" +[compat] +AbstractTrees = "0.3.3, 0.4" +Algoim = "0.2.2" +Combinatorics = "1" +CxxWrap = "0.16" +FillArrays = "0.10, 0.11, 0.12, 0.13, 1" +FiniteDiff = "2.27.0" +ForwardDiff = "0.10.38, 1" +Graphs = "1.12.0" +Gridap = "0.18.12, 0.19" +GridapDistributed = "0.3, 0.4" +MPI = "0.20" +MiniQhull = "0.1.0, 0.2, 0.3, 0.4" +PartitionedArrays = "0.3.4" +julia = "1.3" + [extras] FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" MPIPreferences = "3da0fdf6-3ccc-4f1b-acd9-58baa6c99267" From 41839704ef6960610aee6be5f206a79db553a9a7 Mon Sep 17 00:00:00 2001 From: Jordi Manyer Date: Wed, 11 Jun 2025 23:21:48 +1000 Subject: [PATCH 110/120] Bumped version --- NEWS.md | 6 ++++++ Project.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 7cfea949..65146c6d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,12 @@ 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). +## [0.9.7] - 2025-6-11 + +### Added + +- Added support for Gridap v0.19. Since PR[#110](https://github.com/gridap/GridapEmbedded.jl/pull/110). + ## [0.9.6] - 2025-04-19 ### Added diff --git a/Project.toml b/Project.toml index a0a0e1a7..4e0cd317 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GridapEmbedded" uuid = "8838a6a3-0006-4405-b874-385995508d5d" authors = ["Francesc Verdugo ", "Eric Neiva ", "Pere Antoni Martorell ", "Santiago Badia "] -version = "0.9.6" +version = "0.9.7" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" From 747f1023857adc3cdd032e1fa8cd54075af1c6dd Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Wed, 9 Jul 2025 20:01:29 +1000 Subject: [PATCH 111/120] Add missing update_trian! method for multifield --- .../DifferentiableTriangulations.jl | 22 ++++++++++++---- src/LevelSetCutters/LevelSetCutters.jl | 3 +++ .../GeometricalDifferentiationTests.jl | 17 +++++++++++-- .../GeometricalDifferentiationTests.jl | 25 ++++++++++++++++--- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/LevelSetCutters/DifferentiableTriangulations.jl b/src/LevelSetCutters/DifferentiableTriangulations.jl index 19ef9238..3328f493 100644 --- a/src/LevelSetCutters/DifferentiableTriangulations.jl +++ b/src/LevelSetCutters/DifferentiableTriangulations.jl @@ -10,11 +10,11 @@ methods to compute derivatives w.r.t. deformations of the embedded mesh. To do so, it propagates dual numbers into the geometric maps mapping cut subcells/subfacets to the background mesh. -## Constructor: +## Constructor: DifferentiableTriangulation(trian::Triangulation,fe_space::FESpace) -where `trian` must be an embedded triangulation and `fe_space` is the `FESpace` where +where `trian` must be an embedded triangulation and `fe_space` is the `FESpace` where the level-set function lives. """ @@ -63,6 +63,18 @@ function update_trian!(trian::DifferentiableTriangulation,::FESpace,::Nothing) return trian end +const MultiFieldSpaceTypes = Union{<:MultiFieldFESpace,<:DistributedMultiFieldFESpace} + +function update_trian!(trian::DifferentiableTriangulation,space::MultiFieldSpaceTypes,φh) + map((Ui,φi)->update_trian!(trian,Ui,φi),space,φh) + return trian +end + +function update_trian!(trian::DifferentiableTriangulation,::MultiFieldSpaceTypes,::Nothing) + trian.cell_values = nothing + return trian +end + # Autodiff function FESpaces._change_argument( @@ -424,8 +436,8 @@ function extract_dualized_cell_values( end # TriangulationView -# This is mostly used in distributed, where we remove ghost cells by taking a view -# of the local triangulations. +# This is mostly used in distributed, where we remove ghost cells by taking a view +# of the local triangulations. const DifferentiableTriangulationView{Dc,Dp} = Geometry.TriangulationView{Dc,Dp,<:DifferentiableTriangulation} @@ -465,7 +477,7 @@ end # We only need to propagate the dual numbers to the CUT cells, which is what the # following implementation does: -const DifferentiableAppendedTriangulation{Dc,Dp,A} = +const DifferentiableAppendedTriangulation{Dc,Dp,A} = AppendedTriangulation{Dc,Dp,<:Union{<:DifferentiableTriangulation,<:DifferentiableTriangulationView{Dc,Dp}}} function DifferentiableTriangulation( diff --git a/src/LevelSetCutters/LevelSetCutters.jl b/src/LevelSetCutters/LevelSetCutters.jl index 30592287..9c2cda0c 100644 --- a/src/LevelSetCutters/LevelSetCutters.jl +++ b/src/LevelSetCutters/LevelSetCutters.jl @@ -31,6 +31,9 @@ using Gridap.CellData using Gridap.Polynomials using Gridap.Visualization using Gridap.FESpaces +using Gridap.MultiField + +using GridapDistributed: DistributedMultiFieldFESpace export LevelSetCutter export AnalyticalGeometry diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index 855f695f..515a66c7 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -1,7 +1,7 @@ module DistributedGeometricalDifferentitationTests ############################################################################################ -# These tests are meant to verify the correctness differentiation of functionals w.r.t the -# level set defining the cut domain. +# These tests are meant to verify the correctness differentiation of functionals w.r.t the +# level set defining the cut domain. # They are based on the following work: # "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation" # by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis (2025) @@ -117,6 +117,19 @@ function main_generic( @test norm(dJ_bulk_1_AD_in_u_vec - dJ_bulk_1_exact_in_u_vec) < 1e-10 + # Multifield case + U = TestFESpace(model,reffe) + V_φu = MultiFieldFESpace([V_φ,U]) + φuh = interpolate([φh,x->x[1]],V_φu) + J_bulk_mult((φ,u)) = ∫(fh)dΩ + dJ_bulk_AD = gradient(J_bulk_mult,φuh) + dJ_bulk_AD_vec = assemble_vector(dJ_bulk_AD,V_φu) + + dJ_bulk_exact_mult((dφ,du)) = ∫(-fh*dφ/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJ_bulk_exact_vec = assemble_vector(dJ_bulk_exact_mult,V_φu) + + @test norm(dJ_bulk_AD_vec - dJ_bulk_exact_vec,Inf) < 1e-10 + # A.2) Volume integral g(fh) = ∇(fh)⋅∇(fh) diff --git a/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl b/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl index 8a90387f..d834b0eb 100644 --- a/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl +++ b/test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl @@ -1,14 +1,14 @@ module GeometricalDifferentiationTests ############################################################################################ -# These tests are meant to verify the correctness differentiation of functionals w.r.t the -# level set defining the cut domain. +# These tests are meant to verify the correctness differentiation of functionals w.r.t the +# level set defining the cut domain. # They are based on the following work: # "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation" # by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis (2025) ############################################################################################ using Test, FiniteDiff -using Gridap, Gridap.Geometry, Gridap.Adaptivity, Gridap.Arrays +using Gridap, Gridap.Geometry, Gridap.Adaptivity, Gridap.Arrays, Gridap.MultiField using GridapEmbedded, GridapEmbedded.LevelSetCutters, GridapEmbedded.Interfaces using GridapEmbedded.Interfaces: get_conormal_vector @@ -17,7 +17,7 @@ using GridapEmbedded.Interfaces: get_ghost_normal_vector using GridapEmbedded.LevelSetCutters: DifferentiableTriangulation -# We general a simplicial model where the simplices are created in a symmetric way using +# We general a simplicial model where the simplices are created in a symmetric way using # varycentric refinement of QUADs and HEXs. function generate_model(D,n) domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1) @@ -124,6 +124,23 @@ function main( @test abs_error < 1e-10 + # Multifield case + U = TestFESpace(model,reffe) + V_φu = MultiFieldFESpace([V_φ,U]) + φuh = interpolate([φh,x->x[1]],V_φu) + J_bulk_mult((φ,u)) = ∫(fh)dΩ + dJ_bulk_AD = gradient(J_bulk_mult,φuh) + dJ_bulk_AD_vec = assemble_vector(dJ_bulk_AD,V_φu) + + dJ_bulk_exact_mult((dφ,du)) = ∫(-fh*dφ/(abs(n_Γ ⋅ ∇(φh))))dΓ + dJ_bulk_exact_vec = assemble_vector(dJ_bulk_exact_mult,V_φu) + + abs_error = norm(dJ_bulk_AD_vec - dJ_bulk_exact_vec,Inf) + if verbose + println(" - norm(dJ_AD - dJ_exact,Inf) = ",abs_error," | Multifield test") + end + @test abs_error < 1e-10 + # A.1.1) Volume integral with another field J_bulk_1(u,φ) = ∫(u+fh)dΩ From 3aea54465d1b71cc3828b4dcf6b3a2b695681c5a Mon Sep 17 00:00:00 2001 From: zjwegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 10 Jul 2025 06:40:35 +1000 Subject: [PATCH 112/120] minor --- test/DistributedTests/GeometricalDifferentiationTests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/DistributedTests/GeometricalDifferentiationTests.jl b/test/DistributedTests/GeometricalDifferentiationTests.jl index 515a66c7..147cc6a1 100644 --- a/test/DistributedTests/GeometricalDifferentiationTests.jl +++ b/test/DistributedTests/GeometricalDifferentiationTests.jl @@ -128,7 +128,7 @@ function main_generic( dJ_bulk_exact_mult((dφ,du)) = ∫(-fh*dφ/(abs(n_Γ ⋅ ∇(φh))))dΓ dJ_bulk_exact_vec = assemble_vector(dJ_bulk_exact_mult,V_φu) - @test norm(dJ_bulk_AD_vec - dJ_bulk_exact_vec,Inf) < 1e-10 + @test norm(dJ_bulk_AD_vec - dJ_bulk_exact_vec) < 1e-10 # A.2) Volume integral From 36591829c1cec05908252c392619bd2adc620ed7 Mon Sep 17 00:00:00 2001 From: Zachary J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 10 Jul 2025 08:46:02 +1000 Subject: [PATCH 113/120] Update NEWS.md --- NEWS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS.md b/NEWS.md index 65146c6d..6dff9dcd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,12 @@ 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). +## [0.9.8] - 2025-7-10 + +### Added + +- Added missing update_trian! method for MultiField. Since PR[#112](https://github.com/gridap/GridapEmbedded.jl/pull/112). + ## [0.9.7] - 2025-6-11 ### Added From d825d2c33e44bb04de3f2e2c0733f64c624f0b50 Mon Sep 17 00:00:00 2001 From: Zachary J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 10 Jul 2025 09:08:10 +1000 Subject: [PATCH 114/120] Bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4e0cd317..b5e91a35 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GridapEmbedded" uuid = "8838a6a3-0006-4405-b874-385995508d5d" authors = ["Francesc Verdugo ", "Eric Neiva ", "Pere Antoni Martorell ", "Santiago Badia "] -version = "0.9.7" +version = "0.9.8" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" From 85136c47b073f996542e94e7fe2db159fc4c2deb Mon Sep 17 00:00:00 2001 From: Zachary J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:16:56 +1000 Subject: [PATCH 115/120] Fix precompilation --- .../CutFaceBoundaryTriangulations.jl | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/Interfaces/CutFaceBoundaryTriangulations.jl b/src/Interfaces/CutFaceBoundaryTriangulations.jl index 63f7b2ca..872413a4 100644 --- a/src/Interfaces/CutFaceBoundaryTriangulations.jl +++ b/src/Interfaces/CutFaceBoundaryTriangulations.jl @@ -395,38 +395,38 @@ end ############################################################################################ # This will go to Gridap - -function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField}) - plus = k(a.plus) - minus = k(a.minus) - SkeletonPair(plus,minus) -end - -function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField}) - plus = k(a.plus,b.plus) - minus = k(a.minus,b.minus) - SkeletonPair(plus,minus) -end - -import Gridap.TensorValues: inner, outer -import LinearAlgebra: dot -import Base: abs, *, +, -, / - -for op in (:/,) - @eval begin - ($op)(a::CellField,b::SkeletonPair{<:CellField}) = Operation($op)(a,b) - ($op)(a::SkeletonPair{<:CellField},b::CellField) = Operation($op)(a,b) - end -end - -for op in (:outer,:*,:dot,:/) - @eval begin - ($op)(a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField}) = Operation($op)(a,b) - end -end - -function CellData.change_domain(a::SkeletonPair, ::ReferenceDomain, ::PhysicalDomain) - plus = change_domain(a.plus,ReferenceDomain(),PhysicalDomain()) - minus = change_domain(a.minus,ReferenceDomain(),PhysicalDomain()) - return SkeletonPair(plus,minus) -end +# +# function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField}) +# plus = k(a.plus) +# minus = k(a.minus) +# SkeletonPair(plus,minus) +# end + +# function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField}) +# plus = k(a.plus,b.plus) +# minus = k(a.minus,b.minus) +# SkeletonPair(plus,minus) +# end + +# import Gridap.TensorValues: inner, outer +# import LinearAlgebra: dot +# import Base: abs, *, +, -, / + +# for op in (:/,) +# @eval begin +# ($op)(a::CellField,b::SkeletonPair{<:CellField}) = Operation($op)(a,b) +# ($op)(a::SkeletonPair{<:CellField},b::CellField) = Operation($op)(a,b) +# end +# end + +# for op in (:outer,:*,:dot,:/) +# @eval begin +# ($op)(a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField}) = Operation($op)(a,b) +# end +# end + +# function CellData.change_domain(a::SkeletonPair, ::ReferenceDomain, ::PhysicalDomain) +# plus = change_domain(a.plus,ReferenceDomain(),PhysicalDomain()) +# minus = change_domain(a.minus,ReferenceDomain(),PhysicalDomain()) +# return SkeletonPair(plus,minus) +# end From c48a4527de1e014d63fe56c1ab2c9287aa5e1430 Mon Sep 17 00:00:00 2001 From: Zachary J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:18:17 +1000 Subject: [PATCH 116/120] Update NEWS.md --- NEWS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.md b/NEWS.md index 6dff9dcd..79b8b87d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added missing update_trian! method for MultiField. Since PR[#112](https://github.com/gridap/GridapEmbedded.jl/pull/112). +- Fix failed precompilation due to Gridap v0.19.2. Since PR[#112](https://github.com/gridap/GridapEmbedded.jl/pull/112). ## [0.9.7] - 2025-6-11 From 96f4d979fff378c1bd757c11aff933ba5a717f2f Mon Sep 17 00:00:00 2001 From: Zachary J Wegert <60646897+zjwegert@users.noreply.github.com> Date: Thu, 10 Jul 2025 15:12:20 +1000 Subject: [PATCH 117/120] Update NEWS.md --- NEWS.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 79b8b87d..72fd3937 100644 --- a/NEWS.md +++ b/NEWS.md @@ -9,7 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added missing update_trian! method for MultiField. Since PR[#112](https://github.com/gridap/GridapEmbedded.jl/pull/112). -- Fix failed precompilation due to Gridap v0.19.2. Since PR[#112](https://github.com/gridap/GridapEmbedded.jl/pull/112). + +### Fixed + +- Fixed failed precompilation due to Gridap v0.19.2. Since PR[#112](https://github.com/gridap/GridapEmbedded.jl/pull/112). ## [0.9.7] - 2025-6-11 From 59911d614ac70d56c4738f83b7770275343cd9ea Mon Sep 17 00:00:00 2001 From: Eric Neiva Date: Mon, 14 Jul 2025 15:09:02 +0200 Subject: [PATCH 118/120] Setup branch to start dev --- Manifest.toml | 989 ++++++++++++++++++++++ test/DistributedTests/AggregationTests.jl | 2 +- 2 files changed, 990 insertions(+), 1 deletion(-) create mode 100644 Manifest.toml diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 00000000..4dc7563e --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,989 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.11.5" +manifest_format = "2.0" +project_hash = "0647d3409ba6f0505a76eb825c3eb703439c42f8" + +[[deps.ADTypes]] +git-tree-sha1 = "be7ae030256b8ef14a441726c4c37766b90b93a3" +uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" +version = "1.15.0" + + [deps.ADTypes.extensions] + ADTypesChainRulesCoreExt = "ChainRulesCore" + ADTypesConstructionBaseExt = "ConstructionBase" + ADTypesEnzymeCoreExt = "EnzymeCore" + + [deps.ADTypes.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" + EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" + +[[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 = "f7817e2e585aa6d924fd714df1e2a84be7896c60" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "4.3.0" +weakdeps = ["SparseArrays", "StaticArrays"] + + [deps.Adapt.extensions] + AdaptSparseArraysExt = "SparseArrays" + AdaptStaticArraysExt = "StaticArrays" + +[[deps.Algoim]] +deps = ["CxxWrap", "LinearAlgebra", "StaticArrays", "algoimWrapper_jll"] +git-tree-sha1 = "14f3a55809e3e2ef9cd0d5962157f13a418bb00a" +uuid = "0eb9048c-21de-4c7a-bfac-056de1940b74" +version = "0.2.2" + +[[deps.ArgCheck]] +git-tree-sha1 = "f9e9a66c9b7be1ad7372bbd9b062d9230c30c5ce" +uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197" +version = "2.5.0" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.2" + +[[deps.ArnoldiMethod]] +deps = ["LinearAlgebra", "Random", "StaticArrays"] +git-tree-sha1 = "d57bd3762d308bded22c3b82d033bff85f6195c6" +uuid = "ec485272-7323-5ecc-a04f-4719b315124d" +version = "0.4.0" + +[[deps.ArrayInterface]] +deps = ["Adapt", "LinearAlgebra"] +git-tree-sha1 = "9606d7832795cbef89e06a550475be300364a8aa" +uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" +version = "7.19.0" + + [deps.ArrayInterface.extensions] + ArrayInterfaceBandedMatricesExt = "BandedMatrices" + ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices" + ArrayInterfaceCUDAExt = "CUDA" + ArrayInterfaceCUDSSExt = "CUDSS" + ArrayInterfaceChainRulesCoreExt = "ChainRulesCore" + ArrayInterfaceChainRulesExt = "ChainRules" + ArrayInterfaceGPUArraysCoreExt = "GPUArraysCore" + ArrayInterfaceReverseDiffExt = "ReverseDiff" + ArrayInterfaceSparseArraysExt = "SparseArrays" + 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" + CUDSS = "45b445bb-4962-46a0-9369-b4df9d0f772e" + ChainRules = "082447d4-558c-5d27-93f4-14fc19e9eca2" + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + +[[deps.ArrayLayouts]] +deps = ["FillArrays", "LinearAlgebra"] +git-tree-sha1 = "4e25216b8fea1908a0ce0f5d87368587899f75be" +uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" +version = "1.11.1" +weakdeps = ["SparseArrays"] + + [deps.ArrayLayouts.extensions] + ArrayLayoutsSparseArraysExt = "SparseArrays" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" +version = "1.11.0" + +[[deps.AutoHashEquals]] +git-tree-sha1 = "4ec6b48702dacc5994a835c1189831755e4e76ef" +uuid = "15f4f7f2-30c1-5605-9d31-71845cf9641f" +version = "2.2.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" +version = "1.11.0" + +[[deps.BlockArrays]] +deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra"] +git-tree-sha1 = "291532989f81db780e435452ccb2a5f902ff665f" +uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" +version = "1.7.0" + + [deps.BlockArrays.extensions] + BlockArraysAdaptExt = "Adapt" + BlockArraysBandedMatricesExt = "BandedMatrices" + + [deps.BlockArrays.weakdeps] + Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + +[[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 = "962834c22b66e32aa10f7611c08c8ca4e20749a9" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.8" + +[[deps.Combinatorics]] +git-tree-sha1 = "8010b6bb3388abe68d95743dcbea77650bb2eddf" +uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" +version = "1.0.3" + +[[deps.CommonSubexpressions]] +deps = ["MacroTools"] +git-tree-sha1 = "cda2cfaebb4be89c9084adaca7dd7333369715c5" +uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" +version = "0.3.1" + +[[deps.Compat]] +deps = ["TOML", "UUIDs"] +git-tree-sha1 = "3a3dfb30697e96a440e4149c8c51bf32f818c0f3" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "4.17.0" +weakdeps = ["Dates", "LinearAlgebra"] + + [deps.Compat.extensions] + CompatLinearAlgebraExt = "LinearAlgebra" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.1.1+0" + +[[deps.ConstructionBase]] +git-tree-sha1 = "b4b092499347b18a015186eae3042f72267106cb" +uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" +version = "1.6.0" + + [deps.ConstructionBase.extensions] + ConstructionBaseIntervalSetsExt = "IntervalSets" + ConstructionBaseLinearAlgebraExt = "LinearAlgebra" + ConstructionBaseStaticArraysExt = "StaticArrays" + + [deps.ConstructionBase.weakdeps] + IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" + LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[[deps.CxxWrap]] +deps = ["Libdl", "MacroTools", "libcxxwrap_julia_jll"] +git-tree-sha1 = "3d05a37a8d40524752524da392ec0c2fbee32543" +uuid = "1f15a43c-97ca-5a2a-ae31-89f07a497df4" +version = "0.16.2" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "4e1fe97fdaed23e9dc21d4d664bea76b65fc50a0" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.22" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" +version = "1.11.0" + +[[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.DifferentiationInterface]] +deps = ["ADTypes", "LinearAlgebra"] +git-tree-sha1 = "c092fd1dd0d94e609cd0d29e13897b2825c804bb" +uuid = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" +version = "0.7.2" + + [deps.DifferentiationInterface.extensions] + DifferentiationInterfaceChainRulesCoreExt = "ChainRulesCore" + DifferentiationInterfaceDiffractorExt = "Diffractor" + DifferentiationInterfaceEnzymeExt = ["EnzymeCore", "Enzyme"] + DifferentiationInterfaceFastDifferentiationExt = "FastDifferentiation" + DifferentiationInterfaceFiniteDiffExt = "FiniteDiff" + DifferentiationInterfaceFiniteDifferencesExt = "FiniteDifferences" + DifferentiationInterfaceForwardDiffExt = ["ForwardDiff", "DiffResults"] + DifferentiationInterfaceGPUArraysCoreExt = "GPUArraysCore" + DifferentiationInterfaceGTPSAExt = "GTPSA" + DifferentiationInterfaceMooncakeExt = "Mooncake" + DifferentiationInterfacePolyesterForwardDiffExt = ["PolyesterForwardDiff", "ForwardDiff", "DiffResults"] + DifferentiationInterfaceReverseDiffExt = ["ReverseDiff", "DiffResults"] + DifferentiationInterfaceSparseArraysExt = "SparseArrays" + DifferentiationInterfaceSparseConnectivityTracerExt = "SparseConnectivityTracer" + DifferentiationInterfaceSparseMatrixColoringsExt = "SparseMatrixColorings" + DifferentiationInterfaceStaticArraysExt = "StaticArrays" + DifferentiationInterfaceSymbolicsExt = "Symbolics" + DifferentiationInterfaceTrackerExt = "Tracker" + DifferentiationInterfaceZygoteExt = ["Zygote", "ForwardDiff"] + + [deps.DifferentiationInterface.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" + Diffractor = "9f5e2b26-1114-432f-b630-d3fe2085c51c" + Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" + EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" + FastDifferentiation = "eb9bf01b-bf85-4b60-bf87-ee5de06c00be" + FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" + FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" + GTPSA = "b27dd330-f138-47c5-815b-40db9dd9b6e8" + Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" + PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + SparseConnectivityTracer = "9f842d2f-2579-4b1d-911e-f412cf18a3f5" + SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.Distances]] +deps = ["LinearAlgebra", "Statistics", "StatsAPI"] +git-tree-sha1 = "c7e3a542b999843086e2f29dac96a618c105be1d" +uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" +version = "0.10.12" + + [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" +version = "1.11.0" + +[[deps.DocStringExtensions]] +git-tree-sha1 = "7442a5dfe1ebb773c29cc2962a8980f47221d76c" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.5" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.FFTW]] +deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] +git-tree-sha1 = "797762812ed063b9b94f6cc7742bc8883bb5e69e" +uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" +version = "1.9.0" + +[[deps.FFTW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "6d6219a004b8cf1e0b4dbe27a2860b8e04eba0be" +uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" +version = "3.3.11+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 = "b66970a70db13f45b7e57fbda1736e1cf72174ea" +uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +version = "1.17.0" + + [deps.FileIO.extensions] + HTTPExt = "HTTP" + + [deps.FileIO.weakdeps] + HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" +version = "1.11.0" + +[[deps.FillArrays]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "6a70198746448456524cb442b8af316927ff3e1a" +uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" +version = "1.13.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", "Setfield"] +git-tree-sha1 = "f089ab1f834470c525562030c8cfde4025d5e915" +uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" +version = "2.27.0" + + [deps.FiniteDiff.extensions] + FiniteDiffBandedMatricesExt = "BandedMatrices" + FiniteDiffBlockBandedMatricesExt = "BlockBandedMatrices" + FiniteDiffSparseArraysExt = "SparseArrays" + FiniteDiffStaticArraysExt = "StaticArrays" + + [deps.FiniteDiff.weakdeps] + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + +[[deps.ForwardDiff]] +deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] +git-tree-sha1 = "910febccb28d493032495b7009dce7d7f7aee554" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "1.0.1" +weakdeps = ["StaticArrays"] + + [deps.ForwardDiff.extensions] + ForwardDiffStaticArraysExt = "StaticArrays" + +[[deps.Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" +version = "1.11.0" + +[[deps.Graphs]] +deps = ["ArnoldiMethod", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] +git-tree-sha1 = "c5abfa0ae0aaee162a3fbb053c13ecda39be545b" +uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" +version = "1.13.0" + +[[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 = "956af503f4df1cca06cb018aa8eb68260eb7d6d4" +uuid = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" +version = "0.19.2" + +[[deps.GridapDistributed]] +deps = ["BlockArrays", "CircularArrays", "FillArrays", "ForwardDiff", "Gridap", "LinearAlgebra", "MPI", "PartitionedArrays", "SparseArrays", "SparseMatricesCSR", "WriteVTK"] +git-tree-sha1 = "4fa1869debb61b8070446d8f22317571757b0e82" +repo-rev = "expand-ghost" +repo-url = "https://github.com/gridap/GridapDistributed.jl.git" +uuid = "f9701e48-63b3-45aa-9a63-9bc6c271f355" +version = "0.4.8" + +[[deps.HashArrayMappedTries]] +git-tree-sha1 = "2eaa69a7cab70a52b9687c8bf950a5a93ec895ae" +uuid = "076d061b-32b6-4027-95e0-9a2c6f6d7e74" +version = "0.2.0" + +[[deps.Hwloc_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "92f65c4d78ce8cdbb6b68daf88889950b0a99d11" +uuid = "e33a78d0-f292-5ffc-b300-72abe9b543c8" +version = "2.12.1+0" + +[[deps.Inflate]] +git-tree-sha1 = "d1b1b796e47d94588b3757fe84fbf65a5ec4a80d" +uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" +version = "0.1.5" + +[[deps.IntelOpenMP_jll]] +deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] +git-tree-sha1 = "0f14a5456bdc6b9731a5682f439a672750a09e48" +uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" +version = "2025.0.4+0" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +version = "1.11.0" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "e2222959fbc6c19554dc15174c81bf7bf3aa691c" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.2.4" + +[[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", "ScopedValues", "TranscodingStreams"] +git-tree-sha1 = "d97791feefda45729613fafeccc4fbef3f539151" +uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" +version = "0.5.15" +weakdeps = ["UnPack"] + + [deps.JLD2.extensions] + UnPackExt = "UnPack" + +[[deps.JLLWrappers]] +deps = ["Artifacts", "Preferences"] +git-tree-sha1 = "a007feb38b422fbdab534406aeca1b86823cb4d6" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.7.0" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[deps.LazyArtifacts]] +deps = ["Artifacts", "Pkg"] +uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" +version = "1.11.0" + +[[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.6.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" +version = "1.11.0" + +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.7.2+0" + +[[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" +version = "1.11.0" + +[[deps.Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "be484f5c92fad0bd8acfef35fe017900b0b73809" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.18.0+0" + +[[deps.LightXML]] +deps = ["Libdl", "XML2_jll"] +git-tree-sha1 = "d5d2e3abfb30ea9c2cff81d243e7235b51315ec2" +uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179" +version = "0.9.2" + +[[deps.LineSearches]] +deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] +git-tree-sha1 = "4adee99b7262ad2a1a4bbbc59d993d24e55ea96f" +uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" +version = "7.4.0" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +version = "1.11.0" + +[[deps.LogExpFunctions]] +deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.29" + + [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" +version = "1.11.0" + +[[deps.MKL_jll]] +deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] +git-tree-sha1 = "5de60bc6cb3899cd318d80d627560fae2e2d99ae" +uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" +version = "2025.0.1+1" + +[[deps.MPI]] +deps = ["Distributed", "DocStringExtensions", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "PkgVersion", "PrecompileTools", "Requires", "Serialization", "Sockets"] +git-tree-sha1 = "892676019c58f34e38743bc989b0eca5bce5edc5" +uuid = "da04e1cc-30fd-572f-bb4f-1f8673147195" +version = "0.20.22" + + [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 = "d72d0ecc3f76998aac04e446547259b9ae4c265f" +uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4" +version = "4.3.1+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 = "e214f2a20bdd64c04cd3e4ff62d3c9be7e969a59" +uuid = "f1f71cc9-e9ae-5b93-9b94-4fe0e1ad3748" +version = "5.5.4+0" + +[[deps.MacroTools]] +git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.16" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +version = "1.11.0" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.6+0" + +[[deps.MicrosoftMPI_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bc95bf4149bf535c09602e3acdf950d9b4376227" +uuid = "9237b28f-5490-5468-be7b-bb81f5f5e6cf" +version = "10.1.4+3" + +[[deps.MiniQhull]] +deps = ["QhullMiniWrapper_jll"] +git-tree-sha1 = "9dc837d180ee49eeb7c8b77bb1c860452634b0d1" +uuid = "978d7f02-9e05-4691-894f-ae31a51d76ca" +version = "0.4.0" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" +version = "1.11.0" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.12.12" + +[[deps.NLSolversBase]] +deps = ["ADTypes", "DifferentiationInterface", "Distributed", "FiniteDiff", "ForwardDiff"] +git-tree-sha1 = "25a6638571a902ecfb1ae2a18fc1575f86b1d4df" +uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" +version = "7.10.0" + +[[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 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.1.3" + +[[deps.NearestNeighbors]] +deps = ["Distances", "StaticArrays"] +git-tree-sha1 = "ca7e18198a166a1f3eb92a3650d53d94ed8ca8a1" +uuid = "b8a86587-4115-5ab1-83bc-aa920d37bbce" +version = "0.4.22" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.OffsetArrays]] +git-tree-sha1 = "117432e406b5c023f665fa73dc26e79ec3630151" +uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" +version = "1.17.0" +weakdeps = ["Adapt"] + + [deps.OffsetArrays.extensions] + OffsetArraysAdaptExt = "Adapt" + +[[deps.OpenBLAS32_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] +git-tree-sha1 = "ece4587683695fe4c5f20e990da0ed7e83c351e7" +uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" +version = "0.3.29+0" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.27+1" + +[[deps.OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.5+0" + +[[deps.OpenMPI_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML", "Zlib_jll"] +git-tree-sha1 = "ec764453819f802fc1e144bfe750c454181bd66d" +uuid = "fe0851c0-eecd-5654-98d4-656369965a5c" +version = "5.0.8+0" + +[[deps.OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1346c9208249809840c91b26703912dff463d335" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.6+0" + +[[deps.OrderedCollections]] +git-tree-sha1 = "05868e21324cede2207c6f0f466b4bfef6d5e7ee" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.8.1" + +[[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 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.3" + +[[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", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.11.0" + + [deps.Pkg.extensions] + REPLExt = "REPL" + + [deps.Pkg.weakdeps] + REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[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 = "d04bec789dce5ff61e8f128b6aee0eda09a3855f" +uuid = "c74db56a-226d-5e98-8bb0-a6049094aeea" +version = "0.4.25" + +[[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" +version = "1.11.0" + +[[deps.QhullMiniWrapper_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Qhull_jll"] +git-tree-sha1 = "607cf73c03f8a9f83b36db0b86a3a9c14179621f" +uuid = "460c41e3-6112-5d7f-b78c-b6823adb3f2d" +version = "1.0.0+1" + +[[deps.Qhull_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "b6f3ac0623e1173c006cc7377798ec3fb33fa504" +uuid = "784f63db-0788-585a-bace-daefebcd302b" +version = "8.0.1004+0" + +[[deps.QuadGK]] +deps = ["DataStructures", "LinearAlgebra"] +git-tree-sha1 = "9da16da70037ba9d701192e27befedefb91ec284" +uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" +version = "2.11.2" + + [deps.QuadGK.extensions] + QuadGKEnzymeExt = "Enzyme" + + [deps.QuadGK.weakdeps] + Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +version = "1.11.0" + +[[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.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "62389eeff14780bfe55195b7204c0d8738436d64" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.1" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.ScopedValues]] +deps = ["HashArrayMappedTries", "Logging"] +git-tree-sha1 = "1147f140b4c8ddab224c94efa9569fc23d63ab44" +uuid = "7e506255-f358-4e82-b7e4-beb19740aa63" +version = "1.3.0" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +version = "1.11.0" + +[[deps.Setfield]] +deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"] +git-tree-sha1 = "c5391c6ace3bc430ca630251d02ea9687169ca68" +uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" +version = "1.1.2" + +[[deps.SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" +version = "1.11.0" + +[[deps.SimpleTraits]] +deps = ["InteractiveUtils", "MacroTools"] +git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231" +uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" +version = "0.9.4" + +[[deps.SimpleUnPack]] +git-tree-sha1 = "58e6353e72cde29b90a69527e56df1b5c3d8c437" +uuid = "ce78b400-467f-4804-87d8-8f486da07d0a" +version = "1.1.0" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" +version = "1.11.0" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +version = "1.11.0" + +[[deps.SparseMatricesCSR]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "cc05d16e340aecfa0e4cf4616194abc894cd0bca" +uuid = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1" +version = "0.6.9" + +[[deps.SpecialFunctions]] +deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "41852b8679f78c8d8961eeadc8f62cef861a52e3" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.5.1" + + [deps.SpecialFunctions.extensions] + SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" + + [deps.SpecialFunctions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + +[[deps.StaticArrays]] +deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] +git-tree-sha1 = "0feb6b9031bd5c51f9072393eb5ab3efd31bf9e4" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.9.13" + + [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"] +git-tree-sha1 = "ae3bb1eb3bba077cd276bc5cfc337cc65c3075c0" +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.11.1" +weakdeps = ["SparseArrays"] + + [deps.Statistics.extensions] + SparseArraysExt = ["SparseArrays"] + +[[deps.StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "9d72a13a3f4dd3795a195ac5a44d7d6ff5f552ff" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.7.1" + +[[deps.SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "7.7.0+0" + +[[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" +version = "1.11.0" + +[[deps.TranscodingStreams]] +git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.11.3" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" +version = "1.11.0" + +[[deps.UnPack]] +git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" +uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" +version = "1.0.2" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" +version = "1.11.0" + +[[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 = "a329e0b6310244173690d6a4dfc6d1141f9b9370" +uuid = "64499a7a-5c06-52f2-abe2-ccb03c286192" +version = "1.21.2" + +[[deps.XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] +git-tree-sha1 = "9380cd28f093c901600ab70e0201fb18bae226de" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.14.1+0" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.algoimWrapper_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "libcxxwrap_julia_jll"] +git-tree-sha1 = "686ddc4227be075cff2ec5df1c15b8edcd32e27d" +uuid = "3c43aa7b-5398-51f3-8d75-8f051e6faa4d" +version = "0.3.1+0" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.11.0+0" + +[[deps.libcxxwrap_julia_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "70091a11c756455c15bc6380ea000c16f38f2d3e" +uuid = "3eaa8342-bff7-56a5-9981-c04077f7cee7" +version = "0.13.4+0" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.59.0+0" + +[[deps.oneTBB_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "d5a767a3bb77135a99e433afe0eb14cd7f6914c3" +uuid = "1317d2d5-d96f-522e-a858-c73665f53c3e" +version = "2022.0.0+0" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+2" diff --git a/test/DistributedTests/AggregationTests.jl b/test/DistributedTests/AggregationTests.jl index 7175232b..50a84f2f 100644 --- a/test/DistributedTests/AggregationTests.jl +++ b/test/DistributedTests/AggregationTests.jl @@ -30,7 +30,7 @@ geo = union(geo1,geo2) n = 16 mesh_partition = (n,n) -bgmodel = CartesianDiscreteModel(ranks,np,pmin,pmax,mesh_partition) +bgmodel = CartesianDiscreteModel(ranks,np,pmin,pmax,mesh_partition;ghost=(2,2)) cutgeo = cut(bgmodel,geo) From 3d9a39651b0ab8f55962c791c126e62bacf3a547 Mon Sep 17 00:00:00 2001 From: Eric Neiva Date: Mon, 14 Jul 2025 15:12:42 +0200 Subject: [PATCH 119/120] Revert "Setup branch to start dev" This reverts commit 59911d614ac70d56c4738f83b7770275343cd9ea. --- Manifest.toml | 989 ---------------------- test/DistributedTests/AggregationTests.jl | 2 +- 2 files changed, 1 insertion(+), 990 deletions(-) delete mode 100644 Manifest.toml diff --git a/Manifest.toml b/Manifest.toml deleted file mode 100644 index 4dc7563e..00000000 --- a/Manifest.toml +++ /dev/null @@ -1,989 +0,0 @@ -# This file is machine-generated - editing it directly is not advised - -julia_version = "1.11.5" -manifest_format = "2.0" -project_hash = "0647d3409ba6f0505a76eb825c3eb703439c42f8" - -[[deps.ADTypes]] -git-tree-sha1 = "be7ae030256b8ef14a441726c4c37766b90b93a3" -uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -version = "1.15.0" - - [deps.ADTypes.extensions] - ADTypesChainRulesCoreExt = "ChainRulesCore" - ADTypesConstructionBaseExt = "ConstructionBase" - ADTypesEnzymeCoreExt = "EnzymeCore" - - [deps.ADTypes.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" - EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" - -[[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 = "f7817e2e585aa6d924fd714df1e2a84be7896c60" -uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "4.3.0" -weakdeps = ["SparseArrays", "StaticArrays"] - - [deps.Adapt.extensions] - AdaptSparseArraysExt = "SparseArrays" - AdaptStaticArraysExt = "StaticArrays" - -[[deps.Algoim]] -deps = ["CxxWrap", "LinearAlgebra", "StaticArrays", "algoimWrapper_jll"] -git-tree-sha1 = "14f3a55809e3e2ef9cd0d5962157f13a418bb00a" -uuid = "0eb9048c-21de-4c7a-bfac-056de1940b74" -version = "0.2.2" - -[[deps.ArgCheck]] -git-tree-sha1 = "f9e9a66c9b7be1ad7372bbd9b062d9230c30c5ce" -uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197" -version = "2.5.0" - -[[deps.ArgTools]] -uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" -version = "1.1.2" - -[[deps.ArnoldiMethod]] -deps = ["LinearAlgebra", "Random", "StaticArrays"] -git-tree-sha1 = "d57bd3762d308bded22c3b82d033bff85f6195c6" -uuid = "ec485272-7323-5ecc-a04f-4719b315124d" -version = "0.4.0" - -[[deps.ArrayInterface]] -deps = ["Adapt", "LinearAlgebra"] -git-tree-sha1 = "9606d7832795cbef89e06a550475be300364a8aa" -uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "7.19.0" - - [deps.ArrayInterface.extensions] - ArrayInterfaceBandedMatricesExt = "BandedMatrices" - ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices" - ArrayInterfaceCUDAExt = "CUDA" - ArrayInterfaceCUDSSExt = "CUDSS" - ArrayInterfaceChainRulesCoreExt = "ChainRulesCore" - ArrayInterfaceChainRulesExt = "ChainRules" - ArrayInterfaceGPUArraysCoreExt = "GPUArraysCore" - ArrayInterfaceReverseDiffExt = "ReverseDiff" - ArrayInterfaceSparseArraysExt = "SparseArrays" - 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" - CUDSS = "45b445bb-4962-46a0-9369-b4df9d0f772e" - ChainRules = "082447d4-558c-5d27-93f4-14fc19e9eca2" - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" - ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" - SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" - Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" - -[[deps.ArrayLayouts]] -deps = ["FillArrays", "LinearAlgebra"] -git-tree-sha1 = "4e25216b8fea1908a0ce0f5d87368587899f75be" -uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" -version = "1.11.1" -weakdeps = ["SparseArrays"] - - [deps.ArrayLayouts.extensions] - ArrayLayoutsSparseArraysExt = "SparseArrays" - -[[deps.Artifacts]] -uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" -version = "1.11.0" - -[[deps.AutoHashEquals]] -git-tree-sha1 = "4ec6b48702dacc5994a835c1189831755e4e76ef" -uuid = "15f4f7f2-30c1-5605-9d31-71845cf9641f" -version = "2.2.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" -version = "1.11.0" - -[[deps.BlockArrays]] -deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra"] -git-tree-sha1 = "291532989f81db780e435452ccb2a5f902ff665f" -uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" -version = "1.7.0" - - [deps.BlockArrays.extensions] - BlockArraysAdaptExt = "Adapt" - BlockArraysBandedMatricesExt = "BandedMatrices" - - [deps.BlockArrays.weakdeps] - Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" - BandedMatrices = "aae01518-5342-5314-be14-df237901396f" - -[[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 = "962834c22b66e32aa10f7611c08c8ca4e20749a9" -uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.8" - -[[deps.Combinatorics]] -git-tree-sha1 = "8010b6bb3388abe68d95743dcbea77650bb2eddf" -uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" -version = "1.0.3" - -[[deps.CommonSubexpressions]] -deps = ["MacroTools"] -git-tree-sha1 = "cda2cfaebb4be89c9084adaca7dd7333369715c5" -uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" -version = "0.3.1" - -[[deps.Compat]] -deps = ["TOML", "UUIDs"] -git-tree-sha1 = "3a3dfb30697e96a440e4149c8c51bf32f818c0f3" -uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.17.0" -weakdeps = ["Dates", "LinearAlgebra"] - - [deps.Compat.extensions] - CompatLinearAlgebraExt = "LinearAlgebra" - -[[deps.CompilerSupportLibraries_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "1.1.1+0" - -[[deps.ConstructionBase]] -git-tree-sha1 = "b4b092499347b18a015186eae3042f72267106cb" -uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" -version = "1.6.0" - - [deps.ConstructionBase.extensions] - ConstructionBaseIntervalSetsExt = "IntervalSets" - ConstructionBaseLinearAlgebraExt = "LinearAlgebra" - ConstructionBaseStaticArraysExt = "StaticArrays" - - [deps.ConstructionBase.weakdeps] - IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" - LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[[deps.CxxWrap]] -deps = ["Libdl", "MacroTools", "libcxxwrap_julia_jll"] -git-tree-sha1 = "3d05a37a8d40524752524da392ec0c2fbee32543" -uuid = "1f15a43c-97ca-5a2a-ae31-89f07a497df4" -version = "0.16.2" - -[[deps.DataStructures]] -deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "4e1fe97fdaed23e9dc21d4d664bea76b65fc50a0" -uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.22" - -[[deps.Dates]] -deps = ["Printf"] -uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" -version = "1.11.0" - -[[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.DifferentiationInterface]] -deps = ["ADTypes", "LinearAlgebra"] -git-tree-sha1 = "c092fd1dd0d94e609cd0d29e13897b2825c804bb" -uuid = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" -version = "0.7.2" - - [deps.DifferentiationInterface.extensions] - DifferentiationInterfaceChainRulesCoreExt = "ChainRulesCore" - DifferentiationInterfaceDiffractorExt = "Diffractor" - DifferentiationInterfaceEnzymeExt = ["EnzymeCore", "Enzyme"] - DifferentiationInterfaceFastDifferentiationExt = "FastDifferentiation" - DifferentiationInterfaceFiniteDiffExt = "FiniteDiff" - DifferentiationInterfaceFiniteDifferencesExt = "FiniteDifferences" - DifferentiationInterfaceForwardDiffExt = ["ForwardDiff", "DiffResults"] - DifferentiationInterfaceGPUArraysCoreExt = "GPUArraysCore" - DifferentiationInterfaceGTPSAExt = "GTPSA" - DifferentiationInterfaceMooncakeExt = "Mooncake" - DifferentiationInterfacePolyesterForwardDiffExt = ["PolyesterForwardDiff", "ForwardDiff", "DiffResults"] - DifferentiationInterfaceReverseDiffExt = ["ReverseDiff", "DiffResults"] - DifferentiationInterfaceSparseArraysExt = "SparseArrays" - DifferentiationInterfaceSparseConnectivityTracerExt = "SparseConnectivityTracer" - DifferentiationInterfaceSparseMatrixColoringsExt = "SparseMatrixColorings" - DifferentiationInterfaceStaticArraysExt = "StaticArrays" - DifferentiationInterfaceSymbolicsExt = "Symbolics" - DifferentiationInterfaceTrackerExt = "Tracker" - DifferentiationInterfaceZygoteExt = ["Zygote", "ForwardDiff"] - - [deps.DifferentiationInterface.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" - Diffractor = "9f5e2b26-1114-432f-b630-d3fe2085c51c" - Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" - EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" - FastDifferentiation = "eb9bf01b-bf85-4b60-bf87-ee5de06c00be" - FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" - FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000" - ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" - GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" - GTPSA = "b27dd330-f138-47c5-815b-40db9dd9b6e8" - Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" - PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b" - ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" - SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - SparseConnectivityTracer = "9f842d2f-2579-4b1d-911e-f412cf18a3f5" - SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35" - StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" - Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" - Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" - -[[deps.Distances]] -deps = ["LinearAlgebra", "Statistics", "StatsAPI"] -git-tree-sha1 = "c7e3a542b999843086e2f29dac96a618c105be1d" -uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" -version = "0.10.12" - - [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" -version = "1.11.0" - -[[deps.DocStringExtensions]] -git-tree-sha1 = "7442a5dfe1ebb773c29cc2962a8980f47221d76c" -uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.9.5" - -[[deps.Downloads]] -deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] -uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" -version = "1.6.0" - -[[deps.FFTW]] -deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] -git-tree-sha1 = "797762812ed063b9b94f6cc7742bc8883bb5e69e" -uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" -version = "1.9.0" - -[[deps.FFTW_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6d6219a004b8cf1e0b4dbe27a2860b8e04eba0be" -uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" -version = "3.3.11+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 = "b66970a70db13f45b7e57fbda1736e1cf72174ea" -uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" -version = "1.17.0" - - [deps.FileIO.extensions] - HTTPExt = "HTTP" - - [deps.FileIO.weakdeps] - HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" - -[[deps.FileWatching]] -uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" -version = "1.11.0" - -[[deps.FillArrays]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "6a70198746448456524cb442b8af316927ff3e1a" -uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "1.13.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", "Setfield"] -git-tree-sha1 = "f089ab1f834470c525562030c8cfde4025d5e915" -uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.27.0" - - [deps.FiniteDiff.extensions] - FiniteDiffBandedMatricesExt = "BandedMatrices" - FiniteDiffBlockBandedMatricesExt = "BlockBandedMatrices" - FiniteDiffSparseArraysExt = "SparseArrays" - FiniteDiffStaticArraysExt = "StaticArrays" - - [deps.FiniteDiff.weakdeps] - BandedMatrices = "aae01518-5342-5314-be14-df237901396f" - BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" - SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[[deps.ForwardDiff]] -deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] -git-tree-sha1 = "910febccb28d493032495b7009dce7d7f7aee554" -uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "1.0.1" -weakdeps = ["StaticArrays"] - - [deps.ForwardDiff.extensions] - ForwardDiffStaticArraysExt = "StaticArrays" - -[[deps.Future]] -deps = ["Random"] -uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" -version = "1.11.0" - -[[deps.Graphs]] -deps = ["ArnoldiMethod", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] -git-tree-sha1 = "c5abfa0ae0aaee162a3fbb053c13ecda39be545b" -uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" -version = "1.13.0" - -[[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 = "956af503f4df1cca06cb018aa8eb68260eb7d6d4" -uuid = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e" -version = "0.19.2" - -[[deps.GridapDistributed]] -deps = ["BlockArrays", "CircularArrays", "FillArrays", "ForwardDiff", "Gridap", "LinearAlgebra", "MPI", "PartitionedArrays", "SparseArrays", "SparseMatricesCSR", "WriteVTK"] -git-tree-sha1 = "4fa1869debb61b8070446d8f22317571757b0e82" -repo-rev = "expand-ghost" -repo-url = "https://github.com/gridap/GridapDistributed.jl.git" -uuid = "f9701e48-63b3-45aa-9a63-9bc6c271f355" -version = "0.4.8" - -[[deps.HashArrayMappedTries]] -git-tree-sha1 = "2eaa69a7cab70a52b9687c8bf950a5a93ec895ae" -uuid = "076d061b-32b6-4027-95e0-9a2c6f6d7e74" -version = "0.2.0" - -[[deps.Hwloc_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "92f65c4d78ce8cdbb6b68daf88889950b0a99d11" -uuid = "e33a78d0-f292-5ffc-b300-72abe9b543c8" -version = "2.12.1+0" - -[[deps.Inflate]] -git-tree-sha1 = "d1b1b796e47d94588b3757fe84fbf65a5ec4a80d" -uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" -version = "0.1.5" - -[[deps.IntelOpenMP_jll]] -deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] -git-tree-sha1 = "0f14a5456bdc6b9731a5682f439a672750a09e48" -uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" -version = "2025.0.4+0" - -[[deps.InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" -version = "1.11.0" - -[[deps.IrrationalConstants]] -git-tree-sha1 = "e2222959fbc6c19554dc15174c81bf7bf3aa691c" -uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.2.4" - -[[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", "ScopedValues", "TranscodingStreams"] -git-tree-sha1 = "d97791feefda45729613fafeccc4fbef3f539151" -uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.5.15" -weakdeps = ["UnPack"] - - [deps.JLD2.extensions] - UnPackExt = "UnPack" - -[[deps.JLLWrappers]] -deps = ["Artifacts", "Preferences"] -git-tree-sha1 = "a007feb38b422fbdab534406aeca1b86823cb4d6" -uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.7.0" - -[[deps.JSON]] -deps = ["Dates", "Mmap", "Parsers", "Unicode"] -git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" -uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "0.21.4" - -[[deps.LazyArtifacts]] -deps = ["Artifacts", "Pkg"] -uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" -version = "1.11.0" - -[[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.6.0+0" - -[[deps.LibGit2]] -deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" -version = "1.11.0" - -[[deps.LibGit2_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] -uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.7.2+0" - -[[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" -version = "1.11.0" - -[[deps.Libiconv_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "be484f5c92fad0bd8acfef35fe017900b0b73809" -uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" -version = "1.18.0+0" - -[[deps.LightXML]] -deps = ["Libdl", "XML2_jll"] -git-tree-sha1 = "d5d2e3abfb30ea9c2cff81d243e7235b51315ec2" -uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179" -version = "0.9.2" - -[[deps.LineSearches]] -deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] -git-tree-sha1 = "4adee99b7262ad2a1a4bbbc59d993d24e55ea96f" -uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" -version = "7.4.0" - -[[deps.LinearAlgebra]] -deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -version = "1.11.0" - -[[deps.LogExpFunctions]] -deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] -git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" -uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -version = "0.3.29" - - [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" -version = "1.11.0" - -[[deps.MKL_jll]] -deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] -git-tree-sha1 = "5de60bc6cb3899cd318d80d627560fae2e2d99ae" -uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" -version = "2025.0.1+1" - -[[deps.MPI]] -deps = ["Distributed", "DocStringExtensions", "Libdl", "MPICH_jll", "MPIPreferences", "MPItrampoline_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "PkgVersion", "PrecompileTools", "Requires", "Serialization", "Sockets"] -git-tree-sha1 = "892676019c58f34e38743bc989b0eca5bce5edc5" -uuid = "da04e1cc-30fd-572f-bb4f-1f8673147195" -version = "0.20.22" - - [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 = "d72d0ecc3f76998aac04e446547259b9ae4c265f" -uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4" -version = "4.3.1+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 = "e214f2a20bdd64c04cd3e4ff62d3c9be7e969a59" -uuid = "f1f71cc9-e9ae-5b93-9b94-4fe0e1ad3748" -version = "5.5.4+0" - -[[deps.MacroTools]] -git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" -uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.16" - -[[deps.Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" -version = "1.11.0" - -[[deps.MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.28.6+0" - -[[deps.MicrosoftMPI_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "bc95bf4149bf535c09602e3acdf950d9b4376227" -uuid = "9237b28f-5490-5468-be7b-bb81f5f5e6cf" -version = "10.1.4+3" - -[[deps.MiniQhull]] -deps = ["QhullMiniWrapper_jll"] -git-tree-sha1 = "9dc837d180ee49eeb7c8b77bb1c860452634b0d1" -uuid = "978d7f02-9e05-4691-894f-ae31a51d76ca" -version = "0.4.0" - -[[deps.Mmap]] -uuid = "a63ad114-7e13-5084-954f-fe012c677804" -version = "1.11.0" - -[[deps.MozillaCACerts_jll]] -uuid = "14a3606d-f60d-562e-9121-12d972cd8159" -version = "2023.12.12" - -[[deps.NLSolversBase]] -deps = ["ADTypes", "DifferentiationInterface", "Distributed", "FiniteDiff", "ForwardDiff"] -git-tree-sha1 = "25a6638571a902ecfb1ae2a18fc1575f86b1d4df" -uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" -version = "7.10.0" - -[[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 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" -uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "1.1.3" - -[[deps.NearestNeighbors]] -deps = ["Distances", "StaticArrays"] -git-tree-sha1 = "ca7e18198a166a1f3eb92a3650d53d94ed8ca8a1" -uuid = "b8a86587-4115-5ab1-83bc-aa920d37bbce" -version = "0.4.22" - -[[deps.NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" -version = "1.2.0" - -[[deps.OffsetArrays]] -git-tree-sha1 = "117432e406b5c023f665fa73dc26e79ec3630151" -uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.17.0" -weakdeps = ["Adapt"] - - [deps.OffsetArrays.extensions] - OffsetArraysAdaptExt = "Adapt" - -[[deps.OpenBLAS32_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "ece4587683695fe4c5f20e990da0ed7e83c351e7" -uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.29+0" - -[[deps.OpenBLAS_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] -uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.27+1" - -[[deps.OpenLibm_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.5+0" - -[[deps.OpenMPI_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML", "Zlib_jll"] -git-tree-sha1 = "ec764453819f802fc1e144bfe750c454181bd66d" -uuid = "fe0851c0-eecd-5654-98d4-656369965a5c" -version = "5.0.8+0" - -[[deps.OpenSpecFun_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1346c9208249809840c91b26703912dff463d335" -uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" -version = "0.5.6+0" - -[[deps.OrderedCollections]] -git-tree-sha1 = "05868e21324cede2207c6f0f466b4bfef6d5e7ee" -uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.8.1" - -[[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 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" -uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.8.3" - -[[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", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" -version = "1.11.0" - - [deps.Pkg.extensions] - REPLExt = "REPL" - - [deps.Pkg.weakdeps] - REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[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 = "d04bec789dce5ff61e8f128b6aee0eda09a3855f" -uuid = "c74db56a-226d-5e98-8bb0-a6049094aeea" -version = "0.4.25" - -[[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" -version = "1.11.0" - -[[deps.QhullMiniWrapper_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Qhull_jll"] -git-tree-sha1 = "607cf73c03f8a9f83b36db0b86a3a9c14179621f" -uuid = "460c41e3-6112-5d7f-b78c-b6823adb3f2d" -version = "1.0.0+1" - -[[deps.Qhull_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "b6f3ac0623e1173c006cc7377798ec3fb33fa504" -uuid = "784f63db-0788-585a-bace-daefebcd302b" -version = "8.0.1004+0" - -[[deps.QuadGK]] -deps = ["DataStructures", "LinearAlgebra"] -git-tree-sha1 = "9da16da70037ba9d701192e27befedefb91ec284" -uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" -version = "2.11.2" - - [deps.QuadGK.extensions] - QuadGKEnzymeExt = "Enzyme" - - [deps.QuadGK.weakdeps] - Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" - -[[deps.Random]] -deps = ["SHA"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -version = "1.11.0" - -[[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.Requires]] -deps = ["UUIDs"] -git-tree-sha1 = "62389eeff14780bfe55195b7204c0d8738436d64" -uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.3.1" - -[[deps.SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" -version = "0.7.0" - -[[deps.ScopedValues]] -deps = ["HashArrayMappedTries", "Logging"] -git-tree-sha1 = "1147f140b4c8ddab224c94efa9569fc23d63ab44" -uuid = "7e506255-f358-4e82-b7e4-beb19740aa63" -version = "1.3.0" - -[[deps.Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" -version = "1.11.0" - -[[deps.Setfield]] -deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"] -git-tree-sha1 = "c5391c6ace3bc430ca630251d02ea9687169ca68" -uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" -version = "1.1.2" - -[[deps.SharedArrays]] -deps = ["Distributed", "Mmap", "Random", "Serialization"] -uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" -version = "1.11.0" - -[[deps.SimpleTraits]] -deps = ["InteractiveUtils", "MacroTools"] -git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231" -uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" -version = "0.9.4" - -[[deps.SimpleUnPack]] -git-tree-sha1 = "58e6353e72cde29b90a69527e56df1b5c3d8c437" -uuid = "ce78b400-467f-4804-87d8-8f486da07d0a" -version = "1.1.0" - -[[deps.Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" -version = "1.11.0" - -[[deps.SparseArrays]] -deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -version = "1.11.0" - -[[deps.SparseMatricesCSR]] -deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "cc05d16e340aecfa0e4cf4616194abc894cd0bca" -uuid = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1" -version = "0.6.9" - -[[deps.SpecialFunctions]] -deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "41852b8679f78c8d8961eeadc8f62cef861a52e3" -uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.5.1" - - [deps.SpecialFunctions.extensions] - SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" - - [deps.SpecialFunctions.weakdeps] - ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" - -[[deps.StaticArrays]] -deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] -git-tree-sha1 = "0feb6b9031bd5c51f9072393eb5ab3efd31bf9e4" -uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.9.13" - - [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"] -git-tree-sha1 = "ae3bb1eb3bba077cd276bc5cfc337cc65c3075c0" -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -version = "1.11.1" -weakdeps = ["SparseArrays"] - - [deps.Statistics.extensions] - SparseArraysExt = ["SparseArrays"] - -[[deps.StatsAPI]] -deps = ["LinearAlgebra"] -git-tree-sha1 = "9d72a13a3f4dd3795a195ac5a44d7d6ff5f552ff" -uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.7.1" - -[[deps.SuiteSparse]] -deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] -uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" - -[[deps.SuiteSparse_jll]] -deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] -uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "7.7.0+0" - -[[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" -version = "1.11.0" - -[[deps.TranscodingStreams]] -git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742" -uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" -version = "0.11.3" - -[[deps.UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" -version = "1.11.0" - -[[deps.UnPack]] -git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" -uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" -version = "1.0.2" - -[[deps.Unicode]] -uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" -version = "1.11.0" - -[[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 = "a329e0b6310244173690d6a4dfc6d1141f9b9370" -uuid = "64499a7a-5c06-52f2-abe2-ccb03c286192" -version = "1.21.2" - -[[deps.XML2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] -git-tree-sha1 = "9380cd28f093c901600ab70e0201fb18bae226de" -uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" -version = "2.14.1+0" - -[[deps.Zlib_jll]] -deps = ["Libdl"] -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.2.13+1" - -[[deps.algoimWrapper_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "OpenBLAS32_jll", "libcxxwrap_julia_jll"] -git-tree-sha1 = "686ddc4227be075cff2ec5df1c15b8edcd32e27d" -uuid = "3c43aa7b-5398-51f3-8d75-8f051e6faa4d" -version = "0.3.1+0" - -[[deps.libblastrampoline_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.11.0+0" - -[[deps.libcxxwrap_julia_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "70091a11c756455c15bc6380ea000c16f38f2d3e" -uuid = "3eaa8342-bff7-56a5-9981-c04077f7cee7" -version = "0.13.4+0" - -[[deps.nghttp2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.59.0+0" - -[[deps.oneTBB_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "d5a767a3bb77135a99e433afe0eb14cd7f6914c3" -uuid = "1317d2d5-d96f-522e-a858-c73665f53c3e" -version = "2022.0.0+0" - -[[deps.p7zip_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" -version = "17.4.0+2" diff --git a/test/DistributedTests/AggregationTests.jl b/test/DistributedTests/AggregationTests.jl index 50a84f2f..7175232b 100644 --- a/test/DistributedTests/AggregationTests.jl +++ b/test/DistributedTests/AggregationTests.jl @@ -30,7 +30,7 @@ geo = union(geo1,geo2) n = 16 mesh_partition = (n,n) -bgmodel = CartesianDiscreteModel(ranks,np,pmin,pmax,mesh_partition;ghost=(2,2)) +bgmodel = CartesianDiscreteModel(ranks,np,pmin,pmax,mesh_partition) cutgeo = cut(bgmodel,geo) From d3d6d47d42c149c5cf5a65970cc02c2c4c32f3a3 Mon Sep 17 00:00:00 2001 From: amboschman Date: Mon, 28 Jul 2025 13:07:13 +1000 Subject: [PATCH 120/120] tidy up and outputting test case results --- bulk_ghost_penalty_canvas.jl | 127 +++++++++++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 14 deletions(-) diff --git a/bulk_ghost_penalty_canvas.jl b/bulk_ghost_penalty_canvas.jl index e44fc255..b2dd0659 100644 --- a/bulk_ghost_penalty_canvas.jl +++ b/bulk_ghost_penalty_canvas.jl @@ -122,8 +122,6 @@ vbb=get_fe_basis(Vbb) # Numerical integration (Measures) dΩbg_agg_cells = Measure(Ωbg_agg_cells,degree) -# # LHS of L2 projection on bounding boxes. - # Selecting relevant global dofs ids of aggregate cells (from background mesh) Ωbg_agg_cell_dof_ids = get_cell_dof_ids(X,Ωbg_agg_cells) U_Ωbg_agg_cell_dof_ids = _restrict_to_block(Ωbg_agg_cell_dof_ids, 1) @@ -194,7 +192,7 @@ dp_proj_Qbb, dq_proj_Qbb = setup_L2_proj_in_bb_space( identity, # operation to be applied to u and v P_agg_cells_local_dof_ids) # aggregates local dof ids for space P -div_du_proj_Vbb, div_dv_proj_Vbb = setup_L2_proj_in_bb_space( +div_du_proj_Qbb, div_dv_proj_Qbb = setup_L2_proj_in_bb_space( dΩbg_agg_cells, # measure of aggregated cells in background domain ref_agg_cell_to_ref_bb_map, # map agg_cells_to_aggregate, # @@ -271,8 +269,8 @@ w_divu_diff, r_divu_diff, c_divu_diff = bulk_ghost_penalty_stabilization_collect γ, du, dv, - div_du_proj_Vbb, - div_dv_proj_Vbb, + div_du_proj_Qbb, + div_dv_proj_Qbb, U_Ωbg_cut_cell_dof_ids, U_Ωbg_cut_cell_dof_ids, U_cut_cells_to_aggregate_dof_ids, @@ -285,7 +283,7 @@ w_divuq_diff, r_divuq_diff, c_divuq_diff = bulk_ghost_penalty_stabilization_coll γ, du, dq, - div_du_proj_Vbb, + div_du_proj_Qbb, dq_proj_Qbb, U_Ωbg_cut_cell_dof_ids, P_Ωbg_cut_cell_dof_ids, @@ -300,7 +298,7 @@ w_pdivv_diff, r_pdivv_diff, c_pdivv_diff = bulk_ghost_penalty_stabilization_coll dp, dv, dp_proj_Qbb, - div_dv_proj_Vbb, + div_dv_proj_Qbb, P_Ωbg_cut_cell_dof_ids, U_Ωbg_cut_cell_dof_ids, P_cut_cells_to_aggregate_dof_ids, @@ -340,7 +338,7 @@ w_divu_full, r_divu_full, c_divu_full = bulk_ghost_penalty_stabilization_collect γ, du, dv, - div_du_proj_Vbb, + div_du_proj_Qbb, U_Ωbg_cut_cell_dof_ids, U_Ωbg_cut_cell_dof_ids, U_cut_cells_to_aggregate_dof_ids, @@ -352,7 +350,7 @@ w_divuq_full, r_divuq_full, c_divuq_full = bulk_ghost_penalty_stabilization_coll γ, du, dq, - div_du_proj_Vbb, + div_du_proj_Qbb, U_Ωbg_cut_cell_dof_ids, P_Ωbg_cut_cell_dof_ids, U_cut_cells_to_aggregate_dof_ids, @@ -374,21 +372,32 @@ w_pdivv_full, r_pdivv_full, c_pdivv_full = bulk_ghost_penalty_stabilization_coll ########################################## ### Setup rhs stabilization ### ########################################## +rhs_func = divuex +rhs_func_proj_Qbb = setup_L2_proj_in_bb_space(dΩbg_agg_cells, + ref_agg_cell_to_ref_bb_map, + agg_cells_to_aggregate, + aggregate_to_local_cells, + rhs_func, + pbb, + qbb) + w_rhsq_diff, r_rhsq_diff = bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dΩbg_cut_cells, γ, - dq, + dq, dq_proj_Qbb, P_Ωbg_cut_cell_dof_ids, P_cut_cells_to_aggregate_dof_ids, identity, - divuex) + rhs_func, + rhs_func_proj_Qbb) w_rhsq_full, r_rhsq_full = bulk_ghost_penalty_stabilization_collect_cell_vector_on_D(dΩbg_cut_cells, γ, dq, P_Ωbg_cut_cell_dof_ids, identity, - divuex) + rhs_func, + rhs_func_proj_Qbb) ## WEAK FORM if problem==0 @@ -544,7 +553,7 @@ res_stab_p_diff res_stab_divu_full res_stab_divu_diff res_stab_pdivv_full # THIS IS OK. -res_stab_divuq_full_rhs #THIS SEEMS TO BE INCORRECT +res_stab_divuq_full_rhs # ERRORS SEEM TO BE OF SAME ORDER NOW. # Alternatives for res_stab_divuq_full_rhs res_stab_divuq_full #THIS SEEMS BETTER @@ -554,4 +563,94 @@ res_stab_divuq_diff_rhs # seems incorrect # Lastly compare these: res_stab_pdivv_full -res_stab_pdivv_diff \ No newline at end of file +res_stab_pdivv_diff + +### +# UFULL + PFULL + DIVUFULL +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], w_u_full...) +push!(wrc[2], r_u_full...) +push!(wrc[3], c_u_full...) +push!(wrc[1], w_p_full...) +push!(wrc[2], r_p_full...) +push!(wrc[3], c_p_full...) +push!(wrc[1], w_divu_full...) +push!(wrc[2], r_divu_full...) +push!(wrc[3], c_divu_full...) +A = assemble_matrix(assem, wrc) +res_stab_updivu_full = compute_quantities(problem,A,b,dΩ) #ok + +# UDIFF+ PDIFF + DIVUDIFF +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], w_u_diff...) +push!(wrc[2], r_u_diff...) +push!(wrc[3], c_u_diff...) +push!(wrc[1], w_p_diff...) +push!(wrc[2], r_p_diff...) +push!(wrc[3], c_p_diff...) +push!(wrc[1], w_divu_diff...) +push!(wrc[2], r_divu_diff...) +push!(wrc[3], c_divu_diff...) +A = assemble_matrix(assem, wrc) +res_stab_updivu_diff = compute_quantities(problem,A,b,dΩ) #ok + +# UFULL + DIVUFULL + "MIX" +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], w_u_full...) +push!(wrc[2], r_u_full...) +push!(wrc[3], c_u_full...) +push!(wrc[1], w_divu_full...) +push!(wrc[2], r_divu_full...) +push!(wrc[3], c_divu_full...) +push!(wrc[1], w_divuq_full...) +push!(wrc[2], r_divuq_full...) +push!(wrc[3], c_divuq_full...) +push!(wrc[1], w_pdivv_full...) +push!(wrc[2], r_pdivv_full...) +push!(wrc[3], c_pdivv_full...) +A = assemble_matrix(assem, wrc) +res_stab_udivumix_full = compute_quantities(problem,A,b,dΩ) + +# UDIFF + DIVUDIFF + "MIX" +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], w_u_diff...) +push!(wrc[2], r_u_diff...) +push!(wrc[3], c_u_diff...) +push!(wrc[1], w_divu_diff...) +push!(wrc[2], r_divu_diff...) +push!(wrc[3], c_divu_diff...) +A = assemble_matrix(assem, wrc) +res_stab_udivumix_rhs_diff= compute_quantities(problem,A,b_rhsq_diff,dΩ) +res_stab_udivumix_diff = compute_quantities(problem,A,b,dΩ) # this is the same for rhs_func = constant +@assert res_stab_udivumix_rhs_diff == res_stab_udivumix_diff + +# UFULL + DIVUFULL + "MIX" +wrc=Gridap.FESpaces.collect_cell_matrix(X,Y,a(dx,dy)) +push!(wrc[1], w_u_full...) +push!(wrc[2], r_u_full...) +push!(wrc[3], c_u_full...) +push!(wrc[1], w_divu_full...) +push!(wrc[2], r_divu_full...) +push!(wrc[3], c_divu_full...) +A = assemble_matrix(assem, wrc) +res_stab_udivumix_rhs_full= compute_quantities(problem,A,b_rhsq_full,dΩ) +res_stab_udivumix_full = compute_quantities(problem,A,b,dΩ) # this is the same for rhs_func = constant +@assert res_stab_udivumix_rhs_full == res_stab_udivumix_full + +## GENERATE EXCEL SHEET RESULTS`` +print("results") +res_nostab +res_stab_u_full +res_stab_u_diff +res_stab_p_full +res_stab_p_diff +res_stab_divu_full +res_stab_divu_diff +res_stab_pdivv_full # THIS IS OK. +res_stab_divuq_full_rhs # ERRORS SEEM TO BE OF SAME ORDER NOW. + +res_stab_updivu_full +res_stab_updivu_diff +res_stab_udivumix_full +res_stab_udivumix_rhs_diff +res_stab_udivumix_rhs_full \ No newline at end of file