bool ML_Epetra::ValidateMLPParameters(const Teuchos::ParameterList &inList, int depth){ using Teuchos::ParameterList; using Teuchos::Exceptions::InvalidParameterName; using Teuchos::Exceptions::InvalidParameterType; using Teuchos::Exceptions::InvalidParameterValue; using std::cout; using std::endl; using std::string; ParameterList List,*validList; bool rv=true; /* Build a copy of the list to be validated. */ for (ParameterList::ConstIterator param = inList.begin(); param != inList.end(); ++param) { const std::string pname=inList.name(param); if (pname.find("user-defined function",0) == std::string::npos) { List.setEntry(pname,inList.entry(param)); } } List.setName(inList.name()); /* Get Defaults + Validate */ try { validList = GetValidMLPParameters(); } catch(...) { std::cout << "Error in GetValidMLPParameters. Please report this bug to the ML " "developers." << std::endl; #ifdef HAVE_MPI MPI_Finalize(); #endif exit(EXIT_FAILURE); } try { List.validateParameters (*validList, depth, Teuchos::VALIDATE_USED_ENABLED, Teuchos::VALIDATE_DEFAULTS_DISABLED); } #ifdef HAVE_IFPACK_DYNAMIC_FACTORY catch(InvalidParameterName &excpt) {/*rv=false; std::cout<<excpt.what()<<std::endl;*/} #else catch(InvalidParameterName &excpt) {rv=false; std::cout<<excpt.what()<<std::endl;} #endif catch(InvalidParameterType &excpt) {rv=false; std::cout<<excpt.what()<<std::endl;} catch(InvalidParameterValue &excpt) {rv=false; std::cout<<excpt.what()<<std::endl;} catch(...) {rv=false;} delete validList; return rv; }
bool ML_Epetra::ValidateRefMaxwellParameters(const Teuchos::ParameterList &inList){ using Teuchos::ParameterList; using Teuchos::Exceptions::InvalidParameterName; using Teuchos::Exceptions::InvalidParameterType; using Teuchos::Exceptions::InvalidParameterValue; using std::cout; using std::endl; using std::string; ParameterList List,*validList; bool rv=true; /* Build a list with level-specific stuff stripped */ //TODO this should be fixed for (ParameterList::ConstIterator param = inList.begin(); param != inList.end(); ++param) { const string pname=inList.name(param); if (pname.find("(level",0) == string::npos) { List.setEntry(pname,inList.entry(param)); } } List.setName(inList.name()); /* Get Defaults + Validate */ try{ validList = GetValidRefMaxwellParameters(); } catch(...) { cout << "Error in GetValidMLPParameters. Please report this bug to the ML " "developers." << endl; #ifdef HAVE_MPI MPI_Finalize(); #endif exit(EXIT_FAILURE); } try { List.validateParameters(*validList, 0, Teuchos::VALIDATE_USED_DISABLED, Teuchos::VALIDATE_DEFAULTS_DISABLED); } catch(InvalidParameterName &excpt) {rv=false; cout<<excpt.what();} catch(InvalidParameterType &excpt) {rv=false; cout<<excpt.what();} catch(InvalidParameterValue &excpt) {rv=false; cout<<excpt.what();} catch(...) {rv=false;} delete validList; return rv; }
bool UpdateContFile( const string & fileName, const int & idStep, const Teuchos::ParameterList & fileParams ) { // The file to open ofstream oFile(fileName.c_str(), ios_base::app); // Writing the id oFile << scientific << setw(7) << idStep; // Looping on the parameters Teuchos::map<string, Teuchos::ParameterEntry>::const_iterator i; for (i = fileParams.begin(); i !=fileParams.end(); ++i) oFile << scientific << setw(15) << fileParams.entry(i); oFile << std::endl; // Closing oFile.close(); return true; }
std::string ML2MueLuParameterTranslator::SetParameterList(const Teuchos::ParameterList & paramList_in, const std::string& defaultVals) { Teuchos::ParameterList paramList = paramList_in; RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout)); // TODO: use internal out (GetOStream()) #if defined(HAVE_MUELU_ML) && defined(HAVE_MUELU_EPETRA) // TODO alternative with standard parameterlist from ML user guide? if (defaultVals != "") { TEUCHOS_TEST_FOR_EXCEPTION(defaultVals!="SA" && defaultVals!="NSSA", Exceptions::RuntimeError, "MueLu::MLParameterListInterpreter: only \"SA\" and \"NSSA\" allowed as options for ML default parameters."); Teuchos::ParameterList ML_defaultlist; ML_Epetra::SetDefaults(defaultVals,ML_defaultlist); // merge user parameters with default parameters MueLu::MergeParameterList(paramList_in, ML_defaultlist, true); paramList = ML_defaultlist; } #else if (defaultVals != "") { // If no validator available: issue a warning and set parameter value to false in the output list *out << "Warning: MueLu_ENABLE_ML=OFF. No ML default values available." << std::endl; } #endif // HAVE_MUELU_ML // // Move smoothers/aggregation/coarse parameters to sublists // // ML allows to have level-specific smoothers/aggregation/coarse parameters at the top level of the list or/and defined in sublists: // See also: ML Guide section 6.4.1, MueLu::CreateSublists, ML_CreateSublists ParameterList paramListWithSubList; MueLu::CreateSublists(paramList, paramListWithSubList); paramList = paramListWithSubList; // swap Teuchos::ParameterList adaptingParamList = paramList; // copy of paramList which is used to removed already interpreted parameters // // Validate parameter list // { bool validate = paramList.get("ML validate parameter list", true); /* true = default in ML */ if (validate) { #if defined(HAVE_MUELU_ML) && defined(HAVE_MUELU_EPETRA) // Validate parameter list using ML validator int depth = paramList.get("ML validate depth", 5); /* 5 = default in ML */ TEUCHOS_TEST_FOR_EXCEPTION(! ML_Epetra::ValidateMLPParameters(paramList, depth), Exceptions::RuntimeError, "ERROR: ML's Teuchos::ParameterList contains incorrect parameter!"); #else // If no validator available: issue a warning and set parameter value to false in the output list *out << "Warning: MueLu_ENABLE_ML=OFF. The parameter list cannot be validated." << std::endl; paramList.set("ML validate parameter list", false); #endif // HAVE_MUELU_ML } // if(validate) } // scope // stringstream for concatenating xml parameter strings. std::stringstream mueluss; // create surrounding MueLu parameter list mueluss << "<ParameterList name=\"MueLu\">" << std::endl; // loop over all ML parameters in provided parameter list for (ParameterList::ConstIterator param = paramListWithSubList.begin(); param != paramListWithSubList.end(); ++param) { // extract ML parameter name const std::string & pname=paramListWithSubList.name(param); // extract corresponding (ML) value // remove ParameterList specific information from result string std::stringstream valuess; valuess << paramList.entry(param); std::string valuestr = valuess.str(); replaceAll(valuestr, "[unused]", ""); replaceAll(valuestr, "[default]", ""); valuestr = trim(valuestr); // transform ML parameter to corresponding MueLu parameter and generate XML string std::string valueInterpreterStr = "\"" + valuestr + "\""; std::string ret = MasterList::interpretParameterName(MasterList::ML2MueLu(pname),valueInterpreterStr); // add XML string if (ret != "") { mueluss << ret << std::endl; // remove parameter from ML parameter list adaptingParamList.remove(pname,false); } // special handling for energy minimization // TAW: this is not optimal for symmetric problems but at least works. // for symmetric problems the "energy minimization" parameter should not exist anyway... if (pname == "energy minimization: enable") { mueluss << "<Parameter name=\"problem: symmetric\" type=\"bool\" value=\"false\"/>" << std::endl; mueluss << "<Parameter name=\"transpose: use implicit\" type=\"bool\" value=\"false\"/>" << std::endl; } // special handling for smoothers if (pname == "smoother: type") { mueluss << GetSmootherFactory(paramList, adaptingParamList, pname, valuestr); } // special handling for level-specific smoothers if (pname.find("smoother: list (level",0) == 0) { // Scan pname (ex: pname="smoother: type (level 2)") std::string type, option; int levelID=-1; { typedef Teuchos::ArrayRCP<char>::size_type size_type; Teuchos::Array<char> ctype (size_type(pname.size()+1)); Teuchos::Array<char> coption(size_type(pname.size()+1)); int matched = sscanf(pname.c_str(),"%s %[^(](level %d)", ctype.getRawPtr(), coption.getRawPtr(), &levelID); // use [^(] instead of %s to allow for strings with white-spaces (ex: "ifpack list") type = std::string(ctype.getRawPtr()); option = std::string(coption.getRawPtr()); option.resize(option.size () - 1); // remove final white-space if (matched != 3 || (type != "smoother:")) { TEUCHOS_TEST_FOR_EXCEPTION(true, MueLu::Exceptions::RuntimeError, "MueLu::CreateSublist(), Line " << __LINE__ << ". " << "Error in creating level-specific sublists" << std::endl << "Offending parameter: " << pname << std::endl); } mueluss << "<ParameterList name=\"level " << levelID << "\">" << std::endl; mueluss << GetSmootherFactory(paramList.sublist(pname),adaptingParamList.sublist(pname), "smoother: type", paramList.sublist(pname).get<std::string>("smoother: type")); mueluss << "</ParameterList>" << std::endl; } } // special handling for coarse level TEUCHOS_TEST_FOR_EXCEPTION(paramList.isParameter("coarse: type"), Exceptions::RuntimeError, "MueLu::MLParameterListInterpreter::Setup(): The parameter \"coarse: type\" should not exist but being stored in \"coarse: list\" instead."); if ( pname == "coarse: list" ) { // interpret smoother/coarse solver data. // Note, that we inspect the "coarse: list" sublist to define the "coarse" smoother/solver // Be aware, that MueLu::CreateSublists renames the prefix of the parameters in the "coarse: list" from "coarse" to "smoother". // Therefore, we have to check the values of the "smoother" parameters TEUCHOS_TEST_FOR_EXCEPTION(!paramList.sublist("coarse: list").isParameter("smoother: type"), Exceptions::RuntimeError, "MueLu::MLParameterListInterpreter::Setup(): no coarse grid solver defined."); mueluss << GetSmootherFactory(paramList.sublist("coarse: list"), adaptingParamList.sublist("coarse: list"), "coarse: type", paramList.sublist("coarse: list").get<std::string>("smoother: type")); } } // for mueluss << "</ParameterList>" << std::endl; return mueluss.str(); }
//! @name Constructor/Destructor //@{ AMGXOperator(const Teuchos::RCP<Tpetra::CrsMatrix<SC,LO,GO,NO> > &inA, Teuchos::ParameterList ¶mListIn) { RCP<const Teuchos::Comm<int> > comm = inA->getRowMap()->getComm(); int numProcs = comm->getSize(); int myRank = comm->getRank(); RCP<Teuchos::Time> amgxTimer = Teuchos::TimeMonitor::getNewTimer("MueLu: AMGX: initialize"); amgxTimer->start(); // Initialize AMGX_SAFE_CALL(AMGX_initialize()); AMGX_SAFE_CALL(AMGX_initialize_plugins()); /*system*/ //AMGX_SAFE_CALL(AMGX_register_print_callback(&print_callback)); AMGX_SAFE_CALL(AMGX_install_signal_handler()); Teuchos::ParameterList configs = paramListIn.sublist("amgx:params", true); if (configs.isParameter("json file")) { AMGX_SAFE_CALL(AMGX_config_create_from_file(&Config_, (const char *) &configs.get<std::string>("json file")[0])); } else { std::ostringstream oss; oss << ""; ParameterList::ConstIterator itr; for (itr = configs.begin(); itr != configs.end(); ++itr) { const std::string& name = configs.name(itr); const ParameterEntry& entry = configs.entry(itr); oss << name << "=" << filterValueToString(entry) << ", "; } oss << "\0"; std::string configString = oss.str(); if (configString == "") { //print msg that using defaults //GetOStream(Warnings0) << "Warning: No configuration parameters specified, using default AMGX configuration parameters. \n"; } AMGX_SAFE_CALL(AMGX_config_create(&Config_, configString.c_str())); } // TODO: we probably need to add "exception_handling=1" to the parameter list // to switch on internal error handling (with no need for AMGX_SAFE_CALL) #define NEW_COMM #ifdef NEW_COMM // NOTE: MPI communicator used in AMGX_resources_create must exist in the scope of AMGX_matrix_comm_from_maps_one_ring // FIXME: fix for serial comm RCP<const Teuchos::MpiComm<int> > tmpic = Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm->duplicate()); TEUCHOS_TEST_FOR_EXCEPTION(tmpic.is_null(), Exceptions::RuntimeError, "Communicator is not MpiComm"); RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > rawMpiComm = tmpic->getRawMpiComm(); MPI_Comm mpiComm = *rawMpiComm; #endif // Construct AMGX resources if (numProcs == 1) { AMGX_resources_create_simple(&Resources_, Config_); } else { int numGPUDevices; cudaGetDeviceCount(&numGPUDevices); int device[] = {(comm->getRank() % numGPUDevices)}; AMGX_config_add_parameters(&Config_, "communicator=MPI"); #ifdef NEW_COMM AMGX_resources_create(&Resources_, Config_, &mpiComm, 1/* number of GPU devices utilized by this rank */, device); #else AMGX_resources_create(&Resources_, Config_, MPI_COMM_WORLD, 1/* number of GPU devices utilized by this rank */, device); #endif } AMGX_Mode mode = AMGX_mode_dDDI; AMGX_solver_create(&Solver_, Resources_, mode, Config_); AMGX_matrix_create(&A_, Resources_, mode); AMGX_vector_create(&X_, Resources_, mode); AMGX_vector_create(&Y_, Resources_, mode); amgxTimer->stop(); amgxTimer->incrementNumCalls(); std::vector<int> amgx2muelu; // Construct AMGX communication pattern if (numProcs > 1) { RCP<const Tpetra::Import<LO,GO> > importer = inA->getCrsGraph()->getImporter(); TEUCHOS_TEST_FOR_EXCEPTION(importer.is_null(), MueLu::Exceptions::RuntimeError, "The matrix A has no Import object."); Tpetra::Distributor distributor = importer->getDistributor(); Array<int> sendRanks = distributor.getImagesTo(); Array<int> recvRanks = distributor.getImagesFrom(); std::sort(sendRanks.begin(), sendRanks.end()); std::sort(recvRanks.begin(), recvRanks.end()); bool match = true; if (sendRanks.size() != recvRanks.size()) { match = false; } else { for (int i = 0; i < sendRanks.size(); i++) { if (recvRanks[i] != sendRanks[i]) match = false; break; } } TEUCHOS_TEST_FOR_EXCEPTION(!match, MueLu::Exceptions::RuntimeError, "AMGX requires that the processors that we send to and receive from are the same. " "This is not the case: we send to {" << sendRanks << "} and receive from {" << recvRanks << "}"); int num_neighbors = sendRanks.size(); // does not include the calling process const int* neighbors = &sendRanks[0]; // Later on, we'll have to organize the send and recv data by PIDs, // i.e, a vector V of vectors, where V[i] is PID i's vector of data. // Hence we need to be able to quickly look up an array index // associated with each PID. Tpetra::Details::HashTable<int,int> hashTable(3*num_neighbors); for (int i = 0; i < num_neighbors; i++) hashTable.add(neighbors[i], i); // Get some information out ArrayView<const int> exportLIDs = importer->getExportLIDs(); ArrayView<const int> exportPIDs = importer->getExportPIDs(); Array<int> importPIDs; Tpetra::Import_Util::getPids(*importer, importPIDs, true/* make local -1 */); // Construct the reordering for AMGX as in AMGX_matrix_upload_all documentation RCP<const Map> rowMap = inA->getRowMap(); RCP<const Map> colMap = inA->getColMap(); int N = rowMap->getNodeNumElements(), Nc = colMap->getNodeNumElements(); muelu2amgx_.resize(Nc, -1); int numUniqExports = 0; for (int i = 0; i < exportLIDs.size(); i++) if (muelu2amgx_[exportLIDs[i]] == -1) { numUniqExports++; muelu2amgx_[exportLIDs[i]] = -2; } int localOffset = 0, exportOffset = N - numUniqExports; // Go through exported LIDs and put them at the end of LIDs for (int i = 0; i < exportLIDs.size(); i++) if (muelu2amgx_[exportLIDs[i]] < 0) // exportLIDs are not unique muelu2amgx_[exportLIDs[i]] = exportOffset++; // Go through all non-export LIDs, and put them at the beginning of LIDs for (int i = 0; i < N; i++) if (muelu2amgx_[i] == -1) muelu2amgx_[i] = localOffset++; // Go through the tail (imported LIDs), and order those by neighbors int importOffset = N; for (int k = 0; k < num_neighbors; k++) for (int i = 0; i < importPIDs.size(); i++) if (importPIDs[i] != -1 && hashTable.get(importPIDs[i]) == k) muelu2amgx_[i] = importOffset++; amgx2muelu.resize(muelu2amgx_.size()); for (int i = 0; i < muelu2amgx_.size(); i++) amgx2muelu[muelu2amgx_[i]] = i; // Construct send arrays std::vector<std::vector<int> > sendDatas (num_neighbors); std::vector<int> send_sizes(num_neighbors, 0); for (int i = 0; i < exportPIDs.size(); i++) { int index = hashTable.get(exportPIDs[i]); sendDatas [index].push_back(muelu2amgx_[exportLIDs[i]]); send_sizes[index]++; } // FIXME: sendDatas must be sorted (based on GIDs) std::vector<const int*> send_maps(num_neighbors); for (int i = 0; i < num_neighbors; i++) send_maps[i] = &(sendDatas[i][0]); // Debugging printMaps(comm, sendDatas, amgx2muelu, neighbors, *importer->getTargetMap(), "send_map_vector"); // Construct recv arrays std::vector<std::vector<int> > recvDatas (num_neighbors); std::vector<int> recv_sizes(num_neighbors, 0); for (int i = 0; i < importPIDs.size(); i++) if (importPIDs[i] != -1) { int index = hashTable.get(importPIDs[i]); recvDatas [index].push_back(muelu2amgx_[i]); recv_sizes[index]++; } // FIXME: recvDatas must be sorted (based on GIDs) std::vector<const int*> recv_maps(num_neighbors); for (int i = 0; i < num_neighbors; i++) recv_maps[i] = &(recvDatas[i][0]); // Debugging printMaps(comm, recvDatas, amgx2muelu, neighbors, *importer->getTargetMap(), "recv_map_vector"); 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])); AMGX_vector_bind(X_, A_); AMGX_vector_bind(Y_, A_); } RCP<Teuchos::Time> matrixTransformTimer = Teuchos::TimeMonitor::getNewTimer("MueLu: AMGX: transform matrix"); matrixTransformTimer->start(); ArrayRCP<const size_t> ia_s; ArrayRCP<const int> ja; ArrayRCP<const double> a; inA->getAllValues(ia_s, ja, a); ArrayRCP<int> ia(ia_s.size()); for (int i = 0; i < ia.size(); i++) ia[i] = Teuchos::as<int>(ia_s[i]); N_ = inA->getNodeNumRows(); int nnz = inA->getNodeNumEntries(); matrixTransformTimer->stop(); matrixTransformTimer->incrementNumCalls(); // Upload matrix // TODO Do we need to pin memory here through AMGX_pin_memory? RCP<Teuchos::Time> matrixTimer = Teuchos::TimeMonitor::getNewTimer("MueLu: AMGX: transfer matrix CPU->GPU"); matrixTimer->start(); if (numProcs == 1) { AMGX_matrix_upload_all(A_, N_, nnz, 1, 1, &ia[0], &ja[0], &a[0], NULL); } else { // Transform the matrix std::vector<int> ia_new(ia.size()); std::vector<int> ja_new(ja.size()); std::vector<double> a_new (a.size()); ia_new[0] = 0; for (int i = 0; i < N_; i++) { int oldRow = amgx2muelu[i]; ia_new[i+1] = ia_new[i] + (ia[oldRow+1] - ia[oldRow]); for (int j = ia[oldRow]; j < ia[oldRow+1]; j++) { int offset = j - ia[oldRow]; ja_new[ia_new[i] + offset] = muelu2amgx_[ja[j]]; a_new [ia_new[i] + offset] = a[j]; } // Do bubble sort on two arrays // NOTE: There are multiple possible optimizations here (even of bubble sort) bool swapped; do { swapped = false; for (int j = ia_new[i]; j < ia_new[i+1]-1; j++) if (ja_new[j] > ja_new[j+1]) { std::swap(ja_new[j], ja_new[j+1]); std::swap(a_new [j], a_new [j+1]); swapped = true; } } while (swapped == true); } AMGX_matrix_upload_all(A_, N_, nnz, 1, 1, &ia_new[0], &ja_new[0], &a_new[0], NULL); } matrixTimer->stop(); matrixTimer->incrementNumCalls(); domainMap_ = inA->getDomainMap(); rangeMap_ = inA->getRangeMap(); RCP<Teuchos::Time> realSetupTimer = Teuchos::TimeMonitor::getNewTimer("MueLu: AMGX: real setup"); realSetupTimer->start(); AMGX_solver_setup(Solver_, A_); realSetupTimer->stop(); realSetupTimer->incrementNumCalls(); vectorTimer1_ = Teuchos::TimeMonitor::getNewTimer("MueLu: AMGX: transfer vectors CPU->GPU"); vectorTimer2_ = Teuchos::TimeMonitor::getNewTimer("MueLu: AMGX: transfer vector GPU->CPU"); }