@@ -45,8 +45,77 @@ function CoupledDofsRestriction(matrices::Vector{AM}) where {AM <: AbstractMatri
4545end
4646
4747
48+ """
49+ CoupledDofsRestriction(source::Ti, target::Ti, axis::Ti) where Ti
50+
51+ Create an incomplete CoupledDofsRestriction by only providing abstract information:
52+ - unknown: the unknown to be coupled
53+ - source_region: source boundary region
54+ - target_region: target boundary region
55+
56+ This constructor assumes that
57+ - the source and target boundary regions form two parallel hyperplanes
58+ - the coupling is performed orthogonally between the given hyperplanes
59+
60+ The concrete coupling matrix will be computed in the solver, when the grid geometry and the FES is known.
61+ """
62+ function CoupledDofsRestriction (unknown:: Unknown , source_region:: Ti , target_region:: Ti ; kwargs... ) where {Ti}
63+ return CoupledDofsRestriction (
64+ [nothing ],
65+ Dict {Symbol, Any} (
66+ :name => " CoupledDofsRestriction" ,
67+ :reduce_col_space => false ,
68+ :unknown => unknown,
69+ :source_region => source_region,
70+ :target_region => target_region,
71+ :kwargs => kwargs
72+ )
73+ )
74+ end
75+
76+
4877function assemble! (R:: CoupledDofsRestriction , sol, SC; kwargs... )
4978
79+ # remember original R
80+ R_orig = R
81+
82+ # compute the coupling matrix first, if necessary
83+ if R. coupling_matrices[begin ] === nothing
84+ FES = sol[R. parameters[:unknown ]]. FES
85+ source_region = R. parameters[:source_region ]
86+ target_region = R. parameters[:target_region ]
87+ R_kwargs = R. parameters[:kwargs ]
88+
89+ grid = FES. dofgrid
90+
91+ # at first, we select one face on source/target region
92+ source_bface = findfirst (== (source_region), grid[BFaceRegions])
93+ target_bface = findfirst (== (target_region), grid[BFaceRegions])
94+
95+ # the normal (it should really be opposite to the normal on the other side)
96+ normal = grid[BFaceNormals][:, source_bface]
97+ @assert normal ≈ - grid[BFaceNormals][:, target_bface]
98+
99+ # pick a coordinate on each boundary region
100+ source_coord = grid[Coordinates][:, grid[BFaceNodes][1 , source_bface]]
101+ target_coord = grid[Coordinates][:, grid[BFaceNodes][1 , target_bface]]
102+
103+ # compute the sum of scalar product with the normals (reflection point)
104+ γ = source_coord' normal + target_coord' normal
105+
106+ function give_opposite! (y, x)
107+ σ = 2.0 * normal' x
108+ @. y = x + (γ - σ) * normal # then x ⇔ y are opposite along the normal vector
109+ return nothing
110+ end
111+
112+ coupling_matrix = get_periodic_coupling_matrix (FES, source_region, target_region, give_opposite!; R_kwargs... )
113+
114+ # replace R (in this scope)
115+ R = CoupledDofsRestriction (coupling_matrix)
116+ end
117+
118+
50119 # extract all col indices and remove duplicates
51120 # subtract diagonal and shrink matrix to non-empty cols
52121 Bs = [ (matrix - LinearAlgebra. I)[:, unique (findnz (matrix)[2 ])] for matrix in R. coupling_matrices ]
@@ -63,11 +132,11 @@ function assemble!(R::CoupledDofsRestriction, sol, SC; kwargs...)
63132 B = B[:, cols_of_interest]
64133 end
65134
66- R . parameters[:matrix ] = B
67- R . parameters[:rhs ] = zeros (size (B, 2 ))
135+ R_orig . parameters[:matrix ] = B
136+ R_orig . parameters[:rhs ] = zeros (size (B, 2 ))
68137
69138 # fixed dofs are all active rows of B
70- R . parameters[:fixed_dofs ] = unique (findnz (B)[1 ])
139+ R_orig . parameters[:fixed_dofs ] = unique (findnz (B)[1 ])
71140
72141 return nothing
73142end
0 commit comments