Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Stokhos_MatrixFreeOperator.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 "EpetraExt_BlockMultiVector.h"
12 #include "EpetraExt_BlockUtility.h"
13 #include "Teuchos_TimeMonitor.hpp"
14 
18  const Teuchos::RCP<const Stokhos::OrthogPolyBasis<int,double> >& sg_basis_,
20  const Teuchos::RCP<const Epetra_Map>& domain_base_map_,
21  const Teuchos::RCP<const Epetra_Map>& range_base_map_,
22  const Teuchos::RCP<const Epetra_Map>& domain_sg_map_,
23  const Teuchos::RCP<const Epetra_Map>& range_sg_map_,
25  label("Stokhos Matrix Free Operator"),
26  sg_comm(sg_comm_),
27  sg_basis(sg_basis_),
28  epetraCijk(epetraCijk_),
29  domain_base_map(domain_base_map_),
30  range_base_map(range_base_map_),
31  domain_sg_map(domain_sg_map_),
32  range_sg_map(range_sg_map_),
33  is_stoch_parallel(epetraCijk->isStochasticParallel()),
34  global_col_map(),
35  global_col_map_trans(),
36  stoch_col_map(epetraCijk->getStochasticColMap()),
37  col_importer(),
38  col_importer_trans(),
39  Cijk(epetraCijk->getParallelCijk()),
40  block_ops(),
41  scale_op(true),
42  include_mean(true),
43  only_use_linear(false),
44  useTranspose(false),
45  use_block_apply(true),
46  expansion_size(sg_basis->size()),
47  num_blocks(0),
48  input_col(),
49  input_col_trans(),
50  input_block(),
51  result_block(),
52  tmp(),
53  tmp_trans(),
54  k_begin(Cijk->k_begin()),
55  k_end(Cijk->k_end())
56 {
57  scale_op = params->get("Scale Operator by Inverse Basis Norms", true);
58  include_mean = params->get("Include Mean", true);
59  only_use_linear = params->get("Only Use Linear Terms", false);
60  use_block_apply = params->get("Use Block Apply", true);
61 
62  // Compute maximum number of mat-vec's needed
63  if (!include_mean && index(k_begin) == 0)
64  ++k_begin;
65  if (only_use_linear) {
66  int dim = sg_basis->dimension();
67  k_end = Cijk->find_k(dim+1);
68  }
69  max_num_mat_vec = 0;
70  for (Cijk_type::k_iterator k=k_begin; k!=k_end; ++k) {
71  int nj = Cijk->num_j(k);
72  if (max_num_mat_vec < nj)
73  max_num_mat_vec = nj;
74  }
75 
76  // Build up column map of SG operator
77  int num_col_blocks = expansion_size;
78  int num_row_blocks = expansion_size;
79  if (is_stoch_parallel) {
80 
81  // Build column map from base domain map. This will communicate
82  // stochastic components to column map, but not deterministic. It would
83  // be more efficient to do both, but the Epetra_Operator interface
84  // doesn't have the concept of a column map.
86  Teuchos::rcp(EpetraExt::BlockUtility::GenerateBlockMap(*domain_base_map,
88  *sg_comm));
90  Teuchos::rcp(EpetraExt::BlockUtility::GenerateBlockMap(*range_base_map,
92  *sg_comm));
93 
94  // Build importer from Domain Map to Column Map
95  col_importer =
99 
100  num_col_blocks = epetraCijk->numMyCols();
101  num_row_blocks = epetraCijk->numMyRows();
102  }
103 
104  input_block.resize(num_col_blocks);
105  result_block.resize(num_row_blocks);
106 }
107 
110 {
111 }
112 
113 double
116 {
117  int n_apply = 0;
118  int n_add = 0;
119  for (Cijk_type::k_iterator k_it=k_begin; k_it!=k_end; ++k_it) {
120  Cijk_type::kj_iterator j_begin = Cijk->j_begin(k_it);
121  Cijk_type::kj_iterator j_end = Cijk->j_end(k_it);
122  for (Cijk_type::kj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
123  ++n_apply;
124  for (Cijk_type::kji_iterator i_it = Cijk->i_begin(j_it);
125  i_it != Cijk->i_end(j_it); ++i_it) {
126  ++n_add;
127  }
128  }
129  }
130 
131  const Epetra_CrsMatrix& mat =
132  dynamic_cast<const Epetra_CrsMatrix&>((*block_ops)[0]);
133  const int nnz = mat.NumGlobalNonzeros();
134  const int nrow = mat.NumGlobalRows();
135  return 2.0 * static_cast<double>(n_apply) * static_cast<double>(nnz) +
136  static_cast<double>(n_add) * static_cast<double>(nrow);
137 }
138 
139 void
143 {
144  block_ops = ops;
145  num_blocks = block_ops->size();
146  if (num_blocks < Cijk->num_k())
147  k_end = Cijk->find_k(num_blocks);
148 }
149 
153 {
154  return block_ops;
155 }
156 
160 {
161  return block_ops;
162 }
163 
164 int
166 SetUseTranspose (bool UseTheTranspose)
167 {
168  useTranspose = UseTheTranspose;
169  for (int i=0; i<num_blocks; i++)
170  (*block_ops)[i].SetUseTranspose(useTranspose);
171 
172  return 0;
173 }
174 
175 int
177 Apply(const Epetra_MultiVector& Input, Epetra_MultiVector& Result) const
178 {
179 #ifdef STOKHOS_TEUCHOS_TIME_MONITOR
180  TEUCHOS_FUNC_TIME_MONITOR("Stokhos: SG Operator Apply()");
181 #endif
182 
183  // Note for transpose:
184  // The stochastic matrix is symmetric, however the matrix blocks may not
185  // be. So the algorithm here is the same whether we are using the transpose
186  // or not. We just apply the transpose of the blocks in the case of
187  // applying the global transpose, and make sure the imported Input
188  // vectors use the right map.
189 
190  // We have to be careful if Input and Result are the same vector.
191  // If this is the case, the only possible solution is to make a copy
192  const Epetra_MultiVector *input = &Input;
193  bool made_copy = false;
194  if (Input.Values() == Result.Values() && !is_stoch_parallel) {
195  input = new Epetra_MultiVector(Input);
196  made_copy = true;
197  }
198 
199  // Initialize
200  Result.PutScalar(0.0);
201 
202  const Epetra_Map* input_base_map = domain_base_map.get();
203  const Epetra_Map* result_base_map = range_base_map.get();
204  if (useTranspose == true) {
205  input_base_map = range_base_map.get();
206  result_base_map = domain_base_map.get();
207  }
208 
209  // Allocate temporary storage
210  int m = Input.NumVectors();
211  if (useTranspose == false &&
212  (tmp == Teuchos::null || tmp->NumVectors() != m*max_num_mat_vec))
213  tmp = Teuchos::rcp(new Epetra_MultiVector(*result_base_map,
214  m*max_num_mat_vec));
215  else if (useTranspose == true &&
216  (tmp_trans == Teuchos::null ||
217  tmp_trans->NumVectors() != m*max_num_mat_vec))
218  tmp_trans = Teuchos::rcp(new Epetra_MultiVector(*result_base_map,
219  m*max_num_mat_vec));
220  Epetra_MultiVector *tmp_result;
221  if (useTranspose == false)
222  tmp_result = tmp.get();
223  else
224  tmp_result = tmp_trans.get();
225 
226  // Map input into column map
227  const Epetra_MultiVector *tmp_col;
228  if (!is_stoch_parallel)
229  tmp_col = input;
230  else {
231  if (useTranspose == false) {
232  if (input_col == Teuchos::null || input_col->NumVectors() != m)
233  input_col = Teuchos::rcp(new Epetra_MultiVector(*global_col_map, m));
234  input_col->Import(*input, *col_importer, Insert);
235  tmp_col = input_col.get();
236  }
237  else {
238  if (input_col_trans == Teuchos::null ||
239  input_col_trans->NumVectors() != m)
240  input_col_trans =
241  Teuchos::rcp(new Epetra_MultiVector(*global_col_map_trans, m));
242  input_col_trans->Import(*input, *col_importer_trans, Insert);
243  tmp_col = input_col_trans.get();
244  }
245  }
246 
247  // Extract blocks
248  EpetraExt::BlockMultiVector sg_input(View, *input_base_map, *tmp_col);
249  EpetraExt::BlockMultiVector sg_result(View, *result_base_map, Result);
250  for (int i=0; i<input_block.size(); i++)
251  input_block[i] = sg_input.GetBlock(i);
252  for (int i=0; i<result_block.size(); i++)
253  result_block[i] = sg_result.GetBlock(i);
254 
255  // Apply block SG operator via
256  // w_i =
257  // \sum_{j=0}^P \sum_{k=0}^L J_k v_j < \psi_i \psi_j \psi_k > / <\psi_i^2>
258  // for i=0,...,P where P = expansion_size, L = num_blocks, w_j is the jth
259  // input block, w_i is the ith result block, and J_k is the kth block operator
260 
261  // k_begin and k_end are initialized in the constructor
262  const Teuchos::Array<double>& norms = sg_basis->norm_squared();
263  for (Cijk_type::k_iterator k_it=k_begin; k_it!=k_end; ++k_it) {
264  int k = index(k_it);
265  Cijk_type::kj_iterator j_begin = Cijk->j_begin(k_it);
266  Cijk_type::kj_iterator j_end = Cijk->j_end(k_it);
267  int nj = Cijk->num_j(k_it);
268  if (nj > 0) {
269  Teuchos::Array<double*> j_ptr(nj*m);
270  Teuchos::Array<int> mj_indices(nj*m);
271  int l = 0;
272  for (Cijk_type::kj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
273  int j = index(j_it);
274  for (int mm=0; mm<m; mm++) {
275  j_ptr[l*m+mm] = (*input_block[j])[mm];
276  mj_indices[l*m+mm] = l*m+mm;
277  }
278  l++;
279  }
280  Epetra_MultiVector input_tmp(View, *input_base_map, &j_ptr[0], nj*m);
281  Epetra_MultiVector result_tmp(View, *tmp_result, &mj_indices[0], nj*m);
282  if (use_block_apply) {
283  (*block_ops)[k].Apply(input_tmp, result_tmp);
284  }
285  else {
286  for (int jj=0; jj<nj*m; jj++)
287  (*block_ops)[k].Apply(*(input_tmp(jj)), *(result_tmp(jj)));
288  }
289  l = 0;
290  for (Cijk_type::kj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
291  int j = index(j_it);
292  for (Cijk_type::kji_iterator i_it = Cijk->i_begin(j_it);
293  i_it != Cijk->i_end(j_it); ++i_it) {
294  int i = index(i_it);
295  double c = value(i_it);
296  if (scale_op) {
297  int i_gid;
298  if (useTranspose)
299  i_gid = epetraCijk->GCID(j);
300  else
301  i_gid = epetraCijk->GRID(i);
302  c /= norms[i_gid];
303  }
304  for (int mm=0; mm<m; mm++)
305  (*result_block[i])(mm)->Update(c, *result_tmp(l*m+mm), 1.0);
306  }
307  l++;
308  }
309  }
310  }
311 
312  // Destroy blocks
313  for (int i=0; i<input_block.size(); i++)
314  input_block[i] = Teuchos::null;
315  for (int i=0; i<result_block.size(); i++)
316  result_block[i] = Teuchos::null;
317 
318  if (made_copy)
319  delete input;
320 
321  return 0;
322 }
323 
324 int
326  Epetra_MultiVector& Result) const
327 {
328  throw "MatrixFreeOperator::ApplyInverse not defined!";
329  return -1;
330 }
331 
332 double
334 {
335  return 1.0;
336 }
337 
338 
339 const char*
341 {
342  return const_cast<char*>(label.c_str());
343 }
344 
345 bool
347 {
348  return useTranspose;
349 }
350 
351 bool
353 {
354  return false;
355 }
356 
357 const Epetra_Comm &
359 {
360  return *sg_comm;
361 }
362 const Epetra_Map&
364 {
365  if (useTranspose)
366  return *range_sg_map;
367  return *domain_sg_map;
368 }
369 
370 const Epetra_Map&
372 {
373  if (useTranspose)
374  return *domain_sg_map;
375  return *range_sg_map;
376 }
MatrixFreeOperator(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.
#define TEUCHOS_FUNC_TIME_MONITOR(FUNCNAME)
Teuchos::RCP< const Cijk_type > Cijk
Stores triple product tensor.
virtual double NormInf() const
Returns an approximate infinity norm of the operator matrix.
virtual const Epetra_Map & OperatorRangeMap() const
Returns the Epetra_Map object associated with the range 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 ...
virtual const char * Label() const
Returns a character string describing the operator.
T & get(ParameterList &l, const std::string &name)
int NumGlobalRows() const
Cijk_type::k_iterator k_end
Ending k iterator.
int expansion_size
Number of terms in expansion.
Teuchos::RCP< Epetra_Map > global_col_map_trans
Stores operator column SG map for transpose.
Teuchos::RCP< const Epetra_BlockMap > stoch_col_map
Stores stochastic part of column map.
virtual int SetUseTranspose(bool UseTranspose)
Set to true if the transpose of the operator is requested.
virtual ordinal_type dimension() const =0
Return dimension of basis.
Teuchos::RCP< const Stokhos::OrthogPolyBasis< int, double > > sg_basis
Stochastic Galerking basis.
virtual bool HasNormInf() const
Returns true if the this object can provide an approximate Inf-norm, false otherwise.
Bi-directional iterator for traversing a sparse array.
bool is_stoch_parallel
Whether we have parallelism over stochastic blocks.
Teuchos::RCP< Epetra_Map > global_col_map
Stores operator column SG map.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
int max_num_mat_vec
Maximum number of matvecs in Apply.
Cijk_type::k_iterator k_begin
Starting k iterator.
Teuchos::RCP< const Epetra_Map > range_base_map
Stores range base map.
Teuchos::RCP< const Stokhos::EpetraSparse3Tensor > epetraCijk
Stores Epetra Cijk tensor.
virtual bool UseTranspose() const
Returns the current UseTranspose setting.
bool include_mean
Flag indicating whether to include mean term.
virtual const Epetra_Comm & Comm() const
Returns a reference to the Epetra_Comm communicator associated with this operator.
int NumGlobalNonzeros() const
Teuchos::RCP< const EpetraExt::MultiComm > sg_comm
Stores SG parallel communicator.
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 ...
Teuchos::Array< Teuchos::RCP< Epetra_MultiVector > > result_block
MultiVectors for each block for Apply() result.
virtual Teuchos::RCP< Stokhos::EpetraOperatorOrthogPoly > getSGPolynomial()
Get SG polynomial.
Teuchos::RCP< Epetra_Import > col_importer
Importer from domain map to column map.
Teuchos::RCP< const Epetra_Map > domain_base_map
Stores domain base map.
bool scale_op
Flag indicating whether operator be scaled with &lt;^2&gt;
Teuchos::RCP< const Epetra_Map > domain_sg_map
Stores domain SG map.
bool use_block_apply
Flag indicating whether to use block Epetra_MultiVector apply.
bool only_use_linear
Flag indicating whether to only use linear terms.
double countApplyFlops() const
Return number of FLOPS for each call to Apply()
Teuchos::RCP< const Epetra_Map > range_sg_map
Stores range SG map.
virtual const Epetra_Map & OperatorDomainMap() const
Returns the Epetra_Map object associated with the domain of this matrix operator. ...
Teuchos::RCP< Epetra_Import > col_importer_trans
Importer from range map to column map.
virtual void setupOperator(const Teuchos::RCP< Stokhos::EpetraOperatorOrthogPoly > &poly)
Setup operator.
ordinal_type size() const
Return size.
Teuchos::Array< Teuchos::RCP< const Epetra_MultiVector > > input_block
MultiVectors for each block for Apply() input.