MueLu  Version of the Day
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 
66 
67 namespace MueLu {
68 
69  long ExtractNonSerializableData(const Teuchos::ParameterList& inList, Teuchos::ParameterList& serialList, Teuchos::ParameterList& nonSerialList) {
70  using Teuchos::ParameterList;
71 
72  long maxLevel = 0;
73 
74  for (ParameterList::ConstIterator inListEntry = inList.begin(); inListEntry != inList.end(); inListEntry++) {
75  const std::string& levelName = inListEntry->first;
76 
77  // Check for match of the form "level X" where X is a positive integer
78  if (inList.isSublist(levelName) && ((levelName.find("level ") == 0 && levelName.size() > 6) || levelName.find("user data") == 0)) {
79  int levelID = strtol(levelName.substr(6).c_str(), 0, 0);
80  bool userFlag = true;
81  if(levelName.find("user data") == std::string::npos) { // if "user data" is not found in levelName, switch userFlag and set levelID
82  userFlag = false;
83  levelID = strtol(levelName.substr(6).c_str(), 0, 0);
84  if (maxLevel < levelID)
85  maxLevel = levelID;
86  }
87 
88  // Split the sublist
89  const ParameterList& levelList = inList.sublist(levelName);
90  for (ParameterList::ConstIterator levelListEntry = levelList.begin(); levelListEntry != levelList.end(); levelListEntry++) {
91  const std::string& name = levelListEntry->first;
92  if (name == "A" || name == "P" || name == "R" || name== "M" || name == "Mdiag" || name == "K" || name == "Nullspace" || name == "Coordinates"
93  || name == "Node Comm" || name == "DualNodeID2PrimalNodeID"
94 #ifdef HAVE_MUELU_INTREPID2 // For the IntrepidPCoarsenFactory
95  || name == "pcoarsen: element to node map"
96 #endif
97  || name == "output stream"
98  )
99  {
100  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
101  }
102 #ifdef HAVE_MUELU_MATLAB
103  else if(!userFlag && IsParamMuemexVariable(name))
104  {
105  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
106  }
107 #endif
108  else if( userFlag && IsParamValidVariable(name)) {
109  nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
110  } else {
111  serialList.sublist(levelName).setEntry(name, levelListEntry->second);
112  }
113  }
114 
115  } else {
116  serialList.setEntry(inListEntry->first, inListEntry->second);
117  }
118  }
119 
120  return maxLevel;
121  }
122 
123  void TokenizeStringAndStripWhiteSpace(const std::string& stream, std::vector<std::string>& tokenList, const char* delimChars)
124  {
125  //note: default delimiter string is ","
126  // Take a comma-separated list and tokenize it, stripping out leading & trailing whitespace. Then add to tokenList
127  char* buf = (char*) malloc(stream.size() + 1);
128  strcpy(buf, stream.c_str());
129  char* token = strtok(buf, delimChars);
130  if(token == NULL)
131  {
132  free(buf);
133  return;
134  }
135  while(token)
136  {
137  //token points to start of string to add to tokenList
138  //remove front whitespace...
139  char* tokStart = token;
140  char* tokEnd = token + strlen(token) - 1;
141  while(*tokStart == ' ' && tokStart < tokEnd)
142  tokStart++;
143  while(*tokEnd == ' ' && tokStart < tokEnd)
144  tokEnd--;
145  tokEnd++;
146  if(tokStart < tokEnd)
147  {
148  std::string finishedToken(tokStart, tokEnd - tokStart); //use the constructor that takes a certain # of chars
149  tokenList.push_back(finishedToken);
150  }
151  token = strtok(NULL, delimChars);
152  }
153  free(buf);
154  }
155 
156  bool IsParamMuemexVariable(const std::string& name)
157  {
158  //see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
159  char* str = (char*) malloc(name.length() + 1);
160  strcpy(str, name.c_str());
161  //Strip leading and trailing whitespace
162  char* firstWord = strtok(str, " ");
163  if(!firstWord) {
164  free(str);
165  return false;
166  }
167  char* secondWord = strtok(NULL, " ");
168  if(!secondWord) {
169  free(str);
170  return false;
171  }
172  char* thirdWord = strtok(NULL, " ");
173  if(thirdWord) {
174  free(str);
175  return false;
176  }
177  //convert first word to all lowercase for case insensitive compare
178  char* tolowerIt = firstWord;
179  while(*tolowerIt)
180  {
181  *tolowerIt = (char) tolower(*tolowerIt);
182  tolowerIt++;
183  }
184  //See if the first word is one of the custom variable names
185  if(strstr(firstWord, "matrix") ||
186  strstr(firstWord, "multivector") ||
187  strstr(firstWord, "map") ||
188  strstr(firstWord, "ordinalvector") ||
189  strstr(firstWord, "int") ||
190  strstr(firstWord, "scalar") ||
191  strstr(firstWord, "double") ||
192  strstr(firstWord, "complex") ||
193  strstr(firstWord, "string"))
194  //Add name to list of keys to remove
195  {
196  free(str);
197  return true;
198  }
199  else
200  {
201  free(str);
202  return false;
203  }
204  }
205 
206 bool IsParamValidVariable(const std::string& name)
207  {
208  //see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
209  char* str = (char*) malloc(name.length() + 1);
210  strcpy(str, name.c_str());
211  //Strip leading and trailing whitespace
212  char* firstWord = strtok(str, " ");
213  if(!firstWord) {
214  free(str);
215  return false;
216  }
217  char* secondWord = strtok(NULL, " ");
218  if(!secondWord) {
219  free(str);
220  return false;
221  }
222  char* thirdWord = strtok(NULL, " ");
223  if(thirdWord) {
224  free(str);
225  return false;
226  }
227  //convert first word to all lowercase for case insensitive compare
228  char* tolowerIt = firstWord;
229  while(*tolowerIt)
230  {
231  *tolowerIt = (char) tolower(*tolowerIt);
232  tolowerIt++;
233  }
234  //See if the first word is one of the custom variable names
235  if(strstr(firstWord, "matrix") ||
236  strstr(firstWord, "multivector") ||
237  strstr(firstWord, "map") ||
238  strstr(firstWord, "ordinalvector") ||
239  strstr(firstWord, "int") ||
240  strstr(firstWord, "scalar") ||
241  strstr(firstWord, "double") ||
242  strstr(firstWord, "complex") ||
243  strstr(firstWord, "string") ||
244  strstr(firstWord, "array<go>") ||
245  strstr(firstWord, "array<lo>") ||
246  strstr(firstWord, "arrayrcp<lo>") ||
247  strstr(firstWord, "arrayrcp<go>"))
248  //Add name to list of keys to remove
249  {
250  free(str);
251  return true;
252  }
253  else
254  {
255  free(str);
256  return false;
257  }
258  }
259 
260 
261  // Generates a communicator whose only members are other ranks of the baseComm on my node
262  Teuchos::RCP<const Teuchos::Comm<int> > GenerateNodeComm(RCP<const Teuchos::Comm<int> > & baseComm, int &NodeId, const int reductionFactor) {
263 #ifdef HAVE_MPI
264  int numRanks = baseComm->getSize();
265  if(numRanks == 1) {NodeId = baseComm->getRank(); return baseComm;}
266 
267  // Get an integer from the hostname
268  char hostname[MPI_MAX_PROCESSOR_NAME];
269  int len;
270  MPI_Get_processor_name(hostname,&len);
271  struct hostent * host = gethostbyname(hostname);
272  int myaddr = (int) inet_addr(inet_ntoa(*(struct in_addr *)host->h_addr));
273 
274  // All-to-all exchange of address integers
275  std::vector<int> addressList(numRanks);
276  Teuchos::gatherAll(*baseComm,1,&myaddr,numRanks,&addressList[0]);
277 
278  // Sort!
279  std::sort(addressList.begin(),addressList.end());
280 
281  // Find which node I'm on (and stop when I've done that)
282  int numNodes = 0;
283  for(int i=0, prev=addressList[0]; i<numRanks && prev != myaddr; i++) {
284  if(prev != addressList[i]) {
285  prev = addressList[i];
286  numNodes++;
287  }
288  }
289  NodeId = numNodes;
290 
291  // Generate nodal communicator
292  Teuchos::RCP<const Teuchos::Comm<int> > newComm = baseComm->split(NodeId,baseComm->getRank());
293 
294  // If we want to divide nodes up (for really beefy nodes), we do so here
295  if(reductionFactor != 1) {
296  // Find # cores per node
297  int lastI = 0;
298  int coresPerNode = 0;
299  for(int i=0, prev=addressList[0]; i<numRanks; i++) {
300  if(prev != addressList[i]) {
301  prev = addressList[i];
302  coresPerNode = std::max(i - lastI, coresPerNode);
303  lastI = i;
304  }
305  }
306  coresPerNode = std::max(numRanks - lastI, coresPerNode);
307 
308  // Can we chop that up?
309  if(coresPerNode % reductionFactor != 0)
310  throw std::runtime_error("Reduction factor does not evently divide # cores per node");
311  int reducedCPN = coresPerNode / reductionFactor;
312  int nodeDivision = newComm->getRank() / reducedCPN;
313 
314  NodeId = numNodes * reductionFactor + nodeDivision;
315  newComm = baseComm->split(NodeId,baseComm->getRank());
316  }
317 
318  return newComm;
319 #else
320  NodeId = baseComm->getRank();
321  return baseComm;
322 #endif
323  }
324 
325 
326 } // namespace MueLu
Teuchos::RCP< const Teuchos::Comm< int > > GenerateNodeComm(RCP< const Teuchos::Comm< int > > &baseComm, int &NodeId, const int reductionFactor)
std::string tolower(const std::string &str)
Namespace for MueLu classes and methods.
bool IsParamMuemexVariable(const std::string &name)
bool IsParamValidVariable(const std::string &name)
void TokenizeStringAndStripWhiteSpace(const std::string &stream, std::vector< std::string > &tokenList, const char *delimChars)
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...