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 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #include "MueLu_Utilities_def.hpp"
47 
48 #include <string>
49 #include <locale>
50 
51 #ifdef HAVE_MUELU_EPETRAEXT
53 #endif
54 
55 #ifdef HAVE_MPI
56 #include <mpi.h>
57 #ifdef _WIN32
58 #include <winsock2.h>
59 #else
60 #include <netdb.h>
61 #include <arpa/inet.h>
62 #endif
63 #endif
64 
65 namespace MueLu {
66 
69 
70  long maxLevel = 0;
71 
72  for (ParameterList::ConstIterator inListEntry = inList.begin(); inListEntry != inList.end(); inListEntry++) {
73  const std::string& levelName = inListEntry->first;
74 
75  // Check for match of the form "level X" where X is a positive integer
76  if (inList.isSublist(levelName) && ((levelName.find("level ") == 0 && levelName.size() > 6) || levelName.find("user data") == 0)) {
77  int levelID = strtol(levelName.substr(6).c_str(), 0, 0);
78  bool userFlag = true;
79  if (levelName.find("user data") == std::string::npos) { // if "user data" is not found in levelName, switch userFlag and set levelID
80  userFlag = false;
81  levelID = strtol(levelName.substr(6).c_str(), 0, 0);
82  if (maxLevel < levelID)
83  maxLevel = levelID;
84  }
85 
86  // Split the sublist
87  const ParameterList& levelList = inList.sublist(levelName);
88  for (ParameterList::ConstIterator levelListEntry = levelList.begin(); levelListEntry != levelList.end(); levelListEntry++) {
89  const std::string& name = levelListEntry->first;
90  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"
91 #ifdef HAVE_MUELU_INTREPID2 // For the IntrepidPCoarsenFactory
92  || name == "pcoarsen: element to node map"
93 #endif
94  || name == "output stream") {
95  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
96  }
97 #ifdef HAVE_MUELU_MATLAB
98  else if (!userFlag && IsParamMuemexVariable(name)) {
99  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
100  }
101 #endif
102  else if (userFlag && IsParamValidVariable(name)) {
103  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
104  } else {
105  serialList.sublist(levelName).setEntry(name, levelListEntry->second);
106  }
107  }
108 
109  } else {
110  serialList.setEntry(inListEntry->first, inListEntry->second);
111  }
112  }
113 
114  return maxLevel;
115 }
116 
117 void TokenizeStringAndStripWhiteSpace(const std::string& stream, std::vector<std::string>& tokenList, const char* delimChars) {
118  // note: default delimiter string is ","
119  // Take a comma-separated list and tokenize it, stripping out leading & trailing whitespace. Then add to tokenList
120  char* buf = (char*)malloc(stream.size() + 1);
121  strcpy(buf, stream.c_str());
122  char* token = strtok(buf, delimChars);
123  if (token == NULL) {
124  free(buf);
125  return;
126  }
127  while (token) {
128  // token points to start of string to add to tokenList
129  // remove front whitespace...
130  char* tokStart = token;
131  char* tokEnd = token + strlen(token) - 1;
132  while (*tokStart == ' ' && tokStart < tokEnd)
133  tokStart++;
134  while (*tokEnd == ' ' && tokStart < tokEnd)
135  tokEnd--;
136  tokEnd++;
137  if (tokStart < tokEnd) {
138  std::string finishedToken(tokStart, tokEnd - tokStart); // use the constructor that takes a certain # of chars
139  tokenList.push_back(finishedToken);
140  }
141  token = strtok(NULL, delimChars);
142  }
143  free(buf);
144 }
145 
146 bool IsParamMuemexVariable(const std::string& name) {
147  // see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
148  char* str = (char*)malloc(name.length() + 1);
149  strcpy(str, name.c_str());
150  // Strip leading and trailing whitespace
151  char* firstWord = strtok(str, " ");
152  if (!firstWord) {
153  free(str);
154  return false;
155  }
156  char* secondWord = strtok(NULL, " ");
157  if (!secondWord) {
158  free(str);
159  return false;
160  }
161  char* thirdWord = strtok(NULL, " ");
162  if (thirdWord) {
163  free(str);
164  return false;
165  }
166  // convert first word to all lowercase for case insensitive compare
167  char* tolowerIt = firstWord;
168  while (*tolowerIt) {
169  *tolowerIt = (char)tolower(*tolowerIt);
170  tolowerIt++;
171  }
172  // See if the first word is one of the custom variable names
173  if (strstr(firstWord, "matrix") ||
174  strstr(firstWord, "multivector") ||
175  strstr(firstWord, "map") ||
176  strstr(firstWord, "ordinalvector") ||
177  strstr(firstWord, "int") ||
178  strstr(firstWord, "scalar") ||
179  strstr(firstWord, "double") ||
180  strstr(firstWord, "complex") ||
181  strstr(firstWord, "string"))
182  // Add name to list of keys to remove
183  {
184  free(str);
185  return true;
186  } else {
187  free(str);
188  return false;
189  }
190 }
191 
192 bool IsParamValidVariable(const std::string& name) {
193  // see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
194  char* str = (char*)malloc(name.length() + 1);
195  strcpy(str, name.c_str());
196  // Strip leading and trailing whitespace
197  char* firstWord = strtok(str, " ");
198  if (!firstWord) {
199  free(str);
200  return false;
201  }
202  char* secondWord = strtok(NULL, " ");
203  if (!secondWord) {
204  free(str);
205  return false;
206  }
207  char* thirdWord = strtok(NULL, " ");
208  if (thirdWord) {
209  free(str);
210  return false;
211  }
212  // convert first word to all lowercase for case insensitive compare
213  char* tolowerIt = firstWord;
214  while (*tolowerIt) {
215  *tolowerIt = (char)tolower(*tolowerIt);
216  tolowerIt++;
217  }
218  // See if the first word is one of the custom variable names
219  if (strstr(firstWord, "matrix") ||
220  strstr(firstWord, "multivector") ||
221  strstr(firstWord, "map") ||
222  strstr(firstWord, "ordinalvector") ||
223  strstr(firstWord, "int") ||
224  strstr(firstWord, "scalar") ||
225  strstr(firstWord, "double") ||
226  strstr(firstWord, "complex") ||
227  strstr(firstWord, "string") ||
228  strstr(firstWord, "array<go>") ||
229  strstr(firstWord, "array<lo>") ||
230  strstr(firstWord, "arrayrcp<lo>") ||
231  strstr(firstWord, "arrayrcp<go>"))
232  // Add name to list of keys to remove
233  {
234  free(str);
235  return true;
236  } else {
237  free(str);
238  return false;
239  }
240 }
241 
242 // Generates a communicator whose only members are other ranks of the baseComm on my node
243 Teuchos::RCP<const Teuchos::Comm<int> > GenerateNodeComm(RCP<const Teuchos::Comm<int> >& baseComm, int& NodeId, const int reductionFactor) {
244 #ifdef HAVE_MPI
245  int numRanks = baseComm->getSize();
246  if (numRanks == 1) {
247  NodeId = baseComm->getRank();
248  return baseComm;
249  }
250 
251  // Get an integer from the hostname
252  char hostname[MPI_MAX_PROCESSOR_NAME];
253  int len;
254  MPI_Get_processor_name(hostname, &len);
255  struct hostent* host = gethostbyname(hostname);
256  int myaddr = (int)inet_addr(inet_ntoa(*(struct in_addr*)host->h_addr));
257 
258  // All-to-all exchange of address integers
259  std::vector<int> addressList(numRanks);
260  Teuchos::gatherAll(*baseComm, 1, &myaddr, numRanks, &addressList[0]);
261 
262  // Sort!
263  std::sort(addressList.begin(), addressList.end());
264 
265  // Find which node I'm on (and stop when I've done that)
266  int numNodes = 0;
267  for (int i = 0, prev = addressList[0]; i < numRanks && prev != myaddr; i++) {
268  if (prev != addressList[i]) {
269  prev = addressList[i];
270  numNodes++;
271  }
272  }
273  NodeId = numNodes;
274 
275  // Generate nodal communicator
276  Teuchos::RCP<const Teuchos::Comm<int> > newComm = baseComm->split(NodeId, baseComm->getRank());
277 
278  // If we want to divide nodes up (for really beefy nodes), we do so here
279  if (reductionFactor != 1) {
280  // Find # cores per node
281  int lastI = 0;
282  int coresPerNode = 0;
283  for (int i = 0, prev = addressList[0]; i < numRanks; i++) {
284  if (prev != addressList[i]) {
285  prev = addressList[i];
286  coresPerNode = std::max(i - lastI, coresPerNode);
287  lastI = i;
288  }
289  }
290  coresPerNode = std::max(numRanks - lastI, coresPerNode);
291 
292  // Can we chop that up?
293  if (coresPerNode % reductionFactor != 0)
294  throw std::runtime_error("Reduction factor does not evently divide # cores per node");
295  int reducedCPN = coresPerNode / reductionFactor;
296  int nodeDivision = newComm->getRank() / reducedCPN;
297 
298  NodeId = numNodes * reductionFactor + nodeDivision;
299  newComm = baseComm->split(NodeId, baseComm->getRank());
300  }
301 
302  return newComm;
303 #else
304  NodeId = baseComm->getRank();
305  return baseComm;
306 #endif
307 }
308 
309 } // 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...