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