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
+273 -95
View File
@@ -13,11 +13,35 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
"WARNING: Base.String is deprecated, use AbstractString instead.\n",
"WARNING: Base.String is deprecated, use AbstractString instead.\n"
]
},
{
"data": {
"text/plain": [
"Logger(root,DEBUG,PipeEndpoint(open, 0 bytes waiting),root)"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"using Logging\n",
"using FactCheck\n",
@@ -49,7 +73,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 2,
"metadata": {
"collapsed": false
},
@@ -133,7 +157,7 @@
{
"data": {
"text/plain": [
"get_element_dimension (generic function with 8 methods)"
"get_element_dimension (generic function with 7 methods)"
]
},
"execution_count": 5,
@@ -164,21 +188,25 @@
"name": "stderr",
"output_type": "stream",
"text": [
"28-Sep 12:56:52:INFO:root:Testing element MyQuad4\n",
"28-Sep 12:56:52:INFO:root:number of basis functions in this element: 4\n",
"28-Sep 12:56:53:INFO:root:Initializing element\n",
"28-Sep 12:56:53:INFO:root:Element dimension: 2\n",
"28-Sep 12:56:53:INFO:root:Setting scalar field JuliaFEM.Field{Int64}(0.0,1,[1,2,3,4]) to element.\n"
"29-Sep 00:06:50:INFO:root:Testing element MyQuad4\n",
"29-Sep 00:06:50:INFO:root:number of basis functions in this element: 4\n",
"29-Sep 00:06:50:INFO:root:Initializing element\n",
"29-Sep 00:06:50:INFO:root:Element dimension: 2\n",
"29-Sep 00:06:50:INFO:root:Creating new scalar field JuliaFEM.Field{Array{Int64,1}}(0.0,1,[1,2,3,4])\n",
"29-Sep 00:06:50:INFO:root:Pushing field to element.\n",
"29-Sep 00:06:50:INFO:root:Interpolating scalar field at [0.0,0.0]\n",
"29-Sep 00:06:51:INFO:root:Value: 2.5\n"
]
},
{
"ename": "LoadError",
"evalue": "LoadError: MethodError: `convert` has no method matching convert(::Type{Array{JuliaFEM.Field{T},1}}, ::JuliaFEM.Field{Int64})\nThis may have arisen from a call to the constructor Array{JuliaFEM.Field{T},1}(...),\nsince type constructors fall back to convert methods.\nClosest candidates are:\n call{T}(::Type{T}, ::Any)\n convert{T}(::Type{Array{T,1}}, !Matched::Range{T})\n convert{T,S,N}(::Type{Array{T,N}}, !Matched::SubArray{S,N,P<:AbstractArray{T,N},I<:Tuple{Vararg{Union{AbstractArray{T,1},Colon,Int64}}},LD})\n ...\nwhile loading In[6], in expression starting on line 2",
"output_type": "error",
"traceback": [
"LoadError: MethodError: `convert` has no method matching convert(::Type{Array{JuliaFEM.Field{T},1}}, ::JuliaFEM.Field{Int64})\nThis may have arisen from a call to the constructor Array{JuliaFEM.Field{T},1}(...),\nsince type constructors fall back to convert methods.\nClosest candidates are:\n call{T}(::Type{T}, ::Any)\n convert{T}(::Type{Array{T,1}}, !Matched::Range{T})\n convert{T,S,N}(::Type{Array{T,N}}, !Matched::SubArray{S,N,P<:AbstractArray{T,N},I<:Tuple{Vararg{Union{AbstractArray{T,1},Colon,Int64}}},LD})\n ...\nwhile loading In[6], in expression starting on line 2",
""
]
"data": {
"text/plain": [
"PipeEndpoint(open, 0 bytes waiting)"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
@@ -195,31 +223,7 @@
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"24-Sep 21:04:04:INFO:root:Value: [2.5]\n",
"24-Sep 21:04:04:INFO:root:Element MyQuad4 passed tests.\n"
]
}
],
"source": [
"using JuliaFEM: set_field, interpolate\n",
"el1 = MyQuad4([1, 2, 3, 4])\n",
"set_field(el1, :temperature, [1, 2, 3, 4])\n",
"set_field(el1, :Geometry, Vector[[0.0,0.0,0.0], [10.0,0.0,0.0], [10.0,1.0,0.0], [0.0,1.0,0.0]]);\n",
"set_field(el1, :\"heat coefficient\", 1);"
]
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 7,
"metadata": {
"collapsed": false
},
@@ -227,22 +231,59 @@
{
"data": {
"text/plain": [
"2.5"
"2-element Array{JuliaFEM.Field{T},1}:\n",
" JuliaFEM.Field{Int64}(0.0,1,2)\n",
" JuliaFEM.Field{Int64}(1.0,1,3)"
]
},
"execution_count": 9,
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"29-Sep 00:06:51:INFO:root:Element MyQuad4 passed tests.\n"
]
}
],
"source": [
"using JuliaFEM: new_field!, push_field!, interpolate, dinterpolate\n",
"el1 = MyQuad4([1, 2, 3, 4])\n",
"new_field!(el1, :temperature, Field(0.0, [0.0, 0.0, 0.0, 0.0]))\n",
"push_field!(el1, :temperature, Field(1.0, [1.0, 2.0, 3.0, 4.0]))\n",
"new_field!(el1, :Geometry, Field(0.0, Vector[[0.0,0.0,0.0], [10.0,0.0,0.0], [10.0,1.0,0.0], [0.0,1.0,0.0]]))\n",
"new_field!(el1, \"heat coefficient\", Field(0.0, 2))\n",
"push_field!(el1, \"heat coefficient\", Field(1.0, 3))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1.25"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# temperature at the middle poinf of the element, 1/4*(1+2+3+4)\n",
"interpolate(el1, :temperature, [0.0, 0.0])"
"# temperature at the middle poinf of the element, 1/4*(1+2+3+4) at t=0.5\n",
"interpolate(el1, :temperature, [0.0, 0.0], 0.5)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 9,
"metadata": {
"collapsed": false
},
@@ -256,14 +297,39 @@
" 0.0"
]
},
"execution_count": 10,
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# geometry midpoint of element\n",
"interpolate(el1, :Geometry, [0.0, 0.0])"
"interpolate(el1, :Geometry, [0.0, 0.0], -Inf)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"3x2 Array{Float64,2}:\n",
" 5.0 0.0\n",
" 0.0 0.5\n",
" 0.0 0.0"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dinterpolate(el1, :Geometry, [0.0, 0.0], -Inf)"
]
},
{
@@ -276,7 +342,7 @@
{
"data": {
"text/plain": [
"1"
"([0.625,0.625,0.625,0.625],[0.75,0.75,0.75,0.75])"
]
},
"execution_count": 11,
@@ -286,7 +352,7 @@
],
"source": [
"# interpolating scalar -> scalar.\n",
"interpolate(el1, :\"heat coefficient\", [0.0, 0.0])"
"interpolate(el1, \"heat coefficient\", [0.0, 0.0], 0.5), interpolate(el1, \"heat coefficient\", [0.0, 0.0], Inf)"
]
},
{
@@ -304,10 +370,9 @@
"source": [
"## Developing own formulation\n",
"\n",
"Let's consider Poisson equation\n",
"Let's consider a Laplace equation\n",
"\\begin{align}\n",
"\\Delta{u} &= 0 && \\text{on } \\Omega \\\\\n",
"u &= u_0 && \\text{on } \\Gamma_{\\mathrm{D}} \\\\\n",
"\\frac{\\partial u}{\\partial n} &= g && \\text{on } \\Gamma_{\\mathrm{N}}\n",
"\\end{align}\n",
"\n",
@@ -399,7 +464,7 @@
" IntegrationPoint(1.0/sqrt(3.0)*[ 1, -1], 1.0),\n",
" IntegrationPoint(1.0/sqrt(3.0)*[ 1, 1], 1.0),\n",
" IntegrationPoint(1.0/sqrt(3.0)*[-1, 1], 1.0)]\n",
" set_field(el, :temperature, zeros(2, 4)) # assign new field \"temperature\" to element\n",
" new_field!(el, :temperature) # assign new field \"temperature\" to element\n",
" DC2D4(el, integration_points, [])\n",
"end"
]
@@ -435,10 +500,11 @@
"\"\"\"\n",
"Left hand side defined in integration point\n",
"\"\"\"\n",
"function JuliaFEM.get_lhs(eq::DC2D4, ip)\n",
"function JuliaFEM.get_lhs(eq::DC2D4, ip, t)\n",
" el = get_element(eq)\n",
" dNdX = get_dbasisdX(el, ip.xi)\n",
" hc = interpolate(el, :\"temperature thermal conductivity\", ip.xi)\n",
" dNdX = get_dbasisdX(el, ip.xi, t)\n",
" fld = el[\"temperature thermal conductivity\"](t)\n",
" hc = sum(el(ip.xi) * fld)\n",
" return dNdX*hc*dNdX'\n",
"end\n",
"JuliaFEM.has_lhs(eq::DC2D4) = true"
@@ -476,17 +542,10 @@
"source": [
"using JuliaFEM: integrate, integrate_lhs, integrate_rhs\n",
"el = Quad4([1, 2, 3, 4])\n",
"set_field(el, :Geometry, Vector[[0,0], [1,0], [1,1], [0,1]])\n",
"set_field(el, :\"temperature thermal conductivity\", 6)\n",
"new_field!(el, :Geometry, Field(0.0, Vector[[0.0,0.0], [1.0,0.0], [1.0,1.0], [0.0,1.0]]))\n",
"new_field!(el, \"temperature thermal conductivity\", Field(0.0, 6.0))\n",
"eq = DC2D4(el)\n",
"integrate_lhs(eq)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If rhs or lhs is not defined, integration returns nothing."
"integrate_lhs(eq, 1.0)"
]
},
{
@@ -508,14 +567,14 @@
}
],
"source": [
"isa(integrate_rhs(eq), Void)"
"JuliaFEM.has_lhs(eq)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next heat flux on boundary:"
"If rhs or lhs is not defined, integration returns nothing."
]
},
{
@@ -528,7 +587,7 @@
{
"data": {
"text/plain": [
"has_rhs (generic function with 2 methods)"
"true"
]
},
"execution_count": 18,
@@ -536,6 +595,35 @@
"output_type": "execute_result"
}
],
"source": [
"isa(integrate_rhs(eq, 1.0), Void)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next heat flux on boundary:"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"has_rhs (generic function with 2 methods)"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"using JuliaFEM: get_basis, Seg2\n",
"\n",
@@ -551,25 +639,25 @@
"function DC2D2(el::Seg2)\n",
" integration_points = [\n",
" IntegrationPoint([0], 2.0)]\n",
" set_field(el, :temperature, zeros(2, 1))\n",
" new_field!(el, :temperature)\n",
" DC2D2(el, integration_points, [])\n",
"end\n",
"\n",
"\"\"\"\n",
"Right hand side defined in integration point\n",
"\"\"\"\n",
"function JuliaFEM.get_rhs(eq::DC2D2, ip)\n",
"function JuliaFEM.get_rhs(eq::DC2D2, ip, t)\n",
" el = get_element(eq)\n",
" N = get_basis(el, ip.xi)\n",
" f = interpolate(el, :\"temperature flux\", ip.xi)\n",
" return f*N\n",
" ϕ = get_basis(el)\n",
" f = el[\"temperature flux\"]\n",
" return ϕ(ip.xi)*f(t)\n",
"end\n",
"JuliaFEM.has_rhs(eq::DC2D2) = true"
]
},
{
"cell_type": "code",
"execution_count": 19,
"execution_count": 20,
"metadata": {
"collapsed": false
},
@@ -582,17 +670,17 @@
" 50.0"
]
},
"execution_count": 19,
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"el = Seg2([1, 2])\n",
"set_field(el, :Geometry, Vector[[0.0,0.0], [0.0,1.0]])\n",
"set_field(el, :\"temperature flux\", 100.0)\n",
"new_field!(el, :Geometry, Field(0.0, Vector[[0.0,0.0], [0.0,1.0]]))\n",
"new_field!(el, \"temperature flux\", Field(0.0, 100.0))\n",
"eq = DC2D2(el)\n",
"integrate_rhs(eq)"
"integrate_rhs(eq, 1.0)"
]
},
{
@@ -607,7 +695,7 @@
},
{
"cell_type": "code",
"execution_count": 20,
"execution_count": 21,
"metadata": {
"collapsed": false
},
@@ -618,7 +706,7 @@
"PlaneHeatProblem"
]
},
"execution_count": 20,
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
@@ -627,14 +715,14 @@
"using JuliaFEM: Problem, get_equation, get_dimension\n",
"\n",
"type PlaneHeatProblem <: Problem\n",
" equations :: Array{Any, 1}\n",
" equations :: Array{Equation, 1}\n",
"end\n",
"PlaneHeatProblem() = PlaneHeatProblem([])"
]
},
{
"cell_type": "code",
"execution_count": 21,
"execution_count": 22,
"metadata": {
"collapsed": false
},
@@ -645,7 +733,7 @@
"get_equation (generic function with 3 methods)"
]
},
"execution_count": 21,
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
@@ -674,7 +762,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"24-Sep 21:04:17:DEBUG:root:Problem (matrix) dimension: 4\n"
"29-Sep 00:06:53:DEBUG:root:Problem (matrix) dimension: 4\n"
]
},
{
@@ -687,7 +775,7 @@
" -2.0 -1.0 4.0 -1.0\n",
" -1.0 -2.0 -1.0 4.0,\n",
"\n",
"[50.0,50.0,0.0,0.0])"
"[300.0,300.0,0.0,0.0])"
]
},
"execution_count": 23,
@@ -700,11 +788,11 @@
"\n",
"# create elements and add necessary properties like connectivity and geometry\n",
"el1 = Quad4([1, 2, 3, 4])\n",
"set_field(el1, :Geometry, Vector[[0,0], [1,0], [1,1], [0,1]])\n",
"set_field(el1, :\"temperature thermal conductivity\", 6)\n",
"new_field!(el1, :Geometry, Field(0.0, Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]))\n",
"new_field!(el1, \"temperature thermal conductivity\", Field(0.0, 6.0))\n",
"el2 = Seg2([1, 2])\n",
"set_field(el2, :Geometry, Vector[[0.0,0.0], [0.0,1.0]])\n",
"set_field(el2, :\"temperature flux\", 100.0)\n",
"new_field!(el2, :Geometry, Field(0.0, Vector[[0.0, 0.0], [0.0, 1.0]]))\n",
"new_field!(el2, \"temperature flux\", Field(1.0, 600.0))\n",
"\n",
"problem = PlaneHeatProblem()\n",
"add_element!(problem, el1)\n",
@@ -716,20 +804,108 @@
"n = get_matrix_dimension(problem)\n",
"\n",
"# integrate and assembly\n",
"t = 1.0\n",
"A = zeros(n, n)\n",
"b = zeros(n)\n",
"for eq in get_equations(problem)\n",
" dofs = get_global_dofs(eq)\n",
" if has_lhs(eq)\n",
" A[dofs, dofs] += integrate_lhs(eq)\n",
" A[dofs, dofs] += integrate_lhs(eq, t)\n",
" end\n",
" if has_rhs(eq)\n",
" b[dofs] += integrate_rhs(eq)\n",
" b[dofs] += integrate_rhs(eq, t)\n",
" end\n",
"end\n",
"A, b"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2-element Array{Float64,1}:\n",
" 100.0\n",
" 100.0"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fdofs = [1, 2]\n",
"A[fdofs, fdofs] \\ b[fdofs]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We still need to consider Dirichlet boundary conditions:\n",
"\\begin{align}\n",
"u &= u_0 && \\text{on } \\Gamma_{\\mathrm{D}} \\\\\n",
"\\end{align}"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2x4 Array{Float64,2}:\n",
" 0.0 0.0 0.333333 0.166667\n",
" 0.0 0.0 0.166667 0.333333"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"M = 1/6*[0 0 2 1; 0 0 1 2]"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"6-element Array{Float64,1}:\n",
" 100.0 \n",
" 100.0 \n",
" 1.36187e-14\n",
" 1.77636e-15\n",
" 600.0 \n",
" 600.0 "
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[A M'; M zeros(2, 2)] \\ [b; 0; 0]"
]
},
{
"cell_type": "code",
"execution_count": null,
@@ -742,13 +918,15 @@
],
"metadata": {
"kernelspec": {
"display_name": "Julia 0.5.0-dev",
"display_name": "Julia 0.4.0-rc2",
"language": "julia",
"name": "julia-0.5"
"name": "julia-0.4"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "0.5.0"
"version": "0.4.0"
}
},
"nbformat": 4,
+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
+3 -9
View File
@@ -2,13 +2,7 @@
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
using FactCheck
using JuliaFEM: test_element
facts("test set and interpolate field variable") do
el = Quad4(1, [1, 2, 3, 4])
set_coordinates(el, [0.0 0.0; 10.0 0.0; 10.0 1.0; 0.0 1.0]')
set_field(el, "displacement", [0.0 0.0; 0.0 0.0; 0.5 0.0; 0.0 0.0]'')
fval = interpolate(el, "displacement", [0.0, 1.0])
Logging.debug(fval)
@fact fval --> roughly([0.25 0.0]')
end
using JuliaFEM: Quad4
test_element(Quad4)
+4
View File
@@ -57,4 +57,8 @@ facts("test fields and interpolation") do
@fact diff(h)([0.0, 0.0])*X --> [0.5 0.0; 0.0 0.5]
@fact (diff(h)*X)([0.0, 0.0]) --> [0.5 0.0; 0.0 0.5]
b = Basis((xi) -> [1/2*(1-xi[1]), 1/2*(1+xi[1])])
f = Field(0.0, 100.0)
@fact b(0.0) * f --> [50.0, 50.0]
end