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