Skip to content

Commit 7f8a9b5

Browse files
committed
Use DOFMap in Assembly
Also, losen data type definitions in `add!` so that generators works also when adding data do sparse matricse.
1 parent d61501f commit 7f8a9b5

File tree

7 files changed

+71
-59
lines changed

7 files changed

+71
-59
lines changed

src/FEMBase.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ export element_info!
2727
include("elements_lagrange.jl")
2828
include("integrate.jl")
2929

30+
include("dofmap.jl")
31+
export get_gdofs
32+
3033
include("problems.jl")
31-
export set_gdofs!, get_gdofs, get_formulation_type
34+
export get_formulation_type
3235

33-
include("dofmap.jl")
3436

3537
include("assembly.jl")
3638
export assemble_prehook!, assemble_posthook!, assemble_elements!

src/problems.jl

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ type Problem{P<:AbstractProblem}
100100
dimension :: Int # degrees of freedom per node
101101
parent_field_name :: AbstractString # (optional) name of the parent field e.g. "displacement"
102102
elements :: Vector{Element}
103-
dofmap :: Dict{Element, Vector{Int64}} # connects the element local dofs to the global dofs
103+
dofmap :: AbstractDOFMap # connects the element local dofs to the global dofs
104104
assembly :: Assembly
105105
fields :: Dict{String, AbstractField}
106106
postprocess_fields :: Vector{String}
@@ -125,7 +125,13 @@ prob1 = Problem(Elasticity, "this is my problem", 3)
125125
126126
"""
127127
function Problem{P<:FieldProblem}(::Type{P}, name::AbstractString, dimension::Int64)
128-
return Problem{P}(name, dimension, "none", [], Dict(), Assembly(), Dict(), Vector(), P())
128+
dofmap = DOFMap()
129+
assembly = Assembly()
130+
local_dof_indices = Dict(Symbol("u$i") => i for i=1:dimension)
131+
set_local_dof_indices!(dofmap, local_dof_indices)
132+
problem = Problem{P}(name, dimension, "none", [], dofmap, assembly,
133+
Dict(), Vector(), P())
134+
return problem
129135
end
130136

131137
"""
@@ -139,14 +145,20 @@ julia> bc1 = Problem(Dirichlet, "support", 3, "displacement")
139145
solver.
140146
"""
141147
function Problem{P<:BoundaryProblem}(::Type{P}, name, dimension, parent_field_name)
142-
return Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), Dict(), Vector(), P())
148+
dofmap = DOFMap()
149+
assembly = Assembly()
150+
local_dof_indices = Dict(Symbol("u$i") => i for i=1:dimension)
151+
set_local_dof_indices!(dofmap, local_dof_indices)
152+
problem = Problem{P}(name, dimension, parent_field_name, [], dofmap,
153+
assembly, Dict(), Vector(), P())
154+
return problem
143155
end
144156

145157
function get_formulation_type(::Problem)
146158
return :incremental
147159
end
148160

149-
"""
161+
"""
150162
get_unknown_field_dimension(problem)
151163
152164
Return the dimension of the unknown field of this problem.
@@ -419,35 +431,47 @@ function push!(problem::Problem, elements_::Vector...)
419431
end
420432

421433
"""
422-
set_gdofs!(problem, element)
434+
get_dof_names(problem, element)
435+
436+
Return an iterable containing the abbreviations of dof names for this element
437+
and problem. This could be e.g. `(:u1, :u2, :T)` for two-dimensional problem
438+
having two displacement dofs and temperature dof.
423439
424-
Set element global degrees of freedom.
440+
Each new Problem should define this function. If now defined, assumption is that
441+
dofs for problem are (:u1, :u2, ..., :uN) where N is the unknown field dimension.
425442
"""
426-
function set_gdofs!(problem, element, dofs)
427-
problem.dofmap[element] = dofs
443+
function get_dof_names(problem::Problem{P}, ::Element) where {P}
444+
dim = get_unknown_field_dimension(problem)
445+
dof_names = (Symbol("u$i") for i=1:dim)
446+
warn("Define function FEMBase.get_dof_names(::Problem{$P}, ::Element).")
447+
warn("Assuming that dofs for problem $P are $(collect(dof_names)).")
448+
code = quote
449+
function FEMBase.get_dof_names(::Problem{$P}, ::Element)
450+
return $dof_names
451+
end
452+
end
453+
eval(code)
454+
return dof_names
455+
end
456+
457+
"""
458+
get_dofmap(problem)
459+
460+
Return `DOFMap` for problem.
461+
"""
462+
function get_dofmap(problem)
463+
return problem.dofmap
428464
end
429465

430466
"""
431467
get_gdofs(problem, element)
432468
433469
Return the global degrees of freedom for element.
434470
435-
First make lookup from problem dofmap. If not defined there, make implicit
436-
assumption that dofs follow formula `gdofs = [dim*(nid-1)+j for j=1:dim]`,
437-
where `nid` is node id and `dim` is the dimension of problem. This formula
438-
arranges dofs so that first comes all dofs of node 1, then node 2 and so on:
439-
(u11, u12, u13, u21, u22, u23, ..., un1, un2, un3) for 3 dofs/node setting.
440471
"""
441-
function get_gdofs(problem::Problem, element::Element)
442-
if haskey(problem.dofmap, element)
443-
return problem.dofmap[element]
444-
end
445-
conn = get_connectivity(element)
446-
if length(conn) == 0
447-
error("element connectivity not defined, cannot determine global ",
448-
"degrees of freedom for element #: $(element.id)")
449-
end
450-
dim = get_unknown_field_dimension(problem)
451-
gdofs = [dim*(i-1)+j for i in conn for j=1:dim]
452-
return gdofs
472+
function get_gdofs(problem::Problem{P}, element::Element) where {P}
473+
nodes = get_connectivity(element)
474+
dof_names = get_dof_names(problem, element)
475+
dofmap = get_dofmap(problem)
476+
return get_gdofs(dofmap, nodes, dof_names)
453477
end

src/sparse.jl

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,10 @@ Example
116116
0.0 0.0 0.0 0.0 0.0 8.0 9.0 10.0
117117
118118
"""
119-
function add!(A::SparseMatrixCOO, dofs1::Vector{Int}, dofs2::Vector{Int}, data::Matrix)
120-
n, m = size(data)
121-
for j=1:m
122-
for i=1:n
123-
add!(A, dofs1[i], dofs2[j], data[i,j])
119+
function add!(A::SparseMatrixCOO, dofs1, dofs2, data)
120+
for (j, d1) in enumerate(dofs1)
121+
for (i, d2) in enumerate(dofs2)
122+
add!(A, d1, d2, data[i,j])
124123
end
125124
end
126125
return nothing
@@ -134,15 +133,11 @@ function add!(A::SparseMatrixCOO, B::SparseMatrixCSC)
134133
end
135134

136135
""" Add new data to COO Sparse vector. """
137-
function add!(A::SparseMatrixCOO, dofs::Vector{Int}, data::Array{Float64}, dim::Int=1)
138-
if length(dofs) != length(data)
139-
info("dofs = $dofs")
140-
info("data = $(vec(data))")
141-
error("when adding to sparse vector dimension mismatch!")
136+
function add!(A::SparseMatrixCOO, dofs, data::Array{Float64}, dim::Int=1)
137+
for (d, v) in zip(dofs, data)
138+
add!(A, d, dim, v)
142139
end
143-
append!(A.I, dofs)
144-
append!(A.J, dim*ones(Int, length(dofs)))
145-
append!(A.V, vec(data))
140+
return nothing
146141
end
147142

148143
""" Add SparseVector to SparseVectorCOO. """

src/test.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ function assemble_elements!{E}(problem::Problem{Dirichlet},
112112
for element in elements
113113
for i=1:dim
114114
haskey(element, "$name $i") || continue
115-
gdofs = get_gdofs(problem, element)
115+
gdofs = collect(get_gdofs(problem, element))
116116
ldofs = gdofs[i:dim:end]
117117
xis = get_reference_element_coordinates(E)
118118
for (ldof, xi) in zip(ldofs, xis)
@@ -263,7 +263,7 @@ end
263263
test_resource(resource::String) -> String
264264
265265
`@test_resource(resource)` expands to a string containing full path to the some
266-
`resource` what is needed by a test.
266+
`resource` what is needed by a test.
267267
268268
# Example
269269
@@ -274,7 +274,7 @@ One needs a test mesh file `mesh.inp`. Then, function
274274
mesh_file = @test_resource("mesh.inp")
275275
```
276276
277-
expands to
277+
expands to
278278
279279
`~/.julia/v0.6/Models/test/test_run_model/mesh.inp`
280280

test/test_assembly.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ end
5959
M = full(p.assembly.M)
6060

6161
M_expected = [
62-
6 1 1 1 -4 -6 -4 -4 -6 -6
62+
6 1 1 1 -4 -6 -4 -4 -6 -6
6363
1 6 1 1 -4 -4 -6 -6 -4 -6
6464
1 1 6 1 -6 -4 -4 -6 -6 -4
6565
1 1 1 6 -6 -6 -6 -4 -4 -4
@@ -83,8 +83,8 @@ end
8383
A = Assembly()
8484
B = Assembly()
8585
@test isempty(A)
86-
add!(A.K, [1,2,3,4], [1,2,3,4], [1.0 2.0; 3.0 4.0])
87-
add!(B.K, [1,2,3,4], [1,2,3,4], [1.0 2.0; 3.0 4.0])
86+
add!(A.K, [1,2], [1,2], [1.0 2.0; 3.0 4.0])
87+
add!(B.K, [1,2], [1,2], [1.0 2.0; 3.0 4.0])
8888
@test isapprox(A, B)
8989
@test !isempty(A)
9090
empty!(A)

test/test_problems.jl

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ end
9898
println("elgeom is ", el("geometry", 0.0))
9999
@test isapprox(p1("geometry", 0.0)[1], [0.0, 0.0])
100100
@test get_parent_field_name(p2) == "p"
101-
@test get_gdofs(p1, el) == [1, 2]
101+
@test collect(get_gdofs(p1, el)) == [1, 2]
102102

103103
p3 = Problem(P2, "P3", 1, "p")
104104
as = get_assembly(p3)
@@ -203,7 +203,7 @@ function assemble_elements!{E}(problem::Problem{DirBC},
203203
for element in elements
204204
for i=1:dim
205205
haskey(element, "$name $dim") || continue
206-
gdofs = get_gdofs(problem, element)
206+
gdofs = collect(get_gdofs(problem, element))
207207
ldofs = gdofs[i:dim:end]
208208
xis = get_reference_element_coordinates(E)
209209
for (ldof, xi) in zip(ldofs, xis)
@@ -258,12 +258,8 @@ end
258258
assemble_elements!(problem, problem.assembly, elements, 0.0)
259259
end
260260

261-
@testset "test set and get global dofs for element" begin
261+
@testset "test get global dofs for element" begin
262262
element = Element(Seg2, [1, 2])
263263
problem = Problem(P3, "P3", 2)
264-
@test get_gdofs(problem, element) == [1, 2, 3, 4]
265-
set_gdofs!(problem, element, [2, 3, 4, 5])
266-
@test get_gdofs(problem, element) == [2, 3, 4, 5]
267-
element2 = Element(Seg2, Int[])
268-
@test_throws ErrorException get_gdofs(problem, element2)
264+
@test collect(get_gdofs(problem, element)) == [1, 2, 3, 4]
269265
end

test/test_sparse.jl

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ end
2121
@test isapprox(full(b), full(b2))
2222
end
2323

24-
@testset "Failure to add data to sparse vector due dimension mismatch" begin
25-
b = SparseVectorCOO()
26-
@test_throws ErrorException add!(b, [1, 2], [1.0, 2.0, 3.0])
27-
end
28-
2924
@testset "Test combining of SparseMatrixCOO" begin
3025
k = convert(Matrix{Float64}, reshape(collect(1:9), 3, 3))
3126
dofs1 = [1, 2, 3]

0 commit comments

Comments
 (0)