mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-06 03:06:23 +00:00
data structures, new testing concept
This commit is contained in:
@@ -8,12 +8,13 @@
|
||||
"\n",
|
||||
"**Author(s)**: Jukka Aho\n",
|
||||
"\n",
|
||||
"**Abstract**: Description of basis data structures. In this notebook the concepts of `Increment`, `TimeStep`, `Field`, `FieldSet`, `SpatialBasis`, `TemporalBasis` are intoduced. With combining these atomic structures one is able to form finite elements and interpolate it's fields in time and spatial domain.\n",
|
||||
"**Abstract**: Description of basis data structures. In this notebook the concepts of `Increment`, `TimeStep`, `DiscreteField`, `ContinuousField`, `FieldSet`, `SpatialBasis` and `TemporalBasis` are intoduced. By combining these atomic structures one is able to form finite elements and interpolate it's fields in time and spatial domain.\n",
|
||||
"\n",
|
||||
"- `Increment` is the most atomic structure. It's a vector-like object with 1 dimension. Each element in `Increment` can be scalar, vector or tensor (2 or 4 order). It's easy to extend `Increment` to have other data types too.\n",
|
||||
"- `TimeStep` is container for increments in certain time $t$.\n",
|
||||
"- `Field` is container for timesteps for a single field.\n",
|
||||
"- `DefaultDiscreteField` is container for timesteps for a single field.\n",
|
||||
"- `FieldSet` is container for all fields.\n",
|
||||
"- `DefaultContinuousField` can have continuous field variables.\n",
|
||||
"\n",
|
||||
"## Revision history\n",
|
||||
"\n",
|
||||
@@ -86,8 +87,8 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dict{ASCIIString,JuliaFEM.AbstractField} with 1 entry:\n",
|
||||
" \"temperature\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[JuliaFEM.Inc…"
|
||||
"Dict{ASCIIString,JuliaFEM.Field} with 1 entry:\n",
|
||||
" \"temperature\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(1.0,JuliaFE…"
|
||||
]
|
||||
},
|
||||
"execution_count": 1,
|
||||
@@ -96,7 +97,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"using JuliaFEM: Increment, TimeStep, Field, FieldSet\n",
|
||||
"using JuliaFEM: Increment, TimeStep, Field, FieldSet, DefaultDiscreteField\n",
|
||||
"\n",
|
||||
"fs = FieldSet()\n",
|
||||
"i1 = Increment([1, 2, 3])\n",
|
||||
@@ -105,7 +106,7 @@
|
||||
"i3 = Increment([2, 3, 4])\n",
|
||||
"i4 = Increment([3, 4, 5])\n",
|
||||
"t2 = TimeStep(2.0, Increment[i3, i4])\n",
|
||||
"f1 = Field(TimeStep[t1, t2])\n",
|
||||
"f1 = DefaultDiscreteField(TimeStep[t1, t2])\n",
|
||||
"fs[\"temperature\"] = f1\n",
|
||||
"fs"
|
||||
]
|
||||
@@ -127,7 +128,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"([3,4,5],JuliaFEM.Increment{Int64})"
|
||||
"3-element JuliaFEM.Increment{Int64}:\n",
|
||||
" 3\n",
|
||||
" 4\n",
|
||||
" 5"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
@@ -136,8 +140,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"increment = fs[\"temperature\"][end][end]\n",
|
||||
"increment, typeof(increment)"
|
||||
"fs[\"temperature\"][2][2]"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -188,12 +191,12 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dict{ASCIIString,JuliaFEM.AbstractField} with 5 entries:\n",
|
||||
" \"fourth order tensor fi… => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"constant scalar field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"vector field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"scalar field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"second order tensor fi… => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…"
|
||||
"Dict{ASCIIString,JuliaFEM.Field} with 5 entries:\n",
|
||||
" \"fourth order tensor fi… => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(…\n",
|
||||
" \"constant scalar field\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(…\n",
|
||||
" \"vector field\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(…\n",
|
||||
" \"scalar field\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(…\n",
|
||||
" \"second order tensor fi… => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(…"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
@@ -228,10 +231,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dict{ASCIIString,JuliaFEM.AbstractField} with 3 entries:\n",
|
||||
" \"density\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[JuliaFEM.Inc…\n",
|
||||
" \"geometry\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[JuliaFEM.Inc…\n",
|
||||
" \"temperature\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[JuliaFEM.Inc…"
|
||||
"Dict{ASCIIString,JuliaFEM.Field} with 3 entries:\n",
|
||||
" \"density\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(0.0,JuliaFE…\n",
|
||||
" \"geometry\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(0.0,JuliaFE…\n",
|
||||
" \"temperature\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(0.0,JuliaFE…"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
@@ -287,26 +290,20 @@
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dict{ASCIIString,JuliaFEM.AbstractField} with 6 entries:\n",
|
||||
" \"fourth order tensor fi… => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"constant scalar field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"vector field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"scalar field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"time series\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"second order tensor fi… => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"INFO: time on last timestep: 1.0\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fs2[\"time series\"] = (0.0, [1, 2, 3, 4]), (0.5, [2, 3, 4, 5]), (1.0, [1, 1, 1, 1])\n",
|
||||
"fs2[\"time series\"][end].time\n",
|
||||
"fs2"
|
||||
"t0 = TimeStep(0.0, Increment([1, 2, 3, 4]))\n",
|
||||
"t1 = TimeStep(0.5, Increment([2, 3, 4, 5]))\n",
|
||||
"t2 = TimeStep(1.0, Increment([1, 1, 1, 1]))\n",
|
||||
"fs2[\"time series\"] = [t0, t1, t2]\n",
|
||||
"\n",
|
||||
"info(\"time on last timestep: $(fs2[\"time series\"][end].time)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -324,21 +321,16 @@
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dict{ASCIIString,JuliaFEM.AbstractField} with 7 entries:\n",
|
||||
" \"fourth order tensor fi… => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"constant scalar field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"vector field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"scalar field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"time series\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"time series 2\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…\n",
|
||||
" \"second order tensor fi… => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[J…"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
"ename": "LoadError",
|
||||
"evalue": "LoadError: MethodError: `convert` has no method matching convert(::Type{Float64}, ::Array{Int64,1})\nThis may have arisen from a call to the constructor Float64(...),\nsince type constructors fall back to convert methods.\nClosest candidates are:\n call{T}(::Type{T}, ::Any)\n convert(::Type{Float64}, !Matched::Int8)\n convert(::Type{Float64}, !Matched::Int16)\n ...\nwhile loading In[8], in expression starting on line 1",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"LoadError: MethodError: `convert` has no method matching convert(::Type{Float64}, ::Array{Int64,1})\nThis may have arisen from a call to the constructor Float64(...),\nsince type constructors fall back to convert methods.\nClosest candidates are:\n call{T}(::Type{T}, ::Any)\n convert(::Type{Float64}, !Matched::Int8)\n convert(::Type{Float64}, !Matched::Int16)\n ...\nwhile loading In[8], in expression starting on line 1",
|
||||
"",
|
||||
" in convert at /home/jukka/.julia/v0.4/JuliaFEM/src/fields.jl:205",
|
||||
" in call at essentials.jl:56",
|
||||
" in setindex! at dict.jl:641"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
@@ -363,9 +355,9 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"2-element Array{JuliaFEM.TimeStep{T},1}:\n",
|
||||
" JuliaFEM.Increment[[1,2,3,4]]\n",
|
||||
" JuliaFEM.Increment[[2,3,4,5]]"
|
||||
"2-element Array{JuliaFEM.TimeStep,1}:\n",
|
||||
" JuliaFEM.TimeStep(0.0,JuliaFEM.Increment[[1,2,3,4]])\n",
|
||||
" JuliaFEM.TimeStep(1.0,JuliaFEM.Increment[[2,3,4,5]])"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
@@ -375,7 +367,7 @@
|
||||
],
|
||||
"source": [
|
||||
"T0 = first(fs[\"temperature\"]) # pick first timestep (or to be spesific, last increment of first timestep)\n",
|
||||
"T1 = T0 + 1 # create new increment from old one\n",
|
||||
"T1 = Increment(T0 + 1) # create new increment from old one\n",
|
||||
"timestep = TimeStep(1.0, T1) # create new timestep at t=1.0\n",
|
||||
"push!(fs[\"temperature\"], timestep) # push to field"
|
||||
]
|
||||
@@ -533,7 +525,7 @@
|
||||
"source": [
|
||||
"### Creating continuous and discrete fields\n",
|
||||
"\n",
|
||||
"In the last section the concept of fields was demonstrated. The `Field` is actually just a typealias for a `DefaultDiscreteField` and `DefaultDiscreteField` is subtype of `DiscreteField` which is subtype of `AbstractField`:"
|
||||
"In previous section the concept of discrete fields was demonstrated. `DefaultDiscreteField` is subtype of `DiscreteField` which is subtype of `Field`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -555,8 +547,8 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"using JuliaFEM: AbstractField, DiscreteField\n",
|
||||
"Field <: DiscreteField <: AbstractField"
|
||||
"using JuliaFEM: DefaultDiscreteField, DiscreteField, Field\n",
|
||||
"DefaultDiscreteField <: DiscreteField <: Field"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -574,7 +566,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"using JuliaFEM: FieldSet, ContinuousField"
|
||||
"using JuliaFEM: FieldSet, DefaultContinuousField, ContinuousField"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -587,7 +579,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"MyFunnyField()"
|
||||
"MyContinuousField()"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
@@ -596,12 +588,12 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"type MyFunnyField <: ContinuousField\n",
|
||||
"type MyContinuousField <: ContinuousField\n",
|
||||
"end\n",
|
||||
"function Base.call(f::MyFunnyField, xi::Vector, time::Number)\n",
|
||||
"function Base.call(f::MyContinuousField, xi::Vector, time::Number)\n",
|
||||
" time/4*[(1-xi[1])*(1-xi[2]) (1+xi[1])*(1-xi[2]) (1+xi[1])*(1+xi[2]) (1-xi[1])*(1+xi[2])]\n",
|
||||
"end\n",
|
||||
"f = MyFunnyField()"
|
||||
"f = MyContinuousField()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -637,8 +629,8 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dict{ASCIIString,JuliaFEM.AbstractField} with 1 entry:\n",
|
||||
" \"basis\" => MyFunnyField()"
|
||||
"Dict{ASCIIString,JuliaFEM.Field} with 1 entry:\n",
|
||||
" \"basis\" => MyContinuousField()"
|
||||
]
|
||||
},
|
||||
"execution_count": 19,
|
||||
@@ -648,7 +640,7 @@
|
||||
],
|
||||
"source": [
|
||||
"fs = FieldSet()\n",
|
||||
"fs[\"basis\"] = MyFunnyField()\n",
|
||||
"fs[\"basis\"] = MyContinuousField()\n",
|
||||
"fs"
|
||||
]
|
||||
},
|
||||
@@ -679,7 +671,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Naturally we can pass another fields or even fieldsets to continuous field to make fields depend from each other. Here's another example, where `ContinuousField` takes another field and operates it with some function."
|
||||
"Again we have a shortcut to quickly define continuous fields:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -692,7 +684,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"call (generic function with 1246 methods)"
|
||||
"6.0"
|
||||
]
|
||||
},
|
||||
"execution_count": 21,
|
||||
@@ -701,11 +693,41 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"type MyFunnyContinuousField <: ContinuousField\n",
|
||||
"fs[\"continuous field\"] = (xi, t) -> xi[1]*xi[2]*t\n",
|
||||
"fs[\"continuous field\"]([1.0, 2.0], 3.0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Naturally we can pass another fields or even fieldsets to continuous field to make fields depend from each other. Here's another example, where `ContinuousField` takes another field and operates it with some function."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"call (generic function with 1259 methods)"
|
||||
]
|
||||
},
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"type MyContinuousField2 <: ContinuousField\n",
|
||||
" basis :: Function\n",
|
||||
" discrete_field :: DiscreteField\n",
|
||||
"end\n",
|
||||
"function Base.call(field::MyFunnyContinuousField, xi::Vector, time::Number=1.0)\n",
|
||||
"function Base.call(field::MyContinuousField2, xi::Vector, time::Number=1.0)\n",
|
||||
" data = last(field.discrete_field) # get the last timestep last increment\n",
|
||||
" basis = field.basis(xi) # evaluate basis at point ξ.\n",
|
||||
" sum([basis[i]*data[i] for i=1:length(data)]) # sum results\n",
|
||||
@@ -721,7 +743,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"execution_count": 23,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -729,10 +751,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"MyFunnyContinuousField(basis,JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[JuliaFEM.Increment[[1,2,3,4]]]))"
|
||||
"MyContinuousField2(basis,JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(0.0,JuliaFEM.Increment[[1,2,3,4]])]))"
|
||||
]
|
||||
},
|
||||
"execution_count": 22,
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -745,7 +767,7 @@
|
||||
" (1+xi[1])*(1-xi[2]),\n",
|
||||
" (1+xi[1])*(1+xi[2]),\n",
|
||||
" (1-xi[1])*(1+xi[2])]\n",
|
||||
"fs[\"continuous field\"] = MyFunnyContinuousField(basis, fs[\"discrete field\"])"
|
||||
"fs[\"continuous field\"] = MyContinuousField2(basis, fs[\"discrete field\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -757,7 +779,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"execution_count": 24,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -768,7 +790,7 @@
|
||||
"(2.5,[1,2,3,4])"
|
||||
]
|
||||
},
|
||||
"execution_count": 23,
|
||||
"execution_count": 24,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -786,7 +808,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"execution_count": 25,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -794,19 +816,19 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dict{ASCIIString,JuliaFEM.AbstractField} with 2 entries:\n",
|
||||
" \"continuous field\" => MyFunnyContinuousField(basis,JuliaFEM.DefaultDiscreteFi…\n",
|
||||
" \"discrete field\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[JuliaFE…"
|
||||
"Dict{ASCIIString,JuliaFEM.Field} with 2 entries:\n",
|
||||
" \"continuous field\" => MyContinuousField2(basis,JuliaFEM.DefaultDiscreteField(…\n",
|
||||
" \"discrete field\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(0.0,Ju…"
|
||||
]
|
||||
},
|
||||
"execution_count": 24,
|
||||
"execution_count": 25,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"T0 = last(fs[\"discrete field\"])\n",
|
||||
"push!(fs[\"discrete field\"], TimeStep(1.0, T0 + 1.0)) # push to field\n",
|
||||
"push!(fs[\"discrete field\"], TimeStep(1.0, Increment(T0 + 1.0))) # push to field\n",
|
||||
"fs"
|
||||
]
|
||||
},
|
||||
@@ -819,7 +841,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"execution_count": 26,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -827,10 +849,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(3.5,[2,3,4,5])"
|
||||
"(3.5,[2.0,3.0,4.0,5.0])"
|
||||
]
|
||||
},
|
||||
"execution_count": 25,
|
||||
"execution_count": 26,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -848,7 +870,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"execution_count": 27,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -859,7 +881,7 @@
|
||||
"(2.5,3.5)"
|
||||
]
|
||||
},
|
||||
"execution_count": 26,
|
||||
"execution_count": 27,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -877,7 +899,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 27,
|
||||
"execution_count": 28,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -888,28 +910,28 @@
|
||||
"getindex (generic function with 126 methods)"
|
||||
]
|
||||
},
|
||||
"execution_count": 27,
|
||||
"execution_count": 28,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"using JuliaFEM: DiscreteField\n",
|
||||
"type MyFunnyDiscreteField <: DiscreteField\n",
|
||||
"type MyDiscreteField <: DiscreteField\n",
|
||||
" discrete_points :: Vector\n",
|
||||
" continuous_field :: ContinuousField\n",
|
||||
"end\n",
|
||||
"Base.length(field::MyFunnyDiscreteField) = length(field.discrete_points)\n",
|
||||
"Base.endof(field::MyFunnyDiscreteField) = endof(field.discrete_points)\n",
|
||||
"Base.last(field::MyFunnyDiscreteField) = Float64[field[i] for i=1:length(field)]\n",
|
||||
"function Base.getindex(field::MyFunnyDiscreteField, idx::Int64)\n",
|
||||
"Base.length(field::MyDiscreteField) = length(field.discrete_points)\n",
|
||||
"Base.endof(field::MyDiscreteField) = endof(field.discrete_points)\n",
|
||||
"Base.last(field::MyDiscreteField) = Float64[field[i] for i=1:length(field)]\n",
|
||||
"function Base.getindex(field::MyDiscreteField, idx::Int64)\n",
|
||||
" field.continuous_field(field.discrete_points[idx])\n",
|
||||
"end"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 28,
|
||||
"execution_count": 29,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -924,14 +946,14 @@
|
||||
" 4.24402"
|
||||
]
|
||||
},
|
||||
"execution_count": 28,
|
||||
"execution_count": 29,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"discrete_points = 1.0/sqrt(3.0)*Vector[[-1, -1], [1, -1], [1, 1], [-1, 1]]\n",
|
||||
"fs[\"discrete field 2\"] = MyFunnyDiscreteField(discrete_points, fs[\"continuous field\"])\n",
|
||||
"fs[\"discrete field 2\"] = MyDiscreteField(discrete_points, fs[\"continuous field\"])\n",
|
||||
"last(fs[\"discrete field 2\"])"
|
||||
]
|
||||
},
|
||||
@@ -952,7 +974,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 29,
|
||||
"execution_count": 30,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -963,7 +985,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 30,
|
||||
"execution_count": 31,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -976,7 +998,7 @@
|
||||
" 0.2"
|
||||
]
|
||||
},
|
||||
"execution_count": 30,
|
||||
"execution_count": 31,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -996,7 +1018,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 31,
|
||||
"execution_count": 32,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -1008,7 +1030,7 @@
|
||||
" 0.25 0.25 0.25 0.25"
|
||||
]
|
||||
},
|
||||
"execution_count": 31,
|
||||
"execution_count": 32,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -1028,7 +1050,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 32,
|
||||
"execution_count": 33,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -1039,7 +1061,7 @@
|
||||
"([0.0,0.5,1.0,1.5,2.0],[0.0,0.125,0.5,1.125,2.0])"
|
||||
]
|
||||
},
|
||||
"execution_count": 32,
|
||||
"execution_count": 33,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -1051,28 +1073,6 @@
|
||||
"t, x"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 33,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"((0.0,0.0),(0.5,0.125),(1.0,0.5),(1.5,1.125),(2.0,2.0))"
|
||||
]
|
||||
},
|
||||
"execution_count": 33,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x2 = tuple(collect(zip(t, x))...)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 34,
|
||||
@@ -1093,7 +1093,14 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fs[\"particle position\"] = x2\n",
|
||||
"timesteps = TimeStep[]\n",
|
||||
"for (ti, xi) in zip(t, x)\n",
|
||||
" increment = Increment(xi)\n",
|
||||
" push!(timesteps, TimeStep(ti, increment))\n",
|
||||
"end\n",
|
||||
"\n",
|
||||
"#fs[\"particle position\"] = t, 1/2*t.^2\n",
|
||||
"fs[\"particle position\"] = timesteps\n",
|
||||
"temporalbasis = TemporalBasis((t) -> [1-t, t], (t) -> [-1, 1])\n",
|
||||
"call(fs[\"particle position\"], temporalbasis, 1.0)"
|
||||
]
|
||||
@@ -1105,6 +1112,29 @@
|
||||
"It's also possible to take time derivatives. To do so, call `Field` with `TemporalBasis`, time, and additional argument `Val{:derivative}`. Again, same example:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 35,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"1-element Array{Float64,1}:\n",
|
||||
" 1.0"
|
||||
]
|
||||
},
|
||||
"execution_count": 35,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"call(fs[\"particle position\"], temporalbasis, 1.0, Val{:derivative})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -1123,7 +1153,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 35,
|
||||
"execution_count": 36,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -1131,12 +1161,12 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Dict{ASCIIString,JuliaFEM.AbstractField} with 2 entries:\n",
|
||||
" \"geometry\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[JuliaFEM.In…\n",
|
||||
" \"displacement\" => JuliaFEM.DefaultDiscreteField(JuliaFEM.TimeStep[JuliaFEM.In…"
|
||||
"Dict{ASCIIString,JuliaFEM.Field} with 2 entries:\n",
|
||||
" \"geometry\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(0.0,JuliaF…\n",
|
||||
" \"displacement\" => JuliaFEM.DefaultDiscreteField([JuliaFEM.TimeStep(0.0,JuliaF…"
|
||||
]
|
||||
},
|
||||
"execution_count": 35,
|
||||
"execution_count": 36,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -1144,13 +1174,15 @@
|
||||
"source": [
|
||||
"fs = FieldSet()\n",
|
||||
"fs[\"geometry\"] = Vector{Float64}[[0.0,0.0], [1.0,0.0], [1.0,1.0], [0.0,1.0]]\n",
|
||||
"fs[\"displacement\"] = (0.0, zeros(2, 4)), (1.0, Vector[[0.0, 0.0], [0.0, 0.0], [0.25, 0.0], [0.0, 0.0]])\n",
|
||||
"u0 = TimeStep(0.0, Increment(zeros(2, 4)))\n",
|
||||
"u1 = TimeStep(1.0, Increment(Vector[[0.0, 0.0], [0.0, 0.0], [0.25, 0.0], [0.0, 0.0]]))\n",
|
||||
"fs[\"displacement\"] = [u0, u1]\n",
|
||||
"fs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 36,
|
||||
"execution_count": 37,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -1163,7 +1195,7 @@
|
||||
" 0.5 "
|
||||
]
|
||||
},
|
||||
"execution_count": 36,
|
||||
"execution_count": 37,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -1185,7 +1217,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 37,
|
||||
"execution_count": 38,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -1198,7 +1230,7 @@
|
||||
" 0.0 0.0 "
|
||||
]
|
||||
},
|
||||
"execution_count": 37,
|
||||
"execution_count": 38,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -1220,7 +1252,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 38,
|
||||
"execution_count": 39,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -1231,7 +1263,7 @@
|
||||
"FiniteElement"
|
||||
]
|
||||
},
|
||||
"execution_count": 38,
|
||||
"execution_count": 39,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -1263,17 +1295,17 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 39,
|
||||
"execution_count": 40,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "LoadError",
|
||||
"evalue": "LoadError: MethodError: `setindex!` has no method matching setindex!(::FiniteElement, ::Array{Array{Float64,1},1}, ::ASCIIString)\nwhile loading In[39], in expression starting on line 2",
|
||||
"evalue": "LoadError: MethodError: `setindex!` has no method matching setindex!(::FiniteElement, ::Array{Array{Float64,1},1}, ::ASCIIString)\nwhile loading In[40], in expression starting on line 2",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"LoadError: MethodError: `setindex!` has no method matching setindex!(::FiniteElement, ::Array{Array{Float64,1},1}, ::ASCIIString)\nwhile loading In[39], in expression starting on line 2",
|
||||
"LoadError: MethodError: `setindex!` has no method matching setindex!(::FiniteElement, ::Array{Array{Float64,1},1}, ::ASCIIString)\nwhile loading In[40], in expression starting on line 2",
|
||||
""
|
||||
]
|
||||
}
|
||||
@@ -1295,6 +1327,15 @@
|
||||
"strain_rate = diff(strain)\n",
|
||||
"strain_rate([0.0, 0.0], 1.0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
||||
@@ -47,30 +47,6 @@
|
||||
"- variational form, \"principle of minimum potential energy\": there exists some functional or \"potential function\" $\\Pi$ we are minimizing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Logger(root,DEBUG,Base.PipeEndpoint(open, 0 bytes waiting),root)"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"using Logging\n",
|
||||
"using FactCheck\n",
|
||||
"Logging.configure(level=DEBUG)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -89,13 +65,13 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 69,
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"using JuliaFEM: Element, Field, FieldSet, Basis"
|
||||
"using JuliaFEM: Element, Basis, FieldSet"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -107,7 +83,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -116,7 +92,7 @@
|
||||
"type MyQuad4 <: Element\n",
|
||||
" connectivity :: Array{Int, 1}\n",
|
||||
" basis :: Basis\n",
|
||||
" fields :: Dict{ASCIIString, FieldSet}\n",
|
||||
" fields :: FieldSet\n",
|
||||
"end"
|
||||
]
|
||||
},
|
||||
@@ -129,7 +105,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -140,7 +116,7 @@
|
||||
"MyQuad4"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -165,7 +141,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -173,10 +149,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"size (generic function with 74 methods)"
|
||||
"size (generic function with 81 methods)"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -192,6 +168,68 @@
|
||||
"Here comes one important thing. We always define our \"things\" so that the first index is dimension, like $(x, y, z)$ or $(\\xi_1, \\xi_2, \\xi_3)$ and second index is basis function number / node id or something similar to that. To motivate this, consider the following example:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"2x4 Array{Int64,2}:\n",
|
||||
" 1 3 5 7\n",
|
||||
" 2 4 6 8"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x = [1 2; 3 4; 5 6; 7 8]'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here, if we consider $x$ as of some field e.g. geometry, our coordinates of first node is $(1, 2)$, second is $(3, 4)$ and so on. Typically on vector field problems the global assembly is something like $(u_1, v_1, u_2, v_2, \\ldots, )$. If fields are defined this way we can easily flatten matrix to vector and back:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"8-element Array{Int64,1}:\n",
|
||||
" 1\n",
|
||||
" 2\n",
|
||||
" 3\n",
|
||||
" 4\n",
|
||||
" 5\n",
|
||||
" 6\n",
|
||||
" 7\n",
|
||||
" 8"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"dim = size(x)\n",
|
||||
"x2 = vec(x)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
@@ -212,68 +250,6 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"x = [1 2; 3 4; 5 6; 7 8]'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Here, if we consider $x$ as of some field e.g. geometry, our coordinates of first node is $(1, 2)$, second is $(3, 4)$ and so on. Typically on vector field problems the global assembly is something like $(u_1, v_1, u_2, v_2, \\ldots, )$. If fields are defined this way we can easily flatten matrix to vector and back:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"8-element Array{Int64,1}:\n",
|
||||
" 1\n",
|
||||
" 2\n",
|
||||
" 3\n",
|
||||
" 4\n",
|
||||
" 5\n",
|
||||
" 6\n",
|
||||
" 7\n",
|
||||
" 8"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"dim = size(x)\n",
|
||||
"x2 = vec(x)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"2x4 Array{Int64,2}:\n",
|
||||
" 1 3 5 7\n",
|
||||
" 2 4 6 8"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"reshape(x2, dim)"
|
||||
]
|
||||
@@ -287,7 +263,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -317,7 +293,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
@@ -326,15 +302,22 @@
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"28-Oct 04:26:43:INFO:root:Testing element MyQuad4\n",
|
||||
"28-Oct 04:26:43:INFO:root:element dimension: 2 x 4\n",
|
||||
"28-Oct 04:26:43:INFO:root:Initializing element\n",
|
||||
"28-Oct 04:26:43:INFO:root:basis at [0.0,0.0]: [0.25 0.25 0.25 0.25]\n",
|
||||
"28-Oct 04:26:43:INFO:root:field val at [0.0,0.0]: 2.5\n",
|
||||
"28-Oct 04:26:43:INFO:root:derivative of basis at [0.0,0.0]: [-0.5 0.5 0.5 -0.5\n",
|
||||
" -0.5 -0.5 0.5 0.5]\n",
|
||||
"28-Oct 04:26:43:INFO:root:field val at [0.0,0.0]: [0.0 2.0]\n",
|
||||
"28-Oct 04:26:43:INFO:root:Element MyQuad4 passed tests.\n"
|
||||
"INFO: Testing element MyQuad4\n",
|
||||
"INFO: element dimension: 2 x 4\n",
|
||||
"INFO: Initializing element\n",
|
||||
"INFO: basis at [0.0,0.0]: [0.25 0.25 0.25 0.25]\n",
|
||||
"INFO: field val at [0.0,0.0]: 0.0\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"ename": "LoadError",
|
||||
"evalue": "LoadError: MethodError: `inv` has no method matching inv(::Array{Float64,1})\nwhile loading In[9], in expression starting on line 2",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"LoadError: MethodError: `inv` has no method matching inv(::Array{Float64,1})\nwhile loading In[9], in expression starting on line 2",
|
||||
"",
|
||||
" in call at /home/jukka/.julia/v0.4/JuliaFEM/src/elements.jl:147",
|
||||
" in test_element at /home/jukka/.julia/v0.4/JuliaFEM/src/elements.jl:57"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -1291,6 +1274,7 @@
|
||||
" u = basis(\"displacement\", ip, time, variation)\n",
|
||||
" ∇u = dbasis(\"displacement\", ip, time, variation)\n",
|
||||
" F = I + ∇u\n",
|
||||
" # F = F_e*F_p\n",
|
||||
" b = basis(\"displacement volume load\", ip, time)\n",
|
||||
" E = 1/2*(F'*F - I)\n",
|
||||
" S = λ*trace(E)*I + 2*μ*E\n",
|
||||
|
||||
+8
-1
@@ -11,6 +11,9 @@ module JuliaFEM
|
||||
#using Lexicon
|
||||
|
||||
macro debug(msg)
|
||||
if !haskey(ENV, "JuliaFEM_LOG_LEVEL")
|
||||
return :()
|
||||
end
|
||||
return :( println("DEBUG: ", $msg) )
|
||||
end
|
||||
|
||||
@@ -32,8 +35,10 @@ function Base.linspace{T<:Array}(X1::T, X2::T, n)
|
||||
[1/2*(1-ti)*X1 + 1/2*(1+ti)*X2 for ti in linspace(-1, 1, n)]
|
||||
end
|
||||
|
||||
|
||||
include("fields.jl") # fields, see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/notebooks/2015-06-14-data-structures.ipynb
|
||||
include("basis.jl") # interpolation of discrete fields
|
||||
include("types.jl") # type definitions
|
||||
#include("interpolate.jl") # interpolation routines
|
||||
|
||||
### ELEMENTS ###
|
||||
include("elements.jl")
|
||||
@@ -58,6 +63,8 @@ include("solvers.jl")
|
||||
include("xdmf.jl")
|
||||
include("abaqus_reader.jl")
|
||||
|
||||
include("test.jl")
|
||||
|
||||
end # module
|
||||
|
||||
FEM = JuliaFEM
|
||||
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
abstract AbstractBasis
|
||||
|
||||
""" Defined to dimensionless coordinate ξ∈[-1,1]^n. """
|
||||
type SpatialBasis <: AbstractBasis
|
||||
basis :: Function
|
||||
dbasisdxi :: Function
|
||||
end
|
||||
|
||||
typealias Basis SpatialBasis
|
||||
|
||||
""" Defined to to interval t∈[0, 1]. """
|
||||
type TemporalBasis <: AbstractBasis
|
||||
basis :: Function
|
||||
dbasisdt :: Function
|
||||
end
|
||||
function TemporalBasis()
|
||||
basis(t) = [1-t, t]
|
||||
dbasis(t) = [-1, 1]
|
||||
return TemporalBasis(basis, dbasis)
|
||||
end
|
||||
|
||||
function call(b::TemporalBasis, value::Number)
|
||||
b.basis(value)
|
||||
end
|
||||
|
||||
function call(b::SpatialBasis, value::Vector)
|
||||
b.basis(value)
|
||||
end
|
||||
|
||||
### INTERPOLATION IN TIME DOMAIN ###
|
||||
|
||||
function Base.call(field::Field, basis::TemporalBasis, time)
|
||||
# FieldSet -> Field -> TimeStep -> Increment -> data
|
||||
# special cases, -Inf, +Inf and ~0.0
|
||||
if time > field[end].time
|
||||
return field[end][end]
|
||||
end
|
||||
if (time < field[1].time) || abs(time-field[1].time) < 1.0e-12
|
||||
return field[1][end]
|
||||
end
|
||||
i = length(field)
|
||||
while field[i].time >= time
|
||||
i -= 1
|
||||
end
|
||||
field[i].time == time && return field[i][end]
|
||||
t1 = field[i].time
|
||||
t2 = field[i+1].time
|
||||
inc1 = field[i][end]
|
||||
inc2 = field[i+1][end]
|
||||
# TODO: may there be some reasons for "unphysical" jumps in
|
||||
# fields w.r.t time which should be taken account in some way?
|
||||
# i.e. dt between two fields → 0
|
||||
dt = t2 - t1
|
||||
b = basis.basis((time-t1)/dt)
|
||||
r = Increment[inc1, inc2]
|
||||
return dot(b, r)
|
||||
end
|
||||
function Base.call(field::DiscreteField, time)
|
||||
return Base.call(field, TemporalBasis(), time)
|
||||
end
|
||||
|
||||
function Base.call(field::Field, basis::TemporalBasis, time,
|
||||
derivative::Type{Val{:derivative}})
|
||||
# FieldSet -> Field -> TimeStep -> Increment -> data
|
||||
|
||||
if length(field) == 1
|
||||
# just one timestep, time derivative cannot be evaluated.
|
||||
error("Field length = $(length(field)), cannot evaluate time derivative")
|
||||
end
|
||||
|
||||
function eval_field(i, j)
|
||||
timesteps = TimeStep[field[i], field[j]]
|
||||
increments = Increment[timesteps[1][end], timesteps[2][end]]
|
||||
J = norm(timesteps[2].time - timesteps[1].time)
|
||||
dbasisdt = basis.dbasisdt( (time-timesteps[1].time)/J )
|
||||
return dot(dbasisdt, increments)/J
|
||||
end
|
||||
|
||||
# special cases, +Inf, -Inf, ~0.0
|
||||
if (time > field[end].time) || isapprox(time, field[end].time)
|
||||
return eval_field(endof(field)-1, endof(field))
|
||||
end
|
||||
if (time < field[1].time) || isapprox(time, field[1].time)
|
||||
return eval_field(1, 2)
|
||||
end
|
||||
|
||||
# search for a correct "bin" between time steps
|
||||
i = length(field)
|
||||
while (field[i].time > time) && !isapprox(field[i].time, time)
|
||||
i -= 1
|
||||
end
|
||||
|
||||
if isapprox(field[i].time, time)
|
||||
# This is the hard case, maybe discontinuous time
|
||||
# derivative if linear approximation.
|
||||
# we are on the "mid node" in time axis
|
||||
field1 = eval_field(i-1,i)
|
||||
field2 = eval_field(i,i+1)
|
||||
return 1/2*(field1 + field2)
|
||||
end
|
||||
|
||||
return eval_field(i, i+1)
|
||||
|
||||
end
|
||||
|
||||
### INTERPOLATION IN SPATIAL DOMAIN ###
|
||||
|
||||
function Base.call(increment::Increment, basis::SpatialBasis, xi::Vector)
|
||||
basis = basis.basis(xi)
|
||||
sum([basis[i]*increment[i] for i=1:length(increment)])
|
||||
end
|
||||
|
||||
function Base.call(increment::Increment, basis::SpatialBasis, xi::Vector,
|
||||
geometry::Increment, gradient::Type{Val{:gradient}})
|
||||
dbasis = basis.dbasisdxi(xi)
|
||||
J = sum([dbasis[:,i]*geometry[i]' for i=1:length(geometry)])
|
||||
grad = inv(J)*dbasis
|
||||
gradf = sum([grad[:,i]*increment[i]' for i=1:length(increment)])'
|
||||
return gradf
|
||||
end
|
||||
|
||||
+12
-11
@@ -20,22 +20,22 @@ Raises
|
||||
This uses FactCheck and throws exceptions if element is not passing all tests.
|
||||
"""
|
||||
function test_element(element_type)
|
||||
Logging.info("Testing element $element_type")
|
||||
info("Testing element $element_type")
|
||||
local element
|
||||
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.")
|
||||
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")
|
||||
info("element dimension: $dim x $n")
|
||||
|
||||
Logging.info("Initializing element")
|
||||
info("Initializing element")
|
||||
try
|
||||
element = element_type(collect(1:n))
|
||||
catch
|
||||
Logging.error("""
|
||||
error("""
|
||||
Unable to create element with default constructor define function
|
||||
$eltype(connectivity) which initializes this element.""")
|
||||
return false
|
||||
@@ -51,15 +51,15 @@ function test_element(element_type)
|
||||
dbasis = grad(basis)
|
||||
mid = zeros(dim)
|
||||
val1 = basis(mid, 0.0)
|
||||
Logging.info("basis at $mid: $val1")
|
||||
info("basis at $mid: $val1")
|
||||
val2 = basis("field1", mid, 0.0)
|
||||
Logging.info("field val at $mid: $val2")
|
||||
info("field val at $mid: $val2")
|
||||
val3 = dbasis(mid, 0.0)
|
||||
Logging.info("derivative of basis at $mid: $val3")
|
||||
info("derivative of basis at $mid: $val3")
|
||||
val4 = dbasis("field1", mid, 0.0)
|
||||
Logging.info("field val at $mid: $val4")
|
||||
info("field val at $mid: $val4")
|
||||
|
||||
Logging.info("Element $element_type passed tests.")
|
||||
info("Element $element_type passed tests.")
|
||||
end
|
||||
|
||||
""" Get FieldSet from element. """
|
||||
@@ -75,7 +75,8 @@ Examples
|
||||
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])])))
|
||||
"""
|
||||
function Base.setindex!(element::Element, field_data, field_name)
|
||||
element.fields[field_name] = field_data
|
||||
#element.fields[field_name] = field_data
|
||||
setindex!(element.fields, field_data, field_name)
|
||||
end
|
||||
|
||||
function get_connectivity(el::Element)
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM: Basis, Field, FieldSet, diff
|
||||
|
||||
|
||||
"""
|
||||
Interpolate field u using basis N in point xi.
|
||||
"""
|
||||
function interpolate{T}(N::Basis, u::Field{Vector{T}}, xi::Array{Float64,1})
|
||||
N(xi)*u
|
||||
end
|
||||
"""
|
||||
Interpolate field u using basis N in set of points xi. Convenient function.
|
||||
"""
|
||||
function interpolate{T}(N::Basis, u::Field{Vector{T}}, xis::Array{Array{Float64,1},1})
|
||||
T[N(xi)*u for xi in xis]
|
||||
end
|
||||
function interpolate{T}(N::Basis, u::Field{T}, xi::Array{Float64,1})
|
||||
u.values
|
||||
end
|
||||
|
||||
"""
|
||||
Interpolate a field from fieldset for some time t.
|
||||
"""
|
||||
function interpolate(fields::FieldSet, t::Number)
|
||||
if length(fields) == 0
|
||||
throw("Empty set of fields: $fields")
|
||||
end
|
||||
if t <= fields[1].time
|
||||
return Field(t, fields[1].values)
|
||||
end
|
||||
if t >= fields[end].time
|
||||
return Field(t, fields[end].values)
|
||||
end
|
||||
i = length(fields)
|
||||
while fields[i].time >= t
|
||||
i -= 1
|
||||
end
|
||||
if fields[i].time == t
|
||||
return fields[i]
|
||||
end
|
||||
#Logging.debug("doing linear interpolation between fields $i and $(i+1)")
|
||||
f1 = fields[i]
|
||||
t1 = f1.time
|
||||
f2 = fields[i+1]
|
||||
t2 = f2.time
|
||||
dt = t2 - t1
|
||||
nw = (t2-t)/dt*f1.values + (t-t1)/dt*f2.values
|
||||
f = Field(t, nw)
|
||||
return f
|
||||
end
|
||||
|
||||
function call(fieldset::FieldSet, time::Number)
|
||||
interpolate(fieldset, time)
|
||||
end
|
||||
|
||||
function interpolate(basis::Basis, field::Field, ip::IntegrationPoint)
|
||||
interpolate(basis, field, ip.xi)
|
||||
end
|
||||
|
||||
#function dinterpolate(basis::Basis, u::Field, xi::Array{Float64, 1})
|
||||
# basis.dbasisdxi(xi)*u
|
||||
#end
|
||||
|
||||
-267
@@ -1,273 +1,6 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/notebooks/2015-06-14-data-structures.ipynb
|
||||
|
||||
#abstract AbstractField{T,N} <: AbstractArray{T,N}
|
||||
|
||||
abstract AbstractField
|
||||
|
||||
abstract DiscreteField <: AbstractField
|
||||
|
||||
abstract ContinuousField <: AbstractField
|
||||
abstract TimeContinuousField <: ContinuousField
|
||||
abstract SpatialContinuousField <: ContinuousField
|
||||
abstract TimeAndSpatialContinuousField <: ContinuousField
|
||||
# should we introduce time and spatial discontinuous fields
|
||||
# for discontinuous galerkin?
|
||||
|
||||
### DEFAULT DISCRETE FIELD ###
|
||||
|
||||
# 1. Increment
|
||||
|
||||
# FIXME: This should be Vector.
|
||||
#typealias Increment Vector
|
||||
type Increment{T} <: AbstractVector{T}
|
||||
data :: Vector{T}
|
||||
end
|
||||
Base.size(increment::Increment) = Base.size(increment.data)
|
||||
Base.linearindexing(::Type{Increment}) = Base.LinearFast()
|
||||
Base.getindex(increment::Increment, i::Int) = increment.data[i]
|
||||
Base.setindex!(increment::Increment, v, i::Int) = (increment.data[i] = v)
|
||||
Base.similar{T}(increment::Increment, ::Type{T}) = Increment(similar(increment.data))
|
||||
Base.dot(v::Number, i::Increment) = v*i
|
||||
|
||||
function Base.convert(::Type{Increment}, data::Number)
|
||||
Increment([data])
|
||||
end
|
||||
function Base.convert{T}(::Type{Increment}, data::Array{T, 2})
|
||||
Increment([data[:,i] for i=1:size(data, 2)])
|
||||
end
|
||||
function Base.convert{T}(::Type{Increment}, data::Array{T, 3})
|
||||
Increment([data[:,:,i] for i=1:size(data, 3)])
|
||||
end
|
||||
function Base.convert{T}(::Type{Increment}, data::Array{T, 4})
|
||||
Increment([data[:,:,:,i] for i=1:size(data, 4)])
|
||||
end
|
||||
function Base.convert{T}(::Type{Increment}, data::Array{T, 5})
|
||||
Increment([data[:,:,:,:,i] for i=1:size(data, 5)])
|
||||
end
|
||||
function Base.zeros(::Type{Increment}, dims...)
|
||||
Increment(zeros(dims...))
|
||||
end
|
||||
function Base.vec(increment::Increment)
|
||||
[increment.data...;]
|
||||
end
|
||||
function Base.similar{T}(increment::Increment{Vector{T}}, data::Vector{T})
|
||||
Increment(reshape(data, round(Int, length(data)/length(increment)), length(increment)))
|
||||
end
|
||||
|
||||
# 2. TimeStep
|
||||
|
||||
type TimeStep{T} <: AbstractVector{T}
|
||||
time :: Float64
|
||||
increments :: Vector{T}
|
||||
end
|
||||
Base.size(timestep::TimeStep) = Base.size(timestep.increments)
|
||||
Base.linearindexing(::Type{TimeStep}) = Base.LinearFast()
|
||||
Base.getindex(timestep::TimeStep, i::Int) = timestep.increments[i]
|
||||
|
||||
function Base.convert(::Type{TimeStep}, time::Number, increment::Increment)
|
||||
TimeStep(time, Increment[increment])
|
||||
end
|
||||
|
||||
function Base.push!(timestep::TimeStep, increment::Increment)
|
||||
push!(timestep.increments, increment)
|
||||
end
|
||||
|
||||
# 3. DefaultDiscreteField
|
||||
|
||||
type DefaultDiscreteField <: DiscreteField
|
||||
timesteps :: Vector{TimeStep}
|
||||
end
|
||||
Base.size(field::DefaultDiscreteField) = Base.size(field.timesteps)
|
||||
Base.linearindexing(::Type{DefaultDiscreteField}) = Base.LinearFast()
|
||||
Base.getindex(field::DefaultDiscreteField, i::Int) = field.timesteps[i]
|
||||
Base.length(field::DefaultDiscreteField) = length(field.timesteps)
|
||||
Base.endof(field::DefaultDiscreteField) = endof(field.timesteps)
|
||||
Base.first(field::DefaultDiscreteField) = field[1][end]
|
||||
Base.last(field::DefaultDiscreteField) = field[end][end]
|
||||
function Base.push!(field::DefaultDiscreteField, timestep::TimeStep)
|
||||
push!(field.timesteps, timestep)
|
||||
end
|
||||
|
||||
|
||||
typealias Field DefaultDiscreteField
|
||||
|
||||
### CONTINUOUS FIELDS ###
|
||||
|
||||
|
||||
# fix print_matrix
|
||||
#function Base.print_matrix(::Base.AbstractIOBuffer, field::ContinuousField, args...)
|
||||
# TODO: anything nice to print?
|
||||
#end
|
||||
|
||||
### FIELDSET ###
|
||||
|
||||
typealias FieldSet Dict{ASCIIString, AbstractField}
|
||||
|
||||
"""Quicky add discrete field to fieldset.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> fs = FieldSet()
|
||||
>>> fs["myfield"] = [1, 2, 3, 4]
|
||||
"""
|
||||
function Base.convert(::Type{AbstractField}, data::Union{Array, Number})
|
||||
increment = Increment(data)
|
||||
timestep = TimeStep(0.0, Increment[increment])
|
||||
field = DefaultDiscreteField(TimeStep[timestep])
|
||||
return field
|
||||
end
|
||||
|
||||
""" Quicky add several time steps at once in tuple.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> fs = FieldSet()
|
||||
>>> fs["myfield"] = (0.0, [1, 2, 3, 4]), (0.5, [2, 3, 4, 5])
|
||||
|
||||
or
|
||||
|
||||
>>> fs["myfield"] = [1, 2, 3, 4], [2, 3, 4, 5]
|
||||
|
||||
"""
|
||||
function Base.convert(::Type{AbstractField}, data::Tuple)
|
||||
timesteps = TimeStep[]
|
||||
for (i, timestep) in enumerate(data)
|
||||
if isa(timestep, Tuple)
|
||||
push!(timesteps, TimeStep(Float64(timestep[1]), Increment(timestep[2])))
|
||||
else
|
||||
push!(timesteps, TimeStep(Float64(i-1), Increment(timestep)))
|
||||
end
|
||||
end
|
||||
return DefaultDiscreteField(timesteps)
|
||||
end
|
||||
|
||||
### BASIS ###
|
||||
|
||||
abstract AbstractBasis
|
||||
|
||||
""" Defined to dimensionless coordinate ξ∈[-1,1]^n. """
|
||||
type SpatialBasis <: AbstractBasis
|
||||
basis :: Function
|
||||
dbasisdxi :: Function
|
||||
end
|
||||
|
||||
typealias Basis SpatialBasis
|
||||
|
||||
""" Defined to to interval t∈[0, 1]. """
|
||||
type TemporalBasis <: AbstractBasis
|
||||
basis :: Function
|
||||
dbasisdt :: Function
|
||||
end
|
||||
function TemporalBasis()
|
||||
basis(t) = [1-t, t]
|
||||
dbasis(t) = [-1, 1]
|
||||
return TemporalBasis(basis, dbasis)
|
||||
end
|
||||
|
||||
function call(b::TemporalBasis, value::Number)
|
||||
b.basis(value)
|
||||
end
|
||||
|
||||
function call(b::SpatialBasis, value::Vector)
|
||||
b.basis(value)
|
||||
end
|
||||
|
||||
### INTERPOLATION IN TIME DOMAIN ###
|
||||
|
||||
function Base.call(field::Field, basis::TemporalBasis, time)
|
||||
# FieldSet -> Field -> TimeStep -> Increment -> data
|
||||
# special cases, -Inf, +Inf and ~0.0
|
||||
if time > field[end].time
|
||||
return field[end][end]
|
||||
end
|
||||
if (time < field[1].time) || abs(time-field[1].time) < 1.0e-12
|
||||
return field[1][end]
|
||||
end
|
||||
i = length(field)
|
||||
while field[i].time >= time
|
||||
i -= 1
|
||||
end
|
||||
field[i].time == time && return field[i][end]
|
||||
t1 = field[i].time
|
||||
t2 = field[i+1].time
|
||||
inc1 = field[i][end]
|
||||
inc2 = field[i+1][end]
|
||||
# TODO: may there be some reasons for "unphysical" jumps in
|
||||
# fields w.r.t time which should be taken account in some way?
|
||||
# i.e. dt between two fields → 0
|
||||
dt = t2 - t1
|
||||
b = basis.basis((time-t1)/dt)
|
||||
r = Increment[inc1, inc2]
|
||||
return dot(b, r)
|
||||
end
|
||||
function Base.call(field::DiscreteField, time)
|
||||
return Base.call(field, TemporalBasis(), time)
|
||||
end
|
||||
|
||||
function Base.call(field::Field, basis::TemporalBasis, time,
|
||||
derivative::Type{Val{:derivative}})
|
||||
# FieldSet -> Field -> TimeStep -> Increment -> data
|
||||
|
||||
if length(field) == 1
|
||||
# just one timestep, time derivative cannot be evaluated.
|
||||
error("Field length = $(length(field)), cannot evaluate time derivative")
|
||||
end
|
||||
|
||||
function eval_field(i, j)
|
||||
timesteps = TimeStep[field[i], field[j]]
|
||||
increments = Increment[timesteps[1][end], timesteps[2][end]]
|
||||
J = norm(timesteps[2].time - timesteps[1].time)
|
||||
dbasisdt = basis.dbasisdt( (time-timesteps[1].time)/J )
|
||||
return dot(dbasisdt, increments)/J
|
||||
end
|
||||
|
||||
# special cases, +Inf, -Inf, ~0.0
|
||||
if (time > field[end].time) || isapprox(time, field[end].time)
|
||||
return eval_field(endof(field)-1, endof(field))
|
||||
end
|
||||
if (time < field[1].time) || isapprox(time, field[1].time)
|
||||
return eval_field(1, 2)
|
||||
end
|
||||
|
||||
# search for a correct "bin" between time steps
|
||||
i = length(field)
|
||||
#while field[i].time >= time + 1.0e-12
|
||||
while (field[i].time > time) && !isapprox(field[i].time, time)
|
||||
i -= 1
|
||||
end
|
||||
|
||||
if isapprox(field[i].time, time)
|
||||
# This is the hard case, maybe discontinuous time
|
||||
# derivative if linear approximation.
|
||||
# we are on the "mid node" in time axis
|
||||
field1 = eval_field(i-1,i)
|
||||
field2 = eval_field(i,i+1)
|
||||
return 1/2*(field1 + field2)
|
||||
end
|
||||
|
||||
return eval_field(i, i+1)
|
||||
|
||||
end
|
||||
|
||||
### INTERPOLATION IN SPATIAL DOMAIN ###
|
||||
|
||||
function Base.call(increment::Increment, basis::SpatialBasis, xi::Vector)
|
||||
basis = basis.basis(xi)
|
||||
sum([basis[i]*increment[i] for i=1:length(increment)])
|
||||
end
|
||||
|
||||
function Base.call(increment::Increment, basis::SpatialBasis, xi::Vector,
|
||||
geometry::Increment, gradient::Type{Val{:gradient}})
|
||||
dbasis = basis.dbasisdxi(xi)
|
||||
J = sum([dbasis[:,i]*geometry[i]' for i=1:length(geometry)])
|
||||
grad = inv(J)*dbasis
|
||||
gradf = sum([grad[:,i]*increment[i]' for i=1:length(increment)])'
|
||||
return gradf
|
||||
end
|
||||
|
||||
### INTEGRATIONPOINT ###
|
||||
|
||||
"""
|
||||
|
||||
+37
-3
@@ -5,11 +5,13 @@
|
||||
|
||||
|
||||
using JuliaFEM
|
||||
using FactCheck
|
||||
using Logging
|
||||
@Logging.configure(level=DEBUG)
|
||||
using JuliaFEM.Test
|
||||
|
||||
#using FactCheck
|
||||
#using Logging
|
||||
#@Logging.configure(level=DEBUG)
|
||||
|
||||
#=
|
||||
facts("Testing if somebody used print, println(), @sprint in src directory") do
|
||||
# TODO: make better reqular expression. Currently it will match all print words
|
||||
lines_with_print = Dict()
|
||||
@@ -77,6 +79,7 @@ facts("Looking the [src,test] folders *.jl files header information") do
|
||||
@fact files_no_license => isempty out_str
|
||||
end
|
||||
|
||||
#=
|
||||
test_files = readdir(Pkg.dir("JuliaFEM")*"/test")
|
||||
for test_file in test_files
|
||||
Logging.info("checking is $test_file is real test file")
|
||||
@@ -85,6 +88,7 @@ for test_file in test_files
|
||||
include(test_file)
|
||||
end
|
||||
end
|
||||
=#
|
||||
|
||||
# Keep this at the end of this file (include statements above this)
|
||||
@Logging.configure(level=DEBUG)
|
||||
@@ -92,3 +96,33 @@ end
|
||||
for dic in FactCheck.getstats()
|
||||
@debug(dic[1], ": ",dic[2])
|
||||
end
|
||||
=#
|
||||
|
||||
|
||||
### NEW STYLE OF TESTING
|
||||
|
||||
using JuliaFEM.Test
|
||||
|
||||
function run_tests()
|
||||
|
||||
for test_file in readdir(Pkg.dir("JuliaFEM")*"/test")
|
||||
info("checking is $test_file is real test file")
|
||||
if (startswith(test_file, "test_")) & (endswith(test_file, ".jl"))
|
||||
run_test(test_file)
|
||||
end
|
||||
end
|
||||
|
||||
passed, failed, errors, critical = print_test_statistics()
|
||||
|
||||
# at the very end throw error if something is failed
|
||||
if failed + errors critical != 0
|
||||
error("Some tests has failed. Fix them. Now.")
|
||||
exit(1)
|
||||
else
|
||||
info("""All tests has passed \o/ .""")
|
||||
exit(0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
run_tests()
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
module BasisTests
|
||||
|
||||
using JuliaFEM.Test
|
||||
|
||||
using JuliaFEM: get_basis, grad, FieldSet, Field, Quad4
|
||||
|
||||
|
||||
"""basic continuum interpolations"""
|
||||
function test_basic_interpolations()
|
||||
|
||||
element = Quad4([1, 2, 3, 4])
|
||||
|
||||
element["geometry"] = Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
|
||||
element["temperature"] = ([0.0, 0.0, 0.0, 0.0], [1.0, 2.0, 3.0, 4.0])
|
||||
element["displacement"] = (
|
||||
Vector[[0.0, 0.0], [0.0, 0.0], [0.00, 0.0], [0.0, 0.0]],
|
||||
Vector[[0.0, 0.0], [0.0, 0.0], [0.25, 0.0], [0.0, 0.0]])
|
||||
|
||||
# from my old home works
|
||||
basis = get_basis(element)
|
||||
dbasis = grad(basis)
|
||||
@test isapprox(basis("geometry", [0.0, 0.0], 1.0) + basis("displacement", [0.0, 0.0], 1.0), [9/16, 1/2])
|
||||
gradu = dbasis("displacement", [0.0, 0.0], 1.0)
|
||||
epsilon = 1/2*(gradu + gradu')
|
||||
rotation = 1/2*(gradu - gradu')
|
||||
X = basis("geometry", [0.0, 0.0], 1.0)
|
||||
k = 0.25
|
||||
epsilon_wanted = [X[2]*k 1/2*X[1]*k; 1/2*X[1]*k 0]
|
||||
rotation_wanted = [0 k/2*X[1]; -k/2*X[1] 0]
|
||||
@test isapprox(epsilon, epsilon_wanted)
|
||||
@test isapprox(rotation, rotation_wanted)
|
||||
F = I + gradu
|
||||
@test isapprox(F, [X[2]*k+1 X[1]*k; 0 1])
|
||||
C = F'*F
|
||||
@test isapprox(C, [(X[2]*k+1)^2 (X[2]*k+1)*X[1]*k; (X[2]*k+1)*X[1]*k X[1]^2*k^2+1])
|
||||
E = 1/2*(F'*F - I)
|
||||
@test isapprox(E, [1/2*(X[2]*k + 1)^2-1/2 1/2*(X[2]*k+1)*X[1]*k; 1/2*(X[2]*k + 1)*X[1]*k 1/2*X[1]^2*k^2])
|
||||
U = 1/sqrt(trace(C) + 2*sqrt(det(C)))*(C + sqrt(det(C))*I)
|
||||
@test isapprox(U, [1.24235 0.13804; 0.13804 1.02149])
|
||||
end
|
||||
|
||||
function test_interpolation_in_temporal_basis()
|
||||
info("testing interpolation on temporal basis")
|
||||
temporalbasis = TemporalBasis((t) -> [1-t, t], (t) -> [-1, 1])
|
||||
@test temporalbasis(0.2) == [0.8, 0.2]
|
||||
i1 = Increment([0.0])
|
||||
i2 = Increment([1.0])
|
||||
i3 = Increment([2.0])
|
||||
t1 = TimeStep(0.0, Increment[i1])
|
||||
t2 = TimeStep(2.0, Increment[i2])
|
||||
t3 = TimeStep(4.0, Increment[i3])
|
||||
field = Field(TimeStep[t1, t2, t3])
|
||||
@test call(field, temporalbasis, -Inf) == [0.0]
|
||||
@test call(field, temporalbasis, 0.0) == [0.0]
|
||||
@test call(field, temporalbasis, 1.0) == [0.5]
|
||||
@test call(field, temporalbasis, 2.0) == [1.0]
|
||||
@test call(field, temporalbasis, 3.0) == [1.5]
|
||||
@test call(field, temporalbasis, 4.0) == [2.0]
|
||||
@test call(field, temporalbasis, +Inf) == [2.0]
|
||||
@test call(field, temporalbasis, +Inf, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, -Inf, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 0.0, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 0.5, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 1.0, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 1.5, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 2.0, Val{:derivative}) == [0.5]
|
||||
fs = FieldSet()
|
||||
|
||||
t = collect(linspace(0, 2, 5))
|
||||
x = 1/2*t.^2
|
||||
x2 = tuple(collect(zip(t, x))...)
|
||||
# => ((0.0,0.0),(0.5,0.125),(1.0,0.5),(1.5,1.125),(2.0,2.0))
|
||||
fs["particle"] = x2
|
||||
position = call(fs["particle"], temporalbasis, 1.0)[1]
|
||||
@test isapprox(position, 0.50)
|
||||
velocity = call(fs["particle"], temporalbasis, 2.0, Val{:derivative})[1]
|
||||
@test isapprox(velocity, (2.0-1.125)/0.5) # = 1.75
|
||||
velocity = call(fs["particle"], temporalbasis, 1.0, Val{:derivative})[1]
|
||||
v1 = (0.500 - 0.125)/0.5
|
||||
v2 = (1.125 - 0.500)/0.5
|
||||
info("v1 = $v1, v2 = $v2")
|
||||
info(mean([v1, v2]))
|
||||
@test isapprox(velocity, mean([v1, v2])) # = 1.00
|
||||
|
||||
# FIXME, returns wrong type.
|
||||
@test isa(position, Increment) == true
|
||||
@test isa(velocity, Increment) == true
|
||||
end
|
||||
|
||||
function test_interpolation_in_spatial_basis()
|
||||
info("testing interpolation on spatial basis")
|
||||
basis(xi) = 1/4*[
|
||||
(1-xi[1])*(1-xi[2])
|
||||
(1+xi[1])*(1-xi[2])
|
||||
(1+xi[1])*(1+xi[2])
|
||||
(1-xi[1])*(1+xi[2])]'
|
||||
dbasis(xi) = 1/4*[
|
||||
-(1-xi[2]) (1-xi[2]) (1+xi[2]) -(1+xi[2])
|
||||
-(1-xi[1]) -(1+xi[1]) (1+xi[1]) (1-xi[1])]
|
||||
spatialbasis = SpatialBasis(basis, dbasis)
|
||||
@test spatialbasis.basis([0.0, 0.0]) == 1/4*[1 1 1 1]
|
||||
|
||||
fs = FieldSet()
|
||||
fs["geometry"] = Vector{Float64}[[0.0,0.0], [1.0,0.0], [1.0,1.0], [0.0,1.0]]
|
||||
fs["displacement"] = (0.0, zeros(2, 4)), (1.0, Vector[[0.0, 0.0], [0.0, 0.0], [0.25, 0.0], [0.0, 0.0]])
|
||||
|
||||
X = call(last(fs["geometry"]), spatialbasis, [0.0, 0.0])
|
||||
u = call(last(fs["displacement"]), spatialbasis, [0.0, 0.0])
|
||||
x = X+u
|
||||
@test X ≈ 1/2*[1, 1]
|
||||
@test x ≈ [9/16, 1/2]
|
||||
|
||||
gradu = call(last(fs["displacement"]), spatialbasis, [0.0, 0.0], last(fs["geometry"]), Val{:gradient})
|
||||
@test gradu ≈ [0.125 0.125; 0.0 0.0]
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,13 +1,13 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
module ElasticityTests
|
||||
|
||||
using Base.Test
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM: Quad4, Field, FieldSet, CPS4, get_basis, solve!, PlaneStressElasticityProblem
|
||||
|
||||
|
||||
function run()
|
||||
function test_elasticity_one_element()
|
||||
element = Quad4([1, 2, 3, 4])
|
||||
element["geometry"] = Vector[[0.0, 0.0], [10.0, 0.0], [10.0, 1.0], [0.0, 1.0]]
|
||||
element["youngs modulus"] = 500.0
|
||||
@@ -24,4 +24,5 @@ function run()
|
||||
@test disp ≈ -8.77303119819776
|
||||
end
|
||||
|
||||
run()
|
||||
|
||||
end
|
||||
|
||||
+20
-21
@@ -1,18 +1,22 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using FactCheck
|
||||
using JuliaFEM: Element, Basis, Field, FieldSet, FunctionSpace
|
||||
module ElementTests
|
||||
|
||||
using JuliaFEM.Test
|
||||
|
||||
using JuliaFEM: Element, Basis, Field, FieldSet, FunctionSpace, test_element
|
||||
|
||||
""" Prototype element
|
||||
|
||||
This should always pass test_element if everything is ok.
|
||||
"""
|
||||
type MockElement <: Element
|
||||
connectivity :: Array{Int, 1}
|
||||
connectivity :: Vector{Int}
|
||||
basis :: Basis
|
||||
fields :: Dict{ASCIIString, FieldSet}
|
||||
fields :: FieldSet
|
||||
end
|
||||
|
||||
function MockElement(connectivity)
|
||||
|
||||
h(xi) = 1/4*[(1-xi[1])*(1-xi[2]) (1+xi[1])*(1-xi[2]) (1+xi[1])*(1+xi[2]) (1-xi[1])*(1+xi[2])]
|
||||
@@ -24,33 +28,26 @@ function MockElement(connectivity)
|
||||
basis = Basis(h, dh)
|
||||
MockElement(connectivity, basis, Dict())
|
||||
end
|
||||
|
||||
Base.size(element::Type{MockElement}) = (2, 4)
|
||||
|
||||
using JuliaFEM: test_element
|
||||
facts("test test_element against mock element") do
|
||||
"""test test_element against mock element"""
|
||||
function test_mockelement()
|
||||
test_element(MockElement)
|
||||
end
|
||||
|
||||
|
||||
facts("test adding fieldsets and fields to element") do
|
||||
""" test adding fieldsets and fields to element"""
|
||||
function test_add_fields_to_element()
|
||||
el = MockElement([1, 2, 3, 4])
|
||||
|
||||
fieldset = JuliaFEM.FieldSet("geometry")
|
||||
field1 = JuliaFEM.Field(0.0, [0.0, 0.0, 0.0, 0.0])
|
||||
push!(fieldset, field1)
|
||||
field2 = JuliaFEM.Field(1.0, [1.0, 1.0, 1.0, 1.0])
|
||||
push!(fieldset, field2)
|
||||
|
||||
el["geometry"] = fieldset
|
||||
fields = el["geometry"]
|
||||
@fact length(fields) --> 2
|
||||
@fact fields[1] --> field1
|
||||
@fact fields[2] --> field2
|
||||
el["geometry"] = [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]
|
||||
field = el["geometry"]
|
||||
@test length(field) == 2 # two time steps
|
||||
end
|
||||
|
||||
#=
|
||||
facts("interpolation of fields in some function space") do
|
||||
|
||||
element = MockElement([1, 2, 3, 4])
|
||||
el = MockElement([1, 2, 3, 4])
|
||||
fieldset1 = FieldSet("geometry", [Field(0.0, Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]])])
|
||||
fieldset2 = FieldSet("constant scalar field", [Field(0.0, 1.0)])
|
||||
fieldset3 = FieldSet("scalar field", [Field(0.0, [1.0, 2.0, 3.0, 4.0])])
|
||||
@@ -79,4 +76,6 @@ facts("interpolation of fields in some function space") do
|
||||
@fact v("vector field 3", xi, t) --> 1/4*[1+2+3+4, 5+6+7+8, 9+10+11+12]
|
||||
@fact v("tensor field 1", xi, t) --> 1/4*[1+2+3+4 5+6+7+8; 9+10+11+12 13+14+15+16]
|
||||
end
|
||||
=#
|
||||
|
||||
end
|
||||
|
||||
+237
-178
@@ -2,115 +2,222 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
|
||||
module TypesTests
|
||||
module FieldTests
|
||||
|
||||
using JuliaFEM: Increment, TimeStep, AbstractField, DefaultDiscreteField, FieldSet
|
||||
using JuliaFEM: Increment, TimeStep, Field, DefaultDiscreteField, FieldSet
|
||||
using JuliaFEM: TemporalBasis, SpatialBasis, ContinuousField, DiscreteField
|
||||
using JuliaFEM: Field
|
||||
using JuliaFEM: DefaultContinuousField
|
||||
|
||||
using JuliaFEM.Test
|
||||
|
||||
using Base.Test
|
||||
|
||||
""" testing Increment """
|
||||
function test_increment()
|
||||
info("testing Increment")
|
||||
# testing Increment
|
||||
|
||||
# constant increment
|
||||
I3 = Increment(1)
|
||||
@test isa(I3, Increment)
|
||||
@test length(I3) == 1
|
||||
# FIXME: i don't like 1-length arrays
|
||||
@test I3 == [1]
|
||||
|
||||
# two increments with vector data
|
||||
I1 = Increment([1, 2, 3])
|
||||
I2 = Increment([2, 3, 4])
|
||||
@test dot(I1, I2) == 20
|
||||
@test dot([1,2,3], I2) == 20
|
||||
@test dot(I1, [2,3,4]) == 20
|
||||
@test length(I1) == 3
|
||||
@test length(I2) == 3
|
||||
|
||||
# basic math
|
||||
@test 1/2*(I1+I2) == [1.5, 2.5, 3.5]
|
||||
@test I1 + 1 == [2, 3, 4]
|
||||
@test I1 - 1 == [0, 1, 2]
|
||||
@test I1*3 == [3, 6, 9]
|
||||
@test I1+I2 == [3, 5, 7]
|
||||
|
||||
# dot product
|
||||
@test dot(I1, I2) == 20
|
||||
@test dot([1,2,3], I2) == 20
|
||||
@test dot(I1, [2,3,4]) == 20
|
||||
@test dot([1, 2], Increment[I1, I2])
|
||||
|
||||
# similarity
|
||||
f = zeros(Increment, 2, 4)
|
||||
@test length(f) == 4
|
||||
|
||||
g = similar(f, ones(8))
|
||||
@test typeof(f) == typeof(g)
|
||||
@test length(f) == length(g)
|
||||
|
||||
# promotion of increment
|
||||
@test typeof(I1+1) == typeof(I1)
|
||||
@test typeof(I1-1) == typeof(I1)
|
||||
@test typeof(I1*3) == typeof(I1)
|
||||
# vec
|
||||
@test vec(g) == ones(8)
|
||||
|
||||
# promotion
|
||||
# FIXME: how to do promotion so that modified increment is still increment?
|
||||
@test isa(I1+1, Increment)
|
||||
@test isa(I1-1, Increment)
|
||||
@test isa(3*I1, Increment)
|
||||
@test isa(1/2*I1, Increment)
|
||||
@test isa(I1+I2, Increment)
|
||||
@test isa(I1-I2, Increment)
|
||||
|
||||
# FIXME
|
||||
#@test typeof(I1) == typeof(I1+I2)
|
||||
#@test typeof(I1/2) == typeof(I1)
|
||||
#@test typeof(1/2*S1) == typeof(I1)
|
||||
end
|
||||
test_increment()
|
||||
|
||||
""" testing TimeStep """
|
||||
function test_timestep()
|
||||
info("testing TimeStep")
|
||||
|
||||
info("test_timestep(): create empty timestep")
|
||||
ts = TimeStep()
|
||||
@test length(ts) == 0
|
||||
@test ts.time == 0.0
|
||||
|
||||
info("create timestep with two increments")
|
||||
i1 = Increment([1, 2, 3])
|
||||
i2 = Increment([2, 3, 4])
|
||||
i3 = Increment([2, 3, 4])
|
||||
i4 = Increment([3, 4, 5])
|
||||
t1 = TimeStep(1.0, Increment[i1, i2])
|
||||
t2 = TimeStep(2.0, Increment[i3, i4])
|
||||
@test length(t1) == length(t2) == 2
|
||||
t3 = TimeStep(3.0, i1+1)
|
||||
increments = Increment[i1, i2]
|
||||
ts = TimeStep(1.0, increments)
|
||||
@test length(ts) == 2
|
||||
|
||||
info("create timestep with scalar value")
|
||||
ts = TimeStep(1)
|
||||
@test length(ts) == 1
|
||||
@test ts.time == 0.0
|
||||
@test isa(ts[1], Increment)
|
||||
@test ts[1] == [1]
|
||||
|
||||
info("create timestep compactly for time t=0.0")
|
||||
ts = TimeStep([1, 2, 3])
|
||||
@test length(ts) == 1
|
||||
@test ts.time == 0.0
|
||||
@test isa(ts[1], Increment)
|
||||
@test ts[1] == [1, 2, 3]
|
||||
|
||||
info("create timestep compactly, add three increments compactly for time t=0.0")
|
||||
ts = TimeStep(1, 2, 3)
|
||||
@test length(ts) == 3
|
||||
@test ts.time == 0.0
|
||||
@test isa(ts[1], Increment)
|
||||
|
||||
info("create timestep compactly, add two increments compactly for time t=0.0")
|
||||
ts = TimeStep([1, 2, 3], [2, 3, 4])
|
||||
@test length(ts) == 2
|
||||
@test ts.time == 0.0
|
||||
@test isa(ts[1], Increment)
|
||||
@test ts[1] == [1, 2, 3]
|
||||
@test ts[2] == [2, 3, 4]
|
||||
|
||||
info("create standard timesteps")
|
||||
info(TimeStep(0.5, Increment([1, 2])))
|
||||
|
||||
@test TimeStep(0.5, [1, 2]).time == 0.5
|
||||
@test TimeStep(0.5, [1, 2]) == [1, 2]
|
||||
@test TimeStep(0.5, 1).time == 0.5
|
||||
@test TimeStep(0.5, 1) == [1]
|
||||
|
||||
end
|
||||
test_timestep()
|
||||
|
||||
function test_watta_fak()
|
||||
# TODO: this test will fail if Increment is typealiased to Vector
|
||||
fs = FieldSet()
|
||||
fs["discrete field"] = [1, 2, 3, 4]
|
||||
T0 = last(fs["discrete field"])
|
||||
info("last discrete field: $T0, ", typeof(T0))
|
||||
T1 = T0 + 1
|
||||
info("adding 1 to discrete field: $T1, ", typeof(T1))
|
||||
ts = TimeStep(1.0, T1)
|
||||
info("creating time step: $ts, ", typeof(ts))
|
||||
push!(fs["discrete field"], ts)
|
||||
info("last discrete field = ", last(fs["discrete field"]))
|
||||
|
||||
info("fieldset: $fs")
|
||||
|
||||
@test last(fs["discrete field"]) == [2, 3, 4, 5]
|
||||
end
|
||||
test_watta_fak()
|
||||
|
||||
""" testing DefaultDiscreteField """
|
||||
function test_default_discrete_field()
|
||||
info("testing DefaultDiscreteField")
|
||||
|
||||
info("test_default_discrete_field(): the traditional way")
|
||||
i1 = Increment([1, 2, 3])
|
||||
i2 = Increment([2, 3, 4])
|
||||
t1 = TimeStep(1.0, Increment[i1, i2])
|
||||
i3 = Increment([2, 3, 4])
|
||||
i4 = Increment([3, 4, 5])
|
||||
t1 = TimeStep(1.0, Increment[i1, i2])
|
||||
t2 = TimeStep(2.0, Increment[i3, i4])
|
||||
timesteps = TimeStep[t1, t2]
|
||||
f1 = DefaultDiscreteField(timesteps)
|
||||
@test length(f1) == 2
|
||||
@test isa(f1, AbstractField) == true
|
||||
end
|
||||
test_default_discrete_field()
|
||||
@test isa(f1, Field)
|
||||
@test f1[1][1] == [1, 2, 3]
|
||||
@test f1[1][2] == [2, 3, 4]
|
||||
@test f1[2][1] == [2, 3, 4]
|
||||
@test f1[2][2] == [3, 4, 5]
|
||||
@test f1[1].time == 1.0
|
||||
@test f1[2].time == 2.0
|
||||
|
||||
info("test_default_discrete_field(): quick way, this creates one timestep with vector value")
|
||||
f1 = DefaultDiscreteField([1, 2, 3])
|
||||
info("f1 = $f1")
|
||||
@test isa(f1[1], TimeStep)
|
||||
@test isa(f1[1][1], Increment)
|
||||
@test f1[1][1] == [1, 2, 3]
|
||||
@test f1[1].time == 0.0
|
||||
|
||||
info("test_default_discrete_field(): quick way, two timesteps with constant value")
|
||||
f1 = DefaultDiscreteField(1, 2)
|
||||
@test length(f1) == 2
|
||||
@test isa(f1[1], TimeStep)
|
||||
@test isa(f1[2], TimeStep)
|
||||
@test isa(f1[1][1], Increment)
|
||||
@test isa(f1[2][1], Increment)
|
||||
@test f1[1][1] == [1]
|
||||
@test f1[2][1] == [2]
|
||||
@test f1[1].time == 0.0
|
||||
@test f1[2].time == 1.0
|
||||
|
||||
info("test_default_discrete_field(): quick way, one timestep with scalar value")
|
||||
f1 = DefaultDiscreteField(1)
|
||||
@test length(f1) == 1
|
||||
@test isa(f1[1], TimeStep)
|
||||
@test isa(f1[1][1], Increment)
|
||||
@test f1[1][1] == [1]
|
||||
@test f1[1].time == 0.0
|
||||
|
||||
info("test_default_discrete_field(): quick way, two timesteps with vector value")
|
||||
f1 = DefaultDiscreteField([1, 2, 3], [3, 4, 5])
|
||||
@test length(f1) == 2
|
||||
@test isa(f1[1], TimeStep)
|
||||
@test isa(f1[2], TimeStep)
|
||||
@test isa(f1[1][1], Increment)
|
||||
@test isa(f1[2][1], Increment)
|
||||
@test f1[1][1] == [1, 2, 3]
|
||||
@test f1[2][1] == [3, 4, 5]
|
||||
@test f1[1].time == 0.0
|
||||
@test f1[2].time == 1.0
|
||||
|
||||
info("test_default_discrete_field(): quick way, set time vector also")
|
||||
f1 = DefaultDiscreteField( (0.5, [1, 2, 3]), (1.0, [3, 4, 5]) )
|
||||
@test isa(f1[1], TimeStep)
|
||||
@test isa(f1[2], TimeStep)
|
||||
@test isa(f1[1][1], Increment)
|
||||
@test isa(f1[2][1], Increment)
|
||||
@test f1[1][1] == [1, 2, 3]
|
||||
@test f1[2][1] == [3, 4, 5]
|
||||
@test f1[1].time == 0.5
|
||||
@test f1[2].time == 1.0
|
||||
|
||||
end
|
||||
|
||||
""" testing DefaultContinuousField """
|
||||
function test_default_continuous_field()
|
||||
|
||||
function myfield(xi::Vector, time::Float64)
|
||||
time/4*[
|
||||
(1-xi[1])*(1-xi[2]),
|
||||
(1+xi[1])*(1-xi[2]),
|
||||
(1+xi[1])*(1+xi[2]),
|
||||
(1-xi[1])*(1+xi[2])]'
|
||||
end
|
||||
|
||||
f = DefaultContinuousField(myfield)
|
||||
@test f([0.0, 0.0], 1.0) == [0.25 0.25 0.25 0.25]
|
||||
|
||||
end
|
||||
|
||||
""" testing FieldSet """
|
||||
function test_fieldset()
|
||||
i1 = Increment([1, 2, 3])
|
||||
i2 = Increment([2, 3, 4])
|
||||
i3 = Increment([2, 3, 4])
|
||||
i4 = Increment([3, 4, 5])
|
||||
t1 = TimeStep(1.0, Increment[i1, i2])
|
||||
t2 = TimeStep(2.0, Increment[i3, i4])
|
||||
timesteps = TimeStep[t1, t2]
|
||||
f1 = DefaultDiscreteField(timesteps)
|
||||
info("testing adding discrete field to FieldSet")
|
||||
|
||||
info("test_fieldset(): testing adding discrete field to FieldSet")
|
||||
fs = FieldSet()
|
||||
fs["temperature"] = f1
|
||||
fs["temperature"] = DefaultDiscreteField([1, 2, 3])
|
||||
@test length(fs) == 1
|
||||
|
||||
info("testing adding discrete fields quickly")
|
||||
# the easy way
|
||||
info("test_fieldset(): testing adding discrete fields quickly")
|
||||
fs2 = FieldSet()
|
||||
fs2["temperature"] = [1, 2, 3, 4]
|
||||
@test fs2["temperature"][end][end] == [1, 2, 3, 4]
|
||||
@test last(fs2["temperature"]) == [1, 2, 3, 4]
|
||||
|
||||
info("test_fieldset(): testing adding all kind of discrete fields")
|
||||
fs2 = FieldSet()
|
||||
fs2["constant scalar field"] = 1
|
||||
fs2["scalar field"] = [1, 2, 3, 4]
|
||||
@@ -120,45 +227,61 @@ function test_fieldset()
|
||||
timestep = fs2["vector field"][end]
|
||||
@test timestep.time == 0.0
|
||||
|
||||
info("testing adding timesteps")
|
||||
# add another timestep
|
||||
info("test_fieldset(): testing adding timesteps")
|
||||
fs = FieldSet()
|
||||
fs["temperature"] = [1, 2, 3, 4]
|
||||
T0 = last(fs["temperature"]) # last increment of last field
|
||||
info("last temperature = $T0")
|
||||
T1 = T0 + 1
|
||||
@test typeof(T0) == typeof(T1)
|
||||
info("last temperature T0 = $T0")
|
||||
T1 = Increment(T0 + 1)
|
||||
info("typeof T1 = $(typeof(T1))")
|
||||
timestep = TimeStep(1.0, Increment[T1]) # new list of increments for timestep
|
||||
push!(fs["temperature"], timestep)
|
||||
T2 = last(fs["temperature"])
|
||||
info("last temperature = $T2")
|
||||
info("last temperature T2 = $T2")
|
||||
@test last(fs["temperature"]) == [2, 3, 4, 5]
|
||||
# or more easily
|
||||
|
||||
info("test_fieldset(): testing adding timesteps compactly")
|
||||
timestep = TimeStep(2.0, T1)
|
||||
push!(fs["temperature"], timestep)
|
||||
@test length(fs["temperature"].timesteps) == 3
|
||||
|
||||
info("test adding several time steps at once")
|
||||
info("test_fieldset(): test adding several time steps at once without time vector")
|
||||
fs3 = FieldSet()
|
||||
fs3["time series 1"] = (0.0, [1, 2, 3, 4]), (0.5, [2, 3, 4, 5]), (1.0, [1, 1, 1, 1])
|
||||
@test fs3["time series 1"][end].time == 1.0
|
||||
fs3["time series 2"] = [1, 2, 3, 4], [2, 3, 4, 5], [1, 1, 1, 1]
|
||||
@test fs3["time series 2"][end].time == 2.0
|
||||
end
|
||||
test_fieldset()
|
||||
fs3["time series 2"] = [1, 2, 3, 4], [2, 3, 4, 5]
|
||||
info(fs3)
|
||||
@test fs3["time series 2"][1].time == 0.0
|
||||
@test fs3["time series 2"][2].time == 1.0
|
||||
@test fs3["time series 2"][1][end] == [1, 2, 3, 4]
|
||||
@test fs3["time series 2"][2][end] == [2, 3, 4, 5]
|
||||
|
||||
info("test_fieldset(): test adding several time steps at once with time vector")
|
||||
fs3 = FieldSet()
|
||||
fs3["time series 1"] = (0.0, [1, 2, 3, 4]), (0.5, [2, 3, 4, 5])
|
||||
@test fs3["time series 1"][1].time == 0.0
|
||||
@test fs3["time series 1"][2].time == 0.5
|
||||
@test fs3["time series 1"][1][end] == [1, 2, 3, 4]
|
||||
@test fs3["time series 1"][2][end] == [2, 3, 4, 5]
|
||||
|
||||
info("test_fieldset(): adding continuous field")
|
||||
fs = FieldSet()
|
||||
fs["continuous field"] = (xi, t) -> xi[1]*xi[2]*t
|
||||
@test fs["continuous field"]([1.0, 2.0], 3.0) == 6.0
|
||||
|
||||
type MyFunnyContinuousField <: ContinuousField
|
||||
basis :: Function
|
||||
discretefield :: DiscreteField
|
||||
end
|
||||
function Base.call(field::MyFunnyContinuousField, xi::Vector, time::Number=1.0)
|
||||
data = last(field.discretefield) # get the last timestep last increment
|
||||
|
||||
type MyContinuousField <: ContinuousField
|
||||
basis :: Function
|
||||
discrete_field :: DiscreteField
|
||||
end
|
||||
function Base.call(field::MyContinuousField, xi::Vector, time::Number=1.0)
|
||||
data = last(field.discrete_field) # get the last timestep last increment
|
||||
info("data = $data, typeof data = $(typeof(data))")
|
||||
basis = time*field.basis(xi) # evaluate basis at point ξ.
|
||||
sum([basis[i]*data[i] for i=1:length(data)]) # sum results
|
||||
end
|
||||
|
||||
""" testing ContinuousField """
|
||||
function test_continuous_field()
|
||||
info("testing continuous field")
|
||||
fs = FieldSet()
|
||||
fs["discrete field"] = [1, 2, 3, 4]
|
||||
basis(xi) = 1/4*[
|
||||
@@ -166,7 +289,7 @@ function test_continuous_field()
|
||||
(1+xi[1])*(1-xi[2]),
|
||||
(1+xi[1])*(1+xi[2]),
|
||||
(1-xi[1])*(1+xi[2])]
|
||||
fs["continuous field"] = MyFunnyContinuousField(basis, fs["discrete field"])
|
||||
fs["continuous field"] = MyContinuousField(basis, fs["discrete field"])
|
||||
@test fs["continuous field"]([0.0, 0.0], 1.0) == 1/4*(1+2+3+4)
|
||||
T0 = last(fs["discrete field"])
|
||||
T1 = T0 + 1.0
|
||||
@@ -174,21 +297,20 @@ function test_continuous_field()
|
||||
push!(fs["discrete field"], TimeStep(1.0, T0+1.0))
|
||||
@test fs["continuous field"]([0.0, 0.0], 1.0) == 1/4*(2+3+4+5)
|
||||
end
|
||||
test_continuous_field()
|
||||
|
||||
type MyFunnyDiscreteField <: DiscreteField
|
||||
type MyDiscreteField <: DiscreteField
|
||||
discrete_points :: Vector
|
||||
continuousfield :: ContinuousField
|
||||
continuous_field :: ContinuousField
|
||||
end
|
||||
Base.length(field::MyFunnyDiscreteField) = length(field.discrete_points)
|
||||
Base.endof(field::MyFunnyDiscreteField) = endof(field.discrete_points)
|
||||
Base.last(field::MyFunnyDiscreteField) = Float64[field[i] for i=1:length(field)]
|
||||
function Base.getindex(field::MyFunnyDiscreteField, idx::Int64)
|
||||
field.continuousfield(field.discrete_points[idx])
|
||||
Base.length(field::MyDiscreteField) = length(field.discrete_points)
|
||||
Base.endof(field::MyDiscreteField) = endof(field.discrete_points)
|
||||
Base.last(field::MyDiscreteField) = Float64[field[i] for i=1:length(field)]
|
||||
function Base.getindex(field::MyDiscreteField, idx::Int64)
|
||||
field.continuous_field(field.discrete_points[idx])
|
||||
end
|
||||
|
||||
""" testing DiscreteField """
|
||||
function test_discrete_field()
|
||||
info("testing discrete field")
|
||||
fs = FieldSet()
|
||||
fs["discrete field"] = [1, 2, 3, 4]
|
||||
basis(xi) = 1/4*[
|
||||
@@ -196,98 +318,35 @@ function test_discrete_field()
|
||||
(1+xi[1])*(1-xi[2]),
|
||||
(1+xi[1])*(1+xi[2]),
|
||||
(1-xi[1])*(1+xi[2])]
|
||||
fs["continuous field"] = MyFunnyContinuousField(basis, fs["discrete field"])
|
||||
fs["continuous field"] = MyContinuousField(basis, fs["discrete field"])
|
||||
discrete_points = 1.0/sqrt(3.0)*Vector[[-1, -1], [1, -1], [1, 1], [-1, 1]]
|
||||
fs["discrete field 2"] = MyFunnyDiscreteField(discrete_points, fs["continuous field"])
|
||||
fs["discrete field 2"] = MyDiscreteField(discrete_points, fs["continuous field"])
|
||||
@test last(fs["discrete field 2"]) ≈ [
|
||||
1.7559830641437073,
|
||||
2.0893163974770410,
|
||||
2.9106836025229590,
|
||||
3.2440169358562922]
|
||||
end
|
||||
test_discrete_field()
|
||||
|
||||
|
||||
function test_interpolation_in_temporal_basis()
|
||||
info("testing interpolation on temporal basis")
|
||||
temporalbasis = TemporalBasis((t) -> [1-t, t], (t) -> [-1, 1])
|
||||
@test temporalbasis(0.2) == [0.8, 0.2]
|
||||
i1 = Increment([0.0])
|
||||
i2 = Increment([1.0])
|
||||
i3 = Increment([2.0])
|
||||
t1 = TimeStep(0.0, Increment[i1])
|
||||
t2 = TimeStep(2.0, Increment[i2])
|
||||
t3 = TimeStep(4.0, Increment[i3])
|
||||
field = Field(TimeStep[t1, t2, t3])
|
||||
@test call(field, temporalbasis, -Inf) == [0.0]
|
||||
@test call(field, temporalbasis, 0.0) == [0.0]
|
||||
@test call(field, temporalbasis, 1.0) == [0.5]
|
||||
@test call(field, temporalbasis, 2.0) == [1.0]
|
||||
@test call(field, temporalbasis, 3.0) == [1.5]
|
||||
@test call(field, temporalbasis, 4.0) == [2.0]
|
||||
@test call(field, temporalbasis, +Inf) == [2.0]
|
||||
@test call(field, temporalbasis, +Inf, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, -Inf, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 0.0, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 0.5, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 1.0, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 1.5, Val{:derivative}) == [0.5]
|
||||
@test call(field, temporalbasis, 2.0, Val{:derivative}) == [0.5]
|
||||
fs = FieldSet()
|
||||
|
||||
t = collect(linspace(0, 2, 5))
|
||||
x = 1/2*t.^2
|
||||
x2 = tuple(collect(zip(t, x))...)
|
||||
# => ((0.0,0.0),(0.5,0.125),(1.0,0.5),(1.5,1.125),(2.0,2.0))
|
||||
fs["particle"] = x2
|
||||
position = call(fs["particle"], temporalbasis, 1.0)[1]
|
||||
@test position ≈ 0.50
|
||||
velocity = call(fs["particle"], temporalbasis, 2.0, Val{:derivative})[1]
|
||||
@test velocity ≈ (2.0-1.125)/0.5 # = 1.75
|
||||
velocity = call(fs["particle"], temporalbasis, 1.0, Val{:derivative})[1]
|
||||
v1 = (0.500 - 0.125)/0.5
|
||||
v2 = (1.125 - 0.500)/0.5
|
||||
info("v1 = $v1, v2 = $v2")
|
||||
info(mean([v1, v2]))
|
||||
@test velocity ≈ mean([v1, v2]) # = 1.00
|
||||
|
||||
# FIXME, returns wrong type.
|
||||
#=
|
||||
@test isa(position, Increment) == true
|
||||
@test isa(velocity, Increment) == true
|
||||
=#
|
||||
function test_field_conversion()
|
||||
i1 = Increment([1, 2, 3])
|
||||
i2 = Increment([2, 3, 4])
|
||||
t1 = TimeStep(1.0, Increment[i1, i2])
|
||||
i3 = Increment([2, 3, 4])
|
||||
i4 = Increment([3, 4, 5])
|
||||
t2 = TimeStep(2.0, Increment[i3, i4])
|
||||
timesteps = TimeStep[t1, t2]
|
||||
info("timesteps = $timesteps")
|
||||
f1 = Field(timesteps)
|
||||
info("field = $f1")
|
||||
@test length(f1) == 2
|
||||
@test isa(f1, Field)
|
||||
@test f1[1][1] == [1, 2, 3]
|
||||
@test f1[1][2] == [2, 3, 4]
|
||||
@test f1[2][1] == [2, 3, 4]
|
||||
@test f1[2][2] == [3, 4, 5]
|
||||
@test f1[1].time == 1.0
|
||||
@test f1[2].time == 2.0
|
||||
end
|
||||
test_interpolation_in_temporal_basis()
|
||||
|
||||
function test_interpolation_in_spatial_basis()
|
||||
info("testing interpolation on spatial basis")
|
||||
basis(xi) = 1/4*[
|
||||
(1-xi[1])*(1-xi[2])
|
||||
(1+xi[1])*(1-xi[2])
|
||||
(1+xi[1])*(1+xi[2])
|
||||
(1-xi[1])*(1+xi[2])]'
|
||||
dbasis(xi) = 1/4*[
|
||||
-(1-xi[2]) (1-xi[2]) (1+xi[2]) -(1+xi[2])
|
||||
-(1-xi[1]) -(1+xi[1]) (1+xi[1]) (1-xi[1])]
|
||||
spatialbasis = SpatialBasis(basis, dbasis)
|
||||
@test spatialbasis.basis([0.0, 0.0]) == 1/4*[1 1 1 1]
|
||||
|
||||
fs = FieldSet()
|
||||
fs["geometry"] = Vector{Float64}[[0.0,0.0], [1.0,0.0], [1.0,1.0], [0.0,1.0]]
|
||||
fs["displacement"] = (0.0, zeros(2, 4)), (1.0, Vector[[0.0, 0.0], [0.0, 0.0], [0.25, 0.0], [0.0, 0.0]])
|
||||
|
||||
X = call(last(fs["geometry"]), spatialbasis, [0.0, 0.0])
|
||||
u = call(last(fs["displacement"]), spatialbasis, [0.0, 0.0])
|
||||
x = X+u
|
||||
@test X ≈ 1/2*[1, 1]
|
||||
@test x ≈ [9/16, 1/2]
|
||||
|
||||
gradu = call(last(fs["displacement"]), spatialbasis, [0.0, 0.0], last(fs["geometry"]), Val{:gradient})
|
||||
@test gradu ≈ [0.125 0.125; 0.0 0.0]
|
||||
end
|
||||
test_interpolation_in_spatial_basis()
|
||||
|
||||
|
||||
println("test_fields.jl: all test passing.")
|
||||
|
||||
end
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
module GlobalAssemblyTests
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM: Quad4, Seg2, FieldSet, Field, PlaneHeatProblem
|
||||
using JuliaFEM: initialize_global_assembly, calculate_global_assembly!
|
||||
using FactCheck
|
||||
|
||||
facts("assemble a simple two element problem and solve") do
|
||||
"""assemble a simple two element problem and solve"""
|
||||
function test_asssembly()
|
||||
el1 = Quad4([1, 2, 3, 4])
|
||||
el1["geometry"] = Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
|
||||
el1["temperature thermal conductivity"] = 6.0
|
||||
@@ -28,5 +31,7 @@ facts("assemble a simple two element problem and solve") do
|
||||
A = lufact(global_assembly.stiffness_matrix[free_dofs, free_dofs])
|
||||
b = full(global_assembly.force_vector)[free_dofs]
|
||||
u = A \ b
|
||||
@fact u --> roughly([101.0, 101.0])
|
||||
@test isapprox(u, roughly([101.0, 101.0]))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
+13
-5
@@ -3,10 +3,17 @@
|
||||
|
||||
# unit tests for heat equations
|
||||
|
||||
using FactCheck
|
||||
using JuliaFEM: Seg2, Quad4, Field, FieldSet, DC2D4, initialize_local_assembly, calculate_local_assembly!, DC2D2
|
||||
module HeatTests # always wrap tests to module ending with "Tests"
|
||||
|
||||
facts("tests on [0x1]x[0x1] domain") do
|
||||
using JuliaFEM.Test # always use JuliaFEM.Test, not Base.Test
|
||||
|
||||
using JuliaFEM: Seg2, Quad4, Field, FieldSet, DC2D4,
|
||||
initialize_local_assembly, calculate_local_assembly!,
|
||||
DC2D2
|
||||
|
||||
|
||||
"tests on [0x1]x[0x1] domain"
|
||||
function test_one_element() # always start test function with name test_
|
||||
|
||||
# volume element
|
||||
element = Quad4([1, 2, 3, 4])
|
||||
@@ -29,7 +36,7 @@ facts("tests on [0x1]x[0x1] domain") do
|
||||
fdofs = [1, 2]
|
||||
A = la.stiffness_matrix
|
||||
b = la.force_vector
|
||||
@fact A[fdofs, fdofs] \ b[fdofs] --> roughly([1.0, 1.0])
|
||||
@test isapprox(A[fdofs, fdofs] \ b[fdofs], [1.0, 1.0])
|
||||
|
||||
# Set constant flux g=6 on boundary. Accurate solution is
|
||||
# u(x,y) = x which equals T=1 on boundary.
|
||||
@@ -37,7 +44,8 @@ facts("tests on [0x1]x[0x1] domain") do
|
||||
|
||||
calculate_local_assembly!(la, boundary_equation, "temperature")
|
||||
b = la.force_vector
|
||||
@fact A[fdofs, fdofs] \ b[fdofs] --> roughly([1.0, 1.0])
|
||||
@test isapprox(A[fdofs, fdofs] \ b[fdofs], [1.0, 1.0]) # always use @test to test things.
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM: get_basis, grad, FieldSet, Field, Quad4
|
||||
using FactCheck
|
||||
|
||||
|
||||
facts("basic continuum interpolations") do
|
||||
|
||||
element = Quad4([1, 2, 3, 4])
|
||||
|
||||
element["geometry"] = Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
|
||||
element["temperature"] = ([0.0, 0.0, 0.0, 0.0], [1.0, 2.0, 3.0, 4.0])
|
||||
element["displacement"] = (
|
||||
Vector[[0.0, 0.0], [0.0, 0.0], [0.00, 0.0], [0.0, 0.0]],
|
||||
Vector[[0.0, 0.0], [0.0, 0.0], [0.25, 0.0], [0.0, 0.0]])
|
||||
|
||||
# from my old home works
|
||||
basis = get_basis(element)
|
||||
dbasis = grad(basis)
|
||||
@fact basis("geometry", [0.0, 0.0], 1.0) + basis("displacement", [0.0, 0.0], 1.0) --> [9/16, 1/2]
|
||||
gradu = dbasis("displacement", [0.0, 0.0], 1.0)
|
||||
epsilon = 1/2*(gradu + gradu')
|
||||
rotation = 1/2*(gradu - gradu')
|
||||
X = basis("geometry", [0.0, 0.0], 1.0)
|
||||
k = 0.25
|
||||
epsilon_wanted = [X[2]*k 1/2*X[1]*k; 1/2*X[1]*k 0]
|
||||
rotation_wanted = [0 k/2*X[1]; -k/2*X[1] 0]
|
||||
@fact epsilon --> roughly(epsilon_wanted)
|
||||
@fact rotation --> roughly(rotation_wanted)
|
||||
F = I + gradu
|
||||
@fact F --> [X[2]*k+1 X[1]*k; 0 1]
|
||||
C = F'*F
|
||||
@fact C --> [(X[2]*k+1)^2 (X[2]*k+1)*X[1]*k; (X[2]*k+1)*X[1]*k X[1]^2*k^2+1]
|
||||
E = 1/2*(F'*F - I)
|
||||
@fact E --> [1/2*(X[2]*k + 1)^2-1/2 1/2*(X[2]*k+1)*X[1]*k; 1/2*(X[2]*k + 1)*X[1]*k 1/2*X[1]^2*k^2]
|
||||
U = 1/sqrt(trace(C) + 2*sqrt(det(C)))*(C + sqrt(det(C))*I)
|
||||
#@fact U --> roughly([1.24235 0.13804; 0.13804 1.02149])
|
||||
end
|
||||
+10
-2
@@ -1,10 +1,15 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM: interpolate
|
||||
module MathTests
|
||||
using JuliaFEM.Test
|
||||
|
||||
using FactCheck
|
||||
function test_math()
|
||||
@test 1+1 == 2
|
||||
end
|
||||
|
||||
#using JuliaFEM: interpolate
|
||||
#=
|
||||
facts("test interpolation of different field variables") do
|
||||
N(xi) = [
|
||||
(1-xi[1])*(1-xi[2])/4
|
||||
@@ -31,3 +36,6 @@ facts("test interpolation of different field variables") do
|
||||
@fact interpolate(F5, dNdξ, [0.0, 0.0]) --> [5.0 0.0; 0.0 0.5]
|
||||
@fact interpolate(F6, N, [0.0, 0.0]) --> 36
|
||||
end
|
||||
=#
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user