Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set of improvements/fixes in Gridap.Adaptivity module #886

Merged
merged 30 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
faeb23b
Started working on fine-to-coarse dof correspondance
JordiManyer Mar 15, 2023
51f8401
Working concept
JordiManyer Mar 15, 2023
1fafff7
Generalised approach, needs testing for HEX
JordiManyer Mar 19, 2023
c9cff2a
Implemented coarse_nodes_above_fine_nodes, only tested for QUAD
JordiManyer Mar 19, 2023
8bfc6f3
Renamed method to get_face_subface_ldof_to_cell_ldof
JordiManyer Mar 24, 2023
4980531
Added get_d_to_face_to_parent_face for QUAD & TRI
JordiManyer Mar 24, 2023
5fab8ad
Tests for coarse-to-fine relabeling
JordiManyer Mar 26, 2023
8eb11e0
Fixed face labeling for unstructured refined meshes
JordiManyer Mar 26, 2023
0884381
Small bugfix
JordiManyer Mar 26, 2023
3a34204
Added some documentation for the new methods
JordiManyer Mar 26, 2023
2e00274
Added support for HEX
JordiManyer Apr 12, 2023
1e0300b
Merge branch 'master' of github.com:gridap/Gridap.jl into refinement-…
JordiManyer Apr 12, 2023
2fa1cf3
Bugfix: get_face_subface_ldof_to_cell_ldof for HEX faces
JordiManyer Apr 20, 2023
0e9e065
Merge branch 'master' of github.com:gridap/Gridap.jl into refinement-…
amartinhuertas Jul 11, 2023
6f5dc0d
Merge branch 'master' of github.com:gridap/Gridap.jl into refinement-…
amartinhuertas Jul 18, 2023
04b2ac2
Added fix for change_domain when both adapted triangulations are the …
JordiManyer Aug 2, 2023
0049e7b
Added fix to change_domain_n2o for distributed meshes
JordiManyer Aug 2, 2023
6049786
AdaptivityGlue now accepts a Table as n2o_cell_to_child_id
JordiManyer Aug 2, 2023
b698d6b
Added generic version of get_d_to_face_to_parent_face
JordiManyer Aug 3, 2023
162569b
Added generic version of get_d_to_face_to_child_faces
JordiManyer Aug 3, 2023
1066a22
Moved constructors for CartDM out of the struct.
JordiManyer Aug 3, 2023
dfae593
Fix label refining for CartesianDiscreteModels
JordiManyer Aug 3, 2023
bb450f5
Bugfix: Allow domain limits to be floats in CDM refinement routines
JordiManyer Aug 3, 2023
ac6ffc0
Added get_new_cell_refinement_rules for MixedGlue
JordiManyer Aug 3, 2023
b57e715
Added OldToNewFields and change_domain for MixedGlues
JordiManyer Aug 3, 2023
7c0ed0e
Updated NEWS.md
JordiManyer Aug 3, 2023
e76ae7b
Small bugfix
JordiManyer Aug 3, 2023
783010a
Minor change
JordiManyer Aug 3, 2023
c7a5edd
Small bugfix
JordiManyer Aug 3, 2023
39e0175
Small bugfix
JordiManyer Aug 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Jacobi polynomial bases. Since PR [#896](https://github.com/gridap/Gridap.jl/pull/896).

- Replaced newest vertex bisection mesh adaptation in
`src/Geometry/NewestVertexBisection.jl` with appropriate changes to
`src/Adaptivity/EdgeBasedRefinement.jl`. see PR
`src/Adaptivity/EdgeBasedRefinement.jl`. Since PR
[#901](https://github.com/gridap/Gridap.jl/pull/901).
- 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).
- 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).

### Changed

Expand All @@ -26,9 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed the method `get_normal_vector` for `AdaptedTriangulation`. The method `get_facet_normal`
was using default, it's now using the spetialized implementation for the underlying triangulation type.
Since PR [#884](https://github.com/gridap/Gridap.jl/pull/884).

- Fixed `cell_dof_ids` for the case of vectorial `ConstantFESpace`. Since PR [#888](https://github.com/gridap/Gridap.jl/pull/888)
- Fixed generation of Modal C0 bases for Julia 1.9. Since PR [#918](https://github.com/gridap/Gridap.jl/pull/918).
- 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).
- 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).

## [0.17.17] - 2023-02-24

Expand Down
32 changes: 23 additions & 9 deletions src/Adaptivity/AdaptedDiscreteModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,24 +103,31 @@ function refine(model::CartesianDiscreteModel{Dc}, cell_partition::Tuple) where
desc = Geometry.get_cartesian_descriptor(model)
nC = desc.partition

# Refined model
domain = _get_cartesian_domain(desc)
model_ref = CartesianDiscreteModel(domain,cell_partition.*nC)

# Glue
# Refinement Glue
f2c_cell_map, fcell_to_child_id = _create_cartesian_f2c_maps(nC,cell_partition)
faces_map = [(d==Dc) ? f2c_cell_map : Int[] for d in 0:Dc]
reffe = LagrangianRefFE(Float64,first(get_polytopes(model)),1)
rrules = RefinementRule(reffe,cell_partition)
faces_map = [(d==Dc) ? f2c_cell_map : Int[] for d in 0:Dc]
reffe = LagrangianRefFE(Float64,first(get_polytopes(model)),1)
rrules = RefinementRule(reffe,cell_partition)
glue = AdaptivityGlue(faces_map,fcell_to_child_id,rrules)

# Refined model
domain = _get_cartesian_domain(desc)
_model_ref = CartesianDiscreteModel(domain,cell_partition.*nC)

# Propagate face labels
coarse_labels = get_face_labeling(model)
coarse_topo = get_grid_topology(model)
fine_topo = get_grid_topology(_model_ref)
fine_labels = _refine_face_labeling(coarse_labels,glue,coarse_topo,fine_topo)

model_ref = CartesianDiscreteModel(get_grid(_model_ref),fine_topo,fine_labels)
return AdaptedDiscreteModel(model_ref,model,glue)
end

function _get_cartesian_domain(desc::CartesianDescriptor{D}) where D
origin = desc.origin
corner = origin + VectorValue(desc.sizes .* desc.partition)
domain = Vector{Int}(undef,2*D)
domain = Vector{eltype(origin)}(undef,2*D)
for d in 1:D
domain[d*2-1] = origin[d]
domain[d*2] = corner[d]
Expand Down Expand Up @@ -159,3 +166,10 @@ end
return f2c_map, child_map
end)
end

function get_d_to_fface_to_cface(model::AdaptedDiscreteModel)
ftopo = get_grid_topology(get_model(model))
ctopo = get_grid_topology(get_parent(model))
glue = get_adaptivity_glue(model)
return get_d_to_fface_to_cface(glue,ctopo,ftopo)
end
42 changes: 37 additions & 5 deletions src/Adaptivity/AdaptedTriangulations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,14 @@ end

for sdomain in [:ReferenceDomain,:PhysicalDomain]
for (stype,ttype) in [(:AdaptedTriangulation,:AdaptedTriangulation),(:AdaptedTriangulation,:Triangulation),(:Triangulation,:AdaptedTriangulation)]
sstrian = (stype==:AdaptedTriangulation) ? :(strian.trian) : :(strian)
tttrian = (ttype==:AdaptedTriangulation) ? :(ttrian.trian) : :(ttrian)
@eval begin
function CellData.change_domain(a::CellField,strian::$stype,::$sdomain,ttrian::$ttype,::PhysicalDomain)
function CellData.change_domain(a::CellField,strian::$stype,sd::$sdomain,ttrian::$ttype,::PhysicalDomain)
if (get_background_model(strian) === get_background_model(ttrian))
return change_domain(a,$sstrian,sd,$tttrian,PhysicalDomain())
end

a_ref = change_domain(a,ReferenceDomain())
atrian = change_domain(a_ref,strian,ReferenceDomain(),ttrian,ReferenceDomain())
return change_domain(atrian,PhysicalDomain())
Expand Down Expand Up @@ -281,11 +287,36 @@ function change_domain_o2n(f_coarse,ctrian::Triangulation{Dc},ftrian::AdaptedTri

return CellData.similar_cell_field(f_coarse,f_fine,ftrian,ReferenceDomain())
else
f_fine = Fill(Gridap.Fields.ConstantField(0.0),num_cells(ftrian))
f_fine = Fill(Fields.ConstantField(0.0),num_cells(ftrian))
return CellData.similar_cell_field(f_coarse,f_fine,ftrian,ReferenceDomain())
end
end

function change_domain_o2n(
f_old,
old_trian::Triangulation{Dc},
new_trian::AdaptedTriangulation,
glue::AdaptivityGlue{<:MixedGlue}) where {Dc}

oglue = get_glue(old_trian,Val(Dc))
nglue = get_glue(new_trian,Val(Dc))

@notimplementedif num_point_dims(old_trian) != Dc
@notimplementedif isa(nglue,Nothing)

if (num_cells(old_trian) != 0)
# If mixed refinement/coarsening, then f_c2f is a Table
f_old_data = CellData.get_data(f_old)
f_c2f = c2f_reindex(f_old_data,glue)
new_rrules = get_new_cell_refinement_rules(glue)
field_array = lazy_map(OldToNewField, f_c2f, new_rrules, glue.n2o_cell_to_child_id)
return CellData.similar_cell_field(f_old,field_array,new_trian,ReferenceDomain())
else
f_new = Fill(Fields.ConstantField(0.0),num_cells(new_trian))
return CellData.similar_cell_field(f_old,f_new,new_trian,ReferenceDomain())
end
end

"""
Given a AdaptivityGlue and a CellField defined on the child(new) mesh,
returns an equivalent CellField on the parent(old) mesh.
Expand All @@ -310,16 +341,17 @@ function change_domain_n2o(f_fine,ftrian::AdaptedTriangulation{Dc},ctrian::Trian
# f_c2f[i_coarse] = [f_fine[i_fine_1], ..., f_fine[i_fine_nChildren]]
f_c2f = f2c_reindex(fine_mface_to_field,glue)

rrules = get_old_cell_refinement_rules(glue)
coarse_mface_to_field = lazy_map(FineToCoarseField,f_c2f,rrules)
child_ids = f2c_reindex(glue.n2o_cell_to_child_id,glue)
rrules = get_old_cell_refinement_rules(glue)
coarse_mface_to_field = lazy_map(FineToCoarseField,f_c2f,rrules,child_ids)

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

return CellData.similar_cell_field(f_fine,f_coarse,ctrian,ReferenceDomain())
else
f_coarse = Fill(Gridap.Fields.ConstantField(0.0),num_cells(fcoarse))
f_coarse = Fill(Fields.ConstantField(0.0),num_cells(fcoarse))
return CellData.similar_cell_field(f_fine,f_coarse,ctrian,ReferenceDomain())
end
end
Expand Down
1 change: 1 addition & 0 deletions src/Adaptivity/Adaptivity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export change_domain, move_contributions

include("RefinementRules.jl")
include("FineToCoarseFields.jl")
include("OldToNewFields.jl")
include("FineToCoarseReferenceFEs.jl")
include("AdaptivityGlues.jl")
include("AdaptedDiscreteModels.jl")
Expand Down
140 changes: 137 additions & 3 deletions src/Adaptivity/AdaptivityGlues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@ struct AdaptivityGlue{GT,Dc,A,B,C,D,E} <: GridapType
is_refined :: E

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

GT = all(is_refined) ? RefinementGlue : MixedGlue
if isa(GT(),RefinementGlue)
@assert isa(n2o_faces_map,Vector{<:AbstractVector{<:Integer}})
@assert isa(n2o_cell_to_child_id,AbstractVector{<:Integer})
else
@assert isa(n2o_faces_map,Vector{<:Table{<:Integer}})
@assert isa(n2o_cell_to_child_id,Table{<:Integer})
end

A = typeof(n2o_faces_map)
B = typeof(n2o_cell_to_child_id)
Expand Down Expand Up @@ -67,7 +74,26 @@ end
but the algorithm is optimized for Vectors (refinement only).
"""
function get_o2n_faces_map(ncell_to_ocell::Table{T}) where {T<:Integer}
@notimplemented
nC = maximum(ncell_to_ocell.data)

ptrs = fill(0,nC+1)
for ccell in ncell_to_ocell.data
ptrs[ccell+1] += 1
end
Arrays.length_to_ptrs!(ptrs)

data = Vector{Int}(undef,ptrs[end]-1)
for fcell = 1:length(ncell_to_ocell.ptrs)-1
for j = ncell_to_ocell.ptrs[fcell]:ncell_to_ocell.ptrs[fcell+1]-1
ccell = ncell_to_ocell.data[j]
data[ptrs[ccell]] = fcell
ptrs[ccell] += 1
end
end
Arrays.rewind_ptrs!(ptrs)

ocell_to_ncell = Table(data,ptrs)
return ocell_to_ncell
end

function get_o2n_faces_map(ncell_to_ocell::Vector{T}) where {T<:Integer}
Expand Down Expand Up @@ -95,12 +121,19 @@ function get_o2n_faces_map(ncell_to_ocell::Vector{T}) where {T<:Integer}
return ocell_to_ncell
end

function get_new_cell_refinement_rules(g::AdaptivityGlue)
function get_new_cell_refinement_rules(g::AdaptivityGlue{<:RefinementGlue})
old_rrules = g.refinement_rules
n2o_faces_map = g.n2o_faces_map[end]
return lazy_map(Reindex(old_rrules),n2o_faces_map)
end

function get_new_cell_refinement_rules(g::AdaptivityGlue{<:MixedGlue})
old_rrules = g.refinement_rules
n2o_faces_map = g.n2o_faces_map[end]
new_idx = lazy_map(Reindex(n2o_faces_map.data),n2o_faces_map.ptrs[1:end-1])
return lazy_map(Reindex(old_rrules), new_idx)
end

function get_old_cell_refinement_rules(g::AdaptivityGlue)
return g.refinement_rules
end
Expand Down Expand Up @@ -129,3 +162,104 @@ function _reindex(data,idx::Vector)
m = Reindex(data)
return lazy_map(m,idx)
end


# New to old face glues

function get_d_to_fface_to_cface(::AdaptivityGlue,::GridTopology,::GridTopology)
@notimplemented
end

"
For each child/fine face, returns the parent/coarse face containing it. The parent
face might have higher dimension.

Returns two arrays:
- [dimension][fine face gid] -> coarse parent face gid
- [dimension][fine face gid] -> coarse parent face dimension
"
function get_d_to_fface_to_cface(glue::AdaptivityGlue{<:RefinementGlue},
ctopo::GridTopology{Dc},
ftopo::GridTopology{Dc}) where Dc

# Local data for each coarse cell, at the RefinementRule level
rrules = Adaptivity.get_old_cell_refinement_rules(glue)
ccell_to_d_to_faces = lazy_map(rr->map(d->Geometry.get_faces(get_grid_topology(rr.ref_grid),Dc,d),0:Dc),rrules)
ccell_to_d_to_fface_to_parent_face = lazy_map(get_d_to_face_to_parent_face,rrules)

# Global data, concerning the complete meshes
ccell_to_fcell = glue.o2n_faces_map
d_to_ccell_to_cface = map(d->Geometry.get_faces(ctopo,Dc,d),0:Dc)
d_to_fcell_to_fface = map(d->Geometry.get_faces(ftopo,Dc,d),0:Dc)

d_to_fface_to_cface = [fill(Int32(0),num_faces(ftopo,d)) for d in 0:Dc]
d_to_fface_to_cface_dim = [fill(Int32(0),num_faces(ftopo,d)) for d in 0:Dc]

# For each coarse cell
for ccell in 1:num_cells(ctopo)
local_d_to_fface_to_parent_face,
local_d_to_fface_to_parent_dim = ccell_to_d_to_fface_to_parent_face[ccell]
# For each fine subcell:
# child_id -> Local Id of the fine cell within the refinement rule (ccell)
for (child_id,fcell) in enumerate(ccell_to_fcell[ccell])
# For each fine face on the fine subcell:
# d -> Dimension of the fine face
# iF -> Local Id of the fine face within the fine cell
# fface -> Global Id of the fine face
for d in 0:Dc
for (iF,fface) in enumerate(d_to_fcell_to_fface[d+1][fcell])
# Local Id of the fine face within the refinement rule
fface_child_id = ccell_to_d_to_faces[ccell][d+1][child_id][iF]
# Local Id of the coarse parent face within the coarse cell
parent = local_d_to_fface_to_parent_face[d+1][fface_child_id]

# Global Id of the coarse parent face, and it's dimension
cface_dim = local_d_to_fface_to_parent_dim[d+1][fface_child_id]
cface = d_to_ccell_to_cface[cface_dim+1][ccell][parent]
d_to_fface_to_cface[d+1][fface] = cface
d_to_fface_to_cface_dim[d+1][fface] = cface_dim
end
end
end
end

return (d_to_fface_to_cface,d_to_fface_to_cface_dim)
end

# FaceLabeling refinement

function _refine_face_labeling(coarse_labeling::FaceLabeling,
glue :: AdaptivityGlue,
ctopo :: GridTopology,
ftopo :: GridTopology)
d_to_fface_to_cface,
d_to_fface_to_cface_dim = get_d_to_fface_to_cface(glue,ctopo,ftopo)

return _refine_face_labeling(coarse_labeling,d_to_fface_to_cface,d_to_fface_to_cface_dim)
end

function _refine_face_labeling(coarse_labeling::FaceLabeling,
d_to_fface_to_cface,
d_to_fface_to_cface_dim)
tag_to_name = copy(coarse_labeling.tag_to_name)
tag_to_entities = copy(coarse_labeling.tag_to_entities)

Dc = num_dims(coarse_labeling)
d_to_dface_to_entity = Vector{Vector{Int32}}(undef,Dc+1)
for d in 0:Dc
nF = length(d_to_fface_to_cface[d+1])
dface_to_entity = Vector{Int32}(undef,nF)

for fface in 1:nF
cface = d_to_fface_to_cface[d+1][fface]
cface_dim = d_to_fface_to_cface_dim[d+1][fface]

cface_entity = coarse_labeling.d_to_dface_to_entity[cface_dim+1][cface]
dface_to_entity[fface] = cface_entity
end

d_to_dface_to_entity[d+1] = dface_to_entity
end

return Geometry.FaceLabeling(d_to_dface_to_entity,tag_to_entities,tag_to_name)
end
Loading
Loading