Skip to content

Commit 3a1fe59

Browse files
committed
Added linear_elasticity_fem
1 parent 1205f96 commit 3a1fe59

File tree

3 files changed

+192
-0
lines changed

3 files changed

+192
-0
lines changed

src/PartitionedArrays.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ include("p_timer.jl")
177177

178178
export laplacian_fdm
179179
export laplacian_fem
180+
export linear_elasticity_fem
180181
include("gallery.jl")
181182

182183
end # module

src/gallery.jl

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,188 @@ function laplacian_fem(
226226
I,J,V,node_partition,node_partition
227227
end
228228

229+
function linear_elasticity_fem(
230+
nodes_per_dir, # free (== interior) nodes
231+
parts_per_dir,
232+
parts,
233+
;
234+
E = 1,
235+
ν = 0.25,
236+
index_type::Type{Ti} = Int64,
237+
value_type::Type{Tv} = Float64,
238+
) where {Ti,Tv}
239+
240+
cells_per_dir = nodes_per_dir .+ 1
241+
242+
function is_boundary_node(node_1d,nodes_1d)
243+
!(node_1d in 1:nodes_1d)
244+
end
245+
function ref_matrix(cartesian_local_nodes,h_per_dir,::Type{value_type}) where value_type
246+
D = ndims(cartesian_local_nodes)
247+
gp_1d = value_type[-sqrt(3)/3,sqrt(3)/3]
248+
sf_1d = zeros(value_type,length(gp_1d),2)
249+
sf_1d[:,1] = 0.5 .* (1 .- gp_1d)
250+
sf_1d[:,2] = 0.5 .* (gp_1d .+ 1)
251+
sg_1d = zeros(value_type,length(gp_1d),2)
252+
sg_1d[:,1] .= - 0.5
253+
sg_1d[:,2] .= 0.5
254+
cartesian_points = CartesianIndices(ntuple(d->length(gp_1d),Val{D}()))
255+
cartesian_local_node_to_local_node = LinearIndices(cartesian_local_nodes)
256+
cartesian_point_to_point = LinearIndices(cartesian_points)
257+
n = 2^D
258+
sg = Matrix{NTuple{D,value_type}}(undef,n,length(gp_1d)^D)
259+
for cartesian_local_node in cartesian_local_nodes
260+
local_node = cartesian_local_node_to_local_node[cartesian_local_node]
261+
local_node_tuple = Tuple(cartesian_local_node)
262+
for cartesian_point in cartesian_points
263+
point = cartesian_point_to_point[cartesian_point]
264+
point_tuple = Tuple(cartesian_point)
265+
v = ntuple(Val{D}()) do d
266+
prod(1:D) do i
267+
if i == d
268+
(2/h_per_dir[d])*sg_1d[local_node_tuple[d],point_tuple[d]]
269+
else
270+
sf_1d[local_node_tuple[i],point_tuple[i]]
271+
end
272+
end
273+
end
274+
sg[local_node,point] = v
275+
end
276+
end
277+
Aref = zeros(value_type,n*D,n*D)
278+
dV = prod(h_per_dir)/(2^D)
279+
ε_i = zeros(value_type,D,D)
280+
ε_j = zeros(value_type,D,D)
281+
λ = (E*ν)/((1+ν)*(1-2*ν))
282+
μ = E/(2*(1+ν))
283+
for i in 1:n
284+
for j in 1:n
285+
for ci in 1:D
286+
for cj in 1:D
287+
idof = (i-1)*D+ci
288+
jdof = (j-1)*D+cj
289+
ε_i .= 0
290+
ε_j .= 0
291+
for k in 1:n
292+
ε_i[ci,:] = collect(sg[k,i])
293+
ε_j[cj,:] = collect(sg[k,j])
294+
ε_i .= 0.5 .* ( ε_i .+ transpose(ε_i))
295+
ε_j .= 0.5 .* ( ε_j .+ transpose(ε_j))
296+
σ_j = λ*tr(ε_j)*one(ε_j) + 2*μ*ε_j
297+
Aref[idof,jdof] += tr(ε_i*σ_j)
298+
end
299+
end
300+
end
301+
end
302+
end
303+
Aref
304+
end
305+
function setup(cells,::Type{index_type},::Type{value_type}) where {index_type,value_type}
306+
D = length(nodes_per_dir)
307+
h_per_dir = map(i->1/(i+1),nodes_per_dir)
308+
ttt = ntuple(d->2,Val{D}())
309+
cartesian_local_nodes = CartesianIndices(ttt)
310+
Aref = ref_matrix(cartesian_local_nodes,h_per_dir,value_type)#ones(value_type,2^D,2^D)
311+
cell_to_cartesian_cell = CartesianIndices(cells_per_dir)
312+
first_cartesian_cell = cell_to_cartesian_cell[first(cells)]
313+
last_cartesian_cell = cell_to_cartesian_cell[last(cells)]
314+
ranges = map(:,Tuple(first_cartesian_cell),Tuple(last_cartesian_cell))
315+
cartesian_cells = CartesianIndices(ranges)
316+
offset = CartesianIndex(ttt)
317+
cartesian_local_node_to_local_node = LinearIndices(cartesian_local_nodes)
318+
cartesian_node_to_node = LinearIndices(nodes_per_dir)
319+
nnz = 0
320+
for cartesian_cell in cartesian_cells
321+
for cartesian_local_node_i in cartesian_local_nodes
322+
local_node_i = cartesian_local_node_to_local_node[cartesian_local_node_i]
323+
# This is ugly to support Julia 1.6 (idem below)
324+
cartesian_node_i = CartesianIndex(Tuple(cartesian_cell) .+ Tuple(cartesian_local_node_i) .- Tuple(offset))
325+
boundary = any(map(is_boundary_node,Tuple(cartesian_node_i),nodes_per_dir))
326+
if boundary
327+
continue
328+
end
329+
node_i = cartesian_node_to_node[cartesian_node_i]
330+
for cartesian_local_node_j in cartesian_local_nodes
331+
local_node_j = cartesian_local_node_to_local_node[cartesian_local_node_j]
332+
cartesian_node_j = CartesianIndex(Tuple(cartesian_cell) .+ Tuple(cartesian_local_node_j) .- Tuple(offset))
333+
boundary = any(map(is_boundary_node,Tuple(cartesian_node_j),nodes_per_dir))
334+
if boundary
335+
continue
336+
end
337+
node_j = cartesian_node_to_node[cartesian_node_j]
338+
nnz += D*D
339+
end
340+
end
341+
end
342+
myI = zeros(index_type,nnz)
343+
myJ = zeros(index_type,nnz)
344+
myV = zeros(value_type,nnz)
345+
k = 0
346+
for cartesian_cell in cartesian_cells
347+
for cartesian_local_node_i in cartesian_local_nodes
348+
local_node_i = cartesian_local_node_to_local_node[cartesian_local_node_i]
349+
cartesian_node_i = CartesianIndex(Tuple(cartesian_cell) .+ Tuple(cartesian_local_node_i) .- Tuple(offset))
350+
boundary = any(map(is_boundary_node,Tuple(cartesian_node_i),nodes_per_dir))
351+
if boundary
352+
continue
353+
end
354+
node_i = cartesian_node_to_node[cartesian_node_i]
355+
for cartesian_local_node_j in cartesian_local_nodes
356+
local_node_j = cartesian_local_node_to_local_node[cartesian_local_node_j]
357+
cartesian_node_j = CartesianIndex(Tuple(cartesian_cell) .+ Tuple(cartesian_local_node_j) .- Tuple(offset))
358+
boundary = any(map(is_boundary_node,Tuple(cartesian_node_j),nodes_per_dir))
359+
if boundary
360+
continue
361+
end
362+
node_j = cartesian_node_to_node[cartesian_node_j]
363+
for ci in 1:D
364+
for cj in 1:D
365+
dof_i = (node_i-1)*D + ci
366+
dof_j = (node_j-1)*D + cj
367+
local_dof_i = (local_node_i-1)*D + ci
368+
local_dof_j = (local_node_j-1)*D + cj
369+
k += 1
370+
myI[k] = dof_i
371+
myJ[k] = dof_j
372+
myV[k] = Aref[local_dof_i,local_dof_j]
373+
end
374+
end
375+
end
376+
end
377+
end
378+
myI,myJ,myV
379+
end
380+
node_partition = uniform_partition(parts,parts_per_dir,nodes_per_dir)
381+
global_node_to_owner = global_to_owner(node_partition)
382+
dof_partition = map(node_partition) do mynodes
383+
D = length(nodes_per_dir)
384+
own_to_global_node = own_to_global(mynodes)
385+
n_own_nodes = length(own_to_global_node)
386+
own_to_global_dof = zeros(Int,D*n_own_nodes)
387+
for own_node in 1:n_own_nodes
388+
for ci in 1:D
389+
own_dof = (own_node-1)*D+ci
390+
global_node = own_to_global_node[own_node]
391+
global_dof = (global_node-1)*D+ci
392+
own_to_global_dof[own_dof] = global_dof
393+
end
394+
end
395+
n_global_dofs = global_length(mynodes)*D
396+
owner = part_id(mynodes)
397+
own_dofs = OwnIndices(n_global_dofs,owner,own_to_global_dof)
398+
ghost_dofs = GhostIndices(n_global_dofs,Int[],Int32[])
399+
global_dof_to_owner = global_dof -> begin
400+
global_node = div(global_dof-1,D)+1
401+
global_node_to_owner[global_node]
402+
end
403+
mydofs = OwnAndGhostIndices(own_dofs,ghost_dofs,global_dof_to_owner)
404+
mydofs
405+
end
406+
cell_partition = uniform_partition(parts,parts_per_dir,cells_per_dir)
407+
I,J,V = map(cell_partition) do cells
408+
setup(cells,Ti,Tv)
409+
end |> tuple_of_arrays
410+
I,J,V,dof_partition,dof_partition
411+
end
412+
229413

test/gallery_tests.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ function gallery_tests(distribute,parts_per_dir)
3434
A |> centralize |> display
3535
Y = A*pones(axes(A,2))
3636
@test isa(y,PVector)
37+
38+
args = linear_elasticity_fem(nodes_per_dir,parts_per_dir,ranks)
39+
A = psparse(args...) |> fetch
40+
A |> centralize |> display
41+
Y = A*pones(axes(A,2))
42+
@test isa(y,PVector)
43+
3744
end
3845

3946

0 commit comments

Comments
 (0)