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