MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_Utilities.cpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
11
12#include <string>
13#include <locale>
14#ifdef _WIN32
15#define NOMINMAX
16#endif
17#include <algorithm>
18
19#ifdef HAVE_MUELU_EPETRAEXT
21#endif
22
23#ifdef HAVE_MPI
24#include <mpi.h>
25#ifdef _WIN32
26#include <winsock2.h>
27#else
28#include <netdb.h>
29#include <arpa/inet.h>
30#endif
31#endif
32
33namespace MueLu {
34
35long ExtractNonSerializableData(const Teuchos::ParameterList& inList, Teuchos::ParameterList& serialList, Teuchos::ParameterList& nonSerialList) {
36 using Teuchos::ParameterList;
37
38 long maxLevel = 0;
39
40 for (ParameterList::ConstIterator inListEntry = inList.begin(); inListEntry != inList.end(); inListEntry++) {
41 const std::string& levelName = inListEntry->first;
42
43 // Check for match of the form "level X" where X is a positive integer
44 if (inList.isSublist(levelName) && ((levelName.find("level ") == 0 && levelName.size() > 6) || levelName.find("user data") == 0)) {
45 int levelID = strtol(levelName.substr(6).c_str(), 0, 0);
46 bool userFlag = true;
47 if (levelName.find("user data") == std::string::npos) { // if "user data" is not found in levelName, switch userFlag and set levelID
48 userFlag = false;
49 levelID = strtol(levelName.substr(6).c_str(), 0, 0);
50 if (maxLevel < levelID)
51 maxLevel = levelID;
52 }
53
54 // Split the sublist
55 const ParameterList& levelList = inList.sublist(levelName);
56 for (ParameterList::ConstIterator levelListEntry = levelList.begin(); levelListEntry != levelList.end(); levelListEntry++) {
57 const std::string& name = levelListEntry->first;
58 // Check if the name starts with "Nullspace", has length > 9, and the last character is a digit
59 bool isNumberedNullspace = (name.rfind("Nullspace", 0) == 0 && name.length() > 9 && std::isdigit(name.back(), std::locale::classic()));
60
61 if (name == "A" || name == "P" || name == "R" || name == "M" || name == "Mdiag" || name == "K" || name == "Nullspace" || name == "Material" || name == "Coordinates" || name == "BlockNumber" || name == "D0" || name == "Dk_1" || name == "Dk_2" || name == "Mk_one" || name == "Mk_1_one" || name == "M1_beta" || name == "M1_alpha" || name == "invMk_1_invBeta" || name == "invMk_2_invAlpha" || name == "M1" || name == "Ms" || name == "M0inv" || name == "Pnodal" || name == "NodeMatrix" || name == "NodeAggMatrix" || name == "Node Comm" || name == "DualNodeID2PrimalNodeID"
62#ifdef HAVE_MUELU_INTREPID2 // For the IntrepidPCoarsenFactory
63 || name == "pcoarsen: element to node map"
64#endif
65 || name == "output stream" || isNumberedNullspace) {
66 nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
67 }
68#ifdef HAVE_MUELU_MATLAB
69 else if (!userFlag && IsParamMuemexVariable(name)) {
70 nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
71 }
72#endif
73 else if (userFlag && IsParamValidVariable(name)) {
74 nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
75 } else {
76 serialList.sublist(levelName).setEntry(name, levelListEntry->second);
77 }
78 }
79
80 } else {
81 serialList.setEntry(inListEntry->first, inListEntry->second);
82 }
83 }
84
85 return maxLevel;
86}
87
88void TokenizeStringAndStripWhiteSpace(const std::string& stream, std::vector<std::string>& tokenList, const char* delimChars) {
89 // note: default delimiter string is ","
90 // Take a comma-separated list and tokenize it, stripping out leading & trailing whitespace. Then add to tokenList
91 char* buf = (char*)malloc(stream.size() + 1);
92 strcpy(buf, stream.c_str());
93 char* token = strtok(buf, delimChars);
94 if (token == NULL) {
95 free(buf);
96 return;
97 }
98 while (token) {
99 // token points to start of string to add to tokenList
100 // remove front whitespace...
101 char* tokStart = token;
102 char* tokEnd = token + strlen(token) - 1;
103 while (*tokStart == ' ' && tokStart < tokEnd)
104 tokStart++;
105 while (*tokEnd == ' ' && tokStart < tokEnd)
106 tokEnd--;
107 tokEnd++;
108 if (tokStart < tokEnd) {
109 std::string finishedToken(tokStart, tokEnd - tokStart); // use the constructor that takes a certain # of chars
110 tokenList.push_back(finishedToken);
111 }
112 token = strtok(NULL, delimChars);
113 }
114 free(buf);
115}
116
117bool IsParamMuemexVariable(const std::string& name) {
118 // see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
119 char* str = (char*)malloc(name.length() + 1);
120 strcpy(str, name.c_str());
121 // Strip leading and trailing whitespace
122 char* firstWord = strtok(str, " ");
123 if (!firstWord) {
124 free(str);
125 return false;
126 }
127 char* secondWord = strtok(NULL, " ");
128 if (!secondWord) {
129 free(str);
130 return false;
131 }
132 char* thirdWord = strtok(NULL, " ");
133 if (thirdWord) {
134 free(str);
135 return false;
136 }
137 // convert first word to all lowercase for case insensitive compare
138 char* tolowerIt = firstWord;
139 while (*tolowerIt) {
140 *tolowerIt = (char)tolower(*tolowerIt);
141 tolowerIt++;
142 }
143 // See if the first word is one of the custom variable names
144 if (strstr(firstWord, "matrix") ||
145 strstr(firstWord, "multivector") ||
146 strstr(firstWord, "map") ||
147 strstr(firstWord, "ordinalvector") ||
148 strstr(firstWord, "int") ||
149 strstr(firstWord, "scalar") ||
150 strstr(firstWord, "double") ||
151 strstr(firstWord, "complex") ||
152 strstr(firstWord, "string"))
153 // Add name to list of keys to remove
154 {
155 free(str);
156 return true;
157 } else {
158 free(str);
159 return false;
160 }
161}
162
163bool IsParamValidVariable(const std::string& name) {
164 // see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
165 char* str = (char*)malloc(name.length() + 1);
166 strcpy(str, name.c_str());
167 // Strip leading and trailing whitespace
168 char* firstWord = strtok(str, " ");
169 if (!firstWord) {
170 free(str);
171 return false;
172 }
173 char* secondWord = strtok(NULL, " ");
174 if (!secondWord) {
175 free(str);
176 return false;
177 }
178 char* thirdWord = strtok(NULL, " ");
179 if (thirdWord) {
180 free(str);
181 return false;
182 }
183 // convert first word to all lowercase for case insensitive compare
184 char* tolowerIt = firstWord;
185 while (*tolowerIt) {
186 *tolowerIt = (char)tolower(*tolowerIt);
187 tolowerIt++;
188 }
189 // See if the first word is one of the custom variable names
190 if (strstr(firstWord, "matrix") ||
191 strstr(firstWord, "multivector") ||
192 strstr(firstWord, "map") ||
193 strstr(firstWord, "ordinalvector") ||
194 strstr(firstWord, "int") ||
195 strstr(firstWord, "scalar") ||
196 strstr(firstWord, "double") ||
197 strstr(firstWord, "complex") ||
198 strstr(firstWord, "string") ||
199 strstr(firstWord, "array<go>") ||
200 strstr(firstWord, "array<lo>") ||
201 strstr(firstWord, "arrayrcp<lo>") ||
202 strstr(firstWord, "arrayrcp<go>"))
203 // Add name to list of keys to remove
204 {
205 free(str);
206 return true;
207 } else {
208 free(str);
209 return false;
210 }
211}
212
213// Generates a communicator whose only members are other ranks of the baseComm on my node
214Teuchos::RCP<const Teuchos::Comm<int> > GenerateNodeComm(RCP<const Teuchos::Comm<int> >& baseComm, int& NodeId, const int reductionFactor) {
215#ifdef HAVE_MPI
216 int numRanks = baseComm->getSize();
217 if (numRanks == 1) {
218 NodeId = baseComm->getRank();
219 return baseComm;
220 }
221
222 // Get an integer from the hostname
223 char hostname[MPI_MAX_PROCESSOR_NAME];
224 int len;
225 MPI_Get_processor_name(hostname, &len);
226 struct hostent* host = gethostbyname(hostname);
227 int myaddr = (int)inet_addr(inet_ntoa(*(struct in_addr*)host->h_addr));
228
229 // All-to-all exchange of address integers
230 std::vector<int> addressList(numRanks);
231 Teuchos::gatherAll(*baseComm, 1, &myaddr, numRanks, &addressList[0]);
232
233 // Sort!
234 std::sort(addressList.begin(), addressList.end());
235
236 // Find which node I'm on (and stop when I've done that)
237 int numNodes = 0;
238 for (int i = 0, prev = addressList[0]; i < numRanks && prev != myaddr; i++) {
239 if (prev != addressList[i]) {
240 prev = addressList[i];
241 numNodes++;
242 }
243 }
244 NodeId = numNodes;
245
246 // Generate nodal communicator
247 Teuchos::RCP<const Teuchos::Comm<int> > newComm = baseComm->split(NodeId, baseComm->getRank());
248
249 // If we want to divide nodes up (for really beefy nodes), we do so here
250 if (reductionFactor != 1) {
251 // Find # cores per node
252 int lastI = 0;
253 int coresPerNode = 0;
254 for (int i = 0, prev = addressList[0]; i < numRanks; i++) {
255 if (prev != addressList[i]) {
256 prev = addressList[i];
257 coresPerNode = std::max(i - lastI, coresPerNode);
258 lastI = i;
259 }
260 }
261 coresPerNode = std::max(numRanks - lastI, coresPerNode);
262
263 // Can we chop that up?
264 if (coresPerNode % reductionFactor != 0)
265 throw std::runtime_error("Reduction factor does not evently divide # cores per node");
266 int reducedCPN = coresPerNode / reductionFactor;
267 int nodeDivision = newComm->getRank() / reducedCPN;
268
269 NodeId = numNodes * reductionFactor + nodeDivision;
270 newComm = baseComm->split(NodeId, baseComm->getRank());
271 }
272
273 return newComm;
274#else
275 NodeId = baseComm->getRank();
276 return baseComm;
277#endif
278}
279
280} // 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)