12 #include "../config/config.hpp" 14 #ifdef MFEM_USE_GINKGO 18 #include "../general/globals.hpp" 19 #include "../general/error.hpp" 37 executor = gko::ReferenceExecutor::create();
42 executor = gko::OmpExecutor::create();
47 if (gko::CudaExecutor::get_num_devices() > 0)
50 int current_device = 0;
51 MFEM_GPU_CHECK(cudaGetDevice(¤t_device));
52 executor = gko::CudaExecutor::create(current_device,
53 gko::OmpExecutor::create());
57 MFEM_ABORT(
"gko::CudaExecutor::get_num_devices() did not report " 58 "any valid devices.");
63 if (gko::HipExecutor::get_num_devices() > 0)
66 int current_device = 0;
67 MFEM_GPU_CHECK(hipGetDevice(¤t_device));
68 executor = gko::HipExecutor::create(current_device,
69 gko::OmpExecutor::create());
73 mfem::err <<
"gko::HipExecutor::get_num_devices() did not report " 74 <<
"any valid devices" << std::endl;
78 mfem::err <<
"Invalid ExecType specified" << std::endl;
88 if (gko::CudaExecutor::get_num_devices() > 0)
91 int current_device = 0;
92 MFEM_GPU_CHECK(cudaGetDevice(¤t_device));
93 executor = gko::CudaExecutor::create(current_device,
94 gko::OmpExecutor::create());
98 MFEM_ABORT(
"gko::CudaExecutor::get_num_devices() did not report " 99 "any valid devices.");
103 if (gko::HipExecutor::get_num_devices() > 0)
106 int current_device = 0;
107 MFEM_GPU_CHECK(hipGetDevice(¤t_device));
108 executor = gko::HipExecutor::create(current_device, gko::OmpExecutor::create());
112 MFEM_ABORT(
"gko::HipExecutor::get_num_devices() did not report " 113 "any valid devices.");
117 executor = gko::OmpExecutor::create();
122 bool use_implicit_res_norm)
124 use_implicit_res_norm(use_implicit_res_norm)
141 using ResidualCriterionFactory = gko::stop::ResidualNorm<>;
142 using ImplicitResidualCriterionFactory = gko::stop::ImplicitResidualNorm<>;
147 .with_reduction_factor(sqrt(
rel_tol))
148 .with_baseline(gko::stop::mode::initial_resnorm)
151 .with_reduction_factor(sqrt(
abs_tol))
152 .with_baseline(gko::stop::mode::absolute)
155 gko::stop::Combined::build()
158 gko::stop::Iteration::build()
159 .with_max_iters(static_cast<unsigned long>(
max_iter))
166 .with_reduction_factor(
rel_tol)
167 .with_baseline(gko::stop::mode::initial_resnorm)
170 .with_reduction_factor(
abs_tol)
171 .with_baseline(gko::stop::mode::absolute)
174 gko::stop::Combined::build()
177 gko::stop::Iteration::build()
178 .with_max_iters(static_cast<unsigned long>(
max_iter))
185 GinkgoIterativeSolver::initialize_ginkgo_log(gko::matrix::Dense<double>*
b)
190 #if MFEM_GINKGO_VERSION < 10500 192 executor, gko::log::Logger::criterion_check_completed_mask);
195 gko::log::Logger::criterion_check_completed_mask);
198 gko::lend(system_oper),
b);
210 mfem_x->get_mfem_vec_ref());
214 const gko::LinOp *beta,
223 if (
alpha->get_size()[0] > 1 ||
alpha->get_size()[1] > 1)
225 throw gko::BadDimension(
226 __FILE__, __LINE__, __func__,
"alpha",
alpha->get_size()[0],
227 alpha->get_size()[1],
228 "Expected an object of size [1 x 1] for scaling " 229 " in this operator's apply_impl");
231 if (beta->get_size()[0] > 1 || beta->get_size()[1] > 1)
233 throw gko::BadDimension(
234 __FILE__, __LINE__, __func__,
"beta", beta->get_size()[0],
236 "Expected an object of size [1 x 1] for scaling " 237 " in this operator's apply_impl");
242 if (
alpha->get_executor() ==
alpha->get_executor()->get_master())
245 alpha_f = gko::as<gko::matrix::Dense<double>>(
alpha)->at(0, 0);
250 this->get_executor()->get_master().get()->copy_from(
251 this->get_executor().
get(),
252 1, gko::as<gko::matrix::Dense<double>>(
alpha)->get_const_values(),
255 if (beta->get_executor() == beta->get_executor()->get_master())
258 beta_f = gko::as<gko::matrix::Dense<double>>(beta)->at(0, 0);
263 this->get_executor()->get_master().get()->copy_from(
264 this->get_executor().
get(),
265 1, gko::as<gko::matrix::Dense<double>>(beta)->get_const_values(),
269 mfem_x->get_mfem_vec_ref() *= beta_f;
273 mfem_x->get_mfem_vec_ref().GetMemory().GetMemoryType());
276 mfem_tmp.
UseDevice(mfem_x->get_mfem_vec_ref().UseDevice());
281 mfem_x->get_mfem_vec_ref().Add(alpha_f, mfem_tmp);
290 MFEM_VERIFY(system_oper,
"System matrix or operator not initialized");
291 MFEM_VERIFY(
executor,
"executor is not initialized");
293 "Mismatching sizes for rhs and solution");
295 using vec = gko::matrix::Dense<double>;
303 bool on_device =
false;
308 std::unique_ptr<vec> gko_x;
309 std::unique_ptr<vec> gko_y;
318 x.
Size(),
const_cast<double *
>(
319 x.
Read(on_device))), 1);
327 gko_x = std::unique_ptr<vec>(
329 const_cast<Vector *
>(&x),
false));
330 gko_y = std::unique_ptr<vec>(
337 initialize_ginkgo_log(gko::lend(gko_x));
353 solver->apply(gko::lend(gko_x), gko::lend(gko_y));
359 double final_res_norm = 0.0;
372 auto imp_residual_norm_d =
373 gko::as<gko::matrix::Dense<double>>(imp_residual_norm);
374 auto imp_residual_norm_d_master =
375 gko::matrix::Dense<double>::create(
executor->get_master(),
377 imp_residual_norm_d_master->copy_from(imp_residual_norm_d);
379 final_res_norm = imp_residual_norm_d_master->at(0,0);
383 auto residual_norm_d =
384 gko::as<gko::matrix::Dense<double>>(residual_norm);
385 auto residual_norm_d_master =
386 gko::matrix::Dense<double>::create(
executor->get_master(),
388 residual_norm_d_master->copy_from(residual_norm_d);
390 final_res_norm = residual_norm_d_master->at(0,0);
410 " iterations with final residual norm " 411 << final_res_norm <<
'\n';
441 "System matrix is not square");
443 bool on_device =
false;
449 using mtx = gko::matrix::Csr<double, int>;
451 system_oper = mtx::create(
466 system_oper = std::shared_ptr<OperatorWrapper>(
478 using cg = gko::solver::Cg<double>;
487 using cg = gko::solver::Cg<double>;
493 .with_generated_preconditioner(
496 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
497 GetGeneratedPreconditioner().
get()))
507 .with_preconditioner(preconditioner.
GetFactory())
517 using bicgstab = gko::solver::Bicgstab<double>;
527 using bicgstab = gko::solver::Bicgstab<double>;
532 .with_generated_preconditioner(
535 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
536 GetGeneratedPreconditioner().
get()))
546 .with_preconditioner(preconditioner.
GetFactory())
556 using cgs = gko::solver::Cgs<double>;
565 using cgs = gko::solver::Cgs<double>;
570 .with_generated_preconditioner(
573 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
574 GetGeneratedPreconditioner().
get()))
584 .with_preconditioner(preconditioner.
GetFactory())
594 using fcg = gko::solver::Fcg<double>;
603 using fcg = gko::solver::Fcg<double>;
608 .with_generated_preconditioner(
611 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
612 GetGeneratedPreconditioner().
get()))
622 .with_preconditioner(preconditioner.
GetFactory())
633 using gmres = gko::solver::Gmres<double>;
636 this->solver_gen = gmres::build()
637 .with_criteria(this->combined_factory)
642 this->solver_gen = gmres::build()
643 .with_krylov_dim(static_cast<unsigned long>(m))
644 .with_criteria(this->combined_factory)
654 using gmres = gko::solver::Gmres<double>;
658 if (preconditioner.HasGeneratedPreconditioner())
660 this->solver_gen = gmres::build()
661 .with_criteria(this->combined_factory)
662 .with_generated_preconditioner(
663 preconditioner.GetGeneratedPreconditioner())
665 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
666 GetGeneratedPreconditioner().
get()))
668 this->sub_op_needs_wrapped_vecs =
true;
669 this->needs_wrapped_vecs =
true;
674 this->solver_gen = gmres::build()
675 .with_criteria(this->combined_factory)
676 .with_preconditioner(preconditioner.GetFactory())
682 if (preconditioner.HasGeneratedPreconditioner())
684 this->solver_gen = gmres::build()
685 .with_krylov_dim(static_cast<unsigned long>(m))
686 .with_criteria(this->combined_factory)
687 .with_generated_preconditioner(
688 preconditioner.GetGeneratedPreconditioner())
690 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
691 GetGeneratedPreconditioner().
get()))
693 this->sub_op_needs_wrapped_vecs =
true;
694 this->needs_wrapped_vecs =
true;
699 this->solver_gen = gmres::build()
700 .with_krylov_dim(static_cast<unsigned long>(m))
701 .with_criteria(this->combined_factory)
702 .with_preconditioner(preconditioner.GetFactory())
711 using gmres_type = gko::solver::Gmres<double>;
712 gko::as<gmres_type::Factory>(
solver_gen)->get_parameters().krylov_dim =
m;
715 gko::as<gmres_type>(
solver)->set_krylov_dim(static_cast<unsigned long>(
m));
721 storage_precision prec)
725 using gmres = gko::solver::CbGmres<double>;
728 this->solver_gen = gmres::build()
729 .with_criteria(this->combined_factory)
730 .with_storage_precision(prec)
735 this->solver_gen = gmres::build()
736 .with_krylov_dim(static_cast<unsigned long>(m))
737 .with_criteria(this->combined_factory)
738 .with_storage_precision(prec)
745 int dim, storage_precision prec)
749 using gmres = gko::solver::CbGmres<double>;
753 if (preconditioner.HasGeneratedPreconditioner())
755 this->solver_gen = gmres::build()
756 .with_criteria(this->combined_factory)
757 .with_storage_precision(prec)
758 .with_generated_preconditioner(
759 preconditioner.GetGeneratedPreconditioner())
761 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
762 GetGeneratedPreconditioner().
get()))
764 this->sub_op_needs_wrapped_vecs =
true;
765 this->needs_wrapped_vecs =
true;
770 this->solver_gen = gmres::build()
771 .with_criteria(this->combined_factory)
772 .with_storage_precision(prec)
773 .with_preconditioner(preconditioner.GetFactory())
779 if (preconditioner.HasGeneratedPreconditioner())
781 this->solver_gen = gmres::build()
782 .with_krylov_dim(static_cast<unsigned long>(m))
783 .with_criteria(this->combined_factory)
784 .with_storage_precision(prec)
785 .with_generated_preconditioner(
786 preconditioner.GetGeneratedPreconditioner())
788 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
789 GetGeneratedPreconditioner().
get()))
791 this->sub_op_needs_wrapped_vecs =
true;
792 this->needs_wrapped_vecs =
true;
797 this->solver_gen = gmres::build()
798 .with_krylov_dim(static_cast<unsigned long>(m))
799 .with_criteria(this->combined_factory)
800 .with_storage_precision(prec)
801 .with_preconditioner(preconditioner.GetFactory())
810 using gmres_type = gko::solver::CbGmres<double>;
811 gko::as<gmres_type::Factory>(
solver_gen)->get_parameters().krylov_dim =
m;
814 gko::as<gmres_type>(
solver)->set_krylov_dim(static_cast<unsigned long>(
m));
822 using ir = gko::solver::Ir<double>;
831 using ir = gko::solver::Ir<double>;
858 MFEM_VERIFY(
executor,
"executor is not initialized");
860 using vec = gko::matrix::Dense<double>;
868 bool on_device =
false;
873 auto gko_x = vec::create(
executor, gko::dim<2>(x.
Size(), 1),
875 x.
Size(),
const_cast<double *
>(
876 x.
Read(on_device))), 1);
877 auto gko_y = vec::create(
executor, gko::dim<2>(y.
Size(), 1),
896 MFEM_VERIFY(op_mat != NULL,
897 "GinkgoPreconditioner::SetOperator : not a SparseMatrix!");
899 bool on_device =
false;
905 using mtx = gko::matrix::Csr<double, int>;
907 auto gko_matrix = mtx::create(
926 const std::string &storage_opt,
927 const double accuracy,
928 const int max_block_size
933 if (storage_opt ==
"auto")
935 precond_gen = gko::preconditioner::Jacobi<double, int>::build()
936 .with_storage_optimization(
937 gko::precision_reduction::autodetect())
938 .with_accuracy(accuracy)
939 .with_max_block_size(static_cast<unsigned int>(max_block_size))
944 precond_gen = gko::preconditioner::Jacobi<double, int>::build()
945 .with_storage_optimization(
946 gko::precision_reduction(0, 0))
947 .with_accuracy(accuracy)
948 .with_max_block_size(static_cast<unsigned int>(max_block_size))
957 const std::string &factorization_type,
963 if (factorization_type ==
"exact")
965 using ilu_fact_type = gko::factorization::Ilu<double, int>;
966 std::shared_ptr<ilu_fact_type::Factory> fact_factory =
967 ilu_fact_type::build()
968 .with_skip_sorting(skip_sort)
971 .with_factorization_factory(fact_factory)
976 using ilu_fact_type = gko::factorization::ParIlu<double, int>;
977 std::shared_ptr<ilu_fact_type::Factory> fact_factory =
978 ilu_fact_type::build()
979 .with_iterations(static_cast<unsigned long>(sweeps))
980 .with_skip_sorting(skip_sort)
983 .with_factorization_factory(fact_factory)
991 const std::string &factorization_type,
993 const int sparsity_power,
998 using l_solver_type = gko::preconditioner::LowerIsai<>;
999 using u_solver_type = gko::preconditioner::UpperIsai<>;
1001 std::shared_ptr<l_solver_type::Factory> l_solver_factory =
1002 l_solver_type::build()
1003 .with_sparsity_power(sparsity_power)
1005 std::shared_ptr<u_solver_type::Factory> u_solver_factory =
1006 u_solver_type::build()
1007 .with_sparsity_power(sparsity_power)
1012 if (factorization_type ==
"exact")
1014 using ilu_fact_type = gko::factorization::Ilu<double, int>;
1015 std::shared_ptr<ilu_fact_type::Factory> fact_factory =
1016 ilu_fact_type::build()
1017 .with_skip_sorting(skip_sort)
1019 precond_gen = gko::preconditioner::Ilu<l_solver_type,
1020 u_solver_type>::build()
1021 .with_factorization_factory(fact_factory)
1022 .with_l_solver_factory(l_solver_factory)
1023 .with_u_solver_factory(u_solver_factory)
1029 using ilu_fact_type = gko::factorization::ParIlu<double, int>;
1030 std::shared_ptr<ilu_fact_type::Factory> fact_factory =
1031 ilu_fact_type::build()
1032 .with_iterations(static_cast<unsigned long>(sweeps))
1033 .with_skip_sorting(skip_sort)
1035 precond_gen = gko::preconditioner::Ilu<l_solver_type,
1036 u_solver_type>::build()
1037 .with_factorization_factory(fact_factory)
1038 .with_l_solver_factory(l_solver_factory)
1039 .with_u_solver_factory(u_solver_factory)
1048 const std::string &factorization_type,
1050 const bool skip_sort
1055 if (factorization_type ==
"exact")
1057 using ic_fact_type = gko::factorization::Ic<double, int>;
1058 std::shared_ptr<ic_fact_type::Factory> fact_factory =
1059 ic_fact_type::build()
1060 .with_both_factors(
false)
1061 .with_skip_sorting(skip_sort)
1064 .with_factorization_factory(fact_factory)
1069 using ic_fact_type = gko::factorization::ParIc<double, int>;
1070 std::shared_ptr<ic_fact_type::Factory> fact_factory =
1071 ic_fact_type::build()
1072 .with_both_factors(
false)
1073 .with_iterations(static_cast<unsigned long>(sweeps))
1074 .with_skip_sorting(skip_sort)
1077 .with_factorization_factory(fact_factory)
1084 const std::string &factorization_type,
1086 const int sparsity_power,
1087 const bool skip_sort
1092 using l_solver_type = gko::preconditioner::LowerIsai<>;
1093 std::shared_ptr<l_solver_type::Factory> l_solver_factory =
1094 l_solver_type::build()
1095 .with_sparsity_power(sparsity_power)
1097 if (factorization_type ==
"exact")
1099 using ic_fact_type = gko::factorization::Ic<double, int>;
1100 std::shared_ptr<ic_fact_type::Factory> fact_factory =
1101 ic_fact_type::build()
1102 .with_both_factors(
false)
1103 .with_skip_sorting(skip_sort)
1105 precond_gen = gko::preconditioner::Ic<l_solver_type>::build()
1106 .with_factorization_factory(fact_factory)
1107 .with_l_solver_factory(l_solver_factory)
1112 using ic_fact_type = gko::factorization::ParIc<double, int>;
1113 std::shared_ptr<ic_fact_type::Factory> fact_factory =
1114 ic_fact_type::build()
1115 .with_both_factors(
false)
1116 .with_iterations(static_cast<unsigned long>(sweeps))
1117 .with_skip_sorting(skip_sort)
1119 precond_gen = gko::preconditioner::Ic<l_solver_type>::build()
1120 .with_factorization_factory(fact_factory)
1121 .with_l_solver_factory(l_solver_factory)
1129 const Solver &mfem_precond
1135 mfem_precond.
Height(), &mfem_precond));
1143 #endif // MFEM_USE_GINKGO bool use_implicit_res_norm
std::shared_ptr< gko::log::Convergence<> > convergence_logger
bool UsesVectorWrappers() const
std::shared_ptr< ResidualLogger<> > residual_logger
virtual void SetOperator(const Operator &op)
std::shared_ptr< gko::stop::ResidualNorm<>::Factory > abs_criterion
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
GinkgoIterativeSolver(GinkgoExecutor &exec, bool use_implicit_res_norm)
CBGMRESSolver(GinkgoExecutor &exec, int dim=0, storage_precision prec=storage_precision::reduce1)
const std::shared_ptr< gko::LinOp > GetGeneratedPreconditioner() const
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
std::shared_ptr< gko::LinOpFactory > precond_gen
CGSSolver(GinkgoExecutor &exec)
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Biwise-OR of all HIP backends.
MFEMPreconditioner(GinkgoExecutor &exec, const Solver &mfem_precond)
JacobiPreconditioner(GinkgoExecutor &exec, const std::string &storage_opt="none", const double accuracy=1.e-1, const int max_block_size=32)
int Size() const
Returns the size of the vector.
std::shared_ptr< gko::Executor > executor
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
GinkgoExecutor(ExecType exec_type)
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Memory< double > & GetMemoryData()
virtual void Mult(const Vector &x, Vector &y) const
BICGSTABSolver(GinkgoExecutor &exec)
bool HasGeneratedPreconditioner() const
std::shared_ptr< gko::stop::ImplicitResidualNorm<>::Factory > imp_rel_criterion
IluPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const bool skip_sort=false)
int * ReadWriteI(bool on_dev=true)
const std::shared_ptr< gko::LinOpFactory > GetFactory() const
std::shared_ptr< gko::Executor > executor
bool sub_op_needs_wrapped_vecs
void update_stop_factory()
int Capacity() const
Return the size of the allocated memory.
CGSolver(GinkgoExecutor &exec)
virtual void Mult(const Vector &x, Vector &y) const
Biwise-OR of all CUDA backends.
GMRESSolver(GinkgoExecutor &exec, int dim=0)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
std::shared_ptr< gko::Executor > GetExecutor() const
std::shared_ptr< gko::stop::ResidualNorm<>::Factory > rel_criterion
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
IRSolver(GinkgoExecutor &exec)
const Vector & get_mfem_vec_const_ref() const
IcPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const bool skip_sort=false)
std::shared_ptr< gko::stop::Combined::Factory > combined_factory
virtual double * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
std::shared_ptr< gko::LinOpFactory > solver_gen
bool has_generated_precond
const std::shared_ptr< gko::LinOpFactory > GetFactory() const
FCGSolver(GinkgoExecutor &exec)
IcIsaiPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const int sparsity_power=1, const bool skip_sort=false)
void Destroy()
Destroy a vector.
IluIsaiPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const int sparsity_power=1, const bool skip_sort=false)
GinkgoPreconditioner(GinkgoExecutor &exec)
std::shared_ptr< gko::LinOp > generated_precond
double * ReadWriteData(bool on_dev=true)
int * ReadWriteJ(bool on_dev=true)
std::shared_ptr< gko::stop::ImplicitResidualNorm<>::Factory > imp_abs_criterion
virtual void SetOperator(const Operator &op)
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
gko::Array< T > gko_array
void apply_impl(const gko::LinOp *b, gko::LinOp *x) const override
std::shared_ptr< gko::LinOp > solver