From b070f21aaba766ea6aa69f65b541187f0ee61864 Mon Sep 17 00:00:00 2001 From: Jukka Aho Date: Sun, 3 Jul 2016 05:01:18 +0300 Subject: [PATCH] heat solver tests etc --- src/JuliaFEM.jl | 45 +-- src/assembly.jl | 93 +----- src/contact.jl | 6 +- src/dirichlet.jl | 4 +- src/elasticity.jl | 78 ++--- src/elements.jl | 15 +- src/fields.jl | 54 ++-- src/heat.jl | 49 ++- src/integrate.jl | 6 +- src/lagrange.jl | 570 +++++++++++++++++++++++++++++++++ src/lagrange_macro.jl | 79 +---- src/postprocess_utils.jl | 28 ++ src/preprocess.jl | 67 +++- src/preprocess_aster_reader.jl | 58 +++- src/problems.jl | 12 +- src/solvers.jl | 79 ++++- test/testdata/primitives.hdf | Bin 0 -> 537840 bytes test/testdata/primitives.med | Bin 0 -> 70524 bytes test/testdata/rod_short.med | Bin 0 -> 146020 bytes 19 files changed, 944 insertions(+), 299 deletions(-) create mode 100644 src/lagrange.jl create mode 100644 test/testdata/primitives.hdf create mode 100644 test/testdata/primitives.med create mode 100644 test/testdata/rod_short.med diff --git a/src/JuliaFEM.jl b/src/JuliaFEM.jl index 2c5484f..6c0d502 100644 --- a/src/JuliaFEM.jl +++ b/src/JuliaFEM.jl @@ -27,33 +27,17 @@ export AbstractPoint, Point, IntegrationPoint, IP, Node include("elements.jl") # common element routines export Node, AbstractElement, Element, update!, get_connectivity, get_basis, get_dbasis include("lagrange_macro.jl") # Continuous Galerkin (Lagrange) elements generated using macro +include("lagrange.jl") # Continuous Galerkin (Lagrange) elements +export get_reference_coordinates +export Poi1, + Seg2, Seg3, + Tri3, Tri6, Quad4, Quad8, Quad9, + Tet4, Tet10, Hex8, Hex20, Hex27 -type Poi1 <: AbstractElement -end - -function size(element::Element{Poi1}) - return (0, 1) -end - -function length(element::Element{Poi1}) - return 1 -end - -function get_basis(element::Element{Poi1}, ip, time) - return [1] -end - -function call(element::Element{Poi1}, ip, time, ::Type{Val{:detJ}}) - return 1.0 -end - -export Poi1, Seg2, Seg3, Tri3, Tri6, Quad4, Hex8, Tet4, Tet10 include("nurbs.jl") export NSeg, NSurf, NSolid, is_nurbs #include("hierarchical.jl") # P-elements -#include("mortar_elements.jl") # Mortar elements -#include("equations.jl") include("integrate.jl") # default integration points for elements export get_integration_points @@ -66,7 +50,7 @@ export Problem, AbstractProblem, FieldProblem, BoundaryProblem, get_unknown_field_dimension, get_gdofs, Assembly, get_parent_field_name, get_elements -include("elasticity.jl") # elasticity equations +include("elasticity.jl") export Elasticity include("dirichlet.jl") @@ -75,7 +59,7 @@ export Dirichlet include("heat.jl") export Heat -export assemble, assemble! +export assemble!, postprocess! function assemble!(problem::Problem, element::Element, time=0.0) assemble!(problem.assembly, problem, element, time) @@ -89,7 +73,7 @@ export AbstractSolver, Solver, Nonlinear, NonlinearSolver, Linear, LinearSolver, get_unknown_field_name, get_formulation_type, get_field_problems, get_boundary_problems, get_field_assembly, get_boundary_assembly, - initialize!, create_projection + initialize!, create_projection, eliminate_interior_dofs include("modal.jl") export Modal @@ -124,9 +108,11 @@ export create_elements, Mesh, add_element!, add_elements!, add_element_to_element_set!, add_node_to_node_set!, - find_nearest_nodes + find_nearest_nodes, + reorder_element_connectivity! include("preprocess_abaqus_reader.jl") include("preprocess_abaqus_reader_old.jl") +export parse_abaqus, parse_section, parse_element_section include("preprocess_aster_reader.jl") export aster_create_elements, parse_aster_med_file, is_aster_mail_keyword, parse_aster_header, aster_parse_nodes, aster_renumber_nodes!, @@ -146,10 +132,14 @@ export get_mesh, get_model module Postprocess include("postprocess_utils.jl") -export calc_nodal_values!, get_nodal_vector, copy_field! +export calc_nodal_values!, + get_nodal_vector, + get_nodal_dict, + copy_field! include("postprocess_xdmf.jl") export XDMF, xdmf_new_result!, xdmf_save_field!, xdmf_save! end +export Postprocessor """ JuliaFEM testing routines. """ module Test @@ -171,5 +161,4 @@ module Interfaces include("interfaces.jl") end - end # module diff --git a/src/assembly.jl b/src/assembly.jl index 79a6654..afc827a 100644 --- a/src/assembly.jl +++ b/src/assembly.jl @@ -1,18 +1,6 @@ # This file is a part of JuliaFEM. # License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md -# Functions to handle global assembly of problem - -type CAssembly - interior_dofs :: Vector{Int} - boundary_dofs :: Vector{Int} - F :: Union{Factorization, Matrix} - Kc :: SparseMatrixCSC - fc :: SparseMatrixCSC - Kib :: SparseMatrixCSC - fi :: SparseMatrixCSC -end - function optimize!(assembly::Assembly) optimize!(assembly.K) optimize!(assembly.Kg) @@ -99,54 +87,28 @@ function assemble!(problem::Problem, time::Real, ::Type{Val{:mass_matrix}}; dens end end -""" Calculate reduced stiffness matrix. -mindofs: if dofs < mindofs, do not reduce -""" -function reduce(assembly::Assembly, boundary_dofs_::Vector{Int}, mindofs=100000) - all_dofs = unique(assembly.stiffness_matrix.I) - boundary_dofs = intersect(all_dofs, boundary_dofs_) - interior_dofs = setdiff(all_dofs, boundary_dofs_) +# Static condensation routines - K = sparse(assembly.stiffness_matrix) - f = sparse(assembly.force_vector) +function eliminate_interior_dofs(K::SparseMatrixCSC, f::SparseMatrixCSC, B::Vector{Int64}, I::Vector{Int64}; F=nothing, chunk_size=100000) dim = size(K, 1) + Kib = K[I,B] - # empty assembly to release memory for factorization - empty!(assembly.stiffness_matrix) - empty!(assembly.force_vector) - gc() - - if dim < mindofs - # no need to do any reduction of matrix size at all, just \ it. - return CAssembly([], all_dofs, Matrix{Float64}(), K, f, spzeros(0, 0), spzeros(0,1)) + if F == nothing + F = cholfact(1/2*(K + K')[I,I]) end - # check that matrix is symmetric - s = maximum(abs(1/2*(K + K') - K)) - @assert s < 1.0e-6 - K = 1/2*(K + K') - - Kib = K[interior_dofs, boundary_dofs] - Kbb = K[boundary_dofs, boundary_dofs] - fi = f[interior_dofs] - fb = f[boundary_dofs] - - F = cholfact(K[interior_dofs, interior_dofs]) - K = 0 - gc() - - - if dim < 100000 + if dim < chunk_size # for small problems we don't need to care about memory usage Kd = Kib' * (F \ Kib) else # for larger problems calculate schur complement in pieces - nb = length(boundary_dofs) + nb = length(B) p = nb > 10 ? round(Int, nb/10) : nb Kd = zeros(nb, nb) for bi in 1:nb - mod(bi, p) == 0 && info("Reduction: ", round(Int, bi/nb*100), " % done") + done = round(Int, bi/nb*100) + mod(bi, p) == 0 && info("Static condensation: $done % done") C = full(F \ Kib[:, bi]) for bj in bi:nb d = Kib[:, bj] @@ -155,38 +117,17 @@ function reduce(assembly::Assembly, boundary_dofs_::Vector{Int}, mindofs=100000) end Kd += tril(Kd, -1)' end - Kc = spzeros(dim, dim) - Kc[boundary_dofs, boundary_dofs] = Kbb - Kd - -#= # this is slightly faster but uses more memory - chunks = round(Int, dim/3000) - info("Reduction is done in $chunks chunks.") - nb = length(boundary_dofs) - kk = round(Int, collect(linspace(0, nb, chunks+1))) - sl = [kk[j]+1:kk[j+1] for j=1:length(kk)-1] - Kd = zeros(Float64, nb, nb) - #Kd = SharedArray(Float64, nb, nb) - for (k,sli) in enumerate(sl) - b1 = boundary_dofs[sli] - Sc = F \ Kib[:,sli] - for slj in sl - b2 = boundary_dofs[slj] - #Kc[b2,b1] = Kbb[slj,sli] - Kib[:,slj]'*Sc - Kd[slj, sli] = Kib[:,slj]'*Sc - end - info("Reduction: ", round(k/chunks*100, 0), " % done") - end Kc = spzeros(dim, dim) - Kc[boundary_dofs, boundary_dofs] = Kbb - Kd -=# + Kc[B,B] = K[B,B] - Kd fc = spzeros(dim, 1) - fc[boundary_dofs] = fb - Kib' * (F \ fi) + fc[B] = f[B] - Kib' * (F \ f[I]) - return CAssembly(interior_dofs, boundary_dofs, F, Kc, fc, Kib, fi) + return Kc, fc end +#= function reconstruct!(ca::CAssembly, x::SparseMatrixCSC) if isa(ca.F, Factorization) x[ca.interior_dofs] = ca.F \ (ca.fi - ca.Kib*x[ca.boundary_dofs]) @@ -194,10 +135,4 @@ function reconstruct!(ca::CAssembly, x::SparseMatrixCSC) x[ca.interior_dofs] = ca.F * (ca.fi - ca.Kib*x[ca.boundary_dofs]) end end - -function Base.(:+)(ass1::Assembly, ass2::Assembly) - mass_matrix = ass1.mass_matrix + ass2.mass_matrix - stiffness_matrix = ass1.stiffness_matrix + ass2.stiffness_matrix - force_vector = ass1.force_vector + ass2.force_vector - return Assembly(mass_matrix, stiffness_matrix, force_vector) -end +=# diff --git a/src/contact.jl b/src/contact.jl index 10b0185..b6fd476 100644 --- a/src/contact.jl +++ b/src/contact.jl @@ -96,11 +96,11 @@ function assemble!(problem::Problem{Contact}, time::Float64, end # 3. loop all master elements - for master_element in slave_element["master elements"](time) + for master_element in slave_element("master elements", time) nm = length(master_element) - X2 = master_element["geometry"](time) - u2 = master_element["displacement"](time) + X2 = master_element("geometry", time) + u2 = master_element("displacement", time) x2 = X2 + u2 norm(mean(X1) - X2[1]) / norm(X1[2] - X1[1]) < props.distval || continue diff --git a/src/dirichlet.jl b/src/dirichlet.jl index cd79b25..83cafe5 100644 --- a/src/dirichlet.jl +++ b/src/dirichlet.jl @@ -36,7 +36,7 @@ function assemble!(assembly::Assembly, problem::Problem{Dirichlet}, element::Ele else Ae = eye(nnodes) De = zeros(nnodes, nnodes) - for ip in get_integration_points(element) + for ip in get_integration_points(element, 1) N = element(ip, time) detJ = element(ip, time, Val{:detJ}) De += ip.weight*N'*N*detJ @@ -53,7 +53,7 @@ function assemble!(assembly::Assembly, problem::Problem{Dirichlet}, element::Ele end # right hand side - for ip in get_integration_points(element) + for ip in get_integration_points(element, 1) detJ = element(ip, time, Val{:detJ}) w = ip.weight*detJ N = element(ip, time) diff --git a/src/elasticity.jl b/src/elasticity.jl index 81f10ba..bc7a1cb 100644 --- a/src/elasticity.jl +++ b/src/elasticity.jl @@ -1,8 +1,36 @@ # This file is a part of JuliaFEM. # License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md -""" Elasticity problem +""" Elasticity equations. +Field equation is: + + m∂²u/∂t² = ∇⋅σ - b + +Weak form is: find u∈U such that ∀v in V + + δW := ∫ρ₀∂²u/∂t²⋅δu dV₀ + ∫S:δE dV₀ - ∫b₀⋅δu dV₀ - ∫t₀⋅δu dA₀ = 0 + +where + + ρ₀ = density + b₀ = displacement load + t₀ = displacement traction + +Formulations +------------ +plane stress, plane strain, 3D + +References +---------- + +https://en.wikipedia.org/wiki/Linear_elasticity +https://en.wikipedia.org/wiki/Finite_strain_theory +https://en.wikipedia.org/wiki/Stress_measures +https://en.wikipedia.org/wiki/Mooney%E2%80%93Rivlin_solid +https://en.wikipedia.org/wiki/Strain_energy_density_function +https://en.wikipedia.org/wiki/Plane_stress +https://en.wikipedia.org/wiki/Hooke's_law """ type Elasticity <: FieldProblem @@ -38,8 +66,14 @@ function assemble!(assembly::Assembly, problem::Problem{Elasticity}, element::El add!(assembly.f, gdofs, f) end +typealias Elasticity2DSurfaceElements Union{Poi1, Seg2, Seg3} +typealias Elasticity2DVolumeElements Union{Tri3, Tri6, Quad4, Quad8, Quad9} +typealias Elasticity3DSurfaceElements Union{Poi1, Tri3, Tri6, Quad4, Quad8, Quad9} +typealias Elasticity3DVolumeElements Union{Tet4, Tet10, Hex8, Hex20, Hex27} + + """ Elasticity equations for 2d cases. """ -function assemble{El<:Union{Tri3,Tri6,Quad4}}(problem::Problem{Elasticity}, element::Element{El}, time, ::Type{Val{:plane}}) +function assemble{El<:Elasticity2DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time, ::Type{Val{:plane}}) props = problem.properties dim = get_unknown_field_dimension(problem) @@ -162,7 +196,7 @@ function assemble{El<:Union{Tri3,Tri6,Quad4}}(problem::Problem{Elasticity}, elem return Km, Kg, f end -function assemble{El<:Union{Poi1,Seg2,Seg3}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:plane}}) +function assemble{El<:Elasticity2DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:plane}}) props = problem.properties dim = get_unknown_field_dimension(problem) @@ -203,7 +237,7 @@ function assemble{El<:Union{Poi1,Seg2,Seg3}}(problem::Problem{Elasticity}, eleme end """ Elasticity equations, 3d, linear. """ -function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}}) +function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}}) props = problem.properties dim = get_unknown_field_dimension(problem) @@ -270,7 +304,7 @@ function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, el end """ Material and geometric stiffness for linear buckling analysis. """ -function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_buckling}}) +function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_buckling}}) props = problem.properties dim = get_unknown_field_dimension(problem) @@ -348,7 +382,7 @@ function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, el end """ Elasticity equations, 3d nonlinear. """ -function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}}) +function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}}) props = problem.properties dim = get_unknown_field_dimension(problem) @@ -487,7 +521,7 @@ function assemble{El<:Union{Tet4, Tet10, Hex8}}(problem::Problem{Elasticity}, el end """ Elasticity equations, surface traction for continuum formulation. """ -function assemble{El<:Union{Tri3, Tri6, Quad4}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}}) +function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}}) props = problem.properties dim = get_unknown_field_dimension(problem) @@ -521,39 +555,11 @@ function assemble{El<:Union{Tri3, Tri6, Quad4}}(problem::Problem{Elasticity}, el return Km, Kg, f end -function assemble{El<:Union{Tri3, Tri6, Quad4}}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}}) +function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}}) return assemble(problem, element, time, Val{:continuum}) end """ Elasticity equations using ForwardDiff - -Formulation ------------ - -Field equation is: -∂u/∂t = ∇⋅f - b - -Weak form is: find u∈U such that ∀v in V - - δW := ∫ρ₀∂²u/∂t²⋅δu dV₀ + ∫S:δE dV₀ - ∫b₀⋅δu dV₀ - ∫t₀⋅δu dA₀ = 0 - -where - - ρ₀ = density - b₀ = displacement load - t₀ = displacement traction - -References ----------- - -https://en.wikipedia.org/wiki/Linear_elasticity -https://en.wikipedia.org/wiki/Finite_strain_theory -https://en.wikipedia.org/wiki/Stress_measures -https://en.wikipedia.org/wiki/Mooney%E2%80%93Rivlin_solid -https://en.wikipedia.org/wiki/Strain_energy_density_function -https://en.wikipedia.org/wiki/Plane_stress -https://en.wikipedia.org/wiki/Hooke's_law - """ function assemble(problem::Problem{Elasticity}, element::Element, time::Real, ::Type{Val{:forwarddiff}}) diff --git a/src/elements.jl b/src/elements.jl index 9cd92f6..1538777 100644 --- a/src/elements.jl +++ b/src/elements.jl @@ -41,7 +41,7 @@ function last(element::Element, field_name::ASCIIString) return last(element[field_name]) end -function call(element::Element, ip, time) +function call(element::Element, ip, time=0.0) return get_basis(element, ip, time) end @@ -75,8 +75,17 @@ function call(element::Element, field_name::ASCIIString, ip, time, ::Type{Val{:G return element(ip, time, Val{:Grad})*element[field_name](time) end +function call(element::Element, field::Field, time) + return field(time) +end + +function call(element::Element, field::DCTI, time) + return field.data +end + function call(element::Element, field_name::ASCIIString, time) - return element[field_name](time) + field = element[field_name] + return call(element, field, time) end function call(element::Element, field_name::ASCIIString, ip, time::Float64) @@ -220,6 +229,7 @@ function update!(elements::Vector, field_name::ASCIIString, data) end end +#= dbasis_cache = ForwardDiff.jacobian """ Evaluate partial derivatives of basis functions using ForwardDiff. """ function get_dbasis(element::Element, ip, time) @@ -227,6 +237,7 @@ function get_dbasis(element::Element, ip, time) basis(xi) = vec(get_basis(element, xi, time)) return ForwardDiff.jacobian(basis, xi)' end +=# """ Check existence of field. """ function haskey(element::Element, field_name) diff --git a/src/fields.jl b/src/fields.jl index 6839f26..a73d113 100644 --- a/src/fields.jl +++ b/src/fields.jl @@ -142,57 +142,55 @@ end ### Accessing and manipulating discrete fields -function Base.getindex(field::DVTV, i::Int64) +function getindex(field::DVTV, i::Int64) return field.data[i] end -function Base.push!(field::DCTV, data::Pair) +function push!(field::DCTV, data::Pair) push!(field.data, data) end -function Base.push!(field::DVTV, data::Pair) -# info("field.data = \n$(field.data)") -# info("data = \n$data") +function push!(field::DVTV, data::Pair) push!(field.data, data) end -function Base.getindex(field::DVTV, i::Int64) +function getindex(field::DVTV, i::Int64) return field.data[i] end -function Base.getindex(field::DVTI, i::Int64) +function getindex(field::DVTI, i::Int64) return field.data[i] end -function Base.getindex(field::DCTV, i::Int64) +function getindex(field::DCTV, i::Int64) return field.data[i] end -function Base.getindex(field::Field, i::Int64) +function getindex(field::Field, i::Int64) return field.data[i] end -function Base.length(field::DVTI) +function length(field::DVTI) return length(field.data) end -function Base.length(field::DCTI) +function length(field::DCTI) return 1 end -function Base.length(field::DVTV) +function length(field::DVTV) return length(field.data) end -function Base.length(field::DCTV) +function length(field::DCTV) return length(field.data) end -function Base.first(field::Union{DCTV, DVTV}) +function first(field::Union{DCTV, DVTV}) return field[1] end -function Base.isapprox(f1::DCTI, f2::DCTI) +function isapprox(f1::DCTI, f2::DCTI) isapprox(f1.data, f2.data) end @@ -236,8 +234,7 @@ function vec(field::DVTI) end function vec(field::DCTV) - info("trying to vectorize $field") - error("does not make sense") + error("trying to vectorize $field does not make sense") end function endof(field::Field) @@ -321,21 +318,21 @@ end ### Interpolation """ Interpolate time-invariant field in time direction. """ -function Base.call(field::DVTI, time::Float64) +function call(field::DVTI, time::Float64) return field end -function Base.call(field::DCTI, time::Float64) +function call(field::DCTI, time::Float64) return field end -function Base.call(field::CVTI, time::Float64) +function call(field::CVTI, time::Float64) return field.data() end -function Base.call(field::CCTI, time::Float64) +function call(field::CCTI, time::Float64) return field.data() end """ Interpolate constant time-variant field in time direction. """ -function Base.call(field::DCTV, time::Real) +function call(field::DCTV, time::Real) time < first(field).time && return DCTI(first(field).data) time > last(field).time && return DCTI(last(field).data) for i=reverse(1:length(field)) @@ -355,7 +352,7 @@ function Base.call(field::DCTV, time::Real) error("interpolate DCTV: unknown failure when interpolating $(field.data) for time $time") end -function Base.call(field::DVTV, time::Float64) +function call(field::DVTV, time::Float64) time < first(field).time && return DVTI(first(field).data) time > last(field).time && return DVTI(last(field).data) for i=reverse(1:length(field)) @@ -376,17 +373,17 @@ function Base.call(field::DVTV, time::Float64) end """ Interpolate constant field in spatial dimension. """ -function Base.call(basis::CVTI, field::DCTI, xi::Vector) +function call(basis::CVTI, field::DCTI, xi::Vector) return field.data end """ Interpolate variable field in spatial dimension. """ -function Base.call(basis::CVTI, values::DVTI, xi::Vector) +function call(basis::CVTI, values::DVTI, xi::Vector) N = basis(xi) return sum([N[i]*values[i] for i=1:length(N)]) end -function Base.call(basis::CVTI, geometry::DVTI, xi::Vector, ::Type{Val{:grad}}) +function call(basis::CVTI, geometry::DVTI, xi::Vector, ::Type{Val{:grad}}) dbasis = basis(xi, Val{:grad}) # J = sum([dbasis[:,i]*geometry[i]' for i=1:length(geometry)]) J = sum([kron(dbasis[:,i], geometry[i]') for i=1:length(geometry)]) @@ -395,14 +392,14 @@ function Base.call(basis::CVTI, geometry::DVTI, xi::Vector, ::Type{Val{:grad}}) return grad end -function Base.call(basis::CVTI, geometry::DVTI, values::DVTI, xi::Vector, ::Type{Val{:grad}}) +function call(basis::CVTI, geometry::DVTI, values::DVTI, xi::Vector, ::Type{Val{:grad}}) grad = call(basis, geometry, xi, Val{:grad}) # gradf = sum([grad[:,i]*values[i]' for i=1:length(geometry)])' gradf = sum([kron(grad[:,i], values[i]') for i=1:length(values)])' return length(gradf) == 1 ? gradf[1] : gradf end -function Base.call(basis::CVTI, xi::Vector, time::Number) +function call(basis::CVTI, xi::Vector, time::Number) call(basis, xi) end @@ -413,3 +410,4 @@ end ### FIELDSET ### typealias FieldSet Dict{ASCIIString, Field} + diff --git a/src/heat.jl b/src/heat.jl index 647cd4f..fb64321 100644 --- a/src/heat.jl +++ b/src/heat.jl @@ -1,13 +1,8 @@ # This file is a part of JuliaFEM. # License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md -# Heat problems - """ Heat equations. -Formulation ------------ - Field equation is: ρc∂u/∂t = ∇⋅(k∇u) + f @@ -27,7 +22,6 @@ Parameters temperature thermal conductivity temperature load temperature flux - thermal conductivity heat source heat flux @@ -43,6 +37,7 @@ References ---------- https://en.wikipedia.org/wiki/Heat_equation https://en.wikipedia.org/wiki/Heat_capacity +https://en.wikipedia.org/wiki/Heat_flux https://en.wikipedia.org/wiki/Thermal_conduction https://en.wikipedia.org/wiki/Thermal_conductivity https://en.wikipedia.org/wiki/Thermal_diffusivity @@ -50,17 +45,18 @@ https://en.wikipedia.org/wiki/Volumetric_heat_capacity """ type Heat <: FieldProblem formulation :: ASCIIString + store_fields :: Vector{ASCIIString} end function Heat() - return Heat("3D") + return Heat("3D", []) end function get_unknown_field_name(problem::Problem{Heat}) return "temperature" end -function assemble!(assembly::Assembly, problem::Problem{Heat}, element::Element, time=0.0) +function assemble!(assembly::Assembly, problem::Problem{Heat}, element::Element, time) formulation = Val{Symbol(problem.properties.formulation)} assemble!(assembly, problem, element, time, formulation) end @@ -71,8 +67,8 @@ function assemble!{E}(assembly::Assembly, problem::Problem{Heat}, element::Eleme info("Unknown element type $E for 3d heat problem!") end -typealias Heat3DVolumeElements Union{Tet4, Tet10, Hex8} -typealias Heat3DSurfaceElements Union{Tri3, Tri6, Quad4} +typealias Heat3DVolumeElements Union{Tet4, Tet10, Hex8, Hex20, Hex27} +typealias Heat3DSurfaceElements Union{Tri3, Tri6, Quad4, Quad8, Quad9} function assemble!{E<:Heat3DVolumeElements}(assembly::Assembly, problem::Problem{Heat}, element::Element{E}, time, ::Type{Val{Symbol("3D")}}) gdofs = get_gdofs(problem, element) @@ -100,13 +96,44 @@ function assemble!{E<:Heat3DVolumeElements}(assembly::Assembly, problem::Problem add!(assembly.f, gdofs, fq) end +function postprocess!{E}(assembly::Assembly, problem::Problem{Heat}, element::Element{E}, time) + haskey(element, "temperature thermal conductivity") || return + gdofs = get_gdofs(problem, element) + field_name = get_unknown_field_name(problem) + nnodes = length(element) + Me = zeros(nnodes, nnodes) + De = zeros(nnodes, nnodes) + f = zeros(nnodes, 3) + for ip in get_integration_points(element) + detJ = element(ip, time, Val{:detJ}) + w = ip.weight*detJ + N = element(ip, time) + De += w*diagm(vec(N)) + Me += w*N'*N + end + Ae = De*inv(Me) + for ip in get_integration_points(element) + detJ = element(ip, time, Val{:detJ}) + w = ip.weight*detJ + N = vec(element(ip, time)) + Phi = transpose(Ae*N) + k = element("temperature thermal conductivity", ip, time) + gradT = element(field_name, ip, time, Val{:Grad}) + q = -vec(k*gradT) + update!(ip, "heat flux", time => q) + f += w*Phi'*q' + end + add!(assembly.M, gdofs, gdofs, De) + add!(assembly.f, gdofs, [1, 2, 3], f) +end + function assemble!{E<:Heat3DSurfaceElements}(assembly::Assembly, problem::Problem{Heat}, element::Element{E}, time, ::Type{Val{Symbol("3D")}}) gdofs = get_gdofs(problem, element) field_name = get_unknown_field_name(problem) nnodes = length(element) K = zeros(nnodes, nnodes) fq = zeros(nnodes) - for ip in get_integration_points(element) + for ip in get_integration_points(element, 1) detJ = element(ip, time, Val{:detJ}) w = ip.weight*detJ N = element(ip, time) diff --git a/src/integrate.jl b/src/integrate.jl index 2aa8277..63f892e 100644 --- a/src/integrate.jl +++ b/src/integrate.jl @@ -67,8 +67,8 @@ end ### 1d elements typealias CartesianLineElement Union{Seg2, Seg3, NSeg} -typealias CartesianSurfaceElement Union{Quad4, NSurf} -typealias CartesianVolumeElement Union{Hex8, NSolid} +typealias CartesianSurfaceElement Union{Quad4, Quad8, Quad9, NSurf} +typealias CartesianVolumeElement Union{Hex8, Hex20, Hex27, NSolid} function get_integration_points(element::CartesianLineElement, order::Int64) w, xi = get_integration_points(order) @@ -238,7 +238,7 @@ end typealias LinearElement Union{Seg2, Tri3, Quad4, Tet4, Hex8} -typealias QuadraticElement Union{Seg3, Tri6, Tet10} +typealias QuadraticElement Union{Seg3, Tri6, Tet10, Quad8, Quad9, Hex20, Hex27} function get_integration_order(element::LinearElement) return 2 diff --git a/src/lagrange.jl b/src/lagrange.jl new file mode 100644 index 0000000..36026cb --- /dev/null +++ b/src/lagrange.jl @@ -0,0 +1,570 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md + +### 0d element + +type Poi1 <: AbstractElement +end + +function description(::Type{Poi1}) + "1 node point" +end + +function size(element::Element{Poi1}) + return (0, 1) +end + +function length(element::Element{Poi1}) + return 1 +end + +function get_basis(element::Element{Poi1}, ip, time) + return [1] +end + +function call(element::Element{Poi1}, ip, time, ::Type{Val{:detJ}}) + return 1.0 +end + +### 1d elements + +type Seg2 <: AbstractElement +end + +function description(::Type{Seg2}) + "2 node segment" +end + +function size(element::Element{Seg2}) + return (1, 2) +end + +function length(element::Element{Seg2}) + return 2 +end + +function get_reference_coordinates(::Type{Seg2}) + Vector{Float64}[ + [-1.0], # N1 + [ 1.0]] # N2 +end + +function get_interpolation_polynomial(::Type{Seg2}, xi) + [1.0 xi[1]] +end + +function get_interpolation_polynomial(::Type{Seg2}, xi, ::Type{Val{:partial_derivatives}}) + [0.0 1.0] +end + +# + +type Seg3 <: AbstractElement +end + +function description(::Type{Seg3}) + "3 node segment" +end + +function size(element::Element{Seg3}) + return (1, 3) +end + +function length(element::Element{Seg3}) + return 3 +end + +function get_reference_coordinates(::Type{Seg3}) + Vector{Float64}[ + [-1.0], # N1 + [ 1.0], # N2 + [ 0.0]] # N3 +end + +function get_interpolation_polynomial(::Type{Seg3}, xi) + [1.0 xi[1] xi[1]^2] +end + +function get_interpolation_polynomial(::Type{Seg3}, xi, ::Type{Val{:partial_derivatives}}) + [0.0 1.0 2.0*xi[1]] +end + +### 2d elements + +type Tri3 <: AbstractElement +end + +function description(::Type{Tri3}) + "3 node triangle" +end + +function size(element::Element{Tri3}) + return (2, 3) +end + +function length(element::Element{Tri3}) + return 3 +end + +function get_reference_coordinates(::Type{Tri3}) + Vector{Float64}[ + [0.0, 0.0], # N1 + [1.0, 0.0], # N2 + [0.0, 1.0]] # N3 +end + +function get_interpolation_polynomial(::Type{Tri3}, xi) + [ + 1 xi[1] xi[2] + ] +end + +function get_interpolation_polynomial(::Type{Tri3}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0.0 1.0 0.0 + 0.0 0.0 1.0 + ] +end + +# + +type Tri6 <: AbstractElement +end + +function description(::Type{Tri6}) + "6 node triangle" +end + +function size(element::Element{Tri6}) + return (2, 6) +end + +function length(element::Element{Tri6}) + return 6 +end + +function get_reference_coordinates(::Type{Tri6}) + Vector{Float64}[ + [0.0, 0.0], # N1 + [1.0, 0.0], # N2 + [0.0, 1.0], # N3 + [0.5, 0.0], # N4 + [0.5, 0.5], # N5 + [0.0, 0.5]] # N6 +end + +function get_interpolation_polynomial(::Type{Tri6}, xi) + [ + 1 xi[1] xi[2] xi[1]^2 xi[1]*xi[2] xi[2]^2 + ] +end + +function get_interpolation_polynomial(::Type{Tri6}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0 1 0 2*xi[1] xi[2] 0 + 0 0 1 0 xi[1] 2*xi[2] + ] +end + +# + +type Quad4 <: AbstractElement +end + +function description(::Type{Quad4}) + "4 node quadrangle" +end + +function size(element::Element{Quad4}) + return (2, 4) +end + +function length(element::Element{Quad4}) + return 4 +end + +function get_reference_coordinates(::Type{Quad4}) + Vector{Float64}[ + [-1.0, -1.0], # N1 + [ 1.0, -1.0], # N2 + [ 1.0, 1.0], # N3 + [-1.0, 1.0]] # N4 +end + +function get_interpolation_polynomial(::Type{Quad4}, xi) + [ + 1.0 xi[1] xi[2] xi[1]*xi[2] + ] +end + +function get_interpolation_polynomial(::Type{Quad4}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0 1 0 xi[2] + 0 0 1 xi[1] + ] +end + +# + +type Quad8 <: AbstractElement +end + +function description(::Type{Quad8}) + "8 node Serendip quadrangle" +end + +function size(element::Element{Quad8}) + return (2, 8) +end + +function length(element::Element{Quad8}) + return 8 +end + +function get_reference_coordinates(::Type{Quad8}) + Vector{Float64}[ + [-1.0, -1.0], # N1 + [ 1.0, -1.0], # N2 + [ 1.0, 1.0], # N3 + [-1.0, 1.0], # N4 + [ 0.0, -1.0], # N5 + [ 1.0, 0.0], # N6 + [ 0.0, 1.0], # N7 + [-1.0, 0.0]] # N8 +end + +function get_interpolation_polynomial(::Type{Quad8}, xi) + [ + 1 xi[2] xi[1] xi[2]^2 xi[1]*xi[2] xi[1]^2 xi[1]*xi[2]^2 xi[1]^2*xi[2] + ] +end + +function get_interpolation_polynomial(::Type{Quad8}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0 0 1 0 xi[2] 2*xi[1] xi[2]^2 2*xi[1]*xi[2] + 0 1 0 2*xi[2] xi[1] 0 2*xi[1]*xi[2] xi[1]^2 + ] +end + +# + +type Quad9 <: AbstractElement +end + +function description(::Type{Quad9}) + "9 node quadrangle" +end + +function size(element::Element{Quad9}) + return (2, 9) +end + +function length(element::Element{Quad9}) + return 9 +end + +function get_reference_coordinates(::Type{Quad9}) + Vector{Float64}[ + [-1.0, -1.0], # N1 + [ 1.0, -1.0], # N2 + [ 1.0, 1.0], # N3 + [-1.0, 1.0], # N4 + [ 0.0, -1.0], # N5 + [ 1.0, 0.0], # N6 + [ 0.0, 1.0], # N7 + [-1.0, 0.0], # N8 + [ 0.0, 0.0]] # N9 +end + +function get_interpolation_polynomial(::Type{Quad9}, xi) + [ + 1 xi[2] xi[1] xi[2]^2 xi[1]*xi[2] xi[1]^2 xi[1]*xi[2]^2 xi[1]^2*xi[2] xi[1]^2*xi[2]^2 + ] +end + +function get_interpolation_polynomial(::Type{Quad9}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0 0 1 0 xi[2] 2*xi[1] xi[2]^2 2*xi[1]*xi[2] 2*xi[1]*xi[2]^2 + 0 1 0 2*xi[2] xi[1] 0 2*xi[1]*xi[2] xi[1]^2 2*xi[1]^2*xi[2] + ] +end + +### 3d elements + +type Tet4 <: AbstractElement +end + +function description(::Type{Tet4}) + "4 node tetrahedral element" +end + +function size(element::Element{Tet4}) + return (3, 4) +end + +function length(element::Element{Tet4}) + return 4 +end + +function get_reference_coordinates(::Type{Tet4}) + Vector{Float64}[ + [0.0, 0.0, 0.0], # N1 + [1.0, 0.0, 0.0], # N2 + [0.0, 1.0, 0.0], # N3 + [0.0, 0.0, 1.0]] # N4 +end + +function get_interpolation_polynomial(::Type{Tet4}, xi) + [ + 1.0 xi[1] xi[2] xi[3] + ] +end + +function get_interpolation_polynomial(::Type{Tet4}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0.0 1.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + 0.0 0.0 0.0 1.0 + ] +end + +# + +type Tet10 <: AbstractElement +end + +function description(::Type{Tet10}) + "10 node tetrahedral element" +end + +function size(element::Element{Tet10}) + return (3, 10) +end + +function length(element::Element{Tet10}) + return 10 +end + +function get_reference_coordinates(::Type{Tet10}) + Vector{Float64}[ + [0.0, 0.0, 0.0], # N1 + [1.0, 0.0, 0.0], # N2 + [0.0, 1.0, 0.0], # N3 + [0.0, 0.0, 1.0], # N4 + [0.5, 0.0, 0.0], # N5 + [0.5, 0.5, 0.0], # N6 + [0.0, 0.5, 0.0], # N7 + [0.0, 0.0, 0.5], # N8 + [0.5, 0.0, 0.5], # N9 + [0.0, 0.5, 0.5]] # N10 +end + +function get_interpolation_polynomial(::Type{Tet10}, xi) + [ + 1.0 xi[3] xi[2] xi[1] xi[3]^2 xi[2]*xi[3] xi[2]^2 xi[1]*xi[3] xi[1]*xi[2] xi[1]^2 + ] +end + +function get_interpolation_polynomial(::Type{Tet10}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0 0 0 1 0 0 0 xi[3] xi[2] 2*xi[1] + 0 0 1 0 0 xi[3] 2*xi[2] 0 xi[1] 0 + 0 1 0 0 2*xi[3] xi[2] 0 xi[1] 0 0 + ] +end + +# + +type Hex8 <: AbstractElement +end + +function description(::Type{Hex8}) + "8 node hexahedral element" +end + +function size(element::Element{Hex8}) + return (3, 8) +end + +function length(element::Element{Hex8}) + return 8 +end + +function get_reference_coordinates(::Type{Hex8}) + Vector{Float64}[ + [-1.0, -1.0, -1.0], # N1 + [ 1.0, -1.0, -1.0], # N2 + [ 1.0, 1.0, -1.0], # N3 + [-1.0, 1.0, -1.0], # N4 + [-1.0, -1.0, 1.0], # N5 + [ 1.0, -1.0, 1.0], # N6 + [ 1.0, 1.0, 1.0], # N7 + [-1.0, 1.0, 1.0]] # N8 +end + +function get_interpolation_polynomial(::Type{Hex8}, xi) + [ + 1 xi[3] xi[2] xi[1] xi[2]*xi[3] xi[1]*xi[3] xi[1]*xi[2] xi[1]*xi[2]*xi[3] + ] +end + +function get_interpolation_polynomial(::Type{Hex8}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0 0 0 1 0 xi[3] xi[2] xi[2]*xi[3] + 0 0 1 0 xi[3] 0 xi[1] xi[1]*xi[3] + 0 1 0 0 xi[2] xi[1] 0 xi[1]*xi[2] + ] +end + +# + +type Hex20 <: AbstractElement +end + +function description(::Type{Hex20}) + "20 node hexahedral element" +end + +function size(element::Element{Hex20}) + return (3, 20) +end + +function length(element::Element{Hex20}) + return 20 +end + +function get_reference_coordinates(::Type{Hex20}) + Vector{Float64}[ + [-1.0, -1.0, -1.0], # N1 + [ 1.0, -1.0, -1.0], # N2 + [ 1.0, 1.0, -1.0], # N3 + [-1.0, 1.0, -1.0], # N4 + [-1.0, -1.0, 1.0], # N5 + [ 1.0, -1.0, 1.0], # N6 + [ 1.0, 1.0, 1.0], # N7 + [-1.0, 1.0, 1.0], # N8 + [ 0.0, -1.0, -1.0], # N9 + [ 1.0, 0.0, -1.0], # N10 + [ 0.0, 1.0, -1.0], # N11 + [-1.0, 0.0, -1.0], # N12 + [-1.0, -1.0, 0.0], # N13 + [ 1.0, -1.0, 0.0], # N14 + [ 1.0, 1.0, 0.0], # N15 + [-1.0, 1.0, 0.0], # N16 + [ 0.0, -1.0, 1.0], # N17 + [ 1.0, 0.0, 1.0], # N18 + [ 0.0, 1.0, 1.0], # N19 + [-1.0, 0.0, 1.0]] # N20 +end + +function get_interpolation_polynomial(::Type{Hex20}, xi) + [ + 1 xi[3] xi[2] xi[1] xi[2]*xi[3] xi[1]*xi[3] xi[1]*xi[2] xi[1]*xi[2]*xi[3] xi[3]^2 xi[2]^2 xi[1]^2 xi[2]*xi[3]^2 xi[2]^2*xi[3] xi[1]*xi[3]^2 xi[1]*xi[2]^2 xi[1]^2*xi[3] xi[1]^2*xi[2] xi[1]*xi[2]*xi[3]^2 xi[1]*xi[2]^2*xi[3] xi[1]^2*xi[2]*xi[3] + ] +end + +function get_interpolation_polynomial(::Type{Hex20}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0 0 0 1 0 xi[3] xi[2] xi[2]*xi[3] 0 0 2*xi[1] 0 0 xi[3]^2 xi[2]^2 2*xi[1]*xi[3] 2*xi[1]*xi[2] xi[2]*xi[3]^2 xi[2]^2*xi[3] 2*xi[1]*xi[2]*xi[3] + 0 0 1 0 xi[3] 0 xi[1] xi[1]*xi[3] 0 2*xi[2] 0 xi[3]^2 2*xi[2]*xi[3] 0 2*xi[1]*xi[2] 0 xi[1]^2 xi[1]*xi[3]^2 2*xi[1]*xi[2]*xi[3] xi[1]^2*xi[3] + 0 1 0 0 xi[2] xi[1] 0 xi[1]*xi[2] 2*xi[3] 0 0 2*xi[2]*xi[3] xi[2]^2 2*xi[1]*xi[3] 0 xi[1]^2 0 2*xi[1]*xi[2]*xi[3] xi[1]*xi[2]^2 xi[1]^2*xi[2] + ] +end + +### + +type Hex27 <: AbstractElement +end + +function description(::Type{Hex27}) + "27 node hexahedral element" +end + +function size(element::Element{Hex27}) + return (3, 27) +end + +function length(element::Element{Hex27}) + return 27 +end + +function get_reference_coordinates(::Type{Hex27}) + Vector{Float64}[ + [-1.0, -1.0, -1.0], # N1 + [ 1.0, -1.0, -1.0], # N2 + [ 1.0, 1.0, -1.0], # N3 + [-1.0, 1.0, -1.0], # N4 + [-1.0, -1.0, 1.0], # N5 + [ 1.0, -1.0, 1.0], # N6 + [ 1.0, 1.0, 1.0], # N7 + [-1.0, 1.0, 1.0], # N8 + [ 0.0, -1.0, -1.0], # N9 + [ 1.0, 0.0, -1.0], # N10 + [ 0.0, 1.0, -1.0], # N11 + [-1.0, 0.0, -1.0], # N12 + [-1.0, -1.0, 0.0], # N13 + [ 1.0, -1.0, 0.0], # N14 + [ 1.0, 1.0, 0.0], # N15 + [-1.0, 1.0, 0.0], # N16 + [ 0.0, -1.0, 1.0], # N17 + [ 1.0, 0.0, 1.0], # N18 + [ 0.0, 1.0, 1.0], # N19 + [-1.0, 0.0, 1.0], # N20 + [ 0.0, 0.0, -1.0], # N21 + [ 0.0, -1.0, 0.0], # N22 + [ 1.0, 0.0, 0.0], # N23 + [ 0.0, 1.0, 0.0], # N24 + [-1.0, 0.0, 0.0], # N25 + [ 0.0, 0.0, 1.0], # N26 + [ 0.0, 0.0, 0.0]] # N27 +end + +function get_interpolation_polynomial(::Type{Hex27}, xi) + [ + 1 xi[3] xi[2] xi[1] xi[2]*xi[3] xi[1]*xi[3] xi[1]*xi[2] xi[1]*xi[2]*xi[3] xi[3]^2 xi[2]^2 xi[1]^2 xi[2]*xi[3]^2 xi[2]^2*xi[3] xi[1]*xi[3]^2 xi[1]*xi[2]^2 xi[1]^2*xi[3] xi[1]^2*xi[2] xi[2]^2*xi[3]^2 xi[1]*xi[2]*xi[3]^2 xi[1]*xi[2]^2*xi[3] xi[1]^2*xi[3]^2 xi[1]^2*xi[2]*xi[3] xi[1]^2*xi[2]^2 xi[1]*xi[2]^2*xi[3]^2 xi[1]^2*xi[2]*xi[3]^2 xi[1]^2*xi[2]^2*xi[3] xi[1]^2*xi[2]^2*xi[3]^2 + ] +end + +function get_interpolation_polynomial(::Type{Hex27}, xi, ::Type{Val{:partial_derivatives}}) + [ + 0 0 0 1 0 xi[3] xi[2] xi[2]*xi[3] 0 0 2*xi[1] 0 0 xi[3]^2 xi[2]^2 2*xi[1]*xi[3] 2*xi[1]*xi[2] 0 xi[2]*xi[3]^2 xi[2]^2*xi[3] 2*xi[1]*xi[3]^2 2*xi[1]*xi[2]*xi[3] 2*xi[1]*xi[2]^2 xi[2]^2*xi[3]^2 2*xi[1]*xi[2]*xi[3]^2 2*xi[1]*xi[2]^2*xi[3] 2*xi[1]*xi[2]^2*xi[3]^2 + 0 0 1 0 xi[3] 0 xi[1] xi[1]*xi[3] 0 2*xi[2] 0 xi[3]^2 2*xi[2]*xi[3] 0 2*xi[1]*xi[2] 0 xi[1]^2 2*xi[2]*xi[3]^2 xi[1]*xi[3]^2 2*xi[1]*xi[2]*xi[3] 0 xi[1]^2*xi[3] 2*xi[1]^2*xi[2] 2*xi[1]*xi[2]*xi[3]^2 xi[1]^2*xi[3]^2 2*xi[1]^2*xi[2]*xi[3] 2*xi[1]^2*xi[2]*xi[3]^2 + 0 1 0 0 xi[2] xi[1] 0 xi[1]*xi[2] 2*xi[3] 0 0 2*xi[2]*xi[3] xi[2]^2 2*xi[1]*xi[3] 0 xi[1]^2 0 2*xi[2]^2*xi[3] 2*xi[1]*xi[2]*xi[3] xi[1]*xi[2]^2 2*xi[1]^2*xi[3] xi[1]^2*xi[2] 0 2*xi[1]*xi[2]^2*xi[3] 2*xi[1]^2*xi[2]*xi[3] xi[1]^2*xi[2]^2 2*xi[1]^2*xi[2]^2*xi[3] + ] +end + +### + +macro create_basis(T) + quote + T = $T + global get_basis, get_dbasis, length, size + X = get_reference_coordinates(T) + nbasis = length(X) + A = zeros(nbasis, nbasis) + for i=1:nbasis + A[i,:] = get_interpolation_polynomial(T, X[i]) + end + invA = inv(A) + function get_basis(element::Element{$T}, ip, time) + return get_interpolation_polynomial($T, ip)*invA + end + function get_dbasis(element::Element{$T}, ip, time) + return get_interpolation_polynomial($T, ip, Val{:partial_derivatives})*invA + end + end +end + +@create_basis Seg2 +@create_basis Seg3 +@create_basis Tri3 +@create_basis Tri6 +@create_basis Quad4 +@create_basis Quad8 +@create_basis Quad9 +@create_basis Tet4 +@create_basis Tet10 +@create_basis Hex8 +@create_basis Hex20 +@create_basis Hex27 + diff --git a/src/lagrange_macro.jl b/src/lagrange_macro.jl index e9b7ab2..08545be 100644 --- a/src/lagrange_macro.jl +++ b/src/lagrange_macro.jl @@ -30,7 +30,7 @@ Examples macro create_lagrange_element(element_name, element_description, X, P) eltype = esc(element_name) quote - global get_basis, length, size + global get_basis, length, size, get_reference_coordinates #= get_reference_element_coordinates, get_reference_element_midpoint @@ -54,91 +54,16 @@ macro create_lagrange_element(element_name, element_description, X, P) return size($X, 2) end - #= XX = refcoords($X) - function get_reference_element_coordinates(::Type{$eltype}) + function get_reference_coordinates(::Type{$eltype}) return XX end - XXX = vec(mean($X, 2)) - function get_reference_element_midpoint(::Type{$eltype}) - return XXX - end - - function $eltype(args...) - return Element{$eltype}(args...) - end - - =# - end end -# 1d Lagrange elements - -@create_lagrange_element(Seg2, "2 node linear line element", - [-1.0 1.0], (xi) -> [1.0, xi[1]]) - -@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_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_lagrange_element(Tri6, "6 node quadratic triangle element", - [0.0 1.0 0.0 0.5 0.5 0.0 - 0.0 0.0 1.0 0.0 0.5 0.5], - (xi) -> [1.0, xi[1], xi[2], xi[1]^2, xi[2]^2, xi[1]*xi[2]]) - -@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]]) - -@create_lagrange_element(Quad9, "9 node bilinear quadrangle element", - [-1.0 1.0 1.0 -1.0 0.0 1.0 0.0 -1.0 - -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0], - (xi) -> [1.0, xi[1], xi[2], xi[1]*xi[2], - xi[1]^2, xi[2]^2, xi[1]^2*xi[2], xi[1]*xi[2]^2]) - # 3d Lagrange elements -@create_lagrange_element(Hex8, "8 node hexahedra", - [-1.0 1.0 1.0 -1.0 -1.0 1.0 1.0 -1.0 - -1.0 -1.0 1.0 1.0 -1.0 -1.0 1.0 1.0 - -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], xi[3], - xi[1]*xi[3], xi[2]*xi[3], xi[1]*xi[2]*xi[3]]) - -#= -@create_lagrange_element(Hex20, "20 node hexahedra", - [ - -1.0 1.0 1.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0 -1.0 - -1.0 -1.0 1.0 1.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0 -1.0 -1.0 1.0 1.0 -1.0 0.0 1.0 0.0 - -1.0 -1.0 -1.0 -1.0 1.0 1.0 1.0 1.0 -1.0 -1.0 -1.0 -1.0 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 - ], - (xi) -> [1.0, xi[1], xi[2], xi[1]*xi[2], xi[3], xi[1]*xi[3], xi[2]*xi[3], xi[1]*xi[2]*xi[3] - x[1]^2, - ]) -=# - -@create_lagrange_element(Tet4, "4 node tetrahedron", - [0.0 1.0 0.0 0.0 - 0.0 0.0 1.0 0.0 - 0.0 0.0 0.0 1.0], - (xi) -> [1.0, xi[1], xi[2], xi[3]]) - -@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], - (xi) -> [ 1.0, xi[1], xi[2], xi[3], xi[1]^2, - xi[2]^2, xi[3]^2, xi[1]*xi[2], xi[2]*xi[3], xi[3]*xi[1]]) - function get_reference_element_midpoint{E}(element::Element{E}) get_reference_element_midpoint(E) end diff --git a/src/postprocess_utils.jl b/src/postprocess_utils.jl index ca33f40..3f91da1 100644 --- a/src/postprocess_utils.jl +++ b/src/postprocess_utils.jl @@ -85,6 +85,20 @@ function get_nodal_vector(elements, field_name, time) return node_ids, field end +""" Return nodal values in Dict format. """ +function get_nodal_dict(T::DataType, elements, field_name, time) + f = T() + for element in elements + for (c, v) in zip(get_connectivity(element), element(field_name, time)) + if haskey(f, c) + @assert isapprox(f[c], v) + end + f[c] = v + end + end + return f +end + """ Update nodal field values from set of elements to another. Can be used to transform e.g. reaction force from boundary element set to surface of volume elements for easier postprocess. @@ -114,3 +128,17 @@ function copy_field!(src_problem::Problem, dst_problem::Problem, field_name, tim copy_field!(src_problem.elements, dst_problem.elements, field_name, time) end +""" Return field calculated to nodal points for elements in problem p. """ +function call(problem::Problem, field_name, time=0.0) + f = Dict() + for element in get_elements(problem) + for (c, v) in zip(get_connectivity(element), element(field_name, time)) + if haskey(f, c) + @assert isapprox(f[c], v) + end + f[c] = v + end + end + return f +end + diff --git a/src/preprocess.jl b/src/preprocess.jl index aa40855..0590567 100644 --- a/src/preprocess.jl +++ b/src/preprocess.jl @@ -1,6 +1,17 @@ # This file is a part of JuliaFEM. # License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md +#= +- read meshes from different formats +- reorder connectivity, create element sets, node sets, ... +- create partitions for parallel runs +- renumber elements / nodes +- maybe precheck for bad elements +- check surface normal direction in boundary elements +- orientation of 2d elements +- etc only topology related stuff +=# + importall Base using JuliaFEM @@ -88,8 +99,25 @@ function create_elements(mesh::Mesh) return elements end -function create_elements(mesh::Mesh, element_set::ASCIIString) - return create_elements(filter_by_element_set(mesh, element_set)) +function create_elements(mesh::Mesh, element_sets::ASCIIString...) + elements = Element[] + for element_set in element_sets + new_elements = create_elements(filter_by_element_set(mesh, element_set)) + push!(elements, new_elements...) + end + return elements +end + +function create_elements(mesh::Mesh, element_type::Symbol) + elements = Element[] + for (elid, elcon) in mesh.elements + eltype = mesh.element_types[elid] + eltype == element_type || continue + element = Element(JuliaFEM.(eltype), elcon) + update!(element, "geometry", mesh.nodes) + push!(elements, element) + end + return elements end """ find npts nearest nodes form mesh and return id numbers as list. """ @@ -104,3 +132,38 @@ function find_nearest_nodes(mesh::Mesh, coords::Vector, npts=1) return node_ids end +""" +Apply new node ordering to elements. In JuliaFEM same node ordering is used +than in ABAQUS and if mesh is parsed from FEM format with other node ordering +this can be used to reorder nodes. + +Parameters +---------- +mapping :: Dict{Symbol, Vector{Int}} + e.g. :Tet10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +""" +function reorder_element_connectivity!(mesh::Mesh, mapping::Dict{Symbol, Vector{Int}}) + for (elid, eltype) in mesh.element_types + haskey(mapping, eltype) || continue + new_order = mapping[eltype] + element_connectivity = mesh.elements[elid] + new_element_connectivity = element_connectivity[new_order] + mesh.elements[elid] = new_element_connectivity + end +end + +""" +Swap surface element connectivity s.t. normals point outward +""" +function check_orientation! + # TODO +end + +""" +Partition model using METIS +""" +function partition_model! + # TODO +end + diff --git a/src/preprocess_aster_reader.jl b/src/preprocess_aster_reader.jl index 429d980..8dc22b4 100644 --- a/src/preprocess_aster_reader.jl +++ b/src/preprocess_aster_reader.jl @@ -309,18 +309,6 @@ function get_element_sets(med::MEDFile, mesh_name) return es end -global const med_elmap = Dict{Symbol, Vector{Int}}( - :PO1 => [1], - :SE2 => [1, 2], - :SE3 => [1, 2, 3], - :TR3 => [1, 2, 3], - :QU4 => [1, 2, 3, 4], - :TE4 => [3, 2, 1, 4], - :TR6 => [1, 2, 3, 4, 5, 6], - :QU8 => [1, 2, 3, 4, 5, 6, 7, 8], - :HE8 => [4, 8, 7, 3, 1, 5, 6, 2], # ..? - :T10 => [3, 2, 1, 4, 6, 5, 7, 10, 9, 8]) - function get_connectivity(med::MEDFile, elsets, mesh_name) elsets[0] = :OTHER increments = keys(med.data["ENS_MAA"][mesh_name]) @@ -340,12 +328,14 @@ function get_connectivity(med::MEDFile, elsets, mesh_name) eltype = Symbol(eltype) elco = element_connectivity[:, i] elset = Symbol(elsets[elset_ids[i]]) +#= to more general preprocess if haskey(med_elmap, eltype) elco = elco[med_elmap[eltype]] else warn("no element mapping info found for element type $eltype") warn("consider this as a warning: element may have french nodal ordering") end +=# d[element_ids[i]] = (eltype, elset, elco) end end @@ -390,21 +380,56 @@ function parse_aster_med_file(fn::ASCIIString, mesh_name=nothing; debug=false) return result end +# some glues about ordering, this is still a mystery.. +# http://onelab.info/pipermail/gmsh/2008/003850.html +# http://caelinux.org/wiki/index.php/Proj:UNVConvert + +#global const med_connectivity = Dict{Symbol, Vector{Int}}( +# :Tet4 => [3, 2, 1, 4], +# :Hex8 => [4, 8, 7, 3, 1, 5, 6, 2], # ..? +# :Tet10 => [3, 2, 1, 4, 6, 5, 7, 10, 9, 8]) + +global const med_connectivity = Dict{Symbol, Vector{Int}}( + :Tet4 => [4,3,1,2], + :Tet10 => [4,3,1,2,10,7,8,9,6,5], + :Hex8 => [4,8,7,3,1,5,6,2], + :Hex20 => [4,8,7,3,1,5,6,2,20,15,19,11,12,16,14,10,17,13,18,9], + :Hex27 => [4,8,7,3,1,5,6,2,20,15,19,11,12,16,14,10,17,13,18,9,24,25,26,23,21,22,27]) + +# element names in CA -> element names in JuliaFEM global const mapping = Dict( + :PO1 => :Poi1, + :SE2 => :Seg2, :SE3 => :Seg3, + :SE4 => :Seg4, + :TR3 => :Tri3, :TR6 => :Tri6, + :TR7 => :Tru6, + :QU4 => :Quad4, :QU8 => :Quad8, :QU9 => :Quad9, + + :TE4 => :Tet4, + :T10 => :Tet10, + + :PE6 => :Penta6, + :P15 => :Penta15, + :P18 => :Penta18, + :HE8 => :Hex8, :H20 => :Hex20, - :TE4 => :Tet4, - :T10 => :Tet10) + :H27 => :Hex27, -function aster_read_mesh(fn::ASCIIString, mesh_name=nothing) + :PY5 => :Pyramid5, + :P13 => :Pyramid13, + + ) + +function aster_read_mesh(fn::ASCIIString, mesh_name=nothing; reorder_element_connectivity=true) result = parse_aster_med_file(fn, mesh_name) mesh = Mesh() for (nid, (nset, ncoords)) in result["nodes"] @@ -416,6 +441,9 @@ function aster_read_mesh(fn::ASCIIString, mesh_name=nothing) add_element!(mesh, elid, mapping[eltype], elcon) add_element_to_element_set!(mesh, string(elset), elid) end + if reorder_element_connectivity + reorder_element_connectivity!(mesh, med_connectivity) + end return mesh end diff --git a/src/problems.jl b/src/problems.jl index efedf4f..0ed6480 100644 --- a/src/problems.jl +++ b/src/problems.jl @@ -266,10 +266,14 @@ function update_elements!{P<:BoundaryProblem}(problem::Problem{P}, u, la) end end -function get_elements(problem) +function get_elements(problem::Problem) return problem.elements end +function length(problem::Problem) + return length(problem.elements) +end + function update!(problem::Problem, field_name::ASCIIString, field) update!(problem.elements, field_name, field) end @@ -297,6 +301,12 @@ function push!(problem::Problem, elements::Vector) push!(problem.elements, elements...) end +function push!(problem::Problem, elements_::Vector...) + for elements in elements_ + push!(problem.elements, elements...) + end +end + function get_gdofs(element::Element, dim::Int) conn = get_connectivity(element) if length(conn) == 0 diff --git a/src/solvers.jl b/src/solvers.jl index 4d412be..5aa4fc5 100644 --- a/src/solvers.jl +++ b/src/solvers.jl @@ -207,11 +207,11 @@ conditions are first eliminated before solution. """ function solve!(K, C1, C2, D, f, g, u, la, ::Type{Val{1}}; F=nothing, debug=false) - nnz(D) == 0 || return false + nnz(D) == 0 || return F, false nz = get_nonzero_rows(C2) B = get_nonzero_rows(C2') # C2^-1 exists or this doesn't work - length(nz) == length(B) || return false + length(nz) == length(B) || return F, false A = get_nonzero_rows(K) I = setdiff(A, B) @@ -227,8 +227,7 @@ function solve!(K, C1, C2, D, f, g, u, la, ::Type{Val{1}}; F=nothing, debug=fals try u[B] = lufact(C2[nz,B]) \ full(g[nz]) catch - info("solver #1 failed to solve boundary dofs (you should not see this message).") - return false + error("solver #1 failed to solve boundary dofs (you should not see this message).") end # solve interior domain using LDLt factorization @@ -296,9 +295,7 @@ function solve_linear_system(solver::Solver; F=nothing, empty_assemblies_before_ i = 0 for i in [1, 2] F, status = solve!(K, C1, C2, D, f, g, u, la, Val{i}; F=F) - if status - break - end + status && break end status || error("Failed to solve linear system!") @@ -467,11 +464,6 @@ Main differences in this solver, compared to nonlinear solver are: """ type Linear <: AbstractSolver - norms :: Vector{Tuple} -end - -function Linear() - solver = Linear([]) end function assemble!(solver::Solver{Linear}; show_info=true) @@ -526,3 +518,66 @@ end ### End of linear quasistatic solver +### Postprocessor + +type Postprocessor <: AbstractSolver + assembly :: Assembly + F :: Union{Factorization, Void} +end + +function Postprocessor() + Postprocessor(Assembly(), nothing) +end + +function assemble!(solver::Solver{Postprocessor}; show_info=true) + show_info && info("Assembling problems ...") + tic() + nproblems = 0 + ndofs = 0 + assembly = solver.properties.assembly + empty!(assembly) + for problem in get_problems(solver) + for element in get_elements(problem) + postprocess!(assembly, problem, element, solver.time) + end + nproblems += 1 + ndofs = max(ndofs, size(problem.assembly.K, 2)) + end + solver.ndofs = ndofs + t1 = round(toq(), 2) + show_info && info("Assembled $nproblems problems in $t1 seconds. ndofs = $ndofs.") +end + +function call(solver::Solver{Postprocessor}; show_info=true) + t0 = Base.time() + show_info && info(repeat("-", 80)) + show_info && info("Starting postprocessor") + show_info && info("Increment time t=$(round(solver.time, 3))") + show_info && info(repeat("-", 80)) + initialize!(solver) + assemble!(solver) + assembly = solver.properties.assembly + M = sparse(assembly.M) + f = sparse(assembly.f) + F = cholfact(M) + q = F \ f + t1 = round(Base.time()-t0, 2) + show_info && info("Postprocess of results ready in $t1 seconds.") + return q +end + +""" Convenience function to call postprocessor. """ +function Postprocessor(problems::Problem...) + solver = Solver(Postprocessor, "default postprocessor") + if length(problems) != 0 + push!(solver, problems...) + end + return solver +end + +function Postprocessor(name::ASCIIString, problems::Problem...) + solver = Postprocessor(problems...) + solver.name = name + return solver +end + diff --git a/test/testdata/primitives.hdf b/test/testdata/primitives.hdf new file mode 100644 index 0000000000000000000000000000000000000000..233bdc1926852de7e01dc79dc6635e236102d878 GIT binary patch literal 537840 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

oN{0vd0cnoMs~8Vh<_8|gej&~ASjBk2 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 E4|LaRYXATM literal 0 HcmV?d00001 diff --git a/test/testdata/primitives.med b/test/testdata/primitives.med new file mode 100644 index 0000000000000000000000000000000000000000..851c4e31bc552b44f0972f6e7cc72f2cdef0072b GIT binary patch literal 70524 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 literal 0 HcmV?d00001