Skip to content

Commit add5f00

Browse files
Merge pull request #886 from gridap/refinement-rule-subface-glue
Set of improvements/fixes in Gridap.Adaptivity module
2 parents 6ce09af + 39e0175 commit add5f00

12 files changed

+754
-105
lines changed

NEWS.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Jacobi polynomial bases. Since PR [#896](https://github.com/gridap/Gridap.jl/pull/896).
13-
1413
- Replaced newest vertex bisection mesh adaptation in
1514
`src/Geometry/NewestVertexBisection.jl` with appropriate changes to
16-
`src/Adaptivity/EdgeBasedRefinement.jl`. see PR
15+
`src/Adaptivity/EdgeBasedRefinement.jl`. Since PR
1716
[#901](https://github.com/gridap/Gridap.jl/pull/901).
17+
- When refining `DiscreteModels`, the `FaceLabeling` of the resulting `AdaptedDiscreteModel` will now correctly inhering the tags of the parent model. This has been made possible by the addition of the method `get_d_to_face_to_parent_face`. Since PR[#886](https://github.com/gridap/Gridap.jl/pull/886).
18+
- Added support for mixed adaptivity (i.e coarsening and refining), as well as non-conforming adaptivity. Since PR[#886](https://github.com/gridap/Gridap.jl/pull/886).
1819

1920
### Changed
2021

@@ -26,9 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2627
- Fixed the method `get_normal_vector` for `AdaptedTriangulation`. The method `get_facet_normal`
2728
was using default, it's now using the spetialized implementation for the underlying triangulation type.
2829
Since PR [#884](https://github.com/gridap/Gridap.jl/pull/884).
29-
3030
- Fixed `cell_dof_ids` for the case of vectorial `ConstantFESpace`. Since PR [#888](https://github.com/gridap/Gridap.jl/pull/888)
3131
- Fixed generation of Modal C0 bases for Julia 1.9. Since PR [#918](https://github.com/gridap/Gridap.jl/pull/918).
32+
- Fixed some edge cases for `change_domain` between `AdaptedTriangulations` where inneficient coordinate transformations would be applied between physical and reference domains. Since PR[#886](https://github.com/gridap/Gridap.jl/pull/886).
33+
- Fixed: Domain limits can now be of any type (notably, floats) when refining `CartesianDiscreteModels`. Since PR[#886](https://github.com/gridap/Gridap.jl/pull/886).
3234

3335
## [0.17.17] - 2023-02-24
3436

src/Adaptivity/AdaptedDiscreteModels.jl

+23-9
Original file line numberDiff line numberDiff line change
@@ -103,24 +103,31 @@ function refine(model::CartesianDiscreteModel{Dc}, cell_partition::Tuple) where
103103
desc = Geometry.get_cartesian_descriptor(model)
104104
nC = desc.partition
105105

106-
# Refined model
107-
domain = _get_cartesian_domain(desc)
108-
model_ref = CartesianDiscreteModel(domain,cell_partition.*nC)
109-
110-
# Glue
106+
# Refinement Glue
111107
f2c_cell_map, fcell_to_child_id = _create_cartesian_f2c_maps(nC,cell_partition)
112-
faces_map = [(d==Dc) ? f2c_cell_map : Int[] for d in 0:Dc]
113-
reffe = LagrangianRefFE(Float64,first(get_polytopes(model)),1)
114-
rrules = RefinementRule(reffe,cell_partition)
108+
faces_map = [(d==Dc) ? f2c_cell_map : Int[] for d in 0:Dc]
109+
reffe = LagrangianRefFE(Float64,first(get_polytopes(model)),1)
110+
rrules = RefinementRule(reffe,cell_partition)
115111
glue = AdaptivityGlue(faces_map,fcell_to_child_id,rrules)
116112

113+
# Refined model
114+
domain = _get_cartesian_domain(desc)
115+
_model_ref = CartesianDiscreteModel(domain,cell_partition.*nC)
116+
117+
# Propagate face labels
118+
coarse_labels = get_face_labeling(model)
119+
coarse_topo = get_grid_topology(model)
120+
fine_topo = get_grid_topology(_model_ref)
121+
fine_labels = _refine_face_labeling(coarse_labels,glue,coarse_topo,fine_topo)
122+
123+
model_ref = CartesianDiscreteModel(get_grid(_model_ref),fine_topo,fine_labels)
117124
return AdaptedDiscreteModel(model_ref,model,glue)
118125
end
119126

120127
function _get_cartesian_domain(desc::CartesianDescriptor{D}) where D
121128
origin = desc.origin
122129
corner = origin + VectorValue(desc.sizes .* desc.partition)
123-
domain = Vector{Int}(undef,2*D)
130+
domain = Vector{eltype(origin)}(undef,2*D)
124131
for d in 1:D
125132
domain[d*2-1] = origin[d]
126133
domain[d*2] = corner[d]
@@ -159,3 +166,10 @@ end
159166
return f2c_map, child_map
160167
end)
161168
end
169+
170+
function get_d_to_fface_to_cface(model::AdaptedDiscreteModel)
171+
ftopo = get_grid_topology(get_model(model))
172+
ctopo = get_grid_topology(get_parent(model))
173+
glue = get_adaptivity_glue(model)
174+
return get_d_to_fface_to_cface(glue,ctopo,ftopo)
175+
end

src/Adaptivity/AdaptedTriangulations.jl

+37-5
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,14 @@ end
183183

184184
for sdomain in [:ReferenceDomain,:PhysicalDomain]
185185
for (stype,ttype) in [(:AdaptedTriangulation,:AdaptedTriangulation),(:AdaptedTriangulation,:Triangulation),(:Triangulation,:AdaptedTriangulation)]
186+
sstrian = (stype==:AdaptedTriangulation) ? :(strian.trian) : :(strian)
187+
tttrian = (ttype==:AdaptedTriangulation) ? :(ttrian.trian) : :(ttrian)
186188
@eval begin
187-
function CellData.change_domain(a::CellField,strian::$stype,::$sdomain,ttrian::$ttype,::PhysicalDomain)
189+
function CellData.change_domain(a::CellField,strian::$stype,sd::$sdomain,ttrian::$ttype,::PhysicalDomain)
190+
if (get_background_model(strian) === get_background_model(ttrian))
191+
return change_domain(a,$sstrian,sd,$tttrian,PhysicalDomain())
192+
end
193+
188194
a_ref = change_domain(a,ReferenceDomain())
189195
atrian = change_domain(a_ref,strian,ReferenceDomain(),ttrian,ReferenceDomain())
190196
return change_domain(atrian,PhysicalDomain())
@@ -281,11 +287,36 @@ function change_domain_o2n(f_coarse,ctrian::Triangulation{Dc},ftrian::AdaptedTri
281287

282288
return CellData.similar_cell_field(f_coarse,f_fine,ftrian,ReferenceDomain())
283289
else
284-
f_fine = Fill(Gridap.Fields.ConstantField(0.0),num_cells(ftrian))
290+
f_fine = Fill(Fields.ConstantField(0.0),num_cells(ftrian))
285291
return CellData.similar_cell_field(f_coarse,f_fine,ftrian,ReferenceDomain())
286292
end
287293
end
288294

295+
function change_domain_o2n(
296+
f_old,
297+
old_trian::Triangulation{Dc},
298+
new_trian::AdaptedTriangulation,
299+
glue::AdaptivityGlue{<:MixedGlue}) where {Dc}
300+
301+
oglue = get_glue(old_trian,Val(Dc))
302+
nglue = get_glue(new_trian,Val(Dc))
303+
304+
@notimplementedif num_point_dims(old_trian) != Dc
305+
@notimplementedif isa(nglue,Nothing)
306+
307+
if (num_cells(old_trian) != 0)
308+
# If mixed refinement/coarsening, then f_c2f is a Table
309+
f_old_data = CellData.get_data(f_old)
310+
f_c2f = c2f_reindex(f_old_data,glue)
311+
new_rrules = get_new_cell_refinement_rules(glue)
312+
field_array = lazy_map(OldToNewField, f_c2f, new_rrules, glue.n2o_cell_to_child_id)
313+
return CellData.similar_cell_field(f_old,field_array,new_trian,ReferenceDomain())
314+
else
315+
f_new = Fill(Fields.ConstantField(0.0),num_cells(new_trian))
316+
return CellData.similar_cell_field(f_old,f_new,new_trian,ReferenceDomain())
317+
end
318+
end
319+
289320
"""
290321
Given a AdaptivityGlue and a CellField defined on the child(new) mesh,
291322
returns an equivalent CellField on the parent(old) mesh.
@@ -310,16 +341,17 @@ function change_domain_n2o(f_fine,ftrian::AdaptedTriangulation{Dc},ctrian::Trian
310341
# f_c2f[i_coarse] = [f_fine[i_fine_1], ..., f_fine[i_fine_nChildren]]
311342
f_c2f = f2c_reindex(fine_mface_to_field,glue)
312343

313-
rrules = get_old_cell_refinement_rules(glue)
314-
coarse_mface_to_field = lazy_map(FineToCoarseField,f_c2f,rrules)
344+
child_ids = f2c_reindex(glue.n2o_cell_to_child_id,glue)
345+
rrules = get_old_cell_refinement_rules(glue)
346+
coarse_mface_to_field = lazy_map(FineToCoarseField,f_c2f,rrules,child_ids)
315347

316348
### Old Model -> Old Triangulation
317349
coarse_tface_to_field = lazy_map(Reindex(coarse_mface_to_field),cglue.tface_to_mface)
318350
f_coarse = lazy_map(Broadcasting(),coarse_tface_to_field,cglue.tface_to_mface_map)
319351

320352
return CellData.similar_cell_field(f_fine,f_coarse,ctrian,ReferenceDomain())
321353
else
322-
f_coarse = Fill(Gridap.Fields.ConstantField(0.0),num_cells(fcoarse))
354+
f_coarse = Fill(Fields.ConstantField(0.0),num_cells(fcoarse))
323355
return CellData.similar_cell_field(f_fine,f_coarse,ctrian,ReferenceDomain())
324356
end
325357
end

src/Adaptivity/Adaptivity.jl

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export change_domain, move_contributions
4242

4343
include("RefinementRules.jl")
4444
include("FineToCoarseFields.jl")
45+
include("OldToNewFields.jl")
4546
include("FineToCoarseReferenceFEs.jl")
4647
include("AdaptivityGlues.jl")
4748
include("AdaptedDiscreteModels.jl")

src/Adaptivity/AdaptivityGlues.jl

+137-3
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@ struct AdaptivityGlue{GT,Dc,A,B,C,D,E} <: GridapType
2222
is_refined :: E
2323

2424
function AdaptivityGlue(n2o_faces_map::Vector{<:Union{AbstractVector{<:Integer},Table{<:Integer}}},
25-
n2o_cell_to_child_id::AbstractVector{<:Integer},
25+
n2o_cell_to_child_id::Union{AbstractVector{<:Integer},Table{<:Integer}},
2626
refinement_rules::AbstractVector{<:RefinementRule})
2727
Dc = length(n2o_faces_map)-1
2828
is_refined = select_refined_cells(n2o_faces_map[Dc+1])
2929
o2n_faces_map = get_o2n_faces_map(n2o_faces_map[Dc+1])
3030

3131
GT = all(is_refined) ? RefinementGlue : MixedGlue
32+
if isa(GT(),RefinementGlue)
33+
@assert isa(n2o_faces_map,Vector{<:AbstractVector{<:Integer}})
34+
@assert isa(n2o_cell_to_child_id,AbstractVector{<:Integer})
35+
else
36+
@assert isa(n2o_faces_map,Vector{<:Table{<:Integer}})
37+
@assert isa(n2o_cell_to_child_id,Table{<:Integer})
38+
end
3239

3340
A = typeof(n2o_faces_map)
3441
B = typeof(n2o_cell_to_child_id)
@@ -67,7 +74,26 @@ end
6774
but the algorithm is optimized for Vectors (refinement only).
6875
"""
6976
function get_o2n_faces_map(ncell_to_ocell::Table{T}) where {T<:Integer}
70-
@notimplemented
77+
nC = maximum(ncell_to_ocell.data)
78+
79+
ptrs = fill(0,nC+1)
80+
for ccell in ncell_to_ocell.data
81+
ptrs[ccell+1] += 1
82+
end
83+
Arrays.length_to_ptrs!(ptrs)
84+
85+
data = Vector{Int}(undef,ptrs[end]-1)
86+
for fcell = 1:length(ncell_to_ocell.ptrs)-1
87+
for j = ncell_to_ocell.ptrs[fcell]:ncell_to_ocell.ptrs[fcell+1]-1
88+
ccell = ncell_to_ocell.data[j]
89+
data[ptrs[ccell]] = fcell
90+
ptrs[ccell] += 1
91+
end
92+
end
93+
Arrays.rewind_ptrs!(ptrs)
94+
95+
ocell_to_ncell = Table(data,ptrs)
96+
return ocell_to_ncell
7197
end
7298

7399
function get_o2n_faces_map(ncell_to_ocell::Vector{T}) where {T<:Integer}
@@ -95,12 +121,19 @@ function get_o2n_faces_map(ncell_to_ocell::Vector{T}) where {T<:Integer}
95121
return ocell_to_ncell
96122
end
97123

98-
function get_new_cell_refinement_rules(g::AdaptivityGlue)
124+
function get_new_cell_refinement_rules(g::AdaptivityGlue{<:RefinementGlue})
99125
old_rrules = g.refinement_rules
100126
n2o_faces_map = g.n2o_faces_map[end]
101127
return lazy_map(Reindex(old_rrules),n2o_faces_map)
102128
end
103129

130+
function get_new_cell_refinement_rules(g::AdaptivityGlue{<:MixedGlue})
131+
old_rrules = g.refinement_rules
132+
n2o_faces_map = g.n2o_faces_map[end]
133+
new_idx = lazy_map(Reindex(n2o_faces_map.data),n2o_faces_map.ptrs[1:end-1])
134+
return lazy_map(Reindex(old_rrules), new_idx)
135+
end
136+
104137
function get_old_cell_refinement_rules(g::AdaptivityGlue)
105138
return g.refinement_rules
106139
end
@@ -129,3 +162,104 @@ function _reindex(data,idx::Vector)
129162
m = Reindex(data)
130163
return lazy_map(m,idx)
131164
end
165+
166+
167+
# New to old face glues
168+
169+
function get_d_to_fface_to_cface(::AdaptivityGlue,::GridTopology,::GridTopology)
170+
@notimplemented
171+
end
172+
173+
"
174+
For each child/fine face, returns the parent/coarse face containing it. The parent
175+
face might have higher dimension.
176+
177+
Returns two arrays:
178+
- [dimension][fine face gid] -> coarse parent face gid
179+
- [dimension][fine face gid] -> coarse parent face dimension
180+
"
181+
function get_d_to_fface_to_cface(glue::AdaptivityGlue{<:RefinementGlue},
182+
ctopo::GridTopology{Dc},
183+
ftopo::GridTopology{Dc}) where Dc
184+
185+
# Local data for each coarse cell, at the RefinementRule level
186+
rrules = Adaptivity.get_old_cell_refinement_rules(glue)
187+
ccell_to_d_to_faces = lazy_map(rr->map(d->Geometry.get_faces(get_grid_topology(rr.ref_grid),Dc,d),0:Dc),rrules)
188+
ccell_to_d_to_fface_to_parent_face = lazy_map(get_d_to_face_to_parent_face,rrules)
189+
190+
# Global data, concerning the complete meshes
191+
ccell_to_fcell = glue.o2n_faces_map
192+
d_to_ccell_to_cface = map(d->Geometry.get_faces(ctopo,Dc,d),0:Dc)
193+
d_to_fcell_to_fface = map(d->Geometry.get_faces(ftopo,Dc,d),0:Dc)
194+
195+
d_to_fface_to_cface = [fill(Int32(0),num_faces(ftopo,d)) for d in 0:Dc]
196+
d_to_fface_to_cface_dim = [fill(Int32(0),num_faces(ftopo,d)) for d in 0:Dc]
197+
198+
# For each coarse cell
199+
for ccell in 1:num_cells(ctopo)
200+
local_d_to_fface_to_parent_face,
201+
local_d_to_fface_to_parent_dim = ccell_to_d_to_fface_to_parent_face[ccell]
202+
# For each fine subcell:
203+
# child_id -> Local Id of the fine cell within the refinement rule (ccell)
204+
for (child_id,fcell) in enumerate(ccell_to_fcell[ccell])
205+
# For each fine face on the fine subcell:
206+
# d -> Dimension of the fine face
207+
# iF -> Local Id of the fine face within the fine cell
208+
# fface -> Global Id of the fine face
209+
for d in 0:Dc
210+
for (iF,fface) in enumerate(d_to_fcell_to_fface[d+1][fcell])
211+
# Local Id of the fine face within the refinement rule
212+
fface_child_id = ccell_to_d_to_faces[ccell][d+1][child_id][iF]
213+
# Local Id of the coarse parent face within the coarse cell
214+
parent = local_d_to_fface_to_parent_face[d+1][fface_child_id]
215+
216+
# Global Id of the coarse parent face, and it's dimension
217+
cface_dim = local_d_to_fface_to_parent_dim[d+1][fface_child_id]
218+
cface = d_to_ccell_to_cface[cface_dim+1][ccell][parent]
219+
d_to_fface_to_cface[d+1][fface] = cface
220+
d_to_fface_to_cface_dim[d+1][fface] = cface_dim
221+
end
222+
end
223+
end
224+
end
225+
226+
return (d_to_fface_to_cface,d_to_fface_to_cface_dim)
227+
end
228+
229+
# FaceLabeling refinement
230+
231+
function _refine_face_labeling(coarse_labeling::FaceLabeling,
232+
glue :: AdaptivityGlue,
233+
ctopo :: GridTopology,
234+
ftopo :: GridTopology)
235+
d_to_fface_to_cface,
236+
d_to_fface_to_cface_dim = get_d_to_fface_to_cface(glue,ctopo,ftopo)
237+
238+
return _refine_face_labeling(coarse_labeling,d_to_fface_to_cface,d_to_fface_to_cface_dim)
239+
end
240+
241+
function _refine_face_labeling(coarse_labeling::FaceLabeling,
242+
d_to_fface_to_cface,
243+
d_to_fface_to_cface_dim)
244+
tag_to_name = copy(coarse_labeling.tag_to_name)
245+
tag_to_entities = copy(coarse_labeling.tag_to_entities)
246+
247+
Dc = num_dims(coarse_labeling)
248+
d_to_dface_to_entity = Vector{Vector{Int32}}(undef,Dc+1)
249+
for d in 0:Dc
250+
nF = length(d_to_fface_to_cface[d+1])
251+
dface_to_entity = Vector{Int32}(undef,nF)
252+
253+
for fface in 1:nF
254+
cface = d_to_fface_to_cface[d+1][fface]
255+
cface_dim = d_to_fface_to_cface_dim[d+1][fface]
256+
257+
cface_entity = coarse_labeling.d_to_dface_to_entity[cface_dim+1][cface]
258+
dface_to_entity[fface] = cface_entity
259+
end
260+
261+
d_to_dface_to_entity[d+1] = dface_to_entity
262+
end
263+
264+
return Geometry.FaceLabeling(d_to_dface_to_entity,tag_to_entities,tag_to_name)
265+
end

0 commit comments

Comments
 (0)