Files
JuliaFEM.jl/src/elements.jl
T

258 lines
7.8 KiB
Julia
Raw Normal View History

2015-08-24 01:14:03 +03:00
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
2015-11-27 10:10:00 +02:00
abstract AbstractElement
2015-08-31 20:15:28 +03:00
2015-11-27 10:10:00 +02:00
type Element{E<:AbstractElement}
connectivity :: Vector{Int}
fields :: Dict{ASCIIString, Field}
end
function convert{E}(::Type{Element{E}}, connectivity::Vector{Int})
# return Element{E}(connectivity, get_integration_points(E), Dict())
return Element{E}(connectivity, Dict())
end
2015-12-05 10:58:01 +02:00
function get_integration_points{E}(element::Element{E}, args...)
return get_integration_points(E, args...)
2015-11-27 10:10:00 +02:00
end
2015-08-24 01:14:03 +03:00
function update_gauss_fields!(element::Element, data::Vector{IntegrationPoint}, time::Real)
if haskey(element, "integration points")
# push or update
if !isapprox(last(element["integration points"]).time, time)
push!(element["integration points"], time => data)
else
last(element["integration points"]).data = data
end
else
# create
element["integration points"] = Field(time => data)
end
end
2015-09-10 02:20:34 +03:00
"""
2015-09-14 23:20:33 +03:00
Test routine for element. If this passes, element interface is properly
defined.
2015-09-10 02:20:34 +03:00
Parameters
----------
eltype::Type{Element}
Element to test
2015-08-31 20:15:28 +03:00
2015-09-10 02:20:34 +03:00
Raises
------
2015-09-14 23:20:33 +03:00
This uses FactCheck and throws exceptions if element is not passing all tests.
2015-09-10 02:20:34 +03:00
"""
2015-10-20 15:54:47 +03:00
function test_element(element_type)
2015-11-01 18:44:50 +02:00
info("Testing element $element_type")
2015-10-20 15:54:47 +03:00
local element
2015-10-27 06:37:58 +02:00
dim = nothing
n = nothing
try
dim, n = size(element_type)
catch
2015-11-01 18:44:50 +02:00
error("Unable to determine element dimensions. Define Base.size(element::Type{$elementtype}) = (dim, nbasis) where dim is spatial dimension of element and nbasis is number of basis functions of element.")
2015-10-27 06:37:58 +02:00
end
2015-11-01 18:44:50 +02:00
info("element dimension: $dim x $n")
2015-11-01 18:44:50 +02:00
info("Initializing element")
2015-08-31 20:15:28 +03:00
try
element = Element{element_type}(collect(1:n))
2015-08-31 20:15:28 +03:00
catch
2015-11-01 18:44:50 +02:00
error("""
Unable to create element with default constructor define function
$eltype(connectivity) which initializes this element.""")
2015-09-10 02:20:34 +03:00
return false
2015-08-31 20:15:28 +03:00
end
2015-08-31 20:15:28 +03:00
# try to interpolate some scalar field
element["field1"] = range(1, n)
2015-10-27 06:37:58 +02:00
# TODO: how to parametrize this?
element["geometry"] = Vector{Float64}[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
2015-10-20 15:54:47 +03:00
# evaluate basis functions at middle point of element
2015-09-28 13:22:12 +03:00
mid = zeros(dim)
val1 = element(mid, 0.0)
2015-11-01 18:44:50 +02:00
info("basis at $mid: $val1")
val2 = element("field1", mid, 0.0)
2015-11-01 18:44:50 +02:00
info("field val at $mid: $val2")
val3 = element(mid, 0.0, Val{:grad})
2015-11-11 00:52:16 +02:00
info("derivative of basis at $mid:\n$val3")
#val4 = element("field1", mid, Val{:grad})
#info("field val at $mid: $val4")
2015-08-31 20:15:28 +03:00
2015-11-01 18:44:50 +02:00
info("Element $element_type passed tests.")
2015-08-31 20:15:28 +03:00
end
2015-10-28 04:29:14 +02:00
""" Get FieldSet from element. """
function Base.getindex(element::Element, field_name)
2015-11-11 00:52:16 +02:00
return element.fields[field_name]
2015-10-28 04:29:14 +02:00
end
2015-11-27 10:10:00 +02:00
function Base.length{E}(element::Element{E})
size(E)[2]
end
2015-11-11 00:52:16 +02:00
"""Add new Field to element.
2015-10-28 04:29:14 +02:00
Examples
--------
2015-11-11 00:52:16 +02:00
>>> element["temperature"] = [1, 2, 3, 4]
>>> element["temperature"] = (0.0, [0, 0, 0, 0]), (1.0, [1, 2, 3, 4])
>>> element["temperature"] = (0.0 => [0, 0, 0, 0], 1.0 => [1, 2, 3, 4])
2015-10-28 04:29:14 +02:00
"""
2015-11-21 18:23:41 +02:00
function Base.setindex!(element::Element, data, name::ASCIIString)
element.fields[name] = Field(data)
2015-10-28 04:29:14 +02:00
end
function Base.setindex!(element::Element, field::Field, name::ASCIIString)
element.fields[name] = field
end
2015-11-21 18:23:41 +02:00
function Base.setindex!(element::Element, data::Tuple, name::ASCIIString)
element.fields[name] = Field(data...)
2015-11-11 00:52:16 +02:00
end
function get_connectivity(el::Element)
2015-11-11 00:52:16 +02:00
return el.connectivity
end
2015-09-14 23:20:33 +03:00
typealias VecOrIP Union{Vector, IntegrationPoint}
2015-12-04 07:27:40 +02:00
function call(element::Element, field_name::ASCIIString, time::Real, variation=nothing)
return isa(variation, Void) ? element[field_name](time) : variation
end
2015-11-27 10:10:00 +02:00
function call(element::Element, field_name::ASCIIString, xi::VecOrIP, time::Number, variation=nothing)
2015-12-04 07:27:40 +02:00
field = element(field_name, time, variation)
# field = isa(variation, Void) ? element[field_name](time) : variation
2015-11-27 10:10:00 +02:00
basis = get_basis(element)
return basis(field, xi)
end
2015-11-27 10:10:00 +02:00
function call(element::Element, field_name::ASCIIString, xi::VecOrIP, time::Number, ::Type{Val{:grad}}, variation=nothing)
2015-12-04 07:27:40 +02:00
# field = isa(variation, Void) ? element[field_name](time) : variation
field = element(field_name, time, variation)
2015-11-27 10:10:00 +02:00
basis = get_basis(element)
geom = element["geometry"](time)
return basis(geom, field, xi, Val{:grad})
end
2015-11-27 10:10:00 +02:00
function call(element::Element, field_name::ASCIIString, xi::VecOrIP)
field = element[field_name]
basis = get_basis(element)
return basis(element[field_name], xi)
end
2015-11-27 10:10:00 +02:00
function call(element::Element, field_name::ASCIIString, xi::VecOrIP, ::Type{Val{:grad}})
field = element[field_name]
geom = element["geometry"]
basis = get_basis(element)
return basis(geom, field, xi, Val{:grad})
end
2015-11-27 10:10:00 +02:00
function call(element::Element, field_name::ASCIIString, time::Number)
return element[field_name](time)
end
2015-11-30 18:49:45 +02:00
function get_dbasis{E<:AbstractElement}(::Type{E}, xi::Vector)
basis(xi) = vec(get_basis(E, xi))
return ForwardDiff.jacobian(basis, xi, cache=autodiffcache)'
end
2015-11-27 10:10:00 +02:00
function get_basis{E}(element::Element{E}, ip::IntegrationPoint)
return get_basis(E, ip.xi)
end
function get_basis{E}(::Type{Element{E}}, xi::Vector{Float64})
return get_basis(E, xi)
end
2015-11-27 15:06:55 +02:00
function get_basis{E}(element::Element{E}, xi::Vector{Float64})
return get_basis(E, xi)
end
function call{E}(element::Element{E}, xi::VecOrIP, time::Float64=0.0)
2015-11-27 10:10:00 +02:00
return get_basis(element, xi)
end
2015-11-11 00:52:16 +02:00
2015-11-27 10:10:00 +02:00
function get_basis{E}(element::Element{E})
basis = CVTI(
(xi::Vector) -> get_basis(E, xi),
(xi::Vector) -> get_dbasis(E, xi))
return basis
end
function call{E}(element::Element{E}, xi::VecOrIP, ::Type{Val{:grad}})
basis = get_basis(element)
geom = element["geometry"]
return basis(geom, xi, Val{:grad})
end
2015-11-27 10:10:00 +02:00
function call{E}(element::Element{E}, xi::VecOrIP, time::Float64, ::Type{Val{:grad}})
basis = get_basis(element)
return basis(element["geometry"](time), xi, Val{:grad})
2015-08-24 01:14:03 +03:00
end
2015-11-27 10:10:00 +02:00
function call(element::Element, field_name::ASCIIString)
return element[field_name]
2015-08-24 01:14:03 +03:00
end
""" Return the jacobian of element. """
function get_jacobian{E}(element::Element{E}, xi::Vector{Float64}, time::Real)
2015-11-27 10:10:00 +02:00
X = element("geometry", time)
dN = get_dbasis(E, xi)
2015-12-04 07:27:40 +02:00
J = sum([kron(dN[:,i], X[i]') for i=1:length(X)])
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
2015-11-11 00:52:16 +02:00
""" Check does field exist. """
function Base.haskey(element::Element, what)
2015-10-27 06:37:58 +02:00
haskey(element.fields, what)
end
2015-09-14 23:20:33 +03:00
2015-12-12 10:08:20 +02:00
""" Calculate local normal-tangential coordinates for element. """
function calculate_normal_tangential_coordinates!{E}(element::Element{E}, time::Real)
proj(u, v) = dot(v, u) / dot(u, u) * u
ntcoords = Matrix[]
refcoords = get_reference_element_coordinates(E)
x = element("geometry", time)
for xi in refcoords
dN = get_dbasis(E, xi)*x
normal = cross(dN[:,1], dN[:,2])
normal /= norm(normal)
u1 = normal
j = indmax(abs(u1))
v2 = zeros(3)
v2[mod(j,3)+1] = 1.0
u2 = v2 - proj(u1, v2)
u3 = cross(u1, u2)
tangent1 = u2/norm(u2)
tangent2 = u3/norm(u3)
push!(ntcoords, [normal tangent1 tangent2])
end
element["normal-tangential coordinates"] = ntcoords
end