mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-27 04:10:54 +00:00
analytical tests, hollow sphere and radial displacement + longitudinal vibration of rod (modal analysis)
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Testing
|
||||
|
||||
#=
|
||||
test subjects:
|
||||
- surface pressure load in curved surface
|
||||
- verification of elements wedge6 and wedge15
|
||||
|
||||
from Code Aster:
|
||||
N38 -8.85861895037377E-01 -3.46944695195361E-18 -3.46944695195361E-18
|
||||
coords of N38 = (1.0, 0.0, 0.0)
|
||||
|
||||
Analytical solution
|
||||
uᵣ(r) = b³p/(2Er²(a³-b³)) * (a³(ν+1) + r³(-4ν+2)), where
|
||||
a = inner surface radial distance, b = outer surface ...
|
||||
|
||||
if a=0.9, b=1.0, ν=1/3, E = 24580 and p = 7317 equation yields
|
||||
-9/10 for radial displacement
|
||||
=#
|
||||
|
||||
@testset """1/8 hollow sphere with surface load""" begin
|
||||
mesh_file = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(mesh_file, "HOLLOWSPHERE8_WEDGE6")
|
||||
body = Problem(Elasticity, "hollow sphere 1/8 model", 3)
|
||||
body.elements = create_elements(mesh, "HOLLOWSPHERE8")
|
||||
update!(body, "youngs modulus", 24580.0)
|
||||
update!(body, "poissons ratio", 1/3)
|
||||
bc = Problem(Dirichlet, "symmetry bc", 3, "displacement")
|
||||
el1 = create_elements(mesh, "FACE1")
|
||||
update!(el1, "displacement 3", 0.0)
|
||||
el2 = create_elements(mesh, "FACE2")
|
||||
update!(el2, "displacement 2", 0.0)
|
||||
el3 = create_elements(mesh, "FACE3")
|
||||
update!(el3, "displacement 1", 0.0)
|
||||
bc.elements = [el1; el2; el3]
|
||||
lo = Problem(Elasticity, "pressure load", 3)
|
||||
lo.elements = create_elements(mesh, "OUTER")
|
||||
update!(lo, "surface pressure", 7317.0)
|
||||
solver = LinearSolver(body, bc, lo)
|
||||
solver()
|
||||
|
||||
X = lo("geometry")
|
||||
u = lo("displacement")
|
||||
nids = sort(collect(keys(X)))
|
||||
umag = Float64[norm(u[id]) for id in nids]
|
||||
um = mean(umag)
|
||||
info("mean umag = $um")
|
||||
info("std umag = ", std(umag))
|
||||
rtol = norm(um - 0.9) / max(norm(um), 0.9) * 100.0
|
||||
info("rtol = $rtol")
|
||||
@test rtol < 1.5 # percents
|
||||
u_CA = [-8.85861895037377E-01, -3.46944695195361E-18, -3.46944695195361E-18]
|
||||
rtol = norm(u[38] - u_CA) / max(norm(u[38]), norm(u_CA)) * 100.0
|
||||
info("rel diff to CA = $rtol %")
|
||||
@test isapprox(u[38], u_CA)
|
||||
end
|
||||
@@ -0,0 +1,142 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "calculate cross-sectional properties" begin
|
||||
mesh_file = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(mesh_file, "CYLINDER_20_TET4")
|
||||
# calculate cross-sectional properties A and Iₓ
|
||||
fixed1 = Problem(Dirichlet, "left support", 3, "displacement")
|
||||
fixed1.elements = create_elements(mesh, "FACE1")
|
||||
A = calculate_area(fixed1)
|
||||
info("cross-section area: $A")
|
||||
# real area is π
|
||||
@test isapprox(A, pi; rtol=0.1)
|
||||
Xc = calculate_center_of_mass(fixed1)
|
||||
info("center of mass: $Xc")
|
||||
@test isapprox(Xc, [0.0, 0.0, 0.0]; atol=1.0e-12)
|
||||
I = calculate_second_moment_of_mass(fixed1)
|
||||
info("moments:")
|
||||
info(I)
|
||||
I_expected = zeros(3, 3)
|
||||
I_expected[2,2] = I_expected[3,3] = pi/4
|
||||
rtol = norm(I[2,2]-I_expected[2,2]) / max(I[2,2],I_expected[2,2])
|
||||
info("I rtol = $rtol")
|
||||
@test isapprox(I, I_expected; rtol = 0.2)
|
||||
end
|
||||
|
||||
#=
|
||||
test subjects:
|
||||
- calculate cross-sectional properties
|
||||
- modal analysis with known solution
|
||||
|
||||
Fixed-fixed solution is ωᵢ = λᵢ²√(EI/ρA) , where λᵢ = cosh(λᵢℓ)cos(λᵢℓ)
|
||||
|
||||
1: 4.730040744862704
|
||||
2: 7.853204624095838
|
||||
3: 10.995607838001671
|
||||
|
||||
[1] De Silva, Clarence W. Vibration: fundamentals and practice. CRC press, 2006, p.355
|
||||
=#
|
||||
|
||||
@testset "long rod under point load" begin
|
||||
mesh_file = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(mesh_file, "CYLINDER_20_TET10")
|
||||
# for (id, coords) in mesh.nodes
|
||||
# mesh.nodes[id][1] *= 5.0
|
||||
# end
|
||||
body = Problem(Elasticity, "rod", 3)
|
||||
body.elements = create_elements(mesh, "CYLINDER")
|
||||
E = 50475.44814745859
|
||||
rho = 1.0
|
||||
update!(body.elements, "youngs modulus", E)
|
||||
update!(body.elements, "poissons ratio", 0.3)
|
||||
update!(body.elements, "density", rho)
|
||||
# calculate cross-sectional properties A and Iₓ
|
||||
fixed1 = Problem(Dirichlet, "left support", 3, "displacement")
|
||||
fixed1.elements = create_elements(mesh, "FACE1")
|
||||
update!(fixed1.elements, "displacement 1", 0.0)
|
||||
update!(fixed1.elements, "displacement 2", 0.0)
|
||||
update!(fixed1.elements, "displacement 3", 0.0)
|
||||
fixed2 = Problem(Dirichlet, "right support", 3, "displacement")
|
||||
fixed2.elements = create_elements(mesh, "FACE2")
|
||||
update!(fixed2.elements, "displacement 1", 0.0)
|
||||
update!(fixed2.elements, "displacement 2", 0.0)
|
||||
update!(fixed2.elements, "displacement 3", 0.0)
|
||||
A = calculate_area(fixed1)
|
||||
info("cross-section area: $A")
|
||||
# using SALOME / SMESH, A = 2.82843
|
||||
# real area is π
|
||||
@test isapprox(A, pi; rtol=0.1)
|
||||
Xc = calculate_center_of_mass(fixed1)
|
||||
info("center of mass: $Xc")
|
||||
@test isapprox(Xc, [0.0, 0.0, 0.0]; atol=1.0e-5)
|
||||
I = calculate_second_moment_of_mass(fixed1)
|
||||
info("moments:")
|
||||
info(I)
|
||||
I_expected = zeros(3, 3)
|
||||
r = 1.0
|
||||
I_expected[2,2] = I_expected[3,3] = pi/4*r^2
|
||||
rtol = norm(I[2,2]-I_expected[2,2]) / max(I[2,2],I_expected[2,2])
|
||||
info("I rtol = $rtol")
|
||||
@test isapprox(I, I_expected; rtol = 0.2)
|
||||
#=
|
||||
# apply transform Tx + b, in this case move cross-section to
|
||||
# xy-plane from yz-plane, i.e.
|
||||
# x₁ = y₂
|
||||
# y₁ = z₂
|
||||
T = [
|
||||
0.0 1.0 0.0
|
||||
0.0 0.0 1.0]
|
||||
b = [0.0, 0.0]
|
||||
X 1 = first(cross_section)("geometry", [1/3, 1/3], 0.0)
|
||||
apply_affine_transform!(cross_section, T, b)
|
||||
X2 = first(cross_section)("geometry", [1/3, 1/3], 0.0)
|
||||
info("X1 = $X1, X2 = $X2")
|
||||
@test isapprox(T*X1+b, X2)
|
||||
=#
|
||||
c = sqrt(E*I[2,2]/(rho*A))
|
||||
info("c = $c")
|
||||
|
||||
|
||||
# analytical solution is
|
||||
l = 20.0
|
||||
r = 1.0
|
||||
la = 4.730040744862704/l
|
||||
|
||||
# semi-analytical (c numerical)
|
||||
freq_sa = (c*la^2)/(2*pi)
|
||||
info("freq_sa = $freq_sa")
|
||||
|
||||
A = pi*r^2
|
||||
I = pi/4*r^4
|
||||
c = sqrt(E*I/(rho*A))
|
||||
info("c analytical = $c")
|
||||
freq_a = (c*la^2)/(2*pi)
|
||||
|
||||
info("freq_a = $freq_a")
|
||||
|
||||
solver = Solver(Modal, body, fixed1, fixed2)
|
||||
solver()
|
||||
freqs = keys(body["displacement"])
|
||||
|
||||
rtol1 = norm(freq_sa - freqs[2])/max(freq_sa, freqs[2])
|
||||
rtol2 = norm(freq_a - freqs[2])/max(freq_a, freqs[2])
|
||||
info("rtol 1 = $rtol1, rtol 2 = $rtol2")
|
||||
@test rtol2 < 1.0e-2
|
||||
#=
|
||||
result = XDMF()
|
||||
for (i, freq) in enumerate(freqs)
|
||||
isapprox(freq, 0.0) && continue
|
||||
info("$i freq: $freq")
|
||||
xdmf_new_result!(result, body, freq)
|
||||
xdmf_save_field!(result, body, freq, "displacement"; field_type="Vector")
|
||||
end
|
||||
xdmf_save!(result, "/tmp/rod_nf.xmf")
|
||||
=#
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user