Skip to content

Commit 49523d7

Browse files
committed
Merge branch 'master' of github.com:gridap/GridapEmbedded.jl into hdiv-stabilisation
2 parents 19735cc + 7e045af commit 49523d7

6 files changed

Lines changed: 123 additions & 30 deletions

File tree

.github/workflows/ci.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ jobs:
1515
- x64
1616
steps:
1717
- uses: actions/checkout@v6
18-
- uses: julia-actions/setup-julia@v2
18+
- uses: julia-actions/setup-julia@v3
1919
with:
2020
version: ${{ matrix.version }}
2121
arch: ${{ matrix.arch }}
22-
- uses: julia-actions/cache@v2
22+
- uses: julia-actions/cache@v3
2323
- uses: julia-actions/julia-buildpkg@v1
2424
- uses: julia-actions/julia-runtest@v1
2525
- uses: julia-actions/julia-processcoverage@v1
26-
- uses: codecov/codecov-action@v5
26+
- uses: codecov/codecov-action@v6
2727
with:
2828
file: lcov.info
2929
drivers:
@@ -40,11 +40,11 @@ jobs:
4040
- x64
4141
steps:
4242
- uses: actions/checkout@v6
43-
- uses: julia-actions/setup-julia@v2
43+
- uses: julia-actions/setup-julia@v3
4444
with:
4545
version: ${{ matrix.version }}
4646
arch: ${{ matrix.arch }}
47-
- uses: julia-actions/cache@v2
47+
- uses: julia-actions/cache@v3
4848
- uses: julia-actions/julia-buildpkg@v1
4949
- run: |
5050
julia --color=yes --project=. --check-bounds=yes --depwarn=error -e '
@@ -66,11 +66,11 @@ jobs:
6666
- x64
6767
steps:
6868
- uses: actions/checkout@v6
69-
- uses: julia-actions/setup-julia@v2
69+
- uses: julia-actions/setup-julia@v3
7070
with:
7171
version: ${{ matrix.version }}
7272
arch: ${{ matrix.arch }}
73-
- uses: julia-actions/cache@v2
73+
- uses: julia-actions/cache@v3
7474
- uses: julia-actions/julia-buildpkg@v1
7575
- run: |
7676
julia --color=yes --project=. --check-bounds=yes --depwarn=error -e '
@@ -83,7 +83,7 @@ jobs:
8383
runs-on: ubuntu-latest
8484
steps:
8585
- uses: actions/checkout@v6
86-
- uses: julia-actions/setup-julia@v2
86+
- uses: julia-actions/setup-julia@v3
8787
with:
8888
version: '1.10'
8989
- run: |

.github/workflows/ci_x86.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ jobs:
2121
- x86
2222
steps:
2323
- uses: actions/checkout@v6
24-
- uses: julia-actions/setup-julia@v2
24+
- uses: julia-actions/setup-julia@v3
2525
with:
2626
version: ${{ matrix.version }}
2727
arch: ${{ matrix.arch }}
28-
- uses: julia-actions/cache@v2
28+
- uses: julia-actions/cache@v3
2929
- uses: julia-actions/julia-buildpkg@v1
3030
- uses: julia-actions/julia-runtest@v1

NEWS.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
### Fixed
10+
11+
- Fix for issue #115, which is a bug in the logic of the `ACTIVE` mask and `GhostSkeleton` construction. Since PR [#123](https://github.com/gridap/GridapEmbedded.jl/pull/123).
12+
913
## [0.9.11] - 2026-4-28
1014

11-
- Small bugfix for empty embedded facet triangulations, following changes in Gridap v0.20.4. Since PR[#121](https://github.com/gridap/GridapEmbedded.jl/pull/121).
15+
### Fixed
16+
17+
- Small bugfix for empty embedded facet triangulations, following changes in Gridap v0.20.4. Since PR[#121](https://github.com/gridap/GridapEmbedded.jl/pull/121).
1218

1319
## [0.9.10] - 2026-3-24
1420

src/Interfaces/EmbeddedDiscretizations.jl

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,42 @@ function Triangulation(cut::EmbeddedDiscretization,in_or_out::Integer,geo::CSG.G
316316
Triangulation(cut.bgmodel,cell_to_mask)
317317
end
318318

319+
function compute_bgcell_to_active_inoutcut(
320+
cut::EmbeddedDiscretization, in_or_out, geo::CSG.Geometry
321+
)
322+
compute_bgcell_to_active_inoutcut(cut, in_or_out.in_or_out, geo)
323+
end
324+
325+
# Deals with the phantom cut issue (see Issue #115)
326+
function compute_bgcell_to_active_inoutcut(
327+
cut::EmbeddedDiscretization, in_or_out::Integer, geo::CSG.Geometry
328+
)
329+
@check in_or_out in (IN,OUT,CUT)
330+
331+
bgcell_to_inoutcut = compute_bgcell_to_inoutcut(cut, geo)
332+
if in_or_out == CUT
333+
# CUT cells are always genuinely cut (no phantom issue), so no filtering needed
334+
return bgcell_to_inoutcut
335+
end
336+
337+
subcell_to_inout = compute_subcell_to_inout(cut, geo)
338+
subcell_to_bgcell = cut.subcells.cell_to_bgcell
339+
340+
keep = isequal(in_or_out)
341+
bgcell_to_true_cut = fill(false, length(bgcell_to_inoutcut))
342+
for (bgcell,io) in zip(subcell_to_bgcell, subcell_to_inout)
343+
bgcell_to_true_cut[bgcell] |= keep(io)
344+
end
345+
346+
out = -Int8(in_or_out) # IN → OUT, OUT → IN
347+
map(bgcell_to_inoutcut, bgcell_to_true_cut) do ioc, is_true_cut
348+
ifelse(ioc == CUT, ifelse(is_true_cut, ioc, out), ioc)
349+
end
350+
end
351+
319352
function Triangulation(cut::EmbeddedDiscretization,in_or_out::ActiveInOrOut,geo::CSG.Geometry)
320-
cell_to_inoutcut = compute_bgcell_to_inoutcut(cut,geo)
321-
cell_to_mask = lazy_map(i-> i==CUT || i==in_or_out.in_or_out,cell_to_inoutcut)
353+
cell_to_inoutcut = compute_bgcell_to_active_inoutcut(cut, in_or_out, geo)
354+
cell_to_mask = map(i -> i==CUT || i==in_or_out.in_or_out, cell_to_inoutcut)
322355
Triangulation(cut.bgmodel,cell_to_mask)
323356
end
324357

@@ -486,40 +519,37 @@ function GhostSkeleton(cut::EmbeddedDiscretization,geo::CSG.Geometry)
486519
GhostSkeleton(cut,ACTIVE_IN,geo)
487520
end
488521

489-
#function GhostSkeleton(cut::EmbeddedDiscretization,name::String,in_or_out)
490-
# GhostSkeleton(cut,in_or_out,name)
491-
#end
492-
#
493-
#function GhostSkeleton(cut::EmbeddedDiscretization,geo::CSG.Geometry,in_or_out)
494-
# GhostSkeleton(cut,in_or_out,geo)
495-
#end
496-
497522
function GhostSkeleton(cut::EmbeddedDiscretization,in_or_out,name::String)
498523
geo = get_geometry(cut.geo,name)
499524
GhostSkeleton(cut,in_or_out,geo)
500525
end
501526

502-
GhostSkeleton(cut::EmbeddedDiscretization,in_or_out::Integer,geo::CSG.Geometry) = GhostSkeleton(cut,ActiveInOrOut(in_or_out),geo)
527+
function GhostSkeleton(cut::EmbeddedDiscretization,in_or_out::Integer,geo::CSG.Geometry)
528+
GhostSkeleton(cut,ActiveInOrOut(in_or_out),geo)
529+
end
503530

504531
function GhostSkeleton(cut::EmbeddedDiscretization,in_or_out,geo::CSG.Geometry)
505-
506-
@notimplementedif in_or_out in (PHYSICAL_IN,PHYSICAL_OUT) "Not implemented but not needed in practice. Ghost stabilization can be integrated in full facets."
532+
@notimplementedif in_or_out in (PHYSICAL_IN,PHYSICAL_OUT) """
533+
Not implemented but not needed in practice. Ghost stabilization can be integrated in full facets.
534+
"""
507535
@assert in_or_out in (ACTIVE_IN,ACTIVE_OUT) || in_or_out.in_or_out in (IN,OUT,CUT)
508-
cell_to_inoutcut = compute_bgcell_to_inoutcut(cut,geo)
536+
509537
model = cut.bgmodel
510538
topo = get_grid_topology(model)
511539
D = num_cell_dims(model)
540+
541+
cell_to_inoutcut = compute_bgcell_to_active_inoutcut(cut, in_or_out, geo)
512542
facet_to_cells = Table(get_faces(topo,D-1,D))
513543
facet_to_mask = fill(false,length(facet_to_cells))
514544
_fill_ghost_skeleton_mask!(facet_to_mask,facet_to_cells,cell_to_inoutcut,in_or_out.in_or_out)
515545

516546
SkeletonTriangulation(model,facet_to_mask)
517547
end
518548

519-
function _fill_ghost_skeleton_mask!(facet_to_mask,facet_to_cells::Table,cell_to_inoutcut,in_or_out)
520-
521-
nfacets = length(facet_to_cells)
522-
for facet in 1:nfacets
549+
function _fill_ghost_skeleton_mask!(
550+
facet_to_mask,facet_to_cells::Table,cell_to_inoutcut,in_or_out
551+
)
552+
for facet in eachindex(facet_to_cells)
523553
a = facet_to_cells.ptrs[facet]
524554
b = facet_to_cells.ptrs[facet+1]
525555
ncells_around = b-a
@@ -539,5 +569,4 @@ function _fill_ghost_skeleton_mask!(facet_to_mask,facet_to_cells::Table,cell_to_
539569
facet_to_mask[facet] = true
540570
end
541571
end
542-
543572
end

test/InterfacesTests/issue_115.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Tests for the fix to issue #115:
2+
# https://github.com/gridap/GridapEmbedded.jl/issues/115
3+
#
4+
# When a compound CSG geometry (e.g. setdiff) is used, the conservative cell-level
5+
# classification can mark background cells as CUT even when no physical subcell of
6+
# the target domain lies in them. Before the fix, Triangulation(ACTIVE) and
7+
# GhostSkeleton would include these phantom cells, producing isolated elements.
8+
9+
module Issue115Tests
10+
11+
using Test
12+
using Gridap
13+
using Gridap.Geometry
14+
using Gridap.Adaptivity
15+
using GridapEmbedded
16+
using GridapEmbedded.LevelSetCutters
17+
18+
n = 12
19+
base_model = UnstructuredDiscreteModel(CartesianDiscreteModel((0,1,0,1),(n,n)))
20+
ref_model = refine(base_model, refinement_method = "barycentric")
21+
model = get_model(ref_model)
22+
23+
# Two concentric circles: φ1 (radius r1=0.3), φ2 (radius r2 < r1 → empty setdiff)
24+
r1 = 0.3
25+
r2 = r1 - 0.5/n # r2 < r1: Ω2 = setdiff(inside φ2, inside φ1) is geometrically empty
26+
φ1((x,y)) = (x-0.5)^2 + (y-0.5)^2 - r1^2
27+
φ2((x,y)) = (x-0.5)^2 + (y-0.5)^2 - r2^2
28+
29+
V_φ = TestFESpace(model, ReferenceFE(lagrangian,Float64,1))
30+
φh1 = interpolate(φ1, V_φ)
31+
φh2 = interpolate(φ2, V_φ)
32+
33+
geo1 = DiscreteGeometry(φh1, model, name="geo1")
34+
geo2 = DiscreteGeometry(φh2, model, name="geo2")
35+
Ω1_geo = setdiff(!geo1, geo2, name="Ω1") # ring outside φ2 and inside φ1 (non-empty)
36+
Ω2_geo = setdiff(geo2, geo1, name="Ω2") # inside φ2 and outside φ1 (empty, r2 < r1)
37+
cutgeo = cut(model, union(Ω1_geo, Ω2_geo))
38+
39+
# Empty domain: ACTIVE triangulation must contain no cells
40+
Ω2_act = Triangulation(cutgeo, ACTIVE, "Ω2")
41+
@test num_cells(Ω2_act) == 0
42+
43+
# Empty domain: GhostSkeleton must contain no facets
44+
Λ2 = GhostSkeleton(cutgeo, ACTIVE_IN, "Ω2")
45+
@test num_cells(Λ2) == 0
46+
47+
# Non-empty domain Ω1 must be unaffected
48+
Ω1_act = Triangulation(cutgeo, ACTIVE, "Ω1")
49+
@test num_cells(Ω1_act) > 0
50+
51+
Λ1 = GhostSkeleton(cutgeo, ACTIVE_IN, "Ω1")
52+
@test num_cells(Λ1) > 0
53+
54+
end # module

test/InterfacesTests/runtests.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ using Test
1212

1313
@testset "Cutters" begin include("CuttersTests.jl") end
1414

15+
@testset "Issue Reproducers" begin
16+
@testset "Issue115" begin include("issue_115.jl") end
17+
end
18+
1519
end # module

0 commit comments

Comments
 (0)