61 GetPropType<TypeTag, Properties::GlobalEqVector>>
68 using Matrix =
typename SparseMatrixAdapter::IstlMatrix;
72 using ElementChunksType = Opm::ElementChunks<GridView, Dune::Partitions::All>;
74 using real_type =
typename Vector::field_type;
84 using CommunicationType = Dune::OwnerOverlapCopyCommunication<int, int>;
86 using CommunicationType = Dune::Communication<int>;
100 bool forceSerial =
false)
101 : m_parameters(parameters)
102 , m_simulator(simulator)
103 , m_forceSerial(forceSerial)
104 , m_element_chunks(simulator.vanguard().gridView(), Dune::Partitions::all, ThreadManager::maxThreads())
107 m_comm = std::make_shared<CommunicationType>(simulator.vanguard().grid().comm());
111 ElementMapper elemMapper(simulator.vanguard().gridView(), Dune::mcmgElementLayout());
113 Opm::detail::findOverlapAndInterior(simulator.vanguard().grid(), elemMapper, m_overlapRows, m_interiorRows);
115 const std::size_t size = simulator.vanguard().grid().leafGridView().size(0);
117 Opm::detail::copyParValues(m_parallelInformation, size, *m_comm);
121 m_comm = std::make_shared<CommunicationType>(simulator.gridView().comm());
123 m_parameters.init(simulator.vanguard().eclState().getSimulationConfig().useCPR());
128 OPM_THROW(std::logic_error,
"Well operators are currently not supported for the GPU backend. "
129 "Use --matrix-add-well-contributions=true to add well contributions to the matrix instead.");
132 Opm::detail::printLinearSolverParameters(m_parameters, m_propertyTree, simulator.gridView().comm());
161 OPM_THROW(std::logic_error,
"Only one solver available for the GPU backend.");
184 void prepare(
const SparseMatrixAdapter& M, Vector& b)
override
198 void prepare(
const Matrix& M, Vector& b)
override
202 Opm::detail::makeOverlapRowsInvalid(
const_cast<Matrix&
>(M), m_overlapRows);
207 OPM_CATCH_AND_RETHROW_AS_CRITICAL_ERROR(
"This is likely due to a faulty linear solver JSON specification. "
208 "Check for errors related to missing nodes.");
232 OPM_THROW(std::runtime_error,
"m_rhs not initialized, prepare(matrix, rhs); needs to be called");
234 m_rhs->copyToHost(b);
261 Dune::InverseOperatorResult result;
263 OPM_THROW(std::runtime_error,
"m_matrix not initialized, prepare(matrix, rhs); needs to be called");
266 OPM_THROW(std::runtime_error,
"m_rhs not initialized, prepare(matrix, rhs); needs to be called");
269 OPM_THROW(std::runtime_error,
270 "m_gpuFlexibleSolver not initialized, prepare(matrix, rhs); needs to be called");
274 m_x = std::make_unique<GPUVector>(x);
275 m_pinnedXMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
276 const_cast<real_type*
>(&x[0][0]),
281 m_x->copyFromHostAsync(x);
283 m_gpuSolver->apply(*m_x, *m_rhs, result);
289 m_lastSeenIterations = result.iterations;
290 return checkConvergence(result);
300 return m_lastSeenIterations;
306 const CommunicationType*
comm()
const override
319 return !m_forceSerial && m_comm->communicator().size() > 1;
334 bool checkConvergence(
const Dune::InverseOperatorResult& result)
const
340 std::function<GPUVector&()> getWeightsCalculator()
342 std::function<GPUVector&()> weightsCalculator;
344 using namespace std::string_literals;
346 auto preconditionerType = m_propertyTree.
get(
"preconditioner.type"s,
"cpr"s);
348 std::transform(preconditionerType.begin(), preconditionerType.end(), preconditionerType.begin(), ::tolower);
349 if (preconditionerType ==
"cpr" || preconditionerType ==
"cprt"
350 || preconditionerType ==
"cprw" || preconditionerType ==
"cprwt") {
351 const bool transpose = preconditionerType ==
"cprt" || preconditionerType ==
"cprwt";
352 const auto weightsType = m_propertyTree.
get(
"preconditioner.weight_type"s,
"quasiimpes"s);
353 if (weightsType ==
"quasiimpes") {
354 m_weights.emplace(m_matrix->N() * m_matrix->blockSize());
356 auto diagonalIndices = Amg::precomputeDiagonalIndices(*m_matrix);
357 m_diagonalIndices.emplace(diagonalIndices);
360 weightsCalculator = [
this]() -> GPUVector& {
361 Amg::getQuasiImpesWeights<real_type, true>(
362 *m_matrix, pressureIndex, *m_weights, *m_diagonalIndices);
366 weightsCalculator = [
this]() -> GPUVector& {
367 Amg::getQuasiImpesWeights<real_type, false>(
368 *m_matrix, pressureIndex, *m_weights, *m_diagonalIndices);
372 }
else if (weightsType ==
"trueimpes") {
374 m_cpuWeights.resize(m_matrix->N());
375 m_pinnedWeightsMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
376 const_cast<real_type*
>(&m_cpuWeights[0][0]), m_cpuWeights.dim());
377 m_weights.emplace(m_cpuWeights);
379 const bool enableThreadParallel = m_parameters.cpr_weights_thread_parallel_;
381 weightsCalculator = [
this, enableThreadParallel]() -> GPUVector& {
383 ElementContext elemCtx(m_simulator);
384 Amg::getTrueImpesWeights(pressureIndex,
386 elemCtx, m_simulator.model(),
388 enableThreadParallel);
391 m_weights->copyFromHostAsync(m_cpuWeights);
394 }
else if (weightsType ==
"trueimpesanalytic") {
396 m_cpuWeights.resize(m_matrix->N());
397 m_pinnedWeightsMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
398 const_cast<real_type*
>(&m_cpuWeights[0][0]), m_cpuWeights.dim());
399 m_weights.emplace(m_cpuWeights);
400 const bool enableThreadParallel = m_parameters.cpr_weights_thread_parallel_;
402 weightsCalculator = [
this, enableThreadParallel]() -> GPUVector& {
404 ElementContext elemCtx(m_simulator);
405 Amg::getTrueImpesWeightsAnalytic(pressureIndex,
407 elemCtx, m_simulator.model(),
409 enableThreadParallel);
412 m_weights->copyFromHostAsync(m_cpuWeights);
416 OPM_THROW(std::invalid_argument,
417 "Weights type " + weightsType
418 +
" not implemented for cpr."
419 " Please use quasiimpes, trueimpes or trueimpesanalytic.");
422 return weightsCalculator;
425 void updateMatrix(
const Matrix& M)
429 m_pinnedMatrixMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
430 const_cast<real_type*
>(&M[0][0][0][0]),
431 M.nonzeroes() * M[0][0].N() * M[0][0].M()
433 std::function<GPUVector&()> weightsCalculator = getWeightsCalculator();
434 m_gpuSolver = std::make_unique<SolverType>(
435 *m_matrix,
isParallel(), m_propertyTree, pressureIndex, weightsCalculator, m_forceSerial, m_comm.get());
437 m_matrix->updateNonzeroValues(M,
true);
438 m_gpuSolver->update();
442 void updateRhs(
const Vector& b)
445 m_rhs = std::make_unique<GPUVector>(b);
446 m_pinnedRhsMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
447 const_cast<real_type*
>(&b[0][0]),
452 m_rhs->copyFromHostAsync(b);
456 FlowLinearSolverParameters m_parameters;
457 const Simulator& m_simulator;
458 const bool m_forceSerial;
459 PropertyTree m_propertyTree;
460 ElementChunksType m_element_chunks;
462 int m_lastSeenIterations = 0;
463 int m_solveCount = 0;
465 std::unique_ptr<GPUMatrix> m_matrix;
467 std::unique_ptr<SolverType> m_gpuSolver;
469 std::unique_ptr<GPUVector> m_rhs;
470 std::unique_ptr<GPUVector> m_x;
472 std::unique_ptr<PinnedMemoryHolder<real_type>> m_pinnedMatrixMemory;
473 std::unique_ptr<PinnedMemoryHolder<real_type>> m_pinnedRhsMemory;
474 std::unique_ptr<PinnedMemoryHolder<real_type>> m_pinnedXMemory;
475 std::unique_ptr<PinnedMemoryHolder<real_type>> m_pinnedWeightsMemory;
478 std::optional<GPUVector> m_weights;
479 std::optional<GPUVectorInt> m_diagonalIndices;
481 std::shared_ptr<CommunicationType> m_comm;
482 std::vector<int> m_interiorRows;
483 std::vector<int> m_overlapRows;
484 std::any m_parallelInformation;