Files
JuliaFEM.jl/src/elements.jl
T

195 lines
6.5 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-08-31 20:15:28 +03:00
using FactCheck
2015-09-10 02:20:34 +03:00
using ForwardDiff
2015-08-31 20:15:28 +03:00
2015-08-25 00:21:05 +03:00
abstract Element
2015-08-24 01:14:03 +03:00
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
2015-10-20 15:54:47 +03:00
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
2015-11-11 00:52:16 +02:00
element["field1"] = Field(collect(1:n))
2015-10-27 06:37:58 +02:00
# TODO: how to parametrize this?
2015-11-11 00:52:16 +02:00
element["geometry"] = Field(Vector[[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-10-27 06:37:58 +02:00
basis = get_basis(element)
dbasis = grad(basis)
2015-09-28 13:22:12 +03:00
mid = zeros(dim)
2015-10-27 06:37:58 +02:00
val1 = basis(mid, 0.0)
2015-11-01 18:44:50 +02:00
info("basis at $mid: $val1")
2015-10-27 06:37:58 +02:00
val2 = basis("field1", mid, 0.0)
2015-11-01 18:44:50 +02:00
info("field val at $mid: $val2")
2015-10-27 06:37:58 +02:00
val3 = dbasis(mid, 0.0)
2015-11-11 00:52:16 +02:00
info("derivative of basis at $mid:\n$val3")
2015-10-27 06:37:58 +02:00
val4 = dbasis("field1", mid, 0.0)
2015-11-01 18:44:50 +02:00
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-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
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
2015-11-21 18:23:41 +02:00
#function Base.setindex!(element::Element, field_data::Tuple, field_name)
# field = Field()
# for (time, data) in field_data
# ts = TimeStep(time, Increment[Increment(data)])
# push!(field, ts)
# end
# element[field_name] = field
#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
2015-10-28 04:29:14 +02:00
abstract AbstractFunctionSpace
type FunctionSpace <: AbstractFunctionSpace
2015-11-21 18:23:41 +02:00
basis :: CVTI
2015-11-11 00:52:16 +02:00
fields :: FieldSet
2015-10-28 04:29:14 +02:00
end
type GradientFunctionSpace <: AbstractFunctionSpace
2015-11-21 18:23:41 +02:00
basis :: CVTI
2015-11-11 00:52:16 +02:00
fields :: FieldSet
end
2015-09-28 13:22:12 +03:00
2015-10-28 04:29:14 +02:00
function get_basis(element::Element)
2015-11-11 00:52:16 +02:00
return FunctionSpace(element.basis, element.fields)
end
2015-09-29 00:07:56 +03:00
2015-10-28 04:29:14 +02:00
function get_dbasis(element::Element)
2015-11-11 00:52:16 +02:00
return GradientFunctionSpace(element.basis, element.fields)
2015-09-29 00:07:56 +03:00
end
function grad(u::FunctionSpace)
2015-11-11 00:52:16 +02:00
return GradientFunctionSpace(u.basis, u.fields)
2015-10-21 07:24:19 +03:00
end
2015-09-29 00:07:56 +03:00
2015-11-11 00:52:16 +02:00
""" If basis is called without a field, return basis functions evaluated at that point. """
function call(u::FunctionSpace, xi::Union{Vector, IntegrationPoint}, t::Number=0.0)
return u.basis(xi)
2015-09-29 00:07:56 +03:00
end
2015-11-11 00:52:16 +02:00
""" If gradient of basis is called without a field, return "empty" gradient evaluated at that point. """
function call(gradu::GradientFunctionSpace, xi::Union{Vector, IntegrationPoint}, t::Number=0.0)
geometry = gradu.fields["geometry"](t)
gradu.basis(geometry, xi, Val{:grad})
2015-10-21 07:24:19 +03:00
end
2015-09-29 00:07:56 +03:00
2015-11-11 00:52:16 +02:00
""" Evaluate field on element function space. """
function call(u::FunctionSpace, field_name, xi::Union{Vector, IntegrationPoint}, t::Number=0.0, variation=nothing)
field = !isa(variation, Void) ? variation : u.fields[field_name](t)
u.basis(field, xi)
2015-10-23 01:11:45 +03:00
end
2015-11-11 00:52:16 +02:00
""" Evaluate gradient of field on element function space. """
function call(gradu::GradientFunctionSpace, field_name, xi::Union{Vector, IntegrationPoint}, t::Number=0.0, variation=nothing)
field = !isa(variation, Void) ? variation : gradu.fields[field_name](t)
geometry = gradu.fields["geometry"](t)
gradu.basis(geometry, field, xi, Val{:grad})
end
2015-09-10 02:20:34 +03:00
2015-11-11 00:52:16 +02:00
# on-line functions to get api more easy to use, ip -> xi.ip
2015-11-11 00:52:16 +02:00
#call(u::FunctionSpace, ip::IntegrationPoint, t::Number=Inf) = call(u, ip.xi, t)
#call(u::GradientFunctionSpace, ip::IntegrationPoint, t::Number=Inf) = call(u, ip.xi, t)
2015-10-27 06:37:58 +02:00
# i think these will be the most called functions.
2015-11-11 00:52:16 +02:00
#call(u::FunctionSpace, field_name, ip::IntegrationPoint, t::Number=0.0, variation=nothing) = call(u, field_name, ip.xi, t, variation)
#call(u::GradientFunctionSpace, field_name, ip::IntegrationPoint, t::Number=0.0, variation=nothing) = call(u, field_name, ip.xi, t, variation)
#call(u::FunctionSpace, field_name) = (args...) -> call(u, field_name, args...)
#call(u::GradientFunctionSpace, field_name) = (args...) -> call(u, field_name, args...)
2015-09-14 23:20:33 +03:00
2015-10-27 06:37:58 +02:00
""" Return a field from function space. """
2015-11-11 00:52:16 +02:00
function get_field(u::FunctionSpace, field_name, time::Number=0.0)
return u.fields[field_name](time)
end
2015-10-27 06:37:58 +02:00
""" Return a field from function space. """
2015-11-11 00:52:16 +02:00
function get_field(u::FunctionSpace, field_name, time::Number=0.0, variation=nothing)
return !isa(variation, Void) ? variation : u.fields[field_name](time)
2015-08-24 01:14:03 +03:00
end
2015-11-11 00:52:16 +02:00
""" Return a field from function space. """
function get_fieldset(u::FunctionSpace, field_name)
2015-11-11 00:52:16 +02:00
return u.fields[field_name]
2015-08-24 01:14:03 +03:00
end
2015-10-28 04:29:14 +02:00
""" Get a determinant of element in point ξ. """
2015-11-11 00:52:16 +02:00
function LinAlg.det(u::FunctionSpace, xi::Vector, time::Number=0.0)
X = u.fields["geometry"](time)
2015-11-21 18:23:41 +02:00
dN = u.basis(xi, Val{:grad})
2015-10-27 06:37:58 +02:00
J = sum([dN[:,i]*X[i]' for i=1:length(X)])
m, n = size(J)
return m == n ? det(J) : norm(J)
end
2015-11-11 00:52:16 +02:00
function LinAlg.det(u::FunctionSpace, ip::IntegrationPoint, time::Number=0.0)
LinAlg.det(u, ip.xi, time)
end
function LinAlg.det(u::FunctionSpace)
2015-10-27 06:37:58 +02:00
return (args...) -> det(u, args...)
end
2015-11-11 00:52:16 +02:00
#Base.(:+)(u::FunctionSpace, v::FunctionSpace) = (args...) -> u(args...) + v(args...)
#Base.(:-)(u::FunctionSpace, v::FunctionSpace) = (args...) -> u(args...) - v(args...)
#Base.(:+)(u::GradientFunctionSpace, v::GradientFunctionSpace) = (args...) -> u(args...) + v(args...)
#Base.(:-)(u::GradientFunctionSpace, v::GradientFunctionSpace) = (args...) -> u(args...) - v(args...)
2015-09-29 00:07:56 +03:00
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