Thyra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
exampleImplicitlyComposedLinearOperators.cpp
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 // Bring in all of the operator/vector ANA client support software
11 #include "Thyra_OperatorVectorClientSupport.hpp"
12 
13 // Just use a default SPMD space for this example
14 #include "Thyra_DefaultSpmdVectorSpace.hpp"
15 
16 // Some utilities from Teuchos
17 #include "Teuchos_CommandLineProcessor.hpp"
18 #include "Teuchos_VerboseObject.hpp"
19 #include "Teuchos_VerbosityLevelCommandLineProcessorHelpers.hpp"
20 #include "Teuchos_Time.hpp"
21 #include "Teuchos_StandardCatchMacros.hpp"
22 #include "Teuchos_as.hpp"
23 #include "Teuchos_GlobalMPISession.hpp"
24 
25 
68 template<class Scalar>
69 int exampleImplicitlyComposedLinearOperators(
70  const int n0,
71  const int n1,
72  const int n2,
74  const Teuchos::EVerbosityLevel verbLevel,
76  const bool testAdjoint
77  )
78 {
79 
80  // Using and other declarations
82  using Teuchos::as;
83  using Teuchos::RCP;
84  using Teuchos::OSTab;
86  using Thyra::VectorBase;
88  using Thyra::LinearOpBase;
89  using Thyra::defaultSpmdVectorSpace;
90  using Thyra::randomize;
91  using Thyra::identity;
92  using Thyra::diagonal;
93  using Thyra::multiply;
94  using Thyra::add;
95  using Thyra::subtract;
96  using Thyra::scale;
97  using Thyra::adjoint;
98  using Thyra::block1x2;
99  using Thyra::block2x2;
100  using Thyra::block2x2;
101 
102  out << "\n***"
103  << "\n*** Demonstrating building linear operators for scalar type "
104  << ST::name()
105  << "\n***\n";
106 
107  OSTab tab(out);
108 
109  //
110  // A) Set up the basic objects and other inputs to build the implicitly
111  // composed linear operators.
112  //
113 
114  // Create serial vector spaces in this case
115  const RCP<const VectorSpaceBase<Scalar> >
116  space0 = defaultSpmdVectorSpace<Scalar>(n0),
117  space1 = defaultSpmdVectorSpace<Scalar>(n1),
118  space2 = defaultSpmdVectorSpace<Scalar>(n2);
119 
120  // Create the component linear operators first as multi-vectors
121  const RCP<MultiVectorBase<Scalar> >
122  mvA = createMembers(space2, n0, "A"),
123  mvB = createMembers(space0, n2, "B"),
124  mvC = createMembers(space0, n0, "C"),
125  mvE = createMembers(space0, n1, "E"),
126  mvF = createMembers(space0, n1, "F"),
127  mvJ = createMembers(space2, n1, "J"),
128  mvK = createMembers(space1, n2, "K"),
129  mvL = createMembers(space2, n1, "L"),
130  mvN = createMembers(space0, n1, "N"),
131  mvP = createMembers(space2, n1, "P"),
132  mvQ = createMembers(space0, n2, "Q");
133 
134  // Create the vector diagonal for D
135  const RCP<VectorBase<Scalar> > d = createMember(space2);
136 
137  // Get the constants
138  const Scalar
139  one = 1.0,
140  beta = 2.0,
141  gamma = 3.0,
142  eta = 4.0;
143 
144  // Randomize the values in the Multi-Vector
145  randomize( -one, +one, mvA.ptr() );
146  randomize( -one, +one, mvB.ptr() );
147  randomize( -one, +one, mvC.ptr() );
148  randomize( -one, +one, d.ptr() );
149  randomize( -one, +one, mvE.ptr() );
150  randomize( -one, +one, mvF.ptr() );
151  randomize( -one, +one, mvJ.ptr() );
152  randomize( -one, +one, mvK.ptr() );
153  randomize( -one, +one, mvL.ptr() );
154  randomize( -one, +one, mvN.ptr() );
155  randomize( -one, +one, mvP.ptr() );
156  randomize( -one, +one, mvQ.ptr() );
157 
158  // Get the linear operator forms of the basic component linear operators
159  const RCP<const LinearOpBase<Scalar> >
160  A = mvA,
161  B = mvB,
162  C = mvC,
163  E = mvE,
164  F = mvF,
165  J = mvJ,
166  K = mvK,
167  L = mvL,
168  N = mvN,
169  P = mvP,
170  Q = mvQ;
171 
172  out << describe(*A, verbLevel);
173  out << describe(*B, verbLevel);
174  out << describe(*C, verbLevel);
175  out << describe(*E, verbLevel);
176  out << describe(*F, verbLevel);
177  out << describe(*J, verbLevel);
178  out << describe(*K, verbLevel);
179  out << describe(*L, verbLevel);
180  out << describe(*N, verbLevel);
181  out << describe(*P, verbLevel);
182  out << describe(*Q, verbLevel);
183 
184  //
185  // B) Create the composed linear operators
186  //
187 
188  // I
189  const RCP<const LinearOpBase<Scalar> > I = identity(space1, "I");
190 
191  // D = diag(d)
192  const RCP<const LinearOpBase<Scalar> > D = diagonal(d, "D");
193 
194  // M00 = [ gama*B*A + C, E + F ] ^H
195  // [ J^H * A, I ]
196  const RCP<const LinearOpBase<Scalar> > M00 =
197  adjoint(
198  block2x2(
199  add( scale(gamma,multiply(B,A)), C ), add( E, F ),
200  multiply(adjoint(J),A), I
201  ),
202  "M00"
203  );
204 
205  out << "\nM00 = " << describe(*M00, verbLevel);
206 
207  // M01 = beta * [ Q ]
208  // [ K ]
209  const RCP<const LinearOpBase<Scalar> > M01 =
210  scale(
211  beta,
212  block2x1( Q, K ),
213  "M01"
214  );
215 
216  out << "\nM01 = " << describe(*M01, verbLevel);
217 
218  // M10 = [ L * N^H, eta*P ]
219  const RCP<const LinearOpBase<Scalar> > M10 =
220  block1x2(
221  multiply(L,adjoint(N)), scale(eta,P),
222  "M10"
223  );
224 
225  out << "\nM10 = " << describe(*M10, verbLevel);
226 
227  // M11 = D - Q^H*Q
228  const RCP<const LinearOpBase<Scalar> > M11 =
229  subtract( D, multiply(adjoint(Q),Q), "M11" );
230 
231  out << "\nM11 = " << describe(*M11, verbLevel);
232 
233 
234  // M = [ M00, M01 ]
235  // [ M10, M11 ]
236  const RCP<const LinearOpBase<Scalar> > M =
237  block2x2(
238  M00, M01,
239  M10, M11,
240  "M"
241  );
242 
243  out << "\nM = " << describe(*M, verbLevel);
244 
245 
246  //
247  // C) Test the final composed operator
248  //
249 
250  Thyra::LinearOpTester<Scalar> linearOpTester;
251  linearOpTester.set_all_error_tol(errorTol);
252  linearOpTester.check_adjoint(testAdjoint);
253  if (as<int>(verbLevel) >= as<int>(Teuchos::VERB_HIGH))
254  linearOpTester.show_all_tests(true);
255  if (as<int>(verbLevel) >= as<int>(Teuchos::VERB_EXTREME))
256  linearOpTester.dump_all(true);
257 
258  const bool result = linearOpTester.check(*M, Teuchos::inOutArg(out));
259 
260  return result;
261 
262 }
263 
264 
265 //
266 // Main driver program
267 //
268 int main( int argc, char *argv[] )
269 {
270 
272 
273  bool success = true;
274  bool result;
275 
276  Teuchos::GlobalMPISession mpiSession(&argc,&argv);
277  // Above is needed to run in an MPI build with some MPI implementations
278 
281 
282  try {
283 
284  //
285  // Read in command-line options
286  //
287 
288  CommandLineProcessor clp;
289  clp.throwExceptions(false);
290  clp.addOutputSetupOptions(true);
291 
292  int n0 = 2;
293  clp.setOption( "n0", &n0 );
294 
295  int n1 = 3;
296  clp.setOption( "n1", &n1 );
297 
298  int n2 = 4;
299  clp.setOption( "n2", &n2 );
300 
302  setVerbosityLevelOption( "verb-level", &verbLevel,
303  "Top-level verbosity level. By default, this gets deincremented as you go deeper into numerical objects.",
304  &clp );
305 
306  CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
307  if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;
308 
309 #if defined(HAVE_TEUCHOS_INST_FLOAT)
310  // Run using float
311  result = exampleImplicitlyComposedLinearOperators<float>(
312  n0, n1, n2, *out, verbLevel, 1e-5, true );
313  if (!result) success = false;
314 #endif
315 
316  // Run using double
317  result = exampleImplicitlyComposedLinearOperators<double>(
318  n0, n1, n2, *out, verbLevel, 1e-12, true );
319  if (!result) success = false;
320 
321 #if defined(HAVE_TEUCHOS_INST_COMPLEX_FLOAT) && defined(HAVE_TEUCHOS_INST_FLOAT)
322  // Run using std::complex<float>
323  result = exampleImplicitlyComposedLinearOperators<std::complex<float> >(
324  n0, n1, n2, *out, verbLevel, 1e-5, false );
325  if (!result) success = false;
326  // 2007/11/02: rabartl: Above, I skip the test of the adjoint since it
327  // fails but a lot. On my machine, the relative error is:
328  // rel_err((-3.00939,-0.836347),(-0.275689,1.45244)) = 1.14148.
329  // Since this works just fine for the next complex<double> case, I am
330  // going to just skip this test.
331 #endif
332 
333 #if defined(HAVE_TEUCHOS_INST_COMPLEX_DOUBLE)
334  // Run using std::complex<double>
335  result = exampleImplicitlyComposedLinearOperators<std::complex<double> >(
336  n0, n1, n2, *out, verbLevel, 1e-12, true );
337  if (!result) success = false;
338 #endif
339 
340 #ifdef HAVE_TEUCHOS_GNU_MP
341 
342  // Run using mpf_class
343  result = exampleImplicitlyComposedLinearOperators<mpf_class>(
344  n0, n1, n2, *out, verbLevel, 1e-20, true );
345  if (!result) success = false;
346 
347 #endif // HAVE_TEUCHOS_GNU_MP
348 
349  }
350  TEUCHOS_STANDARD_CATCH_STATEMENTS(true,*out,success)
351 
352  if(success)
353  *out << "\nCongratulations! All of the tests checked out!\n";
354  else
355  *out << "\nOh no! At least one of the tests failed!\n";
356 
357  return success ? 0 : 1;
358 
359 } // end main()
Testing class for LinearOpBase.
basic_OSTab< char > OSTab
RCP< const LinearOpBase< Scalar > > diagonal(const RCP< VectorBase< Scalar > > &diag, const std::string &label="")
Nonmember constructor function.
Teuchos::RCP< const LinearOpBase< Scalar > > block2x1(const Teuchos::RCP< const LinearOpBase< Scalar > > &A00, const Teuchos::RCP< const LinearOpBase< Scalar > > &A10, const std::string &label="")
Form an implicit block 2x1 linear operator [ A00; A10 ].
Abstract interface for objects that represent a space for vectors.
RCP< const LinearOpBase< Scalar > > scale(const Scalar &scalar, const RCP< const LinearOpBase< Scalar > > &Op, const std::string &label="")
Build an implicit const scaled linear operator.
Teuchos::RCP< const LinearOpBase< Scalar > > block1x2(const Teuchos::RCP< const LinearOpBase< Scalar > > &A00, const Teuchos::RCP< const LinearOpBase< Scalar > > &A01, const std::string &label="")
Form an implicit block 1x2 linear operator [ A00, A01 ].
RCP< const LinearOpBase< Scalar > > add(const RCP< const LinearOpBase< Scalar > > &A, const RCP< const LinearOpBase< Scalar > > &B, const std::string &label="")
Form an implicit addition of two linear operators: M = A + B.
Interface for a collection of column vectors called a multi-vector.
static RCP< FancyOStream > getDefaultOStream()
RCP< VectorBase< Scalar > > createMember(const RCP< const VectorSpaceBase< Scalar > > &vs, const std::string &label="")
Create a vector member from the vector space.
RCP< const LinearOpBase< Scalar > > subtract(const RCP< const LinearOpBase< Scalar > > &A, const RCP< const LinearOpBase< Scalar > > &B, const std::string &label="")
Form an implicit subtraction of two linear operators: M = A - B.
Abstract interface for finite-dimensional dense vectors.
Base class for all linear operators.
RCP< const LinearOpBase< Scalar > > adjoint(const RCP< const LinearOpBase< Scalar > > &Op, const std::string &label="")
Build an implicit const adjoined linear operator.
void randomize(Scalar l, Scalar u, const Ptr< MultiVectorBase< Scalar > > &V)
Generate a random multi-vector with elements uniformly distributed elements.
Teuchos::RCP< const LinearOpBase< Scalar > > block2x2(const Teuchos::RCP< const LinearOpBase< Scalar > > &A00, const Teuchos::RCP< const LinearOpBase< Scalar > > &A01, const Teuchos::RCP< const LinearOpBase< Scalar > > &A10, const Teuchos::RCP< const LinearOpBase< Scalar > > &A11, const std::string &label="")
Form an implicit block 2x2 linear operator [ A00, A01; A10, A11 ].
bool check(const LinearOpBase< Scalar > &op, const Ptr< MultiVectorRandomizerBase< Scalar > > &rangeRandomizer, const Ptr< MultiVectorRandomizerBase< Scalar > > &domainRandomizer, const Ptr< FancyOStream > &out) const
Check a linear operator.
RCP< const LinearOpBase< Scalar > > identity(const RCP< const VectorSpaceBase< Scalar > > &space, const std::string &label="")
Create an identity linear operator with given a vector space.
TypeTo as(const TypeFrom &t)
#define TEUCHOS_STANDARD_CATCH_STATEMENTS(VERBOSE, ERR_STREAM, SUCCESS_FLAG)
RCP< MultiVectorBase< Scalar > > createMembers(const RCP< const VectorSpaceBase< Scalar > > &vs, int numMembers, const std::string &label="")
Create a set of vector members (a MultiVectorBase) from the vector space.
void set_all_error_tol(const ScalarMag error_tol)
Set all the error tolerances to the same value.
RCP< const LinearOpBase< Scalar > > multiply(const RCP< const LinearOpBase< Scalar > > &A, const RCP< const LinearOpBase< Scalar > > &B, const std::string &M_label="")
Form an implicit multiplication of two linear operators: M = A.