13#include <ginkgo/ginkgo.hpp>
14#include <ginkgo/extensions/kokkos.hpp>
15#include <ginkgo/extensions/config/json_config.hpp>
25namespace NeoN::la::ginkgo
28std::shared_ptr<gko::Executor> getGkoExecutor(Executor exec);
30gko::config::pnode parse(
const Dictionary& dict);
33template<
typename NeoNMatrixType>
34std::shared_ptr<const gko::LinOp> createGkoMtx(
const NeoNMatrixType& mtx);
36#ifdef NF_WITH_MPI_SUPPORT
39template<
typename IndexType>
40std::shared_ptr<const gko::LinOp> createGkoMtxDist(
41 std::shared_ptr<const gko::Executor> exec,
42 const gko::experimental::mpi::communicator& comm,
43 const CSRMatrix<scalar, IndexType>& mtx,
44 const COOMatrix<scalar, IndexType>& bmtx,
45 const CommunicationPattern& commPattern,
46 std::shared_ptr<gko::experimental::distributed::index_map<label, gko::int64>>& imapCache,
47 std::shared_ptr<gko::matrix::Coo<scalar, IndexType>>& nonLocalMtxCache
52gko::array<T> gkoArrayView(std::shared_ptr<const gko::Executor> exec, std::span<T> values)
54 return gko::make_array_view(exec, values.size(), values.data());
59std::shared_ptr<gko::matrix::Dense<scalar>>
60gkoVecView(std::shared_ptr<const gko::Executor> exec, T* ptr, localIdx s)
62 constexpr std::size_t cols = std::is_same_v<T, Vec3> ? 3 : 1;
63 auto size =
static_cast<std::size_t
>(s);
64 return gko::share(gko::matrix::Dense<scalar>::create(
66 gko::dim<2> {size, cols},
67 gkoArrayView<scalar>(exec, std::span<scalar> {
reinterpret_cast<scalar*
>(ptr), cols * size}),
74std::shared_ptr<const gko::matrix::Dense<scalar>>
75gkoVecView(std::shared_ptr<const gko::Executor> exec,
const T* ptr, localIdx s)
77 constexpr std::size_t cols = std::is_same_v<T, Vec3> ? 3 : 1;
78 auto size =
static_cast<std::size_t
>(s);
79 return gko::share(gko::matrix::Dense<scalar>::create_const(
81 gko::dim<2> {size, cols},
82 gko::array<scalar>::const_view(exec, cols * size,
reinterpret_cast<const scalar*
>(ptr)),
88template<
typename InType>
89scalar retrieve(
const InType& in)
91 using vec = gko::matrix::Dense<scalar>;
92 auto host = vec::create(in->get_executor()->get_master(), gko::dim<2> {1});
93 return host->copy_from(in)->at(0);
101struct L1ResidualControl
105 gko::size_type maxIter;
106 gko::size_type minIter;
117struct L1ResidualResult
119 gko::size_type numIter = 0;
121 scalar finalResNorm = 0.0;
124 std::vector<scalar> perColInitNorms;
125 std::vector<scalar> perColFinalNorms;
133inline constexpr const char* l1CriterionKey =
"neon::l1ScaledResidual";
142std::shared_ptr<gko::stop::CriterionFactory> makeL1CriterionFactory(
143 std::shared_ptr<const gko::Executor> exec,
144 const L1ResidualControl& control,
145 L1ResidualResult* report
154L1ResidualResult solveWithL1Stop(
155 std::shared_ptr<const gko::Executor> exec,
156 std::shared_ptr<const gko::LinOp> mtx,
157 std::shared_ptr<
const gko::matrix::Dense<scalar>> b,
158 std::shared_ptr<gko::matrix::Dense<scalar>> x,
160 const L1ResidualControl& control
163#ifdef NF_WITH_MPI_SUPPORT
170L1ResidualResult solveWithL1StopDist(
171 std::shared_ptr<const gko::Executor> exec,
172 std::shared_ptr<const gko::LinOp> mtx,
173 std::shared_ptr<
const gko::experimental::distributed::Vector<scalar>> b,
174 std::shared_ptr<gko::experimental::distributed::Vector<scalar>> x,
176 const L1ResidualControl& control
188inline std::optional<L1ResidualControl> readL1ResidualControl(
const Dictionary& cfg)
190 const std::string flag =
"l1ScaledResidual";
191 if (!cfg.contains(flag))
197 bool enabled =
false;
198 if (cfg.isType<
bool>(flag))
200 enabled = cfg.get<
bool>(flag);
202 else if (cfg.isType<
int>(flag))
204 enabled = cfg.get<
int>(flag) != 0;
206 else if (cfg.isType<std::string>(flag))
208 const std::string v = cfg.get<std::string>(flag);
209 enabled = (v ==
"true" || v ==
"yes" || v ==
"on" || v ==
"1");
216 L1ResidualControl control {0.0, 0.0, 1000, 0, 1};
219 auto readScalar = [](
const Dictionary& d,
const std::string& key,
scalar fallback)
221 if (!d.contains(key))
return fallback;
222 if (d.isType<
int>(key))
return scalar(d.get<
int>(key));
223 if (d.isType<label>(key))
return scalar(d.get<label>(key));
224 return d.get<
scalar>(key);
226 auto readInt = [](
const Dictionary& d,
const std::string& key,
localIdx fallback)
228 if (!d.contains(key))
return fallback;
229 if (d.isType<
int>(key))
return localIdx(d.get<
int>(key));
230 if (d.isType<scalar>(key))
return localIdx(d.get<scalar>(key));
236 control.tolerance = readScalar(cfg,
"tolerance", control.tolerance);
237 control.relTol = readScalar(cfg,
"relTol", control.relTol);
238 control.maxIter = readInt(cfg,
"maxIter", control.maxIter);
242 if (cfg.contains(
"criteria"))
244 const Dictionary& criteria = cfg.subDict(
"criteria");
245 control.tolerance = readScalar(criteria,
"absolute_residual_norm", control.tolerance);
246 control.relTol = readScalar(criteria,
"initial_residual_norm", control.relTol);
247 control.maxIter = readInt(criteria,
"iteration", control.maxIter);
249 control.minIter = readInt(cfg,
"minIter", control.minIter);
250 control.checkFrequency = readInt(cfg,
"checkFrequency", control.checkFrequency);
259inline bool pnodeReferencesString(
const gko::config::pnode& node,
const std::string& name)
261 using tag = gko::config::pnode::tag_t;
262 switch (node.get_tag())
265 return node.get_string() ==
name;
267 for (
const auto& e : node.get_array())
268 if (pnodeReferencesString(e,
name)) return true;
271 for (
const auto& kv : node.get_map())
272 if (pnodeReferencesString(kv.second,
name)) return true;
279class GinkgoSolver :
public SolverFactory::template
Register<GinkgoSolver>
286 GinkgoSolver(Executor exec,
const Dictionary& solverConfig)
287 : Base(exec), gkoExec_(getGkoExecutor(exec)), coupled_(solverConfig.get(
"coupled", false)),
288 l1Control_(readL1ResidualControl(solverConfig)), config_(parse(solverConfig))
296 gko::config::registry reg;
299 l1CritFactory_ = makeL1CriterionFactory(gkoExec_, *l1Control_, &l1Report_);
300 reg.emplace(std::string(l1CriterionKey), l1CritFactory_);
301 l1InConfig_ = pnodeReferencesString(config_, l1CriterionKey);
303 factory_ = gko::config::parse(config_, reg, gko::config::make_type_descriptor<scalar>())
307 static std::string
name() {
return "Ginkgo"; }
309 static std::string doc() {
return "TBD"; }
311 static std::string schema() {
return "none"; }
313 virtual SolverStats
solve(
314 const LinearSystem<scalar, scalar, CSRMatrix<scalar, localIdx>>& sys, Vector<scalar>& x
317 virtual SolverStats
solve(
318 const LinearSystem<Vec3, Vec3, CSRMatrix<Vec3, localIdx>>& sys, Vector<Vec3>& x
321 virtual SolverStats
solve(
322 const LinearSystem<scalar, Vec3, CSRMatrix<scalar, localIdx>, COOMatrix<scalar, localIdx>>&
327#ifdef NF_WITH_MPI_SUPPORT
328 virtual SolverStats solveDist(
329 const LinearSystem<scalar, scalar, CSRMatrix<scalar, localIdx>>& sys, Vector<scalar>& x
332 virtual SolverStats solveDist(
333 const LinearSystem<Vec3, Vec3, CSRMatrix<Vec3, localIdx>>& sys, Vector<Vec3>& x
336 virtual SolverStats solveDist(
337 const LinearSystem<scalar, Vec3, CSRMatrix<scalar, localIdx>, COOMatrix<scalar, localIdx>>&
344 virtual std::unique_ptr<SolverFactory> clone() const final
352 std::shared_ptr<const gko::Executor> gkoExec_;
354 std::optional<L1ResidualControl> l1Control_;
355 gko::config::pnode config_;
356 std::shared_ptr<const gko::LinOpFactory> factory_;
358 std::shared_ptr<gko::stop::CriterionFactory> l1CritFactory_;
361 bool l1InConfig_ =
false;
363 mutable L1ResidualResult l1Report_;
364#ifdef NF_WITH_MPI_SUPPORT
366 mutable std::shared_ptr<gko::experimental::distributed::index_map<label, gko::int64>>
368 mutable std::shared_ptr<gko::matrix::Coo<scalar, localIdx>> cachedNonLocalMtx_;
A template class for registering derived classes with a base class.
#define NF_ERROR_EXIT(message)
Macro for printing an error message and aborting the program.
std::optional< la::SolverStats > solve(Expression< typename VectorType::ElementType, IndexType > &exp, VectorType &solution, scalar t, scalar dt, const Dictionary &fvSchemes, const Dictionary &fvSolution, std::vector< const PostAssemblyBase< typename VectorType::ElementType, IndexType > * > p={})
const std::string & name(const NeoN::Document &doc)
Retrieves the name of a Document.