diff --git a/src/Distributed/Distributed.jl b/src/Distributed/Distributed.jl index c68af9a..ee2ea62 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 PartitionedArrays: VectorFromDict @@ -27,6 +28,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, testitem, return_type using Gridap.FESpaces: FESpaceWithLinearConstraints using Gridap.FESpaces: _dof_to_DOF, _DOF_to_dof using GridapDistributed: DistributedDiscreteModel @@ -47,6 +49,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, DiscreteGeometry import Gridap.Geometry: Triangulation import Gridap.Geometry: SkeletonTriangulation import Gridap.Geometry: BoundaryTriangulation @@ -56,6 +59,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 0000000..935e3b9 --- /dev/null +++ b/src/Distributed/DistributedDiscreteGeometries.jl @@ -0,0 +1,144 @@ +struct DistributedDiscreteGeometry{A} <: GridapType + geometries::A +end + +local_views(a::DistributedDiscreteGeometry) = a.geometries + +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))) + 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(loc_φ,point_to_coords;name) + 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 08816f3..9ae968c 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/src/LevelSetCutters/DiscreteGeometries.jl b/src/LevelSetCutters/DiscreteGeometries.jl index 5289299..23d8cbe 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) + 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) 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 diff --git a/src/LevelSetCutters/LevelSetCutters.jl b/src/LevelSetCutters/LevelSetCutters.jl index aa5b147..ac7caf5 100644 --- a/src/LevelSetCutters/LevelSetCutters.jl +++ b/src/LevelSetCutters/LevelSetCutters.jl @@ -22,12 +22,14 @@ 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 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 0000000..26b34ba --- /dev/null +++ b/test/AgFEMTests/PeriodicAgFEMSpacesTests.jl @@ -0,0 +1,67 @@ +module PeriodicAgFEMSpacesTests + +using Test +using Gridap +using GridapEmbedded +using Gridap.Geometry: get_active_model + +const R = 0.55 +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 = 1 + +# 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-7 +@test sum( ∫(abs2(v-vhagg))dΩ ) < tol +@test sum( ∫(abs2(v-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-7 +@test sum( ∫(abs2(v-vhagg))dΩ ) < tol +@test sum( ∫(abs2(v-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 9d03917..66d7f07 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/DistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 0000000..10a9959 --- /dev/null +++ b/test/DistributedTests/DistributedDiscreteGeometryPoissonTest.jl @@ -0,0 +1,143 @@ +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 + +end # module \ No newline at end of file diff --git a/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/DistributedLSDiscreteGeometryPoissonTest.jl new file mode 100644 index 0000000..68bbf39 --- /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/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/PeriodicDistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 0000000..26cde8c --- /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/sequential/DistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 0000000..080d4b9 --- /dev/null +++ b/test/DistributedTests/sequential/DistributedDiscreteGeometryPoissonTest.jl @@ -0,0 +1,8 @@ +module DistributedDiscreteGeometryPoissonTestsSeq +using PartitionedArrays +include("../DistributedDiscreteGeometryPoissonTest.jl") +with_debug() do distribute + DistributedDiscreteGeometryPoissonTest.main(distribute,(2,2)) + DistributedDiscreteGeometryPoissonTest.main(distribute,(4,1),cells=(12,12),geometry=:remotes) +end +end diff --git a/test/DistributedTests/sequential/DistributedLSDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/DistributedLSDiscreteGeometryPoissonTest.jl new file mode 100644 index 0000000..afdba27 --- /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/PeriodicDistributedDiscreteGeometryPoissonTest.jl b/test/DistributedTests/sequential/PeriodicDistributedDiscreteGeometryPoissonTest.jl new file mode 100644 index 0000000..7802ba3 --- /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 e68831c..57910a8 100644 --- a/test/DistributedTests/sequential/runtests.jl +++ b/test/DistributedTests/sequential/runtests.jl @@ -3,5 +3,10 @@ module SequentialTests 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 + +## 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 0000000..0ce321e --- /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 1576bc4..f6d52df 100644 --- a/test/GridapEmbeddedTests/runtests.jl +++ b/test/GridapEmbeddedTests/runtests.jl @@ -6,6 +6,8 @@ using Test @time @testset "PoissonAgFEM" begin include("PoissonAgFEMTests.jl") end +@time @testset "PeriodicPoissonAgFEM" begin include("PeriodicPoissonAgFEMTests.jl") end + @time @testset "PoissonModalC0AgFEM" begin include("PoissonModalC0AgFEMTests.jl") end @time @testset "BimaterialPoissonCutFEM" begin include("BimaterialPoissonCutFEMTests.jl") end diff --git a/test/LevelSetCuttersTests/DiscreteGeometriesTests.jl b/test/LevelSetCuttersTests/DiscreteGeometriesTests.jl index 5a7479e..f246c2e 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