Skip to content

Commit 19bed4d

Browse files
authored
Merge pull request #112 from zjwegert/fix-diff_trian-multifield
Add missing update_trian! method for MultiField
2 parents b596a9a + 96f4d97 commit 19bed4d

File tree

7 files changed

+102
-47
lines changed

7 files changed

+102
-47
lines changed

NEWS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [0.9.8] - 2025-7-10
8+
9+
### Added
10+
11+
- Added missing update_trian! method for MultiField. Since PR[#112](https://github.com/gridap/GridapEmbedded.jl/pull/112).
12+
13+
### Fixed
14+
15+
- Fixed failed precompilation due to Gridap v0.19.2. Since PR[#112](https://github.com/gridap/GridapEmbedded.jl/pull/112).
16+
717
## [0.9.7] - 2025-6-11
818

919
### Added

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "GridapEmbedded"
22
uuid = "8838a6a3-0006-4405-b874-385995508d5d"
33
authors = ["Francesc Verdugo <[email protected]>", "Eric Neiva <[email protected]>", "Pere Antoni Martorell <[email protected]>", "Santiago Badia <[email protected]>"]
4-
version = "0.9.7"
4+
version = "0.9.8"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"

src/Interfaces/CutFaceBoundaryTriangulations.jl

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -395,38 +395,38 @@ end
395395

396396
############################################################################################
397397
# This will go to Gridap
398-
399-
function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField})
400-
plus = k(a.plus)
401-
minus = k(a.minus)
402-
SkeletonPair(plus,minus)
403-
end
404-
405-
function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField})
406-
plus = k(a.plus,b.plus)
407-
minus = k(a.minus,b.minus)
408-
SkeletonPair(plus,minus)
409-
end
410-
411-
import Gridap.TensorValues: inner, outer
412-
import LinearAlgebra: dot
413-
import Base: abs, *, +, -, /
414-
415-
for op in (:/,)
416-
@eval begin
417-
($op)(a::CellField,b::SkeletonPair{<:CellField}) = Operation($op)(a,b)
418-
($op)(a::SkeletonPair{<:CellField},b::CellField) = Operation($op)(a,b)
419-
end
420-
end
421-
422-
for op in (:outer,:*,:dot,:/)
423-
@eval begin
424-
($op)(a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField}) = Operation($op)(a,b)
425-
end
426-
end
427-
428-
function CellData.change_domain(a::SkeletonPair, ::ReferenceDomain, ::PhysicalDomain)
429-
plus = change_domain(a.plus,ReferenceDomain(),PhysicalDomain())
430-
minus = change_domain(a.minus,ReferenceDomain(),PhysicalDomain())
431-
return SkeletonPair(plus,minus)
432-
end
398+
#
399+
# function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField})
400+
# plus = k(a.plus)
401+
# minus = k(a.minus)
402+
# SkeletonPair(plus,minus)
403+
# end
404+
405+
# function Arrays.evaluate!(cache,k::Operation,a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField})
406+
# plus = k(a.plus,b.plus)
407+
# minus = k(a.minus,b.minus)
408+
# SkeletonPair(plus,minus)
409+
# end
410+
411+
# import Gridap.TensorValues: inner, outer
412+
# import LinearAlgebra: dot
413+
# import Base: abs, *, +, -, /
414+
415+
# for op in (:/,)
416+
# @eval begin
417+
# ($op)(a::CellField,b::SkeletonPair{<:CellField}) = Operation($op)(a,b)
418+
# ($op)(a::SkeletonPair{<:CellField},b::CellField) = Operation($op)(a,b)
419+
# end
420+
# end
421+
422+
# for op in (:outer,:*,:dot,:/)
423+
# @eval begin
424+
# ($op)(a::SkeletonPair{<:CellField},b::SkeletonPair{<:CellField}) = Operation($op)(a,b)
425+
# end
426+
# end
427+
428+
# function CellData.change_domain(a::SkeletonPair, ::ReferenceDomain, ::PhysicalDomain)
429+
# plus = change_domain(a.plus,ReferenceDomain(),PhysicalDomain())
430+
# minus = change_domain(a.minus,ReferenceDomain(),PhysicalDomain())
431+
# return SkeletonPair(plus,minus)
432+
# end

src/LevelSetCutters/DifferentiableTriangulations.jl

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ methods to compute derivatives w.r.t. deformations of the embedded mesh.
1010
To do so, it propagates dual numbers into the geometric maps mapping cut subcells/subfacets
1111
to the background mesh.
1212
13-
## Constructor:
13+
## Constructor:
1414
1515
DifferentiableTriangulation(trian::Triangulation,fe_space::FESpace)
1616
17-
where `trian` must be an embedded triangulation and `fe_space` is the `FESpace` where
17+
where `trian` must be an embedded triangulation and `fe_space` is the `FESpace` where
1818
the level-set function lives.
1919
2020
"""
@@ -63,6 +63,18 @@ function update_trian!(trian::DifferentiableTriangulation,::FESpace,::Nothing)
6363
return trian
6464
end
6565

66+
const MultiFieldSpaceTypes = Union{<:MultiFieldFESpace,<:DistributedMultiFieldFESpace}
67+
68+
function update_trian!(trian::DifferentiableTriangulation,space::MultiFieldSpaceTypes,φh)
69+
map((Ui,φi)->update_trian!(trian,Ui,φi),space,φh)
70+
return trian
71+
end
72+
73+
function update_trian!(trian::DifferentiableTriangulation,::MultiFieldSpaceTypes,::Nothing)
74+
trian.cell_values = nothing
75+
return trian
76+
end
77+
6678
# Autodiff
6779

6880
function FESpaces._change_argument(
@@ -424,8 +436,8 @@ function extract_dualized_cell_values(
424436
end
425437

426438
# TriangulationView
427-
# This is mostly used in distributed, where we remove ghost cells by taking a view
428-
# of the local triangulations.
439+
# This is mostly used in distributed, where we remove ghost cells by taking a view
440+
# of the local triangulations.
429441

430442
const DifferentiableTriangulationView{Dc,Dp} = Geometry.TriangulationView{Dc,Dp,<:DifferentiableTriangulation}
431443

@@ -465,7 +477,7 @@ end
465477
# We only need to propagate the dual numbers to the CUT cells, which is what the
466478
# following implementation does:
467479

468-
const DifferentiableAppendedTriangulation{Dc,Dp,A} =
480+
const DifferentiableAppendedTriangulation{Dc,Dp,A} =
469481
AppendedTriangulation{Dc,Dp,<:Union{<:DifferentiableTriangulation,<:DifferentiableTriangulationView{Dc,Dp}}}
470482

471483
function DifferentiableTriangulation(

src/LevelSetCutters/LevelSetCutters.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ using Gridap.CellData
3131
using Gridap.Polynomials
3232
using Gridap.Visualization
3333
using Gridap.FESpaces
34+
using Gridap.MultiField
35+
36+
using GridapDistributed: DistributedMultiFieldFESpace
3437

3538
export LevelSetCutter
3639
export AnalyticalGeometry

test/DistributedTests/GeometricalDifferentiationTests.jl

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module DistributedGeometricalDifferentitationTests
22
############################################################################################
3-
# These tests are meant to verify the correctness differentiation of functionals w.r.t the
4-
# level set defining the cut domain.
3+
# These tests are meant to verify the correctness differentiation of functionals w.r.t the
4+
# level set defining the cut domain.
55
# They are based on the following work:
66
# "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation"
77
# by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis (2025)
@@ -117,6 +117,19 @@ function main_generic(
117117

118118
@test norm(dJ_bulk_1_AD_in_u_vec - dJ_bulk_1_exact_in_u_vec) < 1e-10
119119

120+
# Multifield case
121+
U = TestFESpace(model,reffe)
122+
V_φu = MultiFieldFESpace([V_φ,U])
123+
φuh = interpolate([φh,x->x[1]],V_φu)
124+
J_bulk_mult((φ,u)) = (fh)dΩ
125+
dJ_bulk_AD = gradient(J_bulk_mult,φuh)
126+
dJ_bulk_AD_vec = assemble_vector(dJ_bulk_AD,V_φu)
127+
128+
dJ_bulk_exact_mult((dφ,du)) = (-fh*/(abs(n_Γ (φh))))dΓ
129+
dJ_bulk_exact_vec = assemble_vector(dJ_bulk_exact_mult,V_φu)
130+
131+
@test norm(dJ_bulk_AD_vec - dJ_bulk_exact_vec) < 1e-10
132+
120133
# A.2) Volume integral
121134

122135
g(fh) = (fh)(fh)

test/LevelSetCuttersTests/GeometricalDifferentiationTests.jl

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
module GeometricalDifferentiationTests
22
############################################################################################
3-
# These tests are meant to verify the correctness differentiation of functionals w.r.t the
4-
# level set defining the cut domain.
3+
# These tests are meant to verify the correctness differentiation of functionals w.r.t the
4+
# level set defining the cut domain.
55
# They are based on the following work:
66
# "Level-set topology optimisation with unfitted finite elements and automatic shape differentiation"
77
# by Z. J. Wegert, J. Manyer, C. Mallon, S. Badia, V. J. Challis (2025)
88
############################################################################################
99
using Test, FiniteDiff
1010

11-
using Gridap, Gridap.Geometry, Gridap.Adaptivity, Gridap.Arrays
11+
using Gridap, Gridap.Geometry, Gridap.Adaptivity, Gridap.Arrays, Gridap.MultiField
1212
using GridapEmbedded, GridapEmbedded.LevelSetCutters, GridapEmbedded.Interfaces
1313

1414
using GridapEmbedded.Interfaces: get_conormal_vector
@@ -17,7 +17,7 @@ using GridapEmbedded.Interfaces: get_ghost_normal_vector
1717

1818
using GridapEmbedded.LevelSetCutters: DifferentiableTriangulation
1919

20-
# We general a simplicial model where the simplices are created in a symmetric way using
20+
# We general a simplicial model where the simplices are created in a symmetric way using
2121
# varycentric refinement of QUADs and HEXs.
2222
function generate_model(D,n)
2323
domain = (D==2) ? (0,1,0,1) : (0,1,0,1,0,1)
@@ -124,6 +124,23 @@ function main(
124124

125125
@test abs_error < 1e-10
126126

127+
# Multifield case
128+
U = TestFESpace(model,reffe)
129+
V_φu = MultiFieldFESpace([V_φ,U])
130+
φuh = interpolate([φh,x->x[1]],V_φu)
131+
J_bulk_mult((φ,u)) = (fh)dΩ
132+
dJ_bulk_AD = gradient(J_bulk_mult,φuh)
133+
dJ_bulk_AD_vec = assemble_vector(dJ_bulk_AD,V_φu)
134+
135+
dJ_bulk_exact_mult((dφ,du)) = (-fh*/(abs(n_Γ (φh))))dΓ
136+
dJ_bulk_exact_vec = assemble_vector(dJ_bulk_exact_mult,V_φu)
137+
138+
abs_error = norm(dJ_bulk_AD_vec - dJ_bulk_exact_vec,Inf)
139+
if verbose
140+
println(" - norm(dJ_AD - dJ_exact,Inf) = ",abs_error," | Multifield test")
141+
end
142+
@test abs_error < 1e-10
143+
127144
# A.1.1) Volume integral with another field
128145

129146
J_bulk_1(u,φ) = (u+fh)dΩ

0 commit comments

Comments
 (0)