Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
twoD_diffusion_problem.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 
13 #include "EpetraExt_MatrixMatrix.h"
14 #include "Teuchos_Assert.hpp"
16 
17 namespace {
18 
19  // Functor representing a diffusion function given by a KL expansion
20  struct KL_Diffusion_Func {
21  double mean;
22  mutable Teuchos::Array<double> point;
24 
25  KL_Diffusion_Func(double xyLeft, double xyRight,
26  double mean_, double std_dev,
27  double L, int num_KL) : mean(mean_), point(2)
28  {
29  Teuchos::ParameterList rfParams;
30  rfParams.set("Number of KL Terms", num_KL);
31  rfParams.set("Mean", mean);
32  rfParams.set("Standard Deviation", std_dev);
33  int ndim = 2;
34  Teuchos::Array<double> domain_upper(ndim), domain_lower(ndim),
35  correlation_length(ndim);
36  for (int i=0; i<ndim; i++) {
37  domain_upper[i] = xyRight;
38  domain_lower[i] = xyLeft;
39  correlation_length[i] = L;
40  }
41  rfParams.set("Domain Upper Bounds", domain_upper);
42  rfParams.set("Domain Lower Bounds", domain_lower);
43  rfParams.set("Correlation Lengths", correlation_length);
44 
45  rf =
47  }
48 
49  double operator() (double x, double y, int k) const {
50  if (k == 0)
51  return mean;
52  point[0] = x;
53  point[1] = y;
54  return rf->evaluate_eigenfunction(point, k-1);
55  }
56  };
57 
58  // Functor representing a diffusion function given by a KL expansion
59  // where the basis is normalized
60  template <typename DiffusionFunc>
61  struct Normalized_KL_Diffusion_Func {
62  const DiffusionFunc& func;
63  int d;
64  Teuchos::Array<double> psi_0, psi_1;
65 
66  Normalized_KL_Diffusion_Func(
67  const DiffusionFunc& func_,
69  func(func_),
70  d(basis.dimension()),
71  psi_0(basis.size()),
72  psi_1(basis.size())
73  {
74  Teuchos::Array<double> zero(d), one(d);
75  for(int k=0; k<d; k++) {
76  zero[k] = 0.0;
77  one[k] = 1.0;
78  }
79  basis.evaluateBases(zero, psi_0);
80  basis.evaluateBases(one, psi_1);
81  }
82 
83  double operator() (double x, double y, int k) const {
84  if (k == 0) {
85  double val = func(x, y, 0);
86  for (int i=1; i<=d; i++)
87  val -= psi_0[i]/(psi_1[i]-psi_0[i])*func(x, y, i);
88  val /= psi_0[0];
89  return val;
90  }
91  else
92  return 1.0/(psi_1[k]-psi_0[k])*func(x, y, k);
93  }
94  };
95 
96  // Functor representing a diffusion function given by a log-normal PC expansion
97  template <typename DiffusionFunc>
98  struct LogNormal_Diffusion_Func {
99  double mean;
100  const DiffusionFunc& func;
102 
103  LogNormal_Diffusion_Func(
104  double mean_,
105  const DiffusionFunc& func_,
106  const Teuchos::RCP<const Stokhos::ProductBasis<int, double> > prodbasis_)
107  : mean(mean_), func(func_), prodbasis(prodbasis_) {}
108 
109  double operator() (double x, double y, int k) const {
110  int d = prodbasis->dimension();
111  const Teuchos::Array<double>& norms = prodbasis->norm_squared();
112  Teuchos::Array<int> multiIndex = prodbasis->getTerm(k);
113  double sum_g = 0.0, efval;
114  for (int l=0; l<d; l++) {
115  sum_g += std::pow(func(x,y,l+1),2);
116  }
117  efval = std::exp(mean + 0.5*sum_g)/norms[k];
118  for (int l=0; l<d; l++) {
119  efval *= std::pow(func(x,y,l+1),multiIndex[l]);
120  }
121  return efval;
122  }
123  };
124 
125 }
126 
129  const Teuchos::RCP<const Epetra_Comm>& comm, int n, int d,
130  double s, double mu,
132  bool log_normal_,
133  bool eliminate_bcs_) :
134  mesh(n*n),
135  basis(basis_),
136  log_normal(log_normal_),
137  eliminate_bcs(eliminate_bcs_)
138 {
140  // Construct the mesh.
141  // The mesh is uniform and the nodes are numbered
142  // LEFT to RIGHT, DOWN to UP.
143  //
144  // 5-6-7-8-9
145  // | | | | |
146  // 0-1-2-3-4
148  double xyLeft = -.5;
149  double xyRight = .5;
150  h = (xyRight - xyLeft)/((double)(n-1));
151  Teuchos::Array<int> global_dof_indices;
152  for (int j=0; j<n; j++) {
153  double y = xyLeft + j*h;
154  for (int i=0; i<n; i++) {
155  double x = xyLeft + i*h;
156  int idx = j*n+i;
157  mesh[idx].x = x;
158  mesh[idx].y = y;
159  if (i == 0 || i == n-1 || j == 0 || j == n-1)
160  mesh[idx].boundary = true;
161  if (i != 0)
162  mesh[idx].left = idx-1;
163  if (i != n-1)
164  mesh[idx].right = idx+1;
165  if (j != 0)
166  mesh[idx].down = idx-n;
167  if (j != n-1)
168  mesh[idx].up = idx+n;
169  if (!(eliminate_bcs && mesh[idx].boundary))
170  global_dof_indices.push_back(idx);
171  }
172  }
173 
174  // Solution vector map
175  int n_global_dof = global_dof_indices.size();
176  int n_proc = comm->NumProc();
177  int proc_id = comm->MyPID();
178  int n_my_dof = n_global_dof / n_proc;
179  if (proc_id == n_proc-1)
180  n_my_dof += n_global_dof % n_proc;
181  int *my_dof = global_dof_indices.getRawPtr() + proc_id*(n_global_dof / n_proc);
182  x_map =
183  Teuchos::rcp(new Epetra_Map(n_global_dof, n_my_dof, my_dof, 0, *comm));
184 
185  // Initial guess, initialized to 0.0
186  x_init = Teuchos::rcp(new Epetra_Vector(*x_map));
187  x_init->PutScalar(0.0);
188 
189  // Parameter vector map
190  p_map = Teuchos::rcp(new Epetra_LocalMap(d, 0, *comm));
191 
192  // Response vector map
193  g_map = Teuchos::rcp(new Epetra_LocalMap(1, 0, *comm));
194 
195  // Initial parameters
197  p_init->PutScalar(0.0);
198 
199  // Parameter names
201  for (int i=0;i<d;i++) {
202  std::stringstream ss;
203  ss << "KL Random Variable " << i+1;
204  (*p_names)[i] = ss.str();
205  }
206 
207  // Build Jacobian graph
208  int NumMyElements = x_map->NumMyElements();
209  int *MyGlobalElements = x_map->MyGlobalElements();
210  graph = Teuchos::rcp(new Epetra_CrsGraph(Copy, *x_map, 5));
211  for (int i=0; i<NumMyElements; ++i ) {
212 
213  // Center
214  int global_idx = MyGlobalElements[i];
215  graph->InsertGlobalIndices(global_idx, 1, &global_idx);
216 
217  if (!mesh[global_idx].boundary) {
218  // Down
219  if (!(eliminate_bcs && mesh[mesh[global_idx].down].boundary))
220  graph->InsertGlobalIndices(global_idx, 1, &mesh[global_idx].down);
221 
222  // Left
223  if (!(eliminate_bcs && mesh[mesh[global_idx].left].boundary))
224  graph->InsertGlobalIndices(global_idx, 1, &mesh[global_idx].left);
225 
226  // Right
227  if (!(eliminate_bcs && mesh[mesh[global_idx].right].boundary))
228  graph->InsertGlobalIndices(global_idx, 1, &mesh[global_idx].right);
229 
230  // Up
231  if (!(eliminate_bcs && mesh[mesh[global_idx].up].boundary))
232  graph->InsertGlobalIndices(global_idx, 1, &mesh[global_idx].up);
233  }
234  }
235  graph->FillComplete();
237 
238  KL_Diffusion_Func klFunc(xyLeft, xyRight, mu, s, 1.0, d);
239  if (!log_normal) {
240  // Fill coefficients of KL expansion of operator
241  if (basis == Teuchos::null) {
242  fillMatrices(klFunc, d+1);
243  }
244  else {
245  Normalized_KL_Diffusion_Func<KL_Diffusion_Func> nklFunc(klFunc, *basis);
246  fillMatrices(nklFunc, d+1);
247  }
248  }
249  else {
250  // Fill coefficients of PC expansion of operator
251  int sz = basis->size();
253  Teuchos::rcp_dynamic_cast<const Stokhos::ProductBasis<int, double> >(
254  basis, true);
256  fillMatrices(lnFunc, sz);
257  }
258 
259  // Construct deterministic operator
261 
262  // Construct the RHS vector.
263  b = Teuchos::rcp(new Epetra_Vector(*x_map));
264  for( int i=0 ; i<NumMyElements; ++i ) {
265  int global_idx = MyGlobalElements[i];
266  if (mesh[global_idx].boundary)
267  (*b)[i] = 0;
268  else
269  (*b)[i] = 1;
270  }
271 
272  if (basis != Teuchos::null) {
273  point.resize(d);
274  basis_vals.resize(basis->size());
275  }
276 }
277 
278 // Overridden from EpetraExt::ModelEvaluator
279 
282 get_x_map() const
283 {
284  return x_map;
285 }
286 
289 get_f_map() const
290 {
291  return x_map;
292 }
293 
296 get_p_map(int l) const
297 {
299  std::logic_error,
300  std::endl <<
301  "Error! twoD_diffusion_problem::get_p_map(): " <<
302  "Invalid parameter index l = " << l << std::endl);
303 
304  return p_map;
305 }
306 
309 get_g_map(int l) const
310 {
312  std::logic_error,
313  std::endl <<
314  "Error! twoD_diffusion_problem::get_g_map(): " <<
315  "Invalid parameter index l = " << l << std::endl);
316 
317  return g_map;
318 }
319 
322 get_p_names(int l) const
323 {
325  std::logic_error,
326  std::endl <<
327  "Error! twoD_diffusion_problem::get_p_names(): " <<
328  "Invalid parameter index l = " << l << std::endl);
329 
330  return p_names;
331 }
332 
335 get_x_init() const
336 {
337  return x_init;
338 }
339 
342 get_p_init(int l) const
343 {
345  std::logic_error,
346  std::endl <<
347  "Error! twoD_diffusion_problem::get_p_init(): " <<
348  "Invalid parameter index l = " << l << std::endl);
349 
350  return p_init;
351 }
352 
355 create_W() const
356 {
359  AA->FillComplete();
360  AA->OptimizeStorage();
361  return AA;
362 }
363 
364 void
367  const Epetra_Vector& p,
368  Epetra_Vector& f)
369 {
370  // f = A*x - b
371  compute_A(p);
372  A->Apply(x,f);
373  f.Update(-1.0, *b, 1.0);
374 }
375 
376 void
379  const Epetra_Vector& p,
380  Epetra_Operator& J)
381 {
382  // J = A
383  compute_A(p);
384  Epetra_CrsMatrix& jac = dynamic_cast<Epetra_CrsMatrix&>(J);
385  jac = *A;
386  jac.FillComplete();
387  jac.OptimizeStorage();
388 }
389 
390 void
393  const Epetra_Vector& p,
394  Epetra_Vector& g)
395 {
396  // g = average of x
397  x.MeanValue(&g[0]);
398  g[0] *= double(x.GlobalLength()) / double(mesh.size());
399 }
400 
401 void
407 {
408  // Get stochastic expansion data
411  const Teuchos::Array<double>& norms = basis->norm_squared();
412 
413  if (sg_kx_vec_all.size() != basis->size()) {
414  sg_kx_vec_all.resize(basis->size());
415  for (int i=0;i<basis->size();i++) {
417  }
418  }
419  f_sg.init(0.0);
420 
421  Cijk_type::k_iterator k_begin = Cijk->k_begin();
422  Cijk_type::k_iterator k_end = Cijk->k_end();
423  for (Cijk_type::k_iterator k_it=k_begin; k_it!=k_end; ++k_it) {
424  int k = Stokhos::index(k_it);
425  for (Cijk_type::kj_iterator j_it = Cijk->j_begin(k_it);
426  j_it != Cijk->j_end(k_it); ++j_it) {
427  int j = Stokhos::index(j_it);
428  A_k[k]->Apply(x_sg[j],*(sg_kx_vec_all[j]));
429  }
430  for (Cijk_type::kj_iterator j_it = Cijk->j_begin(k_it);
431  j_it != Cijk->j_end(k_it); ++j_it) {
432  int j = Stokhos::index(j_it);
433  for (Cijk_type::kji_iterator i_it = Cijk->i_begin(j_it);
434  i_it != Cijk->i_end(j_it); ++i_it) {
435  int i = Stokhos::index(i_it);
436  double c = Stokhos::value(i_it); // C(i,j,k)
437  f_sg[i].Update(1.0*c/norms[i],*(sg_kx_vec_all[j]),1.0);
438  }
439  }
440  }
441  f_sg[0].Update(-1.0,*b,1.0);
442 }
443 
444 void
449 {
450  for (int i=0; i<J_sg.size(); i++) {
452  Teuchos::rcp_dynamic_cast<Epetra_CrsMatrix>(J_sg.getCoeffPtr(i), true);
453  *jac = *A_k[i];
454  jac->FillComplete();
455  jac->OptimizeStorage();
456  }
457 }
458 
459 void
464 {
465  int sz = x_sg.size();
466  for (int i=0; i<sz; i++) {
467  x_sg[i].MeanValue(&g_sg[i][0]);
468  g_sg[i][0] *= double(x_sg[i].GlobalLength()) / double(mesh.size());
469  }
470 }
471 
472 template <typename FuncT>
473 void
475 fillMatrices(const FuncT& func, int sz)
476 {
477  int NumMyElements = x_map->NumMyElements();
478  int *MyGlobalElements = x_map->MyGlobalElements();
479  double h2 = h*h;
480  double val;
481 
482  A_k.resize(sz);
483  for (int k=0; k<sz; k++) {
485  for( int i=0 ; i<NumMyElements; ++i ) {
486 
487  // Center
488  int global_idx = MyGlobalElements[i];
489  if (mesh[global_idx].boundary) {
490  if (k == 0)
491  val = 1.0; //Enforce BC in mean matrix
492  else
493  val = 0.0;
494  A_k[k]->ReplaceGlobalValues(global_idx, 1, &val, &global_idx);
495  }
496  else {
497  double a_down =
498  -func(mesh[global_idx].x, mesh[global_idx].y-h/2.0, k)/h2;
499  double a_left =
500  -func(mesh[global_idx].x-h/2.0, mesh[global_idx].y, k)/h2;
501  double a_right =
502  -func(mesh[global_idx].x+h/2.0, mesh[global_idx].y, k)/h2;
503  double a_up =
504  -func(mesh[global_idx].x, mesh[global_idx].y+h/2.0, k)/h2;
505 
506  // Center
507  val = -(a_down + a_left + a_right + a_up);
508  A_k[k]->ReplaceGlobalValues(global_idx, 1, &val, &global_idx);
509 
510  // Down
511  if (!(eliminate_bcs && mesh[mesh[global_idx].down].boundary))
512  A_k[k]->ReplaceGlobalValues(global_idx, 1, &a_down,
513  &mesh[global_idx].down);
514 
515  // Left
516  if (!(eliminate_bcs && mesh[mesh[global_idx].left].boundary))
517  A_k[k]->ReplaceGlobalValues(global_idx, 1, &a_left,
518  &mesh[global_idx].left);
519 
520  // Right
521  if (!(eliminate_bcs && mesh[mesh[global_idx].right].boundary))
522  A_k[k]->ReplaceGlobalValues(global_idx, 1, &a_right,
523  &mesh[global_idx].right);
524 
525  // Up
526  if (!(eliminate_bcs && mesh[mesh[global_idx].up].boundary))
527  A_k[k]->ReplaceGlobalValues(global_idx, 1, &a_up,
528  &mesh[global_idx].up);
529  }
530  }
531  A_k[k]->FillComplete();
532  A_k[k]->OptimizeStorage();
533  }
534 }
535 
536 void
539 {
540  if (basis != Teuchos::null) {
541  for (int i=0; i<point.size(); i++)
542  point[i] = p[i];
543  basis->evaluateBases(point, basis_vals);
544  A->PutScalar(0.0);
545  for (int k=0;k<A_k.size();k++)
546  EpetraExt::MatrixMatrix::Add((*A_k[k]), false, basis_vals[k], *A, 1.0);
547  }
548  else {
549  *A = *(A_k[0]);
550  for (int k=1;k<A_k.size();k++)
551  EpetraExt::MatrixMatrix::Add((*A_k[k]), false, p[k-1], *A, 1.0);
552  }
553  A->FillComplete();
554  A->OptimizeStorage();
555 }
A container class storing an orthogonal polynomial whose coefficients are vectors, operators, or in general any type that would have an expensive copy constructor.
void computeSGJacobian(const Stokhos::EpetraVectorOrthogPoly &x_sg, const Stokhos::EpetraVectorOrthogPoly &p_sg, Stokhos::EpetraOperatorOrthogPoly &J_sg)
Compute Jacobian.
Teuchos::Array< Teuchos::RCP< Epetra_CrsMatrix > > A_k
KL coefficients of operator.
Teuchos::RCP< Epetra_Map > x_map
Solution vector map.
int MyGlobalElements(int *MyGlobalElementList) const
Teuchos::RCP< Epetra_Operator > create_W() const
Create W = alpha*M + beta*J matrix.
KOKKOS_INLINE_FUNCTION PCE< Storage > pow(const PCE< Storage > &a, const PCE< Storage > &b)
Teuchos::RCP< const Epetra_Map > get_g_map(int j) const
Return response function map.
void init(const value_type &val)
Initialize coefficients.
Teuchos::RCP< const Epetra_Map > get_p_map(int l) const
Return parameter vector map.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::RCP< Epetra_CrsMatrix > A
Matrix to store deterministic operator.
void computeResidual(const Epetra_Vector &x, const Epetra_Vector &p, Epetra_Vector &f)
Compute residual.
void computeResponse(const Epetra_Vector &x, const Epetra_Vector &p, Epetra_Vector &g)
Compute response.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Teuchos::RCP< const Epetra_Vector > get_p_init(int l) const
Return initial parameters.
virtual void evaluateBases(const Teuchos::ArrayView< const value_type > &point, Teuchos::Array< value_type > &basis_vals) const =0
Evaluate basis polynomials at given point point.
Teuchos::RCP< LogNormal_Diffusion_Func< KL_Diffusion_Func > > lnFunc
void computeSGResponse(const Stokhos::EpetraVectorOrthogPoly &x_sg, const Stokhos::EpetraVectorOrthogPoly &p_sg, Stokhos::EpetraVectorOrthogPoly &g_sg)
Compute SG response.
Teuchos::RCP< Epetra_Map > g_map
Response vector map.
int InsertGlobalIndices(int_type GlobalRow, int NumIndices, int_type *Indices)
virtual int MyPID() const =0
int FillComplete(bool OptimizeDataStorage=true)
Teuchos::RCP< Epetra_Map > p_map
Parameter vector map.
Teuchos::RCP< const Epetra_Map > get_x_map() const
Return solution vector map.
void computeJacobian(const Epetra_Vector &x, const Epetra_Vector &p, Epetra_Operator &J)
Compute Jacobian.
Teuchos::RCP< Epetra_Vector > p_init
Initial parameters.
Abstract base class for orthogonal polynomial-based expansions.
int NumMyElements() const
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::Array< MeshPoint > mesh
A container class storing an orthogonal polynomial whose coefficients are vectors, operators, or in general any type that would have an expensive copy constructor.
Teuchos::RCP< KL_Diffusion_Func > klFunc
Teuchos::Array< double > basis_vals
Array to store values of basis at a point.
Teuchos::RCP< const Epetra_Vector > get_x_init() const
Return initial solution.
Teuchos::RCP< Epetra_Vector > x_init
Initial guess.
Teuchos::RCP< const Epetra_Map > get_f_map() const
Return residual vector map.
Teuchos::RCP< const Stokhos::OrthogPolyBasis< int, double > > basis
Teuchos::Array< Teuchos::RCP< Epetra_Vector > > sg_kx_vec_all
Vectors to store matrix-vector products in SG residual calculation.
void resize(size_type new_size, const value_type &x=value_type())
twoD_diffusion_problem(const Teuchos::RCP< const Epetra_Comm > &comm, int n, int d, double s=0.1, double mu=0.2, const Teuchos::RCP< const Stokhos::OrthogPolyBasis< int, double > > &basis=Teuchos::null, bool log_normal=false, bool eliminate_bcs=false)
Constructor.
virtual const Teuchos::Array< value_type > & norm_squared() const =0
Return array storing norm-squared of each basis polynomial.
KOKKOS_INLINE_FUNCTION PCE< Storage > exp(const PCE< Storage > &a)
Stokhos::Sparse3Tensor< int, double > Cijk_type
Teuchos::RCP< coeff_type > getCoeffPtr(ordinal_type i)
Return ref-count pointer to coefficient i.
Teuchos::RCP< const Teuchos::Array< std::string > > get_p_names(int l) const
Return array of parameter names.
expr val()
void push_back(const value_type &x)
virtual int NumProc() const =0
ScalarType f(const Teuchos::Array< ScalarType > &x, double a, double b)
Teuchos::Array< double > point
Array to store a point for basis evaluation.
size_type size() const
Class representing a KL expansion of an exponential random field.
Teuchos::RCP< Epetra_Vector > b
Deterministic RHS.
void compute_A(const Epetra_Vector &p)
Compute A matrix.
void fillMatrices(const FuncT &func, int sz)
Fill coefficient matrix given function to evaluate diffusion coefficient.
Teuchos::RCP< Teuchos::Array< std::string > > p_names
Parameter names.
Teuchos::RCP< Epetra_CrsGraph > graph
Jacobian graph.
ordinal_type size() const
Return size.
virtual ordinal_type size() const =0
Return total size of basis.
ScalarType g(const Teuchos::Array< ScalarType > &x, const ScalarType &y)
void computeSGResidual(const Stokhos::EpetraVectorOrthogPoly &x_sg, const Stokhos::EpetraVectorOrthogPoly &p_sg, Stokhos::OrthogPolyExpansion< int, double > &expn, Stokhos::EpetraVectorOrthogPoly &f_sg)
Compute SG residual.
virtual Teuchos::RCP< const Sparse3Tensor< ordinal_type, value_type > > getTripleProduct() const =0
Get triple product.