Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Stokhos_KLReducedMatrixFreeOperator.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 #include "EpetraExt_BlockMultiVector.h"
12 #include "Stokhos_PCEAnasaziKL.hpp"
13 #include "Teuchos_Assert.hpp"
14 #include "Teuchos_TimeMonitor.hpp"
18 #include <sstream>
19 
23  const Teuchos::RCP<const Stokhos::OrthogPolyBasis<int,double> >& sg_basis_,
25  const Teuchos::RCP<const Epetra_Map>& domain_base_map_,
26  const Teuchos::RCP<const Epetra_Map>& range_base_map_,
27  const Teuchos::RCP<const Epetra_Map>& domain_sg_map_,
28  const Teuchos::RCP<const Epetra_Map>& range_sg_map_,
29  const Teuchos::RCP<Teuchos::ParameterList>& params_) :
30  label("Stokhos KL Reduced Matrix Free Operator"),
31  sg_comm(sg_comm_),
32  sg_basis(sg_basis_),
33  epetraCijk(epetraCijk_),
34  domain_base_map(domain_base_map_),
35  range_base_map(range_base_map_),
36  domain_sg_map(domain_sg_map_),
37  range_sg_map(range_sg_map_),
38  Cijk(epetraCijk->getParallelCijk()),
39  block_ops(),
40  params(params_),
41  useTranspose(false),
42  expansion_size(sg_basis->size()),
43  num_blocks(0),
44  num_KL(0),
45  num_KL_computed(0),
46  mean(),
47  block_vec_map(),
48  block_vec_poly(),
49  dot_products(),
50  sparse_kl_coeffs(),
51  kl_blocks()
52 {
53  num_KL = params->get("Number of KL Terms", 5);
54  drop_tolerance = params->get("Sparse 3 Tensor Drop Tolerance", 1e-6);
55  do_error_tests = params->get("Do Error Tests", false);
56 }
57 
58 void
62 {
63  block_ops = ops;
64  num_blocks = block_ops->size();
65 
66  // Build a vector polynomial out of matrix nonzeros
67  mean = Teuchos::rcp_dynamic_cast<Epetra_CrsMatrix>(
68  block_ops->getCoeffPtr(0));
69  block_vec_map =
70  Teuchos::rcp(new Epetra_Map(-1, mean->NumMyNonzeros(), 0,
71  domain_base_map->Comm()));
72  block_vec_poly =
74  sg_basis, block_ops->map(), block_vec_map, sg_comm));
75 
76  // Setup KL blocks
77  setup();
78 }
79 
83 {
84  return block_ops;
85 }
86 
90 {
91  return block_ops;
92 }
93 
96 {
97 }
98 
99 int
101 SetUseTranspose(bool UseTheTranspose)
102 {
103  useTranspose = UseTheTranspose;
104  kl_mat_free_op->SetUseTranspose(useTranspose);
105  for (int i=0; i<num_blocks; i++)
106  (*block_ops)[i].SetUseTranspose(useTranspose);
107 
108  return 0;
109 }
110 
111 int
113 Apply(const Epetra_MultiVector& Input, Epetra_MultiVector& Result) const
114 {
115  return kl_mat_free_op->Apply(Input, Result);
116 }
117 
118 int
121 {
122  throw "KLReducedMatrixFreeOperator::ApplyInverse not defined!";
123  return -1;
124 }
125 
126 double
128 NormInf() const
129 {
130  return 1.0;
131 }
132 
133 
134 const char*
136 Label () const
137 {
138  return const_cast<char*>(label.c_str());
139 }
140 
141 bool
144 {
145  return useTranspose;
146 }
147 
148 bool
150 HasNormInf() const
151 {
152  return false;
153 }
154 
155 const Epetra_Comm &
157 Comm() const
158 {
159  return *sg_comm;
160 }
161 const Epetra_Map&
164 {
165  if (useTranspose)
166  return *range_sg_map;
167  return *domain_sg_map;
168 }
169 
170 const Epetra_Map&
173 {
174  if (useTranspose)
175  return *domain_sg_map;
176  return *range_sg_map;
177 }
178 
179 void
182 {
183 #ifdef HAVE_STOKHOS_ANASAZI
184 #ifdef STOKHOS_TEUCHOS_TIME_MONITOR
185  TEUCHOS_FUNC_TIME_MONITOR("Stokhos::KLReducedMatrixFreeOperator -- Calculation/setup of KL opeator");
186 #endif
187 
188  mean = Teuchos::rcp_dynamic_cast<Epetra_CrsMatrix>(
189  block_ops->getCoeffPtr(0));
190 
191  // Copy matrix coefficients into vectors
192  for (int coeff=0; coeff<num_blocks; coeff++) {
194  Teuchos::rcp_dynamic_cast<Epetra_CrsMatrix>
195  (block_ops->getCoeffPtr(coeff));
196  int row = 0;
197  for (int i=0; i<mean->NumMyRows(); i++) {
198  int num_col;
199  mean->NumMyRowEntries(i, num_col);
200  for (int j=0; j<num_col; j++)
201  (*block_vec_poly)[coeff][row++] = (*block_coeff)[i][j];
202  }
203  }
204 
205  int myPID = sg_comm->MyPID();
206 
207  // Compute KL expansion of solution sg_J_vec_poly
208  Stokhos::PCEAnasaziKL pceKL(*block_vec_poly, num_KL);
209  Teuchos::ParameterList anasazi_params = pceKL.getDefaultParams();
210  bool result = pceKL.computeKL(anasazi_params);
211  if (!result && myPID == 0)
212  std::cout << "KL Eigensolver did not converge!" << std::endl;
213  Teuchos::RCP<Epetra_MultiVector> evecs = pceKL.getEigenvectors();
214  Teuchos::Array<double> evals = pceKL.getEigenvalues();
215  //num_KL_computed = evecs->NumVectors();
216  if (myPID == 0)
217  std::cout << "num computed eigenvectors = "
218  << evecs->NumVectors() << std::endl;
219  double kl_tol = params->get("KL Tolerance", 1e-6);
220  num_KL_computed = 0;
221  while (num_KL_computed < evals.size() &&
222  std::sqrt(evals[num_KL_computed]/evals[0]) > kl_tol)
223  num_KL_computed++;
224  if (num_KL_computed == evals.size() && myPID == 0)
225  std::cout << "Can't achieve KL tolerance " << kl_tol
226  << ". Smallest eigenvalue / largest eigenvalue = "
227  << std::sqrt(evals[num_KL_computed-1]/evals[0]) << std::endl;
228  if (myPID == 0)
229  std::cout << "num KL eigenvectors = " << num_KL_computed << std::endl;
230 
231  // Compute dot products of Jacobian blocks and KL eigenvectors
232  dot_products.resize(num_KL_computed);
233  for (int rv=0; rv < num_KL_computed; rv++) {
234  dot_products[rv].resize(num_blocks-1);
235  for (int coeff=1; coeff < num_blocks; coeff++) {
236  double dot;
237  (*block_vec_poly)[coeff].Dot(*((*evecs)(rv)), &dot);
238  dot_products[rv][coeff-1] = dot;
239  }
240  }
241 
242  // Compute KL coefficients
243  const Teuchos::Array<double>& norms = sg_basis->norm_squared();
244  sparse_kl_coeffs =
246  for (Cijk_type::i_iterator i_it=Cijk->i_begin();
247  i_it!=Cijk->i_end(); ++i_it) {
248  int i = epetraCijk->GRID(index(i_it));
249  sparse_kl_coeffs->sum_term(i, i, 0, norms[i]);
250  }
251  Cijk_type::k_iterator l_begin = ++(Cijk->k_begin());
252  Cijk_type::k_iterator l_end = Cijk->k_end();
253  for (Cijk_type::k_iterator l_it=l_begin; l_it!=l_end; ++l_it) {
254  int l = index(l_it);
255  for (Cijk_type::kj_iterator j_it = Cijk->j_begin(l_it);
256  j_it != Cijk->j_end(l_it); ++j_it) {
257  int j = epetraCijk->GCID(index(j_it));
258  for (Cijk_type::kji_iterator i_it = Cijk->i_begin(j_it);
259  i_it != Cijk->i_end(j_it); ++i_it) {
260  int i = epetraCijk->GRID(index(i_it));
261  double c = value(i_it);
262  for (int k=1; k<num_KL_computed+1; k++) {
263  double dp = dot_products[k-1][l-1];
264  double v = dp*c;
265  if (std::abs(v) > drop_tolerance)
266  sparse_kl_coeffs->sum_term(i,j,k,v);
267  }
268  }
269  }
270  }
271  sparse_kl_coeffs->fillComplete();
272 
273  bool save_tensor = params->get("Save Sparse 3 Tensor To File", false);
274  if (save_tensor) {
275  static int idx = 0;
276  std::string basename = params->get("Sparse 3 Tensor Base Filename",
277  "sparse_KL_coeffs");
278  std::stringstream ss;
279  ss << basename << "_" << idx++ << ".mm";
280  sparse3Tensor2MatrixMarket(*sparse_kl_coeffs,
281  *(epetraCijk->getStochasticRowMap()), ss.str());
282  }
283 
284  // Transform eigenvectors back to matrices
285  kl_blocks.resize(num_KL_computed);
287  Teuchos::rcp(new Epetra_LocalMap(num_KL_computed+1, 0,
288  sg_comm->TimeDomainComm()));
289  kl_ops =
291  sg_basis, kl_map, domain_base_map, range_base_map,
292  range_sg_map, sg_comm));
293  kl_ops->setCoeffPtr(0, mean);
294  for (int rv=0; rv<num_KL_computed; rv++) {
295  if (kl_blocks[rv] == Teuchos::null)
296  kl_blocks[rv] = Teuchos::rcp(new Epetra_CrsMatrix(*mean));
297  int row = 0;
298  for (int i=0; i<mean->NumMyRows(); i++) {
299  int num_col;
300  mean->NumMyRowEntries(i, num_col);
301  for (int j=0; j<num_col; j++)
302  (*kl_blocks[rv])[i][j] = (*evecs)[rv][row++];
303  }
304  kl_ops->setCoeffPtr(rv+1, kl_blocks[rv]);
305  }
306 
309  sg_basis, sparse_kl_coeffs, sg_comm,
310  epetraCijk->getStochasticRowMap(), sparse_kl_coeffs,
311  0, -1));
312  reducedEpetraCijk->transformToLocal();
313 
314  // Create matrix-free op
315  kl_mat_free_op = Teuchos::rcp(new Stokhos::MatrixFreeOperator(
316  sg_comm, sg_basis, reducedEpetraCijk,
317  domain_base_map, range_base_map,
318  domain_sg_map, range_sg_map, params));
319  kl_mat_free_op->setupOperator(kl_ops);
320 
321  // Check accuracy of KL expansion
322  if (do_error_tests) {
323  Teuchos::Array<double> point(sg_basis->dimension());
324  for (int i=0; i<sg_basis->dimension(); i++)
325  point[i] = 0.5;
326  Teuchos::Array<double> basis_vals(sg_basis->size());
327  sg_basis->evaluateBases(point, basis_vals);
328 
329  Epetra_Vector val(*block_vec_map);
330  Epetra_Vector val_kl(*block_vec_map);
331  block_vec_poly->evaluate(basis_vals, val);
332  val_kl.Update(1.0, (*block_vec_poly)[0], 0.0);
334  Teuchos::Array<double> val_rvs(num_KL_computed);
335  for (int rv=0; rv<num_KL_computed; rv++) {
336  rvs[rv].reset(sg_basis);
337  rvs[rv][0] = 0.0;
338  for (int coeff=1; coeff<num_blocks; coeff++)
339  rvs[rv][coeff] = dot_products[rv][coeff-1];
340  val_rvs[rv] = rvs[rv].evaluate(point, basis_vals);
341  val_kl.Update(val_rvs[rv], *((*evecs)(rv)), 1.0);
342  }
343  double nrm;
344  val.NormInf(&nrm);
345  val.Update(-1.0, val_kl, 1.0);
346  double diff;
347  val.NormInf(&diff);
348  if (myPID == 0)
349  std::cout << "Infinity norm of random field difference = " << diff/nrm
350  << std::endl;
351 
352  // Check accuracy of operator
353  Epetra_Vector op_input(*domain_sg_map), op_result(*range_sg_map), op_kl_result(*range_sg_map);
354  op_input.PutScalar(1.0);
355  Stokhos::MatrixFreeOperator op(sg_comm, sg_basis, epetraCijk,
356  domain_base_map, range_base_map,
357  domain_sg_map, range_sg_map, params);
358  op.setupOperator(block_ops);
359  op.Apply(op_input, op_result);
360  this->Apply(op_input, op_kl_result);
361  op_result.NormInf(&nrm);
362  op_result.Update(-1.0, op_kl_result, 1.0);
363  op_result.NormInf(&diff);
364  if (myPID == 0)
365  std::cout << "Infinity norm of operator difference = " << diff/nrm
366  << std::endl;
367  }
368 
369 #else
370  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
371  "Stokhos::KLReducedMatrixFreeOperator is available " <<
372  "only when configured with Anasazi support!")
373 #endif
374 }
int NumMyRowEntries(int MyRow, int &NumEntries) const
KOKKOS_INLINE_FUNCTION PCE< Storage > sqrt(const PCE< Storage > &a)
virtual const Epetra_Map & OperatorDomainMap() const
Returns the Epetra_Map object associated with the domain of this matrix operator. ...
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 ...
An Epetra operator representing the block stochastic Galerkin operator.
#define TEUCHOS_FUNC_TIME_MONITOR(FUNCNAME)
A container class storing an orthogonal polynomial whose coefficients are vectors, operators, or in general any type that would have an expensive copy constructor.
virtual bool HasNormInf() const
Returns true if the this object can provide an approximate Inf-norm, false otherwise.
void transformToLocal()
Transform Cijk to local i and j indices.
T & get(ParameterList &l, const std::string &name)
void sparse3Tensor2MatrixMarket(const Stokhos::OrthogPolyBasis< ordinal_type, value_type > &basis, const Stokhos::Sparse3Tensor< ordinal_type, value_type > &Cijk, const Epetra_Comm &comm, const std::string &file)
virtual const char * Label() const
Returns a character string describing the operator.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
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 double NormInf() const
Returns an approximate infinity norm of the operator matrix.
std::enable_if< Kokkos::is_view_uq_pce< Kokkos::View< XD, XP...> >::value &&Kokkos::is_view_uq_pce< Kokkos::View< YD, YP...> >::value, typename Kokkos::Details::InnerProductSpaceTraits< typename Kokkos::View< XD, XP...>::non_const_value_type >::dot_type >::type dot(const Kokkos::View< XD, XP...> &x, const Kokkos::View< YD, YP...> &y)
virtual Teuchos::RCP< Stokhos::EpetraOperatorOrthogPoly > getSGPolynomial()
Get SG polynomial.
Bi-directional iterator for traversing a sparse array.
bool do_error_tests
Whether to do KL error tests (can be expensive)
KLReducedMatrixFreeOperator(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 > &domain_base_map, const Teuchos::RCP< const Epetra_Map > &range_base_map, const Teuchos::RCP< const Epetra_Map > &domain_sg_map, const Teuchos::RCP< const Epetra_Map > &range_sg_map, const Teuchos::RCP< Teuchos::ParameterList > &params)
Constructor.
virtual void setupOperator(const Teuchos::RCP< Stokhos::EpetraOperatorOrthogPoly > &poly)
Setup operator.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
A container class storing an orthogonal polynomial whose coefficients are vectors, operators, or in general any type that would have an expensive copy constructor.
double drop_tolerance
Tolerance for dropping entries in sparse 3 tensor.
KOKKOS_INLINE_FUNCTION PCE< Storage > abs(const PCE< Storage > &a)
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_Comm & Comm() const
Returns a reference to the Epetra_Comm communicator associated with this operator.
expr val()
size_type size() const
Teuchos::RCP< Teuchos::ParameterList > params
Algorithmic parameters.
virtual int SetUseTranspose(bool UseTranspose)
Set to true if the transpose of the operator is requested.
virtual void setupOperator(const Teuchos::RCP< Stokhos::EpetraOperatorOrthogPoly > &poly)
Setup operator.
ordinal_type size() const
Return size.
virtual bool UseTranspose() const
Returns the current UseTranspose setting.
virtual const Epetra_Map & OperatorRangeMap() const
Returns the Epetra_Map object associated with the range of this matrix operator.