mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-30 05:19:19 +00:00
Use package AbaqusReader.jl (#127)
Source code related to read and parse ABAQUS .inp files is now living in it's own repository `AbaqusReader.jl` and in this commit we cleanup the same files from this repository. - add AbaqusReader to .travis.yml because it's not registered package yet - initialize Mesh from AbaqusReader.jl dict - remove ABAQUS tests and files moved to AbaqusReader.jl - remove references to old module Abaqus - move ABAQUS code to preprocess.jl (what is left) - close issue #122 - close issue #55
This commit is contained in:
@@ -1,264 +0,0 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
element_has_nodes(::Type{Val{:C3D4}}) = 4
|
||||
element_has_type( ::Type{Val{:C3D4}}) = :Tet4
|
||||
|
||||
element_has_nodes(::Type{Val{:C3D8}}) = 8
|
||||
element_has_type( ::Type{Val{:C3D8}}) = :Hex8
|
||||
|
||||
element_has_nodes(::Type{Val{:C3D10}}) = 10
|
||||
element_has_type(::Type{Val{:C3D10}}) = :Tet10
|
||||
|
||||
element_has_nodes(::Type{Val{:C3D20}}) = 20
|
||||
|
||||
element_has_nodes(::Type{Val{:C3D20E}}) = 20
|
||||
|
||||
element_has_nodes(::Type{Val{:S3}}) = 3
|
||||
element_has_type( ::Type{Val{:S3}}) = :Tri3
|
||||
|
||||
element_has_nodes(::Type{Val{:STRI65}}) = 6
|
||||
element_has_type(::Type{Val{:STRI65}}) = :Tri6
|
||||
|
||||
element_has_nodes(::Type{Val{:CPS4}}) = 4
|
||||
element_has_type(::Type{Val{:CPS4}}) = :Quad4
|
||||
|
||||
"""
|
||||
Checks for if line is a comment line or just empty
|
||||
"""
|
||||
function empty_or_comment_line{T<:AbstractString}(line::T)
|
||||
startswith(line, "**") || (length(line) == 0)
|
||||
end
|
||||
|
||||
"""
|
||||
Function for parsing nodes from the file
|
||||
"""
|
||||
function parse_section(model, lines, key::Symbol, idx_start,
|
||||
idx_end, ::Type{Val{:NODE}})
|
||||
|
||||
info("Parsing *NODE block between lines $idx_start .. $idx_end")
|
||||
nnodes = 0
|
||||
ids = Integer[]
|
||||
definition = lines[idx_start]
|
||||
debug("Definition line = $definition")
|
||||
for line in lines[idx_start + 1: idx_end]
|
||||
if !(empty_or_comment_line(line))
|
||||
m = matchall(r"[-0-9.eE+]+", line)
|
||||
node_id = parse(Int, m[1])
|
||||
coords = float(m[2:end])
|
||||
model["nodes"][node_id] = coords
|
||||
nnodes += 1
|
||||
end
|
||||
end
|
||||
info("$nnodes nodes found")
|
||||
has_set_def = match(r"NSET=([\w\_\-]+)", definition)
|
||||
if has_set_def != nothing
|
||||
set_name = has_set_def[1]
|
||||
info("Creating node set $set_name")
|
||||
model["nsets"][set_name] = ids
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
Custon regex to find match from string. Index used if there are multiple matches
|
||||
"""
|
||||
function regex_match(regex_str, line, idx)
|
||||
return match(regex_str, line).captures[idx]
|
||||
println(eltype_sym)
|
||||
end
|
||||
|
||||
"""
|
||||
Simple iterator for comsuming element list. Depending
|
||||
on the used element, connectivity nodes might be listed
|
||||
in multiple lines, which is why iterator is used to handle
|
||||
this problem.
|
||||
"""
|
||||
function consumeList(arr, start, stop)
|
||||
function _it()
|
||||
for i=start:stop
|
||||
produce(arr[i])
|
||||
end
|
||||
end
|
||||
Task(_it)
|
||||
end
|
||||
|
||||
"""
|
||||
Parse elements from input.
|
||||
"""
|
||||
function parse_section(model, lines, key, idx_start, idx_end, ::Type{Val{:ELEMENT}})
|
||||
#definition = uppercase(lines[idx_start])
|
||||
definition = lines[idx_start]
|
||||
element_type = regex_match(r"TYPE=([\w\-\_]+)", definition, 1)
|
||||
eltype_sym = Symbol(element_type)
|
||||
eltype_nodes = element_has_nodes(Val{eltype_sym})
|
||||
element_type = element_has_type(Val{eltype_sym})
|
||||
info("Parsing elements. Type: $(element_type)")
|
||||
list_iterator = consumeList(lines, idx_start+1, idx_end)
|
||||
ids = Integer[]
|
||||
line = consume(list_iterator)
|
||||
while line != nothing
|
||||
arr_num_as_str = matchall(r"[0-9]+", line)
|
||||
numbers = map(x-> parse(Int, x), arr_num_as_str)
|
||||
if !(empty_or_comment_line(line))
|
||||
id = numbers[1]
|
||||
push!(ids, id)
|
||||
connectivity = numbers[2:end]
|
||||
while length(connectivity) != eltype_nodes
|
||||
@assert length(connectivity) < eltype_nodes
|
||||
line = consume(list_iterator)
|
||||
arr_num_as_str = matchall(r"[0-9]+", line)
|
||||
numbers = map(x-> parse(Int, x), arr_num_as_str)
|
||||
push!(connectivity, numbers...)
|
||||
end
|
||||
model["elements"][id] = Dict(("type"=>element_type),
|
||||
("connectivity"=>connectivity))
|
||||
end
|
||||
line = consume(list_iterator)
|
||||
end
|
||||
has_set_def = match(r"ELSET=([\w\_\-]+)", definition)
|
||||
if has_set_def != nothing
|
||||
set_name = has_set_def[1]
|
||||
info("Creating elset $set_name")
|
||||
model["elsets"][set_name] = ids
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
Parsing Node- and ElementSets.
|
||||
"""
|
||||
function parse_section(model, lines, key, idx_start, idx_end, ::Union{Type{Val{:NSET}}, Type{Val{:ELSET}}})
|
||||
set_regex_string = Dict(:NSET => r"NSET=([\w\-\_]+)",
|
||||
:ELSET => r"ELSET=([\w\-\_]+)" )
|
||||
#definition = uppercase(lines[idx_start])
|
||||
# FIXME: do not uppercase set names
|
||||
definition = lines[idx_start]
|
||||
regex_string = set_regex_string[key]
|
||||
set_name = regex_match(regex_string, definition, 1)
|
||||
info("Creating $(lowercase(string(key))) $set_name")
|
||||
data = Integer[]
|
||||
if endswith(strip(definition), "GENERATE")
|
||||
line = lines[idx_start + 1]
|
||||
m = matchall(r"[0-9]+", line)
|
||||
first_id, last_id, step = map(x-> parse(Int, x), m)
|
||||
set_ids = collect(first_id:step:last_id)
|
||||
push!(data, set_ids...)
|
||||
else
|
||||
for line in lines[idx_start + 1: idx_end]
|
||||
if !(empty_or_comment_line(line))
|
||||
m = matchall(r"[0-9]+", line)
|
||||
set_ids = map(s -> parse(Int, s), m)
|
||||
try
|
||||
push!(data, set_ids...)
|
||||
catch err
|
||||
if isa(err, MethodError)
|
||||
warn("Problems with element set creation")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
selected_set = key == :NSET ? "nsets" : "elsets"
|
||||
model[selected_set][set_name] = data
|
||||
end
|
||||
|
||||
"""
|
||||
Parse SURFACE keyword
|
||||
"""
|
||||
function parse_section(model, lines, key, idx_start, idx_end, ::Type{Val{:SURFACE}})
|
||||
debug("Parsing surface")
|
||||
#definition = uppercase(lines[idx_start])
|
||||
definition = lines[idx_start]
|
||||
#has_set_def = match(r"TYPE=([\w\_\-]+),.*NAME=([\w\_\-]+)", definition)
|
||||
has_set_def = Dict(map(y -> lowercase(strip(y[1])) => strip(y[2]), map(x -> split(x, "="), matchall(r"([\w\_\-]+[ ]*=[ ]*[\w\_\-]+)", definition))))
|
||||
has_set_def != nothing || return
|
||||
debug(has_set_def)
|
||||
set_type = Symbol(get(has_set_def, "type", "UNKNOWN"))
|
||||
set_name = Symbol(has_set_def["name"])
|
||||
data = Vector{Tuple{Int64, Symbol}}()
|
||||
for line in lines[idx_start + 1: idx_end]
|
||||
empty_or_comment_line(line) && continue
|
||||
m = match(r"(?P<element_id>\d+),.*(?P<element_side>S\d+).*", line)
|
||||
if isa(m, Void)
|
||||
warn("read_abaqus, parsing surface: line $line")
|
||||
continue
|
||||
end
|
||||
element_id = parse(Int, m[:element_id])
|
||||
element_side = Symbol(m[:element_side])
|
||||
push!(data, (element_id, element_side))
|
||||
end
|
||||
model["surface_types"][set_name] = set_type
|
||||
model["surfaces"][set_name] = data
|
||||
return
|
||||
end
|
||||
|
||||
"""
|
||||
Find lines, which contain keywords, for example "*NODE"
|
||||
"""
|
||||
function find_keywords(lines)
|
||||
indexes = Integer[]
|
||||
for (idx, line) in enumerate(lines)
|
||||
if startswith(line, "*") && !startswith(line, "**")
|
||||
push!(indexes, idx)
|
||||
end
|
||||
end
|
||||
return indexes
|
||||
end
|
||||
|
||||
"""
|
||||
Main function for parsing Abaqus input file.
|
||||
"""
|
||||
function parse_abaqus(fid::IOStream)
|
||||
lines = readlines(fid)
|
||||
keyword_indexes = find_keywords(lines)
|
||||
nkeyword_indexes = length(keyword_indexes)
|
||||
debug("$nkeyword_indexes keyword indexes found: $keyword_indexes")
|
||||
|
||||
push!(keyword_indexes, length(lines)+1)
|
||||
idx_start = keyword_indexes[1]
|
||||
keyword_sym::Symbol = :none
|
||||
parser::Function = x->()
|
||||
model = Dict{AbstractString, Any}()
|
||||
model["nodes"] = Dict{Int64, Vector{Float64}}()
|
||||
model["nsets"] = Dict{AbstractString, Vector{Int64}}()
|
||||
model["elsets"] = Dict{AbstractString, Vector{Int64}}()
|
||||
model["elements"] = Dict{Integer, Any}()
|
||||
model["surfaces"] = Dict{Symbol, Vector{Tuple{Int64, Symbol}}}()
|
||||
model["surface_types"] = Dict{Symbol, Symbol}()
|
||||
for idx_end in keyword_indexes[2:end]
|
||||
keyword_line = strip(uppercase(lines[idx_start]))
|
||||
keyword = strip(regex_match(r"\s*([\w ]+)", keyword_line, 1))
|
||||
k_sym = Symbol(keyword)
|
||||
args = Tuple{Dict, Vector{Int}, Symbol, Int, Int, Type{Val{k_sym}}}
|
||||
if method_exists(parse_section, args)
|
||||
parse_section(model, lines, k_sym, idx_start, idx_end-1, Val{k_sym})
|
||||
else
|
||||
debug("Unknown section: '$(keyword)'")
|
||||
debug("keyword_line = '$keyword_line'")
|
||||
debug("idx_start = $idx_start, idx_end = $idx_end")
|
||||
end
|
||||
idx_start = idx_end
|
||||
end
|
||||
return model
|
||||
end
|
||||
|
||||
function abaqus_read_mesh(fn)
|
||||
model = open(parse_abaqus, fn)
|
||||
mesh = Mesh()
|
||||
mesh.nodes = model["nodes"]
|
||||
for (nset_name, node_ids) in model["nsets"]
|
||||
mesh.node_sets[Symbol(nset_name)] = Set(node_ids)
|
||||
end
|
||||
for (elid, eldata) in model["elements"]
|
||||
eltype = eldata["type"]
|
||||
elcon = eldata["connectivity"]
|
||||
mesh.elements[elid] = elcon
|
||||
mesh.element_types[elid] = eltype
|
||||
end
|
||||
for (elset_name, element_ids) in model["elsets"]
|
||||
mesh.element_sets[Symbol(elset_name)] = Set(element_ids)
|
||||
end
|
||||
mesh.surface_sets = model["surfaces"]
|
||||
mesh.surface_types = model["surface_types"]
|
||||
return mesh
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user