mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-20 18:18:31 +00:00
feat: Create IO submodule for mesh readers and result writers
New structure: - src/io/io.jl: IO submodule definition and exports - src/io/aster_reader.jl: Code Aster .med reader (ready for HDF5 extension) Benefits: - Clean separation of I/O code - ABAQUS reader works with stdlib only - Ready for package extensions (HDF5, LightXML) - Easy to add new formats (VTK, Gmsh, etc.) The IO submodule exports abaqus_read_mesh() to main JuliaFEM namespace.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# AbaqusReader consolidated into src/readers/ - no longer a separate package
|
||||
|
||||
"""
|
||||
abaqus_read_mesh(fn::String)
|
||||
|
||||
Read and parse ABAQUS `.inp` file.
|
||||
|
||||
`fn` (filename) is the name of the file to parse.
|
||||
"""
|
||||
function abaqus_read_mesh(fn::String)
|
||||
m = AbaqusReader.abaqus_read_mesh(fn)
|
||||
return Mesh(m)
|
||||
end
|
||||
|
||||
"""
|
||||
create_surface_elements(mesh::Mesh, surface_name::Symbol)
|
||||
|
||||
Create a set of surface elements from solid elements.
|
||||
|
||||
Notation follow what is defined in ABAQUS. For example, if solid elements
|
||||
are Tet10, surface elements will be Tri6 and they can be used to define
|
||||
boundary conditions.
|
||||
"""
|
||||
function create_surface_elements(mesh::Mesh, surface_name::Symbol)
|
||||
elements = Element[]
|
||||
for (elid, elsi) in mesh.surface_sets[surface_name]
|
||||
elty = mesh.element_types[elid]
|
||||
elco = mesh.elements[elid]
|
||||
chel, chcon = AbaqusReader.create_surface_element(elty, elsi, elco)
|
||||
ch = Element(getfield(JuliaFEM, chel), chcon)
|
||||
push!(elements, ch)
|
||||
end
|
||||
update!(elements, "geometry", mesh.nodes)
|
||||
return elements
|
||||
end
|
||||
|
||||
"""
|
||||
create_surface_elements(mesh::Mesh, surface_name::String)
|
||||
|
||||
Create a set of surface elements from solid elements.
|
||||
|
||||
Notation follow what is defined in ABAQUS. For example, if solid elements
|
||||
are Tet10, surface elements will be Tri6 and they can be used to define
|
||||
boundary conditions.
|
||||
"""
|
||||
function create_surface_elements(mesh::Mesh, surface_name::String)
|
||||
return create_surface_elements(mesh, Symbol(surface_name))
|
||||
end
|
||||
|
||||
"""
|
||||
create_nodal_elements(mesh::Mesh, node_set_name::String)
|
||||
|
||||
Create a set of "nodal" elements from node set.
|
||||
|
||||
Nodal elements are of type Poi1. In principle they don't have volume and it's
|
||||
not possible to integrate over them. It is however possible to add boundary
|
||||
conditions to them.
|
||||
"""
|
||||
function create_nodal_elements(mesh::Mesh, node_set_name::String)
|
||||
node_ids = mesh.node_sets[Symbol(node_set_name)]
|
||||
elements = [Element(Poi1, [j]) for j in node_ids]
|
||||
update!(elements, "geometry", mesh.nodes)
|
||||
return elements
|
||||
end
|
||||
@@ -0,0 +1,82 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# using AsterReader # Consolidated into src/readers/, functions are now directly available
|
||||
|
||||
"""
|
||||
Nodes are different order in Code Aster compared to ABAQUS. This is yet
|
||||
incomplete mapping between the permutations. Most of this is still a
|
||||
great mystery.
|
||||
|
||||
# References
|
||||
- http://onelab.info/pipermail/gmsh/2008/003850.html
|
||||
- http://caelinux.org/wiki/index.php/Proj:UNVConvert
|
||||
|
||||
"""
|
||||
const med_connectivity = Dict{Symbol,Vector{Int}}(
|
||||
:Tet4 => [4, 3, 1, 2],
|
||||
:Tet10 => [4, 3, 1, 2, 10, 7, 8, 9, 6, 5],
|
||||
:Pyr5 => [1, 4, 3, 2, 5],
|
||||
:Wedge6 => [4, 5, 6, 1, 2, 3],
|
||||
:Hex8 => [4, 8, 7, 3, 1, 5, 6, 2],
|
||||
:Hex20 => [4, 8, 7, 3, 1, 5, 6, 2, 20, 15, 19, 11, 12, 16, 14, 10, 17, 13, 18, 9],
|
||||
:Hex27 => [4, 8, 7, 3, 1, 5, 6, 2, 20, 15, 19, 11, 12, 16, 14, 10, 17, 13, 18, 9, 24, 25, 26, 23, 21, 22, 27])
|
||||
|
||||
"""
|
||||
Map element names used in in Code Aster to element names used in in JuliaFEM
|
||||
"""
|
||||
const med_element_names = Dict{Symbol,Symbol}(
|
||||
:PO1 => :Poi1,
|
||||
:SE2 => :Seg2,
|
||||
:SE3 => :Seg3,
|
||||
:SE4 => :Seg4,
|
||||
:TR3 => :Tri3,
|
||||
:TR6 => :Tri6,
|
||||
:TR7 => :Tri7,
|
||||
:QU4 => :Quad4,
|
||||
:QU8 => :Quad8,
|
||||
:QU9 => :Quad9,
|
||||
:TE4 => :Tet4,
|
||||
:T10 => :Tet10,
|
||||
:PE6 => :Wedge6,
|
||||
:P15 => :Wedge15,
|
||||
:P18 => :Wedge18,
|
||||
:HE8 => :Hex8,
|
||||
:H20 => :Hex20,
|
||||
:H27 => :Hex27,
|
||||
:PY5 => :Pyr5,
|
||||
:P13 => :Pyr13)
|
||||
|
||||
"""
|
||||
aster_read_mesh(filename, mesh_name=nothing; reorder_element_connectivity=true)
|
||||
|
||||
Read code aster mesh from file and return `Mesh` structure.
|
||||
|
||||
If mesh file contains several meshes, a name of mesh must be given. By default,
|
||||
elements are reordered so that they match to the conventions used in JuliaFEM.
|
||||
"""
|
||||
function aster_read_mesh(filename::String, mesh_name=nothing; reorder_element_connectivity=true)
|
||||
m = aster_read_mesh_raw(filename, mesh_name)
|
||||
mesh = Mesh(m)
|
||||
for (elid, eltype) in mesh.element_types
|
||||
mesh.element_types[elid] = med_element_names[eltype]
|
||||
end
|
||||
if reorder_element_connectivity
|
||||
reorder_element_connectivity!(mesh, med_connectivity)
|
||||
end
|
||||
nnodes = length(mesh.nodes)
|
||||
nelements = length(mesh.elements)
|
||||
@info("Mesh parsed from Code Aster file $filename.")
|
||||
@info("Mesh contains $nnodes nodes and $nelements elements.")
|
||||
for (elset_name, elset_elids) in mesh.element_sets
|
||||
content = Dict{Symbol,Int}()
|
||||
for elid in elset_elids
|
||||
eltype = mesh.element_types[elid]
|
||||
content[eltype] = get(content, eltype, 0) + 1
|
||||
end
|
||||
s = join(("$v x $k" for (k, v) in content), ", ")
|
||||
nels = length(elset_elids)
|
||||
@info("Element set $elset_name contains $nels elements ($s).")
|
||||
end
|
||||
return mesh
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
"""
|
||||
JuliaFEM.IO
|
||||
|
||||
Input/Output submodule for reading mesh files and writing results.
|
||||
|
||||
# Available (zero external dependencies)
|
||||
- `abaqus_read_mesh(filename)`: Read ABAQUS .inp files
|
||||
- `create_surface_elements(mesh, name)`: Create surface elements
|
||||
- `create_nodal_elements(mesh, name)`: Create nodal elements
|
||||
|
||||
# Future (requires optional dependencies)
|
||||
- Code Aster .med files: `aster_read_mesh` (requires HDF5.jl)
|
||||
- Xdmf output format: `Xdmf` writer (requires HDF5.jl + LightXML.jl)
|
||||
- VTK output: Native Julia implementation (no dependencies)
|
||||
|
||||
# Usage
|
||||
```julia
|
||||
using JuliaFEM
|
||||
mesh = abaqus_read_mesh("model.inp")
|
||||
body = create_elements(mesh, "BODY")
|
||||
```
|
||||
"""
|
||||
module IO
|
||||
|
||||
using ..JuliaFEM: Element, Mesh, add_node!, add_element_to_element_set!,
|
||||
add_node_to_node_set!
|
||||
|
||||
# Re-export for convenience
|
||||
import ..JuliaFEM.Preprocess
|
||||
using SparseArrays, LinearAlgebra
|
||||
using Logging
|
||||
|
||||
include("abaqus_reader.jl")
|
||||
export abaqus_read_mesh, create_surface_elements, create_nodal_elements
|
||||
|
||||
# AsterReader would go here when HDF5 is added as optional dependency
|
||||
# include("aster_reader.jl")
|
||||
# export aster_read_mesh
|
||||
|
||||
end # module IO
|
||||
Reference in New Issue
Block a user