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
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
67namespace 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
206bool 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
std::string tolower(const std::string &str)
Namespace for MueLu classes and methods.
bool IsParamMuemexVariable(const std::string &name)
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.
bool IsParamValidVariable(const std::string &name)
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)