Files
JuliaFEM.jl/src/preprocess.jl
T

322 lines
9.2 KiB
Julia
Raw Normal View History

# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
2016-07-03 05:01:18 +03:00
#=
- read meshes from different formats
- reorder connectivity, create element sets, node sets, ...
- create partitions for parallel runs
- renumber elements / nodes
- maybe precheck for bad elements
- check surface normal direction in boundary elements
- orientation of 2d elements
- etc only topology related stuff
=#
2018-07-05 11:21:10 +03:00
mutable struct Mesh
2017-02-25 18:40:14 +02:00
nodes :: Dict{Int, Vector{Float64}}
node_sets :: Dict{Symbol, Set{Int}}
elements :: Dict{Int, Vector{Int}}
element_types :: Dict{Int, Symbol}
element_codes :: Dict{Int, Symbol}
element_sets :: Dict{Symbol, Set{Int}}
surface_sets :: Dict{Symbol, Vector{Tuple{Int, Symbol}}}
surface_types :: Dict{Symbol, Symbol}
end
function Mesh()
return Mesh(Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), Dict())
end
2017-07-21 00:40:52 +03:00
"""
Mesh(m::Dict)
2017-08-23 15:28:20 +03:00
Create a new `Mesh` using data `m`. It is assumed that `m` is in format what
2017-07-21 00:40:52 +03:00
`abaqus_read_mesh` in `AbaqusReader.jl` is returning.
"""
function Mesh(m::Dict)
mesh = Mesh()
mesh.nodes = m["nodes"]
mesh.elements = m["elements"]
mesh.element_types = m["element_types"]
2018-09-06 12:02:56 +03:00
for (k, v) in m["surface_types"]
mesh.surface_types[Symbol(k)] = v
end
2017-07-21 00:40:52 +03:00
for (nset_name, node_ids) in m["node_sets"]
mesh.node_sets[Symbol(nset_name)] = Set(node_ids)
end
for (elset_name, element_ids) in m["element_sets"]
mesh.element_sets[Symbol(elset_name)] = Set(element_ids)
end
for (surfset_name, surfaces) in m["surface_sets"]
mesh.surface_sets[Symbol(surfset_name)] = surfaces
end
return mesh
end
2017-08-23 15:28:20 +03:00
"""
add_node!(mesh, nid, ncoords)
Add node into the mesh. `nid` is node id and `ncoords` are the node
coordinates.
"""
function add_node!(mesh::Mesh, nid::Int, ncoords::Vector{Float64})
mesh.nodes[nid] = ncoords
end
2017-08-23 15:28:20 +03:00
"""
add_nodes!(mesh, nodes)
Add nodes into the mesh.
"""
2017-02-25 18:40:14 +02:00
function add_nodes!(mesh::Mesh, nodes::Dict{Int, Vector{Float64}})
2016-06-25 04:12:53 +03:00
for (nid, ncoords) in nodes
add_node!(mesh, nid, ncoords)
end
end
2017-08-23 15:28:20 +03:00
"""
add_node_to_node_set!(mesh, nid, ncoords)
Add nodes into a node set. `set_name` is the name of the set and `nids...`
are all the node id:s that wants to be added.
"""
function add_node_to_node_set!(mesh::Mesh, set_name, nids...)
2016-06-25 04:12:53 +03:00
if !haskey(mesh.node_sets, set_name)
2017-02-25 18:40:14 +02:00
mesh.node_sets[set_name] = Set{Int}()
2016-06-25 04:12:53 +03:00
end
push!(mesh.node_sets[set_name], nids...)
2017-02-25 18:40:14 +02:00
return
2016-06-25 04:12:53 +03:00
end
2017-08-23 15:28:20 +03:00
"""
create_node_set_from_element_set!(mesh, set_names...)
Create a new node set from the nodes in an element set. ´set_names...´ are all
the set names to be inserted in the function.
"""
2017-02-27 07:33:06 +02:00
function create_node_set_from_element_set!(mesh::Mesh, set_names::String...)
for set_name in set_names
set_name = Symbol(set_name)
2018-09-06 12:02:56 +03:00
@info("Creating node set $set_name from element set")
2017-02-27 07:33:06 +02:00
node_ids = Set{Int}()
for elid in mesh.element_sets[set_name]
push!(node_ids, mesh.elements[elid]...)
end
mesh.node_sets[set_name] = node_ids
2017-02-25 18:40:14 +02:00
end
return
end
2017-08-23 15:28:20 +03:00
"""
create_node_set_from_element_set!(mesh, set_name)
Create a new node set from an element set.
"""
2017-02-27 08:27:08 +02:00
function create_node_set_from_element_set!(mesh::Mesh, set_name::Symbol)
create_node_set_from_element_set!(mesh, string(set_name))
end
2017-08-23 15:28:20 +03:00
"""
add_element!(mesh, elid, eltype, connectivity)
Add an element into the mesh. ´elid´ is the element id, ´eltype´ is the type of
the element and ´connectivity´ is the connectivity of the element.
"""
2018-09-06 12:02:56 +03:00
function FEMBase.add_element!(mesh::Mesh, elid, eltype, connectivity)
mesh.elements[elid] = connectivity
mesh.element_types[elid] = eltype
2018-09-06 12:02:56 +03:00
return nothing
end
2017-08-23 15:28:20 +03:00
"""
add_elements!(mesh, elements)
Add elements into the mesh.
"""
2018-09-06 12:02:56 +03:00
function FEMBase.add_elements!(mesh::Mesh, elements::Dict{Int, Tuple{Symbol, Vector{Int}}})
2016-06-25 04:12:53 +03:00
for (elid, (eltype, elcon)) in elements
add_element!(mesh, elid, eltype, elcon)
end
2018-09-06 12:02:56 +03:00
return nothing
2016-06-25 04:12:53 +03:00
end
2017-08-23 15:28:20 +03:00
"""
add_element_to_element_set!(mesh, set_name, elids...)
Add elements into the mesh. ´set_name´ is the name of the element set and
´elids..´ are id:s of all the elements that wants to be added.
"""
function add_element_to_element_set!(mesh::Mesh, set_name, elids...)
if !haskey(mesh.element_sets, set_name)
2017-02-25 18:40:14 +02:00
mesh.element_sets[set_name] = Set{Int}()
end
push!(mesh.element_sets[set_name], elids...)
end
2017-08-23 15:28:20 +03:00
"""
copy(mesh)
2018-09-06 12:02:56 +03:00
Return a copy of the mesh.
2017-08-23 15:28:20 +03:00
"""
2018-09-06 12:02:56 +03:00
function Base.copy(mesh::Mesh)
mesh2 = Mesh()
mesh2.nodes = copy(mesh.nodes)
mesh2.node_sets = copy(mesh.node_sets)
mesh2.elements = copy(mesh.elements)
mesh2.element_types = copy(mesh.element_types)
mesh2.element_sets = copy(mesh.element_sets)
return mesh2
end
2017-08-23 15:28:20 +03:00
"""
filter_by_element_id(mesh, element_ids)
Filter elements by their id's.
"""
2017-02-25 18:40:14 +02:00
function filter_by_element_id(mesh::Mesh, element_ids::Vector{Int})
mesh2 = copy(mesh)
mesh2.elements = Dict()
for elid in element_ids
if haskey(mesh.elements, elid)
mesh2.elements[elid] = mesh.elements[elid]
end
end
return mesh2
end
2017-08-23 15:28:20 +03:00
"""
filter_by_element_set(mesh, set_name)
Filter elements by an element set.
"""
function filter_by_element_set(mesh::Mesh, set_name)
filter_by_element_id(mesh::Mesh, collect(mesh.element_sets[set_name]))
end
2017-08-23 15:28:20 +03:00
"""
create_element(mesh, id)
Create an element from the mesh by it's id.
"""
2016-07-14 12:43:41 +03:00
function create_element(mesh::Mesh, id::Int)
connectivity = mesh.elements[id]
2016-11-13 13:24:08 +02:00
element_type = getfield(JuliaFEM, mesh.element_types[id])
2016-07-14 12:43:41 +03:00
element = Element(element_type, connectivity)
element.id = id
2016-11-28 10:09:48 +02:00
update!(element, "geometry", mesh.nodes)
2016-07-14 12:43:41 +03:00
return element
end
function create_elements(mesh::Mesh; element_type=nothing)
element_ids = collect(keys(mesh.elements))
if element_type != nothing
filter!(id -> mesh.element_types[id] == element_type, element_ids)
end
2016-07-14 12:43:41 +03:00
elements = [create_element(mesh, id) for id in element_ids]
return elements
end
function create_elements(mesh::Mesh, element_sets::Symbol...; element_type=nothing)
if isempty(element_sets)
element_ids = collect(keys(mesh.elements))
else
2017-02-25 18:40:14 +02:00
element_ids = Set{Int}()
for set_name in element_sets
element_ids = union(element_ids, mesh.element_sets[set_name])
end
2016-07-03 05:01:18 +03:00
end
if element_type != nothing
filter!(id -> mesh.element_types[id] == element_type, element_ids)
2016-07-03 05:01:18 +03:00
end
2016-07-14 12:43:41 +03:00
elements = [create_element(mesh, id) for id in element_ids]
2018-09-06 12:02:56 +03:00
nelements = length(elements)
content = Dict{Symbol, Int}()
for elid in element_ids
eltype = mesh.element_types[elid]
content[eltype] = get(content, eltype, 0) + 1
end
s = join(("$v x $k" for (k, v) in content), ", ")
v = join(element_sets, ", ")
@info("Created $nelements elements ($s) from element set: $v.")
2016-07-03 05:01:18 +03:00
return elements
end
2018-09-06 12:02:56 +03:00
"""
create_elements(mesh::Mesh, element_set::String)
# Examples
Suppose that there is a `mesh` with element set `Body_1`. Creating elements
based on that element set is done then
```julia
create_elements(mesh, "Body_1")
```
"""
function create_elements(mesh::Mesh, element_sets::String...)
return create_elements(mesh, map(Symbol, element_sets)...)
end
2017-08-23 15:28:20 +03:00
"""
find_nearest_nodes(mesh, coords, npts=1; node_set=nothing)
find npts nearest nodes from the mesh and return their id numbers as a list.
"""
2017-02-27 07:33:06 +02:00
function find_nearest_nodes(mesh::Mesh, coords::Vector{Float64}, npts::Int=1; node_set=nothing)
2017-02-25 18:40:14 +02:00
dist = Dict{Int, Float64}()
2016-06-25 04:12:53 +03:00
for (nid, c) in mesh.nodes
2017-02-27 07:33:06 +02:00
if node_set != nothing && !(nid in mesh.node_sets[Symbol(node_set)])
continue
end
2016-06-25 04:12:53 +03:00
dist[nid] = norm(coords-c)
end
s = sort(collect(dist), by=x->x[2])
nd = s[1:npts] # [(id1, dist1), (id2, dist2), ..., (id_npts, dist_npts)]
node_ids = [n[1] for n in nd]
return node_ids
end
2017-02-27 08:27:08 +02:00
function find_nearest_node(mesh::Mesh, coords::Vector{Float64}; node_set=nothing)
return first(find_nearest_nodes(mesh, coords, 1; node_set=node_set))
end
2016-07-03 05:01:18 +03:00
"""
2017-08-23 15:28:20 +03:00
reorder_element_connectivity!(mesh, mapping)
Apply a new node ordering to elements. JuliaFEM uses the same node ordering as
ABAQUS. If the mesh is parsed from FEM format with some other node ordering,
this function can be used to reorder the nodes.
2016-07-03 05:01:18 +03:00
Parameters
----------
mapping :: Dict{Symbol, Vector{Int}}
e.g. :Tet10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
"""
function reorder_element_connectivity!(mesh::Mesh, mapping::Dict{Symbol, Vector{Int}})
for (elid, eltype) in mesh.element_types
haskey(mapping, eltype) || continue
new_order = mapping[eltype]
element_connectivity = mesh.elements[elid]
new_element_connectivity = element_connectivity[new_order]
mesh.elements[elid] = new_element_connectivity
end
end
2018-07-05 11:21:10 +03:00
function JuliaFEM.Problem(mesh::Mesh, ::Type{P}, name::AbstractString, dimension::Int) where P<:FieldProblem
2016-10-01 13:37:15 +03:00
problem = Problem(P, name, dimension)
problem.elements = create_elements(mesh, name)
return problem
end
2018-07-05 11:21:10 +03:00
function JuliaFEM.Problem(mesh::Mesh, ::Type{P}, name, dimension, parent_field_name) where P<:BoundaryProblem
2016-10-01 13:37:15 +03:00
problem = Problem(P, name, dimension, parent_field_name)
problem.elements = create_elements(mesh, name)
return problem
end