FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
transfer_asm.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
9#include <kernel/lafem/dense_vector.hpp>
10#include <kernel/lafem/dense_vector_blocked.hpp>
11#include <kernel/lafem/vector_mirror.hpp>
12#include <kernel/global/gate.hpp>
13#include <kernel/global/transfer.hpp>
14#include <kernel/assembly/symbolic_assembler.hpp>
15#include <kernel/assembly/grid_transfer.hpp>
16
17#include <control/domain/domain_control.hpp>
18
19namespace FEAT
20{
21 namespace Control
22 {
23 namespace Asm
24 {
63 template<typename DomainLevel_, typename SpaceLambda_, typename Transfer_, typename Muxer_, typename Gate_>
64 void asm_transfer_scalar(
65 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_f,
66 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_c,
67 const String& cubature, bool trunc, bool shrink,
68 SpaceLambda_&& space_lambda, Transfer_& transfer, const Muxer_& muxer, const Gate_& gate_f, const Gate_& gate_c)
69 {
70 typedef typename Transfer_::DataType DataType;
71 typedef typename Transfer_::IndexType IndexType;
72 typedef LAFEM::DenseVector<DataType, IndexType> ScalarVectorType;
73
74 // get fine and coarse domain levels
75 const DomainLevel_& level_f = *virt_lvl_f;
76 const DomainLevel_& level_c = virt_lvl_c.is_child() ? virt_lvl_c.level_c() : *virt_lvl_c;
77
78 // get fine and coarse spaces
79 const auto& space_f = *space_lambda(level_f);
80 const auto& space_c = *space_lambda(level_c);
81
82 // get local transfer matrices
83 auto& loc_prol = transfer.get_mat_prol();
84 auto& loc_rest = transfer.get_mat_rest();
85 auto& loc_trunc = transfer.get_mat_trunc();
86
87 // assemble structure?
88 if (loc_prol.empty())
89 Assembly::SymbolicAssembler::assemble_matrix_2lvl(loc_prol, space_f, space_c);
90
91 // create local weight vectors
92 auto loc_vec_weight_p = loc_prol.create_vector_l();
93 auto loc_vec_weight_t = loc_prol.create_vector_r();
94
95 // assemble prolongation matrix
96 loc_prol.format();
97 loc_vec_weight_p.format();
98 loc_vec_weight_t.format();
99
100 // if we need a truncation matrix, then compute its sparsity pattern now
101 if(trunc)
102 loc_trunc.transpose(loc_prol);
103
104 // assemble prolongation matrix
105 Assembly::GridTransfer::assemble_prolongation(loc_prol, loc_vec_weight_p, space_f, space_c, cubature);
106
107 // assemble truncation matrix if desired
108 if(trunc)
109 Assembly::GridTransfer::assemble_truncation(loc_trunc, loc_vec_weight_t, space_f, space_c, cubature);
110
111 // synchronize weight vector using the fine level gate
112 gate_f.sync_0(loc_vec_weight_p);
113
114 // invert components
115 loc_vec_weight_p.component_invert(loc_vec_weight_p);
116
117 // scale prolongation matrix
118 loc_prol.scale_rows(loc_prol, loc_vec_weight_p);
119
120 // shrink prolongation matrix if desired
121 if(shrink)
122 loc_prol.shrink(DataType(1E-3) * loc_prol.max_abs_element());
123
124 // copy and transpose
125 loc_rest = loc_prol.transpose();
126
127 // do we need a truncation operator?
128 if(!trunc)
129 return;
130
131 // We now need to synchronize the weight vector in analogy to the prolongation matrix assembly.
132 // Note that the weight vector is now a coarse-level vector, so we need to synchronize over
133 // the coarse-level gate. This may be a bit more complicated if the coarse level is a ghost
134 // level, as in this case we have to join/split around the sync operation.
135
136 // synchronize weight vector using the muxer/gate
137 if(!virt_lvl_c.is_child())
138 {
139 // The coarse level is a simple (non-child) level that exists on all processes,
140 // so simply sync over the coarse-level gate:
141 gate_c.sync_0(loc_vec_weight_t);
142 }
143 else if(virt_lvl_c.is_parent())
144 {
145 // The coarse level is a child level and this is one of the parent processes which contain
146 // the coarse-level gate. So we first need to join the weight vector onto the parent processes
147 // first, then sync that joined vector over the parent gate and finally split the result
148 // to all child processes -- this "emulates" a sync over the (non-existent) coarse-level
149 // child gate, which is what we actually require here...
150
151 // create temporary vector on parent partitioning
152 ScalarVectorType loc_tmp(gate_c.get_freqs().size());
153
154 // join child weights over muxer
155 muxer.join(loc_vec_weight_t, loc_tmp);
156
157 // sync over coarse gate
158 gate_c.sync_0(loc_tmp);
159
160 // split over muxer
161 muxer.split(loc_vec_weight_t, loc_tmp);
162 }
163 else // ghost
164 {
165 // The coarse level is a ghost level, i.e. a child but not a parent. In this case, we
166 // only have to participate in the join/send operations of the muxer, which are part
167 // of the operations executed on the parents handled by the else-if case above.
168
169 muxer.join_send(loc_vec_weight_t);
170
171 // parent performs sync over its gate here (see above else-if)
172
173 muxer.split_recv(loc_vec_weight_t);
174 }
175
176 // invert components
177 loc_vec_weight_t.component_invert(loc_vec_weight_t);
178
179 // scale prolongation matrix
180 loc_trunc.scale_rows(loc_trunc, loc_vec_weight_t);
181
182 // shrink prolongation matrix if desired
183 if(shrink)
184 loc_trunc.shrink(DataType(1E-3) * loc_trunc.max_abs_element());
185 }
186
225 template<typename DomainLevel_, typename SpaceLambda_, typename Transfer_, typename Muxer_, typename Gate_>
226 void asm_transfer_blocked(
227 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_f,
228 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_c,
229 const String& cubature, bool trunc, bool shrink,
230 SpaceLambda_&& space_lambda, Transfer_& transfer, const Muxer_& muxer, const Gate_& gate_f, const Gate_& gate_c)
231 {
232 typedef typename Transfer_::DataType DataType;
233 typedef typename Transfer_::IndexType IndexType;
234 typedef typename Gate_::MirrorType MirrorType;
235 typedef LAFEM::DenseVector<DataType, IndexType> ScalarVectorType;
236
237 // get fine and coarse domain levels
238 const DomainLevel_& level_f = *virt_lvl_f;
239 const DomainLevel_& level_c = virt_lvl_c.is_child() ? virt_lvl_c.level_c() : *virt_lvl_c;
240
241 // get fine and coarse spaces
242 const auto& space_f = *space_lambda(level_f);
243 const auto& space_c = *space_lambda(level_c);
244
245 // get local transfer matrices
246 auto& loc_prol_wrapped = transfer.get_mat_prol();
247 auto& loc_rest_wrapped = transfer.get_mat_rest();
248 auto& loc_trunc_wrapped = transfer.get_mat_trunc();
249
250 // get the unwrapped types
251 auto& loc_prol = loc_prol_wrapped.unwrap();
252 auto& loc_rest = loc_rest_wrapped.unwrap();
253 auto& loc_trunc = loc_trunc_wrapped.unwrap();
254
255 // assemble structure?
256 if (loc_prol.empty())
257 Assembly::SymbolicAssembler::assemble_matrix_2lvl(loc_prol, space_f, space_c);
258
259 // create local weight vectors
260 auto loc_vec_weight_p = loc_prol.create_vector_l();
261 auto loc_vec_weight_t = loc_prol.create_vector_r();
262
263 // assemble prolongation matrix
264 loc_prol.format();
265 loc_vec_weight_p.format();
266 loc_vec_weight_t.format();
267
268 // if we need a truncation matrix, then compute its sparsity pattern now
269 if(trunc)
270 loc_trunc.transpose(loc_prol);
271
272 // assemble prolongation matrix
273 Assembly::GridTransfer::assemble_prolongation(loc_prol, loc_vec_weight_p, space_f, space_c, cubature);
274
275 // assemble truncation matrix if desired
276 if(trunc)
277 Assembly::GridTransfer::assemble_truncation(loc_trunc, loc_vec_weight_t, space_f, space_c, cubature);
278
279 // create a temporary scalar gate
280 Global::Gate<ScalarVectorType, MirrorType> scalar_gate;
281 scalar_gate.convert(gate_f, loc_vec_weight_p.clone(LAFEM::CloneMode::Allocate));
282
283 // synchronize weight vector using the scalar gate
284 scalar_gate.sync_0(loc_vec_weight_p);
285
286 // invert components
287 loc_vec_weight_p.component_invert(loc_vec_weight_p);
288
289 // scale prolongation matrix
290 loc_prol.scale_rows(loc_prol, loc_vec_weight_p);
291
292 // shrink prolongation matrix if desired
293 if(shrink)
294 loc_prol.shrink(DataType(1E-3) * loc_prol.max_abs_element());
295
296 // copy and transpose
297 loc_rest = loc_prol.transpose();
298
299 // do we need a truncation operator?
300 if(!trunc)
301 return;
302
303 // We now need to synchronize the weight vector in analogy to the prolongation matrix assembly.
304 // Note that the weight vector is now a coarse-level vector, so we need to synchronize over
305 // the coarse-level gate. This may be a bit more complicated if the coarse level is a ghost
306 // level, as in this case we have to join/split around the sync operation.
307
308 // synchronize weight vector using the muxer/gate
309 if(!virt_lvl_c.is_child())
310 {
311 XASSERT(&gate_c != &gate_f);
312
313 // The coarse level is a simple (non-child) level that exists on all processes,
314 // so simply synchronize over the coarse-level gate:
315
316 // create a temporary scalar gate on the coarse level
317 Global::Gate<ScalarVectorType, MirrorType> scalar_gate_c;
318 scalar_gate_c.convert(gate_c, ScalarVectorType(space_c.get_num_dofs()));
319
320 // sync over scalar coarse gate
321 scalar_gate_c.sync_0(loc_vec_weight_t);
322 }
323 else if(virt_lvl_c.is_parent())
324 {
325 XASSERT(&gate_c != &gate_f);
326
327 // The coarse level is a child level and this is one of the parent processes which contain
328 // the coarse-level gate. So we first need to join the weight vector onto the parent processes
329 // first, then sync that joined vector over the parent gate and finally split the result
330 // to all child processes -- this "emulates" a sync over the (non-existent) coarse-level
331 // child gate, which is what we actually require here...
332
333 // get the number of the coarse level dofs from the gate's frequency vector, which is different
334 // than space_c.get_num_dofs(), because the first one is defined on the parent patch, whereas
335 // the latter one is defined on the child patch
336 const Index num_dofs_c = gate_c.get_freqs().size();
337
338 // create a temporary scalar gate on the coarse level
339 Global::Gate<ScalarVectorType, MirrorType> scalar_gate_c;
340 scalar_gate_c.convert(gate_c, ScalarVectorType(num_dofs_c));
341
342 // create a temporary scalar muxer on the fine level
343 Global::Muxer<ScalarVectorType, MirrorType> scalar_muxer_f;
344 scalar_muxer_f.convert(muxer, ScalarVectorType(space_f.get_num_dofs()));
345
346 // create temporary vector on parent partitioning
347 ScalarVectorType loc_tmp(num_dofs_c);
348
349 // join child weights over muxer
350 scalar_muxer_f.join(loc_vec_weight_t, loc_tmp);
351
352 // sync over scalar coarse gate
353 scalar_gate_c.sync_0(loc_tmp);
354
355 // split over muxer
356 scalar_muxer_f.split(loc_vec_weight_t, loc_tmp);
357 }
358 else // ghost
359 {
360 // The coarse level is a ghost level, i.e. a child but not a parent. In this case, we
361 // only have to participate in the join/send operations of the muxer, which are part
362 // of the operations executed on the parents handled by the else-if case above.
363
364 // create a temporary scalar muxer on the fine level
365 Global::Muxer<ScalarVectorType, MirrorType> scalar_muxer_f;
366 scalar_muxer_f.convert(muxer, ScalarVectorType(space_f.get_num_dofs()));
367
368 scalar_muxer_f.join_send(loc_vec_weight_t);
369
370 // parent performs sync over its gate here (see above else-if)
371
372 scalar_muxer_f.split_recv(loc_vec_weight_t);
373 }
374
375 // invert components
376 loc_vec_weight_t.component_invert(loc_vec_weight_t);
377
378 // scale prolongation matrix
379 loc_trunc.scale_rows(loc_trunc, loc_vec_weight_t);
380
381 // shrink prolongation matrix if desired
382 if(shrink)
383 loc_trunc.shrink(DataType(1E-3) * loc_trunc.max_abs_element());
384 }
385 } // namespace Asm
386 } // namespace Control
387} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
FEAT Kernel base header.
static void assemble_truncation(Matrix_ &matrix, Vector_ &vector, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const String &cubature_name)
Assembles a truncation matrix and its corresponding weight vector.
static void assemble_prolongation(Matrix_ &matrix, Vector_ &vector, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space, const String &cubature_name)
Assembles a prolongation matrix and its corresponding weight vector.
static void assemble_matrix_2lvl(MatrixType_ &matrix, const FineSpace_ &fine_space, const CoarseSpace_ &coarse_space)
Assembles a 2-level matrix structure from a fine-coarse-space pair.
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.