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