10 #ifndef MUELU_AMGXOPERATOR_DECL_HPP
11 #define MUELU_AMGXOPERATOR_DECL_HPP
13 #if defined(HAVE_MUELU_AMGX)
16 #include <Tpetra_Operator.hpp>
17 #include <Tpetra_CrsMatrix.hpp>
18 #include <Tpetra_MultiVector.hpp>
19 #include <Tpetra_Distributor.hpp>
20 #include <Tpetra_HashTable.hpp>
21 #include <Tpetra_Import.hpp>
26 #include "MueLu_TpetraOperator.hpp"
29 #include <cuda_runtime.h>
44 class AMGXOperator :
public TpetraOperator<Scalar, LocalOrdinal, GlobalOrdinal, Node>,
public BaseClass {
104 template <
class Node>
116 const int* nbrs,
const Map& map,
const std::string& label) {
117 for (
int p = 0; p < comm->getSize(); p++) {
118 if (comm->getRank() == p) {
119 std::cout <<
"========\n"
120 << label <<
", lid (gid), PID " << p <<
"\n========" << std::endl;
122 for (
size_t i = 0; i < vec.size(); ++i) {
123 std::cout <<
" neighbor " << nbrs[i] <<
" :";
124 for (
size_t j = 0; j < vec[i].size(); ++j)
125 std::cout <<
" " << vec[i][j] <<
" (" << map.
getGlobalElement(perm[vec[i][j]]) <<
")";
126 std::cout << std::endl;
128 std::cout << std::endl;
141 int numProcs = comm->getSize();
142 int myRank = comm->getRank();
152 AMGX_SAFE_CALL(AMGX_install_signal_handler());
155 AMGX_SAFE_CALL(AMGX_config_create_from_file(&Config_, (
const char*)&configs.
get<std::string>(
"json file")[0]));
157 std::ostringstream oss;
160 for (itr = configs.
begin(); itr != configs.
end(); ++itr) {
161 const std::string& name = configs.
name(itr);
163 oss << name <<
"=" << filterValueToString(entry) <<
", ";
166 std::string configString = oss.str();
167 if (configString ==
"") {
171 AMGX_SAFE_CALL(AMGX_config_create(&Config_, configString.c_str()));
187 MPI_Comm mpiComm = *rawMpiComm;
192 AMGX_resources_create_simple(&Resources_, Config_);
196 cudaGetDeviceCount(&numGPUDevices);
197 int device[] = {(comm->getRank() % numGPUDevices)};
199 AMGX_config_add_parameters(&Config_,
"communicator=MPI");
201 AMGX_resources_create(&Resources_, Config_, &mpiComm, 1 , device);
203 AMGX_resources_create(&Resources_, Config_, MPI_COMM_WORLD, 1 , device);
207 AMGX_Mode mode = AMGX_mode_dDDI;
208 AMGX_solver_create(&Solver_, Resources_, mode, Config_);
209 AMGX_matrix_create(&A_, Resources_, mode);
210 AMGX_vector_create(&X_, Resources_, mode);
211 AMGX_vector_create(&Y_, Resources_, mode);
216 std::vector<int> amgx2muelu;
226 Array<int> sendRanks = distributor.getProcsTo();
227 Array<int> recvRanks = distributor.getProcsFrom();
229 std::sort(sendRanks.
begin(), sendRanks.
end());
230 std::sort(recvRanks.
begin(), recvRanks.
end());
233 if (sendRanks.
size() != recvRanks.
size()) {
236 for (
int i = 0; i < sendRanks.
size(); i++) {
237 if (recvRanks[i] != sendRanks[i])
243 "AMGX requires that the processors that we send to and receive from are the same. "
244 "This is not the case: we send to {"
245 << sendRanks <<
"} and receive from {" << recvRanks <<
"}");
247 int num_neighbors = sendRanks.
size();
248 const int* neighbors = &sendRanks[0];
255 for (
int i = 0; i < num_neighbors; i++)
256 hashTable.
add(neighbors[i], i);
262 Tpetra::Import_Util::getPids(*importer, importPIDs,
true );
269 muelu2amgx_.resize(Nc, -1);
271 int numUniqExports = 0;
272 for (
int i = 0; i < exportLIDs.
size(); i++)
273 if (muelu2amgx_[exportLIDs[i]] == -1) {
275 muelu2amgx_[exportLIDs[i]] = -2;
278 int localOffset = 0, exportOffset = N - numUniqExports;
280 for (
int i = 0; i < exportLIDs.
size(); i++)
281 if (muelu2amgx_[exportLIDs[i]] < 0)
282 muelu2amgx_[exportLIDs[i]] = exportOffset++;
284 for (
int i = 0; i < N; i++)
285 if (muelu2amgx_[i] == -1)
286 muelu2amgx_[i] = localOffset++;
288 int importOffset = N;
289 for (
int k = 0; k < num_neighbors; k++)
290 for (
int i = 0; i < importPIDs.
size(); i++)
291 if (importPIDs[i] != -1 && hashTable.
get(importPIDs[i]) == k)
292 muelu2amgx_[i] = importOffset++;
294 amgx2muelu.resize(muelu2amgx_.size());
295 for (
int i = 0; i < (int)muelu2amgx_.size(); i++)
296 amgx2muelu[muelu2amgx_[i]] = i;
299 std::vector<std::vector<int> > sendDatas(num_neighbors);
300 std::vector<int> send_sizes(num_neighbors, 0);
301 for (
int i = 0; i < exportPIDs.
size(); i++) {
302 int index = hashTable.
get(exportPIDs[i]);
303 sendDatas[index].push_back(muelu2amgx_[exportLIDs[i]]);
308 std::vector<const int*> send_maps(num_neighbors);
309 for (
int i = 0; i < num_neighbors; i++)
310 send_maps[i] = &(sendDatas[i][0]);
316 std::vector<std::vector<int> > recvDatas(num_neighbors);
317 std::vector<int> recv_sizes(num_neighbors, 0);
318 for (
int i = 0; i < importPIDs.
size(); i++)
319 if (importPIDs[i] != -1) {
320 int index = hashTable.
get(importPIDs[i]);
321 recvDatas[index].push_back(muelu2amgx_[i]);
326 std::vector<const int*> recv_maps(num_neighbors);
327 for (
int i = 0; i < num_neighbors; i++)
328 recv_maps[i] = &(recvDatas[i][0]);
333 AMGX_SAFE_CALL(AMGX_matrix_comm_from_maps_one_ring(A_, 1, num_neighbors, neighbors, &send_sizes[0], &send_maps[0], &recv_sizes[0], &recv_maps[0]));
335 AMGX_vector_bind(X_, A_);
336 AMGX_vector_bind(Y_, A_);
340 matrixTransformTimer->
start();
345 inA->getAllValues(ia_s, ja, a);
348 for (
int i = 0; i < ia.size(); i++)
349 ia[i] = Teuchos::as<int>(ia_s[i]);
351 N_ = inA->getLocalNumRows();
352 int nnz = inA->getLocalNumEntries();
354 matrixTransformTimer->
stop();
360 matrixTimer->
start();
362 AMGX_matrix_upload_all(A_, N_, nnz, 1, 1, &ia[0], &ja[0], &a[0], NULL);
366 std::vector<int> ia_new(ia.size());
367 std::vector<int> ja_new(ja.
size());
368 std::vector<double> a_new(a.
size());
371 for (
int i = 0; i < N_; i++) {
372 int oldRow = amgx2muelu[i];
374 ia_new[i + 1] = ia_new[i] + (ia[oldRow + 1] - ia[oldRow]);
376 for (
int j = ia[oldRow]; j < ia[oldRow + 1]; j++) {
377 int offset = j - ia[oldRow];
378 ja_new[ia_new[i] + offset] = muelu2amgx_[ja[j]];
379 a_new[ia_new[i] + offset] = a[j];
387 for (
int j = ia_new[i]; j < ia_new[i + 1] - 1; j++)
388 if (ja_new[j] > ja_new[j + 1]) {
389 std::swap(ja_new[j], ja_new[j + 1]);
390 std::swap(a_new[j], a_new[j + 1]);
393 }
while (swapped ==
true);
396 AMGX_matrix_upload_all(A_, N_, nnz, 1, 1, &ia_new[0], &ja_new[0], &a_new[0], NULL);
401 domainMap_ = inA->getDomainMap();
402 rangeMap_ = inA->getRangeMap();
405 realSetupTimer->
start();
406 AMGX_solver_setup(Solver_, A_);
407 realSetupTimer->
stop();
418 AMGX_SAFE_CALL(AMGX_solver_destroy(Solver_));
419 AMGX_SAFE_CALL(AMGX_vector_destroy(X_));
420 AMGX_SAFE_CALL(AMGX_vector_destroy(Y_));
421 AMGX_SAFE_CALL(AMGX_matrix_destroy(A_));
422 AMGX_SAFE_CALL(AMGX_resources_destroy(Resources_));
423 AMGX_SAFE_CALL(AMGX_config_destroy(Config_));
453 AMGX_matrix_get_size(A_, &n, &sizeX, &sizeY);
459 AMGX_solver_get_iterations_number(Solver_, &it);
464 AMGX_SOLVE_STATUS status;
465 AMGX_solver_get_status(Solver_, &status);
473 AMGX_matrix_handle
A_;
474 AMGX_vector_handle
X_;
475 AMGX_vector_handle
Y_;
490 #endif // HAVE_MUELU_AMGX
491 #endif // MUELU_AMGXOPERATOR_DECL_HPP
RCP< const Map > domainMap_
const std::string & name() const
virtual ~AMGXOperator()
Destructor.
ConstIterator end() const
MueLu::DefaultLocalOrdinal LocalOrdinal
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
AMGXOperator(const Teuchos::RCP< Tpetra::CrsMatrix< SC, LO, GO, NO > > &inA, Teuchos::ParameterList ¶mListIn)
T & get(const std::string &name, T def_value)
AMGX_config_handle Config_
size_t getLocalNumElements() const
void printMaps(Teuchos::RCP< const Teuchos::Comm< int > > &comm, const std::vector< std::vector< int > > &vec, const std::vector< int > &perm, const int *nbrs, const Map &map, const std::string &label)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::RCP< const Map > getRangeMap() const
Returns the Tpetra::Map object associated with the range of this operator.
RCP< MueLu::Hierarchy< SC, LO, GO, NO > > GetHierarchy() const
AMGX_solver_handle Solver_
Tpetra::MultiVector< SC, LO, GO, NO > MultiVector
std::vector< int > muelu2amgx_
virtual ~AMGXOperator()
Destructor.
RCP< const Map > rangeMap_
RCP< Teuchos::Time > solverTimer_
static RCP< Time > getNewTimer(const std::string &name)
Tpetra::Map< LO, GO, NO > Map
bool isParameter(const std::string &name) const
void start(bool reset=false)
MueLu::DefaultScalar Scalar
MueLu::DefaultGlobalOrdinal GlobalOrdinal
global_ordinal_type getGlobalElement(local_ordinal_type localIndex) const
void apply(const MultiVector &X, MultiVector &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, Scalar alpha=Teuchos::ScalarTraits< Scalar >::one(), Scalar beta=Teuchos::ScalarTraits< Scalar >::zero()) const
Returns a solution for the linear system AX=Y in the Tpetra::MultiVector X.
params_t::ConstIterator ConstIterator
RCP< MueLu::Hierarchy< SC, LO, GO, NO > > GetHierarchy() const
ConstIterator begin() const
std::string filterValueToString(const Teuchos::ParameterEntry &entry)
const ParameterEntry & entry(ConstIterator i) const
any & getAny(bool activeQry=true)
Teuchos::RCP< const Map > getDomainMap() const
Returns the Tpetra::Map object associated with the domain of this operator.
ValueType get(const KeyType key)
void add(const KeyType key, const ValueType value)
AMGXOperator(const Teuchos::RCP< Tpetra::CrsMatrix< SC, LO, GO, NO > > &InA, Teuchos::ParameterList ¶mListIn)
Constructor.
AMGX_resources_handle Resources_
Tpetra::Map< LO, GO, NO > Map
Wraps an existing MueLu::Hierarchy as a Tpetra::Operator.
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
Exception throws to report errors in the internal logical of the program.
RCP< Teuchos::Time > vectorTimer1_
bool hasTransposeApply() const
Indicates whether this operator supports applying the adjoint operator.
RCP< Teuchos::Time > vectorTimer2_
Tpetra::MultiVector< SC, LO, GO, NO > MultiVector
AMGX_SOLVE_STATUS getStatus()
Adapter for AmgX library from Nvidia.