Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Stokhos_ApproxSchurComplementPreconditioner.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 <algorithm>
13 #include <iostream>
14 #include <iterator>
15 
19  const Teuchos::RCP<const Stokhos::OrthogPolyBasis<int,double> >& sg_basis_,
21  const Teuchos::RCP<const Epetra_Map>& base_map_,
22  const Teuchos::RCP<const Epetra_Map>& sg_map_,
24  const Teuchos::RCP<Teuchos::ParameterList>& params_) :
25  label("Stokhos Approximate Schur Complement Preconditioner"),
26  sg_comm(sg_comm_),
27  sg_basis(sg_basis_),
28  epetraCijk(epetraCijk_),
29  base_map(base_map_),
30  sg_map(sg_map_),
31  prec_factory(prec_factory_),
32  mean_prec(),
33  useTranspose(false),
34  sg_op(),
35  sg_poly(),
36  Cijk(epetraCijk->getParallelCijk()),
37  P(sg_basis->order()),
38  block_indices(P+2),
39  upper_block_Cijk(P+1),
40  lower_block_Cijk(P+1),
41  scale_op(true),
42  symmetric(false),
43  only_use_linear(true),
44  rhs_block()
45 {
46  // Check if parallel, which we don't support
48  epetraCijk->isStochasticParallel(), std::logic_error,
49  "Stokhos::ApproxSchurComplementPreconditioner does not support " <<
50  "a parallel stochastic distribution.");
51 
52  scale_op = params_->get("Scale Operator by Inverse Basis Norms", true);
53  symmetric = params_->get("Symmetric Gauss-Seidel", false);
54  only_use_linear = params_->get("Only Use Linear Terms", true);
55 
56  Cijk_type::k_iterator k_begin = Cijk->k_begin();
57  Cijk_type::k_iterator k_end = Cijk->k_end();
58  if (only_use_linear)
59  k_end = Cijk->find_k(sg_basis()->dimension() + 1);
60 
61  max_num_mat_vec = 0;
62  for (Cijk_type::k_iterator k=k_begin; k!=k_end; ++k) {
63  int nj = Cijk->num_j(k);
64  if (max_num_mat_vec < nj)
65  max_num_mat_vec = nj;
66  }
67 
68  // Get indices for each block
70  Teuchos::rcp_dynamic_cast<const Stokhos::ProductBasis<int,double> >(sg_basis, true);
71  int d = prod_basis->dimension();
72  MultiIndex<int> term(d);
73  for (int p=0; p<=P; p++) {
74  term[0] = p;
75  block_indices[p] = prod_basis->index(term);
78  }
79  block_indices[P+1] = sg_basis->size();
80 
81  // std::cout << "block_indices = [";
82  // std::copy(block_indices.begin(), block_indices.end(),
83  // std::ostream_iterator<int>(std::cout, " "));
84  // std::cout << "]" << std::endl;
85 
86  // Build Cijk tensors for each order block
87  for (Cijk_type::k_iterator k_it=k_begin; k_it!=k_end; ++k_it) {
88  int k = index(k_it);
89  Cijk_type::kj_iterator j_begin = Cijk->j_begin(k_it);
90  Cijk_type::kj_iterator j_end = Cijk->j_end(k_it);
91  for (Cijk_type::kj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
92  int j = index(j_it);
94  std::upper_bound(block_indices.begin(), block_indices.end(), j);
95  int p_col = col_it - block_indices.begin() - 1;
96  Cijk_type::kji_iterator i_begin = Cijk->i_begin(j_it);
97  Cijk_type::kji_iterator i_end = Cijk->i_end(j_it);
98  for (Cijk_type::kji_iterator i_it = i_begin; i_it != i_end; ++i_it) {
99  int i = index(i_it);
100  double c = value(i_it);
102  std::upper_bound(block_indices.begin(), block_indices.end(), i);
103  int p_row = row_it - block_indices.begin() - 1;
104  //std::cout << "i = " << i << ", p_row = " << p_row << ", j = " << j << ", p_col = " << p_col;
105  if (p_col > p_row) {
106  upper_block_Cijk[p_col]->add_term(i,j,k,c);
107  //std::cout << " upper" << std::endl;
108  }
109  else if (p_col < p_row) {
110  lower_block_Cijk[p_row]->add_term(i,j,k,c);
111  //std::cout << " lower" << std::endl;
112  }
113  }
114  }
115  }
116  for (int p=0; p<=P; p++) {
117  upper_block_Cijk[p]->fillComplete();
118  lower_block_Cijk[p]->fillComplete();
119  }
120 }
121 
124 {
125 }
126 
127 void
130  const Epetra_Vector& x)
131 {
132  sg_op = sg_op_;
133  sg_poly = sg_op->getSGPolynomial();
134  mean_prec = prec_factory->compute(sg_poly->getCoeffPtr(0));
135  label = std::string("Stokhos Approximate Schur Complement Preconditioner:\n")
136  + std::string(" ***** ") + std::string(mean_prec->Label());
137 }
138 
139 int
141 SetUseTranspose(bool UseTranspose)
142 {
143  useTranspose = UseTranspose;
144  sg_op->SetUseTranspose(UseTranspose);
145  mean_prec->SetUseTranspose(UseTranspose);
146 
147  return 0;
148 }
149 
150 int
152 Apply(const Epetra_MultiVector& Input, Epetra_MultiVector& Result) const
153 {
154  return sg_op->Apply(Input, Result);
155 }
156 
157 int
160 {
161 #ifdef STOKHOS_TEUCHOS_TIME_MONITOR
162  TEUCHOS_FUNC_TIME_MONITOR("Stokhos: Total Approximate Schur Complement Time");
163 #endif
164 
165  // We have to be careful if Input and Result are the same vector.
166  // If this is the case, the only possible solution is to make a copy
167  const Epetra_MultiVector *input = &Input;
168  bool made_copy = false;
169  if (Input.Values() == Result.Values()) {
170  input = new Epetra_MultiVector(Input);
171  made_copy = true;
172  }
173 
174  // Allocate temporary storage
175  int m = input->NumVectors();
176  if (rhs_block == Teuchos::null || rhs_block->NumVectors() != m)
177  rhs_block =
178  Teuchos::rcp(new EpetraExt::BlockMultiVector(*base_map, *sg_map, m));
179  if (tmp == Teuchos::null || tmp->NumVectors() != m*max_num_mat_vec)
180  tmp = Teuchos::rcp(new Epetra_MultiVector(*base_map,
181  m*max_num_mat_vec));
182  j_ptr.resize(m*max_num_mat_vec);
183  mj_indices.resize(m*max_num_mat_vec);
184 
185  // Extract blocks
186  EpetraExt::BlockMultiVector input_block(View, *base_map, *input);
187  EpetraExt::BlockMultiVector result_block(View, *base_map, Result);
188 
189  result_block.PutScalar(0.0);
190 
191  // Set right-hand-side to input_block
192  rhs_block->Update(1.0, input_block, 0.0);
193 
194  // At level l, linear system has the structure
195  // [ A_{l-1} B_l ][ u_l^{l-1} ] = [ r_l^{l-1} ]
196  // [ C_l D_l ][ u_l^l ] [ r_l^l ]
197 
198  for (int l=P; l>=1; l--) {
199  // Compute D_l^{-1} r_l^l
200  divide_diagonal_block(block_indices[l], block_indices[l+1],
201  *rhs_block, result_block);
202 
203  // Compute r_l^{l-1} = r_l^{l-1} - B_l D_l^{-1} r_l^l
204  multiply_block(upper_block_Cijk[l], -1.0, result_block, *rhs_block);
205  }
206 
207  // Solve A_0 u_0 = r_0
208  divide_diagonal_block(0, 1, *rhs_block, result_block);
209 
210  for (int l=1; l<=P; l++) {
211  // Compute r_l^l - C_l*u_l^{l-1}
212  multiply_block(lower_block_Cijk[l], -1.0, result_block, *rhs_block);
213 
214  // Compute D_l^{-1} (r_l^l - C_l*u_l^{l-1})
215  divide_diagonal_block(block_indices[l], block_indices[l+1],
216  *rhs_block, result_block);
217  }
218 
219  if (made_copy)
220  delete input;
221 
222  return 0;
223 }
224 
225 double
227 NormInf() const
228 {
229  return sg_op->NormInf();
230 }
231 
232 
233 const char*
235 Label() const
236 {
237  return const_cast<char*>(label.c_str());
238 }
239 
240 bool
243 {
244  return useTranspose;
245 }
246 
247 bool
249 HasNormInf() const
250 {
251  return sg_op->HasNormInf();
252 }
253 
254 const Epetra_Comm &
256 Comm() const
257 {
258  return *sg_comm;
259 }
260 const Epetra_Map&
263 {
264  return *sg_map;
265 }
266 
267 const Epetra_Map&
270 {
271  return *sg_map;
272 }
273 
274 void
278  double alpha,
279  const EpetraExt::BlockMultiVector& Input,
280  EpetraExt::BlockMultiVector& Result) const
281 {
282  // Input and Result are the whole vector/multi-vector, not just the portion
283  // needed for the particular sub-block
284  int m = Input.NumVectors();
285  const Teuchos::Array<double>& norms = sg_basis->norm_squared();
286  Cijk_type::k_iterator k_begin = cijk->k_begin();
287  Cijk_type::k_iterator k_end = cijk->k_end();
288  if (only_use_linear)
289  k_end = cijk->find_k(sg_basis()->dimension() + 1);
290  for (Cijk_type::k_iterator k_it=k_begin; k_it!=k_end; ++k_it) {
291  int k = index(k_it);
292  Cijk_type::kj_iterator j_begin = cijk->j_begin(k_it);
293  Cijk_type::kj_iterator j_end = cijk->j_end(k_it);
294  int nj = cijk->num_j(k_it);
295  if (nj > 0) {
296  int l = 0;
297  for (Cijk_type::kj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
298  int j = index(j_it);
299  for (int mm=0; mm<m; mm++) {
300  j_ptr[l*m+mm] = (*(Input.GetBlock(j)))[mm];
301  mj_indices[l*m+mm] = l*m+mm;
302  }
303  l++;
304  }
305  Epetra_MultiVector input_tmp(View, *base_map, &j_ptr[0], nj*m);
306  Epetra_MultiVector result_tmp(View, *tmp, &mj_indices[0], nj*m);
307  (*sg_poly)[k].Apply(input_tmp, result_tmp);
308  l = 0;
309  for (Cijk_type::kj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
310  Cijk_type::kji_iterator i_begin = cijk->i_begin(j_it);
311  Cijk_type::kji_iterator i_end = cijk->i_end(j_it);
312  for (Cijk_type::kji_iterator i_it = i_begin; i_it != i_end; ++i_it) {
313  int i = index(i_it);
314  double c = value(i_it);
315  if (scale_op)
316  c /= norms[i];
317  for (int mm=0; mm<m; mm++)
318  (*Result.GetBlock(i))(mm)->Update(alpha*c, *result_tmp(l*m+mm), 1.0);
319  }
320  l++;
321  }
322  }
323  }
324 }
325 
326 void
328 divide_diagonal_block(int row_begin, int row_end,
329  const EpetraExt::BlockMultiVector& Input,
330  EpetraExt::BlockMultiVector& Result) const
331 {
332  for (int i=row_begin; i<row_end; i++) {
333 #ifdef STOKHOS_TEUCHOS_TIME_MONITOR
335  "Stokhos: ASC Deterministic Preconditioner Time");
336 #endif
337  mean_prec->ApplyInverse(*(Input.GetBlock(i)), *(Result.GetBlock(i)));
338  }
339 }
virtual const Epetra_Comm & Comm() const
Returns a reference to the Epetra_Comm communicator associated with this operator.
#define TEUCHOS_FUNC_TIME_MONITOR(FUNCNAME)
virtual int Apply(const Epetra_MultiVector &Input, Epetra_MultiVector &Result) const
Returns the result of a Epetra_Operator applied to a Epetra_MultiVector Input in Result as described ...
virtual const Epetra_Map & OperatorRangeMap() const
Returns the Epetra_Map object associated with the range of this matrix operator.
Teuchos::RCP< const Stokhos::OrthogPolyBasis< int, double > > sg_basis
Stochastic Galerking basis.
T & get(ParameterList &l, const std::string &name)
void multiply_block(const Teuchos::RCP< const Stokhos::Sparse3Tensor< int, double > > &cijk, double alpha, const EpetraExt::BlockMultiVector &Input, EpetraExt::BlockMultiVector &Result) const
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::RCP< const Cijk_type > Cijk
Pointer to triple product.
virtual int ApplyInverse(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const
Returns the result of the inverse of the operator applied to a Epetra_MultiVector Input in Result as ...
Bi-directional iterator for traversing a sparse array.
A multidimensional index.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual bool HasNormInf() const
Returns true if the this object can provide an approximate Inf-norm, false otherwise.
virtual Teuchos::RCP< Stokhos::EpetraOperatorOrthogPoly > getSGPolynomial()=0
Get SG polynomial.
Teuchos::Array< Teuchos::RCP< Cijk_type > > upper_block_Cijk
Triple product tensor for each sub-block.
virtual const Epetra_Map & OperatorDomainMap() const
Returns the Epetra_Map object associated with the domain of this matrix operator. ...
void divide_diagonal_block(int row_begin, int row_end, const EpetraExt::BlockMultiVector &Input, EpetraExt::BlockMultiVector &Result) const
iterator end()
KOKKOS_INLINE_FUNCTION constexpr std::enable_if< is_view_uq_pce< view_type >::value, typename CijkType< view_type >::type >::type cijk(const view_type &view)
virtual double NormInf() const
Returns an approximate infinity norm of the operator matrix.
ApproxSchurComplementPreconditioner(const Teuchos::RCP< const EpetraExt::MultiComm > &sg_comm, const Teuchos::RCP< const Stokhos::OrthogPolyBasis< int, double > > &sg_basis, const Teuchos::RCP< const Stokhos::EpetraSparse3Tensor > &epetraCijk, const Teuchos::RCP< const Epetra_Map > &base_map, const Teuchos::RCP< const Epetra_Map > &sg_map, const Teuchos::RCP< Stokhos::AbstractPreconditionerFactory > &prec_factory, const Teuchos::RCP< Teuchos::ParameterList > &params)
Constructor.
virtual int SetUseTranspose(bool UseTranspose)
Set to true if the transpose of the operator is requested.
size_type size() const
virtual const char * Label() const
Returns a character string describing the operator.
virtual void setupPreconditioner(const Teuchos::RCP< Stokhos::SGOperator > &sg_op, const Epetra_Vector &x)
Setup preconditioner.
bool scale_op
Flag indicating whether operator be scaled with &lt;^2&gt;
virtual bool UseTranspose() const
Returns the current UseTranspose setting.
Teuchos::RCP< const Stokhos::EpetraSparse3Tensor > epetraCijk
Stores Epetra Cijk tensor.
std::vector< T >::iterator iterator
iterator begin()