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<>;
148 .with_baseline(gko::stop::mode::initial_resnorm)
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)
191 executor, gko::log::Logger::criterion_check_completed_mask);
193 gko::lend(system_oper),
b);
205 mfem_x->get_mfem_vec_ref());
209 const gko::LinOp *beta,
218 if (alpha->get_size()[0] > 1 || alpha->get_size()[1] > 1)
220 throw gko::BadDimension(
221 __FILE__, __LINE__, __func__,
"alpha", alpha->get_size()[0],
222 alpha->get_size()[1],
223 "Expected an object of size [1 x 1] for scaling "
224 " in this operator's apply_impl");
226 if (beta->get_size()[0] > 1 || beta->get_size()[1] > 1)
228 throw gko::BadDimension(
229 __FILE__, __LINE__, __func__,
"beta", beta->get_size()[0],
231 "Expected an object of size [1 x 1] for scaling "
232 " in this operator's apply_impl");
237 if (alpha->get_executor() == alpha->get_executor()->get_master())
240 alpha_f = gko::as<gko::matrix::Dense<double>>(
alpha)->at(0, 0);
245 this->get_executor()->get_master().get()->copy_from(
246 this->get_executor().
get(),
247 1, gko::as<gko::matrix::Dense<double>>(alpha)->get_const_values(),
250 if (beta->get_executor() == beta->get_executor()->get_master())
253 beta_f = gko::as<gko::matrix::Dense<double>>(beta)->at(0, 0);
258 this->get_executor()->get_master().get()->copy_from(
259 this->get_executor().
get(),
260 1, gko::as<gko::matrix::Dense<double>>(beta)->get_const_values(),
264 mfem_x->get_mfem_vec_ref() *= beta_f;
268 mfem_x->get_mfem_vec_ref().GetMemory().GetMemoryType());
271 mfem_tmp.
UseDevice(mfem_x->get_mfem_vec_ref().UseDevice());
276 mfem_x->get_mfem_vec_ref().Add(alpha_f, mfem_tmp);
285 MFEM_VERIFY(system_oper,
"System matrix or operator not initialized");
286 MFEM_VERIFY(
executor,
"executor is not initialized");
288 "Mismatching sizes for rhs and solution");
290 using vec = gko::matrix::Dense<double>;
298 bool on_device =
false;
303 std::unique_ptr<vec> gko_x;
304 std::unique_ptr<vec> gko_y;
313 x.
Size(),
const_cast<double *
>(
314 x.
Read(on_device))), 1);
322 gko_x = std::unique_ptr<vec>(
324 const_cast<Vector *
>(&x),
false));
325 gko_y = std::unique_ptr<vec>(
332 initialize_ginkgo_log(gko::lend(gko_x));
348 solver->apply(gko::lend(gko_x), gko::lend(gko_y));
354 double final_res_norm = 0.0;
367 auto imp_residual_norm_d =
368 gko::as<gko::matrix::Dense<double>>(imp_residual_norm);
369 auto imp_residual_norm_d_master =
370 gko::matrix::Dense<double>::create(
executor->get_master(),
372 imp_residual_norm_d_master->copy_from(imp_residual_norm_d);
374 final_res_norm = imp_residual_norm_d_master->at(0,0);
378 auto residual_norm_d =
379 gko::as<gko::matrix::Dense<double>>(residual_norm);
380 auto residual_norm_d_master =
381 gko::matrix::Dense<double>::create(
executor->get_master(),
383 residual_norm_d_master->copy_from(residual_norm_d);
385 final_res_norm = residual_norm_d_master->at(0,0);
405 " iterations with final residual norm "
406 << final_res_norm <<
'\n';
436 "System matrix is not square");
438 bool on_device =
false;
444 using mtx = gko::matrix::Csr<double, int>;
446 system_oper = mtx::create(
461 system_oper = std::shared_ptr<OperatorWrapper>(
473 using cg = gko::solver::Cg<double>;
482 using cg = gko::solver::Cg<double>;
488 .with_generated_preconditioner(
491 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
492 GetGeneratedPreconditioner().
get()))
502 .with_preconditioner(preconditioner.
GetFactory())
512 using bicgstab = gko::solver::Bicgstab<double>;
522 using bicgstab = gko::solver::Bicgstab<double>;
527 .with_generated_preconditioner(
530 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
531 GetGeneratedPreconditioner().
get()))
541 .with_preconditioner(preconditioner.
GetFactory())
551 using cgs = gko::solver::Cgs<double>;
560 using cgs = gko::solver::Cgs<double>;
565 .with_generated_preconditioner(
568 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
569 GetGeneratedPreconditioner().
get()))
579 .with_preconditioner(preconditioner.
GetFactory())
589 using fcg = gko::solver::Fcg<double>;
598 using fcg = gko::solver::Fcg<double>;
603 .with_generated_preconditioner(
606 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
607 GetGeneratedPreconditioner().
get()))
617 .with_preconditioner(preconditioner.
GetFactory())
628 using gmres = gko::solver::Gmres<double>;
631 this->solver_gen = gmres::build()
632 .with_criteria(this->combined_factory)
637 this->solver_gen = gmres::build()
638 .with_krylov_dim(static_cast<unsigned long>(m))
639 .with_criteria(this->combined_factory)
649 using gmres = gko::solver::Gmres<double>;
653 if (preconditioner.HasGeneratedPreconditioner())
655 this->solver_gen = gmres::build()
656 .with_criteria(this->combined_factory)
657 .with_generated_preconditioner(
658 preconditioner.GetGeneratedPreconditioner())
660 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
661 GetGeneratedPreconditioner().
get()))
663 this->sub_op_needs_wrapped_vecs =
true;
664 this->needs_wrapped_vecs =
true;
669 this->solver_gen = gmres::build()
670 .with_criteria(this->combined_factory)
671 .with_preconditioner(preconditioner.GetFactory())
677 if (preconditioner.HasGeneratedPreconditioner())
679 this->solver_gen = gmres::build()
680 .with_krylov_dim(static_cast<unsigned long>(m))
681 .with_criteria(this->combined_factory)
682 .with_generated_preconditioner(
683 preconditioner.GetGeneratedPreconditioner())
685 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
686 GetGeneratedPreconditioner().
get()))
688 this->sub_op_needs_wrapped_vecs =
true;
689 this->needs_wrapped_vecs =
true;
694 this->solver_gen = gmres::build()
695 .with_krylov_dim(static_cast<unsigned long>(m))
696 .with_criteria(this->combined_factory)
697 .with_preconditioner(preconditioner.GetFactory())
706 using gmres_type = gko::solver::Gmres<double>;
707 gko::as<gmres_type::Factory>(
solver_gen)->get_parameters().krylov_dim =
m;
710 gko::as<gmres_type>(
solver)->set_krylov_dim(static_cast<unsigned long>(
m));
716 storage_precision prec)
720 using gmres = gko::solver::CbGmres<double>;
723 this->solver_gen = gmres::build()
724 .with_criteria(this->combined_factory)
725 .with_storage_precision(prec)
730 this->solver_gen = gmres::build()
731 .with_krylov_dim(static_cast<unsigned long>(m))
732 .with_criteria(this->combined_factory)
733 .with_storage_precision(prec)
740 int dim, storage_precision prec)
744 using gmres = gko::solver::CbGmres<double>;
748 if (preconditioner.HasGeneratedPreconditioner())
750 this->solver_gen = gmres::build()
751 .with_criteria(this->combined_factory)
752 .with_storage_precision(prec)
753 .with_generated_preconditioner(
754 preconditioner.GetGeneratedPreconditioner())
756 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
757 GetGeneratedPreconditioner().
get()))
759 this->sub_op_needs_wrapped_vecs =
true;
760 this->needs_wrapped_vecs =
true;
765 this->solver_gen = gmres::build()
766 .with_criteria(this->combined_factory)
767 .with_storage_precision(prec)
768 .with_preconditioner(preconditioner.GetFactory())
774 if (preconditioner.HasGeneratedPreconditioner())
776 this->solver_gen = gmres::build()
777 .with_krylov_dim(static_cast<unsigned long>(m))
778 .with_criteria(this->combined_factory)
779 .with_storage_precision(prec)
780 .with_generated_preconditioner(
781 preconditioner.GetGeneratedPreconditioner())
783 if (dynamic_cast<const OperatorWrapper*>(preconditioner.
784 GetGeneratedPreconditioner().
get()))
786 this->sub_op_needs_wrapped_vecs =
true;
787 this->needs_wrapped_vecs =
true;
792 this->solver_gen = gmres::build()
793 .with_krylov_dim(static_cast<unsigned long>(m))
794 .with_criteria(this->combined_factory)
795 .with_storage_precision(prec)
796 .with_preconditioner(preconditioner.GetFactory())
805 using gmres_type = gko::solver::CbGmres<double>;
806 gko::as<gmres_type::Factory>(
solver_gen)->get_parameters().krylov_dim =
m;
809 gko::as<gmres_type>(
solver)->set_krylov_dim(static_cast<unsigned long>(
m));
817 using ir = gko::solver::Ir<double>;
826 using ir = gko::solver::Ir<double>;
853 MFEM_VERIFY(
executor,
"executor is not initialized");
855 using vec = gko::matrix::Dense<double>;
863 bool on_device =
false;
868 auto gko_x = vec::create(
executor, gko::dim<2>(x.
Size(), 1),
870 x.
Size(),
const_cast<double *
>(
871 x.
Read(on_device))), 1);
872 auto gko_y = vec::create(
executor, gko::dim<2>(y.
Size(), 1),
891 MFEM_VERIFY(op_mat != NULL,
892 "GinkgoPreconditioner::SetOperator : not a SparseMatrix!");
894 bool on_device =
false;
900 using mtx = gko::matrix::Csr<double, int>;
902 auto gko_matrix = mtx::create(
921 const std::string &storage_opt,
922 const double accuracy,
923 const int max_block_size
928 if (storage_opt ==
"auto")
930 precond_gen = gko::preconditioner::Jacobi<double, int>::build()
931 .with_storage_optimization(
932 gko::precision_reduction::autodetect())
933 .with_accuracy(accuracy)
934 .with_max_block_size(static_cast<unsigned int>(max_block_size))
939 precond_gen = gko::preconditioner::Jacobi<double, int>::build()
940 .with_storage_optimization(
941 gko::precision_reduction(0, 0))
942 .with_accuracy(accuracy)
943 .with_max_block_size(static_cast<unsigned int>(max_block_size))
952 const std::string &factorization_type,
958 if (factorization_type ==
"exact")
960 using ilu_fact_type = gko::factorization::Ilu<double, int>;
961 std::shared_ptr<ilu_fact_type::Factory> fact_factory =
962 ilu_fact_type::build()
963 .with_skip_sorting(skip_sort)
966 .with_factorization_factory(fact_factory)
971 using ilu_fact_type = gko::factorization::ParIlu<double, int>;
972 std::shared_ptr<ilu_fact_type::Factory> fact_factory =
973 ilu_fact_type::build()
974 .with_iterations(static_cast<unsigned long>(sweeps))
975 .with_skip_sorting(skip_sort)
978 .with_factorization_factory(fact_factory)
986 const std::string &factorization_type,
988 const int sparsity_power,
993 using l_solver_type = gko::preconditioner::LowerIsai<>;
994 using u_solver_type = gko::preconditioner::UpperIsai<>;
996 std::shared_ptr<l_solver_type::Factory> l_solver_factory =
997 l_solver_type::build()
998 .with_sparsity_power(sparsity_power)
1000 std::shared_ptr<u_solver_type::Factory> u_solver_factory =
1001 u_solver_type::build()
1002 .with_sparsity_power(sparsity_power)
1007 if (factorization_type ==
"exact")
1009 using ilu_fact_type = gko::factorization::Ilu<double, int>;
1010 std::shared_ptr<ilu_fact_type::Factory> fact_factory =
1011 ilu_fact_type::build()
1012 .with_skip_sorting(skip_sort)
1014 precond_gen = gko::preconditioner::Ilu<l_solver_type,
1015 u_solver_type>::build()
1016 .with_factorization_factory(fact_factory)
1017 .with_l_solver_factory(l_solver_factory)
1018 .with_u_solver_factory(u_solver_factory)
1024 using ilu_fact_type = gko::factorization::ParIlu<double, int>;
1025 std::shared_ptr<ilu_fact_type::Factory> fact_factory =
1026 ilu_fact_type::build()
1027 .with_iterations(static_cast<unsigned long>(sweeps))
1028 .with_skip_sorting(skip_sort)
1030 precond_gen = gko::preconditioner::Ilu<l_solver_type,
1031 u_solver_type>::build()
1032 .with_factorization_factory(fact_factory)
1033 .with_l_solver_factory(l_solver_factory)
1034 .with_u_solver_factory(u_solver_factory)
1043 const std::string &factorization_type,
1045 const bool skip_sort
1050 if (factorization_type ==
"exact")
1052 using ic_fact_type = gko::factorization::Ic<double, int>;
1053 std::shared_ptr<ic_fact_type::Factory> fact_factory =
1054 ic_fact_type::build()
1055 .with_both_factors(
false)
1056 .with_skip_sorting(skip_sort)
1059 .with_factorization_factory(fact_factory)
1064 using ic_fact_type = gko::factorization::ParIc<double, int>;
1065 std::shared_ptr<ic_fact_type::Factory> fact_factory =
1066 ic_fact_type::build()
1067 .with_both_factors(
false)
1068 .with_iterations(static_cast<unsigned long>(sweeps))
1069 .with_skip_sorting(skip_sort)
1072 .with_factorization_factory(fact_factory)
1079 const std::string &factorization_type,
1081 const int sparsity_power,
1082 const bool skip_sort
1087 using l_solver_type = gko::preconditioner::LowerIsai<>;
1088 std::shared_ptr<l_solver_type::Factory> l_solver_factory =
1089 l_solver_type::build()
1090 .with_sparsity_power(sparsity_power)
1092 if (factorization_type ==
"exact")
1094 using ic_fact_type = gko::factorization::Ic<double, int>;
1095 std::shared_ptr<ic_fact_type::Factory> fact_factory =
1096 ic_fact_type::build()
1097 .with_both_factors(
false)
1098 .with_skip_sorting(skip_sort)
1100 precond_gen = gko::preconditioner::Ic<l_solver_type>::build()
1101 .with_factorization_factory(fact_factory)
1102 .with_l_solver_factory(l_solver_factory)
1107 using ic_fact_type = gko::factorization::ParIc<double, int>;
1108 std::shared_ptr<ic_fact_type::Factory> fact_factory =
1109 ic_fact_type::build()
1110 .with_both_factors(
false)
1111 .with_iterations(static_cast<unsigned long>(sweeps))
1112 .with_skip_sorting(skip_sort)
1114 precond_gen = gko::preconditioner::Ic<l_solver_type>::build()
1115 .with_factorization_factory(fact_factory)
1116 .with_l_solver_factory(l_solver_factory)
1124 const Solver &mfem_precond
1130 mfem_precond.
Height(), &mfem_precond));
1138 #endif // MFEM_USE_GINKGO
bool use_implicit_res_norm
std::shared_ptr< gko::log::Convergence<> > convergence_logger
std::shared_ptr< gko::Executor > GetExecutor() const
std::shared_ptr< ResidualLogger<> > residual_logger
virtual void SetOperator(const Operator &op)
std::shared_ptr< gko::stop::ResidualNorm<>::Factory > abs_criterion
GinkgoIterativeSolver(GinkgoExecutor &exec, bool use_implicit_res_norm)
CBGMRESSolver(GinkgoExecutor &exec, int dim=0, storage_precision prec=storage_precision::reduce1)
std::shared_ptr< gko::LinOpFactory > precond_gen
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
CGSSolver(GinkgoExecutor &exec)
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
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.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Memory< double > & GetMemoryData()
int Capacity() const
Return the size of the allocated memory.
BICGSTABSolver(GinkgoExecutor &exec)
virtual void Mult(const Vector &x, Vector &y) const
std::shared_ptr< gko::stop::ImplicitResidualNorm<>::Factory > imp_rel_criterion
bool HasGeneratedPreconditioner() const
IluPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const bool skip_sort=false)
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
const std::shared_ptr< gko::LinOpFactory > GetFactory() const
int * ReadWriteI(bool on_dev=true)
bool UsesVectorWrappers() const
std::shared_ptr< gko::Executor > executor
bool sub_op_needs_wrapped_vecs
void update_stop_factory()
CGSolver(GinkgoExecutor &exec)
Biwise-OR of all CUDA backends.
GMRESSolver(GinkgoExecutor &exec, int dim=0)
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
const std::shared_ptr< gko::LinOpFactory > GetFactory() const
std::shared_ptr< gko::stop::ResidualNorm<>::Factory > rel_criterion
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
FCGSolver(GinkgoExecutor &exec)
FDualNumber< tbase > sqrt(const FDualNumber< tbase > &f)
sqrt([dual number])
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.
virtual void Mult(const Vector &x, Vector &y) const
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)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
const std::shared_ptr< gko::LinOp > GetGeneratedPreconditioner() const
void apply_impl(const gko::LinOp *b, gko::LinOp *x) const override
std::shared_ptr< gko::LinOp > solver