mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-25 19:36:58 +00:00
postprocessing utility
This commit is contained in:
+4
-2
@@ -65,7 +65,8 @@ export AbstractSolver, Solver, Nonlinear, NonlinearSolver, Linear, LinearSolver,
|
||||
get_unknown_field_name, get_formulation_type, get_problems,
|
||||
get_field_problems, get_boundary_problems,
|
||||
get_field_assembly, get_boundary_assembly,
|
||||
initialize!, create_projection, eliminate_interior_dofs
|
||||
initialize!, create_projection, eliminate_interior_dofs,
|
||||
is_field_problem, is_boundary_problem
|
||||
include("solvers_modal.jl")
|
||||
export Modal
|
||||
|
||||
@@ -135,7 +136,8 @@ export calc_nodal_values!,
|
||||
copy_field!,
|
||||
calculate_area,
|
||||
calculate_center_of_mass,
|
||||
calculate_second_moment_of_mass
|
||||
calculate_second_moment_of_mass,
|
||||
extract
|
||||
include("postprocess_xdmf.jl")
|
||||
export XDMF, xdmf_new_result!, xdmf_save_field!, xdmf_save!
|
||||
export DataFrame
|
||||
|
||||
+62
-18
@@ -6,7 +6,6 @@ importall Base
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Postprocess
|
||||
using LightXML
|
||||
|
||||
### Model definitions for ABAQUS data model
|
||||
|
||||
@@ -265,8 +264,9 @@ end
|
||||
typealias BOUNDARY_CONDITIONS Union{BOUNDARY, CLOAD, DLOAD, DSLOAD}
|
||||
|
||||
@register_abaqus_keyword("NODE PRINT")
|
||||
@register_abaqus_keyword("EL PRINT")
|
||||
@register_abaqus_keyword("SECTION PRINT")
|
||||
typealias OUTPUT_REQUESTS Union{NODE_PRINT, SECTION_PRINT}
|
||||
typealias OUTPUT_REQUESTS Union{NODE_PRINT, EL_PRINT, SECTION_PRINT}
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -391,7 +391,7 @@ end
|
||||
""" Dirichlet boundary condition. """
|
||||
function create_boundary_problem(model::Model, bc::AbstractBoundaryCondition, ::BOUNDARY; verbose=true)
|
||||
dim = determine_problem_dimension(model)
|
||||
problem = Problem(Dirichlet, "Dirichlet bc *BOUNDARY", dim, "displacement")
|
||||
problem = Problem(Dirichlet, "Dirichlet boundary *BOUNDARY", dim, "displacement")
|
||||
for row in bc.data
|
||||
|
||||
if isa(row[1], AbstractString) # node set given
|
||||
@@ -462,7 +462,7 @@ function create_boundary_problem(model::Model, bc::AbstractBoundaryCondition, ::
|
||||
|
||||
child_element = Element(JuliaFEM.(child_element_type), child_element_connectivity)
|
||||
update!(child_element, "geometry", model.mesh.nodes)
|
||||
update!(child_element, "surface pressure", pressure)
|
||||
update!(child_element, "surface pressure", -pressure)
|
||||
push!(problem.elements, child_element)
|
||||
end
|
||||
return problem
|
||||
@@ -472,13 +472,18 @@ end
|
||||
function create_boundary_problem(model::Model, bc::AbstractBoundaryCondition, ::CLOAD; verbose=false)
|
||||
dim = determine_problem_dimension(model)
|
||||
problem = Problem(Elasticity, "Concentrated load *CLOAD", dim)
|
||||
for row in bc.data
|
||||
node, dof, load = row
|
||||
nodes = sort(unique([row[1] for row in bc.data]))
|
||||
elements = Dict()
|
||||
for node in nodes
|
||||
element = Element(Poi1, [node])
|
||||
update!(element, "geometry", model.mesh.nodes)
|
||||
update!(element, "displacement traction force $dof", load)
|
||||
push!(problem.elements, element)
|
||||
elements[node] = element
|
||||
end
|
||||
for row in bc.data
|
||||
node, dof, load = row
|
||||
update!(elements[node], "concentrated force $dof", load)
|
||||
end
|
||||
problem.elements = collect(values(elements))
|
||||
return problem
|
||||
end
|
||||
|
||||
@@ -531,8 +536,6 @@ function get_child_element(element_type::Symbol, element_side::Symbol,
|
||||
process_output_request(model, solver, output_request, kind, target)
|
||||
end
|
||||
|
||||
using DataFrames
|
||||
|
||||
function process_output_request(model::Model, solver::Solver, output_request::AbstractOutputRequest,
|
||||
::Type{Val{:NODE}}, ::Type{Val{:PRINT}})
|
||||
data = output_request.data
|
||||
@@ -546,7 +549,7 @@ function process_output_request(model::Model, solver::Solver, output_request::Ab
|
||||
for row in data
|
||||
info(repeat("-", 80))
|
||||
codes = join(row, ", ")
|
||||
info("*NODE OUTPUT request, with fields $codes")
|
||||
info("*NODE PRINT request, with fields $codes")
|
||||
if length(options) != 0
|
||||
info("Additional options: $options")
|
||||
end
|
||||
@@ -554,15 +557,56 @@ function process_output_request(model::Model, solver::Solver, output_request::Ab
|
||||
tables = Any[]
|
||||
for code in row
|
||||
haskey(code_mapping, code) || continue
|
||||
for problem in model.problems
|
||||
field_name = code_mapping[code]
|
||||
abbr = get(abbr_mapping, code, code)
|
||||
table = problem(DataFrame, field_name, abbr, solver.time)
|
||||
push!(tables, table)
|
||||
end
|
||||
field_name = code_mapping[code]
|
||||
abbr = get(abbr_mapping, code, code)
|
||||
table = solver(DataFrame, field_name, abbr, solver.time)
|
||||
push!(tables, table)
|
||||
end
|
||||
length(tables) != 0 || continue
|
||||
results = join(tables..., on=:id, kind=:outer)
|
||||
results = join(tables..., on=:NODE, kind=:outer)
|
||||
sort!(results, cols=[:NODE])
|
||||
println()
|
||||
println(results)
|
||||
println()
|
||||
end
|
||||
end
|
||||
|
||||
function process_output_request(model::Model, solver::Solver, output_request::AbstractOutputRequest,
|
||||
::Type{Val{:EL}}, ::Type{Val{:PRINT}})
|
||||
data = output_request.data
|
||||
options = output_request.options
|
||||
code_mapping = Dict(
|
||||
:COORD => "geometry",
|
||||
:S => "stress",
|
||||
:E => "strain")
|
||||
abbr_mapping = Dict(:COORD => :COOR)
|
||||
for row in data
|
||||
info(repeat("-", 80))
|
||||
codes = join(row, ", ")
|
||||
info("*EL PRINT request, with fields $codes")
|
||||
if length(options) != 0
|
||||
info("Additional options: $options")
|
||||
end
|
||||
info(repeat("-", 80))
|
||||
tables = Any[]
|
||||
for code in row
|
||||
haskey(code_mapping, code) || continue
|
||||
field_name = code_mapping[code]
|
||||
abbr = get(abbr_mapping, code, code)
|
||||
table = solver(DataFrame, solver.time, Val{code})
|
||||
push!(tables, table)
|
||||
end
|
||||
length(tables) != 0 || continue
|
||||
results = first(tables)
|
||||
if length(tables) > 1
|
||||
for i=2:length(tables)
|
||||
results = join(results, tables[i], on=:ELEMENT, kind=:outer)
|
||||
end
|
||||
end
|
||||
sort!(results, cols=[:ELEMENT, :IP])
|
||||
# filter out elements with id -1, they are automatically created boundary elements
|
||||
fel = find(results[:ELEMENT] .!= Symbol("E-1"))
|
||||
results = results[fel, :]
|
||||
println()
|
||||
println(results)
|
||||
println()
|
||||
|
||||
+11
-1
@@ -168,11 +168,13 @@ function update!(element::Element, field_name::AbstractString, datas::Union{Real
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name, datas::Pair...)
|
||||
#=
|
||||
function update!(element::Element, field_name, data::Pair...)
|
||||
for data in datas
|
||||
update!(element, field_name, data)
|
||||
end
|
||||
end
|
||||
=#
|
||||
|
||||
function update!(element::Element, field_name, data::Pair{Float64, Vector{Any}})
|
||||
if haskey(element, field_name)
|
||||
@@ -190,6 +192,14 @@ function update!(element::Element, field_name, data::Pair{Float64, Vector{Int64}
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name, data::Pair{Float64, Vector{Float64}})
|
||||
if haskey(element, field_name)
|
||||
update!(element[field_name], data)
|
||||
else
|
||||
element[field_name] = data
|
||||
end
|
||||
end
|
||||
|
||||
function update!(element::Element, field_name, data::Pair{Float64, Vector{Vector{Float64}}})
|
||||
if haskey(element, field_name)
|
||||
update!(element[field_name], data)
|
||||
|
||||
@@ -22,6 +22,10 @@ function get_basis(element::Element{Poi1}, ip, time)
|
||||
return [1]
|
||||
end
|
||||
|
||||
function get_dbasis(element::Element{Poi1}, ip, time)
|
||||
return [0]
|
||||
end
|
||||
|
||||
function call(element::Element{Poi1}, ip, time::Float64, ::Type{Val{:detJ}})
|
||||
return 1.0
|
||||
end
|
||||
|
||||
+106
-21
@@ -7,6 +7,7 @@ using JuliaFEM
|
||||
using DataFrames
|
||||
using HDF5
|
||||
using LightXML
|
||||
using StringUtils
|
||||
|
||||
import HDF5: h5read, h5write
|
||||
|
||||
@@ -47,21 +48,14 @@ function convert(::Type{DataFrame}, dfs::AbstractString)
|
||||
return readtable(fn)
|
||||
end
|
||||
|
||||
function getindex(df::DataFrame, ids::Vector{Symbol}, cols::Vector{Symbol})
|
||||
rows = Int64[find(df[:id] .== id)[1] for id in ids]
|
||||
return df[rows, cols]
|
||||
end
|
||||
|
||||
function getindex(df::DataFrame, id::Symbol, col::Symbol)
|
||||
return getindex(df, [id], [col])
|
||||
end
|
||||
|
||||
function getindex(df::DataFrame, id::Symbol, cols::Vector{Symbol})
|
||||
return getindex(df, [id], cols)
|
||||
end
|
||||
|
||||
function getindex(df::DataFrame, ids::Vector{Symbol}, col::Symbol)
|
||||
return getindex(df, ids, [col])
|
||||
function extract(df::DataFrame, args...; kwargs...)
|
||||
result = copy(df)
|
||||
for (k,v) in kwargs
|
||||
rows = find(df[k] .== v)
|
||||
result = result[rows, :]
|
||||
end
|
||||
foo = Symbol[si for si in args]
|
||||
return result[foo]
|
||||
end
|
||||
|
||||
function vec(df::DataFrame)
|
||||
@@ -72,6 +66,12 @@ function isapprox(d1::DataFrame, d2::Vector)
|
||||
return isapprox(vec(d1), d2)
|
||||
end
|
||||
|
||||
""" A more appropriate representation for floats in results. """
|
||||
function DataFrames.ourshowcompact(io::IO, x::Float64)
|
||||
print(io, u"\% 0.4E(x)")
|
||||
return
|
||||
end
|
||||
|
||||
"""
|
||||
Calculate field values to nodal points from Gauss points using least-squares fitting.
|
||||
"""
|
||||
@@ -201,9 +201,13 @@ end
|
||||
function call(problem::Problem, field_name::AbstractString, time::Float64=0.0)
|
||||
f = Dict()
|
||||
for element in get_elements(problem)
|
||||
haskey(element, field_name) || continue
|
||||
for (c, v) in zip(get_connectivity(element), element(field_name, time))
|
||||
if haskey(f, c)
|
||||
@assert isapprox(f[c], v)
|
||||
if !isapprox(f[c], v)
|
||||
info("several values for single node when returning field $field_name")
|
||||
info("already have: $(f[c]), and trying to set $v")
|
||||
end
|
||||
end
|
||||
f[c] = v
|
||||
end
|
||||
@@ -211,11 +215,10 @@ function call(problem::Problem, field_name::AbstractString, time::Float64=0.0)
|
||||
return f
|
||||
end
|
||||
|
||||
function call(problem::Problem, ::Type{DataFrame}, field_name::AbstractString,
|
||||
abbreviation::Symbol, time::Float64=0.0)
|
||||
u = problem(field_name, time)
|
||||
function to_dataframe(u::Dict, abbreviation::Symbol)
|
||||
length(u) != 0 || return DataFrame()
|
||||
node_ids = collect(keys(u))
|
||||
column_names = [:id]
|
||||
column_names = [:NODE]
|
||||
n = length(u[first(node_ids)])
|
||||
index = [Symbol("N$id") for id in node_ids]
|
||||
result = Any[index]
|
||||
@@ -224,10 +227,92 @@ function call(problem::Problem, ::Type{DataFrame}, field_name::AbstractString,
|
||||
push!(column_names, Symbol("$abbreviation$dof"))
|
||||
end
|
||||
df = DataFrame(result, column_names)
|
||||
sort!(df, cols=[:id])
|
||||
sort!(df, cols=[:NODE])
|
||||
return df
|
||||
end
|
||||
|
||||
function call(problem::Problem, ::Type{DataFrame}, field_name::AbstractString,
|
||||
abbreviation::Symbol, time::Float64=0.0)
|
||||
u = problem(field_name, time)
|
||||
return to_dataframe(u, abbreviation)
|
||||
end
|
||||
|
||||
function call(solver::Solver, ::Type{DataFrame}, field_name::AbstractString,
|
||||
abbreviation::Symbol, time::Float64=0.0)
|
||||
u = Dict()
|
||||
for problem in get_problems(solver)
|
||||
u = merge(u, problem(field_name, time))
|
||||
end
|
||||
return to_dataframe(u, abbreviation)
|
||||
end
|
||||
|
||||
function get_components(n, m)
|
||||
if n == m
|
||||
if n == 1
|
||||
return Vector{Int}[[1,1]]
|
||||
end
|
||||
if n == 2
|
||||
return Vector{Int}[[1,1], [2,2], [1,2]]
|
||||
elseif n == 3
|
||||
return Vector{Int}[[1,1], [2,2], [3,3], [1,2], [1,3], [2,3]]
|
||||
else
|
||||
error("get_components, n=$n, m=$m!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
""" Return T in integration points. """
|
||||
function call{T}(problem::Problem, ::Type{DataFrame}, element::Element, time::Float64,
|
||||
::Type{Val{T}})
|
||||
column_names = [:ELEMENT, :IP]
|
||||
ips = get_integration_points(element)
|
||||
field = Any[problem(element, ip, time, Val{T}) for ip in ips]
|
||||
# FIXME, handle better ..?
|
||||
first(field) == nothing && return DataFrame()
|
||||
m = length(field)
|
||||
n = length(first(field))
|
||||
result = Any[]
|
||||
push!(result, [Symbol("E$(element.id)") for i=1:m])
|
||||
push!(result, [Symbol("P$i") for i=1:m])
|
||||
is_tensor_field = isa(first(field), Matrix)
|
||||
if is_tensor_field
|
||||
n, m = size(first(field))
|
||||
components = get_components(n, m)
|
||||
for (j, k) in components
|
||||
push!(column_names, Symbol("$T$j$k"))
|
||||
push!(result, [S[j,k] for S in field])
|
||||
end
|
||||
else
|
||||
components = collect(1:n)
|
||||
for j in components
|
||||
push!(column_names, Symbol("$T$j"))
|
||||
push!(result, [S[j] for S in field])
|
||||
end
|
||||
end
|
||||
df = DataFrame(result, column_names)
|
||||
sort!(df, cols=[:IP])
|
||||
end
|
||||
|
||||
function call{T}(problem::Problem, ::Type{DataFrame}, time::Float64, ::Type{Val{T}})
|
||||
tables = [problem(DataFrame, element, time, Val{T}) for element in get_elements(problem)]
|
||||
results = [tables...;]
|
||||
return results
|
||||
end
|
||||
|
||||
function call{T}(solver::Solver, ::Type{DataFrame}, time::Float64, ::Type{Val{T}})
|
||||
problems = get_problems(solver)
|
||||
tables = Any[]
|
||||
for problem in get_problems(solver)
|
||||
try
|
||||
push!(tables, problem(DataFrame, time, Val{T}))
|
||||
catch
|
||||
warn("Unable to obtain results $T for problem $(problem.name)")
|
||||
end
|
||||
end
|
||||
results = [tables...;]
|
||||
return results
|
||||
end
|
||||
|
||||
""" Interpolate field from a set of elements. """
|
||||
function call(problem::Problem, field_name::AbstractString, X::Vector, time::Float64=0.0; fillna=NaN)
|
||||
for element in get_elements(problem)
|
||||
|
||||
+11
-4
@@ -91,13 +91,21 @@ function filter_by_element_set(mesh::Mesh, set_name)
|
||||
filter_by_element_id(mesh::Mesh, collect(mesh.element_sets[set_name]))
|
||||
end
|
||||
|
||||
function create_element(mesh::Mesh, id::Int)
|
||||
connectivity = mesh.elements[id]
|
||||
element_type = JuliaFEM.(mesh.element_types[id])
|
||||
element = Element(element_type, connectivity)
|
||||
update!(element, "geometry", mesh.nodes)
|
||||
element.id = id
|
||||
return element
|
||||
end
|
||||
|
||||
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)
|
||||
elements = [create_element(mesh, id) for id in element_ids]
|
||||
return elements
|
||||
end
|
||||
|
||||
@@ -115,8 +123,7 @@ function create_elements(mesh::Mesh, element_sets::Symbol...; element_type=nothi
|
||||
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)
|
||||
elements = [create_element(mesh, id) for id in element_ids]
|
||||
return elements
|
||||
end
|
||||
|
||||
|
||||
+71
-69
@@ -141,63 +141,53 @@ function get_assembly(problem)
|
||||
return problem.assembly
|
||||
end
|
||||
|
||||
""" Initialize unknown field ready for nonlinear iterations, i.e.,
|
||||
take last known value and set it as a initial quess for next
|
||||
time increment.
|
||||
"""
|
||||
function initialize!(problem::Problem, time=0.0)
|
||||
|
||||
""" Initialize element ready for calculation. """
|
||||
function initialize!(problem::Problem, element::Element, time::Float64)
|
||||
field_name = get_unknown_field_name(problem)
|
||||
field_dim = get_unknown_field_dimension(problem)
|
||||
for element in get_elements(problem)
|
||||
gdofs = get_gdofs(problem, element)
|
||||
if haskey(element, field_name)
|
||||
# if field is found, copy last known solution to new time as initial guess
|
||||
field = last(element[field_name])
|
||||
if !isa(field, TimeVariantField)
|
||||
info("Unable to initialize field $field_name for problem, is not time variant?")
|
||||
continue
|
||||
end
|
||||
nnodes = length(element)
|
||||
|
||||
if !isapprox(field.time, time)
|
||||
last_data = copy(last(element[field_name]).data)
|
||||
push!(element[field_name], time => last_data)
|
||||
end
|
||||
else # if field not found at all, initialize new zero field.
|
||||
data = Vector{Float64}[zeros(field_dim) for i in 1:length(element)]
|
||||
element[field_name] = (time => data)
|
||||
# initialize primary field
|
||||
if !haskey(element, field_name)
|
||||
if field_dim == 1
|
||||
update!(element, field_name, time => zeros(nnodes))
|
||||
else
|
||||
update!(element, field_name, time => [zeros(field_dim) for i=1:nnodes])
|
||||
end
|
||||
end
|
||||
# if this is boundary problem and not dirichlet problem, initialize field
|
||||
# for primary variable too
|
||||
|
||||
# if boundary problem, initialize field for main problem too
|
||||
is_boundary_problem(problem) || return
|
||||
#is_dirichlet_problem(problem) && return
|
||||
field_name = get_parent_field_name(problem)
|
||||
for element in get_elements(problem)
|
||||
gdofs = get_gdofs(problem, element)
|
||||
if haskey(element, field_name)
|
||||
# if field is found, copy last known solution to new time as initial guess
|
||||
if !isapprox(last(element[field_name]).time, time)
|
||||
last_data = copy(last(element[field_name]).data)
|
||||
push!(element[field_name], time => last_data)
|
||||
end
|
||||
else # if field not found at all, initialize new zero field.
|
||||
data = Vector{Float64}[zeros(field_dim) for i in 1:length(element)]
|
||||
element[field_name] = (time => data)
|
||||
if !haskey(element, field_name)
|
||||
if field_dim == 1
|
||||
update!(element, field_name, time => zeros(nnodes))
|
||||
else
|
||||
update!(element, field_name, time => [zeros(field_dim) for i=1:nnodes])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
""" Update problem solution vector for assembly. """
|
||||
function update_assembly!(problem, u, la; verbose=false)
|
||||
function initialize!(problem::Problem, time::Float64=0.0)
|
||||
for element in get_elements(problem)
|
||||
initialize!(problem, element, time)
|
||||
end
|
||||
end
|
||||
|
||||
assembly = get_assembly(problem)
|
||||
""" Update problem solution vector for assembly. """
|
||||
function update!(problem::Problem, assembly::Assembly, u::Vector, la::Vector; verbose=false)
|
||||
|
||||
# resize & fill with zeros vectors if length mismatch with current solution
|
||||
|
||||
if length(u) != length(assembly.u)
|
||||
info("resizing solution vector u")
|
||||
resize!(assembly.u, length(u))
|
||||
fill!(assembly.u, 0.0)
|
||||
end
|
||||
|
||||
if length(la) != length(assembly.la)
|
||||
info("resizing lagrange multipliers vector u")
|
||||
resize!(assembly.la, length(la))
|
||||
fill!(assembly.la, 0.0)
|
||||
end
|
||||
@@ -228,47 +218,54 @@ function update_assembly!(problem, u, la; verbose=false)
|
||||
# calculate change of norm
|
||||
assembly.u_norm_change = norm(assembly.u - assembly.u_prev)
|
||||
assembly.la_norm_change = norm(assembly.la - assembly.la_prev)
|
||||
#return assembly.u_norm_change, assembly.la_norm_change
|
||||
return assembly.u, assembly.la
|
||||
end
|
||||
|
||||
""" Update solutions to elements.
|
||||
""" Return global solution (u, la) for problem.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This assumes that element is properly initialized so that last known field data
|
||||
is from current time. For boundary problems solution is updated from lambda vector
|
||||
and for field problems from actual solution vector.
|
||||
If length of solution vector != number of nodes, i.e. field dimension is
|
||||
something other than 1, reshape vectors so it's length matches to the
|
||||
number of nodes so that one can easily get nodal results.
|
||||
"""
|
||||
function update_elements!{P<:FieldProblem}(problem::Problem{P}, u, la)
|
||||
field_name = get_unknown_field_name(problem)
|
||||
function get_global_solution(problem::Problem, assembly::Assembly)
|
||||
u = assembly.u
|
||||
la = assembly.la
|
||||
field_dim = get_unknown_field_dimension(problem)
|
||||
nnodes = round(Int, length(u)/field_dim)
|
||||
solution = reshape(u, field_dim, nnodes)
|
||||
for element in get_elements(problem)
|
||||
connectivity = get_connectivity(element) # node ids
|
||||
local_sol = Vector{Float64}[solution[:, node_id] for node_id in connectivity]
|
||||
last(element[field_name]).data = local_sol
|
||||
if field_dim == 1
|
||||
return u, la
|
||||
else
|
||||
nnodes = round(Int, length(u)/field_dim)
|
||||
u = reshape(u, field_dim, nnodes)
|
||||
u = Vector{Float64}[u[:,i] for i in 1:nnodes]
|
||||
la = reshape(la, field_dim, nnodes)
|
||||
la = Vector{Float64}[la[:,i] for i in 1:nnodes]
|
||||
return u, la
|
||||
end
|
||||
end
|
||||
function update_elements!{P<:BoundaryProblem}(problem::Problem{P}, u, la)
|
||||
|
||||
""" Update solution from assebly to elements. """
|
||||
function update!{P<:FieldProblem}(problem::Problem{P}, assembly::Assembly, elements::Vector{Element}, time::Float64)
|
||||
u, la = get_global_solution(problem, assembly)
|
||||
field_name = get_unknown_field_name(problem)
|
||||
field_dim = get_unknown_field_dimension(problem)
|
||||
nnodes = round(Int, length(u)/field_dim)
|
||||
solution = reshape(la, field_dim, nnodes)
|
||||
for element in get_elements(problem)
|
||||
connectivity = get_connectivity(element) # node ids
|
||||
local_sol = Vector{Float64}[solution[:, node_id] for node_id in connectivity]
|
||||
last(element[field_name]).data = local_sol
|
||||
# update solution u for elements
|
||||
for element in elements
|
||||
connectivity = get_connectivity(element)
|
||||
update!(element, field_name, time => u[connectivity])
|
||||
end
|
||||
# if boundary problem is not dirichlet, update also data of main problem
|
||||
# is_dirichlet_problem(problem) && return
|
||||
field_name = get_parent_field_name(problem)
|
||||
solution = reshape(u, field_dim, nnodes)
|
||||
for element in get_elements(problem)
|
||||
connectivity = get_connectivity(element) # node ids
|
||||
local_sol = Vector{Float64}[solution[:, node_id] for node_id in connectivity]
|
||||
last(element[field_name]).data = local_sol
|
||||
end
|
||||
|
||||
function update!{P<:BoundaryProblem}(problem::Problem{P}, assembly::Assembly, elements::Vector{Element}, time::Float64)
|
||||
u, la = get_global_solution(problem, assembly)
|
||||
parent_field_name = get_parent_field_name(problem) # displacement
|
||||
field_name = get_unknown_field_name(problem) # reaction force
|
||||
# update solution u and reaction force λ for boundary elements
|
||||
for element in elements
|
||||
connectivity = get_connectivity(element)
|
||||
update!(element, parent_field_name, time => u[connectivity])
|
||||
# FIXME
|
||||
update!(element, field_name, time => -la[connectivity])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -276,12 +273,16 @@ function get_elements(problem::Problem)
|
||||
return problem.elements
|
||||
end
|
||||
|
||||
function get_assembly(problem::Problem)
|
||||
return problem.assembly
|
||||
end
|
||||
|
||||
function length(problem::Problem)
|
||||
return length(problem.elements)
|
||||
end
|
||||
|
||||
function update!(problem::Problem, field_name, field)
|
||||
update!(problem.elements, field_name, field)
|
||||
function update!(problem::Problem, field_name::AbstractString, data)
|
||||
update!(problem.elements, field_name::AbstractString, data)
|
||||
end
|
||||
|
||||
""" Return the dimension of the unknown field of this problem. """
|
||||
@@ -380,3 +381,4 @@ function find_nodes_by_dofs(dim, dofs)
|
||||
end
|
||||
return nodes
|
||||
end
|
||||
|
||||
|
||||
@@ -530,6 +530,7 @@ function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity},
|
||||
Kg = zeros(dim*nnodes, dim*nnodes)
|
||||
f = zeros(dim*nnodes)
|
||||
|
||||
has_concentrated_forces = false
|
||||
for ip in get_integration_points(element)
|
||||
detJ = element(ip, time, Val{:detJ})
|
||||
w = ip.weight*detJ
|
||||
@@ -543,6 +544,11 @@ function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity},
|
||||
T = element("displacement traction force $i", ip, time)
|
||||
f[i:dim:end] += w*vec(T*N)
|
||||
end
|
||||
if haskey(element, "concentrated force $i")
|
||||
has_concentrated_forces = true
|
||||
T = element("concentrated force $i", ip, time)
|
||||
f[i:dim:end] += w*vec(T*N)
|
||||
end
|
||||
end
|
||||
if haskey(element, "surface pressure")
|
||||
J = element(ip, time, Val{:Jacobian})'
|
||||
@@ -553,6 +559,9 @@ function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity},
|
||||
f += w*p*vec(n*N)
|
||||
end
|
||||
end
|
||||
if has_concentrated_forces
|
||||
update!(element, "concentrated force", time => Any[f])
|
||||
end
|
||||
return Km, Kg, f
|
||||
end
|
||||
|
||||
@@ -710,3 +719,32 @@ end
|
||||
|
||||
|
||||
=#
|
||||
|
||||
function call(problem::Problem, element::Element, ip, time::Float64, ::Type{Val{:E}})
|
||||
haskey(element, "displacement") || return nothing
|
||||
gradu = element("displacement", ip, time, Val{:Grad})
|
||||
eps = 0.5*(gradu + gradu')
|
||||
return eps
|
||||
end
|
||||
|
||||
function call(problem::Problem, element::Element, ip, time::Float64, ::Type{Val{:S}})
|
||||
haskey(element, "displacement") || return nothing
|
||||
props = problem.properties
|
||||
eps = problem(element, ip, time, Val{:E})
|
||||
eps == nothing && return nothing
|
||||
E = element("youngs modulus", ip, time)
|
||||
nu = element("poissons ratio", ip, time)
|
||||
mu = E/(2.0*(1.0+nu))
|
||||
la = E*nu/((1.0+nu)*(1.0-2.0*nu))
|
||||
if props.formulation in [:plane_stress, :plane_strain]
|
||||
la = 2.0*la*mu/(la+2.0*mu)
|
||||
end
|
||||
S = la*trace(eps)*I + 2.0*mu*eps
|
||||
return S
|
||||
end
|
||||
|
||||
function call(problem::Problem, element::Element, ip, time::Float64, ::Type{Val{:COORD}})
|
||||
haskey(element, "geometry") || return nothing
|
||||
return element("geometry", ip, time)
|
||||
end
|
||||
|
||||
|
||||
+6
-2
@@ -408,8 +408,12 @@ function update!(solver::Solver, u::Vector, la::Vector; show_info=true)
|
||||
show_info && info("Updating problems ...")
|
||||
t0 = Base.time()
|
||||
for problem in solver.problems
|
||||
u_new, la_new = update_assembly!(problem, u, la)
|
||||
update_elements!(problem, u_new, la_new)
|
||||
assembly = get_assembly(problem)
|
||||
elements = get_elements(problem)
|
||||
# update solution, first for assembly (u,la) ...
|
||||
update!(problem, assembly, u, la)
|
||||
# .. and then from assembly (u,la) to elements
|
||||
update!(problem, assembly, elements, solver.time)
|
||||
end
|
||||
t1 = round(Base.time()-t0, 2)
|
||||
show_info && info("Updated problems in $t1 seconds.")
|
||||
|
||||
+10
-8
@@ -101,21 +101,23 @@ function call(solver::Solver{Modal}; show_info=true, debug=false)
|
||||
info("Eigenvalues computed in $t1 seconds. Eigenvalues: $om2")
|
||||
|
||||
for i=1:length(om2)
|
||||
freq = real(sqrt(om2[i])/(2.0*pi))
|
||||
u = props.eigvecs[:,i]
|
||||
field_dim = get_unknown_field_dimension(solver)
|
||||
field_name = get_unknown_field_name(solver)
|
||||
nnodes = round(Int, length(u)/field_dim)
|
||||
solution = reshape(u, field_dim, nnodes)
|
||||
if field_dim != 1
|
||||
nnodes = round(Int, length(u)/field_dim)
|
||||
u = reshape(u, field_dim, nnodes)
|
||||
u = Vector{Float64}[u[:,i] for i in 1:nnodes]
|
||||
end
|
||||
for problem in get_problems(solver)
|
||||
local_sol = Dict{Int64, Vector{Float64}}()
|
||||
for node_id in get_connectivity(problem)
|
||||
local_sol[node_id] = solution[:, node_id]
|
||||
for element in get_elements(problem)
|
||||
connectivity = get_connectivity(element)
|
||||
update!(element, field_name, freq => u[connectivity])
|
||||
end
|
||||
freq = real(sqrt(om2[i])/(2.0*pi))
|
||||
update!(problem, field_name, freq => local_sol)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user