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
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-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-09-10 20:35:28 +03:00
2015-11-01 18:44:50 +02:00
info ( " Initializing element " )
2015-08-31 20:15:28 +03:00
try
2015-11-30 16:04:13 +02:00
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 ( """
2015-09-10 20:35:28 +03:00
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-09-10 20:35:28 +03:00
2015-08-31 20:15:28 +03:00
# try to interpolate some scalar field
2015-11-30 16:04:13 +02:00
element [ " field1 " ] = range ( 1 , n )
2015-10-27 06:37:58 +02:00
# TODO: how to parametrize this?
2015-11-30 16:04:13 +02:00
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 )
2015-11-30 16:04:13 +02:00
val1 = element ( mid , 0.0 )
2015-11-01 18:44:50 +02:00
info ( " basis at $mid : $val1 " )
2015-11-30 16:04:13 +02:00
val2 = element ( " field1 " , mid , 0.0 )
2015-11-01 18:44:50 +02:00
info ( " field val at $mid : $val2 " )
2015-11-30 16:04:13 +02:00
val3 = element ( mid , 0.0 , Val { :grad } )
2015-11-11 00:52:16 +02:00
info ( " derivative of basis at $mid : \n $val3 " )
2015-11-30 16:04:13 +02:00
#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-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-10-26 05:40:41 +02:00
function get_connectivity ( el :: Element )
2015-11-11 00:52:16 +02:00
return el . connectivity
2015-10-26 05:40:41 +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
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 )
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
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 )
2015-11-23 03:17:15 +02:00
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
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
""" 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 )
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-11-11 00:52:16 +02:00
""" Check does field exist. """
2015-10-26 05:40:41 +02:00
function Base . haskey ( element :: Element , what )
2015-10-27 06:37:58 +02:00
haskey ( element . fields , what )
2015-10-26 05:40:41 +02:00
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