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 )
Logging . info ( " Testing element $element_type " )
local element
2015-10-27 06:37:58 +02:00
dim = nothing
n = nothing
try
dim , n = size ( element_type )
catch
Logging . 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. " )
end
Logging . info ( " element dimension: $dim x $n " )
2015-09-10 20:35:28 +03:00
Logging . 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-09-10 20:35:28 +03:00
Logging . 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-09-10 20:35:28 +03:00
2015-08-31 20:15:28 +03:00
# try to interpolate some scalar field
2015-10-28 04:29:14 +02:00
element [ " field1 " ] = Field ( 0.0 , collect ( 1 : n ) )
2015-10-27 06:37:58 +02:00
# TODO: how to parametrize this?
2015-10-28 04:29:14 +02:00
element [ " geometry " ] = Field ( 0.0 , 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 )
Logging . info ( " basis at $mid : $val1 " )
val2 = basis ( " field1 " , mid , 0.0 )
Logging . info ( " field val at $mid : $val2 " )
val3 = dbasis ( mid , 0.0 )
Logging . info ( " derivative of basis at $mid : $val3 " )
val4 = dbasis ( " field1 " , mid , 0.0 )
Logging . info ( " field val at $mid : $val4 " )
2015-08-31 20:15:28 +03:00
2015-10-20 15:54:47 +03:00
Logging . 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 )
element . fields [ field_name ]
end
""" Add new FieldSet to element.
Examples
--------
>>> element[ " geometry " ] = [1, 2, 3, 4]
JuliaFEM.Quad4([1,2,3,4],JuliaFEM.Basis(basis,dbasisdxi),Dict( " geometry " =>JuliaFEM.FieldSet( " geometry " ,JuliaFEM.Field[JuliaFEM.Field{Array{Int64,1}}(0.0,0,[1,2,3,4])])))
"""
2015-10-30 12:40:56 +02:00
function Base . setindex! ( element :: Element , field_data , field_name )
element . fields [ field_name ] = field_data
2015-10-28 04:29:14 +02:00
end
2015-10-20 15:54:47 +03:00
2015-10-26 05:40:41 +02:00
function get_connectivity ( el :: Element )
el . connectivity
end
2015-09-14 23:20:33 +03:00
2015-10-28 04:29:14 +02:00
abstract AbstractFunctionSpace
type FunctionSpace <: AbstractFunctionSpace
element :: Element
end
type GradientFunctionSpace <: AbstractFunctionSpace
element :: Element
end
type MixedFunctionSpace <: AbstractFunctionSpace
2015-10-26 05:40:41 +02:00
element1 :: Element
element2 :: Element
end
2015-09-28 13:22:12 +03:00
2015-10-28 04:29:14 +02:00
function get_basis ( element :: Element )
return FunctionSpace ( element )
2015-10-26 05:40:41 +02:00
end
2015-09-29 00:07:56 +03:00
2015-10-28 04:29:14 +02:00
function get_dbasis ( element :: Element )
return GradientFunctionSpace ( element )
2015-09-29 00:07:56 +03:00
end
2015-10-26 05:40:41 +02:00
function grad ( u :: FunctionSpace )
2015-10-28 04:29:14 +02:00
return GradientFunctionSpace ( u . element )
2015-10-21 07:24:19 +03:00
end
2015-09-29 00:07:56 +03:00
2015-10-26 05:40:41 +02:00
""" Evaluate field on element function space. """
function call ( u :: FunctionSpace , field_name , xi :: Vector , t :: Number = Inf , variation = nothing )
f = ! isa ( variation , Void ) ? variation : u . element [ field_name ] ( t )
if length ( f ) == 1
2015-10-30 12:40:56 +02:00
return f . data [ 1 ]
2015-10-26 05:40:41 +02:00
end
h = u . element . basis . basis ( xi )
2015-10-30 12:40:56 +02:00
#@debug("vec(h) = $(vec(h)), size(h) = $(size(vec(h)))")
#@debug("f = $f, size(f) = $(size(f))")
#return dot(vec(h), f)
return sum ( vec ( h ) .* f )
2015-09-29 00:07:56 +03:00
end
2015-10-26 05:40:41 +02:00
""" If basis is called without a field, return basis functions evaluated at that point. """
function call ( u :: FunctionSpace , xi :: Vector , t :: Number = Inf )
2015-10-27 06:37:58 +02:00
return u . element . basis . basis ( xi )
2015-10-21 07:24:19 +03:00
end
2015-09-29 00:07:56 +03:00
2015-10-26 05:40:41 +02:00
""" Evaluate gradient of field on element function space. """
function call ( gradu :: GradientFunctionSpace , field_name , xi :: Vector , t :: Number = Inf , variation = nothing )
f = ! isa ( variation , Void ) ? variation : gradu . element [ field_name ] ( t )
X = gradu . element [ " geometry " ] ( t )
2015-10-27 06:37:58 +02:00
dN = gradu . element . basis . dbasisdxi ( xi )
J = sum ( [ dN [ : , i ] * X [ i ] ' for i = 1 : length ( X ) ] )
grad = inv ( J ) * dN
gradf = sum ( [ grad [ : , i ] * f [ i ] ' for i = 1 : length ( f ) ] ) '
return gradf
2015-10-23 01:11:45 +03:00
end
2015-10-26 05:40:41 +02:00
""" If gradient of basis is called without a field, return " empty " gradient evaluated at that point. """
function call ( gradu :: GradientFunctionSpace , xi :: Vector , t :: Number = Inf )
X = gradu . element [ " geometry " ] ( t )
2015-10-27 06:37:58 +02:00
dN = gradu . element . basis . dbasisdxi ( xi )
J = sum ( [ dN [ : , i ] * X [ i ] ' for i = 1 : length ( X ) ] )
grad = inv ( J ) * dN
return grad
2015-10-26 05:40:41 +02:00
end
2015-09-10 02:20:34 +03:00
2015-10-26 05:40:41 +02:00
# on-line functions to get api more easy to use, ip -> xi.ip
2015-10-27 06:37:58 +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 )
# i think these will be the most called functions.
2015-10-28 04:29:14 +02:00
call ( u :: FunctionSpace , field_name , ip :: IntegrationPoint , t :: Number = Inf , variation = nothing ) = call ( u , field_name , ip . xi , t , variation )
call ( u :: GradientFunctionSpace , field_name , ip :: IntegrationPoint , t :: Number = Inf , variation = nothing ) = call ( u , field_name , ip . xi , t , variation )
2015-10-27 06:37:58 +02:00
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-10-26 05:40:41 +02:00
function get_field ( u :: FunctionSpace , field_name , time = Inf )
return u . element [ field_name ] ( time )
end
2015-10-27 06:37:58 +02:00
""" Return a field from function space. """
2015-10-26 05:40:41 +02:00
function get_field ( u :: FunctionSpace , field_name , time = Inf , variation = nothing )
return ! isa ( variation , Void ) ? variation : u . element [ field_name ] ( time )
2015-08-24 01:14:03 +03:00
end
2015-10-27 06:37:58 +02:00
""" Return a fieldset from function space. """
2015-10-26 05:40:41 +02:00
function get_fieldset ( u :: FunctionSpace , field_name )
return u . element [ 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-10-27 06:37:58 +02:00
function LinAlg . det ( u :: FunctionSpace , xi :: Vector , t :: Number = Inf )
X = u . element [ " geometry " ] ( t )
dN = u . element . basis . dbasisdxi ( xi )
J = sum ( [ dN [ : , i ] * X [ i ] ' for i = 1 : length ( X ) ] )
m , n = size ( J )
return m == n ? det ( J ) : norm ( J )
2015-10-26 05:40:41 +02:00
end
2015-10-27 06:37:58 +02:00
function LinAlg . det ( u :: FunctionSpace , ip :: IntegrationPoint , t :: Number = Inf )
LinAlg . det ( u , ip . xi , t )
2015-10-26 05:40:41 +02:00
end
function LinAlg . det ( u :: FunctionSpace )
2015-10-27 06:37:58 +02:00
return ( args ... ) -> det ( u , args ... )
2015-10-26 05:40:41 +02:00
end
2015-09-29 00:07:56 +03:00
2015-10-26 05:40:41 +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 ... )
""" Check does fieldset exist. """
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