Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
linear2d_diffusion_pce_ifpack2.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stokhos Package
4 //
5 // Copyright 2009 NTESS and the Stokhos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 // Stokhos Stochastic Galerkin
11 #include "Stokhos_Epetra.hpp"
12 #include "Stokhos_Sacado.hpp"
13 #include "Stokhos_Ifpack2.hpp"
14 
15 // Class implementing our problem
17 
18 // Epetra communicator
19 #ifdef HAVE_MPI
20 #include "Epetra_MpiComm.h"
21 #else
22 #include "Epetra_SerialComm.h"
23 #endif
24 
25 // solver
26 #include "Ifpack2_Factory.hpp"
27 #include "BelosLinearProblem.hpp"
28 #include "kokkos_pce_specializations.hpp"
29 #include "BelosPseudoBlockCGSolMgr.hpp"
30 #include "BelosPseudoBlockGmresSolMgr.hpp"
31 #include "MatrixMarket_Tpetra.hpp"
32 #include "BelosBlockGmresSolMgr.hpp"
33 
34 // Utilities
35 #include "Teuchos_TimeMonitor.hpp"
37 
38 // Scalar types
40 
41 // Random field types
43 const int num_sg_rf = 2;
45 const char *sg_rf_names[] = { "Uniform", "Log-Normal" };
46 
47 // Krylov methods
49 const int num_krylov_method = 2;
51 const char *krylov_method_names[] = { "GMRES", "CG" };
52 
53 // Preconditioning approaches
55 const int num_sg_prec = 3;
57 const char *sg_prec_names[] = { "None",
58  "Mean-Based",
59  "Stochastic" };
60 
61 // Stochastic division approaches
63 const int num_sg_div = 5;
65 const char *sg_div_names[] = { "Direct",
66  "SPD-Direct",
67  "Mean-Based",
68  "Quadrature",
69  "CG"};
70 
71 // Stochastic division preconditioner approaches
73 const int num_sg_divprec = 5;
75 const char *sg_divprec_names[] = { "None",
76  "Diag",
77  "Jacobi",
78  "GS",
79  "Schur"};
80 
81 
82 // Option for Schur complement precond: full or diag D
84 const int num_schur_option = 2;
86 const char *schur_option_names[] = { "full", "diag"};
87 
88 // Full matrix or linear matrix (pb = dim + 1 ) used for preconditioner
90 const int num_prec_option = 2;
92 const char *prec_option_names[] = { "full", "linear"};
93 
94 int main(int argc, char *argv[]) {
95  typedef double MeshScalar;
96  typedef double BasisScalar;
99 
100  using Teuchos::RCP;
101  using Teuchos::rcp;
102  using Teuchos::Array;
103  using Teuchos::ArrayRCP;
104  using Teuchos::ArrayView;
106 
107 // Initialize MPI
108 #ifdef HAVE_MPI
109  MPI_Init(&argc,&argv);
110 #endif
111 
112  LocalOrdinal MyPID;
113 
114  try {
115 
116  // Create a communicator for Epetra objects
117  RCP<const Epetra_Comm> globalComm;
118 #ifdef HAVE_MPI
119  globalComm = rcp(new Epetra_MpiComm(MPI_COMM_WORLD));
120 #else
121  globalComm = rcp(new Epetra_SerialComm);
122 #endif
123  MyPID = globalComm->MyPID();
124 
125  // Setup command line options
127  CLP.setDocString(
128  "This example runs an interlaced stochastic Galerkin solvers.\n");
129 
130  int n = 32;
131  CLP.setOption("num_mesh", &n, "Number of mesh points in each direction");
132 
133  bool symmetric = false;
134  CLP.setOption("symmetric", "unsymmetric", &symmetric,
135  "Symmetric discretization");
136 
137  int num_spatial_procs = -1;
138  CLP.setOption("num_spatial_procs", &num_spatial_procs, "Number of spatial processors (set -1 for all available procs)");
139 
140  SG_RF randField = UNIFORM;
141  CLP.setOption("rand_field", &randField,
143  "Random field type");
144 
145  double mu = 0.2;
146  CLP.setOption("mean", &mu, "Mean");
147 
148  double s = 0.1;
149  CLP.setOption("std_dev", &s, "Standard deviation");
150 
151  int num_KL = 2;
152  CLP.setOption("num_kl", &num_KL, "Number of KL terms");
153 
154  int order = 3;
155  CLP.setOption("order", &order, "Polynomial order");
156 
157  bool normalize_basis = true;
158  CLP.setOption("normalize", "unnormalize", &normalize_basis,
159  "Normalize PC basis");
160 
161  Krylov_Method solver_method = GMRES;
162  CLP.setOption("solver_method", &solver_method,
164  "Krylov solver method");
165 
166  SG_Prec prec_method = STOCHASTIC;
167  CLP.setOption("prec_method", &prec_method,
169  "Preconditioner method");
170 
171  SG_Div division_method = DIRECT;
172  CLP.setOption("division_method", &division_method,
174  "Stochastic division method");
175 
176  SG_DivPrec divprec_method = NO;
177  CLP.setOption("divprec_method", &divprec_method,
179  "Preconditioner for division method");
180  Schur_option schur_option = diag;
181  CLP.setOption("schur_option", &schur_option,
183  "Schur option");
184  Prec_option prec_option = whole;
185  CLP.setOption("prec_option", &prec_option,
187  "Prec option");
188 
189 
190  double solver_tol = 1e-12;
191  CLP.setOption("solver_tol", &solver_tol, "Outer solver tolerance");
192 
193  double div_tol = 1e-6;
194  CLP.setOption("div_tol", &div_tol, "Tolerance in Iterative Solver");
195 
196  int prec_level = 1;
197  CLP.setOption("prec_level", &prec_level, "Level in Schur Complement Prec 0->Solve A0u0=g0 with division; 1->Form 1x1 Schur Complement");
198 
199  int max_it_div = 50;
200  CLP.setOption("max_it_div", &max_it_div, "Maximum # of Iterations in Iterative Solver for Division");
201 
202  bool equilibrate = true; //JJH 8/26/12 changing to true to match ETP example
203  CLP.setOption("equilibrate", "noequilibrate", &equilibrate,
204  "Equilibrate the linear system");
205 
206 
207  CLP.parse( argc, argv );
208 
209  if (MyPID == 0) {
210  std::cout << "Summary of command line options:" << std::endl
211  << "\tnum_mesh = " << n << std::endl
212  << "\tsymmetric = " << symmetric << std::endl
213  << "\tnum_spatial_procs = " << num_spatial_procs << std::endl
214  << "\trand_field = " << sg_rf_names[randField]
215  << std::endl
216  << "\tmean = " << mu << std::endl
217  << "\tstd_dev = " << s << std::endl
218  << "\tnum_kl = " << num_KL << std::endl
219  << "\torder = " << order << std::endl
220  << "\tnormalize_basis = " << normalize_basis << std::endl
221  << "\tsolver_method = " << krylov_method_names[solver_method] << std::endl
222  << "\tprec_method = " << sg_prec_names[prec_method] << std::endl
223  << "\tdivision_method = " << sg_div_names[division_method] << std::endl
224  << "\tdiv_tol = " << div_tol << std::endl
225  << "\tdiv_prec = " << sg_divprec_names[divprec_method] << std::endl
226  << "\tprec_level = " << prec_level << std::endl
227  << "\tmax_it_div = " << max_it_div << std::endl;
228  }
229  bool nonlinear_expansion = false;
230  if (randField == UNIFORM)
231  nonlinear_expansion = false;
232  else if (randField == LOGNORMAL)
233  nonlinear_expansion = true;
234 
235  {
236  TEUCHOS_FUNC_TIME_MONITOR("Total PCE Calculation Time");
237 
238  // Create Stochastic Galerkin basis and expansion
240  for (LocalOrdinal i=0; i<num_KL; i++)
241  if (randField == UNIFORM)
242  bases[i] = rcp(new Stokhos::LegendreBasis<LocalOrdinal,BasisScalar>(order, normalize_basis));
243  else if (randField == LOGNORMAL)
244  bases[i] = rcp(new Stokhos::HermiteBasis<int,double>(order, normalize_basis));
245  RCP<const Stokhos::CompletePolynomialBasis<LocalOrdinal,BasisScalar> > basis =
247  LocalOrdinal sz = basis->size();
248  RCP<Stokhos::Sparse3Tensor<LocalOrdinal,BasisScalar> > Cijk =
249  basis->computeTripleProductTensor();
250  RCP<const Stokhos::Quadrature<int,double> > quad =
252  RCP<ParameterList> expn_params = Teuchos::rcp(new ParameterList);
253  if (division_method == MEAN_DIV) {
254  expn_params->set("Division Strategy", "Mean-Based");
255  expn_params->set("Use Quadrature for Division", false);
256  }
257  else if (division_method == DIRECT) {
258  expn_params->set("Division Strategy", "Dense Direct");
259  expn_params->set("Use Quadrature for Division", false);
260  }
261  else if (division_method == SPD_DIRECT) {
262  expn_params->set("Division Strategy", "SPD Dense Direct");
263  expn_params->set("Use Quadrature for Division", false);
264  }
265  else if (division_method == CGD) {
266  expn_params->set("Division Strategy", "CG");
267  expn_params->set("Use Quadrature for Division", false);
268  }
269 
270  else if (division_method == QUAD) {
271  expn_params->set("Use Quadrature for Division", true);
272  }
273 
274  if (divprec_method == NO)
275  expn_params->set("Prec Strategy", "None");
276  else if (divprec_method == DIAG)
277  expn_params->set("Prec Strategy", "Diag");
278  else if (divprec_method == JACOBI)
279  expn_params->set("Prec Strategy", "Jacobi");
280  else if (divprec_method == GS)
281  expn_params->set("Prec Strategy", "GS");
282  else if (divprec_method == SCHUR)
283  expn_params->set("Prec Strategy", "Schur");
284 
285  if (schur_option == diag)
286  expn_params->set("Schur option", "diag");
287  else
288  expn_params->set("Schur option", "full");
289  if (prec_option == linear)
290  expn_params->set("Prec option", "linear");
291 
292 
293  if (equilibrate)
294  expn_params->set("Equilibrate", 1);
295  else
296  expn_params->set("Equilibrate", 0);
297  expn_params->set("Division Tolerance", div_tol);
298  expn_params->set("prec_iter", prec_level);
299  expn_params->set("max_it_div", max_it_div);
300 
301  RCP<Stokhos::OrthogPolyExpansion<LocalOrdinal,BasisScalar> > expansion =
303  basis, Cijk, quad, expn_params));
304 
305  if (MyPID == 0)
306  std::cout << "Stochastic Galerkin expansion size = " << sz << std::endl;
307 
308  // Create stochastic parallel distribution
309  ParameterList parallelParams;
310  parallelParams.set("Number of Spatial Processors", num_spatial_procs);
311  // parallelParams.set("Rebalance Stochastic Graph", true);
312  // Teuchos::ParameterList& isorropia_params =
313  // parallelParams.sublist("Isorropia");
314  // isorropia_params.set("Balance objective", "nonzeros");
315  RCP<Stokhos::ParallelData> sg_parallel_data =
316  rcp(new Stokhos::ParallelData(basis, Cijk, globalComm, parallelParams));
317  RCP<const EpetraExt::MultiComm> sg_comm =
318  sg_parallel_data->getMultiComm();
319  RCP<const Epetra_Comm> app_comm =
320  sg_parallel_data->getSpatialComm();
321 
322  // Create Teuchos::Comm from Epetra_Comm
323  RCP< Teuchos::Comm<int> > teuchos_app_comm;
324 #ifdef HAVE_MPI
325  RCP<const Epetra_MpiComm> app_mpi_comm =
326  Teuchos::rcp_dynamic_cast<const Epetra_MpiComm>(app_comm);
327  RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > raw_mpi_comm =
328  Teuchos::opaqueWrapper(app_mpi_comm->Comm());
329  teuchos_app_comm = rcp(new Teuchos::MpiComm<int>(raw_mpi_comm));
330 #else
331  teuchos_app_comm = rcp(new Teuchos::SerialComm<int>());
332 #endif
333 
334  // Create application
336  RCP<problem_type> model =
337  rcp(new problem_type(teuchos_app_comm, n, num_KL, s, mu,
338  nonlinear_expansion, symmetric));
339 
340  // Create vectors and operators
341  typedef problem_type::Tpetra_Vector Tpetra_Vector;
342  typedef problem_type::Tpetra_CrsMatrix Tpetra_CrsMatrix;
343  typedef Tpetra::MatrixMarket::Writer<Tpetra_CrsMatrix> Writer;
344 
345  RCP<Tpetra_Vector> p = Tpetra::createVector<Scalar>(model->get_p_map(0));
346  RCP<Tpetra_Vector> x = Tpetra::createVector<Scalar>(model->get_x_map());
347  x->putScalar(0.0);
348  RCP<Tpetra_Vector> f = Tpetra::createVector<Scalar>(model->get_f_map());
349  RCP<Tpetra_Vector> dx = Tpetra::createVector<Scalar>(model->get_x_map());
350  RCP<Tpetra_CrsMatrix> J = model->create_W();
351  RCP<Tpetra_CrsMatrix> J0;
352  if (prec_method == MEAN)
353  J0 = model->create_W();
354 
355  // Set PCE expansion of p
356  p->putScalar(0.0);
357  ArrayRCP<Scalar> p_view = p->get1dViewNonConst();
358  for (ArrayRCP<Scalar>::size_type i=0; i<p_view.size(); i++) {
359  p_view[i].reset(expansion);
360  p_view[i].copyForWrite();
361  }
362  Array<double> point(num_KL, 1.0);
363  Array<double> basis_vals(sz);
364  basis->evaluateBases(point, basis_vals);
365  if (order > 0) {
366  for (int i=0; i<num_KL; i++) {
367  p_view[i].term(i,1) = 1.0 / basis_vals[i+1];
368  }
369  }
370 
371  // Create preconditioner
372  typedef Ifpack2::Preconditioner<Scalar,LocalOrdinal,GlobalOrdinal,Node> Tprec;
374  if (prec_method != NONE) {
375  ParameterList precParams;
376  std::string prec_name = "RILUK";
377  precParams.set("fact: iluk level-of-fill", 4);
378  precParams.set("fact: iluk level-of-overlap", 0);
379 
380  // std::string prec_name = "ILUT";
381  // precParams.set("fact: ilut level-of-fill", 10.0);
382  // precParams.set("fact: drop tolerance", 1.0e-16);
383  Ifpack2::Factory factory;
384  if (prec_method == MEAN) {
385  M = factory.create<Tpetra_CrsMatrix>(prec_name, J0);
386  } else if (prec_method == STOCHASTIC) {
387  M = factory.create<Tpetra_CrsMatrix>(prec_name, J);
388  }
389  M->setParameters(precParams);
390  }
391 
392  // Evaluate model
393  model->computeResidual(*x, *p, *f);
394  model->computeJacobian(*x, *p, *J);
395 
396  // Compute mean for mean-based preconditioner
397  if (prec_method == MEAN) {
398  size_t nrows = J->getLocalNumRows();
399  ArrayView<const LocalOrdinal> indices;
400  ArrayView<const Scalar> values;
401  J0->resumeFill();
402  for (size_t i=0; i<nrows; i++) {
403  J->getLocalRowView(i, indices, values);
404  Array<Scalar> values0(values.size());
405  for (LocalOrdinal j=0; j<values.size(); j++)
406  values0[j] = values[j].coeff(0);
407  J0->replaceLocalValues(i, indices, values0);
408  }
409  J0->fillComplete();
410  }
411 
412  // compute preconditioner
413  if (prec_method != NONE) {
414  M->initialize();
415  M->compute();
416  }
417 
418  // Setup Belos solver
419  RCP<ParameterList> belosParams = rcp(new ParameterList);
420  belosParams->set("Flexible Gmres", false);
421  belosParams->set("Num Blocks", 500);//20
422  belosParams->set("Convergence Tolerance", solver_tol);
423  belosParams->set("Maximum Iterations", 1000);
424  belosParams->set("Verbosity", 33);
425  belosParams->set("Output Style", 1);
426  belosParams->set("Output Frequency", 1);
427 
428  typedef Tpetra::MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node> MV;
429  typedef Tpetra::Operator<Scalar,LocalOrdinal,GlobalOrdinal,Node> OP;
430  typedef Belos::OperatorTraits<Scalar,MV,OP> BOPT;
431  typedef Belos::MultiVecTraits<double,MV> BMVT;
432  typedef Belos::LinearProblem<double,MV,OP> BLinProb;
433  RCP< BLinProb > problem = rcp(new BLinProb(J, dx, f));
434  if (prec_method != NONE)
435  problem->setRightPrec(M);
436  problem->setProblem();
437  RCP<Belos::SolverManager<double,MV,OP> > solver;
438  if (solver_method == CG)
439  solver = rcp(new Belos::PseudoBlockCGSolMgr<double,MV,OP>(problem, belosParams));
440  else if (solver_method == GMRES)
441  solver = rcp(new Belos::BlockGmresSolMgr<double,MV,OP>(problem, belosParams));
442 
443  // Print initial residual norm
444  std::vector<double> norm_f(1);
445  BMVT::MvNorm(*f, norm_f);
446  if (MyPID == 0)
447  std::cout << "\nInitial residual norm = " << norm_f[0] << std::endl;
448 
449  // Solve linear system
450  Belos::ReturnType ret = solver->solve();
451 
452  if (MyPID == 0) {
453  if (ret == Belos::Converged)
454  std::cout << "Solver converged!" << std::endl;
455  else
456  std::cout << "Solver failed to converge!" << std::endl;
457  }
458 
459  // Update x
460  x->update(-1.0, *dx, 1.0);
461  Writer::writeDenseFile("stochastic_solution.mm", x);
462 
463  // Compute new residual & response function
464  RCP<Tpetra_Vector> g = Tpetra::createVector<Scalar>(model->get_g_map(0));
465  f->putScalar(0.0);
466  model->computeResidual(*x, *p, *f);
467  model->computeResponse(*x, *p, *g);
468 
469  // Print final residual norm
470  BMVT::MvNorm(*f, norm_f);
471  if (MyPID == 0)
472  std::cout << "\nFinal residual norm = " << norm_f[0] << std::endl;
473 
474  // Expected results for num_mesh=32
475  double g_mean_exp = 0.172988; // expected response mean
476  double g_std_dev_exp = 0.0380007; // expected response std. dev.
477  double g_tol = 1e-6; // tolerance on determining success
478  if (n == 8) {
479  g_mean_exp = 1.327563e-01;
480  g_std_dev_exp = 2.949064e-02;
481  }
482 
483  double g_mean = g->get1dView()[0].mean();
484  double g_std_dev = g->get1dView()[0].standard_deviation();
485  std::cout << std::endl;
486  std::cout << "Response Mean = " << g_mean << std::endl;
487  std::cout << "Response Std. Dev. = " << g_std_dev << std::endl;
488  bool passed = false;
489  if (norm_f[0] < 1.0e-10 &&
490  std::abs(g_mean-g_mean_exp) < g_tol &&
491  std::abs(g_std_dev - g_std_dev_exp) < g_tol)
492  passed = true;
493  if (MyPID == 0) {
494  if (passed)
495  std::cout << "Example Passed!" << std::endl;
496  else{
497  std::cout << "Example Failed!" << std::endl;
498  std::cout << "Expected Response Mean = "<< g_mean_exp << std::endl;
499  std::cout << "Expected Response Std. Dev. = "<< g_std_dev_exp << std::endl;
500  }
501  }
502 
503  }
504 
507 
508  }
509 
510  catch (std::exception& e) {
511  std::cout << e.what() << std::endl;
512  }
513  catch (string& s) {
514  std::cout << s << std::endl;
515  }
516  catch (char *s) {
517  std::cout << s << std::endl;
518  }
519  catch (...) {
520  std::cout << "Caught unknown exception!" <<std:: endl;
521  }
522 
523 #ifdef HAVE_MPI
524  MPI_Finalize() ;
525 #endif
526 
527 }
#define TEUCHOS_FUNC_TIME_MONITOR(FUNCNAME)
const char * sg_divprec_names[]
const Prec_option Prec_option_values[]
Hermite polynomial basis.
const Krylov_Method krylov_method_values[]
const char * schur_option_names[]
const char * prec_option_names[]
const SG_Prec sg_prec_values[]
const SG_DivPrec sg_divprec_values[]
const Schur_option Schur_option_values[]
Kokkos::Serial node_type
const SG_Div sg_div_values[]
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
const int num_krylov_method
static void summarize(Ptr< const Comm< int > > comm, std::ostream &out=std::cout, const bool alwaysWriteLocal=false, const bool writeGlobalStats=true, const bool writeZeroTimers=true, const ECounterSetOp setOp=Intersection, const std::string &filter="", const bool ignoreZeroTimers=false)
void setOption(const char option_true[], const char option_false[], bool *option_val, const char documentation[]=NULL)
const SG_RF sg_rf_values[]
EParseCommandLineReturn parse(int argc, char *argv[], std::ostream *errout=&std::cerr) const
KOKKOS_INLINE_FUNCTION PCE< Storage > abs(const PCE< Storage > &a)
const int num_sg_rf
expr expr expr dx(i, j)
Multivariate orthogonal polynomial basis generated from a total-order complete-polynomial tensor prod...
Legendre polynomial basis.
int main(int argc, char **argv)
const char * sg_rf_names[]
ScalarType f(const Teuchos::Array< ScalarType > &x, double a, double b)
void setDocString(const char doc_string[])
const char * sg_prec_names[]
Tpetra::KokkosClassic::DefaultNode::DefaultNodeType Node
const char * sg_div_names[]
Orthogonal polynomial expansions based on numerical quadrature.
int n
Defines quadrature for a tensor product basis by tensor products of 1-D quadrature rules...
ScalarType g(const Teuchos::Array< ScalarType > &x, const ScalarType &y)
static void zeroOutTimers()
A linear 2-D diffusion problem.
const char * krylov_method_names[]