Thyra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ExampleTridiagSpmdLinearOp.hpp
1 // @HEADER
2 // *****************************************************************************
3 // Thyra: Interfaces and Support for Abstract Numerical Algorithms
4 //
5 // Copyright 2004 NTESS and the Thyra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef THYRA_EXAMPLE_TRIDIAG_SPMD_LINEAR_OP_HPP
11 #define THYRA_EXAMPLE_TRIDIAG_SPMD_LINEAR_OP_HPP
12 
13 #include "Thyra_LinearOpDefaultBase.hpp"
14 #include "Thyra_DefaultSpmdVectorSpace.hpp"
15 #include "Thyra_DetachedSpmdVectorView.hpp"
16 #include "Teuchos_DefaultComm.hpp"
17 #include "Teuchos_CommHelpers.hpp"
18 
19 
106 template<class Scalar>
108 public:
109 
112 
115  const Teuchos::RCP<const Teuchos::Comm<Thyra::Ordinal> > &comm,
116  const Thyra::Ordinal localDim,
120  )
121  { this->initialize(comm, localDim, lower, diag, upper); }
122 
144  void initialize(
145  const Teuchos::RCP<const Teuchos::Comm<Thyra::Ordinal> > &comm,
146  const Thyra::Ordinal localDim,
150  );
151 
152 protected:
153 
154  // Overridden from LinearOpBase
155 
158  { return space_; }
159 
162  { return space_; }
163 
165  bool opSupportedImpl(Thyra::EOpTransp M_trans) const
166  {
167  return (M_trans == Thyra::NOTRANS);
168  }
169 
171  void applyImpl(
172  const Thyra::EOpTransp M_trans,
173  const Thyra::MultiVectorBase<Scalar> &X_in,
175  const Scalar alpha,
176  const Scalar beta
177  ) const;
178 
179 private:
180 
183  Teuchos::Array<Scalar> lower_; // size = ( procRank == 0 ? localDim - 1 : localDim )
184  Teuchos::Array<Scalar> diag_; // size = localDim
185  Teuchos::Array<Scalar> upper_; // size = ( procRank == numProc-1 ? localDim - 1 : localDim )
186 
187  void communicate( const bool first, const bool last,
189  const Teuchos::Ptr<Scalar> &x_km1,
190  const Teuchos::Ptr<Scalar> &x_kp1 ) const;
191 
192 }; // end class ExampleTridiagSpmdLinearOp
193 
194 
195 template<class Scalar>
197  const Teuchos::RCP<const Teuchos::Comm<Thyra::Ordinal> > &comm,
198  const Thyra::Ordinal localDim,
202  )
203 {
204  TEUCHOS_TEST_FOR_EXCEPT( localDim < 2 );
205  comm_ = comm;
206  space_ = Thyra::defaultSpmdVectorSpace<Scalar>(comm, localDim, -1);
207  lower_ = lower;
208  diag_ = diag;
209  upper_ = upper;
210 }
211 
212 
213 template<class Scalar>
215  const Thyra::EOpTransp M_trans,
216  const Thyra::MultiVectorBase<Scalar> &X_in,
218  const Scalar alpha,
219  const Scalar beta
220  ) const
221 {
222 
224  typedef Thyra::Ordinal Ordinal;
225  using Teuchos::outArg;
226 
227  TEUCHOS_ASSERT(this->opSupported(M_trans));
228 
229  // Get constants
230  const Scalar zero = ST::zero();
231  const Ordinal localDim = space_->localSubDim();
232  const Ordinal procRank = comm_->getRank();
233  const Ordinal numProcs = comm_->getSize();
234  const Ordinal m = X_in.domain()->dim();
235 
236  // Loop over the input columns
237 
238  for (Ordinal col_j = 0; col_j < m; ++col_j) {
239 
240  // Get access the the elements of column j
242  Thyra::DetachedSpmdVectorView<Scalar> y_vec(Y_inout->col(col_j));
243  const Teuchos::ArrayRCP<const Scalar> x = x_vec.sv().values();
244  const Teuchos::ArrayRCP<Scalar> y = y_vec.sv().values();
245 
246  // Determine what process we are
247  const bool first = (procRank == 0), last = ( procRank == numProcs-1 );
248 
249  // Communicate ghost elements
250  Scalar x_km1, x_kp1;
251  communicate( first, last, x(), outArg(x_km1), outArg(x_kp1) );
252 
253  // Perform operation (if beta==0 then we must be careful since y could
254  // be uninitialized on input!)
255  Thyra::Ordinal k = 0, lk = 0;
256  if( beta == zero ) {
257  // First local row
258  y[k] = alpha * ( (first?zero:lower_[lk]*x_km1) + diag_[k]*x[k]
259  + upper_[k]*x[k+1] );
260  if(!first) ++lk;
261  // Middle local rows
262  for( k = 1; k < localDim - 1; ++lk, ++k )
263  y[k] = alpha * ( lower_[lk]*x[k-1] + diag_[k]*x[k] + upper_[k]*x[k+1] );
264  // Last local row
265  y[k] = alpha * ( lower_[lk]*x[k-1] + diag_[k]*x[k]
266  + (last?zero:upper_[k]*x_kp1) );
267  }
268  else {
269  // First local row
270  y[k] = alpha * ( (first?zero:lower_[lk]*x_km1) + diag_[k]*x[k]
271  + upper_[k]*x[k+1] ) + beta*y[k];
272  if(!first) ++lk;
273  // Middle local rows
274  for( k = 1; k < localDim - 1; ++lk, ++k )
275  y[k] = alpha * ( lower_[lk]*x[k-1] + diag_[k]*x[k] + upper_[k]*x[k+1] )
276  + beta*y[k];
277  // Last local row
278  y[k] = alpha * ( lower_[lk]*x[k-1] + diag_[k]*x[k]
279  + (last?zero:upper_[k]*x_kp1) ) + beta*y[k];
280  }
281 
282  }
283 
284 }
285 
286 
287 template<class Scalar>
289  const bool first, const bool last,
291  const Teuchos::Ptr<Scalar> &x_km1,
292  const Teuchos::Ptr<Scalar> &x_kp1
293  ) const
294 {
295  typedef Thyra::Ordinal Ordinal;
296  const Ordinal localDim = space_->localSubDim();
297  const Ordinal procRank = comm_->getRank();
298  const Ordinal numProcs = comm_->getSize();
299  const bool isEven = (procRank % 2 == 0);
300  const bool isOdd = !isEven;
301  // 1) Send x[localDim-1] from each even process forward to the next odd
302  // process where it is received in x_km1.
303  if(isEven && procRank+1 < numProcs) send(*comm_, x[localDim-1], procRank+1);
304  if(isOdd && procRank-1 >= 0) receive(*comm_, procRank-1, &*x_km1);
305  // 2) Send x[0] from each odd process backward to the previous even
306  // process where it is received in x_kp1.
307  if( isOdd && procRank-1 >= 0 ) send(*comm_, x[0], procRank-1);
308  if( isEven && procRank+1 < numProcs ) receive(*comm_, procRank+1, &*x_kp1);
309  // 3) Send x[localDim-1] from each odd process forward to the next even
310  // process where it is received in x_km1.
311  if (isOdd && procRank+1 < numProcs) send(*comm_, x[localDim-1], procRank+1);
312  if (isEven && procRank-1 >= 0) receive(*comm_, procRank-1, &*x_km1);
313  // 4) Send x[0] from each even process backward to the previous odd
314  // process where it is received in x_kp1.
315  if (isEven && procRank-1 >= 0) send(*comm_, x[0], procRank-1);
316  if (isOdd && procRank+1 < numProcs) receive(*comm_, procRank+1, &*x_kp1);
317 }
318 
319 
320 #endif // THYRA_EXAMPLE_TRIDIAG_SPMD_LINEAR_OP_HPP
Create an explicit detached mutable (non-const) view of all of the local elements on this process of ...
EOpTransp
Enumeration for determining how a linear operator is applied. `*.
bool opSupportedImpl(Thyra::EOpTransp M_trans) const
ExampleTridiagSpmdLinearOp(const Teuchos::RCP< const Teuchos::Comm< Thyra::Ordinal > > &comm, const Thyra::Ordinal localDim, const Teuchos::ArrayView< const Scalar > &lower, const Teuchos::ArrayView< const Scalar > &diag, const Teuchos::ArrayView< const Scalar > &upper)
Use the non-transposed operator.
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > range() const
Node subclass that provides a good default implementation for the describe() function.
RCP< const LinearOpBase< Scalar > > zero(const RCP< const VectorSpaceBase< Scalar > > &range, const RCP< const VectorSpaceBase< Scalar > > &domain)
Create a zero linear operator with given range and domain spaces.
Teuchos::RCP< const Thyra::VectorSpaceBase< Scalar > > domain() const
Simple example subclass for Spmd tridiagonal matrices.
Teuchos::Ordinal Ordinal
Type for the dimension of a vector space. `*.
Interface for a collection of column vectors called a multi-vector.
bool opSupported(const LinearOpBase< Scalar > &M, EOpTransp M_trans)
Determines if an operation is supported for a single scalar type.
RCP< const VectorBase< Scalar > > col(Ordinal j) const
Calls colImpl().
virtual RCP< const VectorSpaceBase< Scalar > > domain() const =0
Return a smart pointer for the domain space for this operator.
void initialize(const Teuchos::RCP< const Teuchos::Comm< Thyra::Ordinal > > &comm, const Thyra::Ordinal localDim, const Teuchos::ArrayView< const Scalar > &lower, const Teuchos::ArrayView< const Scalar > &diag, const Teuchos::ArrayView< const Scalar > &upper)
Create an explicit detached non-mutable (const) view of all of the local elements on this process of ...
#define TEUCHOS_ASSERT(assertion_test)
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
void applyImpl(const Thyra::EOpTransp M_trans, const Thyra::MultiVectorBase< Scalar > &X_in, const Teuchos::Ptr< Thyra::MultiVectorBase< Scalar > > &Y_inout, const Scalar alpha, const Scalar beta) const