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 if (name == "A" || name == "P" || name == "R" || name == "M" || name == "Mdiag" || name == "K" || name == "Nullspace" || name == "Material" || name == "Coordinates" || 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"
59#ifdef HAVE_MUELU_INTREPID2 // For the IntrepidPCoarsenFactory
60 || name == "pcoarsen: element to node map"
61#endif
62 || name == "output stream") {
63 nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
64 }
65#ifdef HAVE_MUELU_MATLAB
66 else if (!userFlag && IsParamMuemexVariable(name)) {
67 nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
68 }
69#endif
70 else if (userFlag && IsParamValidVariable(name)) {
71 nonSerialList.sublist(levelName).setEntry(name, levelListEntry->second);
72 } else {
73 serialList.sublist(levelName).setEntry(name, levelListEntry->second);
74 }
75 }
76
77 } else {
78 serialList.setEntry(inListEntry->first, inListEntry->second);
79 }
80 }
81
82 return maxLevel;
83}
84
85void TokenizeStringAndStripWhiteSpace(const std::string& stream, std::vector<std::string>& tokenList, const char* delimChars) {
86 // note: default delimiter string is ","
87 // Take a comma-separated list and tokenize it, stripping out leading & trailing whitespace. Then add to tokenList
88 char* buf = (char*)malloc(stream.size() + 1);
89 strcpy(buf, stream.c_str());
90 char* token = strtok(buf, delimChars);
91 if (token == NULL) {
92 free(buf);
93 return;
94 }
95 while (token) {
96 // token points to start of string to add to tokenList
97 // remove front whitespace...
98 char* tokStart = token;
99 char* tokEnd = token + strlen(token) - 1;
100 while (*tokStart == ' ' && tokStart < tokEnd)
101 tokStart++;
102 while (*tokEnd == ' ' && tokStart < tokEnd)
103 tokEnd--;
104 tokEnd++;
105 if (tokStart < tokEnd) {
106 std::string finishedToken(tokStart, tokEnd - tokStart); // use the constructor that takes a certain # of chars
107 tokenList.push_back(finishedToken);
108 }
109 token = strtok(NULL, delimChars);
110 }
111 free(buf);
112}
113
114bool IsParamMuemexVariable(const std::string& name) {
115 // see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
116 char* str = (char*)malloc(name.length() + 1);
117 strcpy(str, name.c_str());
118 // Strip leading and trailing whitespace
119 char* firstWord = strtok(str, " ");
120 if (!firstWord) {
121 free(str);
122 return false;
123 }
124 char* secondWord = strtok(NULL, " ");
125 if (!secondWord) {
126 free(str);
127 return false;
128 }
129 char* thirdWord = strtok(NULL, " ");
130 if (thirdWord) {
131 free(str);
132 return false;
133 }
134 // convert first word to all lowercase for case insensitive compare
135 char* tolowerIt = firstWord;
136 while (*tolowerIt) {
137 *tolowerIt = (char)tolower(*tolowerIt);
138 tolowerIt++;
139 }
140 // See if the first word is one of the custom variable names
141 if (strstr(firstWord, "matrix") ||
142 strstr(firstWord, "multivector") ||
143 strstr(firstWord, "map") ||
144 strstr(firstWord, "ordinalvector") ||
145 strstr(firstWord, "int") ||
146 strstr(firstWord, "scalar") ||
147 strstr(firstWord, "double") ||
148 strstr(firstWord, "complex") ||
149 strstr(firstWord, "string"))
150 // Add name to list of keys to remove
151 {
152 free(str);
153 return true;
154 } else {
155 free(str);
156 return false;
157 }
158}
159
160bool IsParamValidVariable(const std::string& name) {
161 // see if paramName is exactly two "words" - like "OrdinalVector myNullspace" or something
162 char* str = (char*)malloc(name.length() + 1);
163 strcpy(str, name.c_str());
164 // Strip leading and trailing whitespace
165 char* firstWord = strtok(str, " ");
166 if (!firstWord) {
167 free(str);
168 return false;
169 }
170 char* secondWord = strtok(NULL, " ");
171 if (!secondWord) {
172 free(str);
173 return false;
174 }
175 char* thirdWord = strtok(NULL, " ");
176 if (thirdWord) {
177 free(str);
178 return false;
179 }
180 // convert first word to all lowercase for case insensitive compare
181 char* tolowerIt = firstWord;
182 while (*tolowerIt) {
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 strstr(firstWord, "array<go>") ||
197 strstr(firstWord, "array<lo>") ||
198 strstr(firstWord, "arrayrcp<lo>") ||
199 strstr(firstWord, "arrayrcp<go>"))
200 // Add name to list of keys to remove
201 {
202 free(str);
203 return true;
204 } else {
205 free(str);
206 return false;
207 }
208}
209
210// Generates a communicator whose only members are other ranks of the baseComm on my node
211Teuchos::RCP<const Teuchos::Comm<int> > GenerateNodeComm(RCP<const Teuchos::Comm<int> >& baseComm, int& NodeId, const int reductionFactor) {
212#ifdef HAVE_MPI
213 int numRanks = baseComm->getSize();
214 if (numRanks == 1) {
215 NodeId = baseComm->getRank();
216 return baseComm;
217 }
218
219 // Get an integer from the hostname
220 char hostname[MPI_MAX_PROCESSOR_NAME];
221 int len;
222 MPI_Get_processor_name(hostname, &len);
223 struct hostent* host = gethostbyname(hostname);
224 int myaddr = (int)inet_addr(inet_ntoa(*(struct in_addr*)host->h_addr));
225
226 // All-to-all exchange of address integers
227 std::vector<int> addressList(numRanks);
228 Teuchos::gatherAll(*baseComm, 1, &myaddr, numRanks, &addressList[0]);
229
230 // Sort!
231 std::sort(addressList.begin(), addressList.end());
232
233 // Find which node I'm on (and stop when I've done that)
234 int numNodes = 0;
235 for (int i = 0, prev = addressList[0]; i < numRanks && prev != myaddr; i++) {
236 if (prev != addressList[i]) {
237 prev = addressList[i];
238 numNodes++;
239 }
240 }
241 NodeId = numNodes;
242
243 // Generate nodal communicator
244 Teuchos::RCP<const Teuchos::Comm<int> > newComm = baseComm->split(NodeId, baseComm->getRank());
245
246 // If we want to divide nodes up (for really beefy nodes), we do so here
247 if (reductionFactor != 1) {
248 // Find # cores per node
249 int lastI = 0;
250 int coresPerNode = 0;
251 for (int i = 0, prev = addressList[0]; i < numRanks; i++) {
252 if (prev != addressList[i]) {
253 prev = addressList[i];
254 coresPerNode = std::max(i - lastI, coresPerNode);
255 lastI = i;
256 }
257 }
258 coresPerNode = std::max(numRanks - lastI, coresPerNode);
259
260 // Can we chop that up?
261 if (coresPerNode % reductionFactor != 0)
262 throw std::runtime_error("Reduction factor does not evently divide # cores per node");
263 int reducedCPN = coresPerNode / reductionFactor;
264 int nodeDivision = newComm->getRank() / reducedCPN;
265
266 NodeId = numNodes * reductionFactor + nodeDivision;
267 newComm = baseComm->split(NodeId, baseComm->getRank());
268 }
269
270 return newComm;
271#else
272 NodeId = baseComm->getRank();
273 return baseComm;
274#endif
275}
276
277} // 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)