@@ -226,4 +226,188 @@ function laplacian_fem(
226226 I,J,V,node_partition,node_partition
227227end
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
0 commit comments