Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Stokhos_GaussSeidelPreconditioner.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 
11 #include "Teuchos_TimeMonitor.hpp"
12 #include "EpetraExt_BlockUtility.h"
13 #include "Teuchos_Assert.hpp"
14 
15 Stokhos::GaussSeidelPreconditioner::
16 GaussSeidelPreconditioner(
18  const Teuchos::RCP<const Stokhos::OrthogPolyBasis<int,double> >& sg_basis_,
20  const Teuchos::RCP<const Epetra_Map>& base_map_,
21  const Teuchos::RCP<const Epetra_Map>& sg_map_,
22  const Teuchos::RCP<NOX::Epetra::LinearSystem>& det_solver_,
24  label("Stokhos Gauss-Seidel Preconditioner"),
25  sg_comm(sg_comm_),
26  sg_basis(sg_basis_),
27  epetraCijk(epetraCijk_),
28  base_map(base_map_),
29  sg_map(sg_map_),
30  is_stoch_parallel(epetraCijk->isStochasticParallel()),
31  stoch_row_map(epetraCijk->getStochasticRowMap()),
32  det_solver(det_solver_),
33  params(params_),
34  useTranspose(false),
35  sg_op(),
36  sg_poly(),
37  Cijk(epetraCijk->getParallelCijk()),
38  is_parallel(epetraCijk->isStochasticParallel())
39 {
40  if (is_parallel) {
42  epetraCijk->getStochasticColMap();
43  sg_col_map =
44  Teuchos::rcp(EpetraExt::BlockUtility::GenerateBlockMap(*base_map,
45  *stoch_col_map,
46  sg_map->Comm()));
47  col_exporter = Teuchos::rcp(new Epetra_Export(*sg_col_map, *sg_map));
48  }
49 }
50 
51 Stokhos::GaussSeidelPreconditioner::
52 ~GaussSeidelPreconditioner()
53 {
54 }
55 
56 void
57 Stokhos::GaussSeidelPreconditioner::
58 setupPreconditioner(const Teuchos::RCP<Stokhos::SGOperator>& sg_op_,
59  const Epetra_Vector& x)
60 {
61  sg_op = sg_op_;
62  sg_poly = sg_op->getSGPolynomial();
63  EpetraExt::BlockVector sg_x_block(View, *base_map, x);
64  det_solver->setJacobianOperatorForSolve(sg_poly->getCoeffPtr(0));
65  det_solver->createPreconditioner(*(sg_x_block.GetBlock(0)),
66  params->sublist("Deterministic Solver Parameters"),
67  false);
68 }
69 
70 int
71 Stokhos::GaussSeidelPreconditioner::
72 SetUseTranspose(bool UseTranspose)
73 {
74  useTranspose = UseTranspose;
76  UseTranspose == true, std::logic_error,
77  "Stokhos::GaussSeidelPreconditioner::SetUseTranspose(): " <<
78  "Preconditioner does not support transpose!" << std::endl);
79 
80  return 0;
81 }
82 
83 int
84 Stokhos::GaussSeidelPreconditioner::
85 Apply(const Epetra_MultiVector& Input, Epetra_MultiVector& Result) const
86 {
87  return sg_op->Apply(Input,Result);
88 }
89 
90 int
91 Stokhos::GaussSeidelPreconditioner::
92 ApplyInverse(const Epetra_MultiVector& Input, Epetra_MultiVector& Result) const
93 {
94  int max_iter = params->get("Max Iterations",100 );
95  double sg_tol = params->get("Tolerance", 1e-12);
96  bool scale_op = params->get("Scale Operator by Inverse Basis Norms", true);
97  bool only_use_linear = params->get("Only Use Linear Terms", true);
98 
99  // We have to be careful if Input and Result are the same vector.
100  // If this is the case, the only possible solution is to make a copy
101  const Epetra_MultiVector *input = &Input;
102  bool made_copy = false;
103  if (Input.Values() == Result.Values()) {
104  input = new Epetra_MultiVector(Input);
105  made_copy = true;
106  }
107 
108  int k_limit = sg_poly->size();
109  int dim = sg_poly->basis()->dimension();
110  if (only_use_linear && sg_poly->size() > dim+1)
111  k_limit = dim + 1;
112  const Teuchos::Array<double>& norms = sg_basis->norm_squared();
113 
114  int m = input->NumVectors();
115  if (sg_df_block == Teuchos::null || sg_df_block->NumVectors() != m) {
116  sg_df_block =
117  Teuchos::rcp(new EpetraExt::BlockMultiVector(*base_map, *sg_map, m));
118  sg_y_block =
119  Teuchos::rcp(new EpetraExt::BlockMultiVector(*base_map, *sg_map, m));
120  kx = Teuchos::rcp(new Epetra_MultiVector(*base_map, m));
121  if (is_parallel) {
122  sg_df_col = Teuchos::rcp(new EpetraExt::BlockMultiVector(*base_map,
123  *sg_col_map, m));
124  sg_df_tmp = Teuchos::rcp(new EpetraExt::BlockMultiVector(*base_map,
125  *sg_map, m));
126  }
127  }
128 
129  // Extract blocks
130  EpetraExt::BlockMultiVector sg_dx_block(View, *base_map, Result);
131  EpetraExt::BlockMultiVector sg_f_block(View, *base_map, *input);
132  sg_dx_block.PutScalar(0.0);
133 
134  // Compute initial residual norm
135  double norm_f,norm_df;
136  sg_f_block.Norm2(&norm_f);
137  sg_op->Apply(sg_dx_block, *sg_df_block);
138  sg_df_block->Update(-1.0, sg_f_block, 1.0);
139  sg_df_block->Norm2(&norm_df);
140 
142 
143  sg_df_block->Update(1.0, sg_f_block, 0.0);
144 
145  int iter = 0;
146  while (((norm_df/norm_f)>sg_tol) && (iter<max_iter)) {
147 #ifdef STOKHOS_TEUCHOS_TIME_MONITOR
148  TEUCHOS_FUNC_TIME_MONITOR("Stokhos: Total global solve Time");
149 #endif
150  iter++;
151 
152  sg_y_block->Update(1.0, sg_f_block, 0.0);
153  if (is_parallel)
154  sg_df_col->PutScalar(0.0);
155 
156  for (Cijk_type::i_iterator i_it=Cijk->i_begin();
157  i_it!=Cijk->i_end(); ++i_it) {
158  int i = index(i_it);
159 
160  f = sg_f_block.GetBlock(i);
161  df = sg_df_block->GetBlock(i);
162  dx = sg_dx_block.GetBlock(i);
163 
164  dx->PutScalar(0.0);
165  Teuchos::ParameterList& det_solver_params =
166  params->sublist("Deterministic Solver Parameters");
167  for (int col=0; col<m; col++) {
168  NOX::Epetra::Vector nox_df(Teuchos::rcp((*df)(col),false),
169  NOX::Epetra::Vector::CreateView);
170  NOX::Epetra::Vector nox_dx(Teuchos::rcp((*dx)(col),false),
171  NOX::Epetra::Vector::CreateView);
172  // Solve linear system
173  {
174 #ifdef STOKHOS_TEUCHOS_TIME_MONITOR
175  TEUCHOS_FUNC_TIME_MONITOR("Stokhos: Total deterministic solve Time");
176 #endif
177  det_solver->applyJacobianInverse(det_solver_params, nox_df, nox_dx);
178  }
179  }
180 
181  df->Update(1.0, *f, 0.0);
182 
183  for (Cijk_type::ik_iterator k_it = Cijk->k_begin(i_it);
184  k_it != Cijk->k_end(i_it); ++k_it) {
185  int k = index(k_it);
186  if (k!=0 && k<k_limit) {
187  (*sg_poly)[k].Apply(*dx, *kx);
188  for (Cijk_type::ikj_iterator j_it = Cijk->j_begin(k_it);
189  j_it != Cijk->j_end(k_it); ++j_it) {
190  int j = index(j_it);
191  int j_gid = epetraCijk->GCID(j);
192  double c = value(j_it);
193  if (scale_op)
194  c /= norms[j_gid];
195  bool owned = epetraCijk->myGRID(j_gid);
196  if (!is_parallel || owned) {
197  sg_df_block->GetBlock(j)->Update(-c, *kx, 1.0);
198  sg_y_block->GetBlock(j)->Update(-c, *kx, 1.0);
199  }
200  else
201  sg_df_col->GetBlock(j)->Update(-c, *kx, 1.0);
202  }
203  }
204  }
205 
206  (*sg_poly)[0].Apply(*dx, *kx);
207  sg_y_block->GetBlock(i)->Update(-1.0, *kx, 1.0);
208 
209  } //End of k loop
210 
211  // Add in contributions from off-process
212  if (is_parallel) {
213  sg_df_tmp->Export(*sg_df_col, *col_exporter, InsertAdd);
214  sg_df_block->Update(1.0, *sg_df_tmp, 1.0);
215  sg_y_block->Update(1.0, *sg_df_tmp, 1.0);
216  }
217 
218  sg_y_block->Norm2(&norm_df);
219  //std::cout << "norm_df = " << norm_df << std::endl;
220  } //End of iter loop
221 
222  if (made_copy)
223  delete input;
224 
225  return 0;
226 }
227 
228 double
229 Stokhos::GaussSeidelPreconditioner::
230 NormInf() const
231 {
232  return sg_op->NormInf();
233 }
234 
235 
236 const char*
237 Stokhos::GaussSeidelPreconditioner::
238 Label () const
239 {
240  return const_cast<char*>(label.c_str());
241 }
242 
243 bool
244 Stokhos::GaussSeidelPreconditioner::
245 UseTranspose() const
246 {
247  return useTranspose;
248 }
249 
250 bool
251 Stokhos::GaussSeidelPreconditioner::
252 HasNormInf() const
253 {
254  return sg_op->HasNormInf();
255 }
256 
257 const Epetra_Comm &
258 Stokhos::GaussSeidelPreconditioner::
259 Comm() const
260 {
261  return *sg_comm;
262 }
263 const Epetra_Map&
264 Stokhos::GaussSeidelPreconditioner::
265 OperatorDomainMap() const
266 {
267  return *sg_map;
268 }
269 
270 const Epetra_Map&
271 Stokhos::GaussSeidelPreconditioner::
272 OperatorRangeMap() const
273 {
274  return *sg_map;
275 }
#define TEUCHOS_FUNC_TIME_MONITOR(FUNCNAME)
SparseArrayIterator< index_iterator, value_iterator >::value_type index(const SparseArrayIterator< index_iterator, value_iterator > &it)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
RCP< ParameterList > sublist(const RCP< ParameterList > &paramList, const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual Teuchos::RCP< Stokhos::EpetraOperatorOrthogPoly > getSGPolynomial()=0
Get SG polynomial.
expr expr expr dx(i, j)
const Epetra_Comm & Comm() const
ScalarType f(const Teuchos::Array< ScalarType > &x, double a, double b)
SparseArrayIterator< index_iterator, value_iterator >::value_reference value(const SparseArrayIterator< index_iterator, value_iterator > &it)