mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-19 17:58:53 +00:00
julia v0.5 compatibility. test -> testing. new elements tri7 and wedge6. abaqus inp reading. more integration rules.
This commit is contained in:
+24
-11
@@ -6,8 +6,6 @@ This is JuliaFEM -- Finite Element Package
|
||||
"""
|
||||
module JuliaFEM
|
||||
|
||||
using Compat
|
||||
import Compat.String
|
||||
importall Base
|
||||
|
||||
include("fields.jl")
|
||||
@@ -18,13 +16,15 @@ export AbstractPoint, Point, IntegrationPoint, IP, Node
|
||||
### ELEMENTS ###
|
||||
include("elements.jl") # common element routines
|
||||
export Node, AbstractElement, Element, update!, get_connectivity, get_basis, get_dbasis, inside, get_local_coordinates
|
||||
include("elements_lagrange_macro.jl") # Continuous Galerkin (Lagrange) elements generated using macro
|
||||
include("elements_lagrange.jl") # Continuous Galerkin (Lagrange) elements
|
||||
export get_reference_coordinates, get_interpolation_polynomial
|
||||
export Poi1,
|
||||
Seg2, Seg3,
|
||||
Tri3, Tri6, Quad4, Quad8, Quad9,
|
||||
Tet4, Tet10, Hex8, Hex20, Hex27
|
||||
Tri3, Tri6, Tri7,
|
||||
Quad4, Quad8, Quad9,
|
||||
Tet4, Tet10,
|
||||
Wedge6,
|
||||
Hex8, Hex20, Hex27
|
||||
|
||||
include("elements_nurbs.jl")
|
||||
export NSeg, NSurf, NSolid, is_nurbs
|
||||
@@ -59,7 +59,7 @@ end
|
||||
|
||||
### ASSEMBLY + SOLVE ###
|
||||
include("assembly.jl")
|
||||
include("solver_utils.jl")
|
||||
include("solvers_utils.jl")
|
||||
include("solvers.jl")
|
||||
export AbstractSolver, Solver, Nonlinear, NonlinearSolver, Linear, LinearSolver,
|
||||
get_unknown_field_name, get_formulation_type, get_problems,
|
||||
@@ -91,10 +91,12 @@ include("problems_contact_3d.jl")
|
||||
include("problems_contact_2d_autodiff.jl")
|
||||
export Contact
|
||||
|
||||
#=
|
||||
module API
|
||||
include("api.jl")
|
||||
# export ....
|
||||
end
|
||||
=#
|
||||
|
||||
module Preprocess
|
||||
include("preprocess.jl")
|
||||
@@ -106,8 +108,8 @@ export create_elements, Mesh,
|
||||
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
|
||||
export parse_abaqus, parse_section, parse_element_section,
|
||||
abaqus_read_mesh, abaqus_read_model
|
||||
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!,
|
||||
@@ -115,11 +117,11 @@ export aster_create_elements, parse_aster_med_file, is_aster_mail_keyword,
|
||||
filter_by_element_set, filter_by_element_id, MEDFile
|
||||
end
|
||||
|
||||
function get_mesh(mesh_name::String, args...; kwargs...)
|
||||
function get_mesh(mesh_name::AbstractString, args...; kwargs...)
|
||||
return get_mesh(Val{Symbol(mesh_name)}, args...; kwargs...)
|
||||
end
|
||||
|
||||
function get_model(model_name::String, args...; kwargs...)
|
||||
function get_model(model_name::AbstractString, args...; kwargs...)
|
||||
return get_model(Val{Symbol(model_name)}, args...; kwargs...)
|
||||
end
|
||||
|
||||
@@ -136,8 +138,15 @@ export XDMF, xdmf_new_result!, xdmf_save_field!, xdmf_save!
|
||||
end
|
||||
export Postprocessor
|
||||
|
||||
# This connects model from preprocess_abaqus_reader to
|
||||
# other JuliaFEM ecosystem and solves problem.
|
||||
module Abaqus
|
||||
include("abaqus.jl")
|
||||
export abaqus_read_model
|
||||
end
|
||||
|
||||
""" JuliaFEM testing routines. """
|
||||
module Test
|
||||
module Testing
|
||||
if VERSION >= v"0.5-"
|
||||
using Base.Test
|
||||
else
|
||||
@@ -148,12 +157,16 @@ export @test, @testset, @test_throws
|
||||
#include("test.jl")
|
||||
end
|
||||
|
||||
#=
|
||||
module MaterialModels
|
||||
include("vonmises.jl")
|
||||
end
|
||||
=#
|
||||
|
||||
#=
|
||||
module Interfaces
|
||||
include("interfaces.jl")
|
||||
end
|
||||
=#
|
||||
|
||||
end # module
|
||||
|
||||
+386
@@ -0,0 +1,386 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
importall Base
|
||||
using JuliaFEM.Preprocess
|
||||
|
||||
global const ABAQUS_SECTIONS = [
|
||||
"HEADING", "NODE", "ELEMENT", "SOLID SECTION",
|
||||
"MATERIAL", "NSET", "SURFACE", "STEP"]
|
||||
|
||||
global const ABAQUS_SUBSECTIONS = [
|
||||
"ELASTIC", "DENSITY", "SPECIFIC HEAT", "CONDUCTIVITY",
|
||||
"STATIC", "BOUNDARY", "DSLOAD", "OUTPUT", "NODE FILE",
|
||||
"RESTART", "END STEP"]
|
||||
|
||||
abstract AbstractMaterial
|
||||
abstract AbstractProperty
|
||||
abstract AbstractStep
|
||||
|
||||
type Model
|
||||
mesh :: Mesh
|
||||
materials :: Dict
|
||||
properties :: Vector
|
||||
steps :: Vector
|
||||
end
|
||||
|
||||
function Model()
|
||||
return Model(Mesh(), Dict(), Vector(), Vector())
|
||||
end
|
||||
|
||||
function push!(model::Model, property::AbstractProperty)
|
||||
push!(model.properties, property)
|
||||
end
|
||||
|
||||
function push!(model::Model, step::AbstractStep)
|
||||
push!(model.steps, step)
|
||||
end
|
||||
|
||||
###
|
||||
|
||||
type Keyword
|
||||
name
|
||||
options
|
||||
end
|
||||
|
||||
function Keyword()
|
||||
return Keyword(nothing, nothing)
|
||||
end
|
||||
|
||||
function getindex(kw::Keyword, s)
|
||||
return parse(Dict(kw.options)[s])
|
||||
end
|
||||
|
||||
type AbaqusReaderState
|
||||
section
|
||||
subsection
|
||||
material
|
||||
property
|
||||
step
|
||||
data
|
||||
end
|
||||
|
||||
function parse(s::AbaqusReaderState)
|
||||
data = []
|
||||
for row in s.data
|
||||
col = split(row, ',')
|
||||
col = map(parse, col)
|
||||
push!(data, col)
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
function AbaqusReaderState()
|
||||
return AbaqusReaderState(Keyword(), Keyword(), nothing, nothing, nothing, [])
|
||||
end
|
||||
|
||||
|
||||
function is_comment(line)
|
||||
return startswith(line, "**")
|
||||
end
|
||||
|
||||
function is_keyword(line)
|
||||
return startswith(line, "*") && !is_comment(line)
|
||||
end
|
||||
|
||||
function parse_keyword(line; uppercase_keyword=true)
|
||||
args = split(line, ",")
|
||||
args = map(strip, args)
|
||||
keyword_name = strip(args[1], '*')
|
||||
if uppercase_keyword
|
||||
keyword_name = uppercase(keyword_name)
|
||||
end
|
||||
keyword_options = []
|
||||
for option in args[2:end]
|
||||
pair = split(option, "=")
|
||||
if uppercase_keyword
|
||||
pair[1] = uppercase(pair[1])
|
||||
end
|
||||
if length(pair) == 1
|
||||
push!(keyword_options, pair)
|
||||
elseif length(pair) == 2
|
||||
push!(keyword_options, pair[1] => pair[2])
|
||||
else
|
||||
error("Keyword failure: $line, $option, $pair")
|
||||
end
|
||||
end
|
||||
return Keyword(keyword_name, keyword_options)
|
||||
end
|
||||
|
||||
function is_new_section(line)
|
||||
is_keyword(line) || return false
|
||||
section = parse_keyword(line)
|
||||
section.name in ABAQUS_SECTIONS || return false
|
||||
return true
|
||||
end
|
||||
|
||||
function is_new_subsection(line)
|
||||
is_keyword(line) || return false
|
||||
subsection = parse_keyword(line)
|
||||
subsection.name in ABAQUS_SUBSECTIONS || return false
|
||||
return true
|
||||
end
|
||||
|
||||
function maybe_open_section!(model, state)
|
||||
section_name = Val{Symbol(state.section.name)}
|
||||
args = Tuple{Model, AbaqusReaderState, Type{section_name}}
|
||||
if method_exists(open_section!, args)
|
||||
info("Opening section $(state.section.name)")
|
||||
open_section!(model, state, section_name)
|
||||
end
|
||||
end
|
||||
|
||||
function maybe_close_section!(model, state)
|
||||
section_name = Val{Symbol(state.section.name)}
|
||||
args = Tuple{Model, AbaqusReaderState, Type{section_name}}
|
||||
if method_exists(close_section!, args)
|
||||
info("Closing section $(state.section.name)")
|
||||
close_section!(model, state, section_name)
|
||||
end
|
||||
end
|
||||
|
||||
function new_section!(model, state, line::AbstractString)
|
||||
maybe_close_subsection!(model, state)
|
||||
maybe_close_section!(model, state)
|
||||
state.data = []
|
||||
state.section = parse_keyword(line)
|
||||
state.subsection = Keyword()
|
||||
info("New section: $(state.section.name) with options $(state.section.options)")
|
||||
maybe_open_section!(model, state)
|
||||
end
|
||||
|
||||
function maybe_open_subsection!(model, state)
|
||||
section_name = Val{Symbol(state.section.name)}
|
||||
subsection_name = Val{Symbol(state.subsection.name)}
|
||||
args = Tuple{Model, AbaqusReaderState, Type{section_name}, Type{subsection_name}}
|
||||
if method_exists(open_subsection!, args)
|
||||
info("Opening subsection $(state.section.name) / $(state.subsection.name)")
|
||||
open_subsection!(model, state, section_name, subsection_name)
|
||||
end
|
||||
end
|
||||
|
||||
function maybe_close_subsection!(model, state)
|
||||
section_name = Val{Symbol(state.section.name)}
|
||||
subsection_name = Val{Symbol(state.subsection.name)}
|
||||
args = Tuple{Model, AbaqusReaderState, Type{section_name}, Type{subsection_name}}
|
||||
if method_exists(close_subsection!, args)
|
||||
info("Closing subsection $(state.section.name) / $(state.subsection.name)")
|
||||
close_subsection!(model, state, section_name, subsection_name)
|
||||
end
|
||||
end
|
||||
|
||||
function new_subsection!(model, state, line::AbstractString)
|
||||
maybe_close_subsection!(model, state)
|
||||
state.data = []
|
||||
state.subsection = parse_keyword(line)
|
||||
info("New subsection: $(state.subsection.name) with options $(state.subsection.options)")
|
||||
maybe_open_subsection!(model, state)
|
||||
end
|
||||
|
||||
# open_section! and open_subsection! are called right after keyword is found
|
||||
function open_section! end
|
||||
function open_subsection! end
|
||||
|
||||
# close_section! and close_subsection! are called at the end or section or before new keyword
|
||||
function close_section! end
|
||||
function close_subsection! end
|
||||
|
||||
function process_line!(model, state, line)
|
||||
if state.section.name == nothing
|
||||
info("unknown section, line = $line")
|
||||
return
|
||||
end
|
||||
if is_keyword(line)
|
||||
warn("missing keyword..? $line")
|
||||
info("($(state.section.name), $(state.subsection.name)) => $line")
|
||||
return
|
||||
end
|
||||
push!(state.data, line)
|
||||
end
|
||||
|
||||
function abaqus_read_model(fn; read_mesh=true)
|
||||
|
||||
model = Model()
|
||||
|
||||
if read_mesh
|
||||
model.mesh = abaqus_read_mesh(fn)
|
||||
else
|
||||
model.mesh = Mesh()
|
||||
end
|
||||
|
||||
state = AbaqusReaderState()
|
||||
|
||||
fid = open(fn)
|
||||
for line in eachline(fid)
|
||||
line = strip(line)
|
||||
is_comment(line) && continue
|
||||
if is_new_section(line)
|
||||
new_section!(model, state, line)
|
||||
elseif is_new_subsection(line)
|
||||
new_subsection!(model, state, line)
|
||||
else
|
||||
process_line!(model, state, line)
|
||||
end
|
||||
end
|
||||
maybe_close_subsection!(model, state)
|
||||
maybe_close_section!(model, state)
|
||||
close(fid)
|
||||
|
||||
return model
|
||||
end
|
||||
|
||||
### Model parse start
|
||||
|
||||
## Properties
|
||||
|
||||
type SolidSection <: AbstractProperty
|
||||
element_set
|
||||
material
|
||||
end
|
||||
|
||||
function close_section!(model, state, ::Type{Val{Symbol("SOLID SECTION")}})
|
||||
property = SolidSection(state.section["ELSET"], state.section["MATERIAL"])
|
||||
push!(model, property)
|
||||
end
|
||||
|
||||
## Materials
|
||||
|
||||
abstract MaterialProperty
|
||||
|
||||
type Elastic <: MaterialProperty
|
||||
E
|
||||
nu
|
||||
end
|
||||
|
||||
type Material <: AbstractMaterial
|
||||
name
|
||||
properties
|
||||
end
|
||||
|
||||
function Material(name)
|
||||
return Material(name, [])
|
||||
end
|
||||
|
||||
function push!(material::Material, property::MaterialProperty)
|
||||
push!(material.properties, property)
|
||||
end
|
||||
|
||||
function open_section!(model, state, ::Type{Val{:MATERIAL}})
|
||||
state.material = Material(state.section["NAME"])
|
||||
end
|
||||
|
||||
function close_subsection!(model, state, ::Type{Val{:MATERIAL}}, ::Type{Val{:ELASTIC}})
|
||||
E, nu = parse(state)[1]
|
||||
push!(state.material, Elastic(E, nu))
|
||||
end
|
||||
|
||||
function close_section!(model, state, ::Type{Val{:MATERIAL}})
|
||||
material_name = state.material.name
|
||||
if haskey(model.materials, material_name)
|
||||
warn("Material $material_name already exists in model, skipping definition.")
|
||||
else
|
||||
model.materials[material_name] = state.material
|
||||
end
|
||||
end
|
||||
|
||||
## Steps
|
||||
|
||||
type Step <: AbstractStep
|
||||
content :: Vector
|
||||
end
|
||||
|
||||
function push!(step::Step, data)
|
||||
push!(step.content, data)
|
||||
end
|
||||
|
||||
abstract AbstractBoundaryCondition
|
||||
|
||||
type Boundary <: AbstractBoundaryCondition
|
||||
data :: Vector
|
||||
end
|
||||
|
||||
function getindex(b::Boundary, j::Int64)
|
||||
return b.data[j]
|
||||
end
|
||||
|
||||
type DSLoad <: AbstractBoundaryCondition
|
||||
data :: Vector
|
||||
end
|
||||
|
||||
function getindex(l::DSLoad, j::Int64)
|
||||
return l.data[j]
|
||||
end
|
||||
|
||||
function open_section!(model, state, ::Type{Val{:STEP}})
|
||||
state.step = Step([])
|
||||
end
|
||||
|
||||
function close_subsection!(model, state, ::Type{Val{:STEP}}, ::Type{Val{:BOUNDARY}})
|
||||
push!(state.step, Boundary(parse(state)))
|
||||
end
|
||||
|
||||
function close_subsection!(model, state, ::Type{Val{:STEP}}, ::Type{Val{:DSLOAD}})
|
||||
push!(state.step, DSLoad(parse(state)))
|
||||
end
|
||||
|
||||
function close_section!(model, state, ::Type{Val{:STEP}})
|
||||
push!(model.steps, state.step)
|
||||
end
|
||||
|
||||
### model parse end
|
||||
|
||||
# when model is called, run simulation
|
||||
|
||||
function determine_problem_type(model, element_set_name)
|
||||
return Elasticity
|
||||
end
|
||||
|
||||
function determine_problem_dimension(model, element_set_name)
|
||||
return 3
|
||||
end
|
||||
|
||||
function call(model::Model)
|
||||
info("Starting JuliaFEM-ABAQUS solver.")
|
||||
# 1. create field problems and add elements
|
||||
field_problems = []
|
||||
for (element_set_name, element_ids) in model.mesh.element_sets
|
||||
problem_type = determine_problem_type(model, element_set_name)
|
||||
problem_name = "BODY $element_set_name"
|
||||
problem_dimension = determine_problem_dimension(model, element_set_name)
|
||||
problem = Problem(problem_type, problem_name, problem_dimension)
|
||||
problem.elements = create_elements(model.mesh, element_set_name)
|
||||
section = get_element_section(element_set_name)
|
||||
material = get_material(section.material)
|
||||
update!(problem, material)
|
||||
push!(field_problems, problem)
|
||||
end
|
||||
# 2. loop steps
|
||||
for step in model.steps
|
||||
boundary_problems = []
|
||||
for bc in step.content
|
||||
if isa(bc, Boundary)
|
||||
problem = Problem(Dirichlet, "fix nodes", 3, "displacement")
|
||||
for (bc_name, dof) in bc.data
|
||||
nodes = model.mesh.node_sets[bc_name]
|
||||
for node in nodes
|
||||
fix_node!(problem, node => dof)
|
||||
end
|
||||
end
|
||||
push!(boundary_problems, problem)
|
||||
end
|
||||
if isa(bc, DSLoad)
|
||||
problem = Problem(Elasticity, "pressure load", 3, "displacement")
|
||||
for (bc_name, bc_type, pressure) in bc.data
|
||||
elements = create_elements_from_surface_set(bc_name)
|
||||
update!(elements, "surface pressure", pressure)
|
||||
problem.elements = [problem.elements; elements]
|
||||
end
|
||||
push!(boundary_problems, problem)
|
||||
end
|
||||
end
|
||||
all_problems = [problems; boundary_problems]
|
||||
solver = Solver(solver_type, solver_description, all_problems...)
|
||||
solver()
|
||||
end
|
||||
end
|
||||
|
||||
+28
-28
@@ -7,7 +7,7 @@ type Element{E<:AbstractElement}
|
||||
id :: Int
|
||||
connectivity :: Vector{Int}
|
||||
integration_points :: Vector{IP}
|
||||
fields :: Dict{String, Field}
|
||||
fields :: Dict{AbstractString, Field}
|
||||
properties :: E
|
||||
end
|
||||
|
||||
@@ -17,15 +17,15 @@ function Element{E<:AbstractElement}(::Type{E}, connectivity=[], integration_poi
|
||||
return element
|
||||
end
|
||||
|
||||
function getindex(element::Element, field_name::String)
|
||||
function getindex(element::Element, field_name::AbstractString)
|
||||
return element.fields[field_name]
|
||||
end
|
||||
|
||||
function setindex!(element::Element, data::Field, field_name::String)
|
||||
function setindex!(element::Element, data::Field, field_name)
|
||||
element.fields[field_name] = data
|
||||
end
|
||||
|
||||
function setindex!(element::Element, data::Function, field_name::String)
|
||||
function setindex!(element::Element, data::Function, field_name)
|
||||
if method_exists(data, Tuple{Element, Vector, Float64})
|
||||
# create enclosure to pass element as argument
|
||||
function wrapper_(ip, time)
|
||||
@@ -38,34 +38,34 @@ function setindex!(element::Element, data::Function, field_name::String)
|
||||
element.fields[field_name] = field
|
||||
end
|
||||
|
||||
function setindex!(element::Element, data, field_name::String)
|
||||
function setindex!(element::Element, data, field_name)
|
||||
element.fields[field_name] = Field(data)
|
||||
end
|
||||
|
||||
function call(element::Element, field_name::String)
|
||||
function call(element::Element, field_name)
|
||||
return element[field_name]
|
||||
end
|
||||
|
||||
function call(element::Element, field_name::String, time)
|
||||
function call(element::Element, field_name, time)
|
||||
return element[field_name](time)
|
||||
end
|
||||
|
||||
function last(element::Element, field_name::String)
|
||||
function last(element::Element, field_name::AbstractString)
|
||||
return last(element[field_name])
|
||||
end
|
||||
|
||||
function call(element::Element, ip, time=0.0)
|
||||
function call(element::Element, ip, time::Float64=0.0)
|
||||
return get_basis(element, ip, time)
|
||||
end
|
||||
|
||||
function call(element::Element, ip, time, ::Type{Val{:Jacobian}})
|
||||
function call(element::Element, ip, time::Float64, ::Type{Val{:Jacobian}})
|
||||
X = element["geometry"](time)
|
||||
dN = get_dbasis(element, ip, time)
|
||||
J = sum([kron(dN[:,i], X[i]') for i=1:length(X)])
|
||||
return J
|
||||
end
|
||||
|
||||
function call(element::Element, ip, time, ::Type{Val{:detJ}})
|
||||
function call(element::Element, ip, time::Float64, ::Type{Val{:detJ}})
|
||||
J = element(ip, time, Val{:Jacobian})
|
||||
n, m = size(J)
|
||||
if n == m # volume element
|
||||
@@ -79,12 +79,12 @@ function call(element::Element, ip, time, ::Type{Val{:detJ}})
|
||||
end
|
||||
end
|
||||
|
||||
function call(element::Element, ip, time, ::Type{Val{:Grad}})
|
||||
function call(element::Element, ip, time::Float64, ::Type{Val{:Grad}})
|
||||
J = element(ip, time, Val{:Jacobian})
|
||||
return inv(J)*get_dbasis(element, ip, time)
|
||||
end
|
||||
|
||||
function call(element::Element, field_name::String, ip, time, ::Type{Val{:Grad}})
|
||||
function call(element::Element, field_name::AbstractString, ip, time::Float64, ::Type{Val{:Grad}})
|
||||
return element(ip, time, Val{:Grad})*element[field_name](time)
|
||||
end
|
||||
|
||||
@@ -96,12 +96,12 @@ function call(element::Element, field::DCTI, time)
|
||||
return field.data
|
||||
end
|
||||
|
||||
function call(element::Element, field_name::String, time)
|
||||
function call(element::Element, field_name::AbstractString, time)
|
||||
field = element[field_name]
|
||||
return element(field, time)
|
||||
end
|
||||
|
||||
function call(element::Element, field_name::String, ip, time::Float64)
|
||||
function call(element::Element, field_name::AbstractString, ip, time::Float64)
|
||||
field = element[field_name]
|
||||
return element(field, ip, time)
|
||||
end
|
||||
@@ -129,7 +129,7 @@ function call(element::Element, field::Field, ip, time::Float64)
|
||||
return sum([field_[i]*basis[i] for i=1:n])
|
||||
end
|
||||
|
||||
function size(element::Element, dim::Int)
|
||||
function size(element::Element, dim)
|
||||
return size(element)[dim]
|
||||
end
|
||||
|
||||
@@ -144,17 +144,17 @@ julia> update!(element, "geometry", data)
|
||||
As a result element now have time invariant (variable) vector field "geometry" with data ([0.0, 0.0], [1.0, 2.0]).
|
||||
|
||||
"""
|
||||
function update!(element::Element, field_name::String, data::Dict)
|
||||
function update!(element::Element, field_name, data::Dict)
|
||||
element[field_name] = [data[i] for i in get_connectivity(element)]
|
||||
end
|
||||
|
||||
function update!{K,V}(element::Element, field_name::String, data::Pair{Float64, Dict{K, V}})
|
||||
function update!{K,V}(element::Element, field_name, data::Pair{Float64, Dict{K, V}})
|
||||
time, field_data = data
|
||||
element_data = V[field_data[i] for i in get_connectivity(element)]
|
||||
update!(element, field_name, time => element_data)
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, datas::Union{Real, Vector, Pair{Float64, Union{Float64, Real, Vector{Any}}}}...)
|
||||
function update!(element::Element, field_name::AbstractString, datas::Union{Real, Vector, Pair{Float64, Union{Float64, Real, Vector{Any}}}}...)
|
||||
for data in datas
|
||||
if haskey(element, field_name)
|
||||
update!(element[field_name], data)
|
||||
@@ -168,13 +168,13 @@ function update!(element::Element, field_name::String, datas::Union{Real, Vector
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, datas::Pair...)
|
||||
function update!(element::Element, field_name, datas::Pair...)
|
||||
for data in datas
|
||||
update!(element, field_name, data)
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, data::Pair{Float64, Vector{Any}})
|
||||
function update!(element::Element, field_name, data::Pair{Float64, Vector{Any}})
|
||||
if haskey(element, field_name)
|
||||
update!(element[field_name], data)
|
||||
else
|
||||
@@ -182,7 +182,7 @@ function update!(element::Element, field_name::String, data::Pair{Float64, Vecto
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, data::Pair{Float64, Vector{Int64}})
|
||||
function update!(element::Element, field_name, data::Pair{Float64, Vector{Int64}})
|
||||
if haskey(element, field_name)
|
||||
update!(element[field_name], data)
|
||||
else
|
||||
@@ -190,7 +190,7 @@ function update!(element::Element, field_name::String, data::Pair{Float64, Vecto
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, data::Pair{Float64, Vector{Vector{Float64}}})
|
||||
function update!(element::Element, field_name, data::Pair{Float64, Vector{Vector{Float64}}})
|
||||
if haskey(element, field_name)
|
||||
update!(element[field_name], data)
|
||||
else
|
||||
@@ -198,7 +198,7 @@ function update!(element::Element, field_name::String, data::Pair{Float64, Vecto
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, data::Pair{Float64, Float64})
|
||||
function update!(element::Element, field_name, data::Pair{Float64, Float64})
|
||||
if haskey(element, field_name)
|
||||
update!(element[field_name], data)
|
||||
else
|
||||
@@ -206,7 +206,7 @@ function update!(element::Element, field_name::String, data::Pair{Float64, Float
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, data::Union{Float64, Vector})
|
||||
function update!(element::Element, field_name::AbstractString, data::Union{Float64, Vector})
|
||||
if haskey(element, field_name)
|
||||
update!(element[field_name], data)
|
||||
else
|
||||
@@ -228,15 +228,15 @@ function update!(element::Element, datas::Pair...)
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, data::Function)
|
||||
function update!(element::Element, field_name, data::Function)
|
||||
element[field_name] = data
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name::String, field::Field)
|
||||
function update!(element::Element, field_name, field::Field)
|
||||
element[field_name] = field
|
||||
end
|
||||
|
||||
function update!(elements::Vector, field_name::String, data)
|
||||
function update!(elements::Vector, field_name, data)
|
||||
for element in elements
|
||||
update!(element, field_name, data)
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ function get_basis(element::Element{Poi1}, ip, time)
|
||||
return [1]
|
||||
end
|
||||
|
||||
function call(element::Element{Poi1}, ip, time, ::Type{Val{:detJ}})
|
||||
function call(element::Element{Poi1}, ip, time::Float64, ::Type{Val{:detJ}})
|
||||
return 1.0
|
||||
end
|
||||
|
||||
@@ -180,6 +180,47 @@ end
|
||||
|
||||
#
|
||||
|
||||
type Tri7 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Tri7})
|
||||
"7 node triangle"
|
||||
end
|
||||
|
||||
function size(element::Element{Tri7})
|
||||
return (2, 7)
|
||||
end
|
||||
|
||||
function length(element::Element{Tri7})
|
||||
return 7
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Tri7})
|
||||
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
|
||||
[1/3, 1/3]] # N7
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tri7}, xi)
|
||||
[
|
||||
1 xi[1] xi[2] xi[1]^2 xi[1]*xi[2] xi[2]^2 xi[1]^2*xi[2]^2
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Tri7}, xi, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 1 0 2*xi[1] xi[2] 0 2*xi[1]*xi[2]^2
|
||||
0 0 1 0 xi[1] 2*xi[2] 2*xi[1]^2*xi[2]
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Quad4 <: AbstractElement
|
||||
end
|
||||
|
||||
@@ -387,6 +428,47 @@ end
|
||||
|
||||
#
|
||||
|
||||
type Wedge6 <: AbstractElement
|
||||
end
|
||||
|
||||
function description(::Type{Wedge6})
|
||||
"6 node prismatic element (wedge)"
|
||||
end
|
||||
|
||||
function size(element::Element{Wedge6})
|
||||
return (3, 6)
|
||||
end
|
||||
|
||||
function length(element::Element{Wedge6})
|
||||
return 6
|
||||
end
|
||||
|
||||
function get_reference_coordinates(::Type{Wedge6})
|
||||
Vector{Float64}[
|
||||
[0.0, 0.0, -1.0], # N1
|
||||
[1.0, 0.0, -1.0], # N2
|
||||
[0.0, 1.0, -1.0], # N3
|
||||
[0.0, 0.0, 1.0], # N4
|
||||
[1.0, 0.0, 1.0], # N5
|
||||
[0.0, 1.0, 1.0]] # N6
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Wedge6}, x)
|
||||
[
|
||||
1 x[1] x[2] x[3] x[1]*x[3] x[2]*x[3]
|
||||
]
|
||||
end
|
||||
|
||||
function get_interpolation_polynomial(::Type{Wedge6}, x, ::Type{Val{:partial_derivatives}})
|
||||
[
|
||||
0 1 0 0 x[3] 0
|
||||
0 0 1 0 0 x[3]
|
||||
0 0 0 1 x[1] x[2]
|
||||
]
|
||||
end
|
||||
|
||||
#
|
||||
|
||||
type Hex8 <: AbstractElement
|
||||
end
|
||||
|
||||
@@ -571,11 +653,13 @@ end
|
||||
@create_basis Seg3
|
||||
@create_basis Tri3
|
||||
@create_basis Tri6
|
||||
@create_basis Tri7
|
||||
@create_basis Quad4
|
||||
@create_basis Quad8
|
||||
@create_basis Quad9
|
||||
@create_basis Tet4
|
||||
@create_basis Tet10
|
||||
@create_basis Wedge6
|
||||
@create_basis Hex8
|
||||
@create_basis Hex20
|
||||
@create_basis Hex27
|
||||
@@ -585,7 +669,7 @@ function inside(::Union{Type{Seg2}, Type{Seg3}, Type{Quad4}, Type{Quad8},
|
||||
return all(-1.0 .<= xi .<= 1.0)
|
||||
end
|
||||
|
||||
function inside(::Union{Type{Tri3}, Type{Tri6}, Type{Tet4}, Type{Tet10}}, xi)
|
||||
function inside(::Union{Type{Tri3}, Type{Tri6}, Type{Tri7}, Type{Tet4}, Type{Tet10}}, xi)
|
||||
return all(xi .>= 0.0) && (sum(xi) <= 1.0)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# Lagrange (Continous Galerkin) finite elements shape functions generated using macro.
|
||||
|
||||
"""
|
||||
Given polynomial P and coordinates of reference element, calculate
|
||||
Lagrange basis functions
|
||||
"""
|
||||
function calculate_lagrange_basis_coefficients(P, X)
|
||||
dim, nbasis = size(X)
|
||||
A = zeros(nbasis, nbasis)
|
||||
for i=1:nbasis
|
||||
A[i,:] = P(X[:, i])
|
||||
end
|
||||
return inv(A)
|
||||
end
|
||||
|
||||
function refcoords(X::Matrix)
|
||||
return Vector{Float64}[X[:,i] for i=1:size(X,2)]
|
||||
end
|
||||
|
||||
"""
|
||||
Create new Lagrange element
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> @create_lagrange_element(Seg2, "2 node linear segment", X, P)
|
||||
"""
|
||||
macro create_lagrange_element(element_name, element_description, X, P)
|
||||
eltype = esc(element_name)
|
||||
quote
|
||||
global get_basis, length, size, get_reference_coordinates
|
||||
#=
|
||||
get_reference_element_coordinates,
|
||||
get_reference_element_midpoint
|
||||
=#
|
||||
|
||||
type $eltype <: AbstractElement
|
||||
end
|
||||
|
||||
A = calculate_lagrange_basis_coefficients($P, $X)
|
||||
#basis(xi) = C*$P(xi)
|
||||
|
||||
function get_basis(element::Element{$eltype}, ip, time)
|
||||
return transpose($P(ip))*A
|
||||
end
|
||||
|
||||
function size(element::Element{$eltype})
|
||||
return size($X)
|
||||
end
|
||||
|
||||
function length(element::Element{$eltype})
|
||||
return size($X, 2)
|
||||
end
|
||||
|
||||
XX = refcoords($X)
|
||||
function get_reference_coordinates(::Type{$eltype})
|
||||
return XX
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# 3d Lagrange elements
|
||||
|
||||
function get_reference_element_midpoint{E}(element::Element{E})
|
||||
get_reference_element_midpoint(E)
|
||||
end
|
||||
+1
-1
@@ -15,7 +15,7 @@ type Field{A<:Union{Discrete,Continuous}, B<:Union{Constant,Variable}, C<:Union{
|
||||
data
|
||||
end
|
||||
|
||||
typealias FieldSet Dict{String, Field}
|
||||
typealias FieldSet Dict{AbstractString, Field}
|
||||
|
||||
### Basic data structure for discrete field
|
||||
|
||||
|
||||
+19
-8
@@ -58,14 +58,10 @@ end
|
||||
|
||||
### "cartesian" elements, integration rules comes from tensor product
|
||||
|
||||
### 0d elements
|
||||
|
||||
function get_integration_points(element::Poi1)
|
||||
[ (1.0, [] ) ]
|
||||
end
|
||||
|
||||
### 1d elements
|
||||
|
||||
typealias CartesianLineElement Union{Seg2, Seg3, NSeg}
|
||||
typealias CartesianSurfaceElement Union{Quad4, Quad8, Quad9, NSurf}
|
||||
typealias CartesianVolumeElement Union{Hex8, Hex20, Hex27, NSolid}
|
||||
@@ -90,7 +86,7 @@ end
|
||||
# http://math2.uncc.edu/~shaodeng/TEACHING/math5172/Lectures/Lect_15.PDF
|
||||
# http://libmesh.github.io/doxygen/quadrature__gauss__2D_8C_source.html
|
||||
|
||||
typealias TriangularElement Union{Tri3, Tri6}
|
||||
typealias TriangularElement Union{Tri3, Tri6, Tri7}
|
||||
|
||||
function get_integration_points(element::TriangularElement, ::Type{Val{1}})
|
||||
weights = [0.5]
|
||||
@@ -229,16 +225,31 @@ function get_integration_points(element::TetrahedralElement, ::Type{Val{4}})
|
||||
return zip(weights, points)
|
||||
end
|
||||
|
||||
function get_integration_points(element::Union{TriangularElement, TetrahedralElement}, order::Int64)
|
||||
typealias PrismaticElement Union{Wedge6}
|
||||
|
||||
function get_integration_points(element::PrismaticElement, ::Type{Val{2}})
|
||||
weights = 1/6*[1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
|
||||
points = Vector{Float64}[
|
||||
[0.5, 0.0, -1.0/sqrt(3)],
|
||||
[0.0, 0.5, -1.0/sqrt(3)],
|
||||
[0.5, 0.5, -1.0/sqrt(3)],
|
||||
[0.5, 0.0, 1.0/sqrt(3)],
|
||||
[0.0, 0.5, 1.0/sqrt(3)],
|
||||
[0.5, 0.5, 1.0/sqrt(3)]]
|
||||
return zip(weights, points)
|
||||
end
|
||||
|
||||
function get_integration_points(element::Union{TriangularElement,
|
||||
TetrahedralElement, PrismaticElement}, order::Int64)
|
||||
return get_integration_points(element, Val{order})
|
||||
end
|
||||
|
||||
### default number of integration points for each element
|
||||
### 2 for linear elements, 3 for quadratic
|
||||
|
||||
typealias LinearElement Union{Seg2, Tri3, Quad4, Tet4, Hex8}
|
||||
typealias LinearElement Union{Seg2, Tri3, Quad4, Tet4, Wedge6, Hex8}
|
||||
|
||||
typealias QuadraticElement Union{Seg3, Tri6, Tet10, Quad8, Quad9, Hex20, Hex27}
|
||||
typealias QuadraticElement Union{Seg3, Tri6, Tri7, Tet10, Quad8, Quad9, Hex20, Hex27}
|
||||
|
||||
function get_integration_order(element::LinearElement)
|
||||
return 2
|
||||
|
||||
@@ -129,7 +129,7 @@ function copy_field!(src_problem::Problem, dst_problem::Problem, field_name, tim
|
||||
end
|
||||
|
||||
""" Return field calculated to nodal points for elements in problem p. """
|
||||
function call(problem::Problem, field_name::String, time::Float64=0.0)
|
||||
function call(problem::Problem, field_name::AbstractString, time::Float64=0.0)
|
||||
f = Dict()
|
||||
for element in get_elements(problem)
|
||||
for (c, v) in zip(get_connectivity(element), element(field_name, time))
|
||||
@@ -143,7 +143,7 @@ function call(problem::Problem, field_name::String, time::Float64=0.0)
|
||||
end
|
||||
|
||||
""" Interpolate field from a set of elements. """
|
||||
function call(problem::Problem, field_name::String, X::Vector, time::Float64=0.0; fillna=NaN)
|
||||
function call(problem::Problem, field_name::AbstractString, X::Vector, time::Float64=0.0; fillna=NaN)
|
||||
for element in get_elements(problem)
|
||||
if inside(element, X, time)
|
||||
xi = get_local_coordinates(element, X, time)
|
||||
@@ -153,3 +153,14 @@ function call(problem::Problem, field_name::String, X::Vector, time::Float64=0.0
|
||||
return fillna
|
||||
end
|
||||
|
||||
""" Interpolate field from a set of elements. """
|
||||
function call(problem::Problem, field_name::AbstractString, X::Vector, time::Float64, ::Type{Val{:Grad}}; fillna=NaN)
|
||||
for element in get_elements(problem)
|
||||
if inside(element, X, time)
|
||||
xi = get_local_coordinates(element, X, time)
|
||||
return element(field_name, xi, time, Val{:Grad})
|
||||
end
|
||||
end
|
||||
return fillna
|
||||
end
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ function xdmf_new_result!(xdmf::XDMF, elements::Vector, time)
|
||||
set_attribute(dataitem, "DataType", "Float")
|
||||
set_attribute(dataitem, "Format", "XML")
|
||||
#set_attribute(dataitem, "Precision", 8)
|
||||
s = String[]
|
||||
s = []
|
||||
ndim = 0
|
||||
for i in xdmf.permutation
|
||||
ndim += length(X[i])
|
||||
@@ -117,7 +117,7 @@ function xdmf_new_result!(xdmf::XDMF, elements::Vector, time)
|
||||
set_attribute(dataitem, "Format", "XML")
|
||||
set_attribute(dataitem, "DataType", "Int")
|
||||
# set_attribute(dataitem, "Precision", 8)
|
||||
s = String[]
|
||||
s = []
|
||||
eldim = 0
|
||||
for element in elements
|
||||
eltype = get_xdmf_element_code(element)
|
||||
@@ -167,7 +167,7 @@ function xdmf_save_field!(xdmf, elements::Vector, time, field_name; field_type="
|
||||
#set_attribute(dataitem, "Precision", 8)
|
||||
debug && info("field dim = $field_dim")
|
||||
debug && info(f)
|
||||
s = String[]
|
||||
s = []
|
||||
dim = 0
|
||||
for i in xdmf.permutation
|
||||
gi = zeros(field_dim)
|
||||
|
||||
+34
-24
@@ -18,14 +18,17 @@ using JuliaFEM
|
||||
|
||||
type Mesh
|
||||
nodes :: Dict{Int64, Vector{Float64}}
|
||||
node_sets :: Dict{String, Set{Int64}}
|
||||
node_sets :: Dict{Symbol, Set{Int64}}
|
||||
elements :: Dict{Int64, Vector{Int64}}
|
||||
element_types :: Dict{Int64, Symbol}
|
||||
element_sets :: Dict{String, Set{Int64}}
|
||||
element_codes :: Dict{Int64, Symbol}
|
||||
element_sets :: Dict{Symbol, Set{Int64}}
|
||||
surfaces :: Dict{Symbol, Vector{Tuple{Int64, Symbol}}}
|
||||
surface_types :: Dict{Symbol, Symbol}
|
||||
end
|
||||
|
||||
function Mesh()
|
||||
return Mesh(Dict(), Dict(), Dict(), Dict(), Dict())
|
||||
return Mesh(Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), Dict(), Dict())
|
||||
end
|
||||
|
||||
function add_node!(mesh::Mesh, nid::Int, ncoords::Vector{Float64})
|
||||
@@ -38,7 +41,7 @@ function add_nodes!(mesh::Mesh, nodes::Dict{Int64, Vector{Float64}})
|
||||
end
|
||||
end
|
||||
|
||||
function add_node_to_node_set!(mesh::Mesh, set_name::String, nids...)
|
||||
function add_node_to_node_set!(mesh::Mesh, set_name, nids...)
|
||||
if !haskey(mesh.node_sets, set_name)
|
||||
mesh.node_sets[set_name] = Set{Int64}()
|
||||
end
|
||||
@@ -56,7 +59,7 @@ function add_elements!(mesh::Mesh, elements::Dict{Int64, Tuple{Symbol, Vector{In
|
||||
end
|
||||
end
|
||||
|
||||
function add_element_to_element_set!(mesh::Mesh, set_name::String, elids...)
|
||||
function add_element_to_element_set!(mesh::Mesh, set_name, elids...)
|
||||
if !haskey(mesh.element_sets, set_name)
|
||||
mesh.element_sets[set_name] = Set{Int64}()
|
||||
end
|
||||
@@ -84,38 +87,45 @@ function filter_by_element_id(mesh::Mesh, element_ids::Vector{Int64})
|
||||
return mesh2
|
||||
end
|
||||
|
||||
function filter_by_element_set(mesh::Mesh, set_name::String)
|
||||
function filter_by_element_set(mesh::Mesh, set_name)
|
||||
filter_by_element_id(mesh::Mesh, collect(mesh.element_sets[set_name]))
|
||||
end
|
||||
|
||||
function create_elements(mesh::Mesh)
|
||||
elements = [Element(JuliaFEM.(mesh.element_types[elid]), elcon) for (elid, elcon) in mesh.elements]
|
||||
function create_elements(mesh::Mesh; element_type=nothing)
|
||||
element_ids = collect(keys(mesh.elements))
|
||||
if element_type != nothing
|
||||
filter!(id -> mesh.element_types[id] == element_type, element_ids)
|
||||
end
|
||||
elements = [Element(JuliaFEM.(mesh.element_types[id]), mesh.elements[id]) for id in element_ids]
|
||||
update!(elements, "geometry", mesh.nodes)
|
||||
return elements
|
||||
end
|
||||
|
||||
function create_elements(mesh::Mesh, element_sets::String...)
|
||||
elements = Element[]
|
||||
for element_set in element_sets
|
||||
new_elements = create_elements(filter_by_element_set(mesh, element_set))
|
||||
elements = [elements; new_elements]
|
||||
function create_elements(mesh::Mesh, element_sets::Symbol...; element_type=nothing)
|
||||
if isempty(element_sets)
|
||||
element_ids = collect(keys(mesh.elements))
|
||||
else
|
||||
element_ids = Set{Int64}()
|
||||
for set_name in element_sets
|
||||
element_ids = union(element_ids, mesh.element_sets[set_name])
|
||||
end
|
||||
end
|
||||
|
||||
if element_type != nothing
|
||||
filter!(id -> mesh.element_types[id] == element_type, element_ids)
|
||||
end
|
||||
|
||||
elements = [Element(JuliaFEM.(mesh.element_types[id]), mesh.elements[id]) for id in element_ids]
|
||||
update!(elements, "geometry", mesh.nodes)
|
||||
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
|
||||
function create_elements(mesh::Mesh, element_sets::AbstractString...; element_type=nothing)
|
||||
element_sets = map(parse, element_sets)
|
||||
return create_elements(mesh, element_sets...; element_type=element_type)
|
||||
end
|
||||
|
||||
""" find npts nearest nodes form mesh and return id numbers as list. """
|
||||
""" find npts nearest nodes from mesh and return id numbers as list. """
|
||||
function find_nearest_nodes(mesh::Mesh, coords::Vector, npts=1)
|
||||
dist = Dict{Int64, Float64}()
|
||||
for (nid, c) in mesh.nodes
|
||||
|
||||
@@ -79,7 +79,8 @@ end
|
||||
Parse elements from input.
|
||||
"""
|
||||
function parse_section(model, lines, key, idx_start, idx_end, ::Type{Val{:ELEMENT}})
|
||||
definition = uppercase(lines[idx_start])
|
||||
#definition = uppercase(lines[idx_start])
|
||||
definition = lines[idx_start]
|
||||
element_type = regex_match(r"TYPE=([\w\-\_]+)", definition, 1)
|
||||
eltype_sym = Symbol(element_type)
|
||||
eltype_nodes = element_has_nodes(Val{eltype_sym})
|
||||
@@ -121,7 +122,9 @@ Parsing Node- and ElementSets.
|
||||
function parse_section(model, lines, key, idx_start, idx_end, ::Union{Type{Val{:NSET}}, Type{Val{:ELSET}}})
|
||||
set_regex_string = Dict(:NSET => r"NSET=([\w\-\_]+)",
|
||||
:ELSET => r"ELSET=([\w\-\_]+)" )
|
||||
definition = uppercase(lines[idx_start])
|
||||
#definition = uppercase(lines[idx_start])
|
||||
# FIXME: do not uppercase set names
|
||||
definition = lines[idx_start]
|
||||
regex_string = set_regex_string[key]
|
||||
set_name = regex_match(regex_string, definition, 1)
|
||||
info("Creating $(lowercase(string(key))) $set_name")
|
||||
@@ -146,28 +149,27 @@ function parse_section(model, lines, key, idx_start, idx_end, ::Union{Type{Val{:
|
||||
end
|
||||
|
||||
"""
|
||||
TODO ! Parse surface keyword
|
||||
Parse SURFACE keyword
|
||||
"""
|
||||
function parse_section(model, lines, key, idx_start, idx_end,
|
||||
::Type{Val{:SURFACE}})
|
||||
function parse_section(model, lines, key, idx_start, idx_end, ::Type{Val{:SURFACE}})
|
||||
info("Parsing surface")
|
||||
definition = uppercase(lines[idx_start])
|
||||
ids = Vector{Tuple(Int, Int)}()
|
||||
#definition = uppercase(lines[idx_start])
|
||||
definition = lines[idx_start]
|
||||
has_set_def = match(r"TYPE=([\w\_\-]+),.*NAME=([\w\_\-]+)", definition)
|
||||
has_set_def != nothing || return
|
||||
set_type = Symbol(has_set_def[1])
|
||||
set_name = Symbol(has_set_def[2])
|
||||
data = Vector{Tuple{Int64, Symbol}}()
|
||||
for line in lines[idx_start + 1: idx_end]
|
||||
if !(empty_or_comment_line(line))
|
||||
m = matchall(r"[-0-9.]+", line)
|
||||
node_id = parse(Int, m[1])
|
||||
coords = float(m[2:end])
|
||||
nodes[node_id] = coords
|
||||
model["nodes"][node_id] = coords
|
||||
end
|
||||
empty_or_comment_line(line) && continue
|
||||
m = match(r"(?P<element_id>\d+),.+(?P<element_side>S\d+).*", line)
|
||||
element_id = parse(Int, m[:element_id])
|
||||
element_side = Symbol(m[:element_side])
|
||||
push!(data, (element_id, element_side))
|
||||
end
|
||||
has_set_def = match(r"NSET=([\w\_\-]+)", definition)
|
||||
if has_set_def != nothing
|
||||
set_name = has_set_def[1]
|
||||
model["nsets"][set_name] = ids
|
||||
end
|
||||
|
||||
model["surface_types"][set_name] = set_type
|
||||
model["surfaces"][set_name] = data
|
||||
return
|
||||
end
|
||||
|
||||
"""
|
||||
@@ -181,7 +183,7 @@ function find_keywords(lines)
|
||||
end
|
||||
end
|
||||
push!(indexes, length(lines) + 1)
|
||||
indexes
|
||||
return indexes
|
||||
end
|
||||
|
||||
"""
|
||||
@@ -195,21 +197,44 @@ function parse_abaqus(fid::IOStream)
|
||||
parser::Function = x->()
|
||||
model = Dict{AbstractString, Any}()
|
||||
model["nodes"] = Dict{Int64, Vector{Float64}}()
|
||||
model["nsets"] = Dict{String, Vector{Int64}}()
|
||||
model["elsets"] = Dict{String, Vector{Int64}}()
|
||||
model["nsets"] = Dict{AbstractString, Vector{Int64}}()
|
||||
model["elsets"] = Dict{AbstractString, Vector{Int64}}()
|
||||
model["elements"] = Dict{Integer, Any}()
|
||||
model["surfaces"] = Dict{Symbol, Vector{Tuple{Int64, Symbol}}}()
|
||||
model["surface_types"] = Dict{Symbol, Symbol}()
|
||||
for idx_end in keyword_indexes[2:end]
|
||||
keyword_line = uppercase(lines[idx_start])
|
||||
keyword = regex_match(r"\s*(\w+)", keyword_line, 1)
|
||||
keyword = regex_match(r"\s*([\w ]+)", keyword_line, 1)
|
||||
k_sym = Symbol(keyword)
|
||||
if method_exists(parse_section, Tuple{Dict, Array{Integer, 1}, Symbol,
|
||||
Integer, Integer, Type{Val{k_sym}}})
|
||||
args = Tuple{Dict, Vector{Int}, Symbol, Int, Int, Type{Val{k_sym}}}
|
||||
if method_exists(parse_section, args)
|
||||
parse_section(model, lines, k_sym, idx_start, idx_end-1, Val{k_sym})
|
||||
else
|
||||
warn("Unknown section: $(keyword)")
|
||||
# else
|
||||
# warn("Unknown section: $(keyword)")
|
||||
end
|
||||
idx_start = idx_end
|
||||
end
|
||||
return model
|
||||
end
|
||||
|
||||
function abaqus_read_mesh(fn)
|
||||
model = open(parse_abaqus, fn)
|
||||
mesh = Mesh()
|
||||
mesh.nodes = model["nodes"]
|
||||
for (nset_name, node_ids) in model["nsets"]
|
||||
mesh.node_sets[Symbol(nset_name)] = Set(node_ids)
|
||||
end
|
||||
for (elid, eldata) in model["elements"]
|
||||
eltype = eldata["type"]
|
||||
elcon = eldata["connectivity"]
|
||||
mesh.elements[elid] = elcon
|
||||
mesh.element_types[elid] = eltype
|
||||
end
|
||||
for (elset_name, element_ids) in model["elsets"]
|
||||
mesh.element_sets[Symbol(elset_name)] = Set(element_ids)
|
||||
end
|
||||
mesh.surfaces = model["surfaces"]
|
||||
mesh.surface_types = model["surface_types"]
|
||||
return mesh
|
||||
end
|
||||
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
global handlers = Dict()
|
||||
|
||||
"""
|
||||
Register new handler for parser
|
||||
"""
|
||||
function add_handler(section, function_name)
|
||||
handlers[section] = function_name
|
||||
end
|
||||
|
||||
function create_or_get(model, key)
|
||||
if !(key in keys(model))
|
||||
model[key] = Dict()
|
||||
end
|
||||
return model[key]
|
||||
end
|
||||
|
||||
function parse_header(header_line)
|
||||
args = map(s -> strip(s), split(header_line, ","))
|
||||
args[1] = strip(args[1], '*')
|
||||
d = Dict("section" => args[1], "options" => Dict())
|
||||
options = d["options"]
|
||||
for k in args[2:end]
|
||||
args2 = split(k, "=")
|
||||
options[args2[1]] = args2[2]
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
function parse_node_section(model, header, data)
|
||||
nodes = create_or_get(model, "nodes")
|
||||
for line in split(data, "\n")
|
||||
m = matchall(r"[-0-9.]+", line)
|
||||
id = parse(Int, m[1])
|
||||
coords = float(m[2:end])
|
||||
nodes[id] = coords
|
||||
end
|
||||
end
|
||||
|
||||
function parse_element_section(model, header, data)
|
||||
info("Parsing elements")
|
||||
eldims = Dict(
|
||||
"C3D10" => 10,
|
||||
"C3D4" => 4,
|
||||
"S3" => 3,
|
||||
"STRI65" => 6)
|
||||
eltype = header["options"]["TYPE"]
|
||||
if !(eltype in keys(eldims))
|
||||
throw("Element $eltype dimension information missing")
|
||||
end
|
||||
eldim = eldims[eltype]
|
||||
test_match = matchall(r"[0-9]+", "234, 242")
|
||||
m = matchall(r"[0-9]+", data)
|
||||
m = map((s) -> parse(Int, s), m)
|
||||
elements = create_or_get(model, "elements")
|
||||
m = reshape(m, eldim+1, round(Int, length(m)/(eldim+1)))
|
||||
nel = size(m)[2]
|
||||
info("$nel elements found")
|
||||
for i=1:nel
|
||||
elements[m[1,i]] = m[2:end,i]
|
||||
end
|
||||
if "ELSET" in keys(header["options"])
|
||||
elsets = create_or_get(model, "elsets")
|
||||
elset_name = header["options"]["ELSET"]
|
||||
info("Creating ELSET $elset_name")
|
||||
elsets[elset_name] = Int64[]
|
||||
for i=1:nel
|
||||
push!(elsets[elset_name], m[1,i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function parse_elset_section(model, header, data)
|
||||
elset_name = header["options"]["ELSET"]
|
||||
info("Creating element set $elset_name")
|
||||
m = matchall(r"[0-9]+", data)
|
||||
element_ids = map((s) -> parse(Int, s), m)
|
||||
elsets = create_or_get(model, "elsets")
|
||||
elsets[elset_name] = Int64[]
|
||||
for j in element_ids
|
||||
push!(elsets[elset_name], j)
|
||||
end
|
||||
end
|
||||
|
||||
function parse_nodeset_section(model, header, data)
|
||||
nset_name = header["options"]["NSET"]
|
||||
info("Creating node set $nset_name")
|
||||
m = matchall(r"[0-9]+", data)
|
||||
node_ids = map((s) -> parse(Int, s), m)
|
||||
nsets = create_or_get(model, "nsets")
|
||||
nsets[nset_name] = Int64[]
|
||||
for j in node_ids
|
||||
push!(nsets[nset_name], j)
|
||||
end
|
||||
end
|
||||
|
||||
function parse_abaqus(fid::IOStream)
|
||||
model = Dict()
|
||||
section = nothing
|
||||
header = nothing
|
||||
data = String[]
|
||||
info("Registered handlers: $(keys(handlers))")
|
||||
|
||||
function process_section(section)
|
||||
if section == nothing
|
||||
return
|
||||
end
|
||||
if !(section in keys(handlers))
|
||||
info("Don't know what to do with data in section $section")
|
||||
info("Skipping $(length(data)) bytes of unknown data")
|
||||
return
|
||||
end
|
||||
joined = join(data, "")
|
||||
handlers[section](model, header, strip(joined))
|
||||
empty!(data)
|
||||
end
|
||||
|
||||
line_idx = 0
|
||||
for line in eachline(fid)
|
||||
if startswith(line, "**")
|
||||
continue
|
||||
end
|
||||
if startswith(line, "*")
|
||||
process_section(section)
|
||||
header = parse_header(line)
|
||||
section = header["section"]
|
||||
continue
|
||||
end
|
||||
push!(data, line)
|
||||
end
|
||||
process_section(section)
|
||||
return model
|
||||
end
|
||||
|
||||
# add handlers
|
||||
add_handler("NODE", parse_node_section)
|
||||
add_handler("ELEMENT", parse_element_section)
|
||||
add_handler("NSET", parse_nodeset_section)
|
||||
add_handler("ELSET", parse_elset_section)
|
||||
+22
-209
@@ -4,42 +4,7 @@
|
||||
using HDF5
|
||||
using JuliaFEM
|
||||
|
||||
function aster_create_elements(mesh, element_set, element_type=nothing; reverse_connectivity=false)
|
||||
elements = Element[]
|
||||
mapping = Dict(
|
||||
:SE2 => Seg2,
|
||||
:TR3 => Tri3,
|
||||
:TR6 => Tri6,
|
||||
:QU4 => Quad4,
|
||||
:HE8 => Hex8,
|
||||
:TE4 => Tet4,
|
||||
:T10 => Tet10)
|
||||
for (elid, (eltype, elset, elcon)) in mesh["connectivity"]
|
||||
elset == element_set || continue
|
||||
if !isa(element_type, Void)
|
||||
if isa(element_type, Tuple)
|
||||
if !(eltype in element_type)
|
||||
continue
|
||||
end
|
||||
elseif eltype != element_type
|
||||
continue
|
||||
end
|
||||
end
|
||||
if reverse_connectivity
|
||||
elcon = reverse(elcon)
|
||||
end
|
||||
if !haskey(mapping, eltype)
|
||||
error("aster_create_elements: unknown element mapping $eltype")
|
||||
end
|
||||
element = Element(mapping[eltype], elcon)
|
||||
push!(elements, element)
|
||||
end
|
||||
update!(elements, "geometry", mesh["nodes"])
|
||||
return elements
|
||||
end
|
||||
|
||||
|
||||
function aster_parse_nodes(section::String; strip_characters=true)
|
||||
function aster_parse_nodes(section; strip_characters=true)
|
||||
nodes = Dict{Any, Vector{Float64}}()
|
||||
has_started = false
|
||||
for line in split(section, '\n')
|
||||
@@ -68,10 +33,10 @@ function aster_parse_nodes(section::String; strip_characters=true)
|
||||
return nodes
|
||||
end
|
||||
|
||||
function parse(mesh::String, ::Type{Val{:CODE_ASTER_MAIL}})
|
||||
model = Dict{String, Any}()
|
||||
function parse(mesh, ::Type{Val{:CODE_ASTER_MAIL}})
|
||||
model = Dict()
|
||||
header = nothing
|
||||
data = String[]
|
||||
data = []
|
||||
for line in split(mesh, '\n')
|
||||
length(line) != 0 || continue
|
||||
info("line: $line")
|
||||
@@ -90,151 +55,6 @@ function parse(mesh::String, ::Type{Val{:CODE_ASTER_MAIL}})
|
||||
end
|
||||
|
||||
|
||||
function aster_renumber_nodes_!(mesh, node_numbering)
|
||||
old_nodes = mesh["nodes"]
|
||||
new_nodes = typeof(old_nodes)()
|
||||
for (node_id, node_coords) in old_nodes
|
||||
new_node_id = node_numbering[node_id]
|
||||
new_nodes[new_node_id] = node_coords
|
||||
end
|
||||
mesh["nodes"] = new_nodes
|
||||
for (elid, (eltype, elset, elcon)) in mesh["connectivity"]
|
||||
new_elcon = [node_numbering[node_id] for node_id in elcon]
|
||||
mesh["connectivity"][elid] = (eltype, elset, new_elcon)
|
||||
end
|
||||
end
|
||||
|
||||
function aster_renumber_nodes(mesh)
|
||||
nodemap = Dict{Int64,Int64}()
|
||||
for (i, nid) in enumerate(keys(mesh["nodes"]))
|
||||
nodemap[nid] = i
|
||||
end
|
||||
new_nodes = Dict{Int64, Vector{Float64}}()
|
||||
for (nid, ncoords) in mesh["nodes"]
|
||||
new_nodes[nodemap[nid]] = ncoords
|
||||
end
|
||||
function change_node_ids(old_ids::Vector{Int64})
|
||||
return Int[nodemap[nid] for nid in old_ids]
|
||||
end
|
||||
new_elements = Dict{Int64, Tuple{Symbol, Symbol, Vector{Int64}}}()
|
||||
for (elid, (eltype, elset, elcon)) in mesh["connectivity"]
|
||||
new_elements[elid] = (eltype, elset, change_node_ids(elcon))
|
||||
end
|
||||
mesh["nodes"] = new_nodes
|
||||
mesh["elements"] = new_elements
|
||||
return mesh
|
||||
end
|
||||
|
||||
function aster_renumber_nodes!(mesh1, mesh2)
|
||||
|
||||
reserved_node_ids = Set(collect(keys(mesh1["nodes"])))
|
||||
mesh2_node_numbering = Dict{Int64, Int64}()
|
||||
|
||||
# find new node ids assigned for mesh 2
|
||||
k = 1
|
||||
for node_id in sort(collect(keys(mesh2["nodes"])))
|
||||
# if node id is reserved in mesh 1, find new number
|
||||
if node_id in reserved_node_ids
|
||||
while k in reserved_node_ids
|
||||
k += 1
|
||||
end
|
||||
mesh2_node_numbering[node_id] = k
|
||||
push!(reserved_node_ids, k)
|
||||
else
|
||||
mesh2_node_numbering[node_id] = node_id
|
||||
end
|
||||
end
|
||||
aster_renumber_nodes_!(mesh2, mesh2_node_numbering)
|
||||
|
||||
#=
|
||||
# create new nodes
|
||||
mesh2_old_nodes = mesh2["nodes"]
|
||||
mesh2_new_nodes = typeof(mesh2_old_nodes)()
|
||||
for (node_id, node_coords) in mesh2_old_nodes
|
||||
new_node_id = mesh2_node_numbering[node_id]
|
||||
mesh2_new_nodes[new_node_id] = node_coords
|
||||
end
|
||||
mesh2["nodes"] = mesh2_new_nodes
|
||||
|
||||
# update connectivity
|
||||
for (elid, (eltype, elset, elcon)) in mesh2["connectivity"]
|
||||
new_elcon = [mesh2_node_numbering[node_id] for node_id in elcon]
|
||||
mesh2["connectivity"][elid] = (eltype, elset, new_elcon)
|
||||
end
|
||||
=#
|
||||
|
||||
end
|
||||
|
||||
|
||||
function aster_renumber_elements!(mesh1, mesh2)
|
||||
|
||||
reserved_element_ids = Set(collect(keys(mesh1["connectivity"])))
|
||||
mesh2_element_numbering = Dict{Int64, Int64}()
|
||||
|
||||
# find new element ids assigned for mesh 2
|
||||
k = 1
|
||||
for element_id in sort(collect(keys(mesh2["connectivity"])))
|
||||
# if node id is reserved in mesh 1, find new number
|
||||
if element_id in reserved_element_ids
|
||||
while k in reserved_element_ids
|
||||
k += 1
|
||||
end
|
||||
mesh2_element_numbering[element_id] = k
|
||||
push!(reserved_element_ids, k)
|
||||
else
|
||||
mesh2_element_numbering[element_id] = element_id
|
||||
end
|
||||
end
|
||||
|
||||
# create new elements
|
||||
mesh2_old_elements = mesh2["connectivity"]
|
||||
mesh2_new_elements = typeof(mesh2_old_elements)()
|
||||
for (element_id, element_data) in mesh2_old_elements
|
||||
new_element_id = mesh2_element_numbering[element_id]
|
||||
mesh2_new_elements[new_element_id] = element_data
|
||||
end
|
||||
mesh2["connectivity"] = mesh2_new_elements
|
||||
|
||||
end
|
||||
|
||||
|
||||
function aster_combine_meshes(mesh1, mesh2)
|
||||
|
||||
# check that meshes are ready to be combined
|
||||
node_ids_mesh_1 = collect(keys(mesh1["nodes"]))
|
||||
node_ids_mesh_2 = collect(keys(mesh2["nodes"]))
|
||||
if length(intersect(node_ids_mesh_1, node_ids_mesh_2)) != 0
|
||||
error("nodes with same id number in both meshes, failed.")
|
||||
end
|
||||
element_ids_mesh_1 = collect(keys(mesh1["connectivity"]))
|
||||
element_ids_mesh_2 = collect(keys(mesh2["connectivity"]))
|
||||
if length(intersect(element_ids_mesh_1, element_ids_mesh_2)) != 0
|
||||
error("elements with same id number in both meshes, failed.")
|
||||
end
|
||||
@assert similar(mesh1) == similar(mesh2)
|
||||
@assert similar(mesh1["nodes"]) == similar(mesh2["nodes"])
|
||||
@assert similar(mesh1["connectivity"]) == similar(mesh2["connectivity"])
|
||||
|
||||
new_mesh = similar(mesh1)
|
||||
new_mesh["nodes"] = similar(mesh1["nodes"])
|
||||
new_mesh["connectivity"] = similar(mesh1["connectivity"])
|
||||
|
||||
for (node_id, node_coords) in mesh1["nodes"]
|
||||
new_mesh["nodes"][node_id] = node_coords
|
||||
end
|
||||
for (node_id, node_coords) in mesh2["nodes"]
|
||||
new_mesh["nodes"][node_id] = node_coords
|
||||
end
|
||||
for (element_id, element_data) in mesh1["connectivity"]
|
||||
new_mesh["connectivity"][element_id] = element_data
|
||||
end
|
||||
for (element_id, element_data) in mesh2["connectivity"]
|
||||
new_mesh["connectivity"][element_id] = element_data
|
||||
end
|
||||
return new_mesh
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
Code Aster binary file (.med), which is exported from SALOME.
|
||||
"""
|
||||
@@ -242,7 +62,7 @@ type MEDFile
|
||||
data :: Dict
|
||||
end
|
||||
|
||||
function MEDFile(fn::String)
|
||||
function MEDFile(fn)
|
||||
MEDFile(h5read(fn, "/"))
|
||||
end
|
||||
|
||||
@@ -316,14 +136,6 @@ 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
|
||||
@@ -334,9 +146,9 @@ end
|
||||
|
||||
Paramters
|
||||
---------
|
||||
fn :: String
|
||||
fn
|
||||
file name to parse
|
||||
mesh_name :: String, optional
|
||||
mesh_name :: optional
|
||||
mesh name, if several meshes in one file
|
||||
|
||||
Returns
|
||||
@@ -344,7 +156,7 @@ Returns
|
||||
Dict containing fields "nodes" and "connectivity".
|
||||
|
||||
"""
|
||||
function parse_aster_med_file(fn::String, mesh_name=nothing; debug=false)
|
||||
function parse_aster_med_file(fn, mesh_name=nothing; debug=false)
|
||||
med = MEDFile(fn)
|
||||
mesh_names = get_mesh_names(med::MEDFile)
|
||||
all_meshes = join(mesh_names, ", ")
|
||||
@@ -364,7 +176,7 @@ function parse_aster_med_file(fn::String, mesh_name=nothing; debug=false)
|
||||
end
|
||||
nodes = get_nodes(med, nsets, mesh_name)
|
||||
conn = get_connectivity(med, elsets, mesh_name)
|
||||
result = Dict{String, Any}()
|
||||
result = Dict("nodes" => nodes, "connectivity" => conn)
|
||||
result["nodes"] = nodes
|
||||
result["connectivity"] = conn
|
||||
return result
|
||||
@@ -380,11 +192,12 @@ end
|
||||
# :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])
|
||||
:Tet4 => [4,3,1,2],
|
||||
:Tet10 => [4,3,1,2,10,7,8,9,6,5],
|
||||
:Wedge6 => [4,5,6,1,2,3],
|
||||
: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(
|
||||
@@ -397,7 +210,7 @@ global const mapping = Dict(
|
||||
|
||||
:TR3 => :Tri3,
|
||||
:TR6 => :Tri6,
|
||||
:TR7 => :Tru6,
|
||||
:TR7 => :Tri7,
|
||||
|
||||
:QU4 => :Quad4,
|
||||
:QU8 => :Quad8,
|
||||
@@ -406,9 +219,9 @@ global const mapping = Dict(
|
||||
:TE4 => :Tet4,
|
||||
:T10 => :Tet10,
|
||||
|
||||
:PE6 => :Penta6,
|
||||
:P15 => :Penta15,
|
||||
:P18 => :Penta18,
|
||||
:PE6 => :Wedge6,
|
||||
:P15 => :Wedge15,
|
||||
:P18 => :Wedge18,
|
||||
|
||||
:HE8 => :Hex8,
|
||||
:H20 => :Hex20,
|
||||
@@ -419,17 +232,17 @@ global const mapping = Dict(
|
||||
|
||||
)
|
||||
|
||||
function aster_read_mesh(fn::String, mesh_name=nothing; reorder_element_connectivity=true)
|
||||
function aster_read_mesh(fn, mesh_name=nothing; reorder_element_connectivity=true)
|
||||
result = parse_aster_med_file(fn, mesh_name)
|
||||
mesh = Mesh()
|
||||
for (nid, (nset, ncoords)) in result["nodes"]
|
||||
add_node!(mesh, nid, ncoords)
|
||||
add_node_to_node_set!(mesh, string(nset), nid)
|
||||
add_node_to_node_set!(mesh, nset, nid)
|
||||
end
|
||||
for (elid, (eltype, elset, elcon)) in result["connectivity"]
|
||||
haskey(mapping, eltype) || error("Code Aster .med reader: element type $eltype not found from mapping")
|
||||
add_element!(mesh, elid, mapping[eltype], elcon)
|
||||
add_element_to_element_set!(mesh, string(elset), elid)
|
||||
add_element_to_element_set!(mesh, elset, elid)
|
||||
end
|
||||
if reorder_element_connectivity
|
||||
reorder_element_connectivity!(mesh, med_connectivity)
|
||||
|
||||
+4
-4
@@ -84,9 +84,9 @@ function get_dofs(assembly::Assembly)
|
||||
end
|
||||
|
||||
type Problem{P<:AbstractProblem}
|
||||
name :: String # descriptive name for problem
|
||||
name :: AbstractString # descriptive name for problem
|
||||
dimension :: Int # degrees of freedom per node
|
||||
parent_field_name :: String # (optional) name of parent field e.g. "displacement"
|
||||
parent_field_name :: AbstractString # (optional) name of parent field e.g. "displacement"
|
||||
elements :: Vector{Element}
|
||||
dofmap :: Dict{Element, Vector{Int64}} # connects element local dofs to global dofs
|
||||
assembly :: Assembly
|
||||
@@ -103,7 +103,7 @@ julia> prob1 = Problem(Elasticity, "this is my problem", 3)
|
||||
julia> prob2 = Problem(Elasticity, 3)
|
||||
|
||||
"""
|
||||
function Problem{P<:FieldProblem}(::Type{P}, name::String, dimension::Int64)
|
||||
function Problem{P<:FieldProblem}(::Type{P}, name::AbstractString, dimension::Int64)
|
||||
Problem{P}(name, dimension, "none", [], Dict(), Assembly(), P())
|
||||
end
|
||||
function Problem{P<:FieldProblem}(::Type{P}, dimension::Int64)
|
||||
@@ -280,7 +280,7 @@ function length(problem::Problem)
|
||||
return length(problem.elements)
|
||||
end
|
||||
|
||||
function update!(problem::Problem, field_name::String, field)
|
||||
function update!(problem::Problem, field_name, field)
|
||||
update!(problem.elements, field_name, field)
|
||||
end
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ type Contact <: BoundaryProblem
|
||||
use_forwarddiff :: Bool
|
||||
minimum_active_set_size :: Int
|
||||
distval :: Float64
|
||||
store_fields :: Vector{String}
|
||||
store_fields :: Vector{AbstractString}
|
||||
end
|
||||
|
||||
function Contact()
|
||||
|
||||
+14
-14
@@ -38,7 +38,7 @@ type Elasticity <: FieldProblem
|
||||
formulation :: Symbol
|
||||
finite_strain :: Bool
|
||||
geometric_stiffness :: Bool
|
||||
store_fields :: Vector{String}
|
||||
store_fields :: Vector{Symbol}
|
||||
end
|
||||
function Elasticity()
|
||||
# formulations: plane_stress, plane_strain, continuum
|
||||
@@ -139,11 +139,11 @@ function assemble{El<:Elasticity2DVolumeElements}(problem::Problem{Elasticity},
|
||||
# calculate stress
|
||||
stress_vec = D * ([1.0, 1.0, 2.0] .* strain_vec)
|
||||
|
||||
"strain" in props.store_fields && update!(ip, "strain", time => strain_vec)
|
||||
"stress" in props.store_fields && update!(ip, "stress", time => stress_vec)
|
||||
"stress 11" in props.store_fields && update!(ip, "stress 11", time => stress_vec[1])
|
||||
"stress 22" in props.store_fields && update!(ip, "stress 22", time => stress_vec[2])
|
||||
"stress 12" in props.store_fields && update!(ip, "stress 12", time => stress_vec[3])
|
||||
:strain in props.store_fields && update!(ip, "strain", time => strain_vec)
|
||||
:stress in props.store_fields && update!(ip, "stress", time => stress_vec)
|
||||
:stress11 in props.store_fields && update!(ip, "stress11", time => stress_vec[1])
|
||||
:stress22 in props.store_fields && update!(ip, "stress22", time => stress_vec[2])
|
||||
:stress12 in props.store_fields && update!(ip, "stress12", time => stress_vec[3])
|
||||
|
||||
Km += w*BL'*D*BL
|
||||
|
||||
@@ -452,14 +452,14 @@ function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity},
|
||||
0.0 0.0 0.0 0.0 0.0 0.5-nu]
|
||||
stress_vec = D * ([1.0, 1.0, 1.0, 2.0, 2.0, 2.0].*strain_vec)
|
||||
|
||||
"strain" in props.store_fields && update!(ip, "strain", time => strain_vec)
|
||||
"stress" in props.store_fields && update!(ip, "stress", time => stress_vec)
|
||||
"stress 11" in props.store_fields && update!(ip, "stress 11", time => stress_vec[1])
|
||||
"stress 22" in props.store_fields && update!(ip, "stress 22", time => stress_vec[2])
|
||||
"stress 33" in props.store_fields && update!(ip, "stress 33", time => stress_vec[3])
|
||||
"stress 12" in props.store_fields && update!(ip, "stress 12", time => stress_vec[4])
|
||||
"stress 23" in props.store_fields && update!(ip, "stress 23", time => stress_vec[5])
|
||||
"stress 13" in props.store_fields && update!(ip, "stress 13", time => stress_vec[6])
|
||||
:strain in props.store_fields && update!(ip, "strain", time => strain_vec)
|
||||
:stress in props.store_fields && update!(ip, "stress", time => stress_vec)
|
||||
:stress11 in props.store_fields && update!(ip, "stress11", time => stress_vec[1])
|
||||
:stress22 in props.store_fields && update!(ip, "stress22", time => stress_vec[2])
|
||||
:stress33 in props.store_fields && update!(ip, "stress33", time => stress_vec[3])
|
||||
:stress12 in props.store_fields && update!(ip, "stress12", time => stress_vec[4])
|
||||
:stress23 in props.store_fields && update!(ip, "stress23", time => stress_vec[5])
|
||||
:stress13 in props.store_fields && update!(ip, "stress13", time => stress_vec[6])
|
||||
|
||||
Km += w*BL'*D*BL
|
||||
|
||||
|
||||
+47
-3
@@ -44,8 +44,8 @@ https://en.wikipedia.org/wiki/Thermal_diffusivity
|
||||
https://en.wikipedia.org/wiki/Volumetric_heat_capacity
|
||||
"""
|
||||
type Heat <: FieldProblem
|
||||
formulation :: String
|
||||
store_fields :: Vector{String}
|
||||
formulation :: AbstractString
|
||||
store_fields :: Vector{Symbol}
|
||||
end
|
||||
|
||||
function Heat()
|
||||
@@ -85,10 +85,19 @@ function assemble!{E<:Heat3DVolumeElements}(assembly::Assembly, problem::Problem
|
||||
k = element("$field_name thermal conductivity", ip, time)
|
||||
K += w*k*dN'*dN
|
||||
end
|
||||
if haskey(element, "thermal conductivity")
|
||||
dN = element(ip, time, Val{:Grad})
|
||||
k = element("thermal conductivity", ip, time)
|
||||
K += w*k*dN'*dN
|
||||
end
|
||||
if haskey(element, "$field_name load")
|
||||
f = element("$field_name load", ip, time)
|
||||
fq += w*N'*f
|
||||
end
|
||||
if haskey(element, "heat source")
|
||||
f = element("heat source", ip, time)
|
||||
fq += w*N'*f
|
||||
end
|
||||
end
|
||||
T = vec(element[field_name](time))
|
||||
fq -= K*T
|
||||
@@ -141,12 +150,22 @@ function assemble!{E<:Heat3DSurfaceElements}(assembly::Assembly, problem::Proble
|
||||
q = element("$field_name flux", ip, time)
|
||||
fq += w*N'*q
|
||||
end
|
||||
if haskey(element, "$field_name heat transfer coefficient")
|
||||
if haskey(element, "heat flux")
|
||||
q = element("heat flux", ip, time)
|
||||
fq += w*N'*q
|
||||
end
|
||||
if haskey(element, "$field_name heat transfer coefficient") && haskey(element, "$field_name external temperature")
|
||||
h = element("$field_name heat transfer coefficient", ip, time)
|
||||
Tu = element("$field_name external temperature", ip, time)
|
||||
K += w*h*N'*N
|
||||
fq += w*N'*h*Tu
|
||||
end
|
||||
if haskey(element, "heat transfer coefficient") && haskey(element, "external temperature")
|
||||
h = element("heat transfer coefficient", ip, time)
|
||||
Tu = element("external temperature", ip, time)
|
||||
K += w*h*N'*N
|
||||
fq += w*N'*h*Tu
|
||||
end
|
||||
end
|
||||
T = vec(element[field_name](time))
|
||||
fq -= K*T
|
||||
@@ -178,10 +197,19 @@ function assemble!{E<:Heat2DVolumeElements}(assembly::Assembly, problem::Problem
|
||||
k = element("$field_name thermal conductivity", ip, time)
|
||||
K += w*k*dN'*dN
|
||||
end
|
||||
if haskey(element, "thermal conductivity")
|
||||
dN = element(ip, time, Val{:Grad})
|
||||
k = element("thermal conductivity", ip, time)
|
||||
K += w*k*dN'*dN
|
||||
end
|
||||
if haskey(element, "$field_name load")
|
||||
f = element("$field_name load", ip, time)
|
||||
fq += w*N'*f
|
||||
end
|
||||
if haskey(element, "heat source")
|
||||
f = element("heat source", ip, time)
|
||||
fq += w*N'*f
|
||||
end
|
||||
end
|
||||
T = vec(element[field_name](time))
|
||||
fq -= K*T
|
||||
@@ -203,6 +231,22 @@ function assemble!{E<:Heat2DSurfaceElements}(assembly::Assembly, problem::Proble
|
||||
g = element("$field_name flux", ip, time)
|
||||
fq += w*N'*g
|
||||
end
|
||||
if haskey(element, "heat flux")
|
||||
g = element("heat flux", ip, time)
|
||||
fq += w*N'*g
|
||||
end
|
||||
if haskey(element, "$field_name heat transfer coefficient") && haskey(element, "$field_name external temperature")
|
||||
h = element("$field_name heat transfer coefficient", ip, time)
|
||||
Tu = element("$field_name external temperature", ip, time)
|
||||
K += w*h*N'*N
|
||||
fq += w*N'*h*Tu
|
||||
end
|
||||
if haskey(element, "heat transfer coefficient") && haskey(element, "external temperature")
|
||||
h = element("heat transfer coefficient", ip, time)
|
||||
Tu = element("external temperature", ip, time)
|
||||
K += w*h*N'*N
|
||||
fq += w*N'*h*Tu
|
||||
end
|
||||
end
|
||||
T = vec(element[field_name](time))
|
||||
fq -= K*T
|
||||
|
||||
@@ -8,7 +8,7 @@ type Mortar <: BoundaryProblem
|
||||
dual_basis :: Bool
|
||||
use_forwarddiff :: Bool
|
||||
distval :: Float64
|
||||
store_fields :: Vector{String}
|
||||
store_fields :: Vector{Symbol}
|
||||
end
|
||||
|
||||
function Mortar()
|
||||
|
||||
+6
-6
@@ -4,8 +4,8 @@
|
||||
abstract AbstractSolver
|
||||
|
||||
type Solver{S<:AbstractSolver}
|
||||
name :: String # some descriptive name for problem
|
||||
time :: Real # current time
|
||||
name :: AbstractString # some descriptive name for problem
|
||||
time :: Float64 # current time
|
||||
problems :: Vector{Problem}
|
||||
norms :: Vector{Tuple} # solution norms for convergence studies
|
||||
ndofs :: Int # number of degrees of freedom in problem
|
||||
@@ -27,7 +27,7 @@ function push!(solver::Solver, problem)
|
||||
push!(solver.problems, problem)
|
||||
end
|
||||
|
||||
function getindex(solver::Solver, problem_name::String)
|
||||
function getindex(solver::Solver, problem_name)
|
||||
for problem in get_problems(solver)
|
||||
if problem.name == problem_name
|
||||
return problem
|
||||
@@ -485,7 +485,7 @@ function NonlinearSolver(problems...)
|
||||
end
|
||||
return solver
|
||||
end
|
||||
function NonlinearSolver(name::String, problems::Problem...)
|
||||
function NonlinearSolver(name::AbstractString, problems::Problem...)
|
||||
solver = NonlinearSolver(problems...)
|
||||
solver.name = name
|
||||
return solver
|
||||
@@ -550,7 +550,7 @@ function LinearSolver(problems::Problem...)
|
||||
end
|
||||
return solver
|
||||
end
|
||||
function LinearSolver(name::String, problems::Problem...)
|
||||
function LinearSolver(name::AbstractString, problems::Problem...)
|
||||
solver = LinearSolver(problems...)
|
||||
solver.name = name
|
||||
return solver
|
||||
@@ -615,7 +615,7 @@ function Postprocessor(problems::Problem...)
|
||||
return solver
|
||||
end
|
||||
|
||||
function Postprocessor(name::String, problems::Problem...)
|
||||
function Postprocessor(name::AbstractString, problems::Problem...)
|
||||
solver = Postprocessor(problems...)
|
||||
solver.name = name
|
||||
return solver
|
||||
|
||||
+5
-5
@@ -9,15 +9,15 @@ type Point{P<:AbstractPoint}
|
||||
id :: Int
|
||||
weight :: Float64
|
||||
coords :: Vector{Float64}
|
||||
fields :: Dict{String, Field}
|
||||
fields :: Dict{AbstractString, Field}
|
||||
properties :: P
|
||||
end
|
||||
|
||||
function setindex!{T}(point::Point, val::Pair{Float64, T}, field_name::String)
|
||||
function setindex!{T}(point::Point, val::Pair{Float64, T}, field_name)
|
||||
point.fields[field_name] = Field(val)
|
||||
end
|
||||
|
||||
function getindex(point::Point, field_name::String)
|
||||
function getindex(point::Point, field_name)
|
||||
return point.fields[field_name]
|
||||
end
|
||||
|
||||
@@ -25,11 +25,11 @@ function getindex(point::Point, idx::Int)
|
||||
return point.coords[idx]
|
||||
end
|
||||
|
||||
function haskey(point::Point, field_name::String)
|
||||
function haskey(point::Point, field_name)
|
||||
return haskey(point.fields, field_name)
|
||||
end
|
||||
|
||||
function call(point::Point, field_name::String, time::Float64=0.0)
|
||||
function call(point::Point, field_name, time=0.0)
|
||||
point.fields[field_name](time).data
|
||||
end
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function run_tests(; verbose=true)
|
||||
|
||||
|
||||
+6
-1
@@ -3,9 +3,12 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Testing
|
||||
|
||||
#=
|
||||
using JuliaFEM.API
|
||||
using JuliaFEM.Interfaces
|
||||
using JuliaFEM.Test
|
||||
=#
|
||||
|
||||
#= TODO: Fix test
|
||||
@testset "test basic workflow" begin
|
||||
@@ -82,6 +85,7 @@ end
|
||||
end
|
||||
=#
|
||||
|
||||
#= TODO: Fix test
|
||||
function test_piston_107168()
|
||||
abaqus_input = open(parse_abaqus, "./geometry/piston/piston_107168_P2.inp")
|
||||
|
||||
@@ -91,6 +95,7 @@ function test_piston_107168()
|
||||
@test length(keys(model.elements)) == 65948
|
||||
@test length(keys(model.nodes)) == 107168
|
||||
end
|
||||
=#
|
||||
|
||||
function slow_test_something_that_takes_long_time()
|
||||
info("This test is SLOW.")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test static condensation" begin
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
importall Base
|
||||
import JuliaFEM: get_basis, get_dbasis
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "geometry missing" begin
|
||||
el = Element(Quad4, [1, 2, 3, 4])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "2d curved block with frictionless finite sliding contact using forwarddiff" begin
|
||||
# FIXME: needs verification of some other fem software
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
import JuliaFEM: get_mesh, get_model
|
||||
|
||||
function get_mesh(::Type{Val{Symbol("curved 2d mesh model")}})
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "3d upper side curved contact" begin
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
importall Base
|
||||
import JuliaFEM: get_basis, get_dbasis, get_integration_points
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
# TODO: Fix tests
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
# TODO: Fix tests.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
#=
|
||||
In [36]: C = Matrix([[0], [30], [15]]) # node coordinates
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
using JLD
|
||||
|
||||
function JuliaFEM.get_model(::Type{Val{Symbol("test 2d linear elasticity with surface + volume load")}})
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "2d nonlinear elasticity: test nonhomogeneous boundary conditions and stress calculation" begin
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test 2d nonlinear elasticity with surface load" begin
|
||||
meshfile = "/geometry/2d_block/BLOCK_1elem.med"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# http://ahojukka5.github.io/posts/finite-element-solution-for-one-element-problem/
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test 2d linear elasticity local matrices" begin
|
||||
element = Element(Quad4, [1, 2, 3, 4])
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test 2d nonlinear residual" begin
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test continuum 3d linear elasticity with surface load" begin
|
||||
nodes = Dict{Int64, Node}(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test continuum nonlinear elasticity with surface load" begin
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function calc_model(mesh_name; with_volume_load=false, debug_print=false)
|
||||
meshfile = Pkg.dir("JuliaFEM")*"/test/testdata/3d_block.med"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
#= TODO: Fix test.
|
||||
@testset "test forwarddiff version + volume load." begin
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test tet10 stiffness matrix" begin
|
||||
el = Element(Tet10, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test tet4 stiffness matrix" begin
|
||||
el = Element(Tet4, [1, 2, 3, 4])
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test tet4 + volume load" begin
|
||||
X1 = [2.0, 3.0, 4.0]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
#= TODO: Fix test
|
||||
function test_interpolate()
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "inverse isoparametric mapping" begin
|
||||
el = Element(Quad4, [1, 2, 3, 4])
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "extrapolate stress from gauss points to nodes" begin
|
||||
X = Dict{Int, Vector{Float64}}(
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test updating time dependent fields" begin
|
||||
f = Field(0.0 => 1.0)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test interpolation of discrete constant time-variant field" begin
|
||||
f = DCTV(0.0 => 0.0, 1.0 => 1.0)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "find intersection of Seg3 element" begin
|
||||
el = Element(Seg3, [1, 2, 3])
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
|
||||
|
||||
+2
-1
@@ -1,9 +1,10 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "3d rod" begin
|
||||
mesh = aster_read_mesh(Pkg.dir("JuliaFEM")*"/test/testdata/primitives.med", "CYLINDER_20_TET4")
|
||||
|
||||
+13
-12
@@ -1,9 +1,10 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "2d poisson problem with known analytical solution" begin
|
||||
# from FENiCS tutorial, u(x,y) = 1 + x² + 2y² on [0x1]×[0,1]
|
||||
@@ -15,8 +16,8 @@ using JuliaFEM.Test
|
||||
field = Problem(Heat, "unit square, 6x4 triangular mesh", 1)
|
||||
field.elements = create_elements(mesh, "UNITSQUARE")
|
||||
field.properties.formulation = "2D"
|
||||
update!(field, "temperature thermal conductivity", 1.0)
|
||||
update!(field, "temperature load", -6.0)
|
||||
update!(field, "thermal conductivity", 1.0)
|
||||
update!(field, "heat source", -6.0)
|
||||
|
||||
bc = Problem(Dirichlet, "u₀(x,y) = 1 + x² + 2y²", 1, "temperature")
|
||||
#bc.properties.order = 2
|
||||
@@ -35,18 +36,18 @@ using JuliaFEM.Test
|
||||
T_fem = Float64[]
|
||||
T_acc = Float64[]
|
||||
for (nid, X) in field("geometry")
|
||||
# info("$nid -> $X")
|
||||
push!(T_fem, field("temperature", X)[1])
|
||||
push!(T_acc, 1.0 + X[1]^2 + 2*X[2]^2)
|
||||
end
|
||||
|
||||
for element in bc.elements
|
||||
for (X, T_fem) in zip(element("geometry", 0.0), element("temperature", 0.0))
|
||||
x, y = X
|
||||
T_acc = 1.0 + x^2 + 2*y^2
|
||||
# info("(x,y) = ($x,$y), T_acc = $T_acc, T_fem = $T_fem")
|
||||
end
|
||||
end
|
||||
|
||||
@test maximum(abs(T_fem-T_acc)) < 1.0e-12
|
||||
|
||||
# gradient of field is
|
||||
gradT(X) = [2*X[1] 4*X[2]]
|
||||
X = [0.5, 0.5]
|
||||
gradT1 = gradT(X)
|
||||
gradT2 = field("temperature", X, solver.time, Val{:Grad})
|
||||
info("gradT1 = $gradT1, gradT2 = $gradT2")
|
||||
# [1.1666666666666625 1.5000000000000018] quite big difference ..?
|
||||
@test isapprox(gradT1, gradT2; rtol=25.0e-2)
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test integration point" begin
|
||||
ip = IP(1, 1.0, sqrt(1.0/3.0)*[-1.0, -1.0])
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
module InterfaceTests
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function test_foo()
|
||||
@test 1+2 == 3
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
ALL_ELEMENTS = [
|
||||
Seg2, Seg3,
|
||||
Tri3, Tri6, Quad4, Quad8, Quad9,
|
||||
Tet4, Tet10, Hex8, Hex20, Hex27
|
||||
Tri3, Tri6, Tri7,
|
||||
Quad4, Quad8, Quad9,
|
||||
Tet4, Tet10,
|
||||
Wedge6,
|
||||
Hex8, Hex20, Hex27
|
||||
]
|
||||
|
||||
@testset "Evaluating basis" begin
|
||||
@@ -39,11 +42,13 @@ end
|
||||
@test isapprox(get_volume(Seg3), 2.0)
|
||||
@test isapprox(get_volume(Tri3), 0.5)
|
||||
@test isapprox(get_volume(Tri6), 0.5)
|
||||
@test isapprox(get_volume(Tri7), 0.5)
|
||||
@test isapprox(get_volume(Quad4), 2.0^2)
|
||||
@test isapprox(get_volume(Quad8), 2.0^2)
|
||||
@test isapprox(get_volume(Quad9), 2.0^2)
|
||||
@test isapprox(get_volume(Tet4), 1/6)
|
||||
@test isapprox(get_volume(Tet10), 1/6)
|
||||
@test isapprox(get_volume(Wedge6), 1.0)
|
||||
@test isapprox(get_volume(Hex8), 2.0^3)
|
||||
@test isapprox(get_volume(Hex20), 2.0^3)
|
||||
@test isapprox(get_volume(Hex27), 2.0^3)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test eigenvalues for single tet4 element" begin
|
||||
X = Dict{Int, Vector{Float64}}(
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function test_auxiliary_plane_transforms()
|
||||
nodes = Vector{Float64}[
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function get_test_model()
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function get_test_2d_model()
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function get_test_2d_model()
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function JuliaFEM.get_mesh(::Type{Val{Symbol("two elements 1.0x0.5 with 0.1 gap in y direction")}})
|
||||
mesh = Mesh()
|
||||
@@ -21,12 +21,12 @@ function JuliaFEM.get_mesh(::Type{Val{Symbol("two elements 1.0x0.5 with 0.1 gap
|
||||
add_element!(mesh, 4, :Seg2, [7, 8])
|
||||
add_element!(mesh, 5, :Seg2, [4, 3])
|
||||
add_element!(mesh, 6, :Seg2, [6, 5])
|
||||
add_element_to_element_set!(mesh, "LOWER", 1)
|
||||
add_element_to_element_set!(mesh, "UPPER", 2)
|
||||
add_element_to_element_set!(mesh, "LOWER_BOTTOM", 3)
|
||||
add_element_to_element_set!(mesh, "UPPER_TOP", 4)
|
||||
add_element_to_element_set!(mesh, "LOWER_TOP", 5)
|
||||
add_element_to_element_set!(mesh, "UPPER_BOTTOM", 6)
|
||||
add_element_to_element_set!(mesh, :LOWER, 1)
|
||||
add_element_to_element_set!(mesh, :UPPER, 2)
|
||||
add_element_to_element_set!(mesh, :LOWER_BOTTOM, 3)
|
||||
add_element_to_element_set!(mesh, :UPPER_TOP, 4)
|
||||
add_element_to_element_set!(mesh, :LOWER_TOP, 5)
|
||||
add_element_to_element_set!(mesh, :UPPER_BOTTOM, 6)
|
||||
return mesh
|
||||
end
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function get_test_model()
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function JuliaFEM.get_mesh(::Type{Val{Symbol("curved 2d block splitted to upper and lower")}})
|
||||
meshfile = Pkg.dir("JuliaFEM") * "/test/testdata/block_2d_curved.med"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
#= TODO: Fix test.
|
||||
@testset "calculate mortar matrices and weighted gap vector for 2d model" begin
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test that interface transfers constant field without error" begin
|
||||
meshfile = Pkg.dir("JuliaFEM") * "/test/testdata/block_3d.med"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "polygon clip case 1" begin
|
||||
S = Vector[
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function get_testproblems(u, la)
|
||||
nodes = Dict{Int64, Node}(
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function JuliaFEM.get_model(::Type{Val{Symbol("1x1 plane stress quad4 block")}})
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
#=
|
||||
@testset "find dofs given a set of nodes" begin
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "get nodal values" begin
|
||||
el1 = Element(Seg2, [1, 2])
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
abstract HeatProblem <: AbstractProblem
|
||||
|
||||
|
||||
+1
-65
@@ -4,7 +4,7 @@
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "renumber element nodes" begin
|
||||
mesh = Mesh()
|
||||
@@ -19,67 +19,3 @@ using JuliaFEM.Test
|
||||
@test mesh.elements[1] == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
end
|
||||
|
||||
function get_volume(element::Element, time=0.0)
|
||||
V = 0.0
|
||||
for ip in get_integration_points(element)
|
||||
V += ip.weight*element(ip, time, Val{:detJ})
|
||||
end
|
||||
return V
|
||||
end
|
||||
|
||||
function get_volume(elements::Vector{Element}, time=0.0)
|
||||
return sum([get_volume(element, time) for element in elements])
|
||||
end
|
||||
|
||||
#=
|
||||
@testset "Hex8 element connectivity order" begin
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/rod_short.med"
|
||||
mesh = aster_read_mesh(fn, "SHORT_ROD_RECTANGLE_HE8_1ELEM")
|
||||
# 1. check volume of element
|
||||
rod = create_elements(mesh, "ROD")
|
||||
V = get_volume(rod)
|
||||
V_expected = 0.01^2*0.2
|
||||
info("Volume of rod = $V, expected = $V_expected")
|
||||
@test isapprox(V, V_expected)
|
||||
# 2. put some field value and calculate flux in gauss points
|
||||
T = Dict{Int64, Float64}(
|
||||
1 => 100.0, 2 => 100.0, 3 => 100.0, 4 => 100.0,
|
||||
5 => 200.0, 6 => 300.0, 7 => 400.0, 8 => 500.0)
|
||||
update!(rod, "temperature", T)
|
||||
# it has been verified using code aster that flux in integration
|
||||
# points is
|
||||
FLUX_ELGA = Dict{Int, Vector{Float64}}(
|
||||
1 => [-4.08493649053890E+04, -2.11324865405187E+05, 1.05662432702594E+05],
|
||||
2 => [-4.08493649053890E+04, -7.88675134594813E+05, 3.94337567297406E+05],
|
||||
3 => [-6.97168783648703E+04, -2.11324865405187E+05, 1.05662432702594E+05],
|
||||
4 => [-6.97168783648703E+04, -7.88675134594813E+05, 3.94337567297406E+05],
|
||||
5 => [-5.52831216351297E+04, -2.11324865405187E+05, 1.05662432702594E+05],
|
||||
6 => [-5.52831216351297E+04, -7.88675134594813E+05, 3.94337567297406E+05],
|
||||
7 => [-8.41506350946110E+04, -2.11324865405187E+05, 1.05662432702594E+05],
|
||||
8 => [-8.41506350946110E+04, -7.88675134594813E+05, 3.94337567297406E+05])
|
||||
# flux is q̄(ξ) = -k∇T
|
||||
element = first(rod)
|
||||
k = -50.0
|
||||
flux(xi, time) = -k*vec(element("temperature", xi, time, Val{:Grad}))
|
||||
weights = ones(8)
|
||||
# code aster integration points (FPG8)
|
||||
a = -1.0/sqrt(3.0)
|
||||
points = Vector{Float64}[
|
||||
[-a, -a, -a],
|
||||
[-a, -a, a],
|
||||
[-a, a, -a],
|
||||
[-a, a, a],
|
||||
[ a, -a, -a],
|
||||
[ a, -a, a],
|
||||
[ a, a, -a],
|
||||
[ a, a, a]]
|
||||
for i=1:8
|
||||
q1 = flux(points[i], 0.0)
|
||||
q2 = FLUX_ELGA[i]
|
||||
rtol = norm(q1-q2)/max(norm(q1),norm(q2))*100.0
|
||||
@printf "ip %i flux, JF: (% e,% e,% e), CA: (% e,% e,% e), rtol: %10.6f %%\n" i q1... q2... rtol
|
||||
@test rtol < 0.05
|
||||
end
|
||||
end
|
||||
=#
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "read inp file" begin
|
||||
model = open(parse_abaqus, Pkg.dir("JuliaFEM")*"/geometry/3d_beam/palkki.inp")
|
||||
@@ -34,45 +34,20 @@ end
|
||||
@test model["elsets"]["BEAM"] == [1, 2]
|
||||
end
|
||||
|
||||
@testset "test unknown handler warning message" begin
|
||||
fn = tempname()
|
||||
fid = open(fn, "w")
|
||||
testdata = """*ELEMENT2, TYPE=C3D10, ELSET=Body1
|
||||
1, 243, 240, 191, 117, 245, 242, 244,
|
||||
1, 2, 196
|
||||
"""
|
||||
write(fid, testdata)
|
||||
close(fid)
|
||||
model = open(parse_abaqus, fn)
|
||||
# empty model expected, parser doesn't know what to do with unknown section
|
||||
@test length(model) == 0
|
||||
@testset "parse nodes from abaqus .inp file to Mesh" begin
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/cube_tet4.inp"
|
||||
mesh = abaqus_read_mesh(fn)
|
||||
info(mesh.surfaces)
|
||||
@test length(mesh.nodes) == 10
|
||||
@test length(mesh.elements) == 17
|
||||
@test haskey(mesh.elements, 1)
|
||||
@test mesh.elements[1] == [8, 10, 1, 2]
|
||||
@test mesh.element_types[1] == :Tet4
|
||||
@test haskey(mesh.node_sets, :SYM12)
|
||||
@test haskey(mesh.element_sets, :CUBE)
|
||||
@test haskey(mesh.surfaces, :LOAD)
|
||||
@test length(mesh.surfaces[:LOAD]) == 2
|
||||
@test mesh.surfaces[:LOAD][1] == (16, :S1)
|
||||
@test mesh.surface_types[:LOAD] == :ELEMENT
|
||||
end
|
||||
|
||||
#= TODO: fix test
|
||||
@testset "test that reader throws error when dimension information of element is missing" begin
|
||||
# *ELEMENT, TYPE=neverseenbefore, ELSET=Body1
|
||||
data = """
|
||||
1, 243, 240, 191, 117, 245, 242, 244,
|
||||
1, 2, 196
|
||||
"""
|
||||
model = Dict()
|
||||
header = Dict("section"=>"ELEMENT", "options" => Dict("TYPE" => "neverseenbefore", "ELSET"=>"Body1"))
|
||||
@test_throws Exception parse_element_section(model, header, data)
|
||||
end
|
||||
=#
|
||||
|
||||
#= TODO: fix test
|
||||
@testset "test read surface set section" begin
|
||||
data = """*SURFACE, TYPE=ELEMENT, NAME=LOAD
|
||||
31429,S1
|
||||
31481,S3
|
||||
"""
|
||||
model = Dict{AbstractString, Any}()
|
||||
model["nsets"] = Dict{AbstractString, Vector{Int}}()
|
||||
model["elsets"] = Dict{AbstractString, Vector{Int}}()
|
||||
model["elements"] = Dict{Integer, Any}()
|
||||
parse_section(model, data, :SURFACE, 1, 3, Val{:SURFACE})
|
||||
@test model["surfaces"]["LOAD"] == [(31429,1), (31481,3)]
|
||||
end
|
||||
=#
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "read ascii mesh" begin
|
||||
mesh = """
|
||||
@@ -64,48 +64,6 @@ end
|
||||
@test length(nodes) == 8
|
||||
end
|
||||
|
||||
@testset "test combining meshes" begin
|
||||
|
||||
mesh1 = Dict{String, Any}(
|
||||
"nodes" => Dict{Int64, Vector{Float64}}(
|
||||
1 => [1.0, 2.0],
|
||||
2 => [2.0, 3.0]
|
||||
),
|
||||
"connectivity" => Dict{Int64, Tuple{Symbol, Symbol, Vector{Int64}}}(
|
||||
1 => (:SE2, :GRP1, [1, 2])
|
||||
),
|
||||
)
|
||||
|
||||
mesh2 = Dict{String, Any}(
|
||||
"nodes" => Dict{Int64, Vector{Float64}}(
|
||||
1 => [3.0, 4.0],
|
||||
2 => [4.0, 5.0]
|
||||
),
|
||||
"connectivity" => Dict{Int64, Tuple{Symbol, Symbol, Vector{Int64}}}(
|
||||
1 => (:SE2, :GRP1, [1, 2])
|
||||
),
|
||||
)
|
||||
|
||||
aster_renumber_nodes!(mesh1, mesh2)
|
||||
@test length(mesh2["nodes"]) == 2
|
||||
@test 3 in keys(mesh2["nodes"])
|
||||
@test 4 in keys(mesh2["nodes"])
|
||||
@test mesh2["connectivity"][1] == (:SE2, :GRP1, [3, 4])
|
||||
|
||||
aster_renumber_elements!(mesh1, mesh2)
|
||||
@test length(mesh2["connectivity"]) == 1
|
||||
@test mesh2["connectivity"][2] == (:SE2, :GRP1, [3, 4])
|
||||
|
||||
mesh = aster_combine_meshes(mesh1, mesh2)
|
||||
@test length(mesh["nodes"]) == 4
|
||||
@test mesh["nodes"][1] == [1.0, 2.0]
|
||||
@test mesh["nodes"][2] == [2.0, 3.0]
|
||||
@test mesh["nodes"][3] == [3.0, 4.0]
|
||||
@test mesh["nodes"][4] == [4.0, 5.0]
|
||||
@test mesh["connectivity"][1] == (:SE2, :GRP1, [1, 2])
|
||||
@test mesh["connectivity"][2] == (:SE2, :GRP1, [3, 4])
|
||||
end
|
||||
|
||||
function JuliaFEM.get_mesh(::Type{Val{Symbol("block_2d_1elem_quad4")}})
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/block_2d_1elem_quad4.med"
|
||||
mesh = aster_read_mesh(fn)
|
||||
@@ -114,6 +72,7 @@ end
|
||||
|
||||
@testset "test reading aster .med file" begin
|
||||
mesh = get_mesh("block_2d_1elem_quad4")
|
||||
#=
|
||||
info("nodes")
|
||||
for (k, v) in mesh.nodes
|
||||
info("$k => $v")
|
||||
@@ -130,15 +89,16 @@ end
|
||||
for (k, v) in mesh.element_sets
|
||||
info("$k => $v")
|
||||
end
|
||||
=#
|
||||
@test length(mesh.element_sets) == 5
|
||||
@test length(mesh.node_sets) == 4
|
||||
@test length(mesh.elements) == 5
|
||||
@test length(mesh.nodes) == 4
|
||||
for elset in ["BLOCK", "TOP", "BOTTOM", "LEFT", "RIGHT"]
|
||||
for elset in [:BLOCK, :TOP, :BOTTOM, :LEFT, :RIGHT]
|
||||
@test haskey(mesh.element_sets, elset)
|
||||
@test length(mesh.element_sets[elset]) == 1
|
||||
end
|
||||
for nset in ["TOP_LEFT", "TOP_RIGHT", "BOTTOM_LEFT", "BOTTOM_RIGHT"]
|
||||
for nset in [:TOP_LEFT, :TOP_RIGHT, :BOTTOM_LEFT, :BOTTOM_RIGHT]
|
||||
@test haskey(mesh.node_sets, nset)
|
||||
@test length(mesh.node_sets[nset]) == 1
|
||||
end
|
||||
@@ -146,15 +106,15 @@ end
|
||||
|
||||
@testset "test filter by element set" begin
|
||||
mesh = get_mesh("block_2d_1elem_quad4")
|
||||
mesh2 = filter_by_element_set(mesh, "BLOCK")
|
||||
@test haskey(mesh2.element_sets, "BLOCK")
|
||||
mesh2 = filter_by_element_set(mesh, :BLOCK)
|
||||
@test haskey(mesh2.element_sets, :BLOCK)
|
||||
@test length(mesh2.elements) == 1
|
||||
end
|
||||
|
||||
function calculate_volume(mesh_name::String, eltype::Symbol)
|
||||
function calculate_volume(mesh_name, eltype)
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(fn, mesh_name)
|
||||
elements = create_elements(mesh, eltype)
|
||||
elements = create_elements(mesh; element_type=eltype)
|
||||
V = 0.0
|
||||
time = 0.0
|
||||
for element in elements
|
||||
@@ -171,7 +131,7 @@ end
|
||||
@testset "calculate volume for 1 element models" begin
|
||||
@test isapprox(calculate_volume("TRIANGLE_TRI3_1", :Tri3), 1/2)
|
||||
@test isapprox(calculate_volume("TRIANGLE_TRI6_1", :Tri6), 1/2)
|
||||
# @test isapprox(calculate_volume("TRIANGLE_TRI7_1", :Tri7), 1/2)
|
||||
@test isapprox(calculate_volume("TRIANGLE_TRI7_1", :Tri7), 1/2)
|
||||
@test isapprox(calculate_volume("SQUARE_QUAD4_1", :Quad4), 2^2)
|
||||
@test isapprox(calculate_volume("SQUARE_QUAD8_1", :Quad8), 2^2)
|
||||
@test isapprox(calculate_volume("SQUARE_QUAD9_1", :Quad9), 2^2)
|
||||
@@ -181,7 +141,7 @@ end
|
||||
@test isapprox(calculate_volume("CUBE_HEX8_1", :Hex8), 2^3)
|
||||
@test isapprox(calculate_volume("CUBE_HEX20_1", :Hex20), 2^3)
|
||||
@test isapprox(calculate_volume("CUBE_HEX27_1", :Hex27), 2^3)
|
||||
# @test isapprox(calculate_volume("WEDGE_WEDGE6_1", :Wedge6, 1/2))
|
||||
@test isapprox(calculate_volume("WEDGE_WEDGE6_1", :Wedge6), 1)
|
||||
# @test isapprox(calculate_volume("WEDGE_WEDGE15_1", :Wedge15, 1/2))
|
||||
# @test isapprox(calculate_volume("PYRAMID_PYRAMID5_1", :Pyramid5, ?))
|
||||
# @test isapprox(calculate_volume("PYRAMID_PYRAMID13_1", :Pyramid13, ?))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test initialize field problem" begin
|
||||
el = Element(Seg2, [1, 2])
|
||||
@@ -11,8 +11,9 @@ using JuliaFEM.Test
|
||||
initialize!(pr)
|
||||
@test haskey(el, "temperature")
|
||||
# one timestep in field "temperature"
|
||||
@test length(el("temperature")) == 1
|
||||
@test length(el["temperature"]) == 1
|
||||
# this way we access to field at default time t=0.0, it's different than ^!
|
||||
@test length(el("temperature")) == 2
|
||||
# length of single increment
|
||||
@test length(el("temperature", 0.0)) == 2
|
||||
@test length(last(el, "temperature").data) == 2
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "test projection" begin
|
||||
C = [
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
function test_linearsolver()
|
||||
el1 = Quad4([1, 2, 3, 4])
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Abaqus
|
||||
using JuliaFEM.Testing
|
||||
|
||||
@testset "parse abaqus inp file to AbaqusModel" begin
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/cube_tet4.inp"
|
||||
model = abaqus_read_model(fn)
|
||||
|
||||
@test length(model.properties) == 1
|
||||
section = first(model.properties)
|
||||
@test section.element_set == :CUBE
|
||||
@test section.material == :MAT
|
||||
|
||||
@test haskey(model.materials, :MAT)
|
||||
material = model.materials[:MAT]
|
||||
@test isapprox(first(material.properties).E, 208.0e3)
|
||||
|
||||
@test length(model.steps) == 1
|
||||
step = first(model.steps)
|
||||
@test length(step.content) == 2
|
||||
|
||||
bc = step.content[1]
|
||||
@test bc[1] == [:SYM12, 3]
|
||||
@test bc[2] == [:SYM23, 1]
|
||||
@test bc[3] == [:SYM13, 2]
|
||||
|
||||
load = step.content[2]
|
||||
@test load[1] == [:LOAD, :P, 1.00000]
|
||||
end
|
||||
|
||||
#=
|
||||
@testset "given abaqus model solve field" begin
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/cube_tet4.inp"
|
||||
model = abaqus_read_model(fn)
|
||||
model()
|
||||
end
|
||||
=#
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
#= TODO: Fix test
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
abstract PlaneStressElasticityProblem <: AbstractProblem
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
#using PyPlot
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.MaterialModels: stiffnessTensor, calculate_stress, State
|
||||
using JuliaFEM.MaterialModels: stiffnessTensorPlaneStress
|
||||
using JuliaFEM.Testing
|
||||
#using JuliaFEM.MaterialModels: stiffnessTensor, calculate_stress, State
|
||||
#using JuliaFEM.MaterialModels: stiffnessTensorPlaneStress
|
||||
|
||||
|
||||
function test_von_mises_3D_basic()
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Postprocess
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Testing
|
||||
|
||||
testdata = """\
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
*NODE, NSET=NALL
|
||||
1, 4.07417, 3.51532, 4.43035
|
||||
2, 6.24583, 4.69753, 6.40067
|
||||
3, 10.00000, 10.00000, 0.00000
|
||||
4, 10.00000, 0.00000, 0.00000
|
||||
5, 0.00000, 0.00000, 0.00000
|
||||
6, 0.00000, 10.00000, 0.00000
|
||||
7, 0.00000, 10.00000, 10.00000
|
||||
8, 0.00000, 0.00000, 10.00000
|
||||
9, 10.00000, 10.00000, 10.00000
|
||||
10, 10.00000, 0.00000, 10.00000
|
||||
*ELEMENT, TYPE=C3D4, ELSET=CUBE
|
||||
1, 8, 10, 1, 2
|
||||
2, 4, 1, 10, 2
|
||||
3, 3, 9, 7, 2
|
||||
4, 3, 5, 4, 1
|
||||
5, 8, 7, 2, 1
|
||||
6, 5, 6, 8, 1
|
||||
7, 7, 6, 1, 8
|
||||
8, 7, 9, 8, 2
|
||||
9, 5, 8, 10, 1
|
||||
10, 3, 6, 5, 1
|
||||
11, 4, 10, 9, 2
|
||||
12, 1, 7, 2, 3
|
||||
13, 3, 4, 9, 2
|
||||
14, 3, 1, 4, 2
|
||||
15, 4, 5, 10, 1
|
||||
16, 8, 9, 10, 2
|
||||
17, 3, 6, 1, 7
|
||||
*SOLID SECTION, ELSET=CUBE, MATERIAL=MAT
|
||||
*MATERIAL, NAME=MAT
|
||||
*ELASTIC
|
||||
2.08000e+005, 3.00000e-001
|
||||
*NSET, NSET=SYM12
|
||||
5, 6, 3, 4,
|
||||
*NSET, NSET=SYM23
|
||||
5, 6, 7, 8,
|
||||
*NSET, NSET=SYM13
|
||||
5, 10, 8, 4,
|
||||
*SURFACE, TYPE=ELEMENT, NAME=LOAD
|
||||
16, S1
|
||||
8, S1
|
||||
*STEP
|
||||
*STATIC
|
||||
*BOUNDARY
|
||||
SYM12, 3
|
||||
SYM23, 1
|
||||
SYM13, 2
|
||||
*DSLOAD
|
||||
LOAD, P, 1.00000
|
||||
*NODE FILE
|
||||
COORD
|
||||
U
|
||||
*END STEP
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user