mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-18 09:41:31 +00:00
code aster .med reader, notebook of 3d mortar.
This commit is contained in:
+1
-1
@@ -20,7 +20,7 @@ end
|
||||
|
||||
module Preprocess
|
||||
include("abaqus_reader.jl")
|
||||
include("aster_reader.jl")
|
||||
include("preprocess_aster_reader.jl")
|
||||
end
|
||||
|
||||
module Postprocess
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
|
||||
function aster_parse_nodes(section::ASCIIString; strip_characters=true)
|
||||
nodes = Dict{Any, Vector{Float64}}()
|
||||
has_started = false
|
||||
for line in split(section, '\n')
|
||||
m = matchall(r"[\w.-]+", line)
|
||||
if (length(m) != 1) && (!has_started)
|
||||
continue
|
||||
end
|
||||
if length(m) == 1
|
||||
if (m[1] == "COOR_2D") || (m[1] == "COOR_3D")
|
||||
has_started = true
|
||||
continue
|
||||
end
|
||||
if m[1] == "FINSF"
|
||||
break
|
||||
end
|
||||
end
|
||||
if length(m) == 4
|
||||
nid = m[1]
|
||||
if strip_characters
|
||||
nid = matchall(r"\d", nid)
|
||||
nid = parse(Int, nid[1])
|
||||
end
|
||||
nodes[nid] = float(m[2:end])
|
||||
end
|
||||
end
|
||||
return nodes
|
||||
end
|
||||
|
||||
function parse(mesh::ASCIIString, ::Type{Val{:CODE_ASTER_MAIL}})
|
||||
model = Dict{ASCIIString, Any}()
|
||||
header = nothing
|
||||
data = ASCIIString[]
|
||||
for line in split(mesh, '\n')
|
||||
length(line) != 0 || continue
|
||||
info("line: $line")
|
||||
if is_aster_mail_keyword(strip(line))
|
||||
header = parse_aster_header(line)
|
||||
empty!(data)
|
||||
continue
|
||||
end
|
||||
if line == "FINSF"
|
||||
info(data)
|
||||
header = nothing
|
||||
process_aster_section!(model, join(data, ""), header, Val{header[1]})
|
||||
end
|
||||
end
|
||||
return model
|
||||
end
|
||||
@@ -207,6 +207,7 @@ function call(solver::DirectSolver, time::Number=0.0)
|
||||
end
|
||||
K = sparse(field_assembly.stiffness_matrix)
|
||||
dim = size(K, 1)
|
||||
info("dim = $dim")
|
||||
f = sparse(field_assembly.force_vector, dim, 1)
|
||||
field_assembly = nothing
|
||||
gc()
|
||||
|
||||
+8
-1
@@ -15,7 +15,14 @@ function assemble!(assembly::Assembly, problem::BoundaryProblem{DirichletProblem
|
||||
|
||||
gdofs = get_gdofs(element, field_dim)
|
||||
for ip in get_integration_points(element, Val{2})
|
||||
w = ip.weight * det(element, ip, time)
|
||||
w = ip.weight
|
||||
J = get_jacobian(element, ip, time)
|
||||
JT = transpose(J)
|
||||
if size(JT, 2) == 1 # plane problem
|
||||
w *= norm(JT)
|
||||
else
|
||||
w *= norm(cross(JT[:,1], JT[:,2]))
|
||||
end
|
||||
N = element(ip, time)
|
||||
A = w*N'*N
|
||||
|
||||
|
||||
+12
-3
@@ -8,6 +8,10 @@ type Element{E<:AbstractElement}
|
||||
fields :: Dict{ASCIIString, Field}
|
||||
end
|
||||
|
||||
function Base.size{E}(::Element{E})
|
||||
return size(E)
|
||||
end
|
||||
|
||||
function convert{E}(::Type{Element{E}}, connectivity::Vector{Int})
|
||||
# return Element{E}(connectivity, get_integration_points(E), Dict())
|
||||
return Element{E}(connectivity, Dict())
|
||||
@@ -211,15 +215,20 @@ end
|
||||
|
||||
""" Return the determinant of jacobian. """
|
||||
function LinAlg.det{E<:AbstractElement}(element::Element{E}, xi::Vector{Float64}, time::Real)
|
||||
warn("det(element, ip, time) is ambiguous: use J = get_jacobian(element, ip, time); det(J) instead.")
|
||||
J = get_jacobian(element, xi, time)
|
||||
n, m = size(J)
|
||||
if n == m
|
||||
warn("det(element, ip, time) is ambiguous: use J = get_jacobian(element, ip, time); det(J) instead.")
|
||||
return det(J)
|
||||
end
|
||||
JT = transpose(J)
|
||||
s = size(JT, 2) == 1 ? norm(JT) : norm(cross(JT[:,1], JT[:,2]))
|
||||
return s
|
||||
if size(JT, 2) == 1
|
||||
warn("det(element, ip, time) is ambiguous: use J = get_jacobian(element, ip, time); norm(J) instead.")
|
||||
return norm(JT)
|
||||
else
|
||||
warn("det(element, ip, time) is ambiguous: use J = get_jacobian(element, ip, time); norm(cross(...)) instead.")
|
||||
return norm(cross(JT[:,1], JT[:,2]))
|
||||
end
|
||||
end
|
||||
function LinAlg.det{E<:AbstractElement}(element::Element{E}, ip::IntegrationPoint, time::Real)
|
||||
return det(element, ip.xi, time)
|
||||
|
||||
+71
-15
@@ -376,6 +376,29 @@ function get_points_inside_triangle(Y::Matrix, X::Matrix)
|
||||
return P
|
||||
end
|
||||
|
||||
"""
|
||||
Determine is point P inside or on boudary of polygon X.
|
||||
|
||||
http://paulbourke.net/geometry/polygonmesh/#insidepoly
|
||||
"""
|
||||
function is_point_inside_convex_polygon(P, X)
|
||||
x, y = P
|
||||
for i=1:length(X)
|
||||
x0, y0 = X[i]
|
||||
x1, y1 = X[mod(i, length(X))+1]
|
||||
if (y-y0)*(x1-x0) - (x-x0)*(y1-y0) < 0
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function get_points_inside_convex_polygon(pts, X)
|
||||
# TODO: Make more readable
|
||||
X2 = [X[:,i] for i=1:size(X,2)]
|
||||
c = filter(P->is_point_inside_convex_polygon(P, X2), [pts[:,i] for i=1:size(pts, 2)])
|
||||
return length(c) == 0 ? zeros(2, 0) : hcat(c...)
|
||||
end
|
||||
|
||||
""" Return unique objects with some given tolerance. This is used in next function
|
||||
because traditional unique() command returns row vectors as non-unique if they
|
||||
@@ -434,9 +457,18 @@ julia> n
|
||||
"""
|
||||
function clip_polygon(S::Matrix, M::Matrix)
|
||||
P1, neighbours = get_edge_intersections(M, S)
|
||||
P2 = get_points_inside_triangle(M, S)
|
||||
P3 = get_points_inside_triangle(S, M)
|
||||
#P2 = get_points_inside_triangle(M, S)
|
||||
#P3 = get_points_inside_triangle(S, M)
|
||||
P2 = get_points_inside_convex_polygon(M, S)
|
||||
P3 = get_points_inside_convex_polygon(S, M)
|
||||
# info("polygon clipping: P1 = $P1")
|
||||
# info("polygon clipping: P2 = $P2")
|
||||
# info("polygon clipping: P3 = $P3")
|
||||
# info("hcat P = $P")
|
||||
P = hcat(P1, P2, P3)
|
||||
if length(P) == 0
|
||||
return nothing, nothing
|
||||
end
|
||||
P = uniquetol(P, 2)
|
||||
meanval = mean(P, 2)
|
||||
tmp = P .- meanval
|
||||
@@ -654,7 +686,7 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::BoundaryPro
|
||||
end
|
||||
|
||||
|
||||
typealias MortarElements3D Union{Tri3}
|
||||
typealias MortarElements3D Union{Tri3, Quad4}
|
||||
|
||||
function assemble!{E<:MortarElements3D}(assembly::Assembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
|
||||
field_dim = problem.parent_field_dim
|
||||
@@ -666,13 +698,14 @@ function assemble!{E<:MortarElements3D}(assembly::Assembly, problem::BoundaryPro
|
||||
# create auxiliary plane and project slave nodes to it
|
||||
# x0 = origo, Q = local basis
|
||||
x0, Q = create_auxiliary_plane(slave_element, time)
|
||||
S = Vector{Float64}[]
|
||||
Sl = Vector{Float64}[]
|
||||
for p in slave_element("geometry", time)
|
||||
push!(S, project_point_to_auxiliary_plane(p, x0, Q))
|
||||
push!(Sl, project_point_to_auxiliary_plane(p, x0, Q))
|
||||
end
|
||||
S = reshape([S...;], 2, 3)
|
||||
#S = reshape([S...;], 2, size(slave_element)[2])
|
||||
S = hcat(Sl...)
|
||||
|
||||
integration_points = get_integration_points(E, Val{5})
|
||||
integration_points = get_integration_points(Tri3, Val{5})
|
||||
|
||||
for master_element in slave_element["master elements"]
|
||||
master_dofs = get_gdofs(master_element, field_dim)
|
||||
@@ -681,25 +714,48 @@ function assemble!{E<:MortarElements3D}(assembly::Assembly, problem::BoundaryPro
|
||||
for p in master_element("geometry", time)
|
||||
push!(M, project_point_to_auxiliary_plane(p, x0, Q))
|
||||
end
|
||||
M = reshape([M...;], 2, 3)
|
||||
P, neighbours = clip_polygon(S, M)
|
||||
#M = reshape([M...;], 2, size(master_element)[2])
|
||||
M = hcat(M...)
|
||||
P = nothing
|
||||
neighbours = nothing
|
||||
try
|
||||
P, neighbours = clip_polygon(S, M)
|
||||
catch
|
||||
info("polygon clipping failed")
|
||||
info("S = ")
|
||||
dump(S)
|
||||
info("M = ")
|
||||
dump(M)
|
||||
info("original Sl = ")
|
||||
info(Sl)
|
||||
error("cannot continue")
|
||||
end
|
||||
isa(P, Void) && continue # no clipping
|
||||
# info("polygon on auxilyary plane: ")
|
||||
# dump(round(P, 3))
|
||||
C = calculate_polygon_centerpoint(P)
|
||||
# info("center point = $C")
|
||||
|
||||
npts = size(P, 2) # number of vertices in polygon
|
||||
# info("number of vectices in polygon: $npts")
|
||||
# S = zeros(3, 3)
|
||||
# M = zeros(3, 3)
|
||||
for i=1:npts # loop vertices and create temporary integrate cells
|
||||
xvec = [C[1], P[1, i], P[1, mod(i, npts)+1]]
|
||||
yvec = [C[2], P[2, i], P[2, mod(i, npts)+1]]
|
||||
X = hcat(xvec, yvec)'
|
||||
# info("cell $i, coords = ")
|
||||
# dump(round(X, 3))
|
||||
geom = Field(Vector{Float64}[X[:,j] for j=1:size(X,2)])
|
||||
for ip in integration_points
|
||||
# calculate determiant of jacobian
|
||||
dN = get_dbasis(E, ip.xi)
|
||||
#dN = get_dbasis(E, ip.xi)
|
||||
dN = get_dbasis(Tri3, ip.xi)
|
||||
J = sum([kron(dN[:,j], geom[j]') for j=1:length(geom)])
|
||||
w = ip.weight*det(J)
|
||||
# gauss point in auxiliary plane
|
||||
N = get_basis(E, ip.xi)
|
||||
#N = get_basis(E, ip.xi)
|
||||
N = get_basis(Tri3, ip.xi)
|
||||
x = vec(N*geom)
|
||||
# find projection of gauss point to master and slave elements
|
||||
theta1 = project_point_from_plane_to_surface(x, x0, Q, slave_element, time)
|
||||
@@ -707,13 +763,13 @@ function assemble!{E<:MortarElements3D}(assembly::Assembly, problem::BoundaryPro
|
||||
# evaluate shape functions values in gauss point and add contribution to matrices
|
||||
N1 = slave_element(theta1[2:3], time)
|
||||
N2 = master_element(theta2[2:3], time)
|
||||
S = w*N1'*N1
|
||||
M = w*N1'*N2
|
||||
Sm = w*N1'*N1
|
||||
Mm = w*N1'*N2
|
||||
for k=1:field_dim
|
||||
sd = slave_dofs[k:field_dim:end]
|
||||
md = master_dofs[k:field_dim:end]
|
||||
add!(assembly.stiffness_matrix, sd, sd, S)
|
||||
add!(assembly.stiffness_matrix, sd, md, -M)
|
||||
add!(assembly.stiffness_matrix, sd, sd, Sm)
|
||||
add!(assembly.stiffness_matrix, sd, md, -Mm)
|
||||
# info("sd = $sd")
|
||||
# info("md = $md")
|
||||
end
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using HDF5
|
||||
|
||||
function aster_parse_nodes(section::ASCIIString; strip_characters=true)
|
||||
nodes = Dict{Any, Vector{Float64}}()
|
||||
has_started = false
|
||||
for line in split(section, '\n')
|
||||
m = matchall(r"[\w.-]+", line)
|
||||
if (length(m) != 1) && (!has_started)
|
||||
continue
|
||||
end
|
||||
if length(m) == 1
|
||||
if (m[1] == "COOR_2D") || (m[1] == "COOR_3D")
|
||||
has_started = true
|
||||
continue
|
||||
end
|
||||
if m[1] == "FINSF"
|
||||
break
|
||||
end
|
||||
end
|
||||
if length(m) == 4
|
||||
nid = m[1]
|
||||
if strip_characters
|
||||
nid = matchall(r"\d", nid)
|
||||
nid = parse(Int, nid[1])
|
||||
end
|
||||
nodes[nid] = float(m[2:end])
|
||||
end
|
||||
end
|
||||
return nodes
|
||||
end
|
||||
|
||||
function parse(mesh::ASCIIString, ::Type{Val{:CODE_ASTER_MAIL}})
|
||||
model = Dict{ASCIIString, Any}()
|
||||
header = nothing
|
||||
data = ASCIIString[]
|
||||
for line in split(mesh, '\n')
|
||||
length(line) != 0 || continue
|
||||
info("line: $line")
|
||||
if is_aster_mail_keyword(strip(line))
|
||||
header = parse_aster_header(line)
|
||||
empty!(data)
|
||||
continue
|
||||
end
|
||||
if line == "FINSF"
|
||||
info(data)
|
||||
header = nothing
|
||||
process_aster_section!(model, join(data, ""), header, Val{header[1]})
|
||||
end
|
||||
end
|
||||
return model
|
||||
end
|
||||
|
||||
"""
|
||||
Code Aster binary file (.med), which is exported from SALOME.
|
||||
"""
|
||||
type MEDFile
|
||||
data :: Dict
|
||||
end
|
||||
|
||||
function MEDFile(fn::ASCIIString)
|
||||
MEDFile(h5read(fn, "/"))
|
||||
end
|
||||
|
||||
function get_mesh_names(med::MEDFile)
|
||||
return collect(keys(med.data["FAS"]))
|
||||
end
|
||||
|
||||
function get_nodes(med::MEDFile, mesh_name)
|
||||
increments = keys(med.data["ENS_MAA"][mesh_name])
|
||||
@assert length(increments) == 1
|
||||
increment = first(increments)
|
||||
nodes = med.data["ENS_MAA"][mesh_name][increment]["NOE"]
|
||||
node_ids = nodes["NUM"]
|
||||
nnodes = length(node_ids)
|
||||
node_coords = nodes["COO"]
|
||||
dim = round(Int, length(node_coords)/nnodes)
|
||||
node_coords = reshape(node_coords, nnodes, dim)'
|
||||
d = Dict{Int64}{Vector{Float64}}()
|
||||
for i=1:nnodes
|
||||
d[node_ids[i]] = node_coords[:, i]
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
function get_element_sets(med::MEDFile, mesh_name)
|
||||
es = Dict{Int64, Symbol}()
|
||||
if !haskey(med.data["FAS"][mesh_name], "ELEME")
|
||||
return es
|
||||
end
|
||||
elsets = med.data["FAS"][mesh_name]["ELEME"]
|
||||
for elset in keys(elsets)
|
||||
k = split(elset, '_')
|
||||
elset_id = parse(Int, k[2])
|
||||
elset_name = ascii(pointer(convert(Vector{UInt8}, elsets[elset]["GRO"]["NOM"][1])))
|
||||
es[elset_id] = Symbol(elset_name)
|
||||
end
|
||||
return es
|
||||
end
|
||||
|
||||
function get_connectivity(med::MEDFile, elsets, mesh_name)
|
||||
elsets[0] = :OTHER
|
||||
increments = keys(med.data["ENS_MAA"][mesh_name])
|
||||
@assert length(increments) == 1
|
||||
increment = first(increments)
|
||||
all_elements = med.data["ENS_MAA"][mesh_name][increment]["MAI"]
|
||||
d = Dict{Int64, Tuple{Symbol, Symbol, Vector{Int64}}}()
|
||||
for eltype in keys(all_elements)
|
||||
elements = all_elements[eltype]
|
||||
elset_ids = elements["FAM"]
|
||||
element_ids = elements["NUM"]
|
||||
nelements = length(element_ids)
|
||||
element_connectivity = elements["NOD"]
|
||||
element_dim = round(Int, length(element_connectivity)/nelements)
|
||||
element_connectivity = reshape(element_connectivity, nelements, element_dim)'
|
||||
for i=1:nelements
|
||||
d[element_ids[i]] = (Symbol(eltype), Symbol(elsets[elset_ids[i]]), element_connectivity[:, i])
|
||||
end
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
""" Parse code aster .med file.
|
||||
|
||||
Paramters
|
||||
---------
|
||||
fn :: ASCIIString
|
||||
file name to parse
|
||||
mesh_name :: ASCIIString, optional
|
||||
mesh name, if several meshes in one file
|
||||
|
||||
Returns
|
||||
-------
|
||||
Dict containing fields "nodes" and "connectivity".
|
||||
|
||||
"""
|
||||
function parse_aster_med_file(fn::ASCIIString, mesh_name=nothing)
|
||||
med = MEDFile(fn)
|
||||
if isa(mesh_name, Void)
|
||||
mesh_names = get_mesh_names(med::MEDFile)
|
||||
all_meshes = join(mesh_names, ", ")
|
||||
length(mesh_names) == 1 || error("several meshes found from med, pick one: $all_meshes")
|
||||
mesh_name = mesh_names[1]
|
||||
end
|
||||
elsets = get_element_sets(med, mesh_name)
|
||||
elset_names = join(values(elsets), ", ")
|
||||
info("Found $(length(elsets)) element sets: $elset_names")
|
||||
nodes = get_nodes(med, mesh_name)
|
||||
conn = get_connectivity(med, elsets, mesh_name)
|
||||
result = Dict{ASCIIString, Any}()
|
||||
result["nodes"] = nodes
|
||||
result["connectivity"] = conn
|
||||
return result
|
||||
end
|
||||
|
||||
+4
-1
@@ -87,6 +87,7 @@ common situation, i.e., some main field problem and it's Dirichlet boundary.
|
||||
"""
|
||||
function call(solver::LinearSolver, time::Float64)
|
||||
|
||||
t0 = Base.time()
|
||||
field_name = get_unknown_field_name(solver.field_problems[1])
|
||||
field_dim = get_unknown_field_dimension(solver.field_problems[1])
|
||||
info("solving $field_name problem, $field_dim dofs / nodes")
|
||||
@@ -94,7 +95,7 @@ function call(solver::LinearSolver, time::Float64)
|
||||
field_assembly = assemble(solver.field_problems[1], time)
|
||||
boundary_assembly = assemble(solver.boundary_problems[1], time)
|
||||
|
||||
info("Creating sparse matrices")
|
||||
#info("Creating sparse matrices")
|
||||
K = sparse(field_assembly.stiffness_matrix)
|
||||
dim = size(K, 1)
|
||||
f = sparse(field_assembly.force_vector, dim, 1)
|
||||
@@ -132,6 +133,8 @@ function call(solver::LinearSolver, time::Float64)
|
||||
end
|
||||
end
|
||||
|
||||
t1 = round(Base.time()-t0, 2)
|
||||
info("solved problem in $t1 seconds.")
|
||||
return norm(u)
|
||||
end
|
||||
|
||||
|
||||
+2
-1
@@ -37,8 +37,9 @@ using LightXML
|
||||
# > #define XDMF_3DCORECTMESH 0x1102
|
||||
|
||||
global eltypes = Dict{Symbol, Int}(
|
||||
:Tet4 => 0x6,
|
||||
:Quad4 => 0x5,
|
||||
:Tet4 => 0x6,
|
||||
:Hex8 => 0x9,
|
||||
:Tet10 => 0x0026)
|
||||
|
||||
function xdmf_new_model(xdmf_version="2.1")
|
||||
|
||||
Reference in New Issue
Block a user