time properly implemented to .. everything.

This commit is contained in:
Jukka Aho
2015-09-29 00:07:56 +03:00
parent b5bcc0a630
commit 7403fb8cb7
9 changed files with 410 additions and 287 deletions
+7 -1
View File
@@ -8,7 +8,13 @@ using Logging
@Logging.configure(level=DEBUG)
include("types.jl") # type definitions
include("elements.jl") # elements
### ELEMENTS ###
include("elements.jl")
include("lagrange.jl") # Lagrange elements
#include("hierarchical.jl") # P-elements
include("equations.jl") # formulations
include("problems.jl") # problems
+68 -27
View File
@@ -90,16 +90,13 @@ End of example.
# These must be implemented for your own element
get_number_of_basis_functions(el::Type{Element}) = nothing
get_number_of_basis_functions(el::Element) = nothing
get_element_dimension(el::Element) = nothing
get_dbasisdxi(el::Element, xi) = nothing
get_connectivity(el::Element) = el.connectivity
get_element_dimension(el::Type{Element}) = nothing
### LAGRANGE ELEMENTS ###
include("lagrange.jl")
#include("lagrange.jl")
### HIERARCHICAL P-ELEMENTS ###
include("hierarchical.jl")
#include("hierarchical.jl")
### COMMON ELEMENT ROUTINES ###
@@ -144,14 +141,15 @@ function test_element(eltype)
# try to interpolate some scalar field
fld = Field(0.0, collect(1:n))
Logging.info("Pushing scalar field $fld to element.")
Logging.info("Creating new scalar field $fld")
Logging.info("Pushing field to element.")
new_field!(el, :field1)
push_field!(el, :field1, fld)
@fact el[:field1][1] --> fld
mid = zeros(dim)
try
f = get_basis(el)(mid)
get_basis(el)(mid)
catch
Logging.error("""
Unable to evaluate basis, define function 'get_basis' for
@@ -167,11 +165,12 @@ function test_element(eltype)
Logging.info("Interpolating scalar field at $mid")
f(field, xi, t) = el(xi)*el[field](t)
i = f(:field, mid, 0.0)
i = f(:field1, mid, 0.0)
Logging.info("Value: $i")
Logging.info("Element $eltype passed tests.")
end
get_connectivity(el::Element) = el.connectivity
"""
Get basis functions of element.
@@ -180,6 +179,32 @@ get_basis(el::Element) = el.basis
get_basis(el::Element, xi::Vector) = el.basis(xi)
Base.call(el::Element, xi::Vector) = el.basis(xi)
"""
Get partial derivatives of basis functions of element.
"""
get_dbasisdxi(el::Element) = el.basis.dbasisdxi
get_dbasisdxi(el::Element, xi::Vector) = el.basis.dbasisdxi(xi)
"""
Interpolate field on element.
"""
function interpolate(el::Element, field::Symbol, xi::Vector, t::Number)
get_basis(el, xi)*el[field](t)
end
function interpolate(el::Element, field::ASCIIString, xi::Vector, t::Number)
interpolate(el, Symbol(field), xi, t)
end
"""
Interpolate derivative of field on element.
"""
function dinterpolate(el::Element, field::Symbol, xi::Vector, t::Number)
get_dbasisdxi(el, xi)*el[field](t)
end
function dinterpolate(el::Element, field::ASCIIString, xi::Vector, t::Number)
dinterpolate(el, Symbol(field), xi, t)
end
"""
Get jacobian of element evaluated at point ξ on element in reference configuration.
@@ -188,6 +213,7 @@ Parameters
el::Element
xi::Vector
geometry_field::Any, optional
time::Number, optional, default=0.0
Returns
-------
@@ -198,8 +224,8 @@ Notes
-----
Big "J" comes from reference (undeformed) configuration.
"""
function get_Jacobian(el::Element, xi, geometry_field=:Geometry)
dinterpolate(el, geometry_field, xi)
function get_Jacobian(el::Element, xi, t, geometry_field=:Geometry)
dinterpolate(el, geometry_field, xi, t)
end
@@ -210,11 +236,11 @@ Notes
-----
Small "j" comes from current (deformed) configuration.
"""
function get_jacobian(el::Element, xi, geometry_field=:Geometry, displacement_field=:displacement)
function get_jacobian(el::Element, xi, t, geometry_field=:Geometry, displacement_field=:displacement)
dbasisdxi = get_dbasisdxi(el, xi)
X = get_field(el, geometry_field)
u = get_field(el, displacement_field)
j = (X+u)*dbasisdxi
X = get_field(el, geometry_field)(t)
u = get_field(el, displacement_field)(t)
j = dbasisdxi*(X+u)
return j
end
@@ -222,9 +248,9 @@ end
"""
Evaluate partial derivatives of basis, dbasis/dX
"""
function get_dbasisdX(el::Element, xi)
function get_dbasisdX(el::Element, xi, t)
dbasisdxi = get_dbasisdxi(el, xi)
J = get_Jacobian(el, xi)
J = get_Jacobian(el, xi, t)
dbasisdxi*inv(J)
end
@@ -232,32 +258,48 @@ end
"""
Evaluate partial derivatives of basis, dbasis/dx
"""
function get_dbasisdx(el::Element, xi)
function get_dbasisdx(el::Element, xi, t)
dbasisdxi = get_dbasisdxi(el, xi)
j = get_jacobian(el, xi)
j = get_jacobian(el, xi, t)
dbasisdxi*inv(j)
end
""" Create new empty field of some type. """
function new_field!(el::Element, field_name)
function new_field!(el::Element, field_name::Symbol)
el.fields[field_name] = Field[]
end
function new_field!(el::Element, field_name::Symbol, field::Field)
new_field!(el, field_name)
push_field!(el, field_name, field)
end
function new_field!(el::Element, field_name::ASCIIString, field::Field)
new_field!(el, Symbol(field_name), field)
end
""" Push to existing set field of fields. """
function push_field!(el::Element, field_name, field::Field)
function push_field!(el::Element, field_name::Symbol, field::Field)
push!(el.fields[field_name], field)
end
function push_field!(el::Element, field_name::ASCIIString, field::Field)
push_field!(el, Symbol(field_name), field)
end
""" Get field variable. """
function get_field(el::Element, field_name)
function get_field(el::Element, field_name::Symbol)
el.fields[field_name]
end
function Base.getindex(el::Element, field_name)
el.fields[field_name]
function get_field(el::Element, field_name::ASCIIString)
el.fields[Symbol(field_name)]
end
function Base.getindex(el::Element, field_name::Union{ASCIIString, Symbol})
get_field(el, field_name)
end
#=
"""
Evaluate some field in point ξ on element using basis functions.
@@ -296,8 +338,6 @@ function interpolate(el::Element, field, xis::Array{Vector, 1})
map(interpolate_, xis)
end
"""
"""
function dinterpolate(el::Element, field, xi::Number)
dinterpolate(el, field, [xi])
end
@@ -309,12 +349,13 @@ function dinterpolate(el::Element, field, xi::Vector)
end
return sum([fld[i]*dbasis[i,:] for i in 1:length(fld)])
end
=#
"""
calculate "local" normals in elements, in a way that
n = Nᵢnᵢ gives some reasonable results for ξ ∈ [-1, 1]
"""
function calculate_normals!(el::Element, field_name=:Normals)
function calculate_normals!(el::Element, t, field_name=:Normals)
new_field!(el, field_name, Vector)
for xi in Vector[[-1.0], [1.0]]
t = dinterpolate(el, :Geometry, xi)
+12 -12
View File
@@ -32,23 +32,23 @@ get_integration_points(eq::Equation) = eq.integration_points
get_connectivity(eq::Equation) = get_connectivity(get_element(eq))
get_basis(eq::Equation, ip::IntegrationPoint) = get_basis(get_element(eq), ip.xi)
get_dbasisdx(eq::Equation, ip::IntegrationPoint) = get_dbasisdx(get_element(eq), ip.xi)
interpolate(eq::Equation, field::Union(ASCIIString, Symbol), ip::IntegrationPoint) = interpolate(get_element(el), field, ip.xi)
integrate_lhs(eq::Equation) = has_lhs(eq) ? integrate(eq, get_lhs) : nothing
integrate_rhs(eq::Equation) = has_rhs(eq) ? integrate(eq, get_rhs) : nothing
interpolate(eq::Equation, field::Union{ASCIIString, Symbol}, ip::IntegrationPoint) = interpolate(get_element(el), field, ip.xi)
integrate_lhs(eq::Equation, t::Number) = has_lhs(eq) ? integrate(eq, get_lhs, t) : nothing
integrate_rhs(eq::Equation, t::Number) = has_rhs(eq) ? integrate(eq, get_rhs, t) : nothing
"""
Return determinant of Jacobian for numerical integration.
"""
function get_detJ(eq::Equation, ip::IntegrationPoint)
function get_detJ(eq::Equation, ip::IntegrationPoint, t::Float64)
el = get_element(eq)
get_detJ(el, ip)
get_detJ(el, ip, t)
end
function get_detJ(el::Element, ip::IntegrationPoint)
J = get_detJ(el, ip.xi)
function get_detJ(el::Element, ip::IntegrationPoint, t::Float64)
get_detJ(el, ip.xi, t)
end
function get_detJ(el::Element, xi::Vector)
J = get_Jacobian(el, xi)
function get_detJ(el::Element, xi::Vector, t::Float64)
J = get_Jacobian(el, xi, t)
s = size(J)
return s[1] == s[2] ? det(J) : norm(J)
end
@@ -63,10 +63,10 @@ eq::Equation
f::Function
Function to integrate
"""
function integrate(eq::Equation, f::Function)
function integrate(eq::Equation, f::Function, t::Float64)
target = []
for ip in get_integration_points(eq)
push!(target, ip.weight*f(eq, ip)*get_detJ(eq, ip))
push!(target, ip.weight*f(eq, ip, t)*get_detJ(eq, ip, t))
end
return sum(target)
end
@@ -80,4 +80,4 @@ function set_global_dofs!(eq::Equation, dofs)
end
# Equations for heat problems
include("heat_equations.jl")
#include("heat_equations.jl")
+30 -56
View File
@@ -5,31 +5,9 @@
abstract CG <: Element
"""
Create new element with element_name to family element_family
Examples
--------
>>> @create_element(Seg2, CG, "2 node linear segment")
"""
macro create_element(element_name, element_family, element_description)
# Logging.debug("Creating element ", element_name, ": ", element_description, "\n")
eltype = esc(element_name)
elfam = esc(element_family)
quote
global get_element_description
type $eltype <: $elfam
connectivity :: Array{Int, 1}
fields :: Dict{Any, Any}
end
$eltype(connectivity) = $eltype(connectivity, Dict{Any, Any}())
get_element_description(el::Type{$eltype}) = $element_description
end
end
"""
Given polynomial P and coordinates of reference element, calculate
Lagrange basis function and partial derivatives.
Lagrange basis functions
"""
function calculate_lagrange_basis(P, X)
dim, nbasis = size(X)
@@ -40,70 +18,66 @@ function calculate_lagrange_basis(P, X)
# Logging.debug("Calculating inverse of A")
invA = inv(A)'
basis(xi) = invA*P(xi)
dbasisdxi = ForwardDiff.jacobian(basis)
basis, dbasisdxi
basis
end
"""
Assign Lagrange basis for element.
Create new Lagrange element
Examples
--------
>>> @create_lagrange_element(Seg2, "2 node linear segment", X, P)
"""
macro create_lagrange_basis(element_name, X, P)
# Logging.debug("Creating Lagrange basis for element ", element_name, ". ")
macro create_lagrange_element(element_name, element_description, X, P)
# Logging.debug("Creating element ", element_name, ": ", element_description, "\n")
eltype = esc(element_name)
quote
global get_element_description
global get_number_of_basis_functions, get_element_dimension
global get_basis, get_dbasisdxi
dim = size($X, 1)
nbasis = size($X, 2)
# Logging.debug("Number of basis functions: ", nbasis, ". ")
# Logging.debug("Element dimension: ", dim)
get_number_of_basis_functions(el::Type{$(esc(element_name))}) = nbasis
get_number_of_basis_functions(el::$(esc(element_name))) = nbasis
get_element_dimension(el::$(esc(element_name))) = dim
basis, dbasisdxi = calculate_lagrange_basis($P, $X)
get_basis(el::$eltype, xi) = basis(xi)
get_dbasisdxi(el::$eltype, xi) = dbasisdxi(xi)
# Logging.debug("Element ", $element_name, " created.")
h = calculate_lagrange_basis($P, $X)
type $eltype <: CG
connectivity :: Array{Int, 1}
basis :: Basis
fields :: Dict{Symbol, Array{Field, 1}}
end
function $eltype(connectivity, args...)
$eltype(connectivity, Basis(h), Dict())
end
get_element_description(el::Type{$eltype}) = $element_description
get_number_of_basis_functions(el::Type{$eltype}) = nbasis
get_element_dimension(el::Type{$eltype}) = dim
end
end
# 0d Lagrange element
@create_element(Point1, CG, "1 node point element")
#@create_element(Point1, CG, "1 node point element")
# 1d Lagrange elements
@create_element(Seg2, CG, "2 node linear line element")
@create_lagrange_basis(Seg2, [-1.0 1.0], (xi) -> [1.0, xi[1]])
@create_lagrange_element(Seg2, "2 node linear line element",
[-1.0 1.0], (xi) -> [1.0, xi[1]])
@create_element(Seg3, CG, "3 node quadratic line element")
@create_lagrange_basis(Seg3, [-1.0 1.0 0.0], (xi) -> [1.0, xi[1], xi[1]^2])
@create_lagrange_element(Seg3, "3 node quadratic line element",
[-1.0 1.0 0.0], (xi) -> [1.0, xi[1], xi[1]^2])
# 2d Lagrange elements
@create_element(Tri3, CG, "3 node bilinear triangle element")
@create_lagrange_basis(Tri3,
@create_lagrange_element(Tri3, "3 node bilinear triangle element",
[0.0 1.0 0.0
0.0 0.0 1.0],
(xi) -> [1.0, xi[1], xi[2]])
@create_element(Quad4, CG, "4 node bilinear quadrangle element")
@create_lagrange_basis(Quad4,
@create_lagrange_element(Quad4, "4 node bilinear quadrangle element",
[-1.0 1.0 1.0 -1.0
-1.0 -1.0 1.0 1.0],
(xi) -> [1.0, xi[1], xi[2], xi[1]*xi[2]])
# 3d Lagrange elements
@create_element(Tet10, CG, "10 node quadratic tetrahedron")
@create_lagrange_basis(Tet10,
@create_lagrange_element(Tet10, "10 node quadratic tetrahedron",
[0.0 1.0 0.0 0.0 0.5 0.5 0.0 0.0 0.5 0.0
0.0 0.0 1.0 0.0 0.0 0.5 0.5 0.0 0.0 0.5
0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.5 0.5 0.5],
+2 -84
View File
@@ -1,69 +1,8 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
## This module contains math stuff, including interpolation, integration, linearization, ...
using ForwardDiff
#export interpolate, integrate, linearize
"""
Interpolate field variable using basis functions f for point ip.
This function tries to be as general as possible and allows interpolating
lot of different fields.
Parameters
----------
field :: Array{Number, dim}
Field variable
basis :: Function
Basis functions
ip :: Array{Number, 1}
Point to interpolate
"""
function interpolate(field::Float64, basis::Function, ip::Array{Float64,1})
# dummy function, unable to interpolate scalar value!
return field
end
function interpolate{T<:Real}(field::Array{T,1}, basis::Function, ip)
result = dot(field, basis(ip))
return result
end
function interpolate{T<:Real}(field::Array{T,2}, basis::Function, ip)
m, n = size(field)
bip = basis(ip)
tmp = size(bip)
if length(tmp) == 1
ndim = 1
nnodes = tmp[1]
else
ndim, nnodes = size(bip)
end
if ndim == 1
if n == nnodes
result = field * bip
elseif m == nnodes
result = field' * bip
end
else
if n == nnodes
result = bip' * field
elseif m == nnodes
result = bip' * field'
end
end
if length(result) == 1
result = result[1]
end
return result
end
#function interpolate(e::Element, field::ASCIIString, x::Array{Float64,1}; derivative=false)
# basis = derivative ? get_dbasisdxi(e) : get_basis(e)
# return interpolate(e.attributes[field], basis, x)
#end
"""
Linearize function f w.r.t some given field, i.e. calculate dR/du
@@ -78,7 +17,6 @@ Returns
-------
Array{Float64, 2}
jacobian / "tangent stiffness matrix"
"""
function linearize(f::Function, el::Element, field::ASCIIString)
dim, nnodes = size(el.attributes[field])
@@ -92,6 +30,7 @@ function linearize(f::Function, el::Element, field::ASCIIString)
return jac(el.attributes[field][:])
end
"""
This version returns another function which can be then evaluated against field
"""
@@ -111,6 +50,7 @@ function linearize(f::Function, field::ASCIIString)
return jacobian
end
"""
In-place version, no additional garbage collection.
"""
@@ -128,8 +68,6 @@ function linearize!(f::Function, el::Element, field::ASCIIString, target::ASCIIS
end
"""
This version returns a function which must be operated with element e
"""
@@ -157,25 +95,6 @@ function integrate!(f::Function, el::Element, target)
end
end
"""
Evaluate field in point xi using basis functions.
"""
function interpolate(el::Element, field::ASCIIString, xi::Array{Float64,1})
f = get_field(el, field)
if !isa(f, Array)
# This is scalar, nothing to interpolate
return f
end
basis = get_basis(el, xi)
dim, nnodes = size(f)
result = zeros(dim)
for i=1:nnodes
result += basis[i]*f[:,i]
end
return result
end
function linearize(eq::Equation, f::Function, field::ASCIIString)
function jacobian(eq::Equation, args...)
el = get_element(eq)
@@ -194,4 +113,3 @@ function linearize(eq::Equation, f::Function, field::ASCIIString)
return jacobian
end
+11 -3
View File
@@ -10,7 +10,7 @@ using ForwardDiff
type Field{T}
time :: Float64
increment :: Int64
values :: Array{T, 1}
values :: T
end
""" Initialize field. """
@@ -25,8 +25,16 @@ Base.length(f::Field) = length(f.values)
Base.getindex(f::Field, i::Int64) = f.values[i]
""" Interpolate field h(ξ)*f = x*f """
Base.(:*)(x::Array{Float64, 1}, f::Field) = sum(x .* f.values)
Base.(:*)(x::Array{Float64, 2}, f::Field) = sum([f[i]*x[i,:] for i in 1:length(f)])
function interpolate{T}(x::Vector, f::Field{Vector{T}})
sum([f[i]*x[i] for i in 1:length(f)])
end
function interpolate{T}(x::Matrix, f::Field{Vector{T}})
sum([f[i]*x[i,:] for i in 1:length(f)])
end
function interpolate(x::Vector, f::Field)
f.values*x
end
Base.(:*)(x::Union{Vector, Matrix}, f::Field) = interpolate(x, f)
""" Interpolate field (h*f)(ξ) """
Base.(:*)(f::Function, fld::Field) = (x) -> f(x)*fld