|
Tpetra Matrix/Vector Services
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Tpetra: Templated Linear Algebra Services Package 00005 // Copyright (2008) Sandia Corporation 00006 // 00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, 00008 // the U.S. Government retains certain rights in this software. 00009 // 00010 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // ************************************************************************ 00040 // @HEADER 00041 00042 #ifndef TPETRA_RTI_detail_HPP 00043 #define TPETRA_RTI_detail_HPP 00044 00045 #include <Teuchos_Assert.hpp> 00046 #include <Teuchos_CommHelpers.hpp> 00047 #include <Kokkos_NodeHelpers.hpp> 00048 00049 #include "Tpetra_Vector.hpp" 00050 00051 namespace Tpetra { 00052 00053 namespace RTI { 00054 00056 namespace detail { 00057 00059 template <class S> 00060 class StdOpKernel 00061 { 00062 protected: 00063 S _alpha, _beta; 00064 S * _vec_inout; 00065 const S * _vec_in2; 00066 public: 00067 inline StdOpKernel() : _alpha(ScalarTraits<S>::one()), _beta(ScalarTraits<S>::zero()) {} 00068 inline void setData(S * vec_inout, const S * vec_in2) { _vec_inout = vec_inout; _vec_in2 = vec_in2; } 00069 inline void setAlphaBeta(const S &alpha, const S &beta) { _alpha = alpha; _beta = beta; } 00070 }; 00071 00073 template <class OP, class S> 00074 class UnaryFunctorAdapter { 00075 protected: 00076 OP _op; 00077 S * _vec; 00078 public: 00079 UnaryFunctorAdapter(OP op) : _op(op) {} 00080 inline void setData(S *vec) { _vec = vec; } 00081 inline void execute(int i) { _vec[i] = _op(_vec[i]); } 00082 }; 00083 00085 template <class OP, class S1, class S2> 00086 class BinaryFunctorAdapter { 00087 protected: 00088 OP _op; 00089 S1 * _vec_inout; 00090 const S2 * _vec_in2; 00091 public: 00092 BinaryFunctorAdapter(OP op) : _op(op) {} 00093 inline void setData(S1 *vec_inout, const S2 *vec_in2) { _vec_inout = vec_inout; _vec_in2 = vec_in2; } 00094 inline void execute(int i) { _vec_inout[i] = _op(_vec_inout[i], _vec_in2[i]); } 00095 }; 00096 00098 template <class OP, class S> 00099 class BinaryFunctorAdapterWithAlphaBeta : public StdOpKernel<S> { 00100 protected: 00101 OP _op; 00102 S * _vec_inout; 00103 const S * _vec_in2; 00104 public: 00105 BinaryFunctorAdapterWithAlphaBeta(OP op) : _op(op) {} 00106 inline void setData(S *vec_inout, const S *vec_in2) { _vec_inout = vec_inout; _vec_in2 = vec_in2; } 00107 inline void execute(int i) 00108 { 00109 S res = _op(_vec_inout[i], _vec_in2[i]); 00110 _vec_inout[i] = this->_alpha * res + this->_beta * _vec_inout[i]; 00111 } 00112 }; 00113 00115 template <class OP, class S1, class S2, class S3> 00116 class TertiaryFunctorAdapter { 00117 protected: 00118 OP _op; 00119 S1 * _vec_inout; 00120 const S2 * _vec_in2; 00121 const S3 * _vec_in3; 00122 public: 00123 TertiaryFunctorAdapter(OP op) : _op(op) {} 00124 inline void setData(S1 *vec_inout, const S2 *vec_in2, const S3 *vec_in3) { _vec_inout = vec_inout; _vec_in2 = vec_in2; _vec_in3 = vec_in3; } 00125 inline void execute(int i) { _vec_inout[i] = _op(_vec_inout[i], _vec_in2[i], _vec_in3[i]); } 00126 }; 00127 00129 template <class Glob, class S> 00130 class RTIReductionAdapter1 { 00131 public: 00132 typedef typename Glob::GenOP GenOP; 00133 typedef typename Glob::RedOP RedOP; 00134 typedef typename Glob::IdOP IdOP; 00135 typedef typename RedOP::result_type ReductionType; 00136 protected: 00137 GenOP _genop; 00138 RedOP _redop; 00139 const S * _vec_in; 00140 public: 00141 RTIReductionAdapter1(Glob glob) : _genop(glob.genop), _redop(glob.redop) {} 00142 inline void setData(const S *vec_in) { _vec_in = vec_in; } 00143 static inline ReductionType identity() { return IdOP::identity(); } 00144 inline ReductionType generate(int i) { return _genop(_vec_in[i]); } 00145 inline ReductionType reduce(ReductionType a, ReductionType b) { return _redop(a, b); } 00146 }; 00147 00149 template <class Glob, class S1, class S2> 00150 class RTIReductionAdapter2 { 00151 public: 00152 typedef typename Glob::GenOP GenOP; 00153 typedef typename Glob::RedOP RedOP; 00154 typedef typename Glob::IdOP IdOP; 00155 typedef typename RedOP::result_type ReductionType; 00156 protected: 00157 GenOP _genop; 00158 RedOP _redop; 00159 const S1 * _vec_in1; 00160 const S2 * _vec_in2; 00161 public: 00162 RTIReductionAdapter2(Glob glob) : _genop(glob.genop), _redop(glob.redop) {} 00163 inline void setData(const S1 *vec_in1, const S2 *vec_in2) { _vec_in1 = vec_in1; _vec_in2 = vec_in2; } 00164 static inline ReductionType identity() { return IdOP::identity(); } 00165 inline ReductionType generate(int i) { return _genop(_vec_in1[i], _vec_in2[i]); } 00166 inline ReductionType reduce(ReductionType a, ReductionType b) { return _redop(a, b); } 00167 }; 00168 00170 template <class Glob, class S1, class S2, class S3> 00171 class RTIReductionAdapter3 { 00172 public: 00173 typedef typename Glob::GenOP GenOP; 00174 typedef typename Glob::RedOP RedOP; 00175 typedef typename Glob::IdOP IdOP; 00176 typedef typename RedOP::result_type ReductionType; 00177 protected: 00178 GenOP _genop; 00179 RedOP _redop; 00180 const S1 * _vec_in1; 00181 const S2 * _vec_in2; 00182 const S3 * _vec_in3; 00183 public: 00184 RTIReductionAdapter3(Glob glob) : _genop(glob.genop), _redop(glob.redop) {} 00185 inline void setData(const S1 *vec_in1, const S2 *vec_in2, const S3 *vec_in3) { _vec_in1 = vec_in1; _vec_in2 = vec_in2; _vec_in3 = vec_in3; } 00186 static inline ReductionType identity() { return IdOP::identity(); } 00187 inline ReductionType generate(int i) { return _genop(_vec_in1[i], _vec_in2[i], _vec_in3[i]); } 00188 inline ReductionType reduce(ReductionType a, ReductionType b) { return _redop(a, b); } 00189 }; 00190 00192 template <class Glob, class S1, class S2> 00193 class RTIPreTransformReductionAdapter { 00194 public: 00195 typedef typename Glob::TOP TOP; 00196 typedef typename Glob::GenOP GenOP; 00197 typedef typename Glob::RedOP RedOP; 00198 typedef typename Glob::IdOP IdOP; 00199 typedef typename RedOP::result_type ReductionType; 00200 protected: 00201 TOP _top; 00202 GenOP _genop; 00203 RedOP _redop; 00204 S1 * _vec_inout; 00205 const S2 * _vec_in2; 00206 public: 00207 RTIPreTransformReductionAdapter(Glob glob) : _top(glob.top), _genop(glob.genop), _redop(glob.redop) {} 00208 inline void setData(S1 *vec_inout, const S2 *vec_in2) { _vec_inout = vec_inout; _vec_in2 = vec_in2; } 00209 static inline ReductionType identity() { return IdOP::identity(); } 00210 inline ReductionType reduce(ReductionType a, ReductionType b) { return _redop(a, b); } 00211 inline ReductionType generate(int i) 00212 { 00213 _vec_inout[i] = _top( _vec_inout[i], _vec_in2[i] ); 00214 return _genop( _vec_inout[i], _vec_in2[i] ); 00215 } 00216 }; 00217 00219 template <class Glob, class S1, class S2, class S3> 00220 class RTIPreTransformReductionAdapter3 { 00221 public: 00222 typedef typename Glob::TOP TOP; 00223 typedef typename Glob::GenOP GenOP; 00224 typedef typename Glob::RedOP RedOP; 00225 typedef typename Glob::IdOP IdOP; 00226 typedef typename RedOP::result_type ReductionType; 00227 protected: 00228 TOP _top; 00229 GenOP _genop; 00230 RedOP _redop; 00231 S1 * _vec_inout; 00232 const S2 * _vec_in2; 00233 const S3 * _vec_in3; 00234 public: 00235 RTIPreTransformReductionAdapter3(Glob glob) : _top(glob.top), _genop(glob.genop), _redop(glob.redop) {} 00236 inline void setData(S1 *vec_inout, const S2 *vec_in2, const S3 *vec_in3) { _vec_inout = vec_inout; _vec_in2 = vec_in2; _vec_in3 = vec_in3; } 00237 static inline ReductionType identity() { return IdOP::identity(); } 00238 inline ReductionType reduce(ReductionType a, ReductionType b) { return _redop(a, b); } 00239 inline ReductionType generate(int i) 00240 { 00241 _vec_inout[i] = _top( _vec_inout[i], _vec_in2[i], _vec_in3[i] ); 00242 return _genop( _vec_inout[i], _vec_in2[i], _vec_in3[i] ); 00243 } 00244 }; 00245 00247 template <class OP> 00248 class TeuchosValueTypeReductionOpAdapter : public Teuchos::ValueTypeReductionOp<int,typename OP::ReductionType> 00249 { 00250 protected: 00251 mutable OP _op; 00252 public: 00253 typedef typename OP::ReductionType Packet; 00254 TeuchosValueTypeReductionOpAdapter(OP op) : _op(op) {} 00255 void reduce(const int count, const Packet inBuffer[], Packet inoutBuffer []) const 00256 { 00257 for (int i=0; i != count; ++i) { 00258 inoutBuffer[i] = _op.reduce( inoutBuffer[i], inBuffer[i] ); 00259 } 00260 } 00261 }; 00262 00264 template <class S, class LO, class GO, class Node, class OP> 00265 void unary_transform(Vector<S,LO,GO,Node> &vec, OP op) 00266 { 00267 Kokkos::MultiVector<S,Node> &mv = vec.getLocalMVNonConst(); 00268 const RCP<Node> node = mv.getNode(); 00269 // ready data 00270 Kokkos::ReadyBufferHelper<Node> rbh(node); 00271 rbh.begin(); 00272 S * out_ptr = rbh.addNonConstBuffer(mv.getValuesNonConst()); 00273 rbh.end(); 00274 op.setData(out_ptr); 00275 const size_t N = mv.getNumRows(); 00276 node->template parallel_for(0, N, op); 00277 } 00278 00280 template <class S1, class S2, class LO, class GO, class Node, class OP> 00281 void binary_transform(Vector<S1,LO,GO,Node> &vec_inout, const Vector<S2,LO,GO,Node> &vec_in2, OP op) 00282 { 00283 Kokkos::MultiVector<S1,Node> &mv_inout = vec_inout.getLocalMVNonConst(); 00284 const Kokkos::MultiVector<S2,Node> &mv_in2 = vec_in2.getLocalMV(); 00285 const RCP<Node> node = mv_inout.getNode(); 00286 // ready data 00287 Kokkos::ReadyBufferHelper<Node> rbh(node); 00288 rbh.begin(); 00289 S1 * out_ptr = rbh.addNonConstBuffer(mv_inout.getValuesNonConst()); 00290 const S2 * in_ptr = rbh.addConstBuffer(mv_in2.getValues()); 00291 rbh.end(); 00292 op.setData(out_ptr, in_ptr); 00293 const size_t N = mv_inout.getNumRows(); 00294 #ifdef HAVE_TPETRA_DEBUG 00295 TEUCHOS_TEST_FOR_EXCEPTION( mv_in2.getNode() != mv_inout.getNode(), std::runtime_error, 00296 "Tpetra::RTI::detail::binary_transform(): multivectors must share the same node."); 00297 #endif 00298 node->template parallel_for(0, N, op); 00299 } 00300 00302 template <class S1, class S2, class S3, class LO, class GO, class Node, class OP> 00303 void tertiary_transform(Vector<S1,LO,GO,Node> &vec_inout, const Vector<S2,LO,GO,Node> &vec_in2, const Vector<S3,LO,GO,Node> &vec_in3, OP op) 00304 { 00305 Kokkos::MultiVector<S1,Node> &mv_inout = vec_inout.getLocalMVNonConst(); 00306 const Kokkos::MultiVector<S2,Node> &mv_in2 = vec_in2.getLocalMV(); 00307 const Kokkos::MultiVector<S3,Node> &mv_in3 = vec_in3.getLocalMV(); 00308 const RCP<Node> node = mv_inout.getNode(); 00309 // ready data 00310 Kokkos::ReadyBufferHelper<Node> rbh(node); 00311 rbh.begin(); 00312 S1 * out_ptr = rbh.addNonConstBuffer(mv_inout.getValuesNonConst()); 00313 const S2 * in_ptr2 = rbh.addConstBuffer(mv_in2.getValues()); 00314 const S3 * in_ptr3 = rbh.addConstBuffer(mv_in3.getValues()); 00315 rbh.end(); 00316 op.setData(out_ptr, in_ptr2, in_ptr3); 00317 const size_t N = mv_inout.getNumRows(); 00318 #ifdef HAVE_TPETRA_DEBUG 00319 TEUCHOS_TEST_FOR_EXCEPTION( mv_in2.getNode() != mv_inout.getNode() || mv_in3.getNode() != mv_in2.getNode(), std::runtime_error, 00320 "Tpetra::RTI::detail::tertiary_transform(): multivectors must share the same node."); 00321 #endif 00322 node->template parallel_for(0, N, op); 00323 } 00324 00326 template <class S, class LO, class GO, class Node, class OP> 00327 typename OP::ReductionType 00328 reduce(const Vector<S,LO,GO,Node> &vec_in, OP op) 00329 { 00330 const Kokkos::MultiVector<S,Node> &mv_in = vec_in.getLocalMV(); 00331 const RCP<Node> node = mv_in.getNode(); 00332 const RCP<const Teuchos::Comm<int> > comm = vec_in.getMap()->getComm(); 00333 // ready data 00334 Kokkos::ReadyBufferHelper<Node> rbh(node); 00335 rbh.begin(); 00336 const S * in_ptr = rbh.addConstBuffer(mv_in.getValues()); 00337 rbh.end(); 00338 op.setData( in_ptr ); 00339 const size_t N = mv_in.getNumRows(); 00340 // compute local reduction 00341 typename OP::ReductionType gbl_res, lcl_res; 00342 lcl_res = node->template parallel_reduce(0, N, op); 00343 // compute global reduction 00344 TeuchosValueTypeReductionOpAdapter<OP> vtrop(op); 00345 Teuchos::reduceAll(*comm, vtrop, 1, &lcl_res, &gbl_res); 00346 return gbl_res; 00347 } 00348 00350 template <class S1, class S2, class LO, class GO, class Node, class OP> 00351 typename OP::ReductionType 00352 reduce(const Vector<S1,LO,GO,Node> &vec_in1, const Vector<S2,LO,GO,Node> &vec_in2, OP op) 00353 { 00354 const Kokkos::MultiVector<S1,Node> &mv_in1 = vec_in1.getLocalMV(), 00355 &mv_in2 = vec_in2.getLocalMV(); 00356 const RCP<Node> node = mv_in1.getNode(); 00357 const RCP<const Teuchos::Comm<int> > comm = vec_in1.getMap()->getComm(); 00358 // ready data 00359 Kokkos::ReadyBufferHelper<Node> rbh(node); 00360 rbh.begin(); 00361 const S1 * in_ptr1 = rbh.addConstBuffer(mv_in1.getValues()); 00362 const S2 * in_ptr2 = rbh.addConstBuffer(mv_in2.getValues()); 00363 rbh.end(); 00364 op.setData( in_ptr1, in_ptr2 ); 00365 const size_t N = mv_in1.getNumRows(); 00366 #ifdef HAVE_TPETRA_DEBUG 00367 TEUCHOS_TEST_FOR_EXCEPTION( mv_in1.getNode() != mv_in2.getNode(), std::runtime_error, 00368 "Tpetra::RTI::detail::reduce(): multivectors must share the same node."); 00369 #endif 00370 // compute local reduction 00371 typename OP::ReductionType gbl_res, lcl_res; 00372 lcl_res = node->template parallel_reduce(0, N, op); 00373 // compute global reduction 00374 TeuchosValueTypeReductionOpAdapter<OP> vtrop(op); 00375 Teuchos::reduceAll(*comm, vtrop, 1, &lcl_res, &gbl_res); 00376 return gbl_res; 00377 } 00378 00380 template <class S1, class S2, class S3, class LO, class GO, class Node, class OP> 00381 typename OP::ReductionType 00382 reduce(const Vector<S1,LO,GO,Node> &vec_in1, const Vector<S2,LO,GO,Node> &vec_in2, const Vector<S3,LO,GO,Node> &vec_in3, OP op) 00383 { 00384 const Kokkos::MultiVector<S1,Node> &mv_in1 = vec_in1.getLocalMV(); 00385 const Kokkos::MultiVector<S2,Node> &mv_in2 = vec_in2.getLocalMV(); 00386 const Kokkos::MultiVector<S3,Node> &mv_in3 = vec_in3.getLocalMV(); 00387 const RCP<Node> node = mv_in1.getNode(); 00388 const RCP<const Teuchos::Comm<int> > comm = vec_in1.getMap()->getComm(); 00389 // ready data 00390 Kokkos::ReadyBufferHelper<Node> rbh(node); 00391 rbh.begin(); 00392 const S1 * in_ptr1 = rbh.addConstBuffer(mv_in1.getValues()); 00393 const S2 * in_ptr2 = rbh.addConstBuffer(mv_in2.getValues()); 00394 const S3 * in_ptr3 = rbh.addConstBuffer(mv_in3.getValues()); 00395 rbh.end(); 00396 op.setData( in_ptr1, in_ptr2, in_ptr3 ); 00397 const size_t N = mv_in1.getNumRows(); 00398 #ifdef HAVE_TPETRA_DEBUG 00399 TEUCHOS_TEST_FOR_EXCEPTION( mv_in1.getNode() != mv_in2.getNode() || mv_in2.getNode() != mv_in3.getNode(), std::runtime_error, 00400 "Tpetra::RTI::detail::reduce(): multivectors must share the same node."); 00401 #endif 00402 // compute local reduction 00403 typename OP::ReductionType gbl_res, lcl_res; 00404 lcl_res = node->template parallel_reduce(0, N, op); 00405 // compute global reduction 00406 TeuchosValueTypeReductionOpAdapter<OP> vtrop(op); 00407 Teuchos::reduceAll(*comm, vtrop, 1, &lcl_res, &gbl_res); 00408 return gbl_res; 00409 } 00410 00412 template <class S1, class S2, class LO, class GO, class Node, class OP> 00413 typename OP::ReductionType 00414 transform_reduce(Vector<S1,LO,GO,Node> &vec_inout, const Vector<S2,LO,GO,Node> &vec_in2, OP op) 00415 { 00416 Kokkos::MultiVector<S1,Node> &mv_inout = vec_inout.getLocalMVNonConst(); 00417 const Kokkos::MultiVector<S2,Node> &mv_in2 = vec_in2.getLocalMV(); 00418 const RCP<Node> node = mv_inout.getNode(); 00419 const RCP<const Teuchos::Comm<int> > comm = vec_inout.getMap()->getComm(); 00420 // ready data 00421 Kokkos::ReadyBufferHelper<Node> rbh(node); 00422 rbh.begin(); 00423 S1 * in_ptr1 = rbh.addNonConstBuffer(mv_inout.getValuesNonConst()); 00424 const S2 * in_ptr2 = rbh.addConstBuffer(mv_in2.getValues()); 00425 rbh.end(); 00426 op.setData( in_ptr1, in_ptr2 ); 00427 const size_t N = mv_inout.getNumRows(); 00428 #ifdef HAVE_TPETRA_DEBUG 00429 TEUCHOS_TEST_FOR_EXCEPTION( mv_inout.getNode() != mv_in2.getNode(), std::runtime_error, 00430 "Tpetra::RTI::detail::transform_reduce(): multivectors must share the same node."); 00431 #endif 00432 // compute local reduction 00433 typename OP::ReductionType gbl_res, lcl_res; 00434 lcl_res = node->template parallel_reduce(0, N, op); 00435 // compute global reduction 00436 TeuchosValueTypeReductionOpAdapter<OP> vtrop(op); 00437 Teuchos::reduceAll(*comm, vtrop, 1, &lcl_res, &gbl_res); 00438 return gbl_res; 00439 } 00440 00442 template <class S1, class S2, class S3, class LO, class GO, class Node, class OP> 00443 typename OP::ReductionType 00444 transform_reduce(Vector<S1,LO,GO,Node> &vec_inout, const Vector<S2,LO,GO,Node> &vec_in2, const Vector<S3,LO,GO,Node> &vec_in3, OP op) 00445 { 00446 Kokkos::MultiVector<S1,Node> &mv_inout = vec_inout.getLocalMVNonConst(); 00447 const Kokkos::MultiVector<S2,Node> &mv_in2 = vec_in2.getLocalMV(); 00448 const Kokkos::MultiVector<S3,Node> &mv_in3 = vec_in3.getLocalMV(); 00449 const RCP<Node> node = mv_inout.getNode(); 00450 const RCP<const Teuchos::Comm<int> > comm = vec_inout.getMap()->getComm(); 00451 // ready data 00452 Kokkos::ReadyBufferHelper<Node> rbh(node); 00453 rbh.begin(); 00454 S1 * in_ptr1 = rbh.addNonConstBuffer(mv_inout.getValuesNonConst()); 00455 const S2 * in_ptr2 = rbh.addConstBuffer(mv_in2.getValues()); 00456 const S3 * in_ptr3 = rbh.addConstBuffer(mv_in3.getValues()); 00457 rbh.end(); 00458 op.setData( in_ptr1, in_ptr2, in_ptr3 ); 00459 const size_t N = mv_inout.getNumRows(); 00460 #ifdef HAVE_TPETRA_DEBUG 00461 TEUCHOS_TEST_FOR_EXCEPTION( mv_inout.getNode() != mv_in2.getNode() && mv_inout.getNode() != mv_in3.getNode(), std::runtime_error, 00462 "Tpetra::RTI::detail::transform_transform(): multivectors must share the same node."); 00463 #endif 00464 // compute local reduction 00465 typename OP::ReductionType gbl_res, lcl_res; 00466 lcl_res = node->template parallel_reduce(0, N, op); 00467 // compute global reduction 00468 TeuchosValueTypeReductionOpAdapter<OP> vtrop(op); 00469 Teuchos::reduceAll(*comm, vtrop, 1, &lcl_res, &gbl_res); 00470 return gbl_res; 00471 } 00472 00473 } // end of namespace Tpetra::RTI::detail 00474 00475 } // end of namespace Tpetra::RTI 00476 00477 } // end of namespace Tpetra 00478 00479 #endif // TPETRA_RTI_detail_HPP
1.7.6.1