MueLu  Version of the Day
MueLu_ML2MueLuParameterTranslator.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
46 
47 #include "MueLu_ConfigDefs.hpp"
48 #if defined(HAVE_MUELU_ML) && defined(HAVE_MUELU_EPETRA)
49 #include <ml_ValidateParameters.h>
50 #include <ml_MultiLevelPreconditioner.h> // for default values
51 #endif
52 
54 
55 namespace MueLu {
56 
57 
58  std::string ML2MueLuParameterTranslator::GetSmootherFactory(const Teuchos::ParameterList& paramList, Teuchos::ParameterList& adaptingParamList, const std::string& pname, const std::string& value) {
59 
60  TEUCHOS_TEST_FOR_EXCEPTION(pname != "coarse: type" && pname != "coarse: list" && pname != "smoother: type" && pname.find("smoother: list",0) != 0, Exceptions::RuntimeError, "MueLu::MLParameterListInterpreter::Setup(): Only \"coarse: type\", \"smoother: type\" or \"smoother: list\" (\"coarse: list\") are supported as ML parameters for transformation of smoother/solver parameters to MueLu");
61 
62  // string stream containing the smoother/solver xml parameters
63  std::stringstream mueluss;
64 
65  // Check whether we are dealing with coarse level (solver) parameters or level smoother parameters
66  std::string mode = "smoother:";
67  if (pname.find("coarse:",0) == 0)
68  mode = "coarse:";
69 
70  // check whether pre and/or post smoothing
71  std::string PreOrPost = "both";
72  if (paramList.isParameter(mode + " pre or post") )
73  {
74  PreOrPost = paramList.get<std::string>(mode + " pre or post");
75  }
76 
77  //std::cout << "PreOrPost=" << PreOrPost << " pname=" << pname << " value=" << value << std::endl;
78 
79  TEUCHOS_TEST_FOR_EXCEPTION(mode=="coarse:" && PreOrPost != "both", Exceptions::RuntimeError, "MueLu::MLParameterListInterpreter::Setup(): The parameter \"coarse: pre or post\" is not supported by MueLu. It does not make sense for direct solvers. For iterative solvers you obtain the same effect by increasing, e.g., the number of sweeps for the coarse grid smoother. Please remove it from your parameters.");
80 
81  // select smoother type
82  std::string valuestr = value; // temporary variable
83  std::transform(valuestr.begin(), valuestr.end(), valuestr.begin(), ::tolower);
84  if ( valuestr == "jacobi" || valuestr == "gauss-seidel" || valuestr == "symmetric gauss-seidel" ) {
85  std::string my_name;
86  if ( PreOrPost == "both" ) my_name = "\"" + pname + "\"";
87  else my_name = "\"smoother: " + PreOrPost + " type\"";
88  mueluss << "<Parameter name=" << my_name << " type=\"string\" value=\"RELAXATION\"/>" << std::endl;
89  } else if ( valuestr == "ifpack" ) {
90  std::string my_name = "\"" + pname + "\"";
91  if ( paramList.isParameter("smoother: ifpack type") ) {
92  if ( paramList.get<std::string>("smoother: ifpack type") == "ILU" ) { mueluss << "<Parameter name=" << my_name << " type=\"string\" value=\"ILU\"/>" << std::endl; adaptingParamList.remove("smoother: ifpack type",false); }
93  if ( paramList.get<std::string>("smoother: ifpack type") == "ILUT" ) { mueluss << "<Parameter name=" << my_name << " type\" type=\"string\" value=\"ILUT\"/>" << std::endl; adaptingParamList.remove("smoother: ifpack type",false); }
94  }
95  } else if ( valuestr == "chebyshev" ) {
96  std::string my_name = "\"" + pname + "\"";
97  mueluss << "<Parameter name=" << my_name << " type=\"string\" value=\"CHEBYSHEV\"/>" << std::endl;
98  } else if (valuestr.length() > strlen("amesos") && valuestr.substr(0, strlen("amesos")) == "amesos") { /* catch Amesos-* */
99  std::string solverType = valuestr.substr(strlen("amesos")+1); /* ("amesos-klu" -> "klu") */
100 
101  bool valid = false;
102  const int validatorSize = 5;
103  std::string validator[validatorSize] = {"superlu", "superludist", "klu", "umfpack"};
104  for (int i=0; i < validatorSize; i++) { if (validator[i] == solverType) valid = true; }
105  TEUCHOS_TEST_FOR_EXCEPTION(!valid, Exceptions::RuntimeError, "MueLu::MLParameterListInterpreter: unknown smoother type. '" << solverType << "' not supported.");
106 
107  mueluss << "<Parameter name=\"" << pname << "\" type=\"string\" value=\"" << solverType << "\"/>" << std::endl;
108  } else {
109  // TODO error message
110  std::cout << "error in " << __FILE__ << ":" << __LINE__ << " could not find valid smoother/solver" << std::endl;
111  }
112 
113  // set smoother: pre or post parameter
114  // Note that there is no "coarse: pre or post" in MueLu!
115  if ( paramList.isParameter("smoother: pre or post") && mode == "smoother:") {
116  //std::cout << "paramList" << paramList << std::endl;
117  //std::string smootherPreOrPost = paramList.get<std::string>("smoother: pre or post");
118  //std::cout << "Create pre or post parameter with " << smootherPreOrPost << std::endl;
119  mueluss << "<Parameter name=\"smoother: pre or post\" type=\"string\" value=\"" << PreOrPost << "\"/>" << std::endl;
120  adaptingParamList.remove("smoother: pre or post",false);
121  }
122 
123  // create smoother parameter list
124  if (PreOrPost != "both") {
125  mueluss << "<ParameterList name=\"smoother: " << PreOrPost << " params\">" << std::endl;
126  } else {
127  mueluss << "<ParameterList name=\"" << mode << " params\">" << std::endl;
128  }
129 
130  // relaxation based smoothers:
131 
132  if ( valuestr == "jacobi" || valuestr == "gauss-seidel" || valuestr == "symmetric gauss-seidel" ) {
133  if ( valuestr == "jacobi" ) { mueluss << "<Parameter name=\"relaxation: type\" type=\"string\" value=\"Jacobi\"/>" << std::endl; adaptingParamList.remove("relaxation: type",false); }
134  if ( valuestr == "gauss-seidel" ) { mueluss << "<Parameter name=\"relaxation: type\" type=\"string\" value=\"Gauss-Seidel\"/>" << std::endl; adaptingParamList.remove("relaxation: type",false); }
135  if ( valuestr == "symmetric gauss-seidel" ) { mueluss << "<Parameter name=\"relaxation: type\" type=\"string\" value=\"Symmetric Gauss-Seidel\"/>" << std::endl; adaptingParamList.remove("relaxation: type",false); }
136 
137  if ( paramList.isParameter("smoother: sweeps") ) { mueluss << "<Parameter name=\"relaxation: sweeps\" type=\"int\" value=\"" << paramList.get<int>("smoother: sweeps") << "\"/>" << std::endl; adaptingParamList.remove("smoother: sweeps",false); }
138  if ( paramList.isParameter("smoother: damping factor") ) { mueluss << "<Parameter name=\"relaxation: damping factor\" type=\"double\" value=\"" << paramList.get<double>("smoother: damping factor") << "\"/>" << std::endl; adaptingParamList.remove("smoother: damping factor",false); }
139  }
140 
141  // Chebyshev
142  if ( valuestr == "chebyshev") {
143  if ( paramList.isParameter("smoother: polynomial order") ) { mueluss << "<Parameter name=\"chebyshev: degree\" type=\"int\" value=\"" << paramList.get<int>("smoother: polynomial order") << "\"/>" << std::endl; adaptingParamList.remove("smoother: polynomial order",false); }
144  else { mueluss << "<Parameter name=\"chebyshev: degree\" type=\"int\" value=\"2\"/>" << std::endl; }
145  if ( paramList.isParameter("smoother: Chebyshev alpha") ) { mueluss << "<Parameter name=\"chebyshev: ratio eigenvalue\" type=\"double\" value=\"" << paramList.get<double>("smoother: Chebyshev alpha") << "\"/>" << std::endl; adaptingParamList.remove("smoother: Chebyshev alpha",false); }
146  else { mueluss << "<Parameter name=\"chebyshev: ratio eigenvalue\" type=\"double\" value=\"20\"/>" << std::endl; adaptingParamList.remove("smoother: Chebyshev alpha",false); }
147  }
148 
149  // parameters for ILU based preconditioners
150  if ( valuestr == "ifpack") {
151 
152  // add Ifpack parameters
153  if ( paramList.isParameter("smoother: ifpack overlap") ) { mueluss << "<Parameter name=\"partitioner: overlap\" type=\"int\" value=\"" << paramList.get<int>("smoother: ifpack overlap") << "\"/>" << std::endl; adaptingParamList.remove("smoother: ifpack overlap",false); }
154  if ( paramList.isParameter("smoother: ifpack level-of-fill") ) { mueluss << "<Parameter name=\"fact: level-of-fill\" type=\"int\" value=\"" << paramList.get<int>("smoother: ifpack level-of-fill") << "\"/>" << std::endl; adaptingParamList.remove("smoother: ifpack level-of-fill",false); }
155  if ( paramList.isParameter("smoother: ifpack absolute threshold") ) { mueluss << "<Parameter name=\"fact: absolute threshold\" type=\"int\" value=\"" << paramList.get<double>("smoother: ifpack absolute threshold") << "\"/>" << std::endl; adaptingParamList.remove("smoother: ifpack absolute threshold",false); }
156  if ( paramList.isParameter("smoother: ifpack relative threshold") ) { mueluss << "<Parameter name=\"fact: relative threshold\" type=\"int\" value=\"" << paramList.get<double>("smoother: ifpack relative threshold") << "\"/>" << std::endl; adaptingParamList.remove("smoother: ifpack relative threshold",false); }
157  }
158 
159  mueluss << "</ParameterList>" << std::endl;
160 
161  // max coarse level size parameter (outside of smoother parameter lists)
162  if ( paramList.isParameter("smoother: max size") ) {
163  mueluss << "<Parameter name=\"coarse: max size\" type=\"int\" value=\"" << paramList.get<int>("smoother: max size") << "\"/>" << std::endl; adaptingParamList.remove("smoother: max size",false);
164  }
165 
166  return mueluss.str();
167  }
168 
169 
170  std::string ML2MueLuParameterTranslator::SetParameterList(const Teuchos::ParameterList & paramList_in, const std::string& defaultVals) {
171  Teuchos::ParameterList paramList = paramList_in;
172 
173  RCP<Teuchos::FancyOStream> out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout)); // TODO: use internal out (GetOStream())
174 
175 #if defined(HAVE_MUELU_ML) && defined(HAVE_MUELU_EPETRA)
176 
177  // TODO alternative with standard parameterlist from ML user guide?
178 
179  if (defaultVals != "") {
180  TEUCHOS_TEST_FOR_EXCEPTION(defaultVals!="SA" && defaultVals!="NSSA", Exceptions::RuntimeError,
181  "MueLu::MLParameterListInterpreter: only \"SA\" and \"NSSA\" allowed as options for ML default parameters.");
182  Teuchos::ParameterList ML_defaultlist;
183  ML_Epetra::SetDefaults(defaultVals,ML_defaultlist);
184 
185  // merge user parameters with default parameters
186  MueLu::MergeParameterList(paramList_in, ML_defaultlist, true);
187  paramList = ML_defaultlist;
188  }
189 #else
190  if (defaultVals != "") {
191  // If no validator available: issue a warning and set parameter value to false in the output list
192  *out << "Warning: MueLu_ENABLE_ML=OFF. No ML default values available." << std::endl;
193  }
194 #endif // HAVE_MUELU_ML
195 
196  //
197  // Move smoothers/aggregation/coarse parameters to sublists
198  //
199 
200  // ML allows to have level-specific smoothers/aggregation/coarse parameters at the top level of the list or/and defined in sublists:
201  // See also: ML Guide section 6.4.1, MueLu::CreateSublists, ML_CreateSublists
202  ParameterList paramListWithSubList;
203  MueLu::CreateSublists(paramList, paramListWithSubList);
204  paramList = paramListWithSubList; // swap
205  Teuchos::ParameterList adaptingParamList = paramList; // copy of paramList which is used to removed already interpreted parameters
206 
207  //
208  // Validate parameter list
209  //
210  {
211  bool validate = paramList.get("ML validate parameter list", true); /* true = default in ML */
212  if (validate) {
213 
214 #if defined(HAVE_MUELU_ML) && defined(HAVE_MUELU_EPETRA)
215  // Validate parameter list using ML validator
216  int depth = paramList.get("ML validate depth", 5); /* 5 = default in ML */
217  TEUCHOS_TEST_FOR_EXCEPTION(! ML_Epetra::ValidateMLPParameters(paramList, depth), Exceptions::RuntimeError,
218  "ERROR: ML's Teuchos::ParameterList contains incorrect parameter!");
219 #else
220  // If no validator available: issue a warning and set parameter value to false in the output list
221  *out << "Warning: MueLu_ENABLE_ML=OFF. The parameter list cannot be validated." << std::endl;
222  paramList.set("ML validate parameter list", false);
223 
224 #endif // HAVE_MUELU_ML
225  } // if(validate)
226  } // scope
227 
228  // stringstream for concatenating xml parameter strings.
229  std::stringstream mueluss;
230 
231  // create surrounding MueLu parameter list
232  mueluss << "<ParameterList name=\"MueLu\">" << std::endl;
233 
234  // loop over all ML parameters in provided parameter list
235  for (ParameterList::ConstIterator param=paramListWithSubList.begin(); param!=paramListWithSubList.end(); ++param) {
236 
237  // extract ML parameter name
238  const std::string & pname=paramListWithSubList.name(param);
239 
240  // extract corresponding (ML) value
241  // remove ParameterList specific information from result string
242  std::stringstream valuess;
243  valuess << paramList.entry(param);
244  std::string valuestr = valuess.str();
245  replaceAll(valuestr, "[unused]", "");
246  replaceAll(valuestr, "[default]", "");
247  valuestr = trim(valuestr);
248 
249  // transform ML parameter to corresponding MueLu parameter and generate XML string
250  std::string valueInterpreterStr = "\"" + valuestr + "\"";
251  std::string ret = MasterList::interpretParameterName(MasterList::ML2MueLu(pname),valueInterpreterStr);
252 
253  // add XML string
254  if (ret != "") {
255  mueluss << ret << std::endl;
256 
257  // remove parameter from ML parameter list
258  adaptingParamList.remove(pname,false);
259  }
260 
261  // special handling for energy minimization
262  // TAW: this is not optimal for symmetric problems but at least works.
263  // for symmetric problems the "energy minimization" parameter should not exist anyway...
264  if (pname == "energy minimization: enable") {
265  mueluss << "<Parameter name=\"problem: symmetric\" type=\"bool\" value=\"false\"/>" << std::endl;
266  mueluss << "<Parameter name=\"transpose: use implicit\" type=\"bool\" value=\"false\"/>" << std::endl;
267  }
268 
269  // special handling for smoothers
270  if (pname == "smoother: type") {
271 
272  mueluss << GetSmootherFactory(paramList, adaptingParamList, pname, valuestr);
273 
274  }
275 
276  // special handling for level-specific smoothers
277  if (pname.find("smoother: list (level",0) == 0) {
278  // Scan pname (ex: pname="smoother: type (level 2)")
279  std::string type, option;
280  int levelID=-1;
281  {
282  typedef Teuchos::ArrayRCP<char>::size_type size_type;
283  Teuchos::Array<char> ctype (size_type(pname.size()+1));
284  Teuchos::Array<char> coption(size_type(pname.size()+1));
285 
286  int matched = sscanf(pname.c_str(),"%s %[^(](level %d)", ctype.getRawPtr(), coption.getRawPtr(), &levelID); // use [^(] instead of %s to allow for strings with white-spaces (ex: "ifpack list")
287  type = std::string(ctype.getRawPtr());
288  option = std::string(coption.getRawPtr()); option.resize(option.size () - 1); // remove final white-space
289 
290  if (matched != 3 || (type != "smoother:")) {
291  TEUCHOS_TEST_FOR_EXCEPTION(true, MueLu::Exceptions::RuntimeError, "MueLu::CreateSublist(), Line " << __LINE__ << ". "
292  << "Error in creating level-specific sublists" << std::endl
293  << "Offending parameter: " << pname << std::endl);
294  }
295 
296  mueluss << "<ParameterList name=\"level " << levelID << "\">" << std::endl;
297  mueluss << GetSmootherFactory(paramList.sublist(pname),adaptingParamList.sublist(pname), "smoother: type", paramList.sublist(pname).get<std::string>("smoother: type"));
298  mueluss << "</ParameterList>" << std::endl;
299  }
300  }
301 
302  // special handling for coarse level
303  TEUCHOS_TEST_FOR_EXCEPTION(paramList.isParameter("coarse: type"), Exceptions::RuntimeError, "MueLu::MLParameterListInterpreter::Setup(): The parameter \"coarse: type\" should not exist but being stored in \"coarse: list\" instead.");
304  if ( pname == "coarse: list" ) {
305 
306  // interpret smoother/coarse solver data.
307  // Note, that we inspect the "coarse: list" sublist to define the "coarse" smoother/solver
308  // Be aware, that MueLu::CreateSublists renames the prefix of the parameters in the "coarse: list" from "coarse" to "smoother".
309  // Therefore, we have to check the values of the "smoother" parameters
310  TEUCHOS_TEST_FOR_EXCEPTION(!paramList.sublist("coarse: list").isParameter("smoother: type"), Exceptions::RuntimeError, "MueLu::MLParameterListInterpreter::Setup(): no coarse grid solver defined.");
311  mueluss << GetSmootherFactory(paramList.sublist("coarse: list"), adaptingParamList.sublist("coarse: list"), "coarse: type", paramList.sublist("coarse: list").get<std::string>("smoother: type"));
312 
313 
314  }
315 
316 
317 
318  } // for
319 
320  mueluss << "</ParameterList>" << std::endl;
321 
322  return mueluss.str();
323  }
324 
325 
326 } // namespace MueLu
static std::string SetParameterList(const Teuchos::ParameterList &paramList_in, const std::string &defaultVals)
: Interpret parameter list
void MergeParameterList(const Teuchos::ParameterList &source, Teuchos::ParameterList &dest, bool overWrite)
: merge two parameter lists
static std::string interpretParameterName(const std::string &name, const std::string &value)
Namespace for MueLu classes and methods.
static std::string GetSmootherFactory(const Teuchos::ParameterList &paramList, Teuchos::ParameterList &adaptingParamList, const std::string &pname, const std::string &value)
: Helper function which translates ML smoother/solver paramters to MueLu XML string ...
void CreateSublists(const ParameterList &List, ParameterList &newList)
static std::string ML2MueLu(const std::string &name)
Translate ML parameter to corresponding MueLu parameter.
Exception throws to report errors in the internal logical of the program.
void replaceAll(std::string &str, const std::string &from, const std::string &to)