MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_Utilities.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "MueLu_Utilities_def.hpp"
11 
12 #include <string>
13 #include <locale>
14 
15 #ifdef HAVE_MUELU_EPETRAEXT
17 #endif
18 
19 #ifdef HAVE_MPI
20 #include <mpi.h>
21 #ifdef _WIN32
22 #include <winsock2.h>
23 #else
24 #include <netdb.h>
25 #include <arpa/inet.h>
26 #endif
27 #endif
28 
29 namespace MueLu {
30 
33 
34  long maxLevel = 0;
35 
36  for (ParameterList::ConstIterator inListEntry = inList.begin(); inListEntry != inList.end(); inListEntry++) {
37  const std::string& levelName = inListEntry->first;
38 
39  // Check for match of the form "level X" where X is a positive integer
40  if (inList.isSublist(levelName) && ((levelName.find("level ") == 0 && levelName.size() > 6) || levelName.find("user data") == 0)) {
41  int levelID = strtol(levelName.substr(6).c_str(), 0, 0);
42  bool userFlag = true;
43  if (levelName.find("user data") == std::string::npos) { // if "user data" is not found in levelName, switch userFlag and set levelID
44  userFlag = false;
45  levelID = strtol(levelName.substr(6).c_str(), 0, 0);
46  if (maxLevel < levelID)
47  maxLevel = levelID;
48  }
49 
50  // Split the sublist
51  const ParameterList& levelList = inList.sublist(levelName);
52  for (ParameterList::ConstIterator levelListEntry = levelList.begin(); levelListEntry != levelList.end(); levelListEntry++) {
53  const std::string& name = levelListEntry->first;
54  if (name == "A" || name == "P" || name == "R" || name == "M" || name == "Mdiag" || name == "K" || name == "Nullspace" || name == "Coordinates" || name == "D0" || name == "Dk_1" || name == "Dk_2" || name == "Mk_one" || name == "Mk_1_one" || name == "M1_beta" || name == "M1_alpha" || name == "invMk_1_invBeta" || name == "invMk_2_invAlpha" || name == "M1" || name == "Ms" || name == "M0inv" || name == "Pnodal" || name == "NodeMatrix" || name == "NodeAggMatrix" || name == "Node Comm" || name == "DualNodeID2PrimalNodeID"
55 #ifdef HAVE_MUELU_INTREPID2 // For the IntrepidPCoarsenFactory
56  || name == "pcoarsen: element to node map"
57 #endif
58  || name == "output stream") {
59  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
60  }
61 #ifdef HAVE_MUELU_MATLAB
62  else if (!userFlag && IsParamMuemexVariable(name)) {
63  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
64  }
65 #endif
66  else if (userFlag && IsParamValidVariable(name)) {
67  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
68  } else {
69  serialList.sublist(levelName).setEntry(name, levelListEntry->second);
70  }
71  }
72 
73  } else {
74  serialList.setEntry(inListEntry->first, inListEntry->second);
75  }
76  }
77 
78  return maxLevel;
79 }
80 
81 void TokenizeStringAndStripWhiteSpace(const std::string& stream, std::vector<std::string>& tokenList, const char* delimChars) {
82  // note: default delimiter string is ","
83  // Take a comma-separated list and tokenize it, stripping out leading & trailing whitespace. Then add to tokenList
84  char* buf = (char*)malloc(stream.size() + 1);
85  strcpy(buf, stream.c_str());
86  char* token = strtok(buf, delimChars);
87  if (token == NULL) {
88  free(buf);
89  return;
90  }
91  while (token) {
92  // token points to start of string to add to tokenList
93  // remove front whitespace...
94  char* tokStart = token;
95  char* tokEnd = token + strlen(token) - 1;
96  while (*tokStart == ' ' && tokStart < tokEnd)
97  tokStart++;
98  while (*tokEnd == ' ' && tokStart < tokEnd)
99  tokEnd--;
100  tokEnd++;
101  if (tokStart < tokEnd) {
102  std::string finishedToken(tokStart, tokEnd - tokStart); // use the constructor that takes a certain # of chars
103  tokenList.push_back(finishedToken);
104  }
105  token = strtok(NULL, delimChars);
106  }
107  free(buf);
108 }
109 
110 bool IsParamMuemexVariable(const std::string& name) {
111  // see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
112  char* str = (char*)malloc(name.length() + 1);
113  strcpy(str, name.c_str());
114  // Strip leading and trailing whitespace
115  char* firstWord = strtok(str, " ");
116  if (!firstWord) {
117  free(str);
118  return false;
119  }
120  char* secondWord = strtok(NULL, " ");
121  if (!secondWord) {
122  free(str);
123  return false;
124  }
125  char* thirdWord = strtok(NULL, " ");
126  if (thirdWord) {
127  free(str);
128  return false;
129  }
130  // convert first word to all lowercase for case insensitive compare
131  char* tolowerIt = firstWord;
132  while (*tolowerIt) {
133  *tolowerIt = (char)tolower(*tolowerIt);
134  tolowerIt++;
135  }
136  // See if the first word is one of the custom variable names
137  if (strstr(firstWord, "matrix") ||
138  strstr(firstWord, "multivector") ||
139  strstr(firstWord, "map") ||
140  strstr(firstWord, "ordinalvector") ||
141  strstr(firstWord, "int") ||
142  strstr(firstWord, "scalar") ||
143  strstr(firstWord, "double") ||
144  strstr(firstWord, "complex") ||
145  strstr(firstWord, "string"))
146  // Add name to list of keys to remove
147  {
148  free(str);
149  return true;
150  } else {
151  free(str);
152  return false;
153  }
154 }
155 
156 bool IsParamValidVariable(const std::string& name) {
157  // see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
158  char* str = (char*)malloc(name.length() + 1);
159  strcpy(str, name.c_str());
160  // Strip leading and trailing whitespace
161  char* firstWord = strtok(str, " ");
162  if (!firstWord) {
163  free(str);
164  return false;
165  }
166  char* secondWord = strtok(NULL, " ");
167  if (!secondWord) {
168  free(str);
169  return false;
170  }
171  char* thirdWord = strtok(NULL, " ");
172  if (thirdWord) {
173  free(str);
174  return false;
175  }
176  // convert first word to all lowercase for case insensitive compare
177  char* tolowerIt = firstWord;
178  while (*tolowerIt) {
179  *tolowerIt = (char)tolower(*tolowerIt);
180  tolowerIt++;
181  }
182  // See if the first word is one of the custom variable names
183  if (strstr(firstWord, "matrix") ||
184  strstr(firstWord, "multivector") ||
185  strstr(firstWord, "map") ||
186  strstr(firstWord, "ordinalvector") ||
187  strstr(firstWord, "int") ||
188  strstr(firstWord, "scalar") ||
189  strstr(firstWord, "double") ||
190  strstr(firstWord, "complex") ||
191  strstr(firstWord, "string") ||
192  strstr(firstWord, "array<go>") ||
193  strstr(firstWord, "array<lo>") ||
194  strstr(firstWord, "arrayrcp<lo>") ||
195  strstr(firstWord, "arrayrcp<go>"))
196  // Add name to list of keys to remove
197  {
198  free(str);
199  return true;
200  } else {
201  free(str);
202  return false;
203  }
204 }
205 
206 // Generates a communicator whose only members are other ranks of the baseComm on my node
207 Teuchos::RCP<const Teuchos::Comm<int> > GenerateNodeComm(RCP<const Teuchos::Comm<int> >& baseComm, int& NodeId, const int reductionFactor) {
208 #ifdef HAVE_MPI
209  int numRanks = baseComm->getSize();
210  if (numRanks == 1) {
211  NodeId = baseComm->getRank();
212  return baseComm;
213  }
214 
215  // Get an integer from the hostname
216  char hostname[MPI_MAX_PROCESSOR_NAME];
217  int len;
218  MPI_Get_processor_name(hostname, &len);
219  struct hostent* host = gethostbyname(hostname);
220  int myaddr = (int)inet_addr(inet_ntoa(*(struct in_addr*)host->h_addr));
221 
222  // All-to-all exchange of address integers
223  std::vector<int> addressList(numRanks);
224  Teuchos::gatherAll(*baseComm, 1, &myaddr, numRanks, &addressList[0]);
225 
226  // Sort!
227  std::sort(addressList.begin(), addressList.end());
228 
229  // Find which node I'm on (and stop when I've done that)
230  int numNodes = 0;
231  for (int i = 0, prev = addressList[0]; i < numRanks && prev != myaddr; i++) {
232  if (prev != addressList[i]) {
233  prev = addressList[i];
234  numNodes++;
235  }
236  }
237  NodeId = numNodes;
238 
239  // Generate nodal communicator
240  Teuchos::RCP<const Teuchos::Comm<int> > newComm = baseComm->split(NodeId, baseComm->getRank());
241 
242  // If we want to divide nodes up (for really beefy nodes), we do so here
243  if (reductionFactor != 1) {
244  // Find # cores per node
245  int lastI = 0;
246  int coresPerNode = 0;
247  for (int i = 0, prev = addressList[0]; i < numRanks; i++) {
248  if (prev != addressList[i]) {
249  prev = addressList[i];
250  coresPerNode = std::max(i - lastI, coresPerNode);
251  lastI = i;
252  }
253  }
254  coresPerNode = std::max(numRanks - lastI, coresPerNode);
255 
256  // Can we chop that up?
257  if (coresPerNode % reductionFactor != 0)
258  throw std::runtime_error("Reduction factor does not evently divide # cores per node");
259  int reducedCPN = coresPerNode / reductionFactor;
260  int nodeDivision = newComm->getRank() / reducedCPN;
261 
262  NodeId = numNodes * reductionFactor + nodeDivision;
263  newComm = baseComm->split(NodeId, baseComm->getRank());
264  }
265 
266  return newComm;
267 #else
268  NodeId = baseComm->getRank();
269  return baseComm;
270 #endif
271 }
272 
273 } // namespace MueLu
ParameterList & setEntry(const std::string &name, U &&entry)
ConstIterator end() const
std::string tolower(const std::string &str)
bool IsParamMuemexVariable(const std::string &name)
bool isSublist(const std::string &name) const
params_t::ConstIterator ConstIterator
ConstIterator begin() const
bool IsParamValidVariable(const std::string &name)
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
void TokenizeStringAndStripWhiteSpace(const std::string &stream, std::vector< std::string > &tokenList, const char *delimChars)
Teuchos::RCP< const Teuchos::Comm< int > > GenerateNodeComm(RCP< const Teuchos::Comm< int > > &baseComm, int &NodeId, const int reductionFactor)
long ExtractNonSerializableData(const Teuchos::ParameterList &inList, Teuchos::ParameterList &serialList, Teuchos::ParameterList &nonSerialList)
Extract non-serializable data from level-specific sublists and move it to a separate parameter list...