mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-12 22:33:19 +00:00
lot of new tests, echangement of modal solver, eigenvalue analysis with mesh tie
This commit is contained in:
+2
-1
@@ -115,7 +115,8 @@ 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!,
|
||||
aster_renumber_elements!, aster_combine_meshes, aster_read_mesh,
|
||||
filter_by_element_set, filter_by_element_id, MEDFile
|
||||
filter_by_element_set, filter_by_element_id, MEDFile, aster_read_data,
|
||||
aster_read_mesh_names, aster_read_node_sets, aster_read_nodes, RMEDFile
|
||||
end
|
||||
|
||||
function get_mesh(mesh_name::AbstractString, args...; kwargs...)
|
||||
|
||||
+1
-1
@@ -672,7 +672,7 @@ function abaqus_download(name)
|
||||
fn = rstrip(ENV["ABAQUS_DOWNLOAD_DIR"], '/') * "/" * fn
|
||||
end
|
||||
if !isfile(fn)
|
||||
info("Downloading model $name from $url to $fn")
|
||||
info("Downloading model $name ...")
|
||||
download("$url/$name.inp", fn)
|
||||
end
|
||||
return 0
|
||||
|
||||
@@ -130,7 +130,7 @@ function calc_nodal_values!(elements::Vector, field_name, field_dim, time;
|
||||
end
|
||||
end
|
||||
|
||||
function calc_nodal_values!(problem::Problem, field_name, field_dim, time)
|
||||
function calc_nodal_values!(problem::Problem, field_name::AbstractString, field_dim::Int, time::Float64)
|
||||
# after all, it's just a mass matrix ...
|
||||
# isempty(problem.assembly.M) && assemble!(problem, time, Val{:mass_matrix}; density=1.0, dual_basis=false, dim=1)
|
||||
# M = sparse(problem.assembly.M)
|
||||
@@ -141,7 +141,7 @@ end
|
||||
"""
|
||||
Return node ids + vector of values
|
||||
"""
|
||||
function get_nodal_vector(elements, field_name, time)
|
||||
function get_nodal_vector(elements::Vector, field_name::AbstractString, time::Float64)
|
||||
f = Dict()
|
||||
for element in elements
|
||||
for (c, v) in zip(get_connectivity(element), element[field_name](time))
|
||||
@@ -337,6 +337,18 @@ function call(problem::Problem, field_name::AbstractString, X::Vector, time::Flo
|
||||
return fillna
|
||||
end
|
||||
|
||||
function call(solver::Solver, field_name::AbstractString, X::Vector, time::Float64; fillna=NaN)
|
||||
for problem in get_problems(solver)
|
||||
for element in get_elements(problem)
|
||||
if inside(element, X, time)
|
||||
xi = get_local_coordinates(element, X, time)
|
||||
return element(field_name, xi, time)
|
||||
end
|
||||
end
|
||||
end
|
||||
return fillna
|
||||
end
|
||||
|
||||
""" Calculate area of cross-section. """
|
||||
function calculate_area(problem::Problem, X=[0.0, 0.0], time=0.0)
|
||||
A = 0.0
|
||||
|
||||
@@ -165,6 +165,18 @@ function reorder_element_connectivity!(mesh::Mesh, mapping::Dict{Symbol, Vector{
|
||||
end
|
||||
end
|
||||
|
||||
function JuliaFEM.Problem{P<:FieldProblem}(mesh::Mesh, ::Type{P}, name::AbstractString, dimension::Int64)
|
||||
problem = Problem{P}(name, dimension, "none", [], Dict(), Assembly(), P())
|
||||
problem.elements = create_elements(mesh, name)
|
||||
return problem
|
||||
end
|
||||
|
||||
function JuliaFEM.Problem{P<:BoundaryProblem}(mesh::Mesh, ::Type{P}, name, dimension, parent_field_name)
|
||||
problem = Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), P())
|
||||
problem.elements = create_elements(mesh, name)
|
||||
return problem
|
||||
end
|
||||
|
||||
"""
|
||||
Swap surface element connectivity s.t. normals point outward
|
||||
"""
|
||||
|
||||
@@ -55,19 +55,17 @@ function parse(mesh, ::Type{Val{:CODE_ASTER_MAIL}})
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
Code Aster binary file (.med), which is exported from SALOME.
|
||||
"""
|
||||
""" Code Aster binary file (.med). """
|
||||
type MEDFile
|
||||
data :: Dict
|
||||
end
|
||||
|
||||
function MEDFile(fn)
|
||||
MEDFile(h5read(fn, "/"))
|
||||
return MEDFile(h5read(fn, "/"))
|
||||
end
|
||||
|
||||
function get_mesh_names(med::MEDFile)
|
||||
return collect(keys(med.data["FAS"]))
|
||||
return sort(collect(keys(med.data["FAS"])))
|
||||
end
|
||||
|
||||
function get_nodes(med::MEDFile, nsets, mesh_name)
|
||||
@@ -91,6 +89,13 @@ end
|
||||
|
||||
function get_node_sets(med::MEDFile, mesh_name)
|
||||
ns = Dict{Int64, Symbol}(0 => :NALL)
|
||||
if !haskey(med.data["FAS"], mesh_name)
|
||||
warn("Mesh $mesh_name not found from med file.")
|
||||
meshes = get_mesh_names(med)
|
||||
all_meshes = join(meshes, ", ")
|
||||
warn("Available meshes: $all_meshes")
|
||||
error("Mesh $mesh_name not found.")
|
||||
end
|
||||
haskey(med.data["FAS"][mesh_name], "NOEUD") || return ns
|
||||
nsets = med.data["FAS"][mesh_name]["NOEUD"]
|
||||
for nset in keys(nsets)
|
||||
@@ -250,4 +255,63 @@ function aster_read_mesh(fn, mesh_name=nothing; reorder_element_connectivity=tru
|
||||
return mesh
|
||||
end
|
||||
|
||||
# TODO: refactor and remove obsolete stuff.
|
||||
""" Code Aster result file (.rmed). """
|
||||
type RMEDFile
|
||||
data :: Dict
|
||||
end
|
||||
|
||||
function RMEDFile(fn)
|
||||
return RMEDFile(h5read(fn, "/"))
|
||||
end
|
||||
|
||||
""" Return nodes from result med file. """
|
||||
function aster_read_nodes(rmed::RMEDFile)
|
||||
increments = keys(rmed.data["ENS_MAA"]["MAIL"])
|
||||
@assert length(increments) == 1
|
||||
increment = first(increments)
|
||||
nodes = rmed.data["ENS_MAA"]["MAIL"][increment]["NOE"]
|
||||
node_names = nodes["NOM"]
|
||||
node_coords = nodes["COO"]
|
||||
nnodes = length(node_names)
|
||||
dim = round(Int, length(node_coords)/nnodes)
|
||||
node_coords = reshape(node_coords, nnodes, dim)'
|
||||
stripper(node_name) = strip(ascii(pointer(convert(Vector{UInt8}, node_name))))
|
||||
node_names = map(stripper, node_names)
|
||||
# INFO: quite safe assumption is that id is in node name, i.e. N1 => 1, N123 => 123
|
||||
node_id(node_name) = parse(matchall(r"\d+", node_name)[1])
|
||||
node_ids = map(node_id, node_names)
|
||||
nodes = Dict([j => node_coords[:,j] for j in node_ids])
|
||||
return nodes
|
||||
end
|
||||
|
||||
""" Read nodal field from rmed file. """
|
||||
function aster_read_data(rmed::RMEDFile, field_name; field_type=:NODE,
|
||||
info_fields=true, node_ids=nothing)
|
||||
|
||||
if contains(field_name, "ELGA")
|
||||
field_type = :GAUSS
|
||||
end
|
||||
|
||||
if node_ids == nothing
|
||||
nodes = aster_read_nodes(rmed)
|
||||
node_ids = sort(collect(keys(nodes)))
|
||||
end
|
||||
|
||||
if info_fields
|
||||
field_names = keys(rmed.data["CHA"])
|
||||
all_fields = join(field_names, ", ")
|
||||
info("results: $all_fields")
|
||||
end
|
||||
|
||||
chdata = rmed.data["CHA"]["RESU____$field_name"]
|
||||
@assert length(chdata) == 1
|
||||
increment = chdata[first(keys(chdata))]
|
||||
if field_type == :NODE
|
||||
data = increment["NOE"]["MED_NO_PROFILE_INTERNAL"]["CO"]
|
||||
results = Dict([j => data[j] for j in node_ids])
|
||||
else
|
||||
error("Unable to read result of type $field_type: not implemented")
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
|
||||
+4
-4
@@ -104,10 +104,10 @@ julia> prob2 = Problem(Elasticity, 3)
|
||||
|
||||
"""
|
||||
function Problem{P<:FieldProblem}(::Type{P}, name::AbstractString, dimension::Int64)
|
||||
Problem{P}(name, dimension, "none", [], Dict(), Assembly(), P())
|
||||
return Problem{P}(name, dimension, "none", [], Dict(), Assembly(), P())
|
||||
end
|
||||
function Problem{P<:FieldProblem}(::Type{P}, dimension::Int64)
|
||||
Problem{P}("$P problem", dimension, "none", [], Dict(), Assembly(), P())
|
||||
return Problem{P}("$P problem", dimension, "none", [], Dict(), Assembly(), P())
|
||||
end
|
||||
|
||||
""" Construct a new boundary problem.
|
||||
@@ -120,13 +120,13 @@ julia> bc1 = Problem(Dirichlet, "support", 3, "displacement")
|
||||
|
||||
"""
|
||||
function Problem{P<:BoundaryProblem}(::Type{P}, name, dimension, parent_field_name)
|
||||
Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), P())
|
||||
return Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), P())
|
||||
end
|
||||
function Problem{P<:BoundaryProblem}(::Type{P}, main_problem::Problem)
|
||||
name = "$P problem"
|
||||
dimension = get_unknown_field_dimension(main_problem)
|
||||
parent_field_name = get_unknown_field_name(main_problem)
|
||||
Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), P())
|
||||
return Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), P())
|
||||
end
|
||||
|
||||
function get_formulation_type{P<:FieldProblem}(problem::Problem{P})
|
||||
|
||||
@@ -86,6 +86,21 @@ function get_cells(P, C)
|
||||
info("indices = $indices")
|
||||
end
|
||||
|
||||
""" Test does P contain q. """
|
||||
function contains{T}(P::Vector{T}, q::T; check_is_close=true, rtol=1.0e-5)
|
||||
if q in P
|
||||
return true
|
||||
end
|
||||
if check_is_close
|
||||
for p in P
|
||||
if isapprox(p, q; rtol=rtol)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function get_polygon_clip(xs, xm, n; debug=false)
|
||||
# objective: search does line xm1 - xm2 clip xs
|
||||
nm = length(xm)
|
||||
@@ -103,7 +118,7 @@ function get_polygon_clip(xs, xm, n; debug=false)
|
||||
# 2. test is slave point inside master, if yes, add to clip
|
||||
for i=1:ns
|
||||
if vertex_inside_polygon(xs[i], xm)
|
||||
xs[i] in P && continue
|
||||
contains(P, xs[i]) && continue
|
||||
debug && info("2. $(xs[i]) inside M -> push")
|
||||
push!(P, xs[i])
|
||||
end
|
||||
@@ -126,7 +141,7 @@ function get_polygon_clip(xs, xm, n; debug=false)
|
||||
q = xs1 + t*(xs2 - xs1)
|
||||
#info("t=$t, q=$q, q ∈ xm ? $(vertex_inside_polygon(q, xm))")
|
||||
if vertex_inside_polygon(q, xm)
|
||||
q in P && continue
|
||||
contains(P, q) && continue
|
||||
debug && info("3. $q inside M -> push")
|
||||
push!(P, q)
|
||||
end
|
||||
|
||||
+29
-2
@@ -217,6 +217,19 @@ function create_projection(C::SparseMatrixCSC, g; S=nothing, tol=1.0e-12)
|
||||
return P, h
|
||||
end
|
||||
|
||||
""" Assume C is invertible. """
|
||||
function create_projection(C, g, ::Type{Val{:invertible}})
|
||||
nz1, nz2 = get_nonzeros(C)
|
||||
P = spzeros(size(C)...)
|
||||
for j=1:size(C,1)
|
||||
j in nz1 && continue
|
||||
P[j,j] = 1.0
|
||||
end
|
||||
v = lufact(C[nz1,nz2]) \ full(g[nz1])
|
||||
return P, v
|
||||
end
|
||||
|
||||
|
||||
|
||||
"""
|
||||
Solve linear system using LDLt factorization (SuiteSparse). This version
|
||||
@@ -332,20 +345,34 @@ function solve_linear_system(solver::Solver; F=nothing, empty_assemblies_before_
|
||||
end
|
||||
|
||||
""" Default assembler for solver. """
|
||||
function assemble!(solver::Solver; show_info=true)
|
||||
function assemble!(solver::Solver; show_info=true, timing=true)
|
||||
show_info && info("Assembling problems ...")
|
||||
t0 = Base.time()
|
||||
assembly_times = Dict()
|
||||
nproblems = 0
|
||||
ndofs = 0
|
||||
for problem in solver.problems
|
||||
t00 = Base.time()
|
||||
empty!(problem.assembly)
|
||||
assemble!(problem, solver.time)
|
||||
nproblems += 1
|
||||
ndofs = max(ndofs, size(problem.assembly.K, 2))
|
||||
Ks = size(problem.assembly.K, 2)
|
||||
Cs = size(problem.assembly.C1, 2)
|
||||
ndofs = max(ndofs, Ks, Cs)
|
||||
t11 = Base.time()
|
||||
assembly_times[problem.name] = t11-t00
|
||||
end
|
||||
solver.ndofs = ndofs
|
||||
t1 = round(Base.time()-t0, 2)
|
||||
show_info && info("Assembled $nproblems problems in $t1 seconds. ndofs = $ndofs.")
|
||||
if timing
|
||||
info("Assembly times:")
|
||||
for (i, problem) in enumerate(solver.problems)
|
||||
pn = problem.name
|
||||
pt = round(assembly_times[pn], 2)
|
||||
info("$i $pn $pt")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function get_unknown_fields(solver::Solver)
|
||||
|
||||
+66
-10
@@ -23,7 +23,7 @@ function Modal(nev=10, which=:SM)
|
||||
solver = Modal(false, Vector(), Matrix(), nev, which)
|
||||
end
|
||||
|
||||
function call(solver::Solver{Modal}; show_info=true, debug=false)
|
||||
function call(solver::Solver{Modal}; show_info=true, debug=false, bc_invertible=false)
|
||||
show_info && info(repeat("-", 80))
|
||||
show_info && info("Starting natural frequency solver")
|
||||
show_info && info("Increment time t=$(round(solver.time, 3))")
|
||||
@@ -48,16 +48,59 @@ function call(solver::Solver{Modal}; show_info=true, debug=false)
|
||||
if solver.properties.geometric_stiffness
|
||||
K += Kg
|
||||
end
|
||||
|
||||
|
||||
@assert nnz(D) == 0
|
||||
@assert C1 == C2
|
||||
|
||||
tic()
|
||||
P, h = create_projection(C1, g)
|
||||
|
||||
if bc_invertible
|
||||
P, h = create_projection(C1, g, Val{:invertible})
|
||||
else
|
||||
P, h = create_projection(C1, g)
|
||||
end
|
||||
K_red = P'*K*P
|
||||
M_red = P'*M*P
|
||||
# make sure matrices are symmetric
|
||||
K_red = 1/2*(K_red + K_red')
|
||||
M_red = 1/2*(M_red + M_red')
|
||||
|
||||
#=
|
||||
ndim = size(C1,1)
|
||||
nz = get_nonzero_rows(C1)
|
||||
nz = setdiff(collect(1:ndim), nz)
|
||||
g = zeros(ndim)
|
||||
P = spzeros(ndim, ndim)
|
||||
for j in nz
|
||||
P[j,j] = 1.0
|
||||
end
|
||||
K_red = P'*K*P
|
||||
M_red = P'*M*P
|
||||
# make sure matrices are symmetric
|
||||
K_red = 1/2*(K_red + K_red')
|
||||
M_red = 1/2*(M_red + M_red')
|
||||
|
||||
#=
|
||||
K_red = K[nz,nz]
|
||||
M_red = M[nz,nz]
|
||||
# make sure matrices are symmetric
|
||||
K_red = 1/2*(K_red + K_red')
|
||||
M_red = 1/2*(M_red + M_red')
|
||||
=#
|
||||
|
||||
#=
|
||||
K_red = copy(K)
|
||||
M_red = copy(M)
|
||||
for j=1:size(K_red)
|
||||
j in nz && continue
|
||||
K_red[j,:] = 0.0
|
||||
K_red[:,j] = 0.0
|
||||
M_red[j,:] = 0.0
|
||||
M_red[:,j] = 0.0
|
||||
end
|
||||
=#
|
||||
=#
|
||||
|
||||
t1 = round(toq(), 2)
|
||||
info("Eliminated dirichlet boundaries in $t1 seconds.")
|
||||
|
||||
@@ -79,16 +122,30 @@ function call(solver::Solver{Modal}; show_info=true, debug=false)
|
||||
om2, X = eigs(K_red[nz,nz], M_red[nz,nz]; nev=props.nev, which=props.which)
|
||||
catch
|
||||
info("failed to calculate eigenvalues")
|
||||
info("K sym?", issym(K_red[nz,nz]))
|
||||
info("M sym?", issym(M_red[nz,nz]))
|
||||
info("K posdef?", isposdef(K_red[nz,nz]))
|
||||
info("M posdef?", isposdef(M_red[nz,nz]))
|
||||
info("reduced system")
|
||||
info("is K symmetric? ", issym(K_red[nz,nz]))
|
||||
info("is M symmetric? ", issym(M_red[nz,nz]))
|
||||
info("is K positive definite? ", isposdef(K_red[nz,nz]))
|
||||
info("is M positive definite? ", isposdef(M_red[nz,nz]))
|
||||
k1 = maximum(abs(K_red[nz,nz] - K_red[nz,nz]'))
|
||||
m1 = maximum(abs(M_red[nz,nz] - M_red[nz,nz]'))
|
||||
info("K skewness ", k1)
|
||||
info("M skewness ", m1)
|
||||
info("K 'skewness' (max(abs(K - K'))) = ", k1)
|
||||
info("M 'skewness' (max(abs(M - M'))) = ", m1)
|
||||
|
||||
info("original matrix")
|
||||
info("is K symmetric? ", issym(K[nz,nz]))
|
||||
info("is M symmetric? ", issym(M[nz,nz]))
|
||||
info("is K positive definite? ", isposdef(K[nz,nz]))
|
||||
info("is M positive definite? ", isposdef(M[nz,nz]))
|
||||
k1 = maximum(abs(K[nz,nz] - K[nz,nz]'))
|
||||
m1 = maximum(abs(M[nz,nz] - M[nz,nz]'))
|
||||
info("K 'skewness' (max(abs(K - K'))) = ", k1)
|
||||
info("M 'skewness' (max(abs(M - M'))) = ", m1)
|
||||
|
||||
rethrow()
|
||||
end
|
||||
info("Eigenvalues computed in $t1 seconds. Eigenvalues: $om2")
|
||||
|
||||
props.eigvals = om2
|
||||
props.eigvecs = zeros(ndofs, length(om2))
|
||||
v = zeros(ndofs)
|
||||
@@ -98,7 +155,6 @@ function call(solver::Solver{Modal}; show_info=true, debug=false)
|
||||
props.eigvecs[:,i] = P*v + g
|
||||
end
|
||||
t1 = round(toq(), 2)
|
||||
info("Eigenvalues computed in $t1 seconds. Eigenvalues: $om2")
|
||||
|
||||
for i=1:length(om2)
|
||||
freq = real(sqrt(om2[i])/(2.0*pi))
|
||||
|
||||
+7
-1
@@ -163,6 +163,12 @@ function get_nonzero_columns(A::Union{SparseMatrixCOO, Matrix})
|
||||
return get_nonzero_columns(sparse(A))
|
||||
end
|
||||
|
||||
function get_nonzeros(C::Union{SparseMatrixCSC, Matrix})
|
||||
nz1 = get_nonzero_rows(C)
|
||||
nz2 = get_nonzero_columns(C)
|
||||
return (nz1, nz2)
|
||||
end
|
||||
|
||||
function size(A::SparseMatrixCOO)
|
||||
isempty(A) && return (0, 0)
|
||||
return maximum(A.I), maximum(A.J)
|
||||
@@ -173,7 +179,7 @@ function size(A::SparseMatrixCOO, idx::Int)
|
||||
end
|
||||
|
||||
""" Matrix norm. Automatically convert to dense when asking for 2-norm for small matrices. """
|
||||
function Base.norm(A::SparseMatrixCOO, p=Inf; maxdim=1000)
|
||||
function norm(A::SparseMatrixCOO, p=Inf; maxdim=1000)
|
||||
dim = size(A, 1)
|
||||
if p == 2 && dim > maxdim
|
||||
info("Assembly norm: dim = $dim > $maxdim and p=$p, not making dense matrices for operation.")
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# 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.Testing
|
||||
|
||||
#=
|
||||
Two rings, RING1 = inner, RING2 = outer, RINGS combined mesh. Set T=1.0 for
|
||||
inner ring and T=2.0 for outer ring, measure temperature from middle of ring.
|
||||
Results are calculated using Code Aster for comparison.
|
||||
=#
|
||||
@testset "test 3d heat, two rings, and compare to CA solution" begin
|
||||
meshfile = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(meshfile, "RINGS_UNION")
|
||||
|
||||
rings = Problem(Heat, "RINGS", 1)
|
||||
# rings.elements = create_elements(mesh; element_type=:Tet4)
|
||||
rings.elements = create_elements(mesh, "RING1", "RING2")
|
||||
update!(rings.elements, "temperature thermal conductivity", 1.0)
|
||||
bc_inner = Problem(Dirichlet, "INNER SURFACE", 1, "temperature")
|
||||
bc_inner.elements = create_elements(mesh, "RING1_INNER")
|
||||
bc_outer = Problem(Dirichlet, "OUTER SURFACE", 1, "temperature")
|
||||
bc_outer.elements = create_elements(mesh, "RING2_OUTER")
|
||||
update!(bc_inner, "temperature 1", 1.0)
|
||||
update!(bc_outer, "temperature 1", 2.0)
|
||||
info("# of elements in RING1_INNER = ", length(bc_inner.elements))
|
||||
info("# of elements in RING2_OUTER = ", length(bc_outer.elements))
|
||||
solver = LinearSolver(rings, bc_inner, bc_outer)
|
||||
solver()
|
||||
|
||||
temp_jf = rings("temperature", 0.0)
|
||||
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/rings.rmed"
|
||||
results = RMEDFile(fn)
|
||||
nodes = aster_read_nodes(results)
|
||||
temp_ca = aster_read_data(results, "TEMP")
|
||||
|
||||
passed = true
|
||||
for j in sort(collect(keys(temp_jf)))
|
||||
X = nodes[j]
|
||||
T1 = temp_jf[j]
|
||||
T2 = temp_ca[j]
|
||||
rtol = norm(T1-T2) / max(T1,T2)
|
||||
@printf "% 5i : %8.5f %8.5f %8.5f | %8.5f %8.5f | %8.5e\n" j X... T1 T2 rtol
|
||||
passed &= rtol < 1.0e-12
|
||||
end
|
||||
@test passed
|
||||
end
|
||||
|
||||
@@ -40,10 +40,29 @@ Fixed-fixed solution is ωᵢ = λᵢ²√(EI/ρA) , where λᵢ = cosh(λᵢℓ
|
||||
2: 7.853204624095838
|
||||
3: 10.995607838001671
|
||||
|
||||
Youngs modulus is tuned such that lowest eigenfrequency matches 1.0
|
||||
|
||||
5 lowest eigenfrequencies using Code Aster and Tet4 elements:
|
||||
numéro fréquence (HZ) norme d'erreur
|
||||
1 1.19789E+00 2.20137E-12
|
||||
2 1.20179E+00 1.99034E-12
|
||||
3 3.07391E+00 3.29226E-13
|
||||
4 3.08812E+00 2.91550E-13
|
||||
5 4.87370E+00 2.95986E-13
|
||||
|
||||
5 lowest eigenfrequencies using Code Aster and Tet10 elements:
|
||||
numéro fréquence (HZ) norme d'erreur
|
||||
1 9.65942E-01 1.54950E-11
|
||||
2 9.66160E-01 1.62712E-11
|
||||
3 2.52127E+00 2.06544E-12
|
||||
4 2.52187E+00 1.77970E-12
|
||||
5 3.48584E+00 9.96170E-13
|
||||
|
||||
|
||||
[1] De Silva, Clarence W. Vibration: fundamentals and practice. CRC press, 2006, p.355
|
||||
=#
|
||||
|
||||
@testset "long rod under point load" begin
|
||||
@testset "long rod natural frequencies" begin
|
||||
mesh_file = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(mesh_file, "CYLINDER_20_TET10")
|
||||
# for (id, coords) in mesh.nodes
|
||||
@@ -51,7 +70,8 @@ Fixed-fixed solution is ωᵢ = λᵢ²√(EI/ρA) , where λᵢ = cosh(λᵢℓ
|
||||
# end
|
||||
body = Problem(Elasticity, "rod", 3)
|
||||
body.elements = create_elements(mesh, "CYLINDER")
|
||||
E = 50475.44814745859
|
||||
#E = 50475.44814745859
|
||||
E = 50475.5
|
||||
rho = 1.0
|
||||
update!(body.elements, "youngs modulus", E)
|
||||
update!(body.elements, "poissons ratio", 0.3)
|
||||
@@ -121,13 +141,27 @@ Fixed-fixed solution is ωᵢ = λᵢ²√(EI/ρA) , where λᵢ = cosh(λᵢℓ
|
||||
info("freq_a = $freq_a")
|
||||
|
||||
solver = Solver(Modal, body, fixed1, fixed2)
|
||||
solver.properties.nev = 5
|
||||
solver()
|
||||
freqs = keys(body["displacement"])
|
||||
freqs_jf = sqrt(solver.properties.eigvals)/(2.0*pi)
|
||||
# with Tet4 elements
|
||||
#freqs_ca = [1.19789E+00, 1.20179E+00, 3.07391E+00, 3.08813E+00, 4.87370E+00]
|
||||
# with Tet10 elements
|
||||
freqs_ca = [9.65942E-01, 9.66160E-01, 2.52127E+00, 2.52187E+00, 3.48584E+00]
|
||||
|
||||
rtol1 = norm(freq_sa - freqs[2])/max(freq_sa, freqs[2])
|
||||
rtol2 = norm(freq_a - freqs[2])/max(freq_a, freqs[2])
|
||||
# looks that juliafem results are more close to 1.0, maybe different integration order
|
||||
rtol1 = norm(freq_sa - freqs_jf[1])/max(freq_sa, freqs_jf[1])
|
||||
rtol2 = norm(freq_a - freqs_jf[1])/max(freq_a, freqs_jf[1])
|
||||
info("rtol 1 = $rtol1, rtol 2 = $rtol2")
|
||||
@test rtol2 < 1.0e-2
|
||||
passed = true
|
||||
for (f1, f2) in zip(freqs_jf, freqs_ca)
|
||||
rtol = norm(f1-f2) / max(f1,f2)
|
||||
@printf "JF: %8.5e | CA: %8.5e | rtol: %8.5e\n" f1 f2 rtol
|
||||
passed &= (rtol < 3.0e-2)
|
||||
end
|
||||
@test rtol2 < 3.0e-2
|
||||
@test passed
|
||||
|
||||
#=
|
||||
result = XDMF()
|
||||
for (i, freq) in enumerate(freqs)
|
||||
@@ -138,5 +172,34 @@ Fixed-fixed solution is ωᵢ = λᵢ²√(EI/ρA) , where λᵢ = cosh(λᵢℓ
|
||||
end
|
||||
xdmf_save!(result, "/tmp/rod_nf.xmf")
|
||||
=#
|
||||
|
||||
end
|
||||
|
||||
@testset "eigenvalues of cube (tet4)" begin
|
||||
meshfile = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(meshfile, "CUBE_TET4")
|
||||
cube = Problem(mesh, Elasticity, "CUBE", 3)
|
||||
update!(cube.elements, "youngs modulus", 10000.0)
|
||||
update!(cube.elements, "poissons ratio", 0.3)
|
||||
update!(cube.elements, "density", 10.0)
|
||||
sym23 = create_elements(mesh, "FACE231")
|
||||
update!(sym23, "displacement 1", 0.0)
|
||||
sym13 = create_elements(mesh, "FACE131")
|
||||
update!(sym13, "displacement 2", 0.0)
|
||||
sym12 = create_elements(mesh, "FACE121")
|
||||
update!(sym12, "displacement 3", 0.0)
|
||||
bcs = Problem(Dirichlet, "bcs", 3, "displacement")
|
||||
bcs.elements = [sym23; sym13; sym12]
|
||||
solver = Solver(Modal)
|
||||
solver.properties.nev = 5
|
||||
push!(solver, cube, bcs)
|
||||
solver()
|
||||
freqs_jf = sqrt(solver.properties.eigvals)/(2.0*pi)
|
||||
freqs_ca = [3.73724E+00, 3.73724E+00, 4.93519E+00, 6.59406E+00, 7.65105E+00]
|
||||
for (f1, f2) in zip(freqs_jf, freqs_ca)
|
||||
rtol = norm(f1-f2) / max(f1,f2)
|
||||
@printf "JF: %8.5e | CA: %8.5e | rtol: %8.5e\n" f1 f2 rtol
|
||||
@test rtol < 1.0e-5
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# 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.Testing
|
||||
|
||||
@testset "eigenvalues of CYLINDER1" begin
|
||||
meshfile = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(meshfile, "CYLINDER_1_TET4")
|
||||
cylinder = Problem(mesh, Elasticity, "CYLINDER", 3)
|
||||
update!(cylinder.elements, "youngs modulus", 10000.0)
|
||||
update!(cylinder.elements, "poissons ratio", 0.3)
|
||||
update!(cylinder.elements, "density", 10.0)
|
||||
bc1 = create_elements(mesh, "FACE_YZ1")
|
||||
update!(bc1, "displacement 1", 0.0)
|
||||
update!(bc1, "displacement 2", 0.0)
|
||||
update!(bc1, "displacement 3", 0.0)
|
||||
bcs = Problem(Dirichlet, "bcs", 3, "displacement")
|
||||
bcs.elements = bc1
|
||||
solver = Solver(Modal)
|
||||
solver.properties.nev = 3
|
||||
push!(solver, cylinder, bcs)
|
||||
solver()
|
||||
freqs_jf = sqrt(solver.properties.eigvals)/(2.0*pi)
|
||||
freqs_ca = [4.84532E+00, 4.90698E+00, 8.33813E+00]
|
||||
passed = []
|
||||
for (f1, f2) in zip(freqs_jf, freqs_ca)
|
||||
rtol = norm(f1-f2) / max(f1,f2)
|
||||
@printf "JF: %8.5e | CA: %8.5e | rtol: %8.5e\n" f1 f2 rtol
|
||||
push!(passed, rtol < 1.0e-5)
|
||||
end
|
||||
@test reduce(&, passed)
|
||||
end
|
||||
|
||||
@testset "eigenvalues of CYLINDER20" begin
|
||||
meshfile = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(meshfile, "CYLINDER_20_TET4")
|
||||
cylinder = Problem(mesh, Elasticity, "CYLINDER", 3)
|
||||
#update!(cylinder.elements, "youngs modulus", 10.0e6)
|
||||
update!(cylinder.elements, "youngs modulus", 50475.5)
|
||||
update!(cylinder.elements, "poissons ratio", 0.3)
|
||||
#update!(cylinder.elements, "density", 10.0)
|
||||
update!(cylinder.elements, "density", 1.0)
|
||||
bc1 = create_elements(mesh, "FACE1", "FACE2")
|
||||
update!(bc1, "displacement 1", 0.0)
|
||||
update!(bc1, "displacement 2", 0.0)
|
||||
update!(bc1, "displacement 3", 0.0)
|
||||
bcs = Problem(Dirichlet, "bcs", 3, "displacement")
|
||||
bcs.elements = bc1
|
||||
solver = Solver(Modal)
|
||||
solver.properties.nev = 3
|
||||
push!(solver, cylinder, bcs)
|
||||
solver()
|
||||
freqs_jf = sqrt(solver.properties.eigvals)/(2.0*pi)
|
||||
#freqs_ca = [8.82848E-01, 8.85353E-01, 5.30286E+00] # only face1 fixed
|
||||
#freqs_ca = [5.33185E+00, 5.34920E+00, 1.36820E+01] # face1 and face2 fixed
|
||||
freqs_ca = [1.19789E+00, 1.20179E+00, 3.07391E+00]
|
||||
passed = []
|
||||
for (f1, f2) in zip(freqs_jf, freqs_ca)
|
||||
rtol = norm(f1-f2) / max(f1,f2)
|
||||
@printf "JF: %8.5e | CA: %8.5e | rtol: %8.5e\n" f1 f2 rtol
|
||||
push!(passed, rtol < 1.0e-5)
|
||||
end
|
||||
@test reduce(&, passed)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
# 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.Testing
|
||||
|
||||
#=
|
||||
test subjects:
|
||||
- modal analysis, with mesh tie contact
|
||||
|
||||
Fixed-fixed solution is ωᵢ = λᵢ²√(EI/ρA) , where λᵢ = cosh(λᵢℓ)cos(λᵢℓ)
|
||||
|
||||
1: 4.730040744862704
|
||||
2: 7.853204624095838
|
||||
3: 10.995607838001671
|
||||
|
||||
[1] De Silva, Clarence W. Vibration: fundamentals and practice. CRC press, 2006, p.355
|
||||
|
||||
Code Aster solution:
|
||||
--------------------
|
||||
numéro fréquence (HZ) norme d'erreur
|
||||
1 1.12946E+00 5.81018E-12
|
||||
2 1.13141E+00 6.33463E-12
|
||||
3 2.93779E+00 6.53408E-13
|
||||
4 2.94143E+00 5.43970E-13
|
||||
5 4.51684E+00 5.43252E-13
|
||||
=#
|
||||
|
||||
|
||||
comm_CA = """
|
||||
DEBUT(PAR_LOT="NON")
|
||||
|
||||
MAIL = LIRE_MAILLAGE(FORMAT="MED", NOM_MED="CYLINDER_20_SPLITTED")
|
||||
|
||||
MO = AFFE_MODELE(
|
||||
MAILLAGE=MAIL,
|
||||
AFFE=_F(TOUT="OUI",
|
||||
PHENOMENE="MECANIQUE", MODELISATION="3D"))
|
||||
|
||||
MAT = DEFI_MATERIAU(
|
||||
ELAS=_F(E=50475.45, NU=0.3, RHO=1.0))
|
||||
|
||||
CHMAT = AFFE_MATERIAU(
|
||||
MAILLAGE=MAIL,
|
||||
AFFE=_F(TOUT="OUI", MATER=MAT))
|
||||
|
||||
BC1 = AFFE_CHAR_MECA(
|
||||
MODELE=MO,
|
||||
DDL_IMPO=(
|
||||
_F(GROUP_MA=("CYLINDER_20_1_FACE1"), DX=0, DY=0, DZ=0)))
|
||||
|
||||
BC2 = AFFE_CHAR_MECA(
|
||||
MODELE=MO,
|
||||
DDL_IMPO=(
|
||||
_F(GROUP_MA=("CYLINDER_20_2_FACE2"), DX=0, DY=0, DZ=0)))
|
||||
|
||||
# ESCL = SLAVE
|
||||
# MAIT = MASTER
|
||||
BC3 = AFFE_CHAR_MECA(
|
||||
MODELE=MO,
|
||||
LIAISON_MAIL=_F(
|
||||
GROUP_MA_ESCL="CYLINDER_20_1_FACE2",
|
||||
GROUP_MA_MAIT="CYLINDER_20_2"))
|
||||
|
||||
# assemble material stiffness matrix
|
||||
|
||||
RIGEL = CALC_MATR_ELEM(
|
||||
MODELE=MO,
|
||||
OPTION="RIGI_MECA",
|
||||
CHAM_MATER=CHMAT,
|
||||
CHARGE=(BC1, BC2, BC3))
|
||||
|
||||
NUMEDDL = NUME_DDL(
|
||||
MATR_RIGI=RIGEL)
|
||||
|
||||
RIGAS = ASSE_MATRICE(
|
||||
MATR_ELEM=RIGEL,
|
||||
NUME_DDL=NUMEDDL)
|
||||
|
||||
# assemble mass matrix
|
||||
|
||||
MASSEL = CALC_MATR_ELEM(
|
||||
MODELE=MO,
|
||||
OPTION="MASS_MECA",
|
||||
CHAM_MATER=CHMAT,
|
||||
CHARGE=(BC1, BC2, BC3))
|
||||
|
||||
MASSAS = ASSE_MATRICE(
|
||||
MATR_ELEM=MASSEL,
|
||||
NUME_DDL=NUMEDDL)
|
||||
|
||||
# modal analysis, without geometric stiffness
|
||||
|
||||
BRESU = CALC_MODES(
|
||||
MATR_RIGI=RIGAS,
|
||||
MATR_MASS=MASSAS,
|
||||
OPTION="BANDE",
|
||||
CALC_FREQ=_F(
|
||||
FREQ=(0.0, 5.0)))
|
||||
|
||||
# modal analysis, with geometric stiffness
|
||||
|
||||
BRESU = NORM_MODE(
|
||||
reuse=BRESU,
|
||||
MODE=BRESU,
|
||||
NORME="TRAN")
|
||||
|
||||
IMPR_RESU(
|
||||
MODELE=MO,
|
||||
FORMAT="RESULTAT",
|
||||
RESU=_F(RESULTAT=BRESU))
|
||||
|
||||
IMPR_RESU(
|
||||
FORMAT="MED",
|
||||
UNITE=80,
|
||||
RESU=_F(RESULTAT=BRESU))
|
||||
|
||||
FIN()
|
||||
"""
|
||||
|
||||
@testset "splitted rod with tie contact" begin
|
||||
# CYLINDER_20_1_FACE1 -- CYLINDER_20_1_FACE2 -- CYLINDER_20_2_FACE_1 -- CYLINDER_20_2_FACE_2
|
||||
mesh_file = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(mesh_file, "CYLINDER_20_SPLITTED")
|
||||
body1 = Problem(mesh, Elasticity, "CYLINDER_20_1", 3)
|
||||
body2 = Problem(mesh, Elasticity, "CYLINDER_20_2", 3)
|
||||
for body in [body1, body2]
|
||||
update!(body.elements, "youngs modulus", 54475.45)
|
||||
update!(body.elements, "poissons ratio", 0.3)
|
||||
update!(body.elements, "density", 1.0)
|
||||
end
|
||||
bc1 = Problem(mesh, Dirichlet, "CYLINDER_20_1_FACE1", 3, "displacement")
|
||||
bc2 = Problem(mesh, Dirichlet, "CYLINDER_20_2_FACE2", 3, "displacement")
|
||||
for bc in [bc1, bc2]
|
||||
update!(bc.elements, "displacement 1", 0.0)
|
||||
update!(bc.elements, "displacement 2", 0.0)
|
||||
update!(bc.elements, "displacement 3", 0.0)
|
||||
end
|
||||
interface = Problem(Mortar, "interface between bodies", 3, "displacement")
|
||||
slave = create_elements(mesh, "CYLINDER_20_1_FACE2")
|
||||
master = create_elements(mesh, "CYLINDER_20_2_FACE1")
|
||||
update!(slave, "master elements", master)
|
||||
interface.elements = [slave; master]
|
||||
|
||||
solver = Solver(Modal, body1, body2, bc1, bc2, interface)
|
||||
solver.properties.nev = 5
|
||||
solver.properties.which = :SM
|
||||
solver()
|
||||
freqs_jf = sqrt(solver.properties.eigvals)/(2*pi)
|
||||
|
||||
freqs_ca = [1.12946E+00, 1.13141E+00, 2.93779E+00, 2.94143E+00, 4.51684E+00]
|
||||
freq_jf = freqs_jf[1]
|
||||
freq_ca = freqs_ca[1]
|
||||
rtol = norm(freq_jf - freq_ca)/max(freq_jf, freq_ca)
|
||||
info("rtol = $rtol")
|
||||
for (i, freq) in enumerate(freqs_jf)
|
||||
@printf "mode %i | freq JuliaFEM %8.3f | freq Code Aster %8.3f\n" i freqs_jf[i] freqs_ca[i]
|
||||
end
|
||||
if rtol > 1.0e-3
|
||||
outfile = tempname() * ".xmf"
|
||||
info("Something went wrong, results are saved to $outfile")
|
||||
result = XDMF()
|
||||
elems = [body1.elements; body2.elements]
|
||||
for (i, freq) in enumerate(freqs_jf)
|
||||
xdmf_new_result!(result, elems, freq)
|
||||
xdmf_save_field!(result, elems, freq, "displacement"; field_type="Vector")
|
||||
end
|
||||
xdmf_save!(result, outfile)
|
||||
end
|
||||
@test rtol < 0.05
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# 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.Testing
|
||||
|
||||
#=
|
||||
Two rings, RING1 is inner, RING2 is outer. Inner diameter is from 0.8 .. 0.9 and
|
||||
outer ring is 0.9 .. 1.0. Contact surface pair is RING1_OUTER <- RING2_INNER.
|
||||
Put constant temperature 1.0 for inner surface of inner ring and 2.0 for outer
|
||||
surface of outer ring. We should expect constant temperature in contact surface.
|
||||
This is conforming mesh so result should match to the conforming situation.
|
||||
=#
|
||||
@testset "test that curved interface transfers constant field without error, two rings problem" begin
|
||||
meshfile = Pkg.dir("JuliaFEM") * "/test/testdata/primitives.med"
|
||||
mesh = aster_read_mesh(meshfile, "RINGS")
|
||||
|
||||
ring1 = Problem(Heat, "RING1", 1)
|
||||
ring1.elements = create_elements(mesh, "RING1")
|
||||
update!(ring1.elements, "temperature thermal conductivity", 1.0)
|
||||
|
||||
ring2 = Problem(Heat, "RING2", 1)
|
||||
ring2.elements = create_elements(mesh, "RING2")
|
||||
update!(ring2.elements, "temperature thermal conductivity", 1.0)
|
||||
|
||||
bc_inner = Problem(Dirichlet, "INNER SURFACE", 1, "temperature")
|
||||
bc_inner.elements = create_elements(mesh, "RING1_INNER")
|
||||
update!(bc_inner, "temperature 1", 1.0)
|
||||
|
||||
bc_outer = Problem(Dirichlet, "OUTER SURFACE", 1, "temperature")
|
||||
bc_outer.elements = create_elements(mesh, "RING2_OUTER")
|
||||
update!(bc_outer, "temperature 1", 2.0)
|
||||
|
||||
interface = Problem(Mortar, "interface between rings", 1, "temperature")
|
||||
interface_slave = create_elements(mesh, "RING1_OUTER")
|
||||
interface_master = create_elements(mesh, "RING2_INNER")
|
||||
interface.elements = [interface_slave; interface_master]
|
||||
update!(interface_slave, "master elements", interface_master)
|
||||
|
||||
solver = LinearSolver(ring1, ring2, bc_inner, bc_outer, interface)
|
||||
solver()
|
||||
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/rings.rmed"
|
||||
results = RMEDFile(fn)
|
||||
nodes = aster_read_nodes(results)
|
||||
temp_ca = aster_read_data(results, "TEMP")
|
||||
|
||||
passed = true
|
||||
for j in sort(collect(keys(nodes)))
|
||||
X = nodes[j]
|
||||
T1 = solver("temperature", X, 0.0)
|
||||
T2 = temp_ca[j]
|
||||
rtol = norm(T1-T2) / max(T1,T2)
|
||||
@printf "% 5i : %8.5f %8.5f %8.5f | %8.5f %8.5f | %8.5f\n" j X... T1 T2 rtol
|
||||
passed = passed && (rtol < 1.0e-12)
|
||||
end
|
||||
@test passed
|
||||
end
|
||||
|
||||
@@ -147,3 +147,12 @@ end
|
||||
# @test isapprox(calculate_volume("PYRAMID_PYRAMID13_1", :Pyramid13, ?))
|
||||
end
|
||||
|
||||
@testset "get nodal field from aster file" begin
|
||||
fn = Pkg.dir("JuliaFEM") * "/test/testdata/rings.rmed"
|
||||
medfile = JuliaFEM.Preprocess.RMEDFile(fn)
|
||||
temp = JuliaFEM.Preprocess.aster_read_data(medfile, "TEMP")
|
||||
info("temp = $temp")
|
||||
# more like functional testing, results are what they are,
|
||||
# we're happy to just have some results
|
||||
@test true
|
||||
end
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Testing
|
||||
using JuliaFEM.Preprocess
|
||||
|
||||
@testset "test projection" begin
|
||||
C = [
|
||||
@@ -28,5 +29,66 @@ using JuliaFEM.Testing
|
||||
h_expected = [1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
||||
@test isapprox(full(P), P_expected)
|
||||
@test isapprox(full(h), h_expected)
|
||||
nz = [5, 6, 7, 8]
|
||||
info("is P'P positive definite? ", isposdef(P[:,nz]'P[:,nz]))
|
||||
@test isposdef(P[:,nz]'P[:,nz])
|
||||
end
|
||||
|
||||
@testset "test creating projection matrix from invertible problem" begin
|
||||
# simple 3 element poisson problem
|
||||
k = [1.0 -1.0; -1.0 1.0]
|
||||
K = zeros(4, 4)
|
||||
K[1:2,1:2] += k
|
||||
K[2:3,2:3] += k
|
||||
K[3:4,3:4] += k
|
||||
# first dof homogeneous bc, last dof u₄ = 1
|
||||
C = zeros(4, 4)
|
||||
C[1,1] = 1.0
|
||||
C[4,4] = 1.0
|
||||
g = zeros(4)
|
||||
g[1] = 0.0
|
||||
g[4] = 1.0
|
||||
P, h = create_projection(sparse(C), g, Val{:invertible})
|
||||
info("P = ")
|
||||
dump(full(P))
|
||||
P_expected = zeros(4, 4)
|
||||
P_expected[2,2] = P_expected[3,3] = 1.0
|
||||
@test isapprox(full(P), P_expected)
|
||||
#h_expected = [0.5, 1.0]
|
||||
#@test isapprox(h, h_expected)
|
||||
end
|
||||
|
||||
@testset "projection between surfaces" begin
|
||||
# FIXME: creating mortar projection takes very long time.
|
||||
meshfile = Pkg.dir("JuliaFEM") * "/test/testdata/joint.med"
|
||||
isfile(meshfile) || return
|
||||
mesh = aster_read_mesh(meshfile, "JOINT")
|
||||
|
||||
# top
|
||||
bc1 = Problem(Dirichlet, "fixed1", 3, "displacement")
|
||||
bc1.elements = create_elements(mesh, "FIXED1")
|
||||
update!(bc1.elements, "displacement 1", 0.0)
|
||||
update!(bc1.elements, "displacement 2", 0.0)
|
||||
update!(bc1.elements, "displacement 3", 0.0)
|
||||
|
||||
# bottom
|
||||
bc2 = Problem(Dirichlet, "fixed2", 3, "displacement")
|
||||
bc2.elements = create_elements(mesh, "FIXED2")
|
||||
update!(bc2.elements, "displacement 1", 0.0)
|
||||
update!(bc2.elements, "displacement 2", 0.0)
|
||||
update!(bc2.elements, "displacement 3", 0.0)
|
||||
|
||||
# joint
|
||||
contact = Problem(Mortar, "joint", 3, "displacement")
|
||||
master_elements = create_elements(mesh, "BODY1_TO_BODY2")
|
||||
slave_elements = create_elements(mesh, "BODY2_TO_BODY1")
|
||||
update!(slave_elements, "master elements", master_elements)
|
||||
contact.elements = [master_elements; slave_elements]
|
||||
|
||||
solver = Solver(Modal)
|
||||
push!(solver, bc1, bc2, contact)
|
||||
assemble!(solver)
|
||||
Kb, C1, C2, D, fb, g = get_boundary_assembly(solver)
|
||||
P, h = create_projection(C1, g)
|
||||
end
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user