FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
transfer_adaptive_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#pragma once
6
7#include "kernel/adjacency/adjactor.hpp"
8#include "kernel/adjacency/base.hpp"
9#include "kernel/adjacency/graph.hpp"
10#include "kernel/geometry/adaptive_mesh.hpp"
11#include "kernel/geometry/adaptive_mesh_layer.hpp"
13#include <kernel/lafem/dense_vector.hpp>
14#include <kernel/lafem/dense_vector_blocked.hpp>
15#include <kernel/lafem/vector_mirror.hpp>
16#include <kernel/global/gate.hpp>
17#include <kernel/global/transfer.hpp>
18#include <kernel/assembly/symbolic_assembler.hpp>
19#include <kernel/assembly/grid_transfer.hpp>
20
21namespace FEAT::Control::Asm
22{
61 template<typename DomainLevel_, typename SpaceLambda_, typename Transfer_, typename Muxer_, typename Gate_>
62 void asm_transfer_adaptive_scalar(
63 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_f,
64 const Domain::VirtualLevel<DomainLevel_>& virt_lvl_c,
65 const String& cubature, bool trunc, bool shrink,
66 SpaceLambda_&& space_lambda, Transfer_& transfer, const Muxer_& muxer, const Gate_& gate_f, const Gate_& gate_c)
67 {
68 using DataType = typename Transfer_::DataType;
69 using IndexType = typename Transfer_::IndexType;
70 using ScalarVectorType = LAFEM::DenseVector<DataType, IndexType>;
71
72 // get fine and coarse domain levels
73 const DomainLevel_& level_f = *virt_lvl_f;
74 const DomainLevel_& level_c = virt_lvl_c.is_child() ? virt_lvl_c.level_c() : *virt_lvl_c;
75
76 // get fine and coarse spaces
77 const auto& space_f = *space_lambda(level_f);
78 const auto& space_c = *space_lambda(level_c);
79
80 // get local transfer matrices
81 auto& loc_prol = transfer.get_mat_prol();
82 auto& loc_rest = transfer.get_mat_rest();
83 auto& loc_trunc = transfer.get_mat_trunc();
84
85 // assemble structure?
86 if (loc_prol.empty())
87 {
88 if(level_c.mesh_layer && level_f.mesh_layer)
89 {
90 // Both levels are local refinements
91 Geometry::AdaptiveChildMapping<typename DomainLevel_::AdaptiveMeshLayerType> c2f_mapping(*level_c.mesh_layer, *level_f.mesh_layer);
92 Assembly::SymbolicAssembler::assemble_matrix_intermesh(loc_prol, space_f, space_c, c2f_mapping);
93 }
94 else if(!level_c.mesh_layer && level_f.mesh_layer)
95 {
96 // Coarse level is foundation mesh
97 Geometry::FoundationAdaptiveAdjactor<typename DomainLevel_::AdaptiveMeshType> foundation_to_adaptive(level_f.mesh_layer->adaptive_mesh());
98 typename DomainLevel_::AdaptiveMeshLayerType layer_zero(level_f.mesh_layer->adaptive_mesh_ptr(), Geometry::Layer{0});
99 Geometry::AdaptiveChildMapping<typename DomainLevel_::AdaptiveMeshLayerType> zero_to_one(layer_zero, *level_f.mesh_layer);
100
101 Adjacency::CompositeAdjactor adj(foundation_to_adaptive, zero_to_one);
102
103 Assembly::SymbolicAssembler::assemble_matrix_intermesh(loc_prol, space_f, space_c, adj);
104 }
105 else
106 {
107 XASSERT(!level_c.mesh_layer);
108 XASSERT(!level_f.mesh_layer);
109 // Both level are regular refinements
110 Assembly::SymbolicAssembler::assemble_matrix_2lvl(loc_prol, space_f, space_c);
111 }
112 }
113
114 // create local weight vectors
115 auto loc_vec_weight_p = loc_prol.create_vector_l();
116 auto loc_vec_weight_t = loc_prol.create_vector_r();
117
118 // assemble prolongation matrix
119 loc_prol.format();
120 loc_vec_weight_p.format();
121 loc_vec_weight_t.format();
122
123 // if we need a truncation matrix, then compute its sparsity pattern now
124 if(trunc)
125 loc_trunc.transpose(loc_prol);
126
127 // assemble prolongation matrix
128 if(level_c.mesh_layer && level_f.mesh_layer)
129 {
130 // Both levels are local refinements
131 Geometry::AdaptiveChildMapping<typename DomainLevel_::AdaptiveMeshLayerType> c2f_mapping(*level_c.mesh_layer, *level_f.mesh_layer);
132 Assembly::SymbolicAssembler::assemble_matrix_intermesh(loc_prol, space_f, space_c, c2f_mapping);
133
134 Adjacency::Graph f2c_mapping(Adjacency::RenderType::transpose, c2f_mapping);
135
136 Assembly::GridTransfer::assemble_intermesh_transfer(loc_prol, loc_vec_weight_p, space_f, space_c, f2c_mapping, cubature);
137
138 if(trunc)
139 Assembly::GridTransfer::assemble_intermesh_transfer(loc_trunc, loc_vec_weight_t, space_f, space_c, f2c_mapping, cubature);
140 }
141 else if(!level_c.mesh_layer && level_f.mesh_layer)
142 {
143 // Coarse level is foundation mesh
144 Geometry::FoundationAdaptiveAdjactor<typename DomainLevel_::AdaptiveMeshType> foundation_to_adaptive(level_f.mesh_layer->adaptive_mesh());
145 typename DomainLevel_::AdaptiveMeshLayerType layer_zero(level_f.mesh_layer->adaptive_mesh_ptr(), Geometry::Layer{0});
146 Geometry::AdaptiveChildMapping<typename DomainLevel_::AdaptiveMeshLayerType> zero_to_one(layer_zero, *level_f.mesh_layer);
147
148 Adjacency::CompositeAdjactor adj(foundation_to_adaptive, zero_to_one);
149 Adjacency::Graph adj_transpose(Adjacency::RenderType::transpose, adj);
150
151 Assembly::GridTransfer::assemble_intermesh_transfer(loc_prol, loc_vec_weight_p, space_f, space_c, adj_transpose, cubature);
152
153 if(trunc)
154 Assembly::GridTransfer::assemble_intermesh_transfer(loc_trunc, loc_vec_weight_t, space_f, space_c, adj_transpose, cubature);
155 }
156 else
157 {
158 // Both level are regular refinements
159 Assembly::GridTransfer::assemble_prolongation(loc_prol, loc_vec_weight_p, space_f, space_c, cubature);
160 if(trunc)
161 Assembly::GridTransfer::assemble_truncation(loc_trunc, loc_vec_weight_t, space_f, space_c, cubature);
162 }
163
164 // synchronize weight vector using the fine level gate
165 gate_f.sync_0(loc_vec_weight_p);
166
167 // invert components
168 loc_vec_weight_p.component_invert(loc_vec_weight_p);
169
170 // scale prolongation matrix
171 loc_prol.scale_rows(loc_prol, loc_vec_weight_p);
172
173 // shrink prolongation matrix if desired
174 if(shrink)
175 loc_prol.shrink(DataType(1E-3) * loc_prol.max_abs_element());
176
177 // copy and transpose
178 loc_rest = loc_prol.transpose();
179
180 // do we need a truncation operator?
181 if(!trunc)
182 return;
183
184 // We now need to synchronize the weight vector in analogy to the prolongation matrix assembly.
185 // Note that the weight vector is now a coarse-level vector, so we need to synchronize over
186 // the coarse-level gate. This may be a bit more complicated if the coarse level is a ghost
187 // level, as in this case we have to join/split around the sync operation.
188
189 // synchronize weight vector using the muxer/gate
190 if(!virt_lvl_c.is_child())
191 {
192 // The coarse level is a simple (non-child) level that exists on all processes,
193 // so simply sync over the coarse-level gate:
194 gate_c.sync_0(loc_vec_weight_t);
195 }
196 else if(virt_lvl_c.is_parent())
197 {
198 // The coarse level is a child level and this is one of the parent processes which contain
199 // the coarse-level gate. So we first need to join the weight vector onto the parent processes
200 // first, then sync that joined vector over the parent gate and finally split the result
201 // to all child processes -- this "emulates" a sync over the (non-existent) coarse-level
202 // child gate, which is what we actually require here...
203
204 // create temporary vector on parent partitioning
205 ScalarVectorType loc_tmp(gate_c.get_freqs().size());
206
207 // join child weights over muxer
208 muxer.join(loc_vec_weight_t, loc_tmp);
209
210 // sync over coarse gate
211 gate_c.sync_0(loc_tmp);
212
213 // split over muxer
214 muxer.split(loc_vec_weight_t, loc_tmp);
215 }
216 else // ghost
217 {
218 // The coarse level is a ghost level, i.e. a child but not a parent. In this case, we
219 // only have to participate in the join/send operations of the muxer, which are part
220 // of the operations executed on the parents handled by the else-if case above.
221
222 muxer.join_send(loc_vec_weight_t);
223
224 // parent performs sync over its gate here (see above else-if)
225
226 muxer.split_recv(loc_vec_weight_t);
227 }
228
229 // invert components
230 loc_vec_weight_t.component_invert(loc_vec_weight_t);
231
232 // scale prolongation matrix
233 loc_trunc.scale_rows(loc_trunc, loc_vec_weight_t);
234
235 // shrink prolongation matrix if desired
236 if(shrink)
237 loc_trunc.shrink(DataType(1E-3) * loc_trunc.max_abs_element());
238 }
239} // namespace FEAT::Control::Asm
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
FEAT Kernel base header.
static int assemble_intermesh_transfer(Matrix_ &matrix, Vector_ &vector, const TargetSpace_ &space_target, const SourceSpace_ &space_source, const Target2SourceAdjactor_ &trg2src, const String &cubature_name)
Assembles a generic inter-mesh transfer matrix and its corresponding weight vector.
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_intermesh(MatrixType_ &matrix, const TestSpace_ &test_space, const TrialSpace_ &trial_space, const Trial2TestAdjactor_ &trial2test_adjactor)
Assembles a matrix structure from a test-trial-mesh pair defined on different meshes.
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.
@ transpose
Render-Transpose mode.
Intern::Layer Layer
Re-export of layer type.