Merge pull request #226 from JuliaFEM/kc/coloring

Implement matrix coloring.
This commit is contained in:
Jukka Aho
2019-04-08 18:56:11 +03:00
committed by GitHub
2 changed files with 101 additions and 1 deletions
+81 -1
View File
@@ -21,10 +21,11 @@ mutable struct Mesh
element_sets :: Dict{Symbol, Set{Int}}
surface_sets :: Dict{Symbol, Vector{Tuple{Int, Symbol}}}
surface_types :: Dict{Symbol, Symbol}
coloring::Union{Nothing, Vector{Vector{Int}}} # Each vector contains a list of elements that do not share nodes
end
function Mesh()
return Mesh(Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), Dict())
return Mesh(Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), nothing)
end
"""
@@ -319,3 +320,82 @@ function JuliaFEM.Problem(mesh::Mesh, ::Type{P}, name, dimension, parent_field_n
problem.elements = create_elements(mesh, name)
return problem
end
"""
create_coloring!(mesh::Mesh)
Greedy algorithm for coloring a grid such that no two cells with the same node
have the same color.
This function sets the `coloring` field in `mesh` to a `Vector{Vector{Int}}` where
each vector contains vectors of elements that do not share any nodes.
It is therefore safe to assemble in parallel each element vector by vector.
"""
function create_coloring!(mesh::Mesh)
# Contains the elements that each node contain
cell_containing_node = Dict{Int, Set{Int}}()
for (cellid, nodes) in mesh.elements
for v in nodes
if !haskey(cell_containing_node, v)
cell_containing_node[v] = Set{Int}()
end
push!(cell_containing_node[v], cellid)
end
end
I, J, V = Int[], Int[], Bool[]
for (node, cells) in cell_containing_node
for cell1 in cells # All these cells have a neighboring node
for cell2 in cells
if cell1 != cell2
push!(I, cell1)
push!(J, cell2)
push!(V, true)
end
end
end
end
incidence_matrix = sparse(I, J, V)
# cell -> color of cell
cell_colors = Dict{Int, Int}()
# color -> list of cells
final_colors = Vector{Int}[]
occupied_colors = Set{Int}()
# Zero represents no color set yet
for (cellid, _) in mesh.elements
cell_colors[cellid] = 0
end
total_colors = 0
for (cellid, _) in mesh.elements
empty!(occupied_colors)
# loop over neighbors
for r in nzrange(incidence_matrix, cellid)
cell_neighbour = incidence_matrix.rowval[r]
color = cell_colors[cell_neighbour]
if color != 0
push!(occupied_colors, color)
end
end
# occupied colors now contains all the colors we are not allowed to use
free_color = 0
for attempt_color in 1:total_colors
if attempt_color occupied_colors
free_color = attempt_color
break
end
end
if free_color == 0 # no free color found, need to bump max colors
total_colors += 1
free_color = total_colors
push!(final_colors, Int[])
end
cell_colors[cellid] = free_color
push!(final_colors[free_color], cellid)
end
mesh.coloring = final_colors
return mesh
end
+20
View File
@@ -0,0 +1,20 @@
using JuliaFEM, LinearAlgebra, Test
datadir = first(splitext(basename(@__FILE__)))
@testset "Test that mesh coloring provides a good coloring"
fn = joinpath(datadir, "cube_tet4.inp")
mesh = JuliaFEM.Mesh(open(parse_abaqus, fn))
JuliaFEM.create_coloring!(mesh)
for colors in mesh.coloring
for ele_i in colors
for ele_j in colors
if ele_i == ele_j
continue
end
@test intersect(Set(mesh.elements[ele_i]), Set(mesh.elements[ele_j])) |> isempty
end
end
end
end