mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-26 11:51:31 +00:00
analytical tests, hollow sphere and radial displacement + longitudinal vibration of rod (modal analysis)
This commit is contained in:
+5
-2
@@ -9,7 +9,7 @@ module JuliaFEM
|
||||
importall Base
|
||||
|
||||
include("fields.jl")
|
||||
export Field, DCTI, DVTI, DCTV, DVTV, CCTI, CVTI, CCTV, CVTV
|
||||
export Field, DCTI, DVTI, DCTV, DVTV, CCTI, CVTI, CCTV, CVTV, Increment
|
||||
include("types.jl") # data types: Point, IntegrationPoint, ...
|
||||
export AbstractPoint, Point, IntegrationPoint, IP, Node
|
||||
|
||||
@@ -132,7 +132,10 @@ include("postprocess_utils.jl")
|
||||
export calc_nodal_values!,
|
||||
get_nodal_vector,
|
||||
get_nodal_dict,
|
||||
copy_field!
|
||||
copy_field!,
|
||||
calculate_area,
|
||||
calculate_center_of_mass,
|
||||
calculate_second_moment_of_mass
|
||||
include("postprocess_xdmf.jl")
|
||||
export XDMF, xdmf_new_result!, xdmf_save_field!, xdmf_save!
|
||||
end
|
||||
|
||||
@@ -410,3 +410,23 @@ function Base.(:*)(grad::Matrix, field::DVTI)
|
||||
return sum([kron(grad[:,i], field[i]') for i=1:length(field)])'
|
||||
end
|
||||
|
||||
function DVTV(data::Pair{Float64, Vector}...)
|
||||
return DVTV([Increment(d[1], d[2]) for d in data])
|
||||
end
|
||||
|
||||
function start(f::DVTV)
|
||||
return start(f.data)
|
||||
end
|
||||
|
||||
function next(f::DVTV, state)
|
||||
return next(f.data, state)
|
||||
end
|
||||
|
||||
function done(f::DVTV, state)
|
||||
return done(f.data, state)
|
||||
end
|
||||
|
||||
""" Return time vector from time variable field. """
|
||||
function keys(field::DVTV)
|
||||
return Float64[increment.time for increment in field]
|
||||
end
|
||||
|
||||
@@ -164,3 +164,83 @@ function call(problem::Problem, field_name::AbstractString, X::Vector, time::Flo
|
||||
return fillna
|
||||
end
|
||||
|
||||
""" Calculate area of cross-section. """
|
||||
function calculate_area(problem::Problem, X=[0.0, 0.0], time=0.0)
|
||||
A = 0.0
|
||||
for element in get_elements(problem)
|
||||
elsize = size(element)
|
||||
elsize[1] == 2 || error("wrong dimension of problem for area calculation, element size = $elsize")
|
||||
for ip in get_integration_points(element)
|
||||
w = ip.weight*element(ip, time, Val{:detJ})
|
||||
A += w
|
||||
end
|
||||
end
|
||||
return A
|
||||
end
|
||||
|
||||
""" Calculate volume of body. """
|
||||
function calculate_volume(problem::Problem, X=[0.0, 0.0, 0.0], time=0.0)
|
||||
V = 0.0
|
||||
for element in get_elements(problem)
|
||||
elsize = size(element)
|
||||
elsize[1] == 3 || error("wrong dimension of problem for area calculation, element size = $elsize")
|
||||
for ip in get_integration_points(element)
|
||||
w = ip.weight*element(ip, time, Val{:detJ})
|
||||
V += w
|
||||
end
|
||||
end
|
||||
return V
|
||||
end
|
||||
|
||||
""" Calculate center of mass of body with respect to X.
|
||||
https://en.wikipedia.org/wiki/Center_of_mass
|
||||
"""
|
||||
function calculate_center_of_mass(problem::Problem, X=[0.0, 0.0, 0.0], time=0.0)
|
||||
M = 0.0
|
||||
Xc = zeros(X)
|
||||
for element in get_elements(problem)
|
||||
for ip in get_integration_points(element)
|
||||
w = ip.weight*element(ip, time, Val{:detJ})
|
||||
M += w
|
||||
rho = haskey(element, "density") ? element("density", ip, time) : 1.0
|
||||
Xp = element("geometry", ip, time)
|
||||
Xc += w*rho*(Xp-X)
|
||||
end
|
||||
end
|
||||
return 1.0/M * Xc
|
||||
end
|
||||
|
||||
""" Calculate second moment of mass with respect to X.
|
||||
https://en.wikipedia.org/wiki/Second_moment_of_area
|
||||
"""
|
||||
function calculate_second_moment_of_mass(problem::Problem, X=[0.0, 0.0, 0.0], time=0.0)
|
||||
n = length(X)
|
||||
I = zeros(n, n)
|
||||
for element in get_elements(problem)
|
||||
for ip in get_integration_points(element)
|
||||
w = ip.weight*element(ip, time, Val{:detJ})
|
||||
rho = haskey(element, "density") ? element("density", ip, time) : 1.0
|
||||
Xp = element("geometry", ip, time) - X
|
||||
I += w*rho*Xp*Xp'
|
||||
end
|
||||
end
|
||||
return I
|
||||
end
|
||||
|
||||
function getindex(problem::Problem, field_name::AbstractString)
|
||||
info("fetching result $field_name")
|
||||
timeframes = []
|
||||
for frame in first(problem.elements)[field_name].data
|
||||
push!(timeframes, frame.time)
|
||||
end
|
||||
info("time frames: $timeframes")
|
||||
conn = get_connectivity(problem)
|
||||
increments = Increment[]
|
||||
for time in timeframes
|
||||
p = problem(field_name, time)
|
||||
data = [p[id] for id in conn]
|
||||
push!(increments, Increment(time, data))
|
||||
end
|
||||
return DVTV(increments)
|
||||
end
|
||||
|
||||
|
||||
@@ -313,6 +313,10 @@ function push!(problem::Problem, elements_::Vector...)
|
||||
end
|
||||
end
|
||||
|
||||
function get_connectivity(problem::Problem)
|
||||
return union([get_connectivity(element) for element in get_elements(problem)]...)
|
||||
end
|
||||
|
||||
function get_gdofs(element::Element, dim::Int)
|
||||
conn = get_connectivity(element)
|
||||
if length(conn) == 0
|
||||
|
||||
@@ -69,7 +69,7 @@ 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}
|
||||
typealias Elasticity3DVolumeElements Union{Tet4, Wedge6, Hex8, Tet10, Hex20, Hex27}
|
||||
|
||||
|
||||
""" Elasticity equations for 2d cases. """
|
||||
@@ -544,11 +544,12 @@ function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity},
|
||||
f[i:dim:end] += w*vec(T*N)
|
||||
end
|
||||
end
|
||||
if haskey(element, "displacement traction force n")
|
||||
if haskey(element, "surface pressure")
|
||||
J = element(ip, time, Val{:Jacobian})'
|
||||
n = cross(J[:,1], J[:,2])
|
||||
n /= norm(n)
|
||||
p = element("displacement traction force n", ip, time)
|
||||
# sign convention, positive pressure is towards surface
|
||||
p = -element("surface pressure", ip, time)
|
||||
f += w*p*vec(n*N)
|
||||
end
|
||||
end
|
||||
|
||||
+29
-2
@@ -19,6 +19,13 @@ function Solver{S<:AbstractSolver}(::Type{S}, name="solver", properties...)
|
||||
return solver
|
||||
end
|
||||
|
||||
function Solver{S<:AbstractSolver}(::Type{S}, problems::Problem...)
|
||||
variant = S()
|
||||
solver = Solver{S}("$(S)Solver", 0.0, [], [], 0, variant)
|
||||
push!(solver.problems, problems...)
|
||||
return solver
|
||||
end
|
||||
|
||||
function get_problems(solver::Solver)
|
||||
return solver.problems
|
||||
end
|
||||
@@ -334,6 +341,26 @@ function assemble!(solver::Solver; show_info=true)
|
||||
show_info && info("Assembled $nproblems problems in $t1 seconds. ndofs = $ndofs.")
|
||||
end
|
||||
|
||||
function get_unknown_fields(solver::Solver)
|
||||
fields = Dict()
|
||||
for problem in get_field_problems(solver)
|
||||
field_name = get_unknown_field_name(problem)
|
||||
field_dim = get_unknown_field_dimension(problem)
|
||||
fields[field_name] = field_dim
|
||||
end
|
||||
return fields
|
||||
end
|
||||
|
||||
function get_unknown_field_name(solver::Solver)
|
||||
fields = get_unknown_fields(solver)
|
||||
return join(sort(collect(keys(fields))), ", ")
|
||||
end
|
||||
|
||||
function get_unknown_field_dimension(solver::Solver)
|
||||
fields = get_unknown_fields(solver)
|
||||
return sum(values(fields))
|
||||
end
|
||||
|
||||
""" Default initializer for solver. """
|
||||
function initialize!(solver::Solver; show_info=true)
|
||||
show_info && info("Initializing problems ...")
|
||||
@@ -342,8 +369,8 @@ function initialize!(solver::Solver; show_info=true)
|
||||
t0 = Base.time()
|
||||
field_problems = get_field_problems(solver)
|
||||
length(field_problems) != 0 || warn("No field problem found from solver, add some..?")
|
||||
field_dim = get_unknown_field_dimension(first(field_problems))
|
||||
field_name = get_unknown_field_name(first(field_problems))
|
||||
field_name = get_unknown_field_name(solver)
|
||||
field_dim = get_unknown_field_dimension(solver)
|
||||
info("initialize!(): looks we are solving $field_name, $field_dim dofs/node")
|
||||
nodes = Set{Int64}()
|
||||
for problem in problems
|
||||
|
||||
+35
-1
@@ -56,6 +56,8 @@ function call(solver::Solver{Modal}; show_info=true, debug=false)
|
||||
P, h = create_projection(C1, g)
|
||||
K_red = P'*K*P
|
||||
M_red = P'*M*P
|
||||
K_red = 1/2*(K_red + K_red')
|
||||
M_red = 1/2*(M_red + M_red')
|
||||
t1 = round(toq(), 2)
|
||||
info("Eliminated dirichlet boundaries in $t1 seconds.")
|
||||
|
||||
@@ -71,7 +73,22 @@ function call(solver::Solver{Modal}; show_info=true, debug=false)
|
||||
end
|
||||
|
||||
tic()
|
||||
om2, X = eigs(K_red[nz,nz], M_red[nz,nz]; nev=props.nev, which=props.which)
|
||||
om2 = nothing
|
||||
X = nothing
|
||||
try
|
||||
om2, X = eigs(K_red[nz,nz], M_red[nz,nz]; nev=props.nev, which=props.which)
|
||||
catch
|
||||
info("failed to calculate eigenvalues")
|
||||
info("K sym?", issym(K_red[nz,nz]))
|
||||
info("M sym?", issym(M_red[nz,nz]))
|
||||
info("K posdef?", isposdef(K_red[nz,nz]))
|
||||
info("M posdef?", isposdef(M_red[nz,nz]))
|
||||
k1 = maximum(abs(K_red[nz,nz] - K_red[nz,nz]'))
|
||||
m1 = maximum(abs(M_red[nz,nz] - M_red[nz,nz]'))
|
||||
info("K skewness ", k1)
|
||||
info("M skewness ", m1)
|
||||
rethrow()
|
||||
end
|
||||
props.eigvals = om2
|
||||
props.eigvecs = zeros(ndofs, length(om2))
|
||||
v = zeros(ndofs)
|
||||
@@ -82,6 +99,23 @@ function call(solver::Solver{Modal}; show_info=true, debug=false)
|
||||
end
|
||||
t1 = round(toq(), 2)
|
||||
info("Eigenvalues computed in $t1 seconds. Eigenvalues: $om2")
|
||||
|
||||
for i=1:length(om2)
|
||||
u = props.eigvecs[:,i]
|
||||
field_dim = get_unknown_field_dimension(solver)
|
||||
field_name = get_unknown_field_name(solver)
|
||||
nnodes = round(Int, length(u)/field_dim)
|
||||
solution = reshape(u, field_dim, nnodes)
|
||||
for problem in get_problems(solver)
|
||||
local_sol = Dict{Int64, Vector{Float64}}()
|
||||
for node_id in get_connectivity(problem)
|
||||
local_sol[node_id] = solution[:, node_id]
|
||||
end
|
||||
freq = real(sqrt(om2[i])/(2.0*pi))
|
||||
update!(problem, field_name, freq => local_sol)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user