mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-01 00:36:24 +00:00
heat solver tests etc
This commit is contained in:
+17
-28
@@ -27,33 +27,17 @@ export AbstractPoint, Point, IntegrationPoint, IP, Node
|
||||
include("elements.jl") # common element routines
|
||||
export Node, AbstractElement, Element, update!, get_connectivity, get_basis, get_dbasis
|
||||
include("lagrange_macro.jl") # Continuous Galerkin (Lagrange) elements generated using macro
|
||||
include("lagrange.jl") # Continuous Galerkin (Lagrange) elements
|
||||
export get_reference_coordinates
|
||||
export Poi1,
|
||||
Seg2, Seg3,
|
||||
Tri3, Tri6, Quad4, Quad8, Quad9,
|
||||
Tet4, Tet10, Hex8, Hex20, Hex27
|
||||
|
||||
type Poi1 <: AbstractElement
|
||||
end
|
||||
|
||||
function size(element::Element{Poi1})
|
||||
return (0, 1)
|
||||
end
|
||||
|
||||
function length(element::Element{Poi1})
|
||||
return 1
|
||||
end
|
||||
|
||||
function get_basis(element::Element{Poi1}, ip, time)
|
||||
return [1]
|
||||
end
|
||||
|
||||
function call(element::Element{Poi1}, ip, time, ::Type{Val{:detJ}})
|
||||
return 1.0
|
||||
end
|
||||
|
||||
export Poi1, Seg2, Seg3, Tri3, Tri6, Quad4, Hex8, Tet4, Tet10
|
||||
include("nurbs.jl")
|
||||
export NSeg, NSurf, NSolid, is_nurbs
|
||||
|
||||
#include("hierarchical.jl") # P-elements
|
||||
#include("mortar_elements.jl") # Mortar elements
|
||||
#include("equations.jl")
|
||||
|
||||
include("integrate.jl") # default integration points for elements
|
||||
export get_integration_points
|
||||
@@ -66,7 +50,7 @@ export Problem, AbstractProblem, FieldProblem, BoundaryProblem,
|
||||
get_unknown_field_dimension, get_gdofs, Assembly,
|
||||
get_parent_field_name, get_elements
|
||||
|
||||
include("elasticity.jl") # elasticity equations
|
||||
include("elasticity.jl")
|
||||
export Elasticity
|
||||
|
||||
include("dirichlet.jl")
|
||||
@@ -75,7 +59,7 @@ export Dirichlet
|
||||
include("heat.jl")
|
||||
export Heat
|
||||
|
||||
export assemble, assemble!
|
||||
export assemble!, postprocess!
|
||||
|
||||
function assemble!(problem::Problem, element::Element, time=0.0)
|
||||
assemble!(problem.assembly, problem, element, time)
|
||||
@@ -89,7 +73,7 @@ export AbstractSolver, Solver, Nonlinear, NonlinearSolver, Linear, LinearSolver,
|
||||
get_unknown_field_name, get_formulation_type,
|
||||
get_field_problems, get_boundary_problems,
|
||||
get_field_assembly, get_boundary_assembly,
|
||||
initialize!, create_projection
|
||||
initialize!, create_projection, eliminate_interior_dofs
|
||||
include("modal.jl")
|
||||
export Modal
|
||||
|
||||
@@ -124,9 +108,11 @@ export create_elements, Mesh,
|
||||
add_element!, add_elements!,
|
||||
add_element_to_element_set!,
|
||||
add_node_to_node_set!,
|
||||
find_nearest_nodes
|
||||
find_nearest_nodes,
|
||||
reorder_element_connectivity!
|
||||
include("preprocess_abaqus_reader.jl")
|
||||
include("preprocess_abaqus_reader_old.jl")
|
||||
export parse_abaqus, parse_section, parse_element_section
|
||||
include("preprocess_aster_reader.jl")
|
||||
export aster_create_elements, parse_aster_med_file, is_aster_mail_keyword,
|
||||
parse_aster_header, aster_parse_nodes, aster_renumber_nodes!,
|
||||
@@ -146,10 +132,14 @@ export get_mesh, get_model
|
||||
|
||||
module Postprocess
|
||||
include("postprocess_utils.jl")
|
||||
export calc_nodal_values!, get_nodal_vector, copy_field!
|
||||
export calc_nodal_values!,
|
||||
get_nodal_vector,
|
||||
get_nodal_dict,
|
||||
copy_field!
|
||||
include("postprocess_xdmf.jl")
|
||||
export XDMF, xdmf_new_result!, xdmf_save_field!, xdmf_save!
|
||||
end
|
||||
export Postprocessor
|
||||
|
||||
""" JuliaFEM testing routines. """
|
||||
module Test
|
||||
@@ -171,5 +161,4 @@ module Interfaces
|
||||
include("interfaces.jl")
|
||||
end
|
||||
|
||||
|
||||
end # module
|
||||
|
||||
+14
-79
@@ -1,18 +1,6 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# Functions to handle global assembly of problem
|
||||
|
||||
type CAssembly
|
||||
interior_dofs :: Vector{Int}
|
||||
boundary_dofs :: Vector{Int}
|
||||
F :: Union{Factorization, Matrix}
|
||||
Kc :: SparseMatrixCSC
|
||||
fc :: SparseMatrixCSC
|
||||
Kib :: SparseMatrixCSC
|
||||
fi :: SparseMatrixCSC
|
||||
end
|
||||
|
||||
function optimize!(assembly::Assembly)
|
||||
optimize!(assembly.K)
|
||||
optimize!(assembly.Kg)
|
||||
@@ -99,54 +87,28 @@ function assemble!(problem::Problem, time::Real, ::Type{Val{:mass_matrix}}; dens
|
||||
end
|
||||
end
|
||||
|
||||
""" Calculate reduced stiffness matrix.
|
||||
mindofs: if dofs < mindofs, do not reduce
|
||||
"""
|
||||
function reduce(assembly::Assembly, boundary_dofs_::Vector{Int}, mindofs=100000)
|
||||
all_dofs = unique(assembly.stiffness_matrix.I)
|
||||
boundary_dofs = intersect(all_dofs, boundary_dofs_)
|
||||
interior_dofs = setdiff(all_dofs, boundary_dofs_)
|
||||
# Static condensation routines
|
||||
|
||||
K = sparse(assembly.stiffness_matrix)
|
||||
f = sparse(assembly.force_vector)
|
||||
function eliminate_interior_dofs(K::SparseMatrixCSC, f::SparseMatrixCSC, B::Vector{Int64}, I::Vector{Int64}; F=nothing, chunk_size=100000)
|
||||
|
||||
dim = size(K, 1)
|
||||
Kib = K[I,B]
|
||||
|
||||
# empty assembly to release memory for factorization
|
||||
empty!(assembly.stiffness_matrix)
|
||||
empty!(assembly.force_vector)
|
||||
gc()
|
||||
|
||||
if dim < mindofs
|
||||
# no need to do any reduction of matrix size at all, just \ it.
|
||||
return CAssembly([], all_dofs, Matrix{Float64}(), K, f, spzeros(0, 0), spzeros(0,1))
|
||||
if F == nothing
|
||||
F = cholfact(1/2*(K + K')[I,I])
|
||||
end
|
||||
|
||||
# check that matrix is symmetric
|
||||
s = maximum(abs(1/2*(K + K') - K))
|
||||
@assert s < 1.0e-6
|
||||
K = 1/2*(K + K')
|
||||
|
||||
Kib = K[interior_dofs, boundary_dofs]
|
||||
Kbb = K[boundary_dofs, boundary_dofs]
|
||||
fi = f[interior_dofs]
|
||||
fb = f[boundary_dofs]
|
||||
|
||||
F = cholfact(K[interior_dofs, interior_dofs])
|
||||
K = 0
|
||||
gc()
|
||||
|
||||
|
||||
if dim < 100000
|
||||
if dim < chunk_size
|
||||
# for small problems we don't need to care about memory usage
|
||||
Kd = Kib' * (F \ Kib)
|
||||
else
|
||||
# for larger problems calculate schur complement in pieces
|
||||
nb = length(boundary_dofs)
|
||||
nb = length(B)
|
||||
p = nb > 10 ? round(Int, nb/10) : nb
|
||||
Kd = zeros(nb, nb)
|
||||
for bi in 1:nb
|
||||
mod(bi, p) == 0 && info("Reduction: ", round(Int, bi/nb*100), " % done")
|
||||
done = round(Int, bi/nb*100)
|
||||
mod(bi, p) == 0 && info("Static condensation: $done % done")
|
||||
C = full(F \ Kib[:, bi])
|
||||
for bj in bi:nb
|
||||
d = Kib[:, bj]
|
||||
@@ -155,38 +117,17 @@ function reduce(assembly::Assembly, boundary_dofs_::Vector{Int}, mindofs=100000)
|
||||
end
|
||||
Kd += tril(Kd, -1)'
|
||||
end
|
||||
Kc = spzeros(dim, dim)
|
||||
Kc[boundary_dofs, boundary_dofs] = Kbb - Kd
|
||||
|
||||
#= # this is slightly faster but uses more memory
|
||||
chunks = round(Int, dim/3000)
|
||||
info("Reduction is done in $chunks chunks.")
|
||||
nb = length(boundary_dofs)
|
||||
kk = round(Int, collect(linspace(0, nb, chunks+1)))
|
||||
sl = [kk[j]+1:kk[j+1] for j=1:length(kk)-1]
|
||||
Kd = zeros(Float64, nb, nb)
|
||||
#Kd = SharedArray(Float64, nb, nb)
|
||||
for (k,sli) in enumerate(sl)
|
||||
b1 = boundary_dofs[sli]
|
||||
Sc = F \ Kib[:,sli]
|
||||
for slj in sl
|
||||
b2 = boundary_dofs[slj]
|
||||
#Kc[b2,b1] = Kbb[slj,sli] - Kib[:,slj]'*Sc
|
||||
Kd[slj, sli] = Kib[:,slj]'*Sc
|
||||
end
|
||||
info("Reduction: ", round(k/chunks*100, 0), " % done")
|
||||
end
|
||||
|
||||
Kc = spzeros(dim, dim)
|
||||
Kc[boundary_dofs, boundary_dofs] = Kbb - Kd
|
||||
=#
|
||||
Kc[B,B] = K[B,B] - Kd
|
||||
|
||||
fc = spzeros(dim, 1)
|
||||
fc[boundary_dofs] = fb - Kib' * (F \ fi)
|
||||
fc[B] = f[B] - Kib' * (F \ f[I])
|
||||
|
||||
return CAssembly(interior_dofs, boundary_dofs, F, Kc, fc, Kib, fi)
|
||||
return Kc, fc
|
||||
end
|
||||
|
||||
#=
|
||||
function reconstruct!(ca::CAssembly, x::SparseMatrixCSC)
|
||||
if isa(ca.F, Factorization)
|
||||
x[ca.interior_dofs] = ca.F \ (ca.fi - ca.Kib*x[ca.boundary_dofs])
|
||||
@@ -194,10 +135,4 @@ function reconstruct!(ca::CAssembly, x::SparseMatrixCSC)
|
||||
x[ca.interior_dofs] = ca.F * (ca.fi - ca.Kib*x[ca.boundary_dofs])
|
||||
end
|
||||
end
|
||||
|
||||
function Base.(:+)(ass1::Assembly, ass2::Assembly)
|
||||
mass_matrix = ass1.mass_matrix + ass2.mass_matrix
|
||||
stiffness_matrix = ass1.stiffness_matrix + ass2.stiffness_matrix
|
||||
force_vector = ass1.force_vector + ass2.force_vector
|
||||
return Assembly(mass_matrix, stiffness_matrix, force_vector)
|
||||
end
|
||||
=#
|
||||
|
||||
+3
-3
@@ -96,11 +96,11 @@ function assemble!(problem::Problem{Contact}, time::Float64,
|
||||
end
|
||||
|
||||
# 3. loop all master elements
|
||||
for master_element in slave_element["master elements"](time)
|
||||
for master_element in slave_element("master elements", time)
|
||||
|
||||
nm = length(master_element)
|
||||
X2 = master_element["geometry"](time)
|
||||
u2 = master_element["displacement"](time)
|
||||
X2 = master_element("geometry", time)
|
||||
u2 = master_element("displacement", time)
|
||||
x2 = X2 + u2
|
||||
|
||||
norm(mean(X1) - X2[1]) / norm(X1[2] - X1[1]) < props.distval || continue
|
||||
|
||||
+2
-2
@@ -36,7 +36,7 @@ function assemble!(assembly::Assembly, problem::Problem{Dirichlet}, element::Ele
|
||||
else
|
||||
Ae = eye(nnodes)
|
||||
De = zeros(nnodes, nnodes)
|
||||
for ip in get_integration_points(element)
|
||||
for ip in get_integration_points(element, 1)
|
||||
N = element(ip, time)
|
||||
detJ = element(ip, time, Val{:detJ})
|
||||
De += ip.weight*N'*N*detJ
|
||||
@@ -53,7 +53,7 @@ function assemble!(assembly::Assembly, problem::Problem{Dirichlet}, element::Ele
|
||||
end
|
||||
|
||||
# right hand side
|
||||
for ip in get_integration_points(element)
|
||||
for ip in get_integration_points(element, 1)
|
||||
detJ = element(ip, time, Val{:detJ})
|
||||
w = ip.weight*detJ
|
||||
N = element(ip, time)
|
||||
|
||||
+42
-36
@@ -1,8 +1,36 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
""" Elasticity problem
|
||||
""" Elasticity equations.
|
||||
|
||||
Field equation is:
|
||||
|
||||
m∂²u/∂t² = ∇⋅σ - b
|
||||
|
||||
Weak form is: find u∈U such that ∀v in V
|
||||
|
||||
δW := ∫ρ₀∂²u/∂t²⋅δu dV₀ + ∫S:δE dV₀ - ∫b₀⋅δu dV₀ - ∫t₀⋅δu dA₀ = 0
|
||||
|
||||
where
|
||||
|
||||
ρ₀ = density
|
||||
b₀ = displacement load
|
||||
t₀ = displacement traction
|
||||
|
||||
Formulations
|
||||
------------
|
||||
plane stress, plane strain, 3D
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
https://en.wikipedia.org/wiki/Linear_elasticity
|
||||
https://en.wikipedia.org/wiki/Finite_strain_theory
|
||||
https://en.wikipedia.org/wiki/Stress_measures
|
||||
https://en.wikipedia.org/wiki/Mooney%E2%80%93Rivlin_solid
|
||||
https://en.wikipedia.org/wiki/Strain_energy_density_function
|
||||
https://en.wikipedia.org/wiki/Plane_stress
|
||||
https://en.wikipedia.org/wiki/Hooke's_law
|
||||
|
||||
"""
|
||||
type Elasticity <: FieldProblem
|
||||
@@ -38,8 +66,14 @@ function assemble!(assembly::Assembly, problem::Problem{Elasticity}, element::El
|
||||
add!(assembly.f, gdofs, f)
|
||||
end
|
||||
|
||||
typealias Elasticity2DSurfaceElements Union{Poi1, Seg2, Seg3}
|
||||
typealias Elasticity2DVolumeElements Union{Tri3, Tri6, Quad4, Quad8, Quad9}
|
||||
typealias Elasticity3DSurfaceElements Union{Poi1, Tri3, Tri6, Quad4, Quad8, Quad9}
|
||||
typealias Elasticity3DVolumeElements Union{Tet4, Tet10, Hex8, Hex20, Hex27}
|
||||
|
||||
|
||||
""" Elasticity equations for 2d cases. """
|
||||
function assemble{El<:Union{Tri3,Tri6,Quad4}}(problem::Problem{Elasticity}, element::Element{El}, time, ::Type{Val{:plane}})
|
||||
function assemble{El<:Elasticity2DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time, ::Type{Val{:plane}})
|
||||
|
||||
props = problem.properties
|
||||
dim = get_unknown_field_dimension(problem)
|
||||
@@ -162,7 +196,7 @@ function assemble{El<:Union{Tri3,Tri6,Quad4}}(problem::Problem{Elasticity}, elem
|
||||
return Km, Kg, f
|
||||
end
|
||||
|
||||
function assemble{El<:Union{Poi1,Seg2,Seg3}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:plane}})
|
||||
function assemble{El<:Elasticity2DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:plane}})
|
||||
|
||||
props = problem.properties
|
||||
dim = get_unknown_field_dimension(problem)
|
||||
@@ -203,7 +237,7 @@ function assemble{El<:Union{Poi1,Seg2,Seg3}}(problem::Problem{Elasticity}, eleme
|
||||
end
|
||||
|
||||
""" Elasticity equations, 3d, linear. """
|
||||
function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}})
|
||||
function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}})
|
||||
|
||||
props = problem.properties
|
||||
dim = get_unknown_field_dimension(problem)
|
||||
@@ -270,7 +304,7 @@ function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, el
|
||||
end
|
||||
|
||||
""" Material and geometric stiffness for linear buckling analysis. """
|
||||
function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_buckling}})
|
||||
function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_buckling}})
|
||||
|
||||
props = problem.properties
|
||||
dim = get_unknown_field_dimension(problem)
|
||||
@@ -348,7 +382,7 @@ function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, el
|
||||
end
|
||||
|
||||
""" Elasticity equations, 3d nonlinear. """
|
||||
function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}})
|
||||
function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}})
|
||||
|
||||
props = problem.properties
|
||||
dim = get_unknown_field_dimension(problem)
|
||||
@@ -487,7 +521,7 @@ function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, el
|
||||
end
|
||||
|
||||
""" Elasticity equations, surface traction for continuum formulation. """
|
||||
function assemble{El<:Union{Tri3, Tri6, Quad4}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}})
|
||||
function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}})
|
||||
|
||||
props = problem.properties
|
||||
dim = get_unknown_field_dimension(problem)
|
||||
@@ -521,39 +555,11 @@ function assemble{El<:Union{Tri3, Tri6, Quad4}}(problem::Problem{Elasticity}, el
|
||||
return Km, Kg, f
|
||||
end
|
||||
|
||||
function assemble{El<:Union{Tri3, Tri6, Quad4}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}})
|
||||
function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}})
|
||||
return assemble(problem, element, time, Val{:continuum})
|
||||
end
|
||||
|
||||
""" Elasticity equations using ForwardDiff
|
||||
|
||||
Formulation
|
||||
-----------
|
||||
|
||||
Field equation is:
|
||||
∂u/∂t = ∇⋅f - b
|
||||
|
||||
Weak form is: find u∈U such that ∀v in V
|
||||
|
||||
δW := ∫ρ₀∂²u/∂t²⋅δu dV₀ + ∫S:δE dV₀ - ∫b₀⋅δu dV₀ - ∫t₀⋅δu dA₀ = 0
|
||||
|
||||
where
|
||||
|
||||
ρ₀ = density
|
||||
b₀ = displacement load
|
||||
t₀ = displacement traction
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
https://en.wikipedia.org/wiki/Linear_elasticity
|
||||
https://en.wikipedia.org/wiki/Finite_strain_theory
|
||||
https://en.wikipedia.org/wiki/Stress_measures
|
||||
https://en.wikipedia.org/wiki/Mooney%E2%80%93Rivlin_solid
|
||||
https://en.wikipedia.org/wiki/Strain_energy_density_function
|
||||
https://en.wikipedia.org/wiki/Plane_stress
|
||||
https://en.wikipedia.org/wiki/Hooke's_law
|
||||
|
||||
"""
|
||||
function assemble(problem::Problem{Elasticity}, element::Element, time::Real, ::Type{Val{:forwarddiff}})
|
||||
|
||||
|
||||
+13
-2
@@ -41,7 +41,7 @@ function last(element::Element, field_name::ASCIIString)
|
||||
return last(element[field_name])
|
||||
end
|
||||
|
||||
function call(element::Element, ip, time)
|
||||
function call(element::Element, ip, time=0.0)
|
||||
return get_basis(element, ip, time)
|
||||
end
|
||||
|
||||
@@ -75,8 +75,17 @@ function call(element::Element, field_name::ASCIIString, ip, time, ::Type{Val{:G
|
||||
return element(ip, time, Val{:Grad})*element[field_name](time)
|
||||
end
|
||||
|
||||
function call(element::Element, field::Field, time)
|
||||
return field(time)
|
||||
end
|
||||
|
||||
function call(element::Element, field::DCTI, time)
|
||||
return field.data
|
||||
end
|
||||
|
||||
function call(element::Element, field_name::ASCIIString, time)
|
||||
return element[field_name](time)
|
||||
field = element[field_name]
|
||||
return call(element, field, time)
|
||||
end
|
||||
|
||||
function call(element::Element, field_name::ASCIIString, ip, time::Float64)
|
||||
@@ -220,6 +229,7 @@ function update!(elements::Vector, field_name::ASCIIString, data)
|
||||
end
|
||||
end
|
||||
|
||||
#=
|
||||
dbasis_cache = ForwardDiff.jacobian
|
||||
""" Evaluate partial derivatives of basis functions using ForwardDiff. """
|
||||
function get_dbasis(element::Element, ip, time)
|
||||
@@ -227,6 +237,7 @@ function get_dbasis(element::Element, ip, time)
|
||||
basis(xi) = vec(get_basis(element, xi, time))
|
||||
return ForwardDiff.jacobian(basis, xi)'
|
||||
end
|
||||
=#
|
||||
|
||||
""" Check existence of field. """
|
||||
function haskey(element::Element, field_name)
|
||||
|
||||
+26
-28
@@ -142,57 +142,55 @@ end
|
||||
|
||||
### Accessing and manipulating discrete fields
|
||||
|
||||
function Base.getindex(field::DVTV, i::Int64)
|
||||
function getindex(field::DVTV, i::Int64)
|
||||
return field.data[i]
|
||||
end
|
||||
|
||||
function Base.push!(field::DCTV, data::Pair)
|
||||
function push!(field::DCTV, data::Pair)
|
||||
push!(field.data, data)
|
||||
end
|
||||
|
||||
function Base.push!(field::DVTV, data::Pair)
|
||||
# info("field.data = \n$(field.data)")
|
||||
# info("data = \n$data")
|
||||
function push!(field::DVTV, data::Pair)
|
||||
push!(field.data, data)
|
||||
end
|
||||
|
||||
function Base.getindex(field::DVTV, i::Int64)
|
||||
function getindex(field::DVTV, i::Int64)
|
||||
return field.data[i]
|
||||
end
|
||||
|
||||
function Base.getindex(field::DVTI, i::Int64)
|
||||
function getindex(field::DVTI, i::Int64)
|
||||
return field.data[i]
|
||||
end
|
||||
|
||||
function Base.getindex(field::DCTV, i::Int64)
|
||||
function getindex(field::DCTV, i::Int64)
|
||||
return field.data[i]
|
||||
end
|
||||
|
||||
function Base.getindex(field::Field, i::Int64)
|
||||
function getindex(field::Field, i::Int64)
|
||||
return field.data[i]
|
||||
end
|
||||
|
||||
function Base.length(field::DVTI)
|
||||
function length(field::DVTI)
|
||||
return length(field.data)
|
||||
end
|
||||
|
||||
function Base.length(field::DCTI)
|
||||
function length(field::DCTI)
|
||||
return 1
|
||||
end
|
||||
|
||||
function Base.length(field::DVTV)
|
||||
function length(field::DVTV)
|
||||
return length(field.data)
|
||||
end
|
||||
|
||||
function Base.length(field::DCTV)
|
||||
function length(field::DCTV)
|
||||
return length(field.data)
|
||||
end
|
||||
|
||||
function Base.first(field::Union{DCTV, DVTV})
|
||||
function first(field::Union{DCTV, DVTV})
|
||||
return field[1]
|
||||
end
|
||||
|
||||
function Base.isapprox(f1::DCTI, f2::DCTI)
|
||||
function isapprox(f1::DCTI, f2::DCTI)
|
||||
isapprox(f1.data, f2.data)
|
||||
end
|
||||
|
||||
@@ -236,8 +234,7 @@ function vec(field::DVTI)
|
||||
end
|
||||
|
||||
function vec(field::DCTV)
|
||||
info("trying to vectorize $field")
|
||||
error("does not make sense")
|
||||
error("trying to vectorize $field does not make sense")
|
||||
end
|
||||
|
||||
function endof(field::Field)
|
||||
@@ -321,21 +318,21 @@ end
|
||||
### Interpolation
|
||||
|
||||
""" Interpolate time-invariant field in time direction. """
|
||||
function Base.call(field::DVTI, time::Float64)
|
||||
function call(field::DVTI, time::Float64)
|
||||
return field
|
||||
end
|
||||
function Base.call(field::DCTI, time::Float64)
|
||||
function call(field::DCTI, time::Float64)
|
||||
return field
|
||||
end
|
||||
function Base.call(field::CVTI, time::Float64)
|
||||
function call(field::CVTI, time::Float64)
|
||||
return field.data()
|
||||
end
|
||||
function Base.call(field::CCTI, time::Float64)
|
||||
function call(field::CCTI, time::Float64)
|
||||
return field.data()
|
||||
end
|
||||
|
||||
""" Interpolate constant time-variant field in time direction. """
|
||||
function Base.call(field::DCTV, time::Real)
|
||||
function call(field::DCTV, time::Real)
|
||||
time < first(field).time && return DCTI(first(field).data)
|
||||
time > last(field).time && return DCTI(last(field).data)
|
||||
for i=reverse(1:length(field))
|
||||
@@ -355,7 +352,7 @@ function Base.call(field::DCTV, time::Real)
|
||||
error("interpolate DCTV: unknown failure when interpolating $(field.data) for time $time")
|
||||
end
|
||||
|
||||
function Base.call(field::DVTV, time::Float64)
|
||||
function call(field::DVTV, time::Float64)
|
||||
time < first(field).time && return DVTI(first(field).data)
|
||||
time > last(field).time && return DVTI(last(field).data)
|
||||
for i=reverse(1:length(field))
|
||||
@@ -376,17 +373,17 @@ function Base.call(field::DVTV, time::Float64)
|
||||
end
|
||||
|
||||
""" Interpolate constant field in spatial dimension. """
|
||||
function Base.call(basis::CVTI, field::DCTI, xi::Vector)
|
||||
function call(basis::CVTI, field::DCTI, xi::Vector)
|
||||
return field.data
|
||||
end
|
||||
|
||||
""" Interpolate variable field in spatial dimension. """
|
||||
function Base.call(basis::CVTI, values::DVTI, xi::Vector)
|
||||
function call(basis::CVTI, values::DVTI, xi::Vector)
|
||||
N = basis(xi)
|
||||
return sum([N[i]*values[i] for i=1:length(N)])
|
||||
end
|
||||
|
||||
function Base.call(basis::CVTI, geometry::DVTI, xi::Vector, ::Type{Val{:grad}})
|
||||
function call(basis::CVTI, geometry::DVTI, xi::Vector, ::Type{Val{:grad}})
|
||||
dbasis = basis(xi, Val{:grad})
|
||||
# J = sum([dbasis[:,i]*geometry[i]' for i=1:length(geometry)])
|
||||
J = sum([kron(dbasis[:,i], geometry[i]') for i=1:length(geometry)])
|
||||
@@ -395,14 +392,14 @@ function Base.call(basis::CVTI, geometry::DVTI, xi::Vector, ::Type{Val{:grad}})
|
||||
return grad
|
||||
end
|
||||
|
||||
function Base.call(basis::CVTI, geometry::DVTI, values::DVTI, xi::Vector, ::Type{Val{:grad}})
|
||||
function call(basis::CVTI, geometry::DVTI, values::DVTI, xi::Vector, ::Type{Val{:grad}})
|
||||
grad = call(basis, geometry, xi, Val{:grad})
|
||||
# gradf = sum([grad[:,i]*values[i]' for i=1:length(geometry)])'
|
||||
gradf = sum([kron(grad[:,i], values[i]') for i=1:length(values)])'
|
||||
return length(gradf) == 1 ? gradf[1] : gradf
|
||||
end
|
||||
|
||||
function Base.call(basis::CVTI, xi::Vector, time::Number)
|
||||
function call(basis::CVTI, xi::Vector, time::Number)
|
||||
call(basis, xi)
|
||||
end
|
||||
|
||||
@@ -413,3 +410,4 @@ end
|
||||
### FIELDSET ###
|
||||
|
||||
typealias FieldSet Dict{ASCIIString, Field}
|
||||
|
||||
|
||||
+38
-11
@@ -1,13 +1,8 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# Heat problems
|
||||
|
||||
""" Heat equations.
|
||||
|
||||
Formulation
|
||||
-----------
|
||||
|
||||
Field equation is:
|
||||
|
||||
ρc∂u/∂t = ∇⋅(k∇u) + f
|
||||
@@ -27,7 +22,6 @@ Parameters
|
||||
temperature thermal conductivity
|
||||
temperature load
|
||||
temperature flux
|
||||
|
||||
thermal conductivity
|
||||
heat source
|
||||
heat flux
|
||||
@@ -43,6 +37,7 @@ References
|
||||
----------
|
||||
https://en.wikipedia.org/wiki/Heat_equation
|
||||
https://en.wikipedia.org/wiki/Heat_capacity
|
||||
https://en.wikipedia.org/wiki/Heat_flux
|
||||
https://en.wikipedia.org/wiki/Thermal_conduction
|
||||
https://en.wikipedia.org/wiki/Thermal_conductivity
|
||||
https://en.wikipedia.org/wiki/Thermal_diffusivity
|
||||
@@ -50,17 +45,18 @@ https://en.wikipedia.org/wiki/Volumetric_heat_capacity
|
||||
"""
|
||||
type Heat <: FieldProblem
|
||||
formulation :: ASCIIString
|
||||
store_fields :: Vector{ASCIIString}
|
||||
end
|
||||
|
||||
function Heat()
|
||||
return Heat("3D")
|
||||
return Heat("3D", [])
|
||||
end
|
||||
|
||||
function get_unknown_field_name(problem::Problem{Heat})
|
||||
return "temperature"
|
||||
end
|
||||
|
||||
function assemble!(assembly::Assembly, problem::Problem{Heat}, element::Element, time=0.0)
|
||||
function assemble!(assembly::Assembly, problem::Problem{Heat}, element::Element, time)
|
||||
formulation = Val{Symbol(problem.properties.formulation)}
|
||||
assemble!(assembly, problem, element, time, formulation)
|
||||
end
|
||||
@@ -71,8 +67,8 @@ function assemble!{E}(assembly::Assembly, problem::Problem{Heat}, element::Eleme
|
||||
info("Unknown element type $E for 3d heat problem!")
|
||||
end
|
||||
|
||||
typealias Heat3DVolumeElements Union{Tet4, Tet10, Hex8}
|
||||
typealias Heat3DSurfaceElements Union{Tri3, Tri6, Quad4}
|
||||
typealias Heat3DVolumeElements Union{Tet4, Tet10, Hex8, Hex20, Hex27}
|
||||
typealias Heat3DSurfaceElements Union{Tri3, Tri6, Quad4, Quad8, Quad9}
|
||||
|
||||
function assemble!{E<:Heat3DVolumeElements}(assembly::Assembly, problem::Problem{Heat}, element::Element{E}, time, ::Type{Val{Symbol("3D")}})
|
||||
gdofs = get_gdofs(problem, element)
|
||||
@@ -100,13 +96,44 @@ function assemble!{E<:Heat3DVolumeElements}(assembly::Assembly, problem::Problem
|
||||
add!(assembly.f, gdofs, fq)
|
||||
end
|
||||
|
||||
function postprocess!{E}(assembly::Assembly, problem::Problem{Heat}, element::Element{E}, time)
|
||||
haskey(element, "temperature thermal conductivity") || return
|
||||
gdofs = get_gdofs(problem, element)
|
||||
field_name = get_unknown_field_name(problem)
|
||||
nnodes = length(element)
|
||||
Me = zeros(nnodes, nnodes)
|
||||
De = zeros(nnodes, nnodes)
|
||||
f = zeros(nnodes, 3)
|
||||
for ip in get_integration_points(element)
|
||||
detJ = element(ip, time, Val{:detJ})
|
||||
w = ip.weight*detJ
|
||||
N = element(ip, time)
|
||||
De += w*diagm(vec(N))
|
||||
Me += w*N'*N
|
||||
end
|
||||
Ae = De*inv(Me)
|
||||
for ip in get_integration_points(element)
|
||||
detJ = element(ip, time, Val{:detJ})
|
||||
w = ip.weight*detJ
|
||||
N = vec(element(ip, time))
|
||||
Phi = transpose(Ae*N)
|
||||
k = element("temperature thermal conductivity", ip, time)
|
||||
gradT = element(field_name, ip, time, Val{:Grad})
|
||||
q = -vec(k*gradT)
|
||||
update!(ip, "heat flux", time => q)
|
||||
f += w*Phi'*q'
|
||||
end
|
||||
add!(assembly.M, gdofs, gdofs, De)
|
||||
add!(assembly.f, gdofs, [1, 2, 3], f)
|
||||
end
|
||||
|
||||
function assemble!{E<:Heat3DSurfaceElements}(assembly::Assembly, problem::Problem{Heat}, element::Element{E}, time, ::Type{Val{Symbol("3D")}})
|
||||
gdofs = get_gdofs(problem, element)
|
||||
field_name = get_unknown_field_name(problem)
|
||||
nnodes = length(element)
|
||||
K = zeros(nnodes, nnodes)
|
||||
fq = zeros(nnodes)
|
||||
for ip in get_integration_points(element)
|
||||
for ip in get_integration_points(element, 1)
|
||||
detJ = element(ip, time, Val{:detJ})
|
||||
w = ip.weight*detJ
|
||||
N = element(ip, time)
|
||||
|
||||
+3
-3
@@ -67,8 +67,8 @@ end
|
||||
### 1d elements
|
||||
|
||||
typealias CartesianLineElement Union{Seg2, Seg3, NSeg}
|
||||
typealias CartesianSurfaceElement Union{Quad4, NSurf}
|
||||
typealias CartesianVolumeElement Union{Hex8, NSolid}
|
||||
typealias CartesianSurfaceElement Union{Quad4, Quad8, Quad9, NSurf}
|
||||
typealias CartesianVolumeElement Union{Hex8, Hex20, Hex27, NSolid}
|
||||
|
||||
function get_integration_points(element::CartesianLineElement, order::Int64)
|
||||
w, xi = get_integration_points(order)
|
||||
@@ -238,7 +238,7 @@ end
|
||||
|
||||
typealias LinearElement Union{Seg2, Tri3, Quad4, Tet4, Hex8}
|
||||
|
||||
typealias QuadraticElement Union{Seg3, Tri6, Tet10}
|
||||
typealias QuadraticElement Union{Seg3, Tri6, Tet10, Quad8, Quad9, Hex20, Hex27}
|
||||
|
||||
function get_integration_order(element::LinearElement)
|
||||
return 2
|
||||
|
||||
+570
@@ -0,0 +1,570 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
### 0d element
|
||||
|
||||
type Poi1 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Poi1})
|
||||
"1 node point"
|
||||
end
|
||||
|
||||
function size(element::Element{Poi1})
|
||||
return (0, 1)
|
||||
end
|
||||
|
||||
function length(element::Element{Poi1})
|
||||
return 1
|
||||
end
|
||||
|
||||
function get_basis(element::Element{Poi1}, ip, time)
|
||||
return [1]
|
||||
end
|
||||
|
||||
function call(element::Element{Poi1}, ip, time, ::Type{Val{:detJ}})
|
||||
return 1.0
|
||||
end
|
||||
|
||||
### 1d elements
|
||||
|
||||
type Seg2 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Seg2})
|
||||
"2 node segment"
|
||||
end
|
||||
|
||||
function size(element::Element{Seg2})
|
||||
return (1, 2)
|
||||
end
|
||||
|
||||
function length(element::Element{Seg2})
|
||||
return 2
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Seg2})
|
||||
Vector{Float64}[
|
||||
[-1.0], # N1
|
||||
[ 1.0]] # N2
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Seg2}, xi)
|
||||
[1.0 xi[1]]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Seg2}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[0.0 1.0]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Seg3 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Seg3})
|
||||
"3 node segment"
|
||||
end
|
||||
|
||||
function size(element::Element{Seg3})
|
||||
return (1, 3)
|
||||
end
|
||||
|
||||
function length(element::Element{Seg3})
|
||||
return 3
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Seg3})
|
||||
Vector{Float64}[
|
||||
[-1.0], # N1
|
||||
[ 1.0], # N2
|
||||
[ 0.0]] # N3
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Seg3}, xi)
|
||||
[1.0 xi[1] xi[1]^2]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Seg3}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[0.0 1.0 2.0*xi[1]]
|
||||
end
|
||||
|
||||
### 2d elements
|
||||
|
||||
type Tri3 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Tri3})
|
||||
"3 node triangle"
|
||||
end
|
||||
|
||||
function size(element::Element{Tri3})
|
||||
return (2, 3)
|
||||
end
|
||||
|
||||
function length(element::Element{Tri3})
|
||||
return 3
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Tri3})
|
||||
Vector{Float64}[
|
||||
[0.0, 0.0], # N1
|
||||
[1.0, 0.0], # N2
|
||||
[0.0, 1.0]] # N3
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tri3}, xi)
|
||||
[
|
||||
1 xi[1] xi[2]
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tri3}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0.0 1.0 0.0
|
||||
0.0 0.0 1.0
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Tri6 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Tri6})
|
||||
"6 node triangle"
|
||||
end
|
||||
|
||||
function size(element::Element{Tri6})
|
||||
return (2, 6)
|
||||
end
|
||||
|
||||
function length(element::Element{Tri6})
|
||||
return 6
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Tri6})
|
||||
Vector{Float64}[
|
||||
[0.0, 0.0], # N1
|
||||
[1.0, 0.0], # N2
|
||||
[0.0, 1.0], # N3
|
||||
[0.5, 0.0], # N4
|
||||
[0.5, 0.5], # N5
|
||||
[0.0, 0.5]] # N6
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tri6}, xi)
|
||||
[
|
||||
1 xi[1] xi[2] xi[1]^2 xi[1]*xi[2] xi[2]^2
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tri6}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 1 0 2*xi[1] xi[2] 0
|
||||
0 0 1 0 xi[1] 2*xi[2]
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Quad4 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Quad4})
|
||||
"4 node quadrangle"
|
||||
end
|
||||
|
||||
function size(element::Element{Quad4})
|
||||
return (2, 4)
|
||||
end
|
||||
|
||||
function length(element::Element{Quad4})
|
||||
return 4
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Quad4})
|
||||
Vector{Float64}[
|
||||
[-1.0, -1.0], # N1
|
||||
[ 1.0, -1.0], # N2
|
||||
[ 1.0, 1.0], # N3
|
||||
[-1.0, 1.0]] # N4
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Quad4}, xi)
|
||||
[
|
||||
1.0 xi[1] xi[2] xi[1]*xi[2]
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Quad4}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 1 0 xi[2]
|
||||
0 0 1 xi[1]
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Quad8 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Quad8})
|
||||
"8 node Serendip quadrangle"
|
||||
end
|
||||
|
||||
function size(element::Element{Quad8})
|
||||
return (2, 8)
|
||||
end
|
||||
|
||||
function length(element::Element{Quad8})
|
||||
return 8
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Quad8})
|
||||
Vector{Float64}[
|
||||
[-1.0, -1.0], # N1
|
||||
[ 1.0, -1.0], # N2
|
||||
[ 1.0, 1.0], # N3
|
||||
[-1.0, 1.0], # N4
|
||||
[ 0.0, -1.0], # N5
|
||||
[ 1.0, 0.0], # N6
|
||||
[ 0.0, 1.0], # N7
|
||||
[-1.0, 0.0]] # N8
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Quad8}, xi)
|
||||
[
|
||||
1 xi[2] xi[1] xi[2]^2 xi[1]*xi[2] xi[1]^2 xi[1]*xi[2]^2 xi[1]^2*xi[2]
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Quad8}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 0 1 0 xi[2] 2*xi[1] xi[2]^2 2*xi[1]*xi[2]
|
||||
0 1 0 2*xi[2] xi[1] 0 2*xi[1]*xi[2] xi[1]^2
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Quad9 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Quad9})
|
||||
"9 node quadrangle"
|
||||
end
|
||||
|
||||
function size(element::Element{Quad9})
|
||||
return (2, 9)
|
||||
end
|
||||
|
||||
function length(element::Element{Quad9})
|
||||
return 9
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Quad9})
|
||||
Vector{Float64}[
|
||||
[-1.0, -1.0], # N1
|
||||
[ 1.0, -1.0], # N2
|
||||
[ 1.0, 1.0], # N3
|
||||
[-1.0, 1.0], # N4
|
||||
[ 0.0, -1.0], # N5
|
||||
[ 1.0, 0.0], # N6
|
||||
[ 0.0, 1.0], # N7
|
||||
[-1.0, 0.0], # N8
|
||||
[ 0.0, 0.0]] # N9
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Quad9}, xi)
|
||||
[
|
||||
1 xi[2] xi[1] xi[2]^2 xi[1]*xi[2] xi[1]^2 xi[1]*xi[2]^2 xi[1]^2*xi[2] xi[1]^2*xi[2]^2
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Quad9}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 0 1 0 xi[2] 2*xi[1] xi[2]^2 2*xi[1]*xi[2] 2*xi[1]*xi[2]^2
|
||||
0 1 0 2*xi[2] xi[1] 0 2*xi[1]*xi[2] xi[1]^2 2*xi[1]^2*xi[2]
|
||||
]
|
||||
end
|
||||
|
||||
### 3d elements
|
||||
|
||||
type Tet4 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Tet4})
|
||||
"4 node tetrahedral element"
|
||||
end
|
||||
|
||||
function size(element::Element{Tet4})
|
||||
return (3, 4)
|
||||
end
|
||||
|
||||
function length(element::Element{Tet4})
|
||||
return 4
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Tet4})
|
||||
Vector{Float64}[
|
||||
[0.0, 0.0, 0.0], # N1
|
||||
[1.0, 0.0, 0.0], # N2
|
||||
[0.0, 1.0, 0.0], # N3
|
||||
[0.0, 0.0, 1.0]] # N4
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tet4}, xi)
|
||||
[
|
||||
1.0 xi[1] xi[2] xi[3]
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tet4}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0.0 1.0 0.0 0.0
|
||||
0.0 0.0 1.0 0.0
|
||||
0.0 0.0 0.0 1.0
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Tet10 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Tet10})
|
||||
"10 node tetrahedral element"
|
||||
end
|
||||
|
||||
function size(element::Element{Tet10})
|
||||
return (3, 10)
|
||||
end
|
||||
|
||||
function length(element::Element{Tet10})
|
||||
return 10
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Tet10})
|
||||
Vector{Float64}[
|
||||
[0.0, 0.0, 0.0], # N1
|
||||
[1.0, 0.0, 0.0], # N2
|
||||
[0.0, 1.0, 0.0], # N3
|
||||
[0.0, 0.0, 1.0], # N4
|
||||
[0.5, 0.0, 0.0], # N5
|
||||
[0.5, 0.5, 0.0], # N6
|
||||
[0.0, 0.5, 0.0], # N7
|
||||
[0.0, 0.0, 0.5], # N8
|
||||
[0.5, 0.0, 0.5], # N9
|
||||
[0.0, 0.5, 0.5]] # N10
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tet10}, xi)
|
||||
[
|
||||
1.0 xi[3] xi[2] xi[1] xi[3]^2 xi[2]*xi[3] xi[2]^2 xi[1]*xi[3] xi[1]*xi[2] xi[1]^2
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tet10}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 0 0 1 0 0 0 xi[3] xi[2] 2*xi[1]
|
||||
0 0 1 0 0 xi[3] 2*xi[2] 0 xi[1] 0
|
||||
0 1 0 0 2*xi[3] xi[2] 0 xi[1] 0 0
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Hex8 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Hex8})
|
||||
"8 node hexahedral element"
|
||||
end
|
||||
|
||||
function size(element::Element{Hex8})
|
||||
return (3, 8)
|
||||
end
|
||||
|
||||
function length(element::Element{Hex8})
|
||||
return 8
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Hex8})
|
||||
Vector{Float64}[
|
||||
[-1.0, -1.0, -1.0], # N1
|
||||
[ 1.0, -1.0, -1.0], # N2
|
||||
[ 1.0, 1.0, -1.0], # N3
|
||||
[-1.0, 1.0, -1.0], # N4
|
||||
[-1.0, -1.0, 1.0], # N5
|
||||
[ 1.0, -1.0, 1.0], # N6
|
||||
[ 1.0, 1.0, 1.0], # N7
|
||||
[-1.0, 1.0, 1.0]] # N8
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Hex8}, xi)
|
||||
[
|
||||
1 xi[3] xi[2] xi[1] xi[2]*xi[3] xi[1]*xi[3] xi[1]*xi[2] xi[1]*xi[2]*xi[3]
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Hex8}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 0 0 1 0 xi[3] xi[2] xi[2]*xi[3]
|
||||
0 0 1 0 xi[3] 0 xi[1] xi[1]*xi[3]
|
||||
0 1 0 0 xi[2] xi[1] 0 xi[1]*xi[2]
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Hex20 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Hex20})
|
||||
"20 node hexahedral element"
|
||||
end
|
||||
|
||||
function size(element::Element{Hex20})
|
||||
return (3, 20)
|
||||
end
|
||||
|
||||
function length(element::Element{Hex20})
|
||||
return 20
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Hex20})
|
||||
Vector{Float64}[
|
||||
[-1.0, -1.0, -1.0], # N1
|
||||
[ 1.0, -1.0, -1.0], # N2
|
||||
[ 1.0, 1.0, -1.0], # N3
|
||||
[-1.0, 1.0, -1.0], # N4
|
||||
[-1.0, -1.0, 1.0], # N5
|
||||
[ 1.0, -1.0, 1.0], # N6
|
||||
[ 1.0, 1.0, 1.0], # N7
|
||||
[-1.0, 1.0, 1.0], # N8
|
||||
[ 0.0, -1.0, -1.0], # N9
|
||||
[ 1.0, 0.0, -1.0], # N10
|
||||
[ 0.0, 1.0, -1.0], # N11
|
||||
[-1.0, 0.0, -1.0], # N12
|
||||
[-1.0, -1.0, 0.0], # N13
|
||||
[ 1.0, -1.0, 0.0], # N14
|
||||
[ 1.0, 1.0, 0.0], # N15
|
||||
[-1.0, 1.0, 0.0], # N16
|
||||
[ 0.0, -1.0, 1.0], # N17
|
||||
[ 1.0, 0.0, 1.0], # N18
|
||||
[ 0.0, 1.0, 1.0], # N19
|
||||
[-1.0, 0.0, 1.0]] # N20
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Hex20}, xi)
|
||||
[
|
||||
1 xi[3] xi[2] xi[1] xi[2]*xi[3] xi[1]*xi[3] xi[1]*xi[2] xi[1]*xi[2]*xi[3] xi[3]^2 xi[2]^2 xi[1]^2 xi[2]*xi[3]^2 xi[2]^2*xi[3] xi[1]*xi[3]^2 xi[1]*xi[2]^2 xi[1]^2*xi[3] xi[1]^2*xi[2] xi[1]*xi[2]*xi[3]^2 xi[1]*xi[2]^2*xi[3] xi[1]^2*xi[2]*xi[3]
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Hex20}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 0 0 1 0 xi[3] xi[2] xi[2]*xi[3] 0 0 2*xi[1] 0 0 xi[3]^2 xi[2]^2 2*xi[1]*xi[3] 2*xi[1]*xi[2] xi[2]*xi[3]^2 xi[2]^2*xi[3] 2*xi[1]*xi[2]*xi[3]
|
||||
0 0 1 0 xi[3] 0 xi[1] xi[1]*xi[3] 0 2*xi[2] 0 xi[3]^2 2*xi[2]*xi[3] 0 2*xi[1]*xi[2] 0 xi[1]^2 xi[1]*xi[3]^2 2*xi[1]*xi[2]*xi[3] xi[1]^2*xi[3]
|
||||
0 1 0 0 xi[2] xi[1] 0 xi[1]*xi[2] 2*xi[3] 0 0 2*xi[2]*xi[3] xi[2]^2 2*xi[1]*xi[3] 0 xi[1]^2 0 2*xi[1]*xi[2]*xi[3] xi[1]*xi[2]^2 xi[1]^2*xi[2]
|
||||
]
|
||||
end
|
||||
|
||||
###
|
||||
|
||||
type Hex27 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Hex27})
|
||||
"27 node hexahedral element"
|
||||
end
|
||||
|
||||
function size(element::Element{Hex27})
|
||||
return (3, 27)
|
||||
end
|
||||
|
||||
function length(element::Element{Hex27})
|
||||
return 27
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Hex27})
|
||||
Vector{Float64}[
|
||||
[-1.0, -1.0, -1.0], # N1
|
||||
[ 1.0, -1.0, -1.0], # N2
|
||||
[ 1.0, 1.0, -1.0], # N3
|
||||
[-1.0, 1.0, -1.0], # N4
|
||||
[-1.0, -1.0, 1.0], # N5
|
||||
[ 1.0, -1.0, 1.0], # N6
|
||||
[ 1.0, 1.0, 1.0], # N7
|
||||
[-1.0, 1.0, 1.0], # N8
|
||||
[ 0.0, -1.0, -1.0], # N9
|
||||
[ 1.0, 0.0, -1.0], # N10
|
||||
[ 0.0, 1.0, -1.0], # N11
|
||||
[-1.0, 0.0, -1.0], # N12
|
||||
[-1.0, -1.0, 0.0], # N13
|
||||
[ 1.0, -1.0, 0.0], # N14
|
||||
[ 1.0, 1.0, 0.0], # N15
|
||||
[-1.0, 1.0, 0.0], # N16
|
||||
[ 0.0, -1.0, 1.0], # N17
|
||||
[ 1.0, 0.0, 1.0], # N18
|
||||
[ 0.0, 1.0, 1.0], # N19
|
||||
[-1.0, 0.0, 1.0], # N20
|
||||
[ 0.0, 0.0, -1.0], # N21
|
||||
[ 0.0, -1.0, 0.0], # N22
|
||||
[ 1.0, 0.0, 0.0], # N23
|
||||
[ 0.0, 1.0, 0.0], # N24
|
||||
[-1.0, 0.0, 0.0], # N25
|
||||
[ 0.0, 0.0, 1.0], # N26
|
||||
[ 0.0, 0.0, 0.0]] # N27
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Hex27}, xi)
|
||||
[
|
||||
1 xi[3] xi[2] xi[1] xi[2]*xi[3] xi[1]*xi[3] xi[1]*xi[2] xi[1]*xi[2]*xi[3] xi[3]^2 xi[2]^2 xi[1]^2 xi[2]*xi[3]^2 xi[2]^2*xi[3] xi[1]*xi[3]^2 xi[1]*xi[2]^2 xi[1]^2*xi[3] xi[1]^2*xi[2] xi[2]^2*xi[3]^2 xi[1]*xi[2]*xi[3]^2 xi[1]*xi[2]^2*xi[3] xi[1]^2*xi[3]^2 xi[1]^2*xi[2]*xi[3] xi[1]^2*xi[2]^2 xi[1]*xi[2]^2*xi[3]^2 xi[1]^2*xi[2]*xi[3]^2 xi[1]^2*xi[2]^2*xi[3] xi[1]^2*xi[2]^2*xi[3]^2
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Hex27}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 0 0 1 0 xi[3] xi[2] xi[2]*xi[3] 0 0 2*xi[1] 0 0 xi[3]^2 xi[2]^2 2*xi[1]*xi[3] 2*xi[1]*xi[2] 0 xi[2]*xi[3]^2 xi[2]^2*xi[3] 2*xi[1]*xi[3]^2 2*xi[1]*xi[2]*xi[3] 2*xi[1]*xi[2]^2 xi[2]^2*xi[3]^2 2*xi[1]*xi[2]*xi[3]^2 2*xi[1]*xi[2]^2*xi[3] 2*xi[1]*xi[2]^2*xi[3]^2
|
||||
0 0 1 0 xi[3] 0 xi[1] xi[1]*xi[3] 0 2*xi[2] 0 xi[3]^2 2*xi[2]*xi[3] 0 2*xi[1]*xi[2] 0 xi[1]^2 2*xi[2]*xi[3]^2 xi[1]*xi[3]^2 2*xi[1]*xi[2]*xi[3] 0 xi[1]^2*xi[3] 2*xi[1]^2*xi[2] 2*xi[1]*xi[2]*xi[3]^2 xi[1]^2*xi[3]^2 2*xi[1]^2*xi[2]*xi[3] 2*xi[1]^2*xi[2]*xi[3]^2
|
||||
0 1 0 0 xi[2] xi[1] 0 xi[1]*xi[2] 2*xi[3] 0 0 2*xi[2]*xi[3] xi[2]^2 2*xi[1]*xi[3] 0 xi[1]^2 0 2*xi[2]^2*xi[3] 2*xi[1]*xi[2]*xi[3] xi[1]*xi[2]^2 2*xi[1]^2*xi[3] xi[1]^2*xi[2] 0 2*xi[1]*xi[2]^2*xi[3] 2*xi[1]^2*xi[2]*xi[3] xi[1]^2*xi[2]^2 2*xi[1]^2*xi[2]^2*xi[3]
|
||||
]
|
||||
end
|
||||
|
||||
###
|
||||
|
||||
macro create_basis(T)
|
||||
quote
|
||||
T = $T
|
||||
global get_basis, get_dbasis, length, size
|
||||
X = get_reference_coordinates(T)
|
||||
nbasis = length(X)
|
||||
A = zeros(nbasis, nbasis)
|
||||
for i=1:nbasis
|
||||
A[i,:] = get_interpolation_polynomial(T, X[i])
|
||||
end
|
||||
invA = inv(A)
|
||||
function get_basis(element::Element{$T}, ip, time)
|
||||
return get_interpolation_polynomial($T, ip)*invA
|
||||
end
|
||||
function get_dbasis(element::Element{$T}, ip, time)
|
||||
return get_interpolation_polynomial($T, ip, Val{:partial_derivatives})*invA
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@create_basis Seg2
|
||||
@create_basis Seg3
|
||||
@create_basis Tri3
|
||||
@create_basis Tri6
|
||||
@create_basis Quad4
|
||||
@create_basis Quad8
|
||||
@create_basis Quad9
|
||||
@create_basis Tet4
|
||||
@create_basis Tet10
|
||||
@create_basis Hex8
|
||||
@create_basis Hex20
|
||||
@create_basis Hex27
|
||||
|
||||
+2
-77
@@ -30,7 +30,7 @@ Examples
|
||||
macro create_lagrange_element(element_name, element_description, X, P)
|
||||
eltype = esc(element_name)
|
||||
quote
|
||||
global get_basis, length, size
|
||||
global get_basis, length, size, get_reference_coordinates
|
||||
#=
|
||||
get_reference_element_coordinates,
|
||||
get_reference_element_midpoint
|
||||
@@ -54,91 +54,16 @@ macro create_lagrange_element(element_name, element_description, X, P)
|
||||
return size($X, 2)
|
||||
end
|
||||
|
||||
#=
|
||||
XX = refcoords($X)
|
||||
function get_reference_element_coordinates(::Type{$eltype})
|
||||
function get_reference_coordinates(::Type{$eltype})
|
||||
return XX
|
||||
end
|
||||
|
||||
XXX = vec(mean($X, 2))
|
||||
function get_reference_element_midpoint(::Type{$eltype})
|
||||
return XXX
|
||||
end
|
||||
|
||||
function $eltype(args...)
|
||||
return Element{$eltype}(args...)
|
||||
end
|
||||
|
||||
=#
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# 1d Lagrange elements
|
||||
|
||||
@create_lagrange_element(Seg2, "2 node linear line element",
|
||||
[-1.0 1.0], (xi) -> [1.0, xi[1]])
|
||||
|
||||
@create_lagrange_element(Seg3, "3 node quadratic line element",
|
||||
[-1.0 1.0 0.0], (xi) -> [1.0, xi[1], xi[1]^2])
|
||||
|
||||
# 2d Lagrange elements
|
||||
|
||||
@create_lagrange_element(Tri3, "3 node bilinear triangle element",
|
||||
[0.0 1.0 0.0
|
||||
0.0 0.0 1.0],
|
||||
(xi) -> [1.0, xi[1], xi[2]])
|
||||
|
||||
@create_lagrange_element(Tri6, "6 node quadratic triangle element",
|
||||
[0.0 1.0 0.0 0.5 0.5 0.0
|
||||
0.0 0.0 1.0 0.0 0.5 0.5],
|
||||
(xi) -> [1.0, xi[1], xi[2], xi[1]^2, xi[2]^2, xi[1]*xi[2]])
|
||||
|
||||
@create_lagrange_element(Quad4, "4 node bilinear quadrangle element",
|
||||
[-1.0 1.0 1.0 -1.0
|
||||
-1.0 -1.0 1.0 1.0],
|
||||
(xi) -> [1.0, xi[1], xi[2], xi[1]*xi[2]])
|
||||
|
||||
@create_lagrange_element(Quad9, "9 node bilinear quadrangle element",
|
||||
[-1.0 1.0 1.0 -1.0 0.0 1.0 0.0 -1.0
|
||||
-1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0],
|
||||
(xi) -> [1.0, xi[1], xi[2], xi[1]*xi[2],
|
||||
xi[1]^2, xi[2]^2, xi[1]^2*xi[2], xi[1]*xi[2]^2])
|
||||
|
||||
# 3d Lagrange elements
|
||||
|
||||
@create_lagrange_element(Hex8, "8 node hexahedra",
|
||||
[-1.0 1.0 1.0 -1.0 -1.0 1.0 1.0 -1.0
|
||||
-1.0 -1.0 1.0 1.0 -1.0 -1.0 1.0 1.0
|
||||
-1.0 -1.0 -1.0 -1.0 1.0 1.0 1.0 1.0],
|
||||
(xi) -> [1.0, xi[1], xi[2], xi[1]*xi[2], xi[3],
|
||||
xi[1]*xi[3], xi[2]*xi[3], xi[1]*xi[2]*xi[3]])
|
||||
|
||||
#=
|
||||
@create_lagrange_element(Hex20, "20 node hexahedra",
|
||||
[
|
||||
-1.0 1.0 1.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0 -1.0
|
||||
-1.0 -1.0 1.0 1.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0
|
||||
-1.0 -1.0 -1.0 -1.0 1.0 1.0 1.0 1.0 -1.0 -1.0 -1.0 -1.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
|
||||
],
|
||||
(xi) -> [1.0, xi[1], xi[2], xi[1]*xi[2], xi[3], xi[1]*xi[3], xi[2]*xi[3], xi[1]*xi[2]*xi[3]
|
||||
x[1]^2,
|
||||
])
|
||||
=#
|
||||
|
||||
@create_lagrange_element(Tet4, "4 node tetrahedron",
|
||||
[0.0 1.0 0.0 0.0
|
||||
0.0 0.0 1.0 0.0
|
||||
0.0 0.0 0.0 1.0],
|
||||
(xi) -> [1.0, xi[1], xi[2], xi[3]])
|
||||
|
||||
@create_lagrange_element(Tet10, "10 node quadratic tetrahedron",
|
||||
[0.0 1.0 0.0 0.0 0.5 0.5 0.0 0.0 0.5 0.0
|
||||
0.0 0.0 1.0 0.0 0.0 0.5 0.5 0.0 0.0 0.5
|
||||
0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.5 0.5 0.5],
|
||||
(xi) -> [ 1.0, xi[1], xi[2], xi[3], xi[1]^2,
|
||||
xi[2]^2, xi[3]^2, xi[1]*xi[2], xi[2]*xi[3], xi[3]*xi[1]])
|
||||
|
||||
function get_reference_element_midpoint{E}(element::Element{E})
|
||||
get_reference_element_midpoint(E)
|
||||
end
|
||||
|
||||
@@ -85,6 +85,20 @@ function get_nodal_vector(elements, field_name, time)
|
||||
return node_ids, field
|
||||
end
|
||||
|
||||
""" Return nodal values in Dict format. """
|
||||
function get_nodal_dict(T::DataType, elements, field_name, time)
|
||||
f = T()
|
||||
for element in elements
|
||||
for (c, v) in zip(get_connectivity(element), element(field_name, time))
|
||||
if haskey(f, c)
|
||||
@assert isapprox(f[c], v)
|
||||
end
|
||||
f[c] = v
|
||||
end
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
""" Update nodal field values from set of elements to another. Can be used to
|
||||
transform e.g. reaction force from boundary element set to surface of
|
||||
volume elements for easier postprocess.
|
||||
@@ -114,3 +128,17 @@ function copy_field!(src_problem::Problem, dst_problem::Problem, field_name, tim
|
||||
copy_field!(src_problem.elements, dst_problem.elements, field_name, time)
|
||||
end
|
||||
|
||||
""" Return field calculated to nodal points for elements in problem p. """
|
||||
function call(problem::Problem, field_name, time=0.0)
|
||||
f = Dict()
|
||||
for element in get_elements(problem)
|
||||
for (c, v) in zip(get_connectivity(element), element(field_name, time))
|
||||
if haskey(f, c)
|
||||
@assert isapprox(f[c], v)
|
||||
end
|
||||
f[c] = v
|
||||
end
|
||||
end
|
||||
return f
|
||||
end
|
||||
|
||||
|
||||
+65
-2
@@ -1,6 +1,17 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
#=
|
||||
- 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
|
||||
=#
|
||||
|
||||
importall Base
|
||||
|
||||
using JuliaFEM
|
||||
@@ -88,8 +99,25 @@ function create_elements(mesh::Mesh)
|
||||
return elements
|
||||
end
|
||||
|
||||
function create_elements(mesh::Mesh, element_set::ASCIIString)
|
||||
return create_elements(filter_by_element_set(mesh, element_set))
|
||||
function create_elements(mesh::Mesh, element_sets::ASCIIString...)
|
||||
elements = Element[]
|
||||
for element_set in element_sets
|
||||
new_elements = create_elements(filter_by_element_set(mesh, element_set))
|
||||
push!(elements, new_elements...)
|
||||
end
|
||||
return elements
|
||||
end
|
||||
|
||||
function create_elements(mesh::Mesh, element_type::Symbol)
|
||||
elements = Element[]
|
||||
for (elid, elcon) in mesh.elements
|
||||
eltype = mesh.element_types[elid]
|
||||
eltype == element_type || continue
|
||||
element = Element(JuliaFEM.(eltype), elcon)
|
||||
update!(element, "geometry", mesh.nodes)
|
||||
push!(elements, element)
|
||||
end
|
||||
return elements
|
||||
end
|
||||
|
||||
""" find npts nearest nodes form mesh and return id numbers as list. """
|
||||
@@ -104,3 +132,38 @@ function find_nearest_nodes(mesh::Mesh, coords::Vector, npts=1)
|
||||
return node_ids
|
||||
end
|
||||
|
||||
"""
|
||||
Apply new node ordering to elements. In JuliaFEM same node ordering is used
|
||||
than in ABAQUS and if mesh is parsed from FEM format with other node ordering
|
||||
this can be used to reorder nodes.
|
||||
|
||||
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
|
||||
|
||||
"""
|
||||
Swap surface element connectivity s.t. normals point outward
|
||||
"""
|
||||
function check_orientation!
|
||||
# TODO
|
||||
end
|
||||
|
||||
"""
|
||||
Partition model using METIS
|
||||
"""
|
||||
function partition_model!
|
||||
# TODO
|
||||
end
|
||||
|
||||
|
||||
@@ -309,18 +309,6 @@ function get_element_sets(med::MEDFile, mesh_name)
|
||||
return es
|
||||
end
|
||||
|
||||
global const med_elmap = Dict{Symbol, Vector{Int}}(
|
||||
:PO1 => [1],
|
||||
:SE2 => [1, 2],
|
||||
:SE3 => [1, 2, 3],
|
||||
:TR3 => [1, 2, 3],
|
||||
:QU4 => [1, 2, 3, 4],
|
||||
:TE4 => [3, 2, 1, 4],
|
||||
:TR6 => [1, 2, 3, 4, 5, 6],
|
||||
:QU8 => [1, 2, 3, 4, 5, 6, 7, 8],
|
||||
:HE8 => [4, 8, 7, 3, 1, 5, 6, 2], # ..?
|
||||
:T10 => [3, 2, 1, 4, 6, 5, 7, 10, 9, 8])
|
||||
|
||||
function get_connectivity(med::MEDFile, elsets, mesh_name)
|
||||
elsets[0] = :OTHER
|
||||
increments = keys(med.data["ENS_MAA"][mesh_name])
|
||||
@@ -340,12 +328,14 @@ function get_connectivity(med::MEDFile, elsets, mesh_name)
|
||||
eltype = Symbol(eltype)
|
||||
elco = element_connectivity[:, i]
|
||||
elset = Symbol(elsets[elset_ids[i]])
|
||||
#= to more general preprocess
|
||||
if haskey(med_elmap, eltype)
|
||||
elco = elco[med_elmap[eltype]]
|
||||
else
|
||||
warn("no element mapping info found for element type $eltype")
|
||||
warn("consider this as a warning: element may have french nodal ordering")
|
||||
end
|
||||
=#
|
||||
d[element_ids[i]] = (eltype, elset, elco)
|
||||
end
|
||||
end
|
||||
@@ -390,21 +380,56 @@ function parse_aster_med_file(fn::ASCIIString, mesh_name=nothing; debug=false)
|
||||
return result
|
||||
end
|
||||
|
||||
# some glues about ordering, this is still a mystery..
|
||||
# http://onelab.info/pipermail/gmsh/2008/003850.html
|
||||
# http://caelinux.org/wiki/index.php/Proj:UNVConvert
|
||||
|
||||
#global const med_connectivity = Dict{Symbol, Vector{Int}}(
|
||||
# :Tet4 => [3, 2, 1, 4],
|
||||
# :Hex8 => [4, 8, 7, 3, 1, 5, 6, 2], # ..?
|
||||
# :Tet10 => [3, 2, 1, 4, 6, 5, 7, 10, 9, 8])
|
||||
|
||||
global const med_connectivity = Dict{Symbol, Vector{Int}}(
|
||||
:Tet4 => [4,3,1,2],
|
||||
:Tet10 => [4,3,1,2,10,7,8,9,6,5],
|
||||
: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])
|
||||
|
||||
# element names in CA -> element names in JuliaFEM
|
||||
global const mapping = Dict(
|
||||
|
||||
:PO1 => :Poi1,
|
||||
|
||||
:SE2 => :Seg2,
|
||||
:SE3 => :Seg3,
|
||||
:SE4 => :Seg4,
|
||||
|
||||
:TR3 => :Tri3,
|
||||
:TR6 => :Tri6,
|
||||
:TR7 => :Tru6,
|
||||
|
||||
:QU4 => :Quad4,
|
||||
:QU8 => :Quad8,
|
||||
:QU9 => :Quad9,
|
||||
|
||||
:TE4 => :Tet4,
|
||||
:T10 => :Tet10,
|
||||
|
||||
:PE6 => :Penta6,
|
||||
:P15 => :Penta15,
|
||||
:P18 => :Penta18,
|
||||
|
||||
:HE8 => :Hex8,
|
||||
:H20 => :Hex20,
|
||||
:TE4 => :Tet4,
|
||||
:T10 => :Tet10)
|
||||
:H27 => :Hex27,
|
||||
|
||||
function aster_read_mesh(fn::ASCIIString, mesh_name=nothing)
|
||||
:PY5 => :Pyramid5,
|
||||
:P13 => :Pyramid13,
|
||||
|
||||
)
|
||||
|
||||
function aster_read_mesh(fn::ASCIIString, mesh_name=nothing; reorder_element_connectivity=true)
|
||||
result = parse_aster_med_file(fn, mesh_name)
|
||||
mesh = Mesh()
|
||||
for (nid, (nset, ncoords)) in result["nodes"]
|
||||
@@ -416,6 +441,9 @@ function aster_read_mesh(fn::ASCIIString, mesh_name=nothing)
|
||||
add_element!(mesh, elid, mapping[eltype], elcon)
|
||||
add_element_to_element_set!(mesh, string(elset), elid)
|
||||
end
|
||||
if reorder_element_connectivity
|
||||
reorder_element_connectivity!(mesh, med_connectivity)
|
||||
end
|
||||
return mesh
|
||||
end
|
||||
|
||||
|
||||
+11
-1
@@ -266,10 +266,14 @@ function update_elements!{P<:BoundaryProblem}(problem::Problem{P}, u, la)
|
||||
end
|
||||
end
|
||||
|
||||
function get_elements(problem)
|
||||
function get_elements(problem::Problem)
|
||||
return problem.elements
|
||||
end
|
||||
|
||||
function length(problem::Problem)
|
||||
return length(problem.elements)
|
||||
end
|
||||
|
||||
function update!(problem::Problem, field_name::ASCIIString, field)
|
||||
update!(problem.elements, field_name, field)
|
||||
end
|
||||
@@ -297,6 +301,12 @@ function push!(problem::Problem, elements::Vector)
|
||||
push!(problem.elements, elements...)
|
||||
end
|
||||
|
||||
function push!(problem::Problem, elements_::Vector...)
|
||||
for elements in elements_
|
||||
push!(problem.elements, elements...)
|
||||
end
|
||||
end
|
||||
|
||||
function get_gdofs(element::Element, dim::Int)
|
||||
conn = get_connectivity(element)
|
||||
if length(conn) == 0
|
||||
|
||||
+67
-12
@@ -207,11 +207,11 @@ conditions are first eliminated before solution.
|
||||
"""
|
||||
function solve!(K, C1, C2, D, f, g, u, la, ::Type{Val{1}}; F=nothing, debug=false)
|
||||
|
||||
nnz(D) == 0 || return false
|
||||
nnz(D) == 0 || return F, false
|
||||
nz = get_nonzero_rows(C2)
|
||||
B = get_nonzero_rows(C2')
|
||||
# C2^-1 exists or this doesn't work
|
||||
length(nz) == length(B) || return false
|
||||
length(nz) == length(B) || return F, false
|
||||
|
||||
A = get_nonzero_rows(K)
|
||||
I = setdiff(A, B)
|
||||
@@ -227,8 +227,7 @@ function solve!(K, C1, C2, D, f, g, u, la, ::Type{Val{1}}; F=nothing, debug=fals
|
||||
try
|
||||
u[B] = lufact(C2[nz,B]) \ full(g[nz])
|
||||
catch
|
||||
info("solver #1 failed to solve boundary dofs (you should not see this message).")
|
||||
return false
|
||||
error("solver #1 failed to solve boundary dofs (you should not see this message).")
|
||||
end
|
||||
|
||||
# solve interior domain using LDLt factorization
|
||||
@@ -296,9 +295,7 @@ function solve_linear_system(solver::Solver; F=nothing, empty_assemblies_before_
|
||||
i = 0
|
||||
for i in [1, 2]
|
||||
F, status = solve!(K, C1, C2, D, f, g, u, la, Val{i}; F=F)
|
||||
if status
|
||||
break
|
||||
end
|
||||
status && break
|
||||
end
|
||||
status || error("Failed to solve linear system!")
|
||||
|
||||
@@ -467,11 +464,6 @@ Main differences in this solver, compared to nonlinear solver are:
|
||||
|
||||
"""
|
||||
type Linear <: AbstractSolver
|
||||
norms :: Vector{Tuple}
|
||||
end
|
||||
|
||||
function Linear()
|
||||
solver = Linear([])
|
||||
end
|
||||
|
||||
function assemble!(solver::Solver{Linear}; show_info=true)
|
||||
@@ -526,3 +518,66 @@ end
|
||||
|
||||
### End of linear quasistatic solver
|
||||
|
||||
### Postprocessor
|
||||
|
||||
type Postprocessor <: AbstractSolver
|
||||
assembly :: Assembly
|
||||
F :: Union{Factorization, Void}
|
||||
end
|
||||
|
||||
function Postprocessor()
|
||||
Postprocessor(Assembly(), nothing)
|
||||
end
|
||||
|
||||
function assemble!(solver::Solver{Postprocessor}; show_info=true)
|
||||
show_info && info("Assembling problems ...")
|
||||
tic()
|
||||
nproblems = 0
|
||||
ndofs = 0
|
||||
assembly = solver.properties.assembly
|
||||
empty!(assembly)
|
||||
for problem in get_problems(solver)
|
||||
for element in get_elements(problem)
|
||||
postprocess!(assembly, problem, element, solver.time)
|
||||
end
|
||||
nproblems += 1
|
||||
ndofs = max(ndofs, size(problem.assembly.K, 2))
|
||||
end
|
||||
solver.ndofs = ndofs
|
||||
t1 = round(toq(), 2)
|
||||
show_info && info("Assembled $nproblems problems in $t1 seconds. ndofs = $ndofs.")
|
||||
end
|
||||
|
||||
function call(solver::Solver{Postprocessor}; show_info=true)
|
||||
t0 = Base.time()
|
||||
show_info && info(repeat("-", 80))
|
||||
show_info && info("Starting postprocessor")
|
||||
show_info && info("Increment time t=$(round(solver.time, 3))")
|
||||
show_info && info(repeat("-", 80))
|
||||
initialize!(solver)
|
||||
assemble!(solver)
|
||||
assembly = solver.properties.assembly
|
||||
M = sparse(assembly.M)
|
||||
f = sparse(assembly.f)
|
||||
F = cholfact(M)
|
||||
q = F \ f
|
||||
t1 = round(Base.time()-t0, 2)
|
||||
show_info && info("Postprocess of results ready in $t1 seconds.")
|
||||
return q
|
||||
end
|
||||
|
||||
""" Convenience function to call postprocessor. """
|
||||
function Postprocessor(problems::Problem...)
|
||||
solver = Solver(Postprocessor, "default postprocessor")
|
||||
if length(problems) != 0
|
||||
push!(solver, problems...)
|
||||
end
|
||||
return solver
|
||||
end
|
||||
|
||||
function Postprocessor(name::ASCIIString, problems::Problem...)
|
||||
solver = Postprocessor(problems...)
|
||||
solver.name = name
|
||||
return solver
|
||||
end
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user