// Compute Y := alpha Op X + beta Y. // // We ignore the cases alpha != 1 and beta != 0 for simplicity. void apply (const MV& X, MV& Y, Teuchos::ETransp mode = Teuchos::NO_TRANS, scalar_type alpha = Teuchos::ScalarTraits<scalar_type>::one (), scalar_type beta = Teuchos::ScalarTraits<scalar_type>::zero ()) const { using Teuchos::RCP; using Teuchos::rcp; using std::cout; using std::endl; typedef Teuchos::ScalarTraits<scalar_type> STS; RCP<const Teuchos::Comm<int> > comm = opMap_->getComm (); const int myRank = comm->getRank (); const int numProcs = comm->getSize (); if (myRank == 0) { cout << "MyOp::apply" << endl; } // We're writing the Operator subclass, so we are responsible for // error handling. You can decide how much error checking you // want to do. Just remember that checking things like Map // sameness or compatibility are expensive. TEUCHOS_TEST_FOR_EXCEPTION( X.getNumVectors () != Y.getNumVectors (), std::invalid_argument, "X and Y do not have the same numbers of vectors (columns)."); // Let's make sure alpha is 1 and beta is 0... // This will throw an exception if that is not the case. TEUCHOS_TEST_FOR_EXCEPTION( alpha != STS::one() || beta != STS::zero(), std::logic_error, "MyOp::apply was given alpha != 1 or beta != 0. " "These cases are not implemented."); // Get the number of vectors (columns) in X (and Y). const size_t numVecs = X.getNumVectors (); // Make a temporary multivector for holding the redistributed // data. You could also create this in the constructor and reuse // it across different apply() calls, but you would need to be // careful to reallocate if it has a different number of vectors // than X. The number of vectors in X can vary across different // apply() calls. RCP<MV> redistData = rcp (new MV (redistMap_, numVecs)); // Redistribute the data. // This will do all the necessary communication for you. // All processes now own enough data to do the matvec. redistData->doImport (X, *importer_, Tpetra::INSERT); // Get the number of local rows in X, on the calling process. const local_ordinal_type nlocRows = static_cast<local_ordinal_type> (X.getLocalLength ()); // Perform the matvec with the data we now locally own. // // For each column... for (size_t c = 0; c < numVecs; ++c) { // Get a view of the desired column Teuchos::ArrayRCP<scalar_type> colView = redistData->getDataNonConst (c); local_ordinal_type offset; // Y[0,c] = -colView[0] + 2*colView[1] - colView[2] (using local indices) if (myRank > 0) { Y.replaceLocalValue (0, c, -colView[0] + 2*colView[1] - colView[2]); offset = 0; } // Y[0,c] = 2*colView[1] - colView[2] (using local indices) else { Y.replaceLocalValue (0, c, 2*colView[0] - colView[1]); offset = 1; } // Y[r,c] = -colView[r-offset] + 2*colView[r+1-offset] - colView[r+2-offset] for (local_ordinal_type r = 1; r < nlocRows - 1; ++r) { const scalar_type newVal = -colView[r-offset] + 2*colView[r+1-offset] - colView[r+2-offset]; Y.replaceLocalValue (r, c, newVal); } // Y[nlocRows-1,c] = -colView[nlocRows-1-offset] + 2*colView[nlocRows-offset] // - colView[nlocRows+1-offset] if (myRank < numProcs - 1) { const scalar_type newVal = -colView[nlocRows-1-offset] + 2*colView[nlocRows-offset] - colView[nlocRows+1-offset]; Y.replaceLocalValue (nlocRows-1, c, newVal); } // Y[nlocRows-1,c] = -colView[nlocRows-1-offset] + 2*colView[nlocRows-offset] else { const scalar_type newVal = -colView[nlocRows-1-offset] + 2*colView[nlocRows-offset]; Y.replaceLocalValue (nlocRows-1, c, newVal); } } }
// // Computes Y = alpha Op X + beta Y // TraceMin will never use alpha ~= 1 or beta ~= 0, // so we have ignored those options for simplicity. // void apply(const MV& X, MV& Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, Scalar alpha=SCT::one(), Scalar beta=SCT::zero()) const { // // Let's make sure alpha is 1 and beta is 0... // This will throw an exception if that is not the case. // TEUCHOS_TEST_FOR_EXCEPTION(alpha != SCT::one() || beta != SCT::zero(),std::invalid_argument, "MyOp::apply was given alpha != 1 or beta != 0. That's not supposed to happen."); // // Get the number of local rows // int nlocRows = X.getLocalLength(); // // Get the number of vectors // int numVecs = X.getNumVectors(); // // Make a multivector for holding the redistributed data // RCP<MV> redistData = rcp(new MV(redistMap_, numVecs)); // // Redistribute the data. // This will do all the necessary communication for you. // All processes now own enough data to do the matvec. // redistData->doImport(X, *importer_, Tpetra::INSERT); // // Perform the matvec with the data we now locally own // // For each column... for(int c=0; c<numVecs; c++) { // Get a view of the desired column Teuchos::ArrayRCP<Scalar> colView = redistData->getDataNonConst(c); int offset; // Y[0,c] = -colView[0] + 2*colView[1] - colView[2] (using local indices) if(myRank_ > 0) { Y.replaceLocalValue(0, c, -colView[0] + 2*colView[1] - colView[2]); offset = 0; } // Y[0,c] = 2*colView[1] - colView[2] (using local indices) else { Y.replaceLocalValue(0, c, 2*colView[0] - colView[1]); offset = 1; } // Y[r,c] = -colView[r-offset] + 2*colView[r+1-offset] - colView[r+2-offset] for(int r=1; r<nlocRows-1; r++) { Y.replaceLocalValue(r, c, -colView[r-offset] + 2*colView[r+1-offset] - colView[r+2-offset]); } // Y[nlocRows-1,c] = -colView[nlocRows-1-offset] + 2*colView[nlocRows-offset] - colView[nlocRows+1-offset] if(myRank_ < numProcs_-1) { Y.replaceLocalValue(nlocRows-1, c, -colView[nlocRows-1-offset] + 2*colView[nlocRows-offset] - colView[nlocRows+1-offset]); } // Y[nlocRows-1,c] = -colView[nlocRows-1-offset] + 2*colView[nlocRows-offset] else { Y.replaceLocalValue(nlocRows-1, c, -colView[nlocRows-1-offset] + 2*colView[nlocRows-offset]); } } }