mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-09 12:42:19 +00:00
fixed problems with surface loads. det(element, ip, time) should be avoided.
This commit is contained in:
+15
-14
@@ -70,20 +70,20 @@ https://en.wikipedia.org/wiki/Hooke's_law
|
||||
"""
|
||||
function get_residual_vector{P<:ElasticityProblem}(problem::Problem{P}, element::Element, ip::IntegrationPoint, time::Number; variation=nothing)
|
||||
|
||||
|
||||
# u = element("displacement", ip, time, variation)
|
||||
|
||||
r = zeros(Float64, problem.dim, length(element))
|
||||
|
||||
J = get_jacobian(element, ip, time)
|
||||
|
||||
# internal forces
|
||||
if haskey(element, "youngs modulus") && haskey(element, "poissons ratio")
|
||||
u = element("displacement", time, variation)
|
||||
grad = element(ip, time, Val{:grad})
|
||||
gradu = grad*u
|
||||
|
||||
F = I + gradu # deformation gradient
|
||||
# info("gradu = \n$(ForwardDiff.get_value(gradu))")
|
||||
# deformation gradient
|
||||
F = I + gradu
|
||||
|
||||
# material
|
||||
young = element("youngs modulus", ip, time)
|
||||
poisson = element("poissons ratio", ip, time)
|
||||
mu = young/(2*(1+poisson))
|
||||
@@ -91,29 +91,30 @@ function get_residual_vector{P<:ElasticityProblem}(problem::Problem{P}, element:
|
||||
if P == PlaneStressElasticityProblem
|
||||
lambda = 2*lambda*mu/(lambda + 2*mu) # <- correction for 2d problems
|
||||
end
|
||||
E = 1/2*(F'*F - I) # strain
|
||||
|
||||
# strain
|
||||
E = 1/2*(F'*F - I)
|
||||
|
||||
# stress
|
||||
S = lambda*trace(E)*I + 2*mu*E
|
||||
|
||||
#J = det(element, ip, time)
|
||||
#T = J^-1*F*S*F'
|
||||
#ip["cauchy stress"] = T
|
||||
#ip["gl strain"] = E
|
||||
|
||||
r += F*S*grad
|
||||
r += F*S*grad*det(J)
|
||||
end
|
||||
|
||||
# external forces - volume load
|
||||
if haskey(element, "displacement load")
|
||||
basis = element(ip, time)
|
||||
b = element("displacement load", ip, time)
|
||||
r -= b*basis
|
||||
r -= b*basis*det(J)
|
||||
end
|
||||
|
||||
# external forces - surface traction force
|
||||
if haskey(element, "displacement traction force")
|
||||
basis = element(ip, time)
|
||||
T = element("displacement traction force", ip, time)
|
||||
r -= T*basis
|
||||
JT = transpose(J)
|
||||
s = size(JT, 2) == 1 ? JT : cross(JT[:,1], JT[:,2])
|
||||
r -= T*basis*norm(s)
|
||||
end
|
||||
|
||||
return vec(r)
|
||||
|
||||
+26
-4
@@ -197,13 +197,35 @@ function call(element::Element, field_name::ASCIIString)
|
||||
return element[field_name]
|
||||
end
|
||||
|
||||
function LinAlg.det{E<:AbstractElement}(element::Element{E}, ip::IntegrationPoint, time::Number=0.0)
|
||||
|
||||
""" Return the jacobian of element. """
|
||||
function get_jacobian{E}(element::Element{E}, xi::Vector{Float64}, time::Real)
|
||||
X = element("geometry", time)
|
||||
dN = get_dbasis(E, ip.xi)
|
||||
dN = get_dbasis(E, xi)
|
||||
J = sum([kron(dN[:,i], X[i]') for i=1:length(X)])
|
||||
m, n = size(J)
|
||||
return m == n ? det(J) : norm(J)
|
||||
return J
|
||||
end
|
||||
function get_jacobian{E}(element::Element{E}, ip::IntegrationPoint, time::Real)
|
||||
return get_jacobian(element, ip.xi, time)
|
||||
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
|
||||
return det(J)
|
||||
end
|
||||
JT = transpose(J)
|
||||
s = size(JT, 2) == 1 ? norm(JT) : norm(cross(JT[:,1], JT[:,2]))
|
||||
return s
|
||||
end
|
||||
function LinAlg.det{E<:AbstractElement}(element::Element{E}, ip::IntegrationPoint, time::Real)
|
||||
return det(element, ip.xi, time)
|
||||
end
|
||||
|
||||
|
||||
|
||||
""" Check does field exist. """
|
||||
function Base.haskey(element::Element, what)
|
||||
|
||||
+7
-9
@@ -77,15 +77,15 @@ function assemble!(assembly::Assembly, problem::Problem, element::Element, time:
|
||||
# 1. if equations are defined we just integrate them, without caring how they are done
|
||||
if has_mass_matrix(problem, element) || has_stiffness_matrix(problem, element) || has_force_vector(problem, element)
|
||||
for ip in get_integration_points(element)
|
||||
s = ip.weight*det(element, ip, time)
|
||||
w = ip.weight*det(J)
|
||||
if has_mass_matrix(element)
|
||||
add!(assembly.mass_matrix, gdofs, gdofs, s*get_mass_matrix(problem, element, ip, time))
|
||||
add!(assembly.mass_matrix, gdofs, gdofs, w*get_mass_matrix(problem, element, ip, time))
|
||||
end
|
||||
if has_stiffness_matrix(element)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, s*get_stiffness_matrix(problem, element, ip, time))
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*get_stiffness_matrix(problem, element, ip, time))
|
||||
end
|
||||
if has_force_vector(element)
|
||||
add!(assembly.force_vector, gdofs, s*get_force_vector(problem, element, ip, time))
|
||||
add!(assembly.force_vector, gdofs, w*get_force_vector(problem, element, ip, time))
|
||||
end
|
||||
end
|
||||
# external loads -- if any nodal loads is defined add to force vector
|
||||
@@ -104,16 +104,15 @@ function assemble!(assembly::Assembly, problem::Problem, element::Element, time:
|
||||
df = similar(field, data)
|
||||
# integrate potential energy
|
||||
for ip in get_integration_points(element)
|
||||
s = ip.weight*det(element, ip, time)
|
||||
dw = get_potential_energy(problem, element, ip, time; variation=df)
|
||||
W += s*dw
|
||||
W += ip.weight*dw
|
||||
end
|
||||
# external energy -- if any nodal loads is defined, decrease from potential energy
|
||||
if haskey(element, "$unknown_field_name nodal load")
|
||||
P = element["$unknown_field_name nodal load"](time)
|
||||
W -= dot(vec(P), vec(df))
|
||||
end
|
||||
return isa(W, Array) ? W[1] : W
|
||||
return W[1]
|
||||
end
|
||||
|
||||
hessian, allresults = ForwardDiff.hessian(calc_W, vec(field), AllResults, cache=autodiffcache)
|
||||
@@ -133,9 +132,8 @@ function assemble!(assembly::Assembly, problem::Problem, element::Element, time:
|
||||
gauss_fields = IntegrationPoint[]
|
||||
# integrate residual vector
|
||||
for ip in get_integration_points(element)
|
||||
s = ip.weight*det(element, ip, time)
|
||||
dr = get_residual_vector(problem, element, ip, time; variation=df)
|
||||
R += s*dr
|
||||
R += ip.weight*dr
|
||||
if ip.changed
|
||||
push!(gauss_fields, ip)
|
||||
end
|
||||
|
||||
+6
-5
@@ -46,24 +46,25 @@ function assemble!(assembly::Assembly, problem::Problem{HeatProblem}, element::E
|
||||
|
||||
gdofs = get_gdofs(element, problem.dim)
|
||||
for ip in get_integration_points(element)
|
||||
w = ip.weight*det(element, ip, time)
|
||||
w = ip.weight
|
||||
J = get_jacobian(element, ip, time)
|
||||
N = element(ip, time)
|
||||
if haskey(element, "density")
|
||||
rho = element("density", ip, time)
|
||||
add!(assembly.mass_matrix, gdofs, gdofs, w*rho*N'*N)
|
||||
add!(assembly.mass_matrix, gdofs, gdofs, w*rho*N'*N*det(J))
|
||||
end
|
||||
if haskey(element, "temperature thermal conductivity")
|
||||
dN = element(ip, time, Val{:grad})
|
||||
k = element("temperature thermal conductivity", ip, time)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*k*dN'*dN)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*k*dN'*dN*det(J))
|
||||
end
|
||||
if haskey(element, "temperature load")
|
||||
f = element("temperature load", ip, time)
|
||||
add!(assembly.force_vector, gdofs, w*N'*f)
|
||||
add!(assembly.force_vector, gdofs, w*N'*f*det(J))
|
||||
end
|
||||
if haskey(element, "temperature flux")
|
||||
g = element("temperature flux", ip, time)
|
||||
add!(assembly.force_vector, gdofs, w*N'*g)
|
||||
add!(assembly.force_vector, gdofs, w*N'*g*norm(J))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+12
-10
@@ -16,7 +16,8 @@ function assemble!{E<:CG, P<:LinearElasticityProblem}(assembly::Assembly, proble
|
||||
ndim, nnodes = size(E)
|
||||
B = zeros(6, 3*nnodes)
|
||||
for ip in get_integration_points(element)
|
||||
w = ip.weight*det(element, ip, time)
|
||||
w = ip.weight
|
||||
J = get_jacobian(element, ip, time)
|
||||
N = element(ip, time)
|
||||
if haskey(element, "youngs modulus") && haskey(element, "poissons ratio")
|
||||
v = element("poissons ratio", ip, time)
|
||||
@@ -44,16 +45,16 @@ function assemble!{E<:CG, P<:LinearElasticityProblem}(assembly::Assembly, proble
|
||||
B[6, 3*(i-1)+1] = dN[3,i]
|
||||
B[6, 3*(i-1)+3] = dN[1,i]
|
||||
end
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*B'*C*B)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*B'*C*B*det(J))
|
||||
end
|
||||
if haskey(element, "displacement load")
|
||||
b = element("displacement load", ip, time)
|
||||
add!(assembly.force_vector, gdofs, w*N'*b)
|
||||
add!(assembly.force_vector, gdofs, w*N'*b*det(J))
|
||||
end
|
||||
if haskey(element, "displacement traction force")
|
||||
T = element("displacement traction force", ip, time)
|
||||
L = w*T*N
|
||||
# dump(L)
|
||||
JT = transpose(J)
|
||||
L = w*T*N*norm(cross(JT[:,1], JT[:,2]))
|
||||
add!(assembly.force_vector, gdofs, vec(L))
|
||||
end
|
||||
end
|
||||
@@ -72,7 +73,8 @@ function assemble!{E<:CG, P<:PlaneStressLinearElasticityProblem}(assembly::Assem
|
||||
ndim, nnodes = size(E)
|
||||
B = zeros(3, 2*nnodes)
|
||||
for ip in get_integration_points(element)
|
||||
w = ip.weight*det(element, ip, time)
|
||||
w = ip.weight
|
||||
J = get_jacobian(element, ip, time)
|
||||
N = element(ip, time)
|
||||
if haskey(element, "youngs modulus") && haskey(element, "poissons ratio")
|
||||
nu = element("poissons ratio", ip, time)
|
||||
@@ -89,17 +91,17 @@ function assemble!{E<:CG, P<:PlaneStressLinearElasticityProblem}(assembly::Assem
|
||||
B[3, 2*(i-1)+1] = dN[2,i]
|
||||
B[3, 2*(i-1)+2] = dN[1,i]
|
||||
end
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*B'*C*B)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*B'*C*B*det(J))
|
||||
end
|
||||
if haskey(element, "displacement load")
|
||||
b = element("displacement load", ip, time)
|
||||
add!(assembly.force_vector, gdofs, w*N'*b)
|
||||
add!(assembly.force_vector, gdofs, w*N'*b*det(J))
|
||||
end
|
||||
if haskey(element, "displacement traction force")
|
||||
T = element("displacement traction force", ip, time)
|
||||
L = w*T*N
|
||||
# dump(L)
|
||||
L = w*T*N*norm(J)
|
||||
add!(assembly.force_vector, gdofs, vec(L))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ function test_continuum_elasticity_with_surface_load()
|
||||
set_geometry!(element1, nodes)
|
||||
# element1["youngs modulus"] = 900.0
|
||||
# element1["poissons ratio"] = 0.25
|
||||
element1["youngs modulus"] = 9000.0
|
||||
element1["youngs modulus"] = 900.0
|
||||
element1["poissons ratio"] = 0.25
|
||||
element1["displacement"] = (0.0 => Vector{Float64}[[0.0, 0.0, 0.0] for i=1:8])
|
||||
|
||||
@@ -105,7 +105,6 @@ function test_continuum_elasticity_with_surface_load()
|
||||
push!(problem, element1)
|
||||
push!(problem, element2)
|
||||
|
||||
#=
|
||||
free_dofs = zeros(Bool, 8, 3)
|
||||
x = 1
|
||||
y = 2
|
||||
@@ -126,8 +125,8 @@ function test_continuum_elasticity_with_surface_load()
|
||||
info("initial stiffness matrix")
|
||||
dump(round(Int, full(ass.stiffness_matrix))[free_dofs, free_dofs])
|
||||
solve!(problem, free_dofs, 0.0; max_iterations=10)
|
||||
=#
|
||||
|
||||
#=
|
||||
dx = Quad4([1, 4, 8, 5])
|
||||
dx["displacement 1"] = 0.0
|
||||
dy = Quad4([1, 5, 6, 2])
|
||||
@@ -145,17 +144,18 @@ function test_continuum_elasticity_with_surface_load()
|
||||
solver.dump_matrices = true
|
||||
solver.name = "3d_hex8"
|
||||
solver(0.0)
|
||||
=#
|
||||
|
||||
disp = element1("displacement", [1.0, 1.0, 1.0], 0.0)
|
||||
info("displacement at tip: $disp")
|
||||
info("displacement on element: ")
|
||||
for (i, d) in enumerate(element1("displacement", 0.0))
|
||||
@printf "%d %f %f %f\n" [i;d]...
|
||||
@printf "%d % f % f % f\n" [i;d]...
|
||||
end
|
||||
# verified using Code Aster.
|
||||
# 2015-12-12-continuum-elasticity/vim c3d_grot_gdep_traction_force.comm
|
||||
# @test isapprox(disp, [3.17431158889468E-02, 3.17431158889468E-02, -1.38591518927826E-01])
|
||||
@test isapprox(disp, [2.80559539222183E-03, 2.80559539222183E-03, -1.13019918093242E-02])
|
||||
@test isapprox(disp, [3.17431158889468E-02, 3.17431158889468E-02, -1.38591518927826E-01])
|
||||
#@test isapprox(disp, [2.80559539222183E-03, 2.80559539222183E-03, -1.13019918093242E-02])
|
||||
end
|
||||
#test_continuum_elasticity_with_surface_load()
|
||||
|
||||
|
||||
+12
-1
@@ -6,7 +6,7 @@ module ElementTests
|
||||
using JuliaFEM.Test
|
||||
|
||||
using JuliaFEM.Core: AbstractElement, Element, Field, FieldSet, test_element
|
||||
using JuliaFEM.Core: Tri3
|
||||
using JuliaFEM.Core: Tri3, Quad4
|
||||
import JuliaFEM.Core: get_basis, get_dbasis, calculate_normal_tangential_coordinates!
|
||||
import Base: size
|
||||
|
||||
@@ -91,4 +91,15 @@ function test_calculate_normal_tangential_coordinates()
|
||||
end
|
||||
#test_calculate_normal_tangential_coordinates()
|
||||
|
||||
function test_manifold_determinant()
|
||||
el = Quad4([1, 2, 3, 4])
|
||||
#el["geometry"] = Vector{Float64}[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
|
||||
el["geometry"] = Vector{Float64}[[0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0]]
|
||||
# mother element area = 2*2 = 4, this element is 1, determinant should be 1/4 everywhere
|
||||
d = det(el, [0.1, 0.2], 0.0)
|
||||
d_expected = 0.25
|
||||
@test d == d_expected
|
||||
end
|
||||
#test_manifold_determinant()
|
||||
|
||||
end
|
||||
|
||||
@@ -36,13 +36,13 @@ function test_plane_stress_linear_elasticity_with_surface_load()
|
||||
|
||||
free_dofs = Int64[3, 5, 6, 8]
|
||||
|
||||
info("initial force vector")
|
||||
ass = assemble(problem, 0.0)
|
||||
f = full(ass.force_vector)
|
||||
K = full(ass.stiffness_matrix)
|
||||
dump(reshape(f, 2, 4))
|
||||
info("initial stiffness matrix")
|
||||
dump(round(Int, K)[free_dofs, free_dofs])
|
||||
# info("initial force vector")
|
||||
# dump(reshape(f, 2, 4))
|
||||
# info("initial stiffness matrix")
|
||||
# dump(round(Int, K)[free_dofs, free_dofs])
|
||||
|
||||
u = zeros(2, 4)
|
||||
u[free_dofs] = K[free_dofs, free_dofs] \ f[free_dofs]
|
||||
@@ -75,7 +75,7 @@ function test_continuum_elasticity_with_surface_load()
|
||||
end
|
||||
element1 = Hex8([1, 2, 3, 4, 5, 6, 7, 8])
|
||||
set_geometry!(element1, nodes)
|
||||
element1["youngs modulus"] = 9000.0
|
||||
element1["youngs modulus"] = 900.0
|
||||
element1["poissons ratio"] = 0.25
|
||||
|
||||
element2 = Quad4([5, 6, 7, 8])
|
||||
@@ -100,13 +100,13 @@ function test_continuum_elasticity_with_surface_load()
|
||||
free_dofs = find(vec(free_dofs'))
|
||||
info("free dofs: $free_dofs")
|
||||
|
||||
info("initial force vector")
|
||||
ass = assemble(problem, 0.0)
|
||||
f = full(ass.force_vector)
|
||||
K = full(ass.stiffness_matrix)
|
||||
dump(reshape(f, 3, 8))
|
||||
info("initial stiffness matrix")
|
||||
dump(round(Int, K)[free_dofs, free_dofs])
|
||||
# info("initial force vector")
|
||||
# dump(reshape(f, 3, 8))
|
||||
# info("initial stiffness matrix")
|
||||
# dump(round(Int, K)[free_dofs, free_dofs])
|
||||
|
||||
u = zeros(3, 8)
|
||||
u[free_dofs] = K[free_dofs, free_dofs] \ f[free_dofs]
|
||||
|
||||
@@ -7,7 +7,7 @@ using JuliaFEM.Test
|
||||
|
||||
using JuliaFEM.Core: AbstractProblem, Problem
|
||||
using JuliaFEM.Core: Element, Seg2, Quad4
|
||||
using JuliaFEM.Core: IntegrationPoint, solve!
|
||||
using JuliaFEM.Core: IntegrationPoint, solve!, get_jacobian
|
||||
|
||||
import JuliaFEM.Core: get_unknown_field_name, get_unknown_field_type, get_potential_energy
|
||||
|
||||
@@ -34,7 +34,9 @@ function get_potential_energy(problem::Problem{HeatProblem}, element::Element{Qu
|
||||
gradT = element("temperature", ip, time, Val{:grad}, variation)
|
||||
Wint = (k + c*T) * 1/2*vecdot(gradT, gradT)
|
||||
Wext = f*T
|
||||
return Wint - Wext
|
||||
W = Wint - Wext
|
||||
J = get_jacobian(element, ip, time)
|
||||
return W*det(J)
|
||||
end
|
||||
|
||||
function get_potential_energy(problem::Problem{HeatProblem}, element::Element{Seg2}, ip::IntegrationPoint, time::Number; variation=nothing)
|
||||
@@ -45,7 +47,8 @@ function get_potential_energy(problem::Problem{HeatProblem}, element::Element{Se
|
||||
Wint = 0.0
|
||||
Wext = q0*T
|
||||
W = Wint - Wext
|
||||
return W
|
||||
J = get_jacobian(element, ip, time)
|
||||
return W*norm(J)
|
||||
end
|
||||
|
||||
function test_potential_energy_method()
|
||||
|
||||
+3
-2
@@ -51,7 +51,7 @@ function test_linearsolver()
|
||||
info("Temperature at point X = $X is T = $T")
|
||||
@test isapprox(T, 100.0)
|
||||
end
|
||||
#test_basic()
|
||||
#test_linearsolver()
|
||||
|
||||
function test_solvers()
|
||||
K = [
|
||||
@@ -88,7 +88,8 @@ function test_solvers()
|
||||
@test isapprox(u1, expected)
|
||||
u2, la2 = solve(K, f, C, g, Val{:CHOLMOD})
|
||||
@test isapprox(u2, expected)
|
||||
include(Pkg.dir("JuliaFEM"*"/src/petsc.jl"))
|
||||
# FIXME: how to dynamically include packages only if they are installed?
|
||||
#include(Pkg.dir("JuliaFEM"*"/src/petsc.jl"))
|
||||
u3, la3 = solve(K, f, C, g, Val{:PETSc_GMRES})
|
||||
@test isapprox(u3, expected)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user