MueLu Version of the Day
Loading...
Searching...
No Matches
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 == "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
208bool 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
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)