Skip to content

Commit 5ba4f24

Browse files
committed
Added first HDG test
1 parent e32c828 commit 5ba4f24

File tree

4 files changed

+174
-43
lines changed

4 files changed

+174
-43
lines changed

src/FESpaces/PatchAssemblers.jl

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,11 @@ function get_patch_dofs(space::FESpace,ptopo::PatchTopology)
109109
patch_to_faces = get_patch_faces(ptopo,Df)
110110

111111
patch_to_dofs = map(patch_to_faces) do pfaces
112-
tfaces = filter(!iszero,face_to_tface[pfaces])
112+
tfaces = filter(x->x>0,face_to_tface[pfaces])
113113
dofs = SortedSet{Int}()
114114
for tface in tfaces
115-
push!(dofs,view(tface_to_dofs,tface)...)
115+
tface_dofs = filter(x->x>0,view(tface_to_dofs,tface))
116+
!isempty(tface_dofs) && push!(dofs,tface_dofs...)
116117
end
117118
collect(dofs)
118119
end |> Table
@@ -235,17 +236,52 @@ struct PatchAssemblyMap{T} <: Map
235236
cell_data
236237
end
237238

239+
function _alloc_cache(::PatchAssemblyStrategy,s::NTuple{N,Int}) where N
240+
zeros(s...)
241+
end
242+
243+
function _alloc_cache(::PatchAssemblyStrategy,s::NTuple{N,<:BlockedOneTo}) where N
244+
bs = map(blocklength,s)
245+
ss = map(blocklengths,s)
246+
array = [ zeros(ntuple(i -> ss[i][I[i]], Val(N))) for I in CartesianIndices(bs) ]
247+
ArrayBlock(array,fill(true,bs))
248+
end
249+
250+
function _alloc_cache(b::ArrayBlockView,s::NTuple{N,<:BlockedOneTo}) where N
251+
bs = map(blocklength,s)
252+
ss = map(blocklengths,s)
253+
array = [ zeros(ntuple(i -> ss[i][I[i]], Val(N))) for I in CartesianIndices(bs) ]
254+
bmap = ifelse(N == 2, b.block_map, map(idx -> CartesianIndex(idx[1]), diag(b.block_map)))
255+
ArrayBlockView(ArrayBlock(array,fill(true,bs)),bmap)
256+
end
257+
258+
function _resize_cache!(a,::PatchAssemblyStrategy,s::NTuple{N,Int}) where N
259+
setsize!(a,s)
260+
end
261+
262+
function _resize_cache!(a,::PatchAssemblyStrategy,s::NTuple{N,<:BlockedOneTo}) where N
263+
bs = map(blocklength,s)
264+
ss = map(blocklengths,s)
265+
for I in CartesianIndices(bs)
266+
setsize!(a.array[I],ntuple(i -> ss[i][I[i]], Val(N)))
267+
end
268+
end
269+
270+
function _resize_cache!(a,b::ArrayBlockView,s::NTuple{N,<:BlockedOneTo}) where N
271+
bs = map(blocklength,s)
272+
ss = map(blocklengths,s)
273+
for I in CartesianIndices(bs)
274+
setsize!(a.array.array[I],ntuple(i -> ss[i][I[i]], Val(N)))
275+
end
276+
end
277+
278+
_unview(a) = a
279+
_unview(a::ArrayBlockView) = a.array
280+
238281
# Mat & Vec assembly
239282

240283
function Arrays.return_cache(k::PatchAssemblyMap,patch)
241-
_zeros(s::NTuple{N,Int}) where N = zeros(s...)
242-
function _zeros(s::NTuple{N,BlockedOneTo}) where N
243-
bs = map(blocklength,s)
244-
ss = map(blocklengths,s)
245-
array = [ zeros(ntuple(i -> ss[i][I[i]], Val(N))) for I in CartesianIndices(bs) ]
246-
ArrayBlock(array,fill(true,bs))
247-
end
248-
res = _zeros(k.patch_sizes[patch])
284+
res = _alloc_cache(k.assem.strategy,k.patch_sizes[patch])
249285
caches = patch_assembly_cache(res,k.cell_data)
250286

251287
c_res = CachedArray(res)
@@ -255,33 +291,19 @@ function Arrays.return_cache(k::PatchAssemblyMap,patch)
255291
end
256292

257293
function Arrays.evaluate!(cache,k::PatchAssemblyMap,patch)
258-
_setsize!(a,s::NTuple{N,Int}) where N = setsize!(a,s)
259-
function _setsize!(a,s::NTuple{N,BlockedOneTo}) where N
260-
bs = map(blocklength,s)
261-
ss = map(blocklengths,s)
262-
for I in CartesianIndices(bs)
263-
setsize!(a.array[I],ntuple(i -> ss[i][I[i]], Val(N)))
264-
end
265-
end
266294
c_res, uwr_cache, caches = cache
267-
_setsize!(c_res,k.patch_sizes[patch])
295+
_resize_cache!(c_res,k.assem.strategy,k.patch_sizes[patch])
268296
res = evaluate!(uwr_cache,Fields.unwrap_cached_array,c_res)
269297
Fields._zero_entries!(res)
270298
patch_assembly!(caches,res,k.cell_data,patch)
271-
return res
299+
return _unview(res)
272300
end
273301

274302
# Mat-Vec assembly
275303

276304
function Arrays.return_cache(k::PatchAssemblyMap{<:Tuple{<:Tuple,<:Tuple}},patch)
277-
_zeros(s::NTuple{N,Int}) where N = zeros(s...)
278-
function _zeros(s::NTuple{N,BlockedOneTo}) where N
279-
bs = map(blocklength,s)
280-
ss = map(blocklengths,s)
281-
array = [ zeros(ntuple(i -> ss[i][I[i]], Val(N))) for I in CartesianIndices(bs) ]
282-
ArrayBlock(array,fill(true,bs))
283-
end
284-
mat, vec = _zeros(k.patch_sizes[patch][1]), _zeros(k.patch_sizes[patch][2])
305+
mat = _alloc_cache(k.assem.strategy,k.patch_sizes[patch][1])
306+
vec = _alloc_cache(k.assem.strategy,k.patch_sizes[patch][2])
285307

286308
matvecdata, matdata, vecdata = k.cell_data
287309
mat_caches = patch_assembly_cache(mat,matdata)
@@ -296,19 +318,11 @@ function Arrays.return_cache(k::PatchAssemblyMap{<:Tuple{<:Tuple,<:Tuple}},patch
296318
end
297319

298320
function Arrays.evaluate!(cache,k::PatchAssemblyMap{<:Tuple{<:Tuple,<:Tuple}},patch)
299-
_setsize!(a,s::NTuple{N,Int}) where N = setsize!(a,s)
300-
function _setsize!(a,s::NTuple{N,BlockedOneTo}) where N
301-
bs = map(blocklength,s)
302-
ss = map(blocklengths,s)
303-
for I in CartesianIndices(bs)
304-
setsize!(a.array[I],ntuple(i -> ss[i][I[i]], Val(N)))
305-
end
306-
end
307321
c_mat, c_vec, uwm_cache, uwv_cache, matvec_caches, mat_caches, vec_caches = cache
308322
matvecdata, matdata, vecdata = k.cell_data
309323

310-
_setsize!(c_mat,k.patch_sizes[patch][1])
311-
_setsize!(c_vec,k.patch_sizes[patch][2])
324+
_resize_cache!(c_mat,k.assem.strategy,k.patch_sizes[patch][1])
325+
_resize_cache!(c_vec,k.assem.strategy,k.patch_sizes[patch][2])
312326
mat = evaluate!(uwm_cache,Fields.unwrap_cached_array,c_mat)
313327
vec = evaluate!(uwv_cache,Fields.unwrap_cached_array,c_vec)
314328

@@ -319,11 +333,11 @@ function Arrays.evaluate!(cache,k::PatchAssemblyMap{<:Tuple{<:Tuple,<:Tuple}},pa
319333
patch_assembly!(mat_caches,mat,matdata,patch)
320334
patch_assembly!(vec_caches,vec,vecdata,patch)
321335

322-
return mat, vec
336+
return _unview(mat), _unview(vec)
323337
end
324338

325-
const MatOrMatBlock = Union{AbstractMatrix,MatrixBlock}
326-
const VecOrVecBlock = Union{AbstractVector,VectorBlock}
339+
const MatOrMatBlock = Union{AbstractMatrix,MatrixBlock,MatrixBlockView}
340+
const VecOrVecBlock = Union{AbstractVector,VectorBlock,VectorBlockView}
327341

328342
function patch_assembly_cache(mat::MatOrMatBlock,cell_matdata)
329343
caches = ()
@@ -451,7 +465,7 @@ function Arrays.evaluate!(cache,k::StaticCondensationMap,matvec)
451465
@check size(mat.array) == (2,2)
452466
@check size(vec.array) == (2,)
453467

454-
Kii, Kib, Kbi, Kbb = mat.array
468+
Kii, Kbi, Kib, Kbb = mat.array
455469
bi, bb = vec.array
456470

457471
f = lu!(Kii,k.pivot;check=false)

src/Fields/ArrayBlocks.jl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,3 +1519,26 @@ end
15191519

15201520
LinearAlgebra.diag(a::MatrixBlockView) = view(a.array.array, diag(a.block_map))
15211521
LinearAlgebra.diag(a::MatrixBlock) = view(a.array,diag(CartesianIndices(a.array)))
1522+
1523+
_zero_entries!(a::ArrayBlockView) = _zero_entries!(a.array)
1524+
1525+
function Arrays.CachedArray(a::ArrayBlockView)
1526+
ArrayBlockView(CachedArray(a.array),a.block_map)
1527+
end
1528+
1529+
function unwrap_cached_array(a::ArrayBlockView)
1530+
cache = return_cache(unwrap_cached_array,a)
1531+
evaluate!(cache,unwrap_cached_array,a)
1532+
end
1533+
1534+
function return_cache(::typeof(unwrap_cached_array),a::ArrayBlockView)
1535+
cache = return_cache(unwrap_cached_array,a.array)
1536+
array = evaluate!(cache,unwrap_cached_array,a.array)
1537+
return ArrayBlockView(array,a.block_map), cache
1538+
end
1539+
1540+
function evaluate!(cache,::typeof(unwrap_cached_array),a::ArrayBlockView)
1541+
r, c = cache
1542+
evaluate!(c,unwrap_cached_array,a.array)
1543+
return r
1544+
end

test/GeometryTests/PatchTriangulationTests.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ x1 = lazy_map(FESpaces.LocalSolveMap(),A,b)
5454
x2 = lazy_map(FESpaces.LocalSolveMap(),Ab)
5555

5656

57-
# MultiField
57+
# MultiField + Static condensation
58+
5859
using Gridap.MultiField
5960
using Gridap.CellData
6061

test/GridapTests/HDGTests.jl

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
2+
using Gridap
3+
using Gridap.Geometry, Gridap.FESpaces, Gridap.MultiField
4+
using Gridap.CellData, Gridap.Fields
5+
6+
function get_abs_normal_vector(trian)
7+
function normal(c)
8+
t = c[2] - c[1]
9+
n = VectorValue(-t[2],t[1])
10+
n = n/norm(n)
11+
return n
12+
end
13+
face_coords = get_cell_coordinates(trian)
14+
face_normals = lazy_map(constant_field,lazy_map(normal,face_coords))
15+
return CellData.GenericCellField(face_normals,trian,ReferenceDomain())
16+
end
17+
18+
function statically_condensed_assembly(ptopo,X,Y,M,M_test,a,l)
19+
# Lazily assemble the global patch-systems and
20+
# perform the static condensation
21+
assem = FESpaces.PatchAssembler(ptopo,X,Y)
22+
full_matvecs = assemble_matrix_and_vector(a,l,assem,X,Y)
23+
sc_matvecs = lazy_map(FESpaces.StaticCondensationMap(),full_matvecs)
24+
25+
# Regular assembly of the statically-assembled systems
26+
patch_rows = assem.strategy.array.array[2,2].patch_rows
27+
patch_cols = assem.strategy.array.array[2,2].patch_cols
28+
matvecdata = ([sc_matvecs,],[patch_rows,],[patch_cols,])
29+
matdata = ([],[],[]) # dummy matdata
30+
vecdata = ([],[],[]) # dummy vecdata
31+
data = (matvecdata, matdata, vecdata)
32+
A, b = assemble_matrix_and_vector(SparseMatrixAssembler(M,M_test),data)
33+
return A, b
34+
end
35+
36+
u(x) = sin(2*π*x[1])*sin(2*π*x[2])*(1-x[1])*x[2]*(1-x[2])
37+
q(x) = -(u)(x)
38+
f(x) = (∇ q)(x)
39+
40+
nc = (4,4)
41+
model = UnstructuredDiscreteModel(CartesianDiscreteModel((0,1,0,1),nc))
42+
D = num_cell_dims(model)
43+
Ω = Triangulation(ReferenceFE{D}, model)
44+
Γ = Triangulation(ReferenceFE{D-1}, model)
45+
46+
ptopo = Geometry.PatchTopology(model)
47+
Ωp = Geometry.PatchTriangulation(model,ptopo)
48+
Γp = Geometry.PatchBoundaryTriangulation(model,ptopo)
49+
50+
# Reference FEs
51+
order = 1
52+
reffeV = ReferenceFE(lagrangian, VectorValue{D, Float64}, order; space=:P)
53+
reffeQ = ReferenceFE(lagrangian, Float64, order; space=:P)
54+
reffeM = ReferenceFE(lagrangian, Float64, order; space=:P)
55+
56+
# HDG test FE Spaces
57+
V_test = TestFESpace(Ω, reffeV; conformity=:L2)
58+
Q_test = TestFESpace(Ω, reffeQ; conformity=:L2)
59+
M_test = TestFESpace(Γ, reffeM; conformity=:L2, dirichlet_tags="boundary")
60+
61+
# HDG trial FE Spaces
62+
V = TrialFESpace(V_test)
63+
Q = TrialFESpace(Q_test)
64+
M = TrialFESpace(M_test, u)
65+
66+
mfs = MultiField.BlockMultiFieldStyle(2,(2,1))
67+
Y = MultiFieldFESpace([V_test, Q_test, M_test];style=mfs)
68+
X = MultiFieldFESpace([V, Q, M];style=mfs)
69+
70+
τ = 1.0 # HDG stab parameter
71+
72+
degree = 2*(order+1)
73+
dΩp = Measure(Ωp,degree)
74+
dΓp = Measure(Γp,degree)
75+
nrel = get_normal_vector(Γp)
76+
nabs = get_abs_normal_vector(Γp)
77+
n = (nrelnabs)nabs
78+
79+
Πn(u) = un
80+
Π(u) = change_domain(u,Γp,DomainStyle(u))
81+
a((qh,uh,sh),(vh,wh,lh)) = ( qhvh - uh*(∇vh) - qh(wh) )dΩp + (sh*Πn(vh))dΓp +
82+
((Πn(qh) + τ*(Π(uh) - sh))*(Π(wh) + lh))dΓp
83+
l((vh,wh,hatmh)) = ( f*wh )*dΩp
84+
85+
A, b = statically_condensed_assembly(ptopo,X,Y,M,M_test,a,l)
86+
87+
solver = LUSolver()
88+
ns = numerical_setup(symbolic_setup(solver,A),A)
89+
x = zeros(size(b))
90+
solve!(x,ns,b)
91+
sh = FEFunction(M_test,x)
92+
93+

0 commit comments

Comments
 (0)