67 using Matrix =
typename SparseMatrixAdapter::IstlMatrix;
71 using ElementChunksType = Opm::ElementChunks<GridView, Dune::Partitions::All>;
73 using real_type =
typename Vector::field_type;
83 using CommunicationType = Dune::OwnerOverlapCopyCommunication<int, int>;
85 using CommunicationType = Dune::Communication<int>;
99 bool forceSerial =
false)
100 : m_parameters(parameters)
101 , m_simulator(simulator)
102 , m_forceSerial(forceSerial)
103 , m_element_chunks(simulator.vanguard().gridView(), Dune::Partitions::all, ThreadManager::maxThreads())
106 m_comm = std::make_shared<CommunicationType>(simulator.vanguard().grid().comm());
108 extractParallelGridInformationToISTL(simulator.vanguard().grid(), m_parallelInformation);
110 ElementMapper elemMapper(simulator.vanguard().gridView(), Dune::mcmgElementLayout());
112 Opm::detail::findOverlapAndInterior(simulator.vanguard().grid(), elemMapper, m_overlapRows, m_interiorRows);
114 const std::size_t size = simulator.vanguard().grid().leafGridView().size(0);
116 Opm::detail::copyParValues(m_parallelInformation, size, *m_comm);
120 m_comm = std::make_shared<CommunicationType>(simulator.gridView().comm());
122 m_parameters.init(simulator.vanguard().eclState().getSimulationConfig().useCPR());
127 OPM_THROW(std::logic_error,
"Well operators are currently not supported for the GPU backend. "
128 "Use --matrix-add-well-contributions=true to add well contributions to the matrix instead.");
131 Opm::detail::printLinearSolverParameters(m_parameters, m_propertyTree, simulator.gridView().comm());
160 OPM_THROW(std::logic_error,
"Only one solver available for the GPU backend.");
183 void prepare(
const SparseMatrixAdapter& M, Vector& b)
override
197 void prepare(
const Matrix& M, Vector& b)
override
201 Opm::detail::makeOverlapRowsInvalid(
const_cast<Matrix&
>(M), m_overlapRows);
206 OPM_CATCH_AND_RETHROW_AS_CRITICAL_ERROR(
"This is likely due to a faulty linear solver JSON specification. "
207 "Check for errors related to missing nodes.");
231 OPM_THROW(std::runtime_error,
"m_rhs not initialized, prepare(matrix, rhs); needs to be called");
233 m_rhs->copyToHost(b);
260 Dune::InverseOperatorResult result;
262 OPM_THROW(std::runtime_error,
"m_matrix not initialized, prepare(matrix, rhs); needs to be called");
265 OPM_THROW(std::runtime_error,
"m_rhs not initialized, prepare(matrix, rhs); needs to be called");
268 OPM_THROW(std::runtime_error,
269 "m_gpuFlexibleSolver not initialized, prepare(matrix, rhs); needs to be called");
273 m_x = std::make_unique<GPUVector>(x);
274 m_pinnedXMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
275 const_cast<real_type*
>(&x[0][0]),
280 m_x->copyFromHostAsync(x);
282 m_gpuSolver->apply(*m_x, *m_rhs, result);
288 m_lastSeenIterations = result.iterations;
289 return checkConvergence(result);
299 return m_lastSeenIterations;
305 const CommunicationType*
comm()
const override
318 return !m_forceSerial && m_comm->communicator().size() > 1;
333 bool checkConvergence(
const Dune::InverseOperatorResult& result)
const
339 std::function<GPUVector&()> getWeightsCalculator()
341 std::function<GPUVector&()> weightsCalculator;
343 using namespace std::string_literals;
345 auto preconditionerType = m_propertyTree.
get(
"preconditioner.type"s,
"cpr"s);
347 std::transform(preconditionerType.begin(), preconditionerType.end(), preconditionerType.begin(), ::tolower);
348 if (preconditionerType ==
"cpr" || preconditionerType ==
"cprt"
349 || preconditionerType ==
"cprw" || preconditionerType ==
"cprwt") {
350 const bool transpose = preconditionerType ==
"cprt" || preconditionerType ==
"cprwt";
351 const auto weightsType = m_propertyTree.
get(
"preconditioner.weight_type"s,
"quasiimpes"s);
352 if (weightsType ==
"quasiimpes") {
353 m_weights.emplace(m_matrix->N() * m_matrix->blockSize());
355 auto diagonalIndices = Amg::precomputeDiagonalIndices(*m_matrix);
356 m_diagonalIndices.emplace(diagonalIndices);
359 weightsCalculator = [
this]() -> GPUVector& {
360 Amg::getQuasiImpesWeights<real_type, true>(
361 *m_matrix, pressureIndex, *m_weights, *m_diagonalIndices);
365 weightsCalculator = [
this]() -> GPUVector& {
366 Amg::getQuasiImpesWeights<real_type, false>(
367 *m_matrix, pressureIndex, *m_weights, *m_diagonalIndices);
371 }
else if (weightsType ==
"trueimpes") {
373 m_cpuWeights.resize(m_matrix->N());
374 m_pinnedWeightsMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
375 const_cast<real_type*
>(&m_cpuWeights[0][0]), m_cpuWeights.dim());
376 m_weights.emplace(m_cpuWeights);
378 const bool enableThreadParallel = m_parameters.cpr_weights_thread_parallel_;
380 weightsCalculator = [
this, enableThreadParallel]() -> GPUVector& {
382 ElementContext elemCtx(m_simulator);
383 Amg::getTrueImpesWeights(pressureIndex,
385 elemCtx, m_simulator.model(),
387 enableThreadParallel);
390 m_weights->copyFromHostAsync(m_cpuWeights);
393 }
else if (weightsType ==
"trueimpesanalytic") {
395 m_cpuWeights.resize(m_matrix->N());
396 m_pinnedWeightsMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
397 const_cast<real_type*
>(&m_cpuWeights[0][0]), m_cpuWeights.dim());
398 m_weights.emplace(m_cpuWeights);
399 const bool enableThreadParallel = m_parameters.cpr_weights_thread_parallel_;
401 weightsCalculator = [
this, enableThreadParallel]() -> GPUVector& {
403 ElementContext elemCtx(m_simulator);
404 Amg::getTrueImpesWeightsAnalytic(pressureIndex,
406 elemCtx, m_simulator.model(),
408 enableThreadParallel);
411 m_weights->copyFromHostAsync(m_cpuWeights);
415 OPM_THROW(std::invalid_argument,
416 "Weights type " + weightsType
417 +
" not implemented for cpr."
418 " Please use quasiimpes, trueimpes or trueimpesanalytic.");
421 return weightsCalculator;
424 void updateMatrix(
const Matrix& M)
428 m_pinnedMatrixMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
429 const_cast<real_type*
>(&M[0][0][0][0]),
430 M.nonzeroes() * M[0][0].N() * M[0][0].M()
432 std::function<GPUVector&()> weightsCalculator = getWeightsCalculator();
433 m_gpuSolver = std::make_unique<SolverType>(
434 *m_matrix,
isParallel(), m_propertyTree, pressureIndex, weightsCalculator, m_forceSerial, m_comm.get());
436 m_matrix->updateNonzeroValues(M,
true);
437 m_gpuSolver->update();
441 void updateRhs(
const Vector& b)
444 m_rhs = std::make_unique<GPUVector>(b);
445 m_pinnedRhsMemory = std::make_unique<PinnedMemoryHolder<real_type>>(
446 const_cast<real_type*
>(&b[0][0]),
451 m_rhs->copyFromHostAsync(b);
455 FlowLinearSolverParameters m_parameters;
456 const Simulator& m_simulator;
457 const bool m_forceSerial;
458 PropertyTree m_propertyTree;
459 ElementChunksType m_element_chunks;
461 int m_lastSeenIterations = 0;
462 int m_solveCount = 0;
464 std::unique_ptr<GPUMatrix> m_matrix;
466 std::unique_ptr<SolverType> m_gpuSolver;
468 std::unique_ptr<GPUVector> m_rhs;
469 std::unique_ptr<GPUVector> m_x;
471 std::unique_ptr<PinnedMemoryHolder<real_type>> m_pinnedMatrixMemory;
472 std::unique_ptr<PinnedMemoryHolder<real_type>> m_pinnedRhsMemory;
473 std::unique_ptr<PinnedMemoryHolder<real_type>> m_pinnedXMemory;
474 std::unique_ptr<PinnedMemoryHolder<real_type>> m_pinnedWeightsMemory;
477 std::optional<GPUVector> m_weights;
478 std::optional<GPUVectorInt> m_diagonalIndices;
480 std::shared_ptr<CommunicationType> m_comm;
481 std::vector<int> m_interiorRows;
482 std::vector<int> m_overlapRows;
483 std::any m_parallelInformation;