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
|
|
|
|
|
2016-05-20 04:39:51 +03:00
|
|
|
|
type Element{E<:AbstractElement}
|
2016-05-25 02:44:29 +03:00
|
|
|
|
id :: Int
|
2016-05-20 04:39:51 +03:00
|
|
|
|
connectivity :: Vector{Int}
|
2016-05-25 22:33:47 +03:00
|
|
|
|
integration_points :: Vector{IP}
|
2016-05-20 04:39:51 +03:00
|
|
|
|
fields :: Dict{ASCIIString, Field}
|
|
|
|
|
|
properties :: E
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-27 17:45:12 +03:00
|
|
|
|
function Element{E<:AbstractElement}(::Type{E}, connectivity=[], integration_points=[], id=-1, fields=Dict(), properties...)
|
2016-05-25 22:33:47 +03:00
|
|
|
|
variant = E(properties...)
|
2016-05-27 17:45:12 +03:00
|
|
|
|
element = Element{E}(id, connectivity, integration_points, fields, variant)
|
|
|
|
|
|
return element
|
2016-05-20 04:39:51 +03:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function getindex(element::Element, field_name::ASCIIString)
|
|
|
|
|
|
element.fields[field_name]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function setindex!(element::Element, data, field_name::ASCIIString)
|
|
|
|
|
|
element.fields[field_name] = Field(data)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-27 17:45:12 +03:00
|
|
|
|
function call(element::Element, field_name::ASCIIString, time)
|
2016-05-24 19:05:25 +03:00
|
|
|
|
return element[field_name](time)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-27 17:45:12 +03:00
|
|
|
|
function call(element::Element, ip, time)
|
2016-05-25 22:33:47 +03:00
|
|
|
|
get_basis(element, ip, time)
|
2016-05-20 04:39:51 +03:00
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-25 22:33:47 +03:00
|
|
|
|
function call(element::Element, ip, time, ::Type{Val{:Jacobian}})
|
2016-05-20 04:39:51 +03:00
|
|
|
|
X = element["geometry"](time)
|
2016-05-25 22:33:47 +03:00
|
|
|
|
dN = get_dbasis(element, ip, time)
|
2016-05-20 04:39:51 +03:00
|
|
|
|
J = sum([kron(dN[:,i], X[i]') for i=1:length(X)])
|
|
|
|
|
|
return J
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-25 22:33:47 +03:00
|
|
|
|
function call(element::Element, ip, time, ::Type{Val{:detJ}})
|
|
|
|
|
|
J = element(ip, time, Val{:Jacobian})
|
2016-05-22 17:00:01 +03:00
|
|
|
|
n, m = size(J)
|
|
|
|
|
|
if n == m # volume element
|
|
|
|
|
|
return det(J)
|
|
|
|
|
|
end
|
|
|
|
|
|
JT = transpose(J)
|
|
|
|
|
|
if size(JT, 2) == 1 # boundary of 2d problem, || ∂X/∂ξ ||
|
|
|
|
|
|
return norm(JT)
|
|
|
|
|
|
else # manifold on 3d problem, || ∂X/∂ξ₁ × ∂X/∂ξ₂ ||
|
|
|
|
|
|
return norm(cross(JT[:,1], JT[:,2]))
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-25 22:33:47 +03:00
|
|
|
|
function call(element::Element, ip, time, ::Type{Val{:Grad}})
|
|
|
|
|
|
J = element(ip, time, Val{:Jacobian})
|
|
|
|
|
|
return inv(J)*get_dbasis(element, ip, time)
|
2016-05-20 04:39:51 +03:00
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-25 22:33:47 +03:00
|
|
|
|
function call(element::Element, field_name::ASCIIString, ip, time, ::Type{Val{:Grad}})
|
|
|
|
|
|
element(ip, time, Val{:Grad})*element[field_name](time)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-27 17:45:12 +03:00
|
|
|
|
function call(element::Element, field_name::ASCIIString, time)
|
|
|
|
|
|
return element[field_name](time)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function call(element::Element, field_name::ASCIIString, ip, time)
|
|
|
|
|
|
field = element(field_name, time)
|
2016-05-25 22:33:47 +03:00
|
|
|
|
isa(field, DCTI) && return field.data
|
|
|
|
|
|
basis = element(ip, time)
|
|
|
|
|
|
n = length(element)
|
|
|
|
|
|
m = length(field)
|
|
|
|
|
|
@assert n == m
|
|
|
|
|
|
return sum([field[i]*basis[i] for i=1:n])
|
2016-05-20 04:39:51 +03:00
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-25 02:44:29 +03:00
|
|
|
|
#function get_jacobian{E}(element::Element{E}, xi::Vector, time=0.0)
|
|
|
|
|
|
# element(xi, time, Val{:Jacobian})
|
|
|
|
|
|
#end
|
2016-05-24 08:35:37 +03:00
|
|
|
|
#function get_basis(element::Element, xi::Vector, time=0.0)
|
|
|
|
|
|
# get_basis(element.properties, xi, time)
|
|
|
|
|
|
#end
|
|
|
|
|
|
#function get_dbasis(element::Element, xi::Vector, time=0.0)
|
|
|
|
|
|
# get_dbasis(element.properties, xi, time)
|
|
|
|
|
|
#end
|
|
|
|
|
|
#function get_integration_points{E}(element::Element{E})
|
|
|
|
|
|
# get_integration_points(element.properties)
|
|
|
|
|
|
#end
|
|
|
|
|
|
#function length{E}(element::Element{E})
|
|
|
|
|
|
# length(element.properties)
|
|
|
|
|
|
#end
|
|
|
|
|
|
#function size{E}(element::Element{E})
|
|
|
|
|
|
# size(element.properties)
|
|
|
|
|
|
#end
|
2016-05-20 04:39:51 +03:00
|
|
|
|
|
2016-05-22 02:34:38 +03:00
|
|
|
|
function size(element::Element, dim::Int)
|
|
|
|
|
|
size(element)[dim]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-20 04:39:51 +03:00
|
|
|
|
""" Update element field based on a dictionary of nodal data and connectivity information.
|
|
|
|
|
|
|
|
|
|
|
|
Examples
|
|
|
|
|
|
--------
|
|
|
|
|
|
julia> data = Dict(1 => [0.0, 0.0], 2 => [1.0, 2.0])
|
|
|
|
|
|
julia> element = Seg2([1, 2])
|
|
|
|
|
|
julia> update!(element, "geometry", data)
|
|
|
|
|
|
|
|
|
|
|
|
As a result element now have time invariant (variable) vector field "geometry" with data ([0.0, 0.0], [1.0, 2.0]).
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
function update!(element::Element, field_name::ASCIIString, data::Dict)
|
|
|
|
|
|
element[field_name] = [data[i] for i in get_connectivity(element)]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-22 02:34:38 +03:00
|
|
|
|
function update!(element::Element, field_name::ASCIIString, data::Union{Real, Vector, Pair})
|
2016-05-20 04:39:51 +03:00
|
|
|
|
element[field_name] = data
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-22 02:34:38 +03:00
|
|
|
|
function update!(elements::Vector, field_name::ASCIIString, data)
|
|
|
|
|
|
for element in elements
|
|
|
|
|
|
update!(element, field_name, data)
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-22 00:22:17 +03:00
|
|
|
|
""" Evaluate partial derivatives of basis functions using ForwardDiff. """
|
2016-05-30 18:30:02 +03:00
|
|
|
|
function get_dbasis(element::Element, ip, time)
|
|
|
|
|
|
xi = isa(ip, IP) ? ip.coords : ip
|
2016-05-22 00:22:17 +03:00
|
|
|
|
basis(xi) = vec(get_basis(element, xi, time))
|
|
|
|
|
|
return ForwardDiff.jacobian(basis, xi, cache=autodiffcache)'
|
|
|
|
|
|
end
|
2016-05-20 04:39:51 +03:00
|
|
|
|
|
2016-05-22 00:22:17 +03:00
|
|
|
|
""" Check existence of field. """
|
|
|
|
|
|
function haskey(element::Element, field_name)
|
|
|
|
|
|
haskey(element.fields, field_name)
|
|
|
|
|
|
end
|
2016-05-20 04:39:51 +03:00
|
|
|
|
|
2016-05-22 02:34:38 +03:00
|
|
|
|
function get_connectivity(element::Element)
|
|
|
|
|
|
return element.connectivity
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-25 22:33:47 +03:00
|
|
|
|
function get_integration_points(element::Element)
|
2016-05-27 17:45:12 +03:00
|
|
|
|
# first time initialize default integration points
|
|
|
|
|
|
if length(element.integration_points) == 0
|
|
|
|
|
|
ips = get_integration_points(element.properties)
|
|
|
|
|
|
element.integration_points = [IP(i, w, xi) for (i, (w, xi)) in enumerate(ips)]
|
|
|
|
|
|
end
|
2016-05-25 22:33:47 +03:00
|
|
|
|
return element.integration_points
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
""" This is a special case, temporarily change order
|
|
|
|
|
|
of integration scheme mainly for mass matrix.
|
|
|
|
|
|
"""
|
|
|
|
|
|
function get_integration_points(element::Element, change_order::Int)
|
|
|
|
|
|
order = get_integration_order(element.properties)
|
|
|
|
|
|
order += change_order
|
|
|
|
|
|
ips = get_integration_points(element.properties, Val{order})
|
|
|
|
|
|
return [IP(i, w, xi) for (i, (w, xi)) in enumerate(ips)]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-22 02:34:38 +03:00
|
|
|
|
function get_gdofs(element::Element)
|
|
|
|
|
|
return get_gdofs(element, 1)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
""" Return dual basis transformation matrix Ae. """
|
|
|
|
|
|
function get_dualbasis(element::Element, time)
|
|
|
|
|
|
nnodes = length(element)
|
|
|
|
|
|
De = zeros(nnodes, nnodes)
|
|
|
|
|
|
Me = zeros(nnodes, nnodes)
|
2016-05-25 22:33:47 +03:00
|
|
|
|
for ip in get_integration_points(element)
|
|
|
|
|
|
detJ = element(ip, time, Val{:detJ})
|
|
|
|
|
|
w = ip.weight*detJ
|
|
|
|
|
|
N = element(ip, time)
|
|
|
|
|
|
De += w*diagm(vec(N))
|
|
|
|
|
|
Me += w*N'*N
|
2016-05-22 02:34:38 +03:00
|
|
|
|
end
|
|
|
|
|
|
return De, Me, De*inv(Me)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-05-20 04:39:51 +03:00
|
|
|
|
#=
|
|
|
|
|
|
|
2015-12-31 12:35:05 +02:00
|
|
|
|
type Element{E}
|
2015-11-27 10:10:00 +02:00
|
|
|
|
connectivity :: Vector{Int}
|
|
|
|
|
|
fields :: Dict{ASCIIString, Field}
|
2016-02-05 11:32:09 +02:00
|
|
|
|
# matrices to construct dual basis
|
|
|
|
|
|
D :: Matrix{Float64}
|
|
|
|
|
|
M :: Matrix{Float64}
|
|
|
|
|
|
A :: Matrix{Float64}
|
2015-11-27 10:10:00 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
2015-12-14 02:09:33 +02:00
|
|
|
|
function Base.size{E}(::Element{E})
|
|
|
|
|
|
return size(E)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2015-12-23 17:39:53 +02:00
|
|
|
|
function Base.size{E}(::Element{E}, i::Int64)
|
|
|
|
|
|
return size(E)[i]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2015-11-27 10:10:00 +02:00
|
|
|
|
function convert{E}(::Type{Element{E}}, connectivity::Vector{Int})
|
2016-02-05 11:32:09 +02:00
|
|
|
|
return Element{E}(connectivity, Dict(), Matrix(), Matrix(), Matrix())
|
2015-11-27 10:10:00 +02:00
|
|
|
|
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
|
|
|
|
|
2015-11-30 16:04:13 +02: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-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-23 03:17:15 +02:00
|
|
|
|
|
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-23 03:17:15 +02:00
|
|
|
|
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
|
|
|
|
|
|
|
2015-09-14 23:20:33 +03:00
|
|
|
|
|
2015-11-23 03:17:15 +02: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)
|
2015-11-23 03:17:15 +02:00
|
|
|
|
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})
|
2015-11-23 03:17:15 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
2015-11-27 10:10:00 +02:00
|
|
|
|
function call(element::Element, field_name::ASCIIString, xi::VecOrIP)
|
2015-11-30 16:04:13 +02:00
|
|
|
|
field = element[field_name]
|
|
|
|
|
|
basis = get_basis(element)
|
|
|
|
|
|
return basis(element[field_name], xi)
|
2015-11-23 03:17:15 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
2015-11-27 10:10:00 +02:00
|
|
|
|
function call(element::Element, field_name::ASCIIString, xi::VecOrIP, ::Type{Val{:grad}})
|
2015-11-30 16:04:13 +02:00
|
|
|
|
field = element[field_name]
|
|
|
|
|
|
geom = element["geometry"]
|
|
|
|
|
|
basis = get_basis(element)
|
|
|
|
|
|
return basis(geom, field, xi, Val{:grad})
|
2015-11-23 03:17:15 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
2015-11-27 10:10:00 +02:00
|
|
|
|
function call(element::Element, field_name::ASCIIString, time::Number)
|
2015-11-23 03:17:15 +02:00
|
|
|
|
return element[field_name](time)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2015-11-30 18:49:45 +02:00
|
|
|
|
|
2015-11-27 10:10:00 +02:00
|
|
|
|
function get_basis{E}(element::Element{E}, ip::IntegrationPoint)
|
|
|
|
|
|
return get_basis(E, ip.xi)
|
2015-11-23 03:17:15 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
2015-11-30 16:04:13 +02:00
|
|
|
|
function get_basis{E}(::Type{Element{E}}, xi::Vector{Float64})
|
|
|
|
|
|
return get_basis(E, xi)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-02-25 10:44:55 +02:00
|
|
|
|
function get_basis{E}(element::Element{E}, xi::Vector)
|
2015-11-27 15:06:55 +02:00
|
|
|
|
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)
|
2015-11-23 03:17:15 +02:00
|
|
|
|
end
|
2015-11-11 00:52:16 +02:00
|
|
|
|
|
2016-02-23 11:32:53 +02:00
|
|
|
|
""" Given a list of elementa and nodes, find a subset of elements
|
|
|
|
|
|
containing nodes.
|
|
|
|
|
|
"""
|
|
|
|
|
|
function find_elements(elements, nodes)
|
|
|
|
|
|
s = Set{Element}()
|
|
|
|
|
|
for element in elements
|
|
|
|
|
|
conn = get_connectivity(element)
|
|
|
|
|
|
for j in nodes
|
|
|
|
|
|
if j in conn
|
|
|
|
|
|
push!(s, element)
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
return collect(s)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function get_dbasis{E}(element::Element{E}, ip::IntegrationPoint)
|
|
|
|
|
|
return get_dbasis(E, ip.xi)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function get_basis{E, T<:Real}(element::Element{E}, xi::T)
|
|
|
|
|
|
return get_basis(E, xi)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-02-05 11:32:09 +02:00
|
|
|
|
|
|
|
|
|
|
function call(element::Element, xi::VecOrIP, time::Real, ::Type{Val{:dualbasis}})
|
|
|
|
|
|
De, Me, Ae = get_dualbasis(element, time)
|
2016-02-03 20:39:03 +02:00
|
|
|
|
N = get_basis(element, xi)
|
2016-02-05 11:32:09 +02:00
|
|
|
|
Phi = Ae*N'
|
2016-02-03 20:39:03 +02:00
|
|
|
|
return Phi'
|
|
|
|
|
|
end
|
|
|
|
|
|
|
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
|
2015-10-26 05:40:41 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
2015-11-30 16:04:13 +02:00
|
|
|
|
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)
|
2015-11-30 16:04:13 +02:00
|
|
|
|
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
|
|
|
|
|
|
|
2015-12-13 13:47:45 +02:00
|
|
|
|
|
|
|
|
|
|
""" 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)
|
2015-12-13 13:47:45 +02:00
|
|
|
|
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)])
|
2015-12-13 13:47:45 +02:00
|
|
|
|
return J
|
|
|
|
|
|
end
|
|
|
|
|
|
function get_jacobian{E}(element::Element{E}, ip::IntegrationPoint, time::Real)
|
|
|
|
|
|
return get_jacobian(element, ip.xi, time)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-02-13 01:12:24 +02:00
|
|
|
|
""" Return Jacobian of element in deformed state. """
|
|
|
|
|
|
function get_jacobian{E}(element::Element{E}, xi::Vector{Float64}, time::Real, ::Type{Val{:deformed}})
|
|
|
|
|
|
x = element("geometry", time)
|
|
|
|
|
|
if haskey(element, "displacement")
|
|
|
|
|
|
x += element("displacement", time)
|
2015-12-14 02:09:33 +02:00
|
|
|
|
end
|
2016-02-13 01:12:24 +02:00
|
|
|
|
dN = get_dbasis(E, xi)
|
|
|
|
|
|
j = sum([kron(dN[:,i], x[i]') for i=1:length(x)])
|
|
|
|
|
|
return j
|
2015-12-13 13:47:45 +02:00
|
|
|
|
end
|
2016-02-13 01:12:24 +02:00
|
|
|
|
function get_jacobian{E}(element::Element{E}, ip::IntegrationPoint, time::Real, ::Type{Val{:deformed}})
|
|
|
|
|
|
return get_jacobian(element, ip.xi, time, Val{:deformed})
|
2015-10-26 05:40:41 +02:00
|
|
|
|
end
|
2015-11-23 03:17:15 +02:00
|
|
|
|
|
2015-12-13 13:47:45 +02:00
|
|
|
|
|
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)
|
|
|
|
|
|
ntcoords = Matrix[]
|
2016-02-03 20:39:03 +02:00
|
|
|
|
normals = Vector{Float64}[]
|
2015-12-12 10:08:20 +02:00
|
|
|
|
refcoords = get_reference_element_coordinates(E)
|
|
|
|
|
|
x = element("geometry", time)
|
|
|
|
|
|
for xi in refcoords
|
|
|
|
|
|
dN = get_dbasis(E, xi)*x
|
2015-12-20 21:17:47 +02:00
|
|
|
|
n, m = size(dN)
|
|
|
|
|
|
@assert n != m # if n == m -> this is not manifold
|
|
|
|
|
|
if m == 1 # plane case
|
|
|
|
|
|
tangent = dN / norm(dN)
|
|
|
|
|
|
normal = [-tangent[2] tangent[1]]'
|
2016-02-03 20:39:03 +02:00
|
|
|
|
push!(normals, vec(normal))
|
2015-12-20 21:17:47 +02:00
|
|
|
|
push!(ntcoords, [normal tangent])
|
|
|
|
|
|
elseif m == 2
|
|
|
|
|
|
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 - dot(u1, v2) / dot(v2, v2) * v2
|
|
|
|
|
|
u3 = cross(u1, u2)
|
|
|
|
|
|
tangent1 = u2/norm(u2)
|
|
|
|
|
|
tangent2 = u3/norm(u3)
|
|
|
|
|
|
push!(ntcoords, [normal tangent1 tangent2])
|
2016-02-03 20:39:03 +02:00
|
|
|
|
push!(normals, vec(normal))
|
2015-12-20 21:17:47 +02:00
|
|
|
|
else
|
|
|
|
|
|
error("calculate_normal_tangential_coordinates!(): n=$n, m=$m")
|
|
|
|
|
|
end
|
2015-12-12 10:08:20 +02:00
|
|
|
|
end
|
|
|
|
|
|
element["normal-tangential coordinates"] = ntcoords
|
2016-02-03 20:39:03 +02:00
|
|
|
|
element["normals"] = normals
|
2015-12-12 10:08:20 +02:00
|
|
|
|
end
|
2016-02-03 20:39:03 +02:00
|
|
|
|
|
2016-02-05 22:26:07 +02:00
|
|
|
|
""" Return list of nodes / connectivity points from a set of elements.
|
|
|
|
|
|
"""
|
|
|
|
|
|
function get_nodes(elements::Vector)
|
|
|
|
|
|
nodes = Set{Int64}()
|
|
|
|
|
|
for element in elements
|
|
|
|
|
|
push!(nodes, get_connectivity(element)...)
|
|
|
|
|
|
end
|
|
|
|
|
|
nodes = sort(collect(nodes))
|
|
|
|
|
|
return nodes
|
|
|
|
|
|
end
|
|
|
|
|
|
|
2016-02-16 17:40:11 +02:00
|
|
|
|
""" Calculate normal-tangential coordinates for a set of elements.
|
2016-02-03 20:39:03 +02:00
|
|
|
|
|
|
|
|
|
|
Notes
|
|
|
|
|
|
-----
|
|
|
|
|
|
Average normals so that normals are unique in nodes.
|
|
|
|
|
|
"""
|
2016-02-05 22:26:07 +02:00
|
|
|
|
|
2016-02-13 01:12:24 +02:00
|
|
|
|
function calculate_normal_tangential_coordinates!(elements::Vector, time::Real, configuration::Symbol=:deformed)
|
2016-02-05 22:26:07 +02:00
|
|
|
|
if size(elements[1], 1) == 1
|
2016-02-13 01:12:24 +02:00
|
|
|
|
return calculate_normal_tangential_coordinates!(elements, time, Val{2}, configuration)
|
2016-02-05 22:26:07 +02:00
|
|
|
|
else
|
2016-02-13 01:12:24 +02:00
|
|
|
|
return calculate_normal_tangential_coordinates!(elements, time, Val{3}, configuration)
|
2016-02-05 22:26:07 +02:00
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
""" Calculate normal-tangential coordinates for 2d case.
|
|
|
|
|
|
|
|
|
|
|
|
Notes
|
|
|
|
|
|
-----
|
|
|
|
|
|
n = (e₃×∂X/∂ξ) / || e₃×∂X/∂ξ || and e₃ = [0 0 1]
|
|
|
|
|
|
"""
|
2016-02-13 01:12:24 +02:00
|
|
|
|
function calculate_normal_tangential_coordinates!(elements::Vector, time::Real, ::Type{Val{2}}, configuration::Symbol)
|
2016-02-05 22:26:07 +02:00
|
|
|
|
nodes = get_nodes(elements)
|
|
|
|
|
|
n = zeros(2, maximum(nodes))
|
|
|
|
|
|
Q = [0 -1; 1 0]
|
2015-12-20 21:17:47 +02:00
|
|
|
|
for element in elements
|
2016-02-05 22:26:07 +02:00
|
|
|
|
gdofs = get_gdofs(element, 1)
|
|
|
|
|
|
for ip in get_integration_points(element, Val{3})
|
2016-02-13 01:12:24 +02:00
|
|
|
|
if configuration == :deformed
|
|
|
|
|
|
J = get_jacobian(element, ip, time, Val{:deformed})
|
|
|
|
|
|
else
|
|
|
|
|
|
J = get_jacobian(element, ip, time)
|
|
|
|
|
|
end
|
2016-02-05 22:26:07 +02:00
|
|
|
|
N = element(ip, time)
|
|
|
|
|
|
n[:, gdofs] += ip.weight*Q*J'*N
|
|
|
|
|
|
end
|
2015-12-20 21:17:47 +02:00
|
|
|
|
end
|
2016-02-03 20:39:03 +02:00
|
|
|
|
t = zeros(n)
|
2016-02-05 22:26:07 +02:00
|
|
|
|
for i=1:size(n,2)
|
|
|
|
|
|
n[:,i] = n[:,i] / norm(n[:,i])
|
|
|
|
|
|
t[:,i] = [-n[2,i], n[1,i]]
|
|
|
|
|
|
end
|
|
|
|
|
|
for element in elements
|
|
|
|
|
|
node_ids = get_connectivity(element)
|
2016-02-13 01:12:24 +02:00
|
|
|
|
Q = Matrix{Float64}[ [n[:,i] t[:,i]] for i in node_ids]
|
|
|
|
|
|
element["normal-tangential coordinates"] = (time => Q)
|
2016-02-16 17:40:11 +02:00
|
|
|
|
element["normals"] = (time => Vector{Float64}[n[:,i] for i in node_ids])
|
2016-02-05 22:26:07 +02:00
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
""" Calculate normal-tangential coordinates for 3d case.
|
|
|
|
|
|
"""
|
|
|
|
|
|
function calculate_normal_tangential_coordinates!(elements::Vector, time::Real, ::Type{Val{3}})
|
|
|
|
|
|
nodes = get_nodes(elements)
|
|
|
|
|
|
n = zeros(3, maximum(nodes))
|
|
|
|
|
|
for element in elements
|
|
|
|
|
|
gdofs = get_gdofs(element, 1)
|
|
|
|
|
|
for ip in get_integration_points(element, Val{3})
|
2016-02-13 01:12:24 +02:00
|
|
|
|
J = transpose(get_jacobian(element, ip, time, Val{:deformed}))
|
2016-02-05 22:26:07 +02:00
|
|
|
|
N = element(ip, time)
|
|
|
|
|
|
c = reshape(cross(J[:,1], J[:,2]), 3, 1)
|
|
|
|
|
|
n[:, gdofs] += ip.weight*c*N
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
t1 = zeros(n)
|
|
|
|
|
|
t2 = zeros(n)
|
|
|
|
|
|
for i=1:size(n,2)
|
|
|
|
|
|
i in nodes || continue
|
|
|
|
|
|
n[:,i] = n[:,i] / norm(n[:,i])
|
|
|
|
|
|
u1 = n[:,i]
|
|
|
|
|
|
j = indmax(abs(n[:,i]))
|
|
|
|
|
|
v2 = zeros(3)
|
|
|
|
|
|
v2[mod(j,3)+1] = 1.0
|
|
|
|
|
|
u2 = v2 - dot(u1, v2) / dot(v2, v2) * v2
|
|
|
|
|
|
u3 = cross(u1, u2)
|
|
|
|
|
|
t1[:,i] = u2/norm(u2)
|
|
|
|
|
|
t2[:,i] = u3/norm(u3)
|
2016-02-03 20:39:03 +02:00
|
|
|
|
end
|
|
|
|
|
|
for element in elements
|
|
|
|
|
|
node_ids = get_connectivity(element)
|
2016-02-05 22:26:07 +02:00
|
|
|
|
Q = Matrix{Float64}[ [n[:,i] t1[:,i] t2[:,i]] for i in node_ids]
|
2016-02-13 01:12:24 +02:00
|
|
|
|
element["normal-tangential coordinates"] = (time => Q)
|
2016-02-16 17:40:11 +02:00
|
|
|
|
element["normals"] = (time => Vector{Float64}[n[:,i] for i in node_ids])
|
2016-02-03 20:39:03 +02:00
|
|
|
|
end
|
2015-12-20 21:17:47 +02:00
|
|
|
|
end
|
2015-12-12 10:08:20 +02:00
|
|
|
|
|
2016-01-01 15:00:18 +02:00
|
|
|
|
|
|
|
|
|
|
""" Update values for several elements at once. """
|
|
|
|
|
|
# FIXME: with or without {T} ?
|
2016-02-10 22:21:30 +02:00
|
|
|
|
function update!{T}(elements::Vector{Element{T}}, field_name::ASCIIString, data...)
|
2016-01-01 15:00:18 +02:00
|
|
|
|
for element in elements
|
2016-02-10 22:21:30 +02:00
|
|
|
|
update!(element, field_name, data...)
|
2016-01-01 15:00:18 +02:00
|
|
|
|
end
|
|
|
|
|
|
end
|
2016-05-20 04:39:51 +03:00
|
|
|
|
|
|
|
|
|
|
=#
|