Tempus  Version of the Day
Time Integration
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CDR_Model_impl.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ****************************************************************************
3 // Tempus: Copyright (2017) Sandia Corporation
4 //
5 // Distributed under BSD 3-clause license (See accompanying file Copyright.txt)
6 // ****************************************************************************
7 // @HEADER
8 
9 #ifndef NOX_THYRA_MODEL_EVALUATOR_1DFEM_DEF_HPP
10 #define NOX_THYRA_MODEL_EVALUATOR_1DFEM_DEF_HPP
11 
12 // Thyra support
13 #include "Thyra_DefaultSpmdVectorSpace.hpp"
14 #include "Thyra_DefaultSerialDenseLinearOpWithSolveFactory.hpp"
15 #include "Thyra_DetachedMultiVectorView.hpp"
16 #include "Thyra_DetachedVectorView.hpp"
17 #include "Thyra_MultiVectorStdOps.hpp"
18 #include "Thyra_VectorStdOps.hpp"
19 #include "Thyra_PreconditionerBase.hpp"
20 
21 // Epetra support
23 #include "Thyra_EpetraLinearOp.hpp"
24 #include "Thyra_get_Epetra_Operator.hpp"
25 #include "Epetra_Comm.h"
26 #include "Epetra_Map.h"
27 #include "Epetra_Vector.h"
28 #include "Epetra_Import.h"
29 #include "Epetra_CrsGraph.h"
30 #include "Epetra_CrsMatrix.h"
31 
32 namespace Tempus_Test {
33 
34 // Constructor
35 
36 template <class Scalar>
38  const int num_global_elements, const Scalar z_min,
39  const Scalar z_max, const Scalar a, const Scalar k)
40  : comm_(comm),
41  num_global_elements_(num_global_elements),
42  z_min_(z_min),
43  z_max_(z_max),
44  a_(a),
45  k_(k),
46  showGetInvalidArg_(false)
47 {
48  using Teuchos::RCP;
49  using Teuchos::rcp;
50  using ::Thyra::VectorBase;
51  typedef ::Thyra::ModelEvaluatorBase MEB;
53 
55 
56  const int num_nodes = num_global_elements_ + 1;
57 
58  // owned space
59  x_owned_map_ = rcp(new Epetra_Map(num_nodes, 0, *comm_));
61 
62  // ghosted space
63  if (comm_->NumProc() == 1) {
65  }
66  else {
67  int OverlapNumMyElements;
68  int OverlapMinMyGID;
69  OverlapNumMyElements = x_owned_map_->NumMyElements() + 2;
70  if ((comm_->MyPID() == 0) || (comm_->MyPID() == (comm_->NumProc() - 1)))
71  OverlapNumMyElements--;
72 
73  if (comm_->MyPID() == 0)
74  OverlapMinMyGID = x_owned_map_->MinMyGID();
75  else
76  OverlapMinMyGID = x_owned_map_->MinMyGID() - 1;
77 
78  int* OverlapMyGlobalElements = new int[OverlapNumMyElements];
79 
80  for (int i = 0; i < OverlapNumMyElements; i++)
81  OverlapMyGlobalElements[i] = OverlapMinMyGID + i;
82 
83  x_ghosted_map_ = Teuchos::rcp(new Epetra_Map(
84  -1, OverlapNumMyElements, OverlapMyGlobalElements, 0, *comm_));
85 
86  delete[] OverlapMyGlobalElements;
87  }
88 
89  importer_ = Teuchos::rcp(new Epetra_Import(*x_ghosted_map_, *x_owned_map_));
90 
91  // residual space
94 
95  x0_ = ::Thyra::createMember(x_space_);
96  V_S(x0_.ptr(), ST::zero());
97 
98  // set_p(Teuchos::tuple<Scalar>(p0, p1)());
99  // set_x0(Teuchos::tuple<Scalar>(x0, x1)());
100 
101  // Initialize the graph for W CrsMatrix object
102  W_graph_ = createGraph();
103 
104  // Create the nodal coordinates
105  {
106  node_coordinates_ = Teuchos::rcp(new Epetra_Vector(*x_owned_map_));
107  Scalar length = z_max_ - z_min_;
108  Scalar dx = length / ((double)num_global_elements_ - 1);
109  for (int i = 0; i < x_owned_map_->NumMyElements(); i++) {
110  (*node_coordinates_)[i] =
111  z_min_ + dx * ((double)x_owned_map_->MinMyGID() + i);
112  }
113  }
114 
115  MEB::InArgsSetup<Scalar> inArgs;
116  inArgs.setModelEvalDescription(this->description());
117  inArgs.setSupports(MEB::IN_ARG_t);
118  inArgs.setSupports(MEB::IN_ARG_x);
119  inArgs.setSupports(MEB::IN_ARG_beta);
120  inArgs.setSupports(MEB::IN_ARG_x_dot);
121  inArgs.setSupports(MEB::IN_ARG_alpha);
122  prototypeInArgs_ = inArgs;
123 
124  MEB::OutArgsSetup<Scalar> outArgs;
125  outArgs.setModelEvalDescription(this->description());
126  outArgs.setSupports(MEB::OUT_ARG_f);
127  outArgs.setSupports(MEB::OUT_ARG_W);
128  outArgs.setSupports(MEB::OUT_ARG_W_op);
129  outArgs.setSupports(MEB::OUT_ARG_W_prec);
130  // outArgs.set_W_properties(DerivativeProperties(
131  // DERIV_LINEARITY_NONCONST
132  // ,DERIV_RANK_FULL
133  // ,true // supportsAdjoint
134  // ));
135  prototypeOutArgs_ = outArgs;
136 
137  // Setup nominal values
138  nominalValues_ = inArgs;
139  nominalValues_.set_x(x0_);
140  auto x_dot_init = Thyra::createMember(this->get_x_space());
141  Thyra::put_scalar(Scalar(0.0), x_dot_init.ptr());
142  nominalValues_.set_x_dot(x_dot_init);
143 }
144 
145 // Initializers/Accessors
146 
147 template <class Scalar>
149 {
151 
152  // Create the shell for the
153  W_graph = Teuchos::rcp(new Epetra_CrsGraph(Copy, *x_owned_map_, 5));
154 
155  // Declare required variables
156  int row;
157  int column;
158  int OverlapNumMyElements = x_ghosted_map_->NumMyElements();
159 
160  // Loop Over # of Finite Elements on Processor
161  for (int ne = 0; ne < OverlapNumMyElements - 1; ne++) {
162  // Loop over Nodes in Element
163  for (int i = 0; i < 2; i++) {
164  row = x_ghosted_map_->GID(ne + i);
165 
166  // Loop over Trial Functions
167  for (int j = 0; j < 2; j++) {
168  // If this row is owned by current processor, add the index
169  if (x_owned_map_->MyGID(row)) {
170  column = x_ghosted_map_->GID(ne + j);
171  W_graph->InsertGlobalIndices(row, 1, &column);
172  }
173  }
174  }
175  }
176  W_graph->FillComplete();
177  return W_graph;
178 }
179 
180 template <class Scalar>
182 {
183 #ifdef TEUCHOS_DEBUG
184  TEUCHOS_ASSERT_EQUALITY(x_space_->dim(), x0_in.size());
185 #endif
187  x0.sv().values()().assign(x0_in);
188 }
189 
190 template <class Scalar>
191 void CDR_Model<Scalar>::setShowGetInvalidArgs(bool showGetInvalidArg)
192 {
193  showGetInvalidArg_ = showGetInvalidArg;
194 }
195 
196 template <class Scalar>
198  const Teuchos::RCP<const ::Thyra::LinearOpWithSolveFactoryBase<Scalar> >&
199  W_factory)
200 {
201  W_factory_ = W_factory;
202 }
203 
204 // Public functions overridden from ModelEvaluator
205 
206 template <class Scalar>
209 {
210  return x_space_;
211 }
212 
213 template <class Scalar>
216 {
217  return f_space_;
218 }
219 
220 template <class Scalar>
222  const
223 {
224  return nominalValues_;
225 }
226 
227 template <class Scalar>
230 {
232  this->get_W_factory();
233 
234  TEUCHOS_TEST_FOR_EXCEPTION(is_null(W_factory), std::runtime_error,
235  "W_factory in CDR_Model has a null W_factory!");
236 
237  Teuchos::RCP<Thyra::LinearOpBase<double> > matrix = this->create_W_op();
238 
240  Thyra::linearOpWithSolve<double>(*W_factory, matrix);
241 
242  return W;
243 }
244 
245 template <class Scalar>
247  const
248 {
250  Teuchos::rcp(new Epetra_CrsMatrix(::Copy, *W_graph_));
251 
252  return Thyra::nonconstEpetraLinearOp(W_epetra);
253 }
254 
255 template <class Scalar>
258 {
260  Teuchos::rcp(new Epetra_CrsMatrix(::Copy, *W_graph_));
261 
263  Thyra::nonconstEpetraLinearOp(W_epetra);
264 
267 
268  prec->initializeRight(W_op);
269 
270  return prec;
271 }
272 
273 template <class Scalar>
276 {
277  return W_factory_;
278 }
279 
280 template <class Scalar>
282  const
283 {
284  return prototypeInArgs_;
285 }
286 
287 // Private functions overridden from ModelEvaluatorDefaultBase
288 
289 template <class Scalar>
292 {
293  return prototypeOutArgs_;
294 }
295 
296 template <class Scalar>
299  const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs) const
300 {
301  using Teuchos::RCP;
302  using Teuchos::rcp;
303  using Teuchos::rcp_dynamic_cast;
304 
305  TEUCHOS_ASSERT(nonnull(inArgs.get_x()));
306  TEUCHOS_ASSERT(nonnull(inArgs.get_x_dot()));
307 
308  // const Thyra::ConstDetachedVectorView<Scalar> x(inArgs.get_x());
309 
310  const RCP<Thyra::VectorBase<Scalar> > f_out = outArgs.get_f();
311  const RCP<Thyra::LinearOpBase<Scalar> > W_out = outArgs.get_W_op();
312  const RCP<Thyra::PreconditionerBase<Scalar> > W_prec_out =
313  outArgs.get_W_prec();
314 
315  if (nonnull(f_out) || nonnull(W_out) || nonnull(W_prec_out)) {
316  // ****************
317  // Get the underlying epetra objects
318  // ****************
319 
321  if (nonnull(f_out)) {
322  f = Thyra::get_Epetra_Vector(*f_owned_map_, outArgs.get_f());
323  }
324 
326  if (nonnull(W_out)) {
328  J = rcp_dynamic_cast<Epetra_CrsMatrix>(W_epetra);
330  }
331 
332  RCP<Epetra_CrsMatrix> M_inv;
333  if (nonnull(W_prec_out)) {
334  RCP<Epetra_Operator> M_epetra =
335  Thyra::get_Epetra_Operator(*(W_prec_out->getNonconstRightPrecOp()));
336  M_inv = rcp_dynamic_cast<Epetra_CrsMatrix>(M_epetra);
337  TEUCHOS_ASSERT(nonnull(M_inv));
338  J_diagonal_ = Teuchos::rcp(new Epetra_Vector(*x_owned_map_));
339  }
340 
341  // ****************
342  // Create ghosted objects
343  // ****************
344 
345  // Set the boundary condition directly. Works for both x and xDot solves.
346  if (comm_->MyPID() == 0) {
348  Teuchos::rcp_const_cast<Thyra::VectorBase<Scalar> >(inArgs.get_x());
349  (*Thyra::get_Epetra_Vector(*x_owned_map_, x))[0] = 1.0;
350  }
351 
352  if (is_null(u_ptr))
353  u_ptr = Teuchos::rcp(new Epetra_Vector(*x_ghosted_map_));
354 
355  u_ptr->Import(*(Thyra::get_Epetra_Vector(*x_owned_map_, inArgs.get_x())),
356  *importer_, Insert);
357 
358  if (is_null(u_dot_ptr))
359  u_dot_ptr = Teuchos::rcp(new Epetra_Vector(*x_ghosted_map_));
360 
361  u_dot_ptr->Import(
362  *(Thyra::get_Epetra_Vector(*x_owned_map_, inArgs.get_x_dot())),
363  *importer_, Insert);
364 
365  if (is_null(x_ptr)) {
366  x_ptr = Teuchos::rcp(new Epetra_Vector(*x_ghosted_map_));
367  x_ptr->Import(*node_coordinates_, *importer_, Insert);
368  }
369 
370  Epetra_Vector& u = *u_ptr;
371  Epetra_Vector& u_dot = *u_dot_ptr;
372  Epetra_Vector& x = *x_ptr;
373 
374  int ierr = 0;
375  int OverlapNumMyElements = x_ghosted_map_->NumMyElements();
376 
377  double xx[2];
378  double uu[2];
379  double uu_dot[2];
380  Basis basis;
381  const auto alpha = inArgs.get_alpha();
382  const auto beta = inArgs.get_beta();
383 
384  // Zero out the objects that will be filled
385  if (nonnull(f)) f->PutScalar(0.0);
386  if (nonnull(J)) J->PutScalar(0.0);
387  if (nonnull(M_inv)) M_inv->PutScalar(0.0);
388 
389  // Loop Over # of Finite Elements on Processor
390  for (int ne = 0; ne < OverlapNumMyElements - 1; ne++) {
391  // Loop Over Gauss Points
392  for (int gp = 0; gp < 2; gp++) {
393  // Get the solution and coordinates at the nodes
394  xx[0] = x[ne];
395  xx[1] = x[ne + 1];
396  uu[0] = u[ne];
397  uu[1] = u[ne + 1];
398  uu_dot[0] = u_dot[ne];
399  uu_dot[1] = u_dot[ne + 1];
400  // Calculate the basis function at the gauss point
401  basis.computeBasis(gp, xx, uu, uu_dot);
402 
403  // Loop over Nodes in Element
404  for (int i = 0; i < 2; i++) {
405  int row = x_ghosted_map_->GID(ne + i);
406  // printf("Proc=%d GlobalRow=%d LocalRow=%d Owned=%d\n",
407  // MyPID, row, ne+i,x_owned_map_.MyGID(row));
408  if (x_owned_map_->MyGID(row)) {
409  if (nonnull(f)) {
410  (*f)[x_owned_map_->LID(x_ghosted_map_->GID(ne + i))] +=
411  +basis.wt * basis.dz *
412  (basis.uu_dot * basis.phi[i] // transient
413  + (a_ / basis.dz * basis.duu * basis.phi[i] // convection
414  + 1.0 / (basis.dz * basis.dz)) *
415  basis.duu * basis.dphide[i] // diffusion
416  + k_ * basis.uu * basis.uu * basis.phi[i]); // source
417  }
418  }
419  // Loop over Trial Functions
420  if (nonnull(J)) {
421  for (int j = 0; j < 2; j++) {
422  if (x_owned_map_->MyGID(row)) {
423  int column = x_ghosted_map_->GID(ne + j);
424  double jac = basis.wt * basis.dz *
425  (alpha * basis.phi[i] * basis.phi[j] // transient
426  + beta * (+a_ / basis.dz * basis.dphide[j] *
427  basis.phi[i] // convection
428  + (1.0 / (basis.dz * basis.dz)) *
429  basis.dphide[j] *
430  basis.dphide[i] // diffusion
431  + 2.0 * k_ * basis.uu * basis.phi[j] *
432  basis.phi[i] // source
433  ));
434  ierr = J->SumIntoGlobalValues(row, 1, &jac, &column);
435  }
436  }
437  }
438  if (nonnull(M_inv)) {
439  for (int j = 0; j < 2; j++) {
440  if (x_owned_map_->MyGID(row)) {
441  int column = x_ghosted_map_->GID(ne + j);
442  // The prec will be the diagonal of J. No need to assemble the
443  // other entries
444  if (row == column) {
445  double jac =
446  basis.wt * basis.dz *
447  (alpha * basis.phi[i] * basis.phi[j] // transient
448  + beta * (+a_ / basis.dz * basis.dphide[j] *
449  basis.phi[i] // convection
450  + (1.0 / (basis.dz * basis.dz)) *
451  basis.dphide[j] *
452  basis.dphide[i] // diffusion
453  + 2.0 * k_ * basis.uu * basis.phi[j] *
454  basis.phi[i] // source
455  ));
456  ierr = M_inv->SumIntoGlobalValues(row, 1, &jac, &column);
457  }
458  }
459  }
460  }
461  }
462  }
463  }
464 
465  // Insert Boundary Conditions and modify Jacobian and function (F)
466  // U(0)=1
467  if (comm_->MyPID() == 0) {
468  if (nonnull(f))
469  (*f)[0] = 0.0; // Setting BC above and zero residual here works for x
470  // and xDot solves.
471  //(*f)[0]= u[0] - 1.0; // BC equation works for x solves.
472  if (nonnull(J)) {
473  int column = 0;
474  double jac = 1.0;
475  ierr = J->ReplaceGlobalValues(0, 1, &jac, &column);
476  column = 1;
477  jac = 0.0;
478  ierr = J->ReplaceGlobalValues(0, 1, &jac, &column);
479  }
480  if (nonnull(M_inv)) {
481  int column = 0;
482  double jac = 1.0;
483  ierr = M_inv->ReplaceGlobalValues(0, 1, &jac, &column);
484  column = 1;
485  jac = 0.0;
486  ierr = M_inv->ReplaceGlobalValues(0, 1, &jac, &column);
487  }
488  }
489 
490  if (nonnull(J)) J->FillComplete();
491 
492  if (nonnull(M_inv)) {
493  // invert the Jacobian diagonal for the preconditioner
494  M_inv->ExtractDiagonalCopy(*J_diagonal_);
495 
496  for (int i = 0; i < J_diagonal_->MyLength(); ++i)
497  (*J_diagonal_)[i] = 1.0 / ((*J_diagonal_)[i]);
498 
499  M_inv->PutScalar(0.0);
500  M_inv->ReplaceDiagonalValues(*J_diagonal_);
501  M_inv->FillComplete();
502  }
503 
504  TEUCHOS_ASSERT(ierr > -1);
505  }
506 }
507 
508 //====================================================================
509 // Basis vector
510 
511 // Constructor
513  : uu(0.0),
514  zz(0.0),
515  duu(0.0),
516  eta(0.0),
517  wt(0.0),
518  dz(0.0),
519  uu_dot(0.0),
520  duu_dot(0.0)
521 {
522  phi = new double[2];
523  dphide = new double[2];
524 }
525 
526 // Destructor
528 {
529  delete[] phi;
530  delete[] dphide;
531 }
532 
533 // Calculates a linear 1D basis
534 void Basis::computeBasis(int gp, double* z, double* u, double* u_dot)
535 {
536  int N = 2;
537  if (gp == 0) {
538  eta = -1.0 / sqrt(3.0);
539  wt = 1.0;
540  }
541  if (gp == 1) {
542  eta = 1.0 / sqrt(3.0);
543  wt = 1.0;
544  }
545 
546  // Calculate basis function and derivatives at nodel pts
547  phi[0] = (1.0 - eta) / 2.0;
548  phi[1] = (1.0 + eta) / 2.0;
549  dphide[0] = -0.5;
550  dphide[1] = 0.5;
551 
552  // Caculate basis function and derivative at GP.
553  dz = 0.5 * (z[1] - z[0]);
554  zz = 0.0;
555  uu = 0.0;
556  duu = 0.0;
557  uu_dot = 0.0;
558  duu_dot = 0.0;
559  for (int i = 0; i < N; i++) {
560  zz += z[i] * phi[i];
561  uu += u[i] * phi[i];
562  duu += u[i] * dphide[i];
563  if (u_dot) {
564  uu_dot += u_dot[i] * phi[i];
565  duu_dot += u_dot[i] * dphide[i];
566  }
567  }
568 
569  return;
570 }
571 
572 } // namespace Tempus_Test
573 
574 #endif
::Thyra::ModelEvaluatorBase::InArgs< Scalar > createInArgs() const
void evalModelImpl(const ::Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs, const ::Thyra::ModelEvaluatorBase::OutArgs< Scalar > &outArgs) const
Teuchos::RCP< const Epetra_Map > x_ghosted_map_
bool is_null(const boost::shared_ptr< T > &p)
Teuchos::RCP< const ::Thyra::LinearOpWithSolveFactoryBase< Scalar > > get_W_factory() const
CDR_Model(const Teuchos::RCP< const Epetra_Comm > &comm, const int num_global_elements, const Scalar z_min, const Scalar z_max, const Scalar a, const Scalar k)
::Thyra::ModelEvaluatorBase::OutArgs< Scalar > prototypeOutArgs_
virtual Teuchos::RCP< Epetra_CrsGraph > createGraph()
RCP< const VectorBase< Scalar > > get_x_dot() const
RCP< const VectorSpaceBase< double > > create_VectorSpace(const RCP< const Epetra_Map > &epetra_map)
Teuchos::RCP< Epetra_CrsGraph > W_graph_
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::RCP< Epetra_Vector > node_coordinates_
Teuchos::RCP< const Epetra_Map > f_owned_map_
size_type size() const
Evaluation< VectorBase< Scalar > > get_f() const
Teuchos::RCP< ::Thyra::VectorBase< Scalar > > x0_
Teuchos::RCP< ::Thyra::PreconditionerBase< Scalar > > create_W_prec() const
void setShowGetInvalidArgs(bool showGetInvalidArg)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< const Epetra_Map > x_owned_map_
Ptr< T > ptr() const
::Thyra::ModelEvaluatorBase::InArgs< Scalar > nominalValues_
void set_W_factory(const Teuchos::RCP< const ::Thyra::LinearOpWithSolveFactoryBase< Scalar > > &W_factory)
void set_x0(const Teuchos::ArrayView< const Scalar > &x0)
RCP< Epetra_Vector > get_Epetra_Vector(const Epetra_Map &map, const RCP< VectorBase< double > > &v)
virtual std::string description() const
void computeBasis(int gp, double *z, double *u, double *u_dot=nullptr)
Teuchos::RCP< const ::Thyra::VectorSpaceBase< Scalar > > x_space_
Teuchos::RCP< ::Thyra::LinearOpBase< Scalar > > create_W_op() const
Teuchos::RCP< Thyra::LinearOpWithSolveBase< double > > create_W() const
::Thyra::ModelEvaluatorBase::OutArgs< Scalar > createOutArgsImpl() const
bool nonnull(const boost::shared_ptr< T > &p)
Teuchos::RCP< const ::Thyra::VectorSpaceBase< Scalar > > get_f_space() const
Teuchos::RCP< Epetra_Operator > get_Epetra_Operator(LinearOpBase< Scalar > &)
::Thyra::ModelEvaluatorBase::InArgs< Scalar > prototypeInArgs_
RCP< PreconditionerBase< Scalar > > get_W_prec() const
Teuchos::RCP< const ::Thyra::VectorSpaceBase< Scalar > > get_x_space() const
#define TEUCHOS_ASSERT(assertion_test)
#define TEUCHOS_ASSERT_EQUALITY(val1, val2)
const Teuchos::RCP< const Epetra_Comm > comm_
Teuchos::RCP< const ::Thyra::VectorSpaceBase< Scalar > > f_space_
RCP< LinearOpBase< Scalar > > get_W_op() const
RCP< const VectorBase< Scalar > > get_x() const
::Thyra::ModelEvaluatorBase::InArgs< Scalar > getNominalValues() const
Teuchos::RCP< const Epetra_Import > importer_