|
Stratimikos Package Browser (Single Doxygen Collection)
Version of the Day
|
00001 00002 // @HEADER 00003 // *********************************************************************** 00004 // 00005 // Stratimikos: Thyra-based strategies for linear solvers 00006 // Copyright (2006) Sandia Corporation 00007 // 00008 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00009 // license for use of this work by or on behalf of the U.S. Government. 00010 // 00011 // Redistribution and use in source and binary forms, with or without 00012 // modification, are permitted provided that the following conditions are 00013 // met: 00014 // 00015 // 1. Redistributions of source code must retain the above copyright 00016 // notice, this list of conditions and the following disclaimer. 00017 // 00018 // 2. Redistributions in binary form must reproduce the above copyright 00019 // notice, this list of conditions and the following disclaimer in the 00020 // documentation and/or other materials provided with the distribution. 00021 // 00022 // 3. Neither the name of the Corporation nor the names of the 00023 // contributors may be used to endorse or promote products derived from 00024 // this software without specific prior written permission. 00025 // 00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00037 // 00038 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 00039 // 00040 // *********************************************************************** 00041 // @HEADER 00042 // 00043 // This driver creates a 2D Laplacian operator as a Tpetra::CisMatrix. 00044 // This matrix is then converted into a Thyra linear operator 00045 // through the Thyra-Tpetra adapters. 00046 // 00047 // The right-hand sides are all random vectors. 00048 // The initial guesses are all set to zero. 00049 // 00050 // 00051 00052 // Thyra includes 00053 #include "Thyra_BelosLinearOpWithSolveFactory.hpp" 00054 #include "Thyra_LinearOpWithSolveFactoryHelpers.hpp" 00055 #include "Thyra_TpetraLinearOp.hpp" 00056 00057 // Tpetra includes 00058 #include "Tpetra_ElementSpace.hpp" 00059 #include "Tpetra_VectorSpace.hpp" 00060 #include "Tpetra_CisMatrix.hpp" 00061 00062 // Teuchos includes 00063 #include "Teuchos_ParameterList.hpp" 00064 #include "Teuchos_VerboseObject.hpp" 00065 #include "Teuchos_GlobalMPISession.hpp" 00066 00067 #ifdef HAVE_MPI 00068 # include "Tpetra_MpiPlatform.hpp" 00069 #else 00070 # include "Tpetra_SerialPlatform.hpp" 00071 #endif 00072 00073 int main(int argc, char* argv[]) 00074 { 00075 // 00076 // Get a default output stream from the Teuchos::VerboseObjectBase 00077 // 00078 Teuchos::RCP<Teuchos::FancyOStream> 00079 out = Teuchos::VerboseObjectBase::getDefaultOStream(); 00080 00081 Teuchos::GlobalMPISession mpiSession(&argc,&argv); 00082 00083 // -------------------------------------------------------------------------------- 00084 // 00085 // Create the scalar-type typedefs 00086 // 00087 // -------------------------------------------------------------------------------- 00088 00089 #ifdef HAVE_COMPLEX 00090 typedef std::complex<double> ST; 00091 #elif HAVE_COMPLEX_H 00092 typedef std::complex<double> ST; 00093 #else 00094 typedef double ST; 00095 #endif 00096 typedef Teuchos::ScalarTraits<ST>::magnitudeType MT; 00097 typedef int OT; 00098 00099 // -------------------------------------------------------------------------------- 00100 // 00101 // Create 2D Laplacian using Tpetra::CisMatrix 00102 // 00103 // -------------------------------------------------------------------------------- 00104 00105 #ifdef HAVE_MPI 00106 MPI_Comm mpiComm = MPI_COMM_WORLD; 00107 const Tpetra::MpiPlatform<OT,OT> ordinalPlatform(mpiComm); 00108 const Tpetra::MpiPlatform<OT,ST> scalarPlatform(mpiComm); 00109 #else 00110 const Tpetra::SerialPlatform<OT,OT> ordinalPlatform; 00111 const Tpetra::SerialPlatform<OT,ST> scalarPlatform; 00112 #endif 00113 00114 // Declare global dimension of the linear operator 00115 OT globalDim = 500; 00116 00117 // Create the element space and std::vector space 00118 const Tpetra::ElementSpace<OT> elementSpace(globalDim,0,ordinalPlatform); 00119 const Tpetra::VectorSpace<OT,ST> vectorSpace(elementSpace,scalarPlatform); 00120 00121 // Allocate the Tpetra::CisMatrix object. 00122 RCP<Tpetra::CisMatrix<OT,ST> > 00123 tpetra_A = rcp(new Tpetra::CisMatrix<OT,ST>(vectorSpace)); 00124 00125 // Get the indexes of the rows on this processor 00126 const int numMyElements = vectorSpace.getNumMyEntries(); 00127 const std::vector<int> &myGlobalElements = vectorSpace.elementSpace().getMyGlobalElements(); 00128 00129 // Fill the local matrix entries one row at a time. 00130 const ST offDiag = -1.0, diag = 2.0; 00131 int numEntries; ST values[3]; int indexes[3]; 00132 for( int k = 0; k < numMyElements; ++k ) { 00133 const int rowIndex = myGlobalElements[k]; 00134 if( rowIndex == 0 ) { // First row 00135 numEntries = 2; 00136 values[0] = diag; values[1] = offDiag; 00137 indexes[0] = 0; indexes[1] = 1; 00138 } 00139 else if( rowIndex == globalDim - 1 ) { // Last row 00140 numEntries = 2; 00141 values[0] = offDiag; values[1] = diag; 00142 indexes[0] = globalDim-2; indexes[1] = globalDim-1; 00143 } 00144 else { // Middle rows 00145 numEntries = 3; 00146 values[0] = offDiag; values[1] = diag; values[2] = offDiag; 00147 indexes[0] = rowIndex-1; indexes[1] = rowIndex; indexes[2] = rowIndex+1; 00148 } 00149 tpetra_A->submitEntries(Tpetra::Insert,rowIndex,numEntries,values,indexes); 00150 } 00151 00152 // Finish the construction of the Tpetra::CisMatrix 00153 tpetra_A->fillComplete(); 00154 00155 // Create a Thyra linear operator (A) using the Tpetra::CisMatrix (tpetra_A). 00156 RCP<Thyra::LinearOpBase<ST> > 00157 A = Teuchos::rcp( new Thyra::TpetraLinearOp<OT,ST>( 00158 Teuchos::rcp_implicit_cast<Tpetra::Operator<OT,ST> >(tpetra_A) ) ); 00159 00160 // Set the parameters for the Belos LOWS Factory and create a parameter list. 00161 // NOTE: All the code below only uses Thyra and is independent of Tpetra. 00162 // 00163 int blockSize = 1; // can only be 1 right now. 00164 int maxIterations = globalDim; 00165 int maxRestarts = 0; 00166 int gmresKrylovLength = globalDim; 00167 int outputFrequency = 100; 00168 bool outputMaxResOnly = true; 00169 MT maxResid = 1e-3; 00170 00171 ST one = Teuchos::ScalarTraits<ST>::one(); 00172 ST zero = Teuchos::ScalarTraits<ST>::zero(); 00173 00174 Teuchos::RCP<Teuchos::ParameterList> 00175 belosLOWSFPL = Teuchos::rcp( new Teuchos::ParameterList() ); 00176 00177 belosLOWSFPL->set("Solver Type","Block GMRES"); 00178 00179 Teuchos::ParameterList& belosLOWSFPL_solver = 00180 belosLOWSFPL->sublist("Solver Types"); 00181 00182 Teuchos::ParameterList& belosLOWSFPL_gmres = 00183 belosLOWSFPL_solver.sublist("Block GMRES"); 00184 00185 belosLOWSFPL_gmres.set("Maximum Iterations",int(maxIterations)); 00186 belosLOWSFPL_gmres.set("Convergence Tolerance",double(maxResid)); 00187 belosLOWSFPL_gmres.set("Maximum Restarts",int(maxRestarts)); 00188 belosLOWSFPL_gmres.set("Block Size",int(blockSize)); 00189 belosLOWSFPL_gmres.set("Num Blocks",int(gmresKrylovLength)); 00190 belosLOWSFPL_gmres.set("Output Frequency",int(outputFrequency)); 00191 belosLOWSFPL_gmres.set("Show Maximum Residual Norm Only",bool(outputMaxResOnly)); 00192 00193 // Whether the linear solver succeeded. 00194 // (this will be set during the residual check at the end) 00195 bool success = true; 00196 00197 // -------------------------------------------------------------------------------- 00198 // 00199 // Create the right-hand sides and solution vectors 00200 // 00201 // -------------------------------------------------------------------------------- 00202 00203 // Number of random right-hand sides we will be solving for. 00204 int numRhs = 5; 00205 00206 // Create smart pointer to right-hand side and solution std::vector to be filled in below. 00207 Teuchos::RCP<Thyra::MultiVectorBase<ST> > x, b; 00208 00209 if (numRhs==1) { 00210 // 00211 // In this case we can construct vectors using Tpetra and just "wrap" them in Thyra objects. 00212 // 00213 00214 // Create RHS std::vector 00215 Teuchos::RCP<Tpetra::Vector<OT,ST> > tpetra_b = 00216 Teuchos::rcp( new Tpetra::Vector<OT,ST>(vectorSpace) ); 00217 00218 // Randomize RHS std::vector 00219 tpetra_b->setAllToRandom(); 00220 00221 // Wrap Tpetra std::vector as Thyra std::vector 00222 b = Thyra::create_Vector(tpetra_b); 00223 00224 // Create solution (LHS) std::vector 00225 Teuchos::RCP<Tpetra::Vector<OT,ST> > tpetra_x = 00226 Teuchos::rcp( new Tpetra::Vector<OT,ST>(vectorSpace) ); 00227 00228 // Initialize solution to zero 00229 tpetra_x->setAllToScalar( zero ); 00230 00231 // Wrap Tpetra std::vector as Thyra std::vector 00232 x = Thyra::create_Vector(tpetra_x); 00233 00234 } 00235 else { 00236 // 00237 // In this case we can construct the multivector using Thyra and extract columns of 00238 // the multivector as Tpetra std::vector, which can then be filled. This is because 00239 // Tpetra does not have a multivector object and Thyra will emulate the multivector. 00240 // 00241 00242 // Get the domain space for the Thyra linear operator 00243 Teuchos::RCP<const Thyra::VectorSpaceBase<ST> > domain = A->domain(); 00244 00245 // Create a right-hand side and solution vectors with numRhs vectors in it. 00246 x = Thyra::createMembers(domain, numRhs); 00247 b = Thyra::createMembers(domain, numRhs); 00248 00249 // Extract the Tpetra std::vector from the columns of the multivector and fill them with 00250 // random numbers (b) or zeros (x). 00251 00252 for ( int j=0; j<numRhs; ++j ) { 00253 // 00254 // Get the j-th column from b as a Tpetra std::vector and randomize it. 00255 // 00256 Teuchos::RCP<Tpetra::Vector<OT,ST> > 00257 tpetra_b_j = Thyra::get_Tpetra_Vector(vectorSpace,b->col(j)); 00258 tpetra_b_j->setAllToRandom(); 00259 // 00260 // Get the j-th column from x as a Tpetra std::vector and set it to zero. 00261 // 00262 Teuchos::RCP<Tpetra::Vector<OT,ST> > 00263 tpetra_x_j = Thyra::get_Tpetra_Vector(vectorSpace,x->col(j)); 00264 tpetra_x_j->setAllToScalar( zero ); 00265 // 00266 // NOTE: Tpetra vectors have element access via the [] operator. 00267 // So and additional approach for filling in a Tpetra std::vector is: 00268 // 00269 for ( int i=0; i<numMyElements; ++i ) { 00270 // 00271 // Get the global index. 00272 // 00273 const int rowIndex = myGlobalElements[ i ]; 00274 00275 // Set the entry to zero. 00276 (*tpetra_x_j)[ rowIndex ] = zero; 00277 } 00278 } 00279 } 00280 00281 // -------------------------------------------------------------------------------- 00282 // 00283 // Create the linear operator with solve factory/object and solve the linear 00284 // system using the iterative solvers in Belos. 00285 // 00286 // NOTE: This is the only part of the code that solely uses Thyra. 00287 // 00288 // -------------------------------------------------------------------------------- 00289 00290 // Create the Belos LOWS factory. 00291 Teuchos::RCP<Thyra::LinearOpWithSolveFactoryBase<ST> > 00292 belosLOWSFactory = Teuchos::rcp(new Thyra::BelosLinearOpWithSolveFactory<ST>()); 00293 00294 // Set the output stream and the verbosity level (prints to std::cout by defualt) 00295 // NOTE: Set to VERB_NONE for no output from the solver. 00296 belosLOWSFactory->setVerbLevel(Teuchos::VERB_LOW); 00297 00298 // Set the parameter list to specify the behavior of the factory. 00299 belosLOWSFactory->setParameterList( belosLOWSFPL ); 00300 00301 // Create a BelosLinearOpWithSolve object from the Belos LOWS factory. 00302 Teuchos::RCP<Thyra::LinearOpWithSolveBase<ST> > 00303 nsA = belosLOWSFactory->createOp(); 00304 00305 // Initialize the BelosLinearOpWithSolve object with the Thyra linear operator. 00306 Thyra::initializeOp<ST>( *belosLOWSFactory, A, &*nsA ); 00307 00308 // Perform solve using the linear operator to get the approximate solution of Ax=b, 00309 // where b is the right-hand side and x is the left-hand side. 00310 Thyra::SolveStatus<ST> solveStatus; 00311 solveStatus = Thyra::solve( *nsA, Thyra::NONCONJ_ELE, *b, &*x ); 00312 00313 // Print out status of solve. 00314 *out << "\nBelos LOWS Status: "<< solveStatus << std::endl; 00315 00316 // -------------------------------------------------------------------------------- 00317 // Compute residual and check convergence. 00318 // NOTE: We will do this by extracting the Tpetra vectors from the multivector. 00319 // 00320 // NOTE 2: We are using scalar traits here instead of the magnitude type 00321 // because Tpetra defines its norm methods to return the scalar type. 00322 // -------------------------------------------------------------------------------- 00323 std::vector<ST> norm_b(numRhs), norm_res(numRhs); 00324 00325 for ( int j=0; j<numRhs; ++j ) { 00326 // 00327 // Get the j-th columns from x and b as Tpetra vectors. 00328 // 00329 Teuchos::RCP<Tpetra::Vector<OT,ST> > 00330 tpetra_x_j = Thyra::get_Tpetra_Vector(vectorSpace,x->col(j)); 00331 00332 Teuchos::RCP<Tpetra::Vector<OT,ST> > 00333 tpetra_b_j = Thyra::get_Tpetra_Vector(vectorSpace,b->col(j)); 00334 00335 // Compute the column norms of the right-hand side b. 00336 norm_b[j] = tpetra_b_j->norm2(); 00337 00338 // Compute y=A*x, where x is the solution from the linear solver. 00339 Tpetra::Vector<OT,ST> y(vectorSpace); 00340 tpetra_A->apply( *tpetra_x_j, y ); 00341 00342 // Compute b-A*x = b-y 00343 y.update( one, *tpetra_b_j, -one ); 00344 00345 // Compute the column norms of A*x-b. 00346 norm_res[j] = y.norm2(); 00347 } 00348 00349 // Print out the final relative residual norms. 00350 MT rel_res = 0.0; 00351 *out << "Final relative residual norms" << std::endl; 00352 for (int i=0; i<numRhs; ++i) { 00353 rel_res = Teuchos::ScalarTraits<ST>::real(norm_res[i]/norm_b[i]); 00354 if (rel_res > maxResid) 00355 success = false; 00356 *out << "RHS " << i+1 << " : " 00357 << std::setw(16) << std::right << rel_res << std::endl; 00358 } 00359 00360 return ( success ? 0 : 1 ); 00361 }
1.7.6.1