diff --git a/Project.toml b/Project.toml index 4bd79e1ead..5907821e95 100644 --- a/Project.toml +++ b/Project.toml @@ -43,6 +43,7 @@ SHA = "ea8e919c-243c-51af-8825-aaa63cd721ce" StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" +Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" [targets] -test = ["BlockArrays", "Downloads", "FerriteGmsh", "ForwardDiff", "Gmsh", "IterativeSolvers", "Metis", "NBInclude", "ProgressMeter", "Random", "SHA", "StableRNGs", "Test", "TimerOutputs"] +test = ["BlockArrays", "Downloads", "FerriteGmsh", "ForwardDiff", "Gmsh", "IterativeSolvers", "Metis", "NBInclude", "ProgressMeter", "Random", "SHA", "StableRNGs", "Test", "TimerOutputs", "Logging"] diff --git a/src/Dofs/ConstraintHandler.jl b/src/Dofs/ConstraintHandler.jl index 6b512bc9a0..0aafffbcc3 100644 --- a/src/Dofs/ConstraintHandler.jl +++ b/src/Dofs/ConstraintHandler.jl @@ -873,8 +873,35 @@ end #Function for adding constraint when using multiple celltypes -function add!(ch::ConstraintHandler, fh::FieldHandler, dbc::Dirichlet) - _check_cellset_dirichlet(ch.dh.grid, fh.cellset, dbc.faces) +function add!(ch::ConstraintHandler{<:MixedDofHandler}, dbc::Dirichlet) + dbc_added = false + for fh in ch.dh.fieldhandlers + if overlaps(fh, dbc) + # Recreating the `dbc` will create a copy of `dbc.faces`. + # If `dbc` have dofs not in `fh`, these will be removed from `dbc`, + # thus the need to copy `dbc.faces`. + # In this case, add! will warn, unless warn_check_cellset=false + dbc_ = Dirichlet(dbc.field_name, dbc.faces, dbc.f, + isempty(dbc.components) ? nothing : dbc.components) + # Check for empty already done when user created `dbc` + add!(ch, fh, dbc_, warn_check_cellset=false) + dbc_added = true + end + end + dbc_added || @warn("No overlap between dbc::Dirichlet and fields in the ConstraintHandler's MixedDofHandler") + return ch +end + +function overlaps(fh::FieldHandler, dbc::Dirichlet) + dbc.field_name in getfieldnames(fh) || return false # Must contain the correct field + for (cellid, _) in dbc.faces + cellid in fh.cellset && return true + end + return false +end + +function add!(ch::ConstraintHandler, fh::FieldHandler, dbc::Dirichlet; warn_check_cellset=true) + warn_check_cellset && _check_cellset_dirichlet(ch.dh.grid, fh.cellset, dbc.faces) celltype = getcelltype(ch.dh.grid, first(fh.cellset)) #Assume same celltype of all cells in fh.cellset diff --git a/test/runtests.jl b/test/runtests.jl index edfb54ccf2..249f28b7a2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,7 @@ using Ferrite using Tensors using Test +using Logging using ForwardDiff import SHA using Random diff --git a/test/test_constraints.jl b/test/test_constraints.jl index e108f7b914..44f898372f 100644 --- a/test/test_constraints.jl +++ b/test/test_constraints.jl @@ -189,6 +189,77 @@ end @test ch.prescribed_dofs == [10, 11, 14, 25, 27] end +@testset "edge bc mixed grid" begin + # Test mesh + # 6---7---8---9---10 + # | |2 /| | | :u 1:5 + # | 1 | / | 4 | 5 | :v 1:2 + # | |/ 3| | | + # 1---2---3---4---5 + # + # |---A---|---B---| + # |---C---| + # + # Dofs per node (note, depends on push! order below) (:u, [:v]) + # node nr 1 2 3 4 5 6 7 8 9 10 + nodedofs = [(1, 5), (2, 6), (11,), (12,), (14,), (4,8), (3,7), (9,10), (13,), (15,)] + + # Create Grid based on above drawing + nodes = [Node{2,Float64}(Vec{2,Float64}((i, j))) for j in 0:1 for i in 0:4] + quadcells = [Quadrilateral((i, i+1, i+6, i+5)) for i in [1, 3, 4]] + tricells = [Triangle((2,8,7)), Triangle((2,3,8))] + cells = [quadcells[1], tricells..., quadcells[2:end]...] + cellsets = Dict("onlyuQ" => Set(4:5), "onlyuT" => Set(3:3), + "uandvQ" => Set(1:1), "uandvT" => Set(2:2)) + facesets = Dict("A" => Set((FaceIndex(1,1), FaceIndex(3,1))), + "B" => Set((FaceIndex(4,1), FaceIndex(5,1))), + "C" => Set((FaceIndex(3,1), FaceIndex(4,1)))) + grid = Grid(cells, nodes, cellsets=cellsets, facesets=facesets) + + # Create MixedDofHandler based on grid + dim = Ferrite.getdim(grid) # 2 + ip_quad = Lagrange{dim,RefCube,1}() + ip_tria = Lagrange{dim,RefTetrahedron,1}() + dh = MixedDofHandler(grid) + field_uT = Field(:u, ip_tria, 1) + field_uQ = Field(:u, ip_quad, 1) + field_vT = Field(:v, ip_tria, 1) + field_vQ = Field(:v, ip_quad, 1) + + # Order important for test to ensure consistent dof ordering + push!(dh, FieldHandler([field_uQ, field_vQ], getcellset(grid, "uandvQ"))) + push!(dh, FieldHandler([field_uT, field_vT], getcellset(grid, "uandvT"))) + push!(dh, FieldHandler([field_uT], getcellset(grid, "onlyuT"))) + push!(dh, FieldHandler([field_uQ], getcellset(grid, "onlyuQ"))) + close!(dh) + + # Add constraints + ch = ConstraintHandler(dh) + dA_u = Dirichlet(:u, getfaceset(grid, "A"), (x,t) -> 1.0) + dA_v = Dirichlet(:v, getfaceset(grid, "A"), (x,t) -> 2.0) + dB_u = Dirichlet(:u, getfaceset(grid, "B"), (x,t) -> 3.0) # Note, overwrites dA_u on node 3 + dB_v = Dirichlet(:v, getfaceset(grid, "B"), (x,t) -> 4.0) # :v not on cells with "B"-faces + dC_v = Dirichlet(:v, getfaceset(grid, "C"), (x,t) -> 5.0) # :v not on cells with "C"-faces + + @test_logs min_level=Logging.Warn add!(ch, dA_u) # No warning should be issued + @test_logs min_level=Logging.Warn add!(ch, dA_v) # No warning should be issued + @test_logs min_level=Logging.Warn add!(ch, dB_u) # No warning should be issued + @test_logs (:warn,) add!(ch, dB_v) # Warn about :v not in cells connected with dB_v's faceset + @test_logs (:warn,) add!(ch, dC_v) # Warn about :v not in cells connected with dC_v's faceset + close!(ch) + + # The full bottom part of the mesh has been prescribed + @test sort(ch.prescribed_dofs) == sort([nd[i] for nd in nodedofs[1:5] for i in 1:length(nd)]) + + # Test that the correct dofs have been prescribed + update!(ch, 0.0) + # nodes N1, N2, N1, N2, N3, N4, N5 + # field :u, :u, :v, :v, :u, :u, :u + # dof 1, 2, 5, 6, 11, 12, 14 + @test ch.inhomogeneities == [1.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0] + # Note that dB_u overwrite dA_u @ N3, hence the value 3.0 there +end + @testset "affine constraints" begin grid = generate_grid(Line, (10,))