FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
stokes_power.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/util/dist.hpp>
10#include <kernel/geometry/export_vtk.hpp>
11#include <kernel/lafem/dense_vector.hpp>
12#include <kernel/lafem/power_vector.hpp>
13#include <kernel/lafem/tuple_vector.hpp>
14#include <kernel/lafem/vector_mirror.hpp>
15#include <kernel/lafem/power_mirror.hpp>
16#include <kernel/lafem/tuple_mirror.hpp>
17#include <kernel/lafem/unit_filter.hpp>
18#include <kernel/lafem/mean_filter.hpp>
19#include <kernel/lafem/none_filter.hpp>
20#include <kernel/lafem/power_filter.hpp>
21#include <kernel/lafem/tuple_filter.hpp>
22#include <kernel/lafem/sparse_matrix_csr.hpp>
23#include <kernel/lafem/saddle_point_matrix.hpp>
24#include <kernel/lafem/tuple_diag_matrix.hpp>
25#include <kernel/lafem/power_diag_matrix.hpp>
26#include <kernel/lafem/power_col_matrix.hpp>
27#include <kernel/lafem/power_row_matrix.hpp>
28#include <kernel/lafem/transfer.hpp>
29#include <kernel/analytic/common.hpp>
30#include <kernel/assembly/mirror_assembler.hpp>
31#include <kernel/assembly/symbolic_assembler.hpp>
32#include <kernel/assembly/domain_assembler_basic_jobs.hpp>
33#include <kernel/assembly/bilinear_operator_assembler.hpp>
34#include <kernel/assembly/linear_functional_assembler.hpp>
35#include <kernel/assembly/common_operators.hpp>
36#include <kernel/assembly/common_functionals.hpp>
37#include <kernel/assembly/grid_transfer.hpp>
38#include <kernel/assembly/discrete_projector.hpp>
39#include <kernel/assembly/mean_filter_assembler.hpp>
40#include <kernel/assembly/unit_filter_assembler.hpp>
41#include <kernel/global/gate.hpp>
42#include <kernel/global/muxer.hpp>
43#include <kernel/global/vector.hpp>
44#include <kernel/global/matrix.hpp>
45#include <kernel/global/filter.hpp>
46#include <kernel/global/mean_filter.hpp>
47#include <kernel/global/transfer.hpp>
48
49#include <control/domain/domain_control.hpp>
50
51namespace FEAT
52{
53 namespace Control
54 {
55 template<
56 int dim_,
57 typename DataType_ = Real,
58 typename IndexType_ = Index,
59 typename ScalarMatrix_ = LAFEM::SparseMatrixCSR<DataType_, IndexType_>,
60 typename TransferMatrix_ = LAFEM::SparseMatrixCSR<DataType_, IndexType_> >
62 {
63 static_assert(std::is_same<DataType_, typename ScalarMatrix_::DataType>::value, "DataType mismatch!");
64 static_assert(std::is_same<IndexType_, typename ScalarMatrix_::IndexType>::value, "IndexType mismatch!");
65
66 // basic types
67 static constexpr int dim = dim_;
68 typedef DataType_ DataType;
69 typedef IndexType_ IndexType;
70
71 // define local matrix types
72 typedef ScalarMatrix_ LocalScalarMatrix;
77
78 // define local vector types
79 typedef typename LocalScalarMatrix::VectorTypeR LocalScalarVector;
81 typedef LocalScalarVector LocalPresVector;
83
84 // define local transfer matrix types
85 typedef TransferMatrix_ LocalScalarTransferMatrix;
87 typedef TransferMatrix_ LocalPresTransferMatrix;
89
90 // define local transfer types
94
95 // define mirror types
100
101 // define gates
105
106 // define muxers
110
111 // define global vector types
115
116 // define global matrix types
122
123 // define global transfer types
127
128 /* ***************************************************************************************** */
129
130 // gates
131 VeloGate gate_velo;
132 PresGate gate_pres;
133 SystemGate gate_sys;
134
137 PresMuxer coarse_muxer_pres;
138 SystemMuxer coarse_muxer_sys;
139
140 // (global) matrices
141 GlobalSystemMatrix matrix_sys;
142 GlobalMatrixBlockA matrix_a;
143 GlobalMatrixBlockB matrix_b;
144 GlobalMatrixBlockD matrix_d;
145 GlobalSchurMatrix matrix_s;
146
149 GlobalPresTransfer transfer_pres;
150 GlobalSystemTransfer transfer_sys;
151
153 matrix_sys(&gate_sys, &gate_sys),
154 matrix_a(&gate_velo, &gate_velo),
155 matrix_b(&gate_velo, &gate_pres),
156 matrix_d(&gate_pres, &gate_velo),
157 matrix_s(&gate_pres, &gate_pres),
159 transfer_pres(&coarse_muxer_pres),
160 transfer_sys(&coarse_muxer_sys)
161 {
162 }
163
164 // no copies, no problems
166 StokesPowerSystemLevel& operator=(const StokesPowerSystemLevel&) = delete;
167
169 {
170 }
171
172 void compile_system_transfer()
173 {
174 // clone content into our global transfer matrix
175 transfer_sys.get_mat_prol().template at<0,0>().clone(transfer_velo.get_mat_prol(), LAFEM::CloneMode::Shallow);
176 transfer_sys.get_mat_rest().template at<0,0>().clone(transfer_velo.get_mat_rest(), LAFEM::CloneMode::Shallow);
177 transfer_sys.get_mat_prol().template at<1,1>().clone(transfer_pres.get_mat_prol(), LAFEM::CloneMode::Shallow);
178 transfer_sys.get_mat_rest().template at<1,1>().clone(transfer_pres.get_mat_rest(), LAFEM::CloneMode::Shallow);
179 transfer_sys.get_mat_trunc().template at<0,0>().clone(transfer_velo.get_mat_trunc(), LAFEM::CloneMode::Shallow);
180 transfer_sys.get_mat_trunc().template at<1,1>().clone(transfer_pres.get_mat_trunc(), LAFEM::CloneMode::Shallow);
181 transfer_sys.compile();
182 }
183
184 void compile_system_matrix()
185 {
186 matrix_sys.local().block_a() = matrix_a.local().clone(LAFEM::CloneMode::Shallow);
187 matrix_sys.local().block_b() = matrix_b.local().clone(LAFEM::CloneMode::Shallow);
188 matrix_sys.local().block_d() = matrix_d.local().clone(LAFEM::CloneMode::Shallow);
189 }
190
191 template<typename D_, typename I_, typename SM_, typename TM_>
192 void convert(const StokesPowerSystemLevel<dim_, D_, I_, SM_, TM_> & other)
193 {
194 gate_velo.convert(other.gate_velo);
195 gate_pres.convert(other.gate_pres);
196 gate_sys.convert(other.gate_sys);
197
198 coarse_muxer_velo.convert(other.coarse_muxer_velo);
199 coarse_muxer_pres.convert(other.coarse_muxer_pres);
200 coarse_muxer_sys.convert(other.coarse_muxer_sys);
201
202 matrix_a.convert(&gate_velo, &gate_velo, other.matrix_a);
203 matrix_b.convert(&gate_velo, &gate_pres, other.matrix_b);
204 matrix_d.convert(&gate_pres, &gate_velo, other.matrix_d);
205 matrix_s.convert(&gate_pres, &gate_pres, other.matrix_s);
206
207 compile_system_matrix();
208
209 compile_system_transfer();
210 }
211
213 template<typename DomainLevel_>
215 {
216 const auto& dom_level = virt_dom_lvl.level();
217 const auto& dom_layer = virt_dom_lvl.layer();
218 const auto& space_velo = dom_level.space_velo;
219 const auto& space_pres = dom_level.space_pres;
220
221 // set the gate comm
222 this->gate_velo.set_comm(dom_layer.comm_ptr());
223 this->gate_pres.set_comm(dom_layer.comm_ptr());
224 this->gate_sys.set_comm(dom_layer.comm_ptr());
225
226 // loop over all ranks
227 for(Index i(0); i < dom_layer.neighbor_count(); ++i)
228 {
229 int rank = dom_layer.neighbor_rank(i);
230
231 // try to find our halo
232 const auto* halo = dom_level.find_halo_part(rank);
233 XASSERT(halo != nullptr);
234
235 // assemble the velocity components mirror
236 ScalarMirror mirror_velo_comp;
237 Assembly::MirrorAssembler::assemble_mirror(mirror_velo_comp, space_velo, *halo);
238
239 // create a velocity mirror
240 VeloMirror mirror_velo(mirror_velo_comp.clone());
241
242 // create (empty) pressure mirror
243 PresMirror mirror_pres;
244 Assembly::MirrorAssembler::assemble_mirror(mirror_pres, space_pres, *halo);
245
246 // create a system mirror
247 SystemMirror mirror_sys(mirror_velo.clone(), mirror_pres.clone());
248
249 // push mirrors into gates
250 if(!mirror_velo.empty())
251 this->gate_velo.push(rank, std::move(mirror_velo));
252 if(!mirror_pres.empty())
253 this->gate_pres.push(rank, std::move(mirror_pres));
254 if(!mirror_sys.empty())
255 this->gate_sys.push(rank, std::move(mirror_sys));
256 }
257
258 // create local template vectors
259 LocalVeloVector tmpl_v(space_velo.get_num_dofs());
260 LocalPresVector tmpl_p(space_pres.get_num_dofs());
261 LocalSystemVector tmpl_s(tmpl_v.clone(), tmpl_p.clone());
262
263 // compile gates
264 this->gate_velo.compile(std::move(tmpl_v));
265 this->gate_pres.compile(std::move(tmpl_p));
266 this->gate_sys.compile(std::move(tmpl_s));
267 }
268
269 template<typename DomainLevel_>
270 void assemble_coarse_muxers(const Domain::VirtualLevel<DomainLevel_>& virt_lvl_coarse)
271 {
272 // assemble muxer parent
273 if(virt_lvl_coarse.is_parent())
274 {
275 XASSERT(virt_lvl_coarse.is_child());
276
277 const auto& layer_c = virt_lvl_coarse.layer_c();
278 const DomainLevel_& level_p = virt_lvl_coarse.level_p();
279
280 // loop over all children
281 for(Index i(0); i < layer_c.child_count(); ++i)
282 {
283 const auto* child = level_p.find_patch_part(int(i));
284 XASSERT(child != nullptr);
285 SystemMirror child_mirror_sys;
286 VeloMirror& child_mirror_v = child_mirror_sys.template at<0>();
287 PresMirror& child_mirror_p = child_mirror_sys.template at<1>();
288 Assembly::MirrorAssembler::assemble_mirror(child_mirror_v._sub_mirror, level_p.space_velo, *child);
289 Assembly::MirrorAssembler::assemble_mirror(child_mirror_p, level_p.space_pres, *child);
290 this->coarse_muxer_velo.push_child(child_mirror_v.clone(LAFEM::CloneMode::Shallow));
291 this->coarse_muxer_pres.push_child(child_mirror_p.clone(LAFEM::CloneMode::Shallow));
292 this->coarse_muxer_sys.push_child(std::move(child_mirror_sys));
293 }
294 }
295
296 // assemble muxer child
297 if(virt_lvl_coarse.is_child())
298 {
299 const auto& layer_c = virt_lvl_coarse.layer_c();
300 const DomainLevel_& level_c = virt_lvl_coarse.level_c();
301
302 SystemMirror parent_mirror_sys;
303 VeloMirror& parent_mirror_v = parent_mirror_sys.template at<0>();
304 PresMirror& parent_mirror_p = parent_mirror_sys.template at<1>();
305
306 // manually set up an identity gather/scatter matrix
307 {
308 Index n = level_c.space_velo.get_num_dofs();
309 parent_mirror_v._sub_mirror = ScalarMirror(n, n);
310 auto* idx = parent_mirror_v._sub_mirror.indices();
311 for(Index i(0); i < n; ++i)
312 idx[i] = i;
313 }
314 {
315 Index n = level_c.space_pres.get_num_dofs();
316 parent_mirror_p = ScalarMirror(n, n);
317 auto* idx = parent_mirror_p.indices();
318 for(Index i(0); i < n; ++i)
319 idx[i] = i;
320 }
321
322 // set parent and sibling comms
323 this->coarse_muxer_velo.set_parent(
324 layer_c.sibling_comm_ptr(),
325 layer_c.get_parent_rank(),
326 parent_mirror_v.clone(LAFEM::CloneMode::Shallow)
327 );
328 this->coarse_muxer_pres.set_parent(
329 layer_c.sibling_comm_ptr(),
330 layer_c.get_parent_rank(),
331 parent_mirror_p.clone(LAFEM::CloneMode::Shallow)
332 );
333 this->coarse_muxer_sys.set_parent(
334 layer_c.sibling_comm_ptr(),
335 layer_c.get_parent_rank(),
336 std::move(parent_mirror_sys)
337 );
338
339 // compile muxer
340 LocalVeloVector tmpl_v(level_c.space_velo.get_num_dofs());
341 LocalPresVector tmpl_p(level_c.space_pres.get_num_dofs());
342 LocalSystemVector tmpl_s(tmpl_v.clone(), tmpl_p.clone());
343 this->coarse_muxer_velo.compile(tmpl_v);
344 this->coarse_muxer_pres.compile(tmpl_p);
345 this->coarse_muxer_sys.compile(tmpl_s);
346 }
347 }
348
349 template<typename DomainLevel_, typename Cubature_>
350 void assemble_velocity_transfer(
351 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_fine,
352 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_coarse,
353 const Cubature_& cubature)
354 {
355 // get fine and coarse domain levels
356 const DomainLevel_& level_f = *virt_lvl_fine;
357 const DomainLevel_& level_c = virt_lvl_coarse.is_child() ? virt_lvl_coarse.level_c() : *virt_lvl_coarse;
358
359 const auto& space_f = level_f.space_velo;
360 const auto& space_c = level_c.space_velo;
361
362 // get local transfer operator
363 LocalVeloTransfer& loc_trans = this->transfer_velo.local();
364
365 // get local transfer matrices
366 LocalVeloTransferMatrix& loc_prol_v = loc_trans.get_mat_prol();
367 LocalVeloTransferMatrix& loc_rest_v = loc_trans.get_mat_rest();
368
369 // get the matrix blocks
370 LocalScalarTransferMatrix& loc_prol_vx = loc_prol_v.get(0,0);
371 LocalScalarTransferMatrix& loc_rest_vx = loc_rest_v.get(0,0);
372
373 // assemble structure?
374 if(loc_prol_vx.empty())
375 {
376 Assembly::SymbolicAssembler::assemble_matrix_2lvl(loc_prol_vx, space_f, space_c);
377
378 for(int i(1); i < loc_prol_v.num_row_blocks; ++i)
379 loc_prol_v.get(i,i) = loc_prol_vx.clone(LAFEM::CloneMode::Layout);
380 }
381
382 // get local velocity weight vector
383 LocalVeloVector loc_vec_weight = loc_prol_v.create_vector_l();
384
385 // get local weight vector components
386 LocalScalarVector& loc_vec_wx = loc_vec_weight.get(0);
387
388 // assemble prolongation matrix
389 {
390 loc_prol_vx.format();
391 loc_vec_weight.format();
392
393 // assemble prolongation matrix
394 Assembly::GridTransfer::assemble_prolongation(loc_prol_vx, loc_vec_wx, space_f, space_c, cubature);
395
396 // synchronize weight vector
397 for(int i(1); i < loc_vec_weight.num_blocks; ++i)
398 loc_vec_weight.get(i).copy(loc_vec_wx);
399
400 this->gate_velo.sync_0(loc_vec_weight);
401
402 // invert components
403 loc_vec_weight.component_invert(loc_vec_weight);
404
405 // scale prolongation matrix
406 loc_prol_vx.scale_rows(loc_prol_vx, loc_vec_wx);
407
408 // copy and transpose
409 loc_rest_vx = loc_prol_vx.transpose();
410 for(int i(1); i < loc_prol_v.num_row_blocks; ++i)
411 {
412 loc_prol_v.get(i,i) = loc_prol_vx.clone(LAFEM::CloneMode::Shallow);
413 loc_rest_v.get(i,i) = loc_rest_vx.clone(LAFEM::CloneMode::Shallow);
414 }
415 }
416
417 // compile velocity transfer
418 this->transfer_velo.compile();
419 }
420
421 template<typename DomainLevel_, typename Cubature_>
422 void assemble_pressure_transfer(
423 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_fine,
424 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_coarse,
425 const Cubature_& cubature)
426 {
427 // get fine and coarse domain levels
428 const DomainLevel_& level_f = *virt_lvl_fine;
429 const DomainLevel_& level_c = virt_lvl_coarse.is_child() ? virt_lvl_coarse.level_c() : *virt_lvl_coarse;
430
431 const auto& space_f = level_f.space_pres;
432 const auto& space_c = level_c.space_pres;
433
434 // get local transfer operator
435 LocalPresTransfer& loc_trans = this->transfer_pres.local();
436
437 // get local transfer matrices
438 LocalPresTransferMatrix& loc_prol_p = loc_trans.get_mat_prol();
439 LocalPresTransferMatrix& loc_rest_p = loc_trans.get_mat_rest();
440
441 // assemble structure?
442 if(loc_prol_p.empty())
443 {
444 Assembly::SymbolicAssembler::assemble_matrix_2lvl(loc_prol_p, space_f, space_c);
445 }
446
447 LocalPresVector loc_vec_weight = loc_prol_p.create_vector_l();
448
449 // assemble prolongation matrix
450 {
451 loc_prol_p.format();
452 loc_vec_weight.format();
453
454 // assemble prolongation matrix
455 Assembly::GridTransfer::assemble_prolongation(loc_prol_p, loc_vec_weight, space_f, space_c, cubature);
456
457 // synchronize weight vector
458 this->gate_pres.sync_0(loc_vec_weight);
459
460 // invert components
461 loc_vec_weight.component_invert(loc_vec_weight);
462
463 // scale prolongation matrix
464 loc_prol_p.scale_rows(loc_prol_p, loc_vec_weight);
465
466 // copy and transpose
467 loc_rest_p = loc_prol_p.transpose();
468 }
469
470 // compile pressure transfer
471 this->transfer_pres.compile();
472 }
473
474 template<typename DomainLevel_, typename Cubature_>
475 void assemble_transfers(
476 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_fine,
477 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_coarse,
478 const Cubature_& cubature)
479 {
480 this->assemble_velocity_transfer(virt_lvl_fine, virt_lvl_coarse, cubature);
481 this->assemble_pressure_transfer(virt_lvl_fine, virt_lvl_coarse, cubature);
482 this->compile_system_transfer();
483 }
484
485 template<typename DomainLevel_, typename Cubature_>
486 void assemble_velocity_truncation(
487 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_fine,
488 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_coarse,
489 const Cubature_& cubature,
490 const StokesPowerSystemLevel* sys_lvl_coarse = nullptr)
491 {
492 // if the coarse level is a parent, then we need the coarse system level
493 XASSERT((sys_lvl_coarse != nullptr) || !virt_lvl_coarse.is_parent());
494
495 // get fine and coarse domain levels
496 const DomainLevel_& level_f = *virt_lvl_fine;
497 const DomainLevel_& level_c = virt_lvl_coarse.is_child() ? virt_lvl_coarse.level_c() : *virt_lvl_coarse;
498
499 const auto& space_f = level_f.space_velo;
500 const auto& space_c = level_c.space_velo;
501
502 // get local transfer operator
503 LocalVeloTransfer& loc_trans = this->transfer_velo.local();
504
505 // get local transfer matrices
506 const LocalVeloTransferMatrix& loc_rest_v = loc_trans.get_mat_rest();
507 LocalVeloTransferMatrix& loc_trunc_v = loc_trans.get_mat_trunc();
508
509 // get the matrix blocks
510 const LocalScalarTransferMatrix& loc_rest_vx = loc_rest_v.get(0,0);
511 LocalScalarTransferMatrix& loc_trunc_vx = loc_trunc_v.get(0,0);
512
513 // restriction matrix must be already assembled
514 XASSERTM(loc_rest_vx.size() > Index(0), "you need to call 'assemble_velocity_transfer' first");
515
516 // clone sparsity pattern of restriction matrix
517 loc_trunc_vx = loc_rest_vx.clone(LAFEM::CloneMode::Layout);
518
519 // create local weight vector
520 LocalVeloVector loc_vec_weight = loc_rest_v.create_vector_l();
521
522 // get local weight vector component
523 LocalScalarVector& loc_vec_wx = loc_vec_weight.get(0);
524
525 // format
526 loc_trunc_vx.format();
527 loc_vec_wx.format();
528
529 // assemble truncation matrix
530 Assembly::GridTransfer::assemble_truncation(loc_trunc_vx, loc_vec_wx, space_f, space_c, cubature);
531
532 // expand weight vector
533 for(int i(1); i < loc_vec_weight.num_blocks; ++i)
534 loc_vec_weight.get(i).copy(loc_vec_wx);
535
536 // We now need to synchronize the weight vector in analogy to the prolongation matrix assembly.
537 // Note that the weight vector is now a coarse-level vector, so we need to synchronize over
538 // the coarse-level gate. This may be a bit more complicated if the coarse level is a ghost
539 // level, as in this case we have to join/split around the synch operation.
540
541 // synchronize weight vector using the muxer/gate
542 if(!virt_lvl_coarse.is_child())
543 {
544 // The coarse level is a simple (non-child) level that exists on all processes,
545 // so simply synch over the coarse-level gate:
546 sys_lvl_coarse->gate_velo.sync_0(loc_vec_weight);
547 }
548 else if(virt_lvl_coarse.is_parent())
549 {
550 // The coarse level is a child level and this is one of the parent processes which contain
551 // the coarse-level gate. So we first need to join the weight vector onto the parent processes
552 // first, then synch that joined vector over the parent gate and finally split the result
553 // to all child processes -- this "emulates" a synch over the (non-existent) coarse-level
554 // child gate, which is what we actually require here...
555
556 // create temporary vector on parent partitioning
557 LocalVeloVector loc_tmp = sys_lvl_coarse->gate_velo._freqs.clone(LAFEM::CloneMode::Allocate);
558
559 // join child weights over muxer
560 this->coarse_muxer_velo.join(loc_vec_weight, loc_tmp);
561
562 // sync over coarse gate
563 sys_lvl_coarse->gate_velo.sync_0(loc_tmp);
564
565 // split over muxer
566 this->coarse_muxer_velo.split(loc_vec_weight, loc_tmp);
567 }
568 else // ghost
569 {
570 // The coarse level is a ghost level, i.e. a child but not a parent. In this case, we
571 // only have to participate in the join/send operations of the muxer, which are part
572 // of the operations executed on the parents handled by the else-if case above.
573
574 this->coarse_muxer_velo.join_send(loc_vec_weight);
575
576 // parent performs sync over its gate here (see above else-if)
577
578 this->coarse_muxer_velo.split_recv(loc_vec_weight);
579 }
580
581 // invert components
582 loc_vec_weight.component_invert(loc_vec_weight);
583
584 // scale reduction matrix
585 loc_trunc_vx.scale_rows(loc_trunc_vx, loc_vec_wx);
586
587 // clone for remaining components
588 for(int i(1); i < loc_trunc_v.num_row_blocks; ++i)
589 loc_trunc_v.get(i,i) = loc_trunc_vx.clone(LAFEM::CloneMode::Shallow);
590 }
591
592 template<typename DomainLevel_, typename Cubature_>
593 void assemble_pressure_truncation(
594 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_fine,
595 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_coarse,
596 const Cubature_& cubature,
597 const StokesPowerSystemLevel* sys_lvl_coarse = nullptr)
598 {
599 // if the coarse level is a parent, then we need the coarse system level
600 XASSERT((sys_lvl_coarse != nullptr) || !virt_lvl_coarse.is_parent());
601
602 // get fine and coarse domain levels
603 const DomainLevel_& level_f = *virt_lvl_fine;
604 const DomainLevel_& level_c = virt_lvl_coarse.is_child() ? virt_lvl_coarse.level_c() : *virt_lvl_coarse;
605
606 const auto& space_f = level_f.space_pres;
607 const auto& space_c = level_c.space_pres;
608
609 // get local transfer operator
610 LocalPresTransfer& loc_trans = this->transfer_pres.local();
611
612 // get local transfer matrices
613 const LocalPresTransferMatrix& loc_rest = loc_trans.get_mat_rest();
614 LocalPresTransferMatrix& loc_trunc = loc_trans.get_mat_trunc();
615
616 // restriction matrix must be already assembled
617 XASSERTM(loc_rest.size() > Index(0), "you need to call 'assemble_prescity_transfer' first");
618
619 // clone sparsity pattern of restriction matrix
620 loc_trunc = loc_rest.clone(LAFEM::CloneMode::Layout);
621
622 // create local weight vector
623 LocalPresVector loc_vec_weight = loc_trunc.create_vector_l();
624
625 // format
626 loc_trunc.format();
627 loc_vec_weight.format();
628
629 // assemble truncation matrix
630 Assembly::GridTransfer::assemble_truncation(loc_trunc, loc_vec_weight, space_f, space_c, cubature);
631
632 // We now need to synchronize the weight vector in analogy to the prolongation matrix assembly.
633 // Note that the weight vector is now a coarse-level vector, so we need to synchronize over
634 // the coarse-level gate. This may be a bit more complicated if the coarse level is a ghost
635 // level, as in this case we have to join/split around the synch operation.
636
637 // synchronize weight vector using the muxer/gate
638 if(!virt_lvl_coarse.is_child())
639 {
640 // The coarse level is a simple (non-child) level that exists on all processes,
641 // so simply synch over the coarse-level gate:
642 sys_lvl_coarse->gate_pres.sync_0(loc_vec_weight);
643 }
644 else if(virt_lvl_coarse.is_parent())
645 {
646 // The coarse level is a child level and this is one of the parent processes which contain
647 // the coarse-level gate. So we first need to join the weight vector onto the parent processes
648 // first, then synch that joined vector over the parent gate and finally split the result
649 // to all child processes -- this "emulates" a synch over the (non-existent) coarse-level
650 // child gate, which is what we actually require here...
651
652 // create temporary vector on parent partitioning
653 LocalPresVector loc_tmp = sys_lvl_coarse->gate_pres._freqs.clone(LAFEM::CloneMode::Allocate);
654
655 // join child weights over muxer
656 this->coarse_muxer_pres.join(loc_vec_weight, loc_tmp);
657
658 // sync over coarse gate
659 sys_lvl_coarse->gate_pres.sync_0(loc_tmp);
660
661 // split over muxer
662 this->coarse_muxer_pres.split(loc_vec_weight, loc_tmp);
663 }
664 else // ghost
665 {
666 // The coarse level is a ghost level, i.e. a child but not a parent. In this case, we
667 // only have to participate in the join/send operations of the muxer, which are part
668 // of the operations executed on the parents handled by the else-if case above.
669
670 this->coarse_muxer_pres.join_send(loc_vec_weight);
671
672 // parent performs sync over its gate here (see above else-if)
673
674 this->coarse_muxer_pres.split_recv(loc_vec_weight);
675 }
676
677 // invert components
678 loc_vec_weight.component_invert(loc_vec_weight);
679
680 // scale reduction matrix
681 loc_trunc.scale_rows(loc_trunc, loc_vec_weight);
682 }
683
684 template<typename DomainLevel_, typename Cubature_>
685 void assemble_truncations(
686 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_fine,
687 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_coarse,
688 const Cubature_& cubature,
689 const StokesPowerSystemLevel* sys_lvl_coarse = nullptr)
690 {
691 this->assemble_velocity_truncation(virt_lvl_fine, virt_lvl_coarse, cubature, sys_lvl_coarse);
692 this->assemble_pressure_truncation(virt_lvl_fine, virt_lvl_coarse, cubature, sys_lvl_coarse);
693 this->compile_system_transfer();
694 }
695
696 template<typename Trafo_, typename SpaceVelo_, typename Cubature_>
697 void assemble_velocity_laplace_matrix(Assembly::DomainAssembler<Trafo_>& dom_asm,
698 const SpaceVelo_& space_velo, const Cubature_& cubature, const DataType nu = DataType(1))
699 {
700 // get the local matrix A
701 LocalMatrixBlockA& mat_loc_a = this->matrix_a.local();
702
703 // get the diagonal blocks
704 LocalScalarMatrix& mat_loc_a1 = mat_loc_a.get(0,0);
705
706 // assemble matrix structure?
707 if(mat_loc_a1.empty())
708 {
709 // assemble matrix structure for A11
711
712 // clone layout for A22,...,Ann
713 for(int i(1); i < mat_loc_a.num_row_blocks; ++i)
714 mat_loc_a.get(i,i) = mat_loc_a1.clone(LAFEM::CloneMode::Layout);
715 }
716
717 // assemble velocity laplace matrix
718 {
719 mat_loc_a1.format();
720 Assembly::Common::LaplaceOperator laplace_op;
721 Assembly::assemble_bilinear_operator_matrix_1(dom_asm, mat_loc_a1, laplace_op, space_velo, cubature, nu);
722 }
723
724 // copy data into A22,...,Ann
725 for(int i(1); i < mat_loc_a.num_row_blocks; ++i)
726 mat_loc_a.get(i,i).copy(mat_loc_a1);
727 }
728
729 template<typename Trafo_, typename SpaceVelo_, typename SpacePres_, typename Cubature_>
731 const SpaceVelo_& space_velo, const SpacePres_& space_pres, const Cubature_& cubature)
732 {
733 // get the local matrix B and D
734 LocalMatrixBlockB& mat_loc_b = this->matrix_b.local();
735 LocalMatrixBlockD& mat_loc_d = this->matrix_d.local();
736
737 // get the matrix blocks
738 LocalScalarMatrix& mat_loc_b1 = mat_loc_b.get(0,0);
739
740 // assemble matrix structure?
741 if(mat_loc_b1.empty())
742 {
743 Assembly::SymbolicAssembler::assemble_matrix_std2(mat_loc_b1, space_velo, space_pres);
744 for(int i(1); i < mat_loc_b.num_row_blocks; ++i)
745 mat_loc_b.get(i,0) = mat_loc_b1.clone(LAFEM::CloneMode::Layout);
746 }
747
748 // assemble pressure gradient matrices
749 for(int ider(0); ider < mat_loc_b.num_row_blocks; ++ider)
750 {
751 LocalScalarMatrix& mat_loc_bi = mat_loc_b.get(ider,0);
752 mat_loc_bi.format();
754 Assembly::assemble_bilinear_operator_matrix_2(dom_asm, mat_loc_bi, deri, space_velo, space_pres, cubature, -DataType(1));
755 }
756
757 // assemble velocity divergence matrices
759 for(int i(0); i < mat_loc_b.num_row_blocks; ++i)
760 mat_loc_d.get(0,i) = mat_loc_b.get(i,0).transpose();
761 }
762 }; // struct StokesPowerSystemLevel<...>
763
764 template<
765 int dim_,
766 typename DataType_ = Real,
767 typename IndexType_ = Index,
768 typename ScalarMatrix_ = LAFEM::SparseMatrixCSR<DataType_, IndexType_> >
770 public StokesPowerSystemLevel<dim_, DataType_, IndexType_, ScalarMatrix_>
771 {
773
774 // define local filter types
779
780 // define global filter types
784
785 // (global) filters
786 GlobalSystemFilter filter_sys;
787 GlobalVeloFilter filter_velo;
788 GlobalPresFilter filter_pres;
789
791 std::size_t bytes() const
792 {
793 return this->matrix_sys.local().bytes () + this->matrix_s.local().bytes() + filter_sys.local().bytes();
794 }
795
796 void compile_system_filter()
797 {
798 filter_sys.local().template at<0>() = filter_velo.local().clone(LAFEM::CloneMode::Shallow);
799 filter_sys.local().template at<1>() = filter_pres.local().clone(LAFEM::CloneMode::Shallow);
800 }
801
805 template<typename D_, typename I_, typename SM_>
807 {
808 BaseClass::convert(other);
809 filter_velo.convert(other.filter_velo);
810 filter_pres.convert(other.filter_pres);
811
812 compile_system_filter();
813 }
814 }; // struct StokesPowerUnitVeloNonePresSystemLevel<...>
815
816
817 template<
818 int dim_,
819 typename DataType_ = Real,
820 typename IndexType_ = Index,
821 typename ScalarMatrix_ = LAFEM::SparseMatrixCSR<DataType_, IndexType_> >
823 public StokesPowerSystemLevel<dim_, DataType_, IndexType_, ScalarMatrix_>
824 {
826
827 // define local filter types
831 //typedef LAFEM::NoneFilter<DataType_, IndexType_> LocalPresFilter;
833
834 // define global filter types
838
839 // (global) filters
840 GlobalSystemFilter filter_sys;
841 GlobalVeloFilter filter_velo;
842 GlobalPresFilter filter_pres;
843
845 std::size_t bytes() const
846 {
847 return this->matrix_sys.local().bytes () + this->matrix_s.local().bytes() + filter_sys.local().bytes();
848 }
849
850 void compile_system_filter()
851 {
852 filter_sys.local().template at<0>() = filter_velo.local().clone(LAFEM::CloneMode::Shallow);
853 filter_sys.local().template at<1>() = filter_pres.local().clone(LAFEM::CloneMode::Shallow);
854 }
855
859 template<typename D_, typename I_, typename SM_>
861 {
862 BaseClass::convert(other);
863 filter_velo.convert(other.filter_velo);
864 filter_pres.convert(other.filter_pres);
865
866 compile_system_filter();
867 }
868
869 template<typename SpacePres_, typename Cubature_>
870 void assemble_pressure_mean_filter(const SpacePres_& space_pres, const Cubature_& cubature)
871 {
872 // get our local pressure filter
873 LocalPresFilter& fil_loc_p = this->filter_pres.local();
874
875 // create two global vectors
876 typename BaseClass::GlobalPresVector vec_glob_v(&this->gate_pres), vec_glob_w(&this->gate_pres);
877
878 // fetch the local vectors
879 typename BaseClass::LocalPresVector& vec_loc_v = vec_glob_v.local();
880 typename BaseClass::LocalPresVector& vec_loc_w = vec_glob_w.local();
881
882 // fetch the frequency vector of the pressure gate
883 typename BaseClass::LocalPresVector& vec_loc_f = this->gate_pres._freqs;
884
885 // assemble the mean filter
886 Assembly::MeanFilterAssembler::assemble(vec_loc_v, vec_loc_w, space_pres, cubature);
887
888 // synchronize the vectors
889 vec_glob_v.sync_1();
890 vec_glob_w.sync_0();
891
892 // build the mean filter
893 fil_loc_p = LocalPresFilter(vec_loc_v.clone(), vec_loc_w.clone(), vec_loc_f.clone(), this->gate_pres.get_comm());
894 }
895 }; // struct StokesPowerUnitVeloNonePresSystemLevel<...>
896 } // namespace Control
897} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
Test-Derivative operator implementation.
Domain Integral Assembler class template.
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(LAFEM::DenseVector< DataType_, IndexType_ > &vec_prim, LAFEM::DenseVector< DataType_, IndexType_ > &vec_dual, const Space_ &space, const String &cubature_name)
Assembles an integral mean filter.
static void assemble_mirror(LAFEM::VectorMirror< DataType_, IndexType_ > &vec_mirror, const Space_ &space, const MeshPart_ &mesh_part)
Assembles a VectorMirror from a space and a mesh-part.
static void assemble_matrix_std1(MatrixType_ &matrix, const Space_ &space)
Assembles a standard matrix structure from a single space.
static void assemble_matrix_std2(MatrixType_ &matrix, const TestSpace_ &test_space, const TrialSpace_ &trial_space)
Assembles a standard matrix structure from a test-trial-space pair.
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.
Virtual Domain Level class template.
Global Filter wrapper class template.
Definition: filter.hpp:21
Global gate implementation.
Definition: gate.hpp:51
void compile(LocalVector_ &&vector)
Compiles the gate to finish its setup.
Definition: gate.hpp:296
void sync_0(LocalVector_ &vector) const
Synchronizes a type-0 vector, resulting in a type-1 vector.
Definition: gate.hpp:408
void convert(const Gate< LVT2_, MT2_ > &other)
Conversion function for same vector container type but with different MDI-Type.
Definition: gate.hpp:191
void push(int rank, Mirror_ &&mirror)
Adds a mirror for a neighbor process.
Definition: gate.hpp:274
void set_comm(const Dist::Comm *comm_)
Sets the communicator for this gate.
Definition: gate.hpp:149
LocalVector_ _freqs
frequency vector
Definition: gate.hpp:75
Global Matrix wrapper class template.
Definition: matrix.hpp:40
LocalMatrix_ & local()
Returns a reference to the internal local LAFEM matrix object.
Definition: matrix.hpp:126
Mean Filter class template.
Definition: mean_filter.hpp:23
MeanFilter clone(LAFEM::CloneMode clone_mode=LAFEM::CloneMode::Deep) const
Creates a clone of itself.
Global multiplexer/demultiplexer implementation.
Definition: muxer.hpp:68
void join_send(const LocalVector_ &vec_src) const
Sends a join operation to the parent process.
Definition: muxer.hpp:375
void compile(const LocalVector_ &vec_tmp_)
Compiles the muxer.
Definition: muxer.hpp:334
void convert(const Muxer< LVT2_, MT2_ > &other)
Conversion function for same vector container type but with different MDI-Type.
Definition: muxer.hpp:155
void split_recv(LocalVector_ &vec_trg) const
Receives a split operation from the parent process.
Definition: muxer.hpp:449
void join(const LocalVector_ &vec_src, LocalVector_ &vec_trg) const
Performs a join operation on the parent process.
Definition: muxer.hpp:401
void push_child(Mirror_ &&child_mirror)
Adds a child rank and mirror for a parent process.
Definition: muxer.hpp:313
void set_parent(const Dist::Comm *sibling_comm_, int parent_rank, Mirror_ &&parent_mirror)
Sets the sibling communicator.
Definition: muxer.hpp:277
void split(LocalVector_ &vec_trg, const LocalVector_ &vec_src) const
Performs a split operation on the parent process.
Definition: muxer.hpp:476
Global grid-transfer operator class template.
Definition: transfer.hpp:23
Transfer clone(LAFEM::CloneMode clone_mode=LAFEM::CloneMode::Weak) const
Creates a clone of this object.
Definition: transfer.hpp:125
LocalTransfer_ & local()
Definition: transfer.hpp:131
Global vector wrapper class template.
Definition: vector.hpp:68
None Filter class template.
Definition: none_filter.hpp:29
NoneFilter clone(CloneMode=CloneMode::Deep) const
Creates a (empty) clone of itself.
Definition: none_filter.hpp:51
Power-Col-Matrix meta class template.
PowerColMatrix clone(LAFEM::CloneMode mode=LAFEM::CloneMode::Weak) const
Creates and returns a deep copy of this matrix.
static constexpr int num_row_blocks
number of row blocks (vertical size)
SubMatrixType & get(int i, int j)
Returns a sub-matrix block.
Power-Diag-Matrix meta class template.
SubMatrixType & get(int i, int j)
Returns a sub-matrix block.
PowerDiagMatrix clone(LAFEM::CloneMode mode=LAFEM::CloneMode::Weak) const
Creates and returns a deep copy of this matrix.
PowerVector meta-filter class template.
PowerFilter clone(CloneMode clone_mode=CloneMode::Deep) const
Creates a clone of itself.
PowerVector meta-mirror class template.
PowerMirror clone(CloneMode clone_mode=CloneMode::Weak) const
Clone operation.
bool empty() const
Checks whether the mirror is empty.
Power-Row-Matrix meta class template.
SubMatrixType & get(int i, int j)
Returns a sub-matrix block.
PowerRowMatrix clone(LAFEM::CloneMode mode=LAFEM::CloneMode::Weak) const
Creates and returns a deep copy of this matrix.
Power-Vector meta class template.
PowerVector clone(LAFEM::CloneMode mode=LAFEM::CloneMode::Weak) const
Creates and returns a copy of this vector.
Saddle-Point matrix meta class template.
MatrixTypeA & block_a()
Returns the sub-matrix block A.
std::size_t bytes() const
Returns the total amount of bytes allocated.
MatrixTypeB & block_b()
Returns the sub-matrix block B.
MatrixTypeD & block_d()
Returns the sub-matrix block D.
CSR based sparse matrix.
Grid-Transfer operator class template.
Definition: transfer.hpp:27
Tuple-Diag-Matrix meta class template.
TupleVector meta-filter class template.
std::size_t bytes() const
Returns the total amount of bytes allocated.
TupleVector meta-mirror class template.
bool empty() const
Checks whether the mirror is empty.
Variadic TupleVector class template.
Unit Filter class template.
Definition: unit_filter.hpp:29
Handles vector prolongation, restriction and serialization.
VectorMirror clone(CloneMode clone_mode=CloneMode::Weak) const
Clone operation.
bool empty() const
Checks whether the mirror is empty.
void assemble_bilinear_operator_matrix_2(DomainAssembler< Trafo_ > &dom_asm, Matrix_ &matrix, const BilOp_ &bilinear_operator, const TestSpace_ &test_space, const TrialSpace_ &trial_space, const String &cubature, const typename Matrix_::DataType alpha=typename Matrix_::DataType(1))
Assembles a bilinear operator into a matrix with different test- and trial-spaces.
void assemble_bilinear_operator_matrix_1(DomainAssembler< Trafo_ > &dom_asm, Matrix_ &matrix, const BilOp_ &bilinear_operator, const Space_ &space, const String &cubature, const typename Matrix_::DataType alpha=typename Matrix_::DataType(1))
Assembles a bilinear operator into a matrix with identical test- and trial-spaces.
@ other
generic/other permutation strategy
FEAT namespace.
Definition: adjactor.hpp:12
double Real
Real data type.
std::uint64_t Index
Index data type.
GlobalVeloTransfer transfer_velo
our global transfer operator
void assemble_gates(const Domain::VirtualLevel< DomainLevel_ > &virt_dom_lvl)
void assemble_grad_div_matrices(Assembly::DomainAssembler< Trafo_ > &dom_asm, const SpaceVelo_ &space_velo, const SpacePres_ &space_pres, const Cubature_ &cubature)
VeloMuxer coarse_muxer_velo
our coarse-level system muxer
std::size_t bytes() const
Returns the total amount of bytes allocated.
void convert(const StokesPowerUnitVeloMeanPresSystemLevel< dim_, D_, I_, SM_ > &other)
Conversion method.
void convert(const StokesPowerUnitVeloNonePresSystemLevel< dim_, D_, I_, SM_ > &other)
Conversion method.
std::size_t bytes() const
Returns the total amount of bytes allocated.