8#include <kernel/lafem/null_matrix.hpp>
9#include <kernel/lafem/sparse_matrix_bcsr.hpp>
10#include <kernel/lafem/sparse_matrix_csr.hpp>
11#include <kernel/lafem/saddle_point_matrix.hpp>
12#include <kernel/lafem/tuple_matrix.hpp>
13#include <kernel/global/matrix.hpp>
14#include <kernel/solver/base.hpp>
15#include <kernel/solver/amavanka_base.hpp>
16#include <kernel/util/stop_watch.hpp>
62 template<
typename Matrix_,
typename Filter_>
79 typedef typename Intern::AmaVankaMatrixHelper<Matrix_>::VankaMatrix
VankaMatrixType;
128 explicit AmaVanka(
const Matrix_& matrix,
const Filter_& filter,
145 this->_macro_dofs.clear();
160 if(
int(
_macro_dofs.size()) >= Intern::AmaVankaMatrixHelper<Matrix_>::num_blocks)
161 XABORTM(
"all macro-dofs graphs have already been added");
165 XABORTM(
"macro count mismatch");
168 _macro_dofs.emplace_back(std::forward<Adjacency::Graph>(dofs));
183 this->_num_steps = num_steps;
195 this->_omega = omega;
206 this->_skip_singular = skip_sing;
214 std::size_t s =
_vanka.bytes();
216 s +=
sizeof(
Index) * std::size_t(g.get_num_nodes_domain() + g.get_num_indices());
217 for(
const auto& g : _dof_macros)
218 s +=
sizeof(
Index) * std::size_t(g.get_num_nodes_domain() + g.get_num_indices());
232 return std::size_t(
_vanka.template used_elements<LAFEM::Perspective::pod>());
240 watch_init_symbolic.
reset();
241 watch_init_numeric.
reset();
250 return watch_init_symbolic.
elapsed();
258 return watch_init_numeric.
elapsed();
278 watch_init_symbolic.
start();
283 if(this->_num_steps >
Index(1))
285 this->_vec_c = this->_matrix.create_vector_l();
286 this->_vec_d = this->_matrix.create_vector_l();
290 if(this->_auto_macros)
293 if(!Intern::AmaVankaCore::deduct_macro_dofs(this->_matrix, this->_macro_dofs))
294 XABORTM(
"Cannot auto-deduct macros for this matrix type");
299 "invalid number of macro-dof graphs; did you push all of them?");
302 this->_dof_macros.resize(this->_macro_dofs.size());
303 for(std::size_t i(0); i < this->_macro_dofs.size(); ++i)
306 XASSERT(this->_macro_dofs.at(i).get_num_nodes_domain() == this->_macro_dofs.front().get_num_nodes_domain());
313 if(this->_skip_singular)
314 this->_macro_mask.resize(this->_macro_dofs.front().get_num_nodes_domain(), 0);
316 Solver::Intern::AmaVankaCore::alloc(this->_vanka, this->_dof_macros, this->_macro_dofs,
Index(0),
Index(0));
318 watch_init_symbolic.
stop();
324 this->_vanka.clear();
325 this->_macro_mask.clear();
326 this->_dof_macros.clear();
327 if(this->_auto_macros)
328 this->_macro_dofs.clear();
329 if(this->_num_steps >
Index(1))
331 this->_vec_d.clear();
332 this->_vec_c.clear();
340 const DataType eps = Math::eps<DataType>();
342 watch_init_numeric.
start();
345 this->_vanka.format();
348 const Index num_macros =
Index(this->_macro_dofs.front().get_num_nodes_domain());
349 const Index stride = Intern::AmaVankaCore::calc_stride(this->_vanka, this->_macro_dofs);
351 FEAT_PRAGMA_OMP(parallel)
354 std::vector<DataType> vec_local(stride*stride,
DataType(0)), vec_local_t(stride*stride,
DataType(0));
355 std::vector<Index> vec_pivot(stride);
357 DataType* local_t = vec_local_t.data();
358 Index* pivot = vec_pivot.data();
362 for(
Index imacro = 0; imacro < num_macros; ++imacro)
365 const std::pair<Index,Index> nrc = Intern::AmaVankaCore::gather(this->_matrix,
369 XASSERTM(nrc.first == nrc.second,
"local matrix is not square");
372 bool singular =
false;
375 if(this->_skip_singular)
385 for(
Index i(0); i < nrc.first; ++i)
386 for(
Index j(0); j < nrc.second; ++j)
387 local_t[i*stride+j] = local[i*stride+j];
394 for(
Index i(0); i < nrc.first; ++i)
396 for(
Index j(0); j < nrc.first; ++j)
399 for(
Index k(0); k < nrc.first; ++k)
400 xij -= local_t[i*stride+k] * local[k*stride+j];
409 singular = !(norm < eps);
412 this->_macro_mask[imacro] = (singular ? 0 : 1);
423 FEAT_PRAGMA_OMP(critical)
425 Intern::AmaVankaCore::scatter_add(this->_vanka, local, stride, imacro, this->_macro_dofs,
431 for(
Index i(0); i < nrc.first; ++i)
432 for(
Index j(0); j < nrc.second; ++j)
438 Solver::Intern::AmaVankaCore::scale_rows(this->_vanka, this->_omega, this->_dof_macros, this->_macro_mask,
Index(0),
Index(0));
440 watch_init_numeric.
stop();
449 this->_vanka.apply(vec_x, vec_b);
450 this->_filter.filter_cor(vec_x);
456 this->_matrix.apply(this->_vec_d, vec_x, vec_b, -
DataType(1));
458 this->_filter.filter_def(this->_vec_d);
460 this->_vanka.apply(this->_vec_c, this->_vec_d);
462 this->_filter.filter_cor(this->_vec_c);
464 vec_x.axpy(this->_vec_c);
472 bool compare(
const AmaVanka* other)
const
474 return Intern::AmaVankaMatrixHelper<VankaMatrixType>::compare(this->_vanka, other->_vanka);
496 template<
typename Matrix_,
typename Filter_>
497 std::shared_ptr<AmaVanka<Matrix_, Filter_>>
new_amavanka(
const Matrix_& matrix,
const Filter_& filter,
498 typename Matrix_::DataType omega =
typename Matrix_::DataType(1),
Index num_steps =
Index(1))
500 return std::make_shared<AmaVanka<Matrix_, Filter_>>(matrix, filter, omega, num_steps);
#define XABORTM(msg)
Abortion macro definition with custom message.
#define XASSERT(expr)
Assertion macro definition.
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Adjacency Graph implementation.
Additive Macro-wise Matrix-based Vanka preconditioner/smoother.
std::size_t bytes() const
Returns the total number of bytes currently allocated in this object.
virtual String name() const override
Returns the name of the solver.
const Matrix_ & _matrix
the system matrix
std::vector< int > _macro_mask
the macro mask
Matrix_::DataType DataType
our data type
virtual Status apply(VectorType &vec_x, const VectorType &vec_b) override
applies the preconditioner
double time_apply() const
Returns the total accumulated time for the solver application.
Index _num_steps
number of steps
void set_omega(DataType omega)
Sets the damping parameter omega.
VectorType _vec_c
temporary vectors
Matrix_::IndexType IndexType
our index type
bool _auto_macros
deduct macro dofs automatically?
DataType _omega
damping parameter
bool _skip_singular
skip singular macros?
int _num_threads
number of threads for numeric factorization
virtual void init_numeric() override
Performs numeric factorization.
void reset_timings()
Resets the internal stop watches for time measurement.
virtual void init_symbolic() override
Performs symbolic factorization.
double time_init_symbolic() const
Returns the total accumulated time for symbolic initialization.
std::size_t data_size() const
Returns the total data size used by the AmaVanka smoother.
void set_skip_singular(bool skip_sing)
Sets whether singular macros are to be skipped.
const Filter_ & _filter
the system filter
Matrix_::VectorTypeL VectorType
our vector type
AmaVanka(const Matrix_ &matrix, const Filter_ &filter, const DataType omega=DataType(1), const Index num_steps=Index(1))
Constructor.
double time_init_numeric() const
Returns the total accumulated time for numeric initialization.
VankaMatrixType _vanka
the Vanka preconditioner matrix
virtual void done_symbolic() override
Releases the symbolic factorization data.
void set_num_steps(Index num_steps)
Sets the number of smoothing steps.
Solver::SolverBase< typename Matrix_::VectorTypeL > BaseClass
our base-class
void push_macro_dofs(Adjacency::Graph &&dofs)
Pushes the dofs-at-macro graph of the next block.
void clear_macro_dofs()
Clears the macro dofs graphs.
Intern::AmaVankaMatrixHelper< Matrix_ >::VankaMatrix VankaMatrixType
the type of our Vanka matrix
std::vector< Adjacency::Graph > _macro_dofs
the DOF-macro graphs
Polymorphic solver interface.
virtual void init_symbolic()
Symbolic initialization method.
virtual void init_numeric()
Numeric initialization method.
virtual void done_symbolic()
Symbolic finalization method.
double elapsed() const
Returns the total elapsed time in seconds.
void start()
Starts the stop-watch.
void reset()
Resets the elapsed time.
void stop()
Stops the stop-watch and increments elapsed time.
String class implementation.
@ transpose
Render-Transpose mode.
DT_ invert_matrix(const IT_ n, const IT_ stride, DT_ a[], IT_ p[])
Inverts a matrix and returns its determinant.
std::shared_ptr< AmaVanka< Matrix_, Filter_ > > new_amavanka(const Matrix_ &matrix, const Filter_ &filter, typename Matrix_::DataType omega=typename Matrix_::DataType(1), Index num_steps=Index(1))
Creates a new AmaVanka smoother object.
Status
Solver status return codes enumeration.
@ success
solving successful (convergence criterion fulfilled)
std::uint64_t Index
Index data type.