Skip to content

Commit

Permalink
Small changes in api (#34)
Browse files Browse the repository at this point in the history
* New function get_problem(problem, name) to fetch a problem from a
  analysis.
* Update docstrings.
* Connectivity can be given with tuple when creating new element.
* Be more information (@info) when calling functions to be more
  responsible.
* Preparations to separate topology and basis.
* Remove function to update properties with string pairs, it's quite
  unpractical approach (we still should implement something like
  update_properties!(...) ).
* `add_elements!`, `add_problems!`, takes also varargs, so can also call
  `add_elements!(p, e1, e2)` instead of creating first iterable.
* `update!` can take list of elements as tuple.
* `SparseMatrixCOO` and `SparseVectorCOO` can be converted to full
  matrices / vectors using `Matrix` and `Vector`.
* Comparison of `SparseMatrixCOO` with matrix / vector using `isapprox`.
* `add!` returns nothing.
  • Loading branch information
ahojukka5 committed Sep 1, 2018
1 parent 5201c70 commit d96a0d3
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 128 deletions.
6 changes: 3 additions & 3 deletions src/FEMBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ include("elements_lagrange.jl")
include("integrate.jl")

include("problems.jl")
export set_gdofs!, get_gdofs, get_formulation_type
export set_gdofs!, get_gdofs, get_formulation_type, add_element!, add_elements!

include("assembly.jl")
export assemble_prehook!, assemble_posthook!, assemble_elements!
Expand All @@ -41,12 +41,12 @@ export LinearSystem, AbstractLinearSystemSolver, solve!
include("analysis.jl")
export AbstractAnalysis, Analysis, add_problems!, get_problems, run!,
AbstractResultsWriter, add_results_writer!, get_results_writers,
write_results!
write_results!, get_problem

export FieldProblem, BoundaryProblem, Problem, Element, Assembly
export Poi1, Seg2, Seg3, Tri3, Tri6, Tri7, Quad4, Quad8, Quad9,
Tet4, Tet10, Pyr5, Wedge6, Wedge15, Hex8, Hex20, Hex27
export add_elements!, add!, group_by_element_type,
export add!, group_by_element_type,
get_unknown_field_name, get_unknown_field_dimension,
get_integration_points, initialize!, assemble!
export SparseMatrixCOO, SparseVectorCOO, Node, BasisInfo,
Expand Down
49 changes: 47 additions & 2 deletions src/analysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,64 @@ mutable struct Analysis{A<:AbstractAnalysis}
properties :: A
end

"""
Analysis(A, analysis_name)
Create a new analysis of type `A`, where `A` is a subtype of `AbstractAnalysis`.
Analysis can be e.g. `Linear` for linear quasistatic analysis, `Nonlinear` for
nonlinear quasistatic analysis or `Modal` for natural frequency analysis.
# Examples
```julia
analysis = Analysis(Linear, "linear quasistatic analysis of beam structure")
```
"""
function Analysis(::Type{A}, name::String="$A Analysis") where A<:AbstractAnalysis
analysis = Analysis{A}(name, [], Dict(), [], A())
@info("Creating a new analysis of type $A with name `$name`.")
return analysis
end

function add_problems!(analysis::Analysis, problems::Vector)
append!(analysis.problems, problems)
function add_problem!(analysis::Analysis, problems::Problem...)
for problem in problems
@info("Adding problem `$(problem.name)` to analysis `$(analysis.name)`.")
push!(analysis.problems, problem)
end
return nothing
end

add_problems!(analysis::Analysis, problems::Union{Vector, Tuple}) = add_problem!(analysis, problems...)

"""
add_problems!(analysis, problem...)
Add problem(s) to analysis.
# Examples
Add two problems, `beam` and `bc`, to linear quasistatic analysis:
```julia
beam = Problem(Beam, "beam structure", 6)
bc = Problem(Dirichlet, "fix", 6, "displacement")
analysis = Analysis(Linear, "linear quasistatic analysis")
add_problems!(analysis, beam, bc)
```
"""
add_problems!(analysis::Analysis, problems...) = add_problem!(analysis, problems...)

function get_problems(analysis::Analysis)
return analysis.problems
end

function get_problem(analysis::Analysis, problem_name)
problems = filter(p -> p.name == problem_name, get_problems(analysis))
if length(problems) != 1
error("Several problem with name $problem_name found from analysis $(analysis.name).")
end
return first(problems)
end

function add_results_writer!(analysis::Analysis, writer::W) where W<:AbstractResultsWriter
push!(analysis.results_writers, writer)
return nothing
Expand Down
102 changes: 86 additions & 16 deletions src/elements.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,52 @@ mutable struct Element{E<:AbstractBasis}
end

"""
Element(element_type, connectivity_vector)
Construct a new element where element_type is the type of the element
and connectivity_vector is the vector of nodes that the element is connected to.
Examples
--------
In the example a new element (E in the figure below) of type Tri3 is created.
This spesific element connects to nodes 89, 43, 12 in the finite element mesh.
```@example
element = Element(Tri3, [89, 43, 12])
Element(topology, connectivity)
Construct a new element where `topology` is the topological type of the element
and connectivity contains node numbers where element is connected.
# Topological types
## 1d elements
- `Seg2`
- `Seg3`
## 2d elements
- `Tri3`
- `Tri6`
- `Tri7`
- `Quad4`
- `Quad8`
- `Quad9`
## 3d elements
- `Tet4`
- `Tet10`
- `Hex8`
- `Hex20`
- `Hex27`
- `Pyr5`
- `Wedge6`
- `Wedge15`
# Examples
```julia
element = Element(Tri3, (1, 2, 3))
```
![img](figs/mesh.png)
"""
function Element(::Type{E}, connectivity::Vector{Int}) where E<:AbstractBasis
return Element{E}(-1, connectivity, [], Dict(), E())
function Element(::Type{T}, connectivity::NTuple{N, Int}) where {N, T<:AbstractBasis}
element_id = -1
topology = T()
integration_points = []
fields = Dict()
element = Element{T}(element_id, collect(connectivity), integration_points, fields, topology)
return element
end

function Element(::Type{T}, connectivity::Vector{Int}) where T<:AbstractBasis
return Element(T, (connectivity...,))
end

"""
Expand Down Expand Up @@ -289,7 +318,48 @@ function update!(element::Element, field_name, data::Function)
end
end

function update!(elements::Vector, field_name, data)
function info_update_field(elements, field_name, data)
nelements = length(elements)
@info("Updating field `$field_name` for $nelements elements.")
end

function info_update_field(elements, field_name, data::Float64)
nelements = length(elements)
@info("Updating field `$field_name` => $data for $nelements elements.")
end

"""
update!(elements, field_name, data)
Given a list of elements, field name and data, update field to elements. Data
is passed directly to the `field`-function.
# Examples
Create two elements with topology `Seg2`, one is connecting to nodes (1, 2) and
the other is connecting to (2, 3). Some examples of updating fields:
```julia
elements = [Element(Seg2, [1, 2]), Element(Seg2, [2, 3])]
X = Dict(1 => 0.0, 2 => 1.0, 3 => 2.0)
u = Dict(1 => 0.0, 2 => 0.0, 3 => 0.0)
update!(elements, "geometry", X)
update!(elements, "displacement", 0.0 => u)
update!(elements, "youngs modulus", 210.0e9)
update!(elements, "time-dependent force", 0.0 => 0.0)
update!(elements, "time-dependent force", 1.0 => 100.0)
```
When using dictionaries in definition of fields, key of dictionary corresponds
to node id, that is, updating field `geometry` in the example above is updating
values `(0.0, 1.0)` for the first elements and values `(1.0, 2.0)` to the second
element. For time dependent field, syntax `time => data` is used. If field is
initialized without time-dependency, it cannot be changed to be time-dependent
afterwards. If unsure, it's better to initialize field with time dependency.
"""
function update!(elements, field_name, data)
info_update_field(elements, field_name, data)
for element in elements
update!(element, field_name, data)
end
Expand Down
5 changes: 0 additions & 5 deletions src/fields.jl
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,6 @@ function interpolate(a, b)
return sum(a[i]*b[i] for i=1:length(a))
end

"""
update!(field, data)
Update new value to field.
"""
function update!(field::F, data) where F<:AbstractField
update_field!(field, data)
end
Loading

0 comments on commit d96a0d3

Please sign in to comment.