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-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-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 ( """
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-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
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-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
2015-10-26 05:40:41 +02:00
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 )
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 )
2015-11-11 00:52:16 +02:00
return GradientFunctionSpace ( element . basis , element . fields )
2015-09-29 00:07:56 +03:00
end
2015-10-26 05:40:41 +02:00
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-10-26 05:40:41 +02:00
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 } )
2015-10-26 05:40:41 +02:00
end
2015-09-10 02:20:34 +03:00
2015-11-11 00:52:16 +02:00
2015-10-26 05:40:41 +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 )
2015-10-26 05:40:41 +02:00
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. """
2015-10-26 05:40:41 +02:00
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 )
2015-10-26 05:40:41 +02:00
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 )
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-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. """
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