Amesos2 - Direct Sparse Solver Interfaces  Version of the Day
Amesos2_TpetraMultiVecAdapter_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Amesos2: Templated Direct Sparse Solver Package
6 // Copyright 2011 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39 //
40 // ***********************************************************************
41 //
42 // @HEADER
43 
53 #ifndef AMESOS2_TPETRA_MULTIVEC_ADAPTER_DEF_HPP
54 #define AMESOS2_TPETRA_MULTIVEC_ADAPTER_DEF_HPP
55 
56 #include <type_traits>
59 
60 
61 namespace Amesos2 {
62 
63  using Tpetra::MultiVector;
64 
65  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node >
66  MultiVecAdapter<
67  MultiVector<Scalar,
68  LocalOrdinal,
69  GlobalOrdinal,
70  Node> >::MultiVecAdapter( const Teuchos::RCP<multivec_t>& m )
71  : mv_(m)
72  {}
73 
74 
75  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node >
76  typename MultiVecAdapter<
77  MultiVector<Scalar,
78  LocalOrdinal,
79  GlobalOrdinal,
80  Node> >::multivec_t::impl_scalar_type *
81  MultiVecAdapter<
82  MultiVector<Scalar,
83  LocalOrdinal,
84  GlobalOrdinal,
85  Node> >::getMVPointer_impl() const
86  {
87  TEUCHOS_TEST_FOR_EXCEPTION( this->getGlobalNumVectors() != 1,
88  std::invalid_argument,
89  "Amesos2_TpetraMultiVectorAdapter: getMVPointer_impl should only be called for case with a single vector and single MPI process" );
90 
91  typedef typename multivec_t::dual_view_type dual_view_type;
92  typedef typename dual_view_type::host_mirror_space host_execution_space;
93  mv_->template sync<host_execution_space> ();
94  auto contig_local_view_2d = mv_->template getLocalView<host_execution_space>();
95  auto contig_local_view_1d = Kokkos::subview (contig_local_view_2d, Kokkos::ALL (), 0);
96  return contig_local_view_1d.data();
97  }
98 
99  // TODO Proper type handling:
100  // Consider a MultiVectorTraits class
101  // typedef Tpetra::MultiVector<Scalar, LocalOrdinal, GlobalOrdinal, Node> multivector_type
102  // NOTE: In this class, above already has a typedef multivec_t
103  // typedef typename multivector_type::impl_scalar_type return_scalar_type; // this is the POD type the dual_view_type is templated on
104  // Traits class needed to do this generically for the general MultiVectorAdapter interface
105 
106 
107  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node >
108  void
109  MultiVecAdapter<
110  MultiVector<Scalar,
111  LocalOrdinal,
112  GlobalOrdinal,
113  Node> >::get1dCopy(const Teuchos::ArrayView<scalar_t>& av,
114  size_t lda,
115  Teuchos::Ptr<
116  const Tpetra::Map<LocalOrdinal,
117  GlobalOrdinal,
118  Node> > distribution_map,
119  EDistribution distribution) const
120  {
121  using Teuchos::as;
122  using Teuchos::RCP;
123  typedef Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node> map_type;
124  const size_t num_vecs = getGlobalNumVectors ();
125 
126  TEUCHOS_TEST_FOR_EXCEPTION(
127  distribution_map.getRawPtr () == NULL, std::invalid_argument,
128  "Amesos2::MultiVecAdapter::get1dCopy: distribution_map argument is null.");
129  TEUCHOS_TEST_FOR_EXCEPTION(
130  mv_.is_null (), std::logic_error,
131  "Amesos2::MultiVecAdapter::get1dCopy: mv_ is null.");
132  // Check mv_ before getMap(), because the latter calls mv_->getMap().
133  TEUCHOS_TEST_FOR_EXCEPTION(
134  this->getMap ().is_null (), std::logic_error,
135  "Amesos2::MultiVecAdapter::get1dCopy: this->getMap() returns null.");
136 
137 #ifdef HAVE_AMESOS2_DEBUG
138  const size_t requested_vector_length = distribution_map->getNodeNumElements ();
139  TEUCHOS_TEST_FOR_EXCEPTION(
140  lda < requested_vector_length, std::invalid_argument,
141  "Amesos2::MultiVecAdapter::get1dCopy: On process " <<
142  distribution_map->getComm ()->getRank () << " of the distribution Map's "
143  "communicator, the given stride lda = " << lda << " is not large enough "
144  "for the local vector length " << requested_vector_length << ".");
145  TEUCHOS_TEST_FOR_EXCEPTION(
146  as<size_t> (av.size ()) < as<size_t> ((num_vecs - 1) * lda + requested_vector_length),
147  std::invalid_argument, "Amesos2::MultiVector::get1dCopy: MultiVector "
148  "storage not large enough given leading dimension and number of vectors." );
149 #endif // HAVE_AMESOS2_DEBUG
150 
151  // Special case when number vectors == 1 and single MPI process
152  if ( num_vecs == 1 && this->getComm()->getRank() == 0 && this->getComm()->getSize() == 1 ) {
153  mv_->get1dCopy (av, lda);
154  }
155  else {
156 
157  // (Re)compute the Export object if necessary. If not, then we
158  // don't need to clone distribution_map; we can instead just get
159  // the previously cloned target Map from the Export object.
160  RCP<const map_type> distMap;
161  if (exporter_.is_null () ||
162  ! exporter_->getSourceMap ()->isSameAs (* (this->getMap ())) ||
163  ! exporter_->getTargetMap ()->isSameAs (* distribution_map)) {
164  // Since we're caching the Export object, and since the Export
165  // needs to keep the distribution Map, we have to make a copy of
166  // the latter in order to ensure that it will stick around past
167  // the scope of this function call. (Ptr is not reference
168  // counted.)
169  distMap = rcp(new map_type(*distribution_map));
170  // (Re)create the Export object.
171  exporter_ = rcp (new export_type (this->getMap (), distMap));
172  }
173  else {
174  distMap = exporter_->getTargetMap ();
175  }
176 
177  multivec_t redist_mv (distMap, num_vecs);
178 
179  // Redistribute the input (multi)vector.
180  redist_mv.doExport (*mv_, *exporter_, Tpetra::REPLACE);
181 
182  if ( distribution != CONTIGUOUS_AND_ROOTED ) {
183  // Do this if GIDs contiguous - existing functionality
184  // Copy the imported (multi)vector's data into the ArrayView.
185  redist_mv.get1dCopy (av, lda);
186  }
187  else {
188  // Do this if GIDs not contiguous...
189  // sync is needed for example if mv was updated on device, but will be passed through Amesos2 to solver running on host
190  typedef typename multivec_t::dual_view_type dual_view_type;
191  typedef typename dual_view_type::host_mirror_space host_execution_space;
192  redist_mv.template sync < host_execution_space > ();
193 
194  auto contig_local_view_2d = redist_mv.template getLocalView<host_execution_space>();
195  if ( redist_mv.isConstantStride() ) {
196  for ( size_t j = 0; j < num_vecs; ++j) {
197  auto av_j = av(lda*j, lda);
198  for ( size_t i = 0; i < lda; ++i ) {
199  av_j[i] = contig_local_view_2d(i,j); //lda may not be correct if redist_mv is not constant stride...
200  }
201  }
202  }
203  else {
204  // ... lda should come from Teuchos::Array* allocation,
205  // not the MultiVector, since the MultiVector does NOT
206  // have constant stride in this case.
207  // TODO lda comes from X->getGlobalLength() in solve_impl - should this be changed???
208  const size_t lclNumRows = redist_mv.getLocalLength();
209  for (size_t j = 0; j < redist_mv.getNumVectors(); ++j) {
210  auto av_j = av(lda*j, lclNumRows);
211  auto X_lcl_j_2d = redist_mv.template getLocalView<host_execution_space> ();
212  auto X_lcl_j_1d = Kokkos::subview (X_lcl_j_2d, Kokkos::ALL (), j);
213 
214  using val_type = typename decltype( X_lcl_j_1d )::value_type;
215  Kokkos::View<val_type*, Kokkos::HostSpace> umavj ( const_cast< val_type* > ( reinterpret_cast<const val_type*> ( av_j.getRawPtr () ) ), av_j.size () );
216  Kokkos::deep_copy (umavj, X_lcl_j_1d);
217  }
218  }
219  }
220  }
221  }
222 
223  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node >
224  template <typename KV>
225  void
226  MultiVecAdapter<
227  MultiVector<Scalar,
228  LocalOrdinal,
229  GlobalOrdinal,
230  Node> >::get1dCopy_kokkos_view(KV& kokkos_view,
231  size_t lda,
232  Teuchos::Ptr<
233  const Tpetra::Map<LocalOrdinal,
234  GlobalOrdinal,
235  Node> > distribution_map,
236  EDistribution distribution) const
237  {
238  using Teuchos::as;
239  using Teuchos::RCP;
240  typedef Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node> map_type;
241  const size_t num_vecs = getGlobalNumVectors ();
242 
243  TEUCHOS_TEST_FOR_EXCEPTION(
244  distribution_map.getRawPtr () == NULL, std::invalid_argument,
245  "Amesos2::MultiVecAdapter::get1dCopy_kokkos_view: distribution_map argument is null.");
246  TEUCHOS_TEST_FOR_EXCEPTION(
247  mv_.is_null (), std::logic_error,
248  "Amesos2::MultiVecAdapter::get1dCopy_kokkos_view: mv_ is null.");
249  // Check mv_ before getMap(), because the latter calls mv_->getMap().
250  TEUCHOS_TEST_FOR_EXCEPTION(
251  this->getMap ().is_null (), std::logic_error,
252  "Amesos2::MultiVecAdapter::get1dCopy_kokkos_view: this->getMap() returns null.");
253 
254 #ifdef HAVE_AMESOS2_DEBUG
255  const size_t requested_vector_length = distribution_map->getNodeNumElements ();
256  TEUCHOS_TEST_FOR_EXCEPTION(
257  lda < requested_vector_length, std::invalid_argument,
258  "Amesos2::MultiVecAdapter::get1dCopy_kokkos_view: On process " <<
259  distribution_map->getComm ()->getRank () << " of the distribution Map's "
260  "communicator, the given stride lda = " << lda << " is not large enough "
261  "for the local vector length " << requested_vector_length << ".");
262 
263  // Note do not check size since deep_copy_or_assign_view below will allocate
264  // if necessary - but may just assign ptrs.
265 #endif // HAVE_AMESOS2_DEBUG
266 
267  // Special case when number vectors == 1 and single MPI process
268  if ( num_vecs == 1 && this->getComm()->getRank() == 0 && this->getComm()->getSize() == 1 ) {
269  if(mv_->isConstantStride()) {
270  deep_copy_or_assign_view(kokkos_view, mv_->getLocalViewDevice());
271  }
272  else {
273  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "Resolve handling for non-constant stride.");
274  }
275  }
276  else {
277 
278  // (Re)compute the Export object if necessary. If not, then we
279  // don't need to clone distribution_map; we can instead just get
280  // the previously cloned target Map from the Export object.
281  RCP<const map_type> distMap;
282  if (exporter_.is_null () ||
283  ! exporter_->getSourceMap ()->isSameAs (* (this->getMap ())) ||
284  ! exporter_->getTargetMap ()->isSameAs (* distribution_map)) {
285  // Since we're caching the Export object, and since the Export
286  // needs to keep the distribution Map, we have to make a copy of
287  // the latter in order to ensure that it will stick around past
288  // the scope of this function call. (Ptr is not reference
289  // counted.)
290  distMap = rcp(new map_type(*distribution_map));
291  // (Re)create the Export object.
292  exporter_ = rcp (new export_type (this->getMap (), distMap));
293  }
294  else {
295  distMap = exporter_->getTargetMap ();
296  }
297 
298  multivec_t redist_mv (distMap, num_vecs);
299 
300  // Redistribute the input (multi)vector.
301  redist_mv.doExport (*mv_, *exporter_, Tpetra::REPLACE);
302 
303  if ( distribution != CONTIGUOUS_AND_ROOTED ) {
304  // Do this if GIDs contiguous - existing functionality
305  // Copy the imported (multi)vector's data into the Kokkos View.
306  deep_copy_or_assign_view(kokkos_view, redist_mv.getLocalViewDevice());
307  }
308  else {
309  if(redist_mv.isConstantStride()) {
310  deep_copy_or_assign_view(kokkos_view, redist_mv.getLocalViewDevice());
311  }
312  else {
313  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "Kokkos adapter non-constant stride not imlemented.");
314  }
315  }
316  }
317  }
318 
319  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node >
320  Teuchos::ArrayRCP<Scalar>
321  MultiVecAdapter<
322  MultiVector<Scalar,
323  LocalOrdinal,
324  GlobalOrdinal,
325  Node> >::get1dViewNonConst (bool local)
326  {
327  // FIXME (mfh 22 Jan 2014) When I first found this routine, all of
328  // its code was commented out, and it didn't return anything. The
329  // latter is ESPECIALLY dangerous, given that the return value is
330  // an ArrayRCP. Thus, I added the exception throw below.
331  TEUCHOS_TEST_FOR_EXCEPTION(
332  true, std::logic_error, "Amesos2::MultiVecAdapter::get1dViewNonConst: "
333  "Not implemented.");
334 
335  // if( local ){
336  // this->localize();
337  // /* Use the global element list returned by
338  // * mv_->getMap()->getNodeElementList() to get a subCopy of mv_ which we
339  // * assign to l_l_mv_, then return get1dViewNonConst() of l_l_mv_
340  // */
341  // if(l_l_mv_.is_null() ){
342  // Teuchos::ArrayView<const GlobalOrdinal> nodeElements_go
343  // = mv_->getMap()->getNodeElementList();
344  // Teuchos::Array<size_t> nodeElements_st(nodeElements_go.size());
345 
346  // // Convert the node element to a list of size_t type objects
347  // typename Teuchos::ArrayView<const GlobalOrdinal>::iterator it_go;
348  // Teuchos::Array<size_t>::iterator it_st = nodeElements_st.begin();
349  // for( it_go = nodeElements_go.begin(); it_go != nodeElements_go.end(); ++it_go ){
350  // *(it_st++) = Teuchos::as<size_t>(*it_go);
351  // }
352 
353  // // To be consistent with the globalize() function, get a view of the local mv
354  // l_l_mv_ = l_mv_->subViewNonConst(nodeElements_st);
355 
356  // return(l_l_mv_->get1dViewNonConst());
357  // } else {
358  // // We need to re-import values to the local, since changes may have been
359  // // made to the global structure that are not reflected in the local
360  // // view.
361  // Teuchos::ArrayView<const GlobalOrdinal> nodeElements_go
362  // = mv_->getMap()->getNodeElementList();
363  // Teuchos::Array<size_t> nodeElements_st(nodeElements_go.size());
364 
365  // // Convert the node element to a list of size_t type objects
366  // typename Teuchos::ArrayView<const GlobalOrdinal>::iterator it_go;
367  // Teuchos::Array<size_t>::iterator it_st = nodeElements_st.begin();
368  // for( it_go = nodeElements_go.begin(); it_go != nodeElements_go.end(); ++it_go ){
369  // *(it_st++) = Teuchos::as<size_t>(*it_go);
370  // }
371 
372  // return l_l_mv_->get1dViewNonConst();
373  // }
374  // } else {
375  // if( mv_->isDistributed() ){
376  // this->localize();
377 
378  // return l_mv_->get1dViewNonConst();
379  // } else { // not distributed, no need to import
380  // return mv_->get1dViewNonConst();
381  // }
382  // }
383  }
384 
385 
386  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node>
387  void
388  MultiVecAdapter<
389  MultiVector<Scalar,
390  LocalOrdinal,
391  GlobalOrdinal,
392  Node> >::put1dData(const Teuchos::ArrayView<const scalar_t>& new_data,
393  size_t lda,
394  Teuchos::Ptr<
395  const Tpetra::Map<LocalOrdinal,
396  GlobalOrdinal,
397  Node> > source_map,
398  EDistribution distribution )
399  {
400  using Teuchos::RCP;
401  typedef Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node> map_type;
402 
403  TEUCHOS_TEST_FOR_EXCEPTION(
404  source_map.getRawPtr () == NULL, std::invalid_argument,
405  "Amesos2::MultiVecAdapter::put1dData: source_map argument is null.");
406  TEUCHOS_TEST_FOR_EXCEPTION(
407  mv_.is_null (), std::logic_error,
408  "Amesos2::MultiVecAdapter::put1dData: the internal MultiVector mv_ is null.");
409  // getMap() calls mv_->getMap(), so test first whether mv_ is null.
410  TEUCHOS_TEST_FOR_EXCEPTION(
411  this->getMap ().is_null (), std::logic_error,
412  "Amesos2::MultiVecAdapter::put1dData: this->getMap() returns null.");
413 
414  const size_t num_vecs = getGlobalNumVectors ();
415 
416  // Special case when number vectors == 1 and single MPI process
417  if ( num_vecs == 1 && this->getComm()->getRank() == 0 && this->getComm()->getSize() == 1 ) {
418  typedef typename multivec_t::dual_view_type::host_mirror_space host_execution_space;
419  // num_vecs = 1; stride does not matter
420  auto mv_view_to_modify_2d = mv_->template getLocalView<host_execution_space>();
421  for ( size_t i = 0; i < lda; ++i ) {
422  mv_view_to_modify_2d(i,0) = new_data[i]; // Only one vector
423  }
424  }
425  else {
426 
427  // (Re)compute the Import object if necessary. If not, then we
428  // don't need to clone source_map; we can instead just get the
429  // previously cloned source Map from the Import object.
430  RCP<const map_type> srcMap;
431  if (importer_.is_null () ||
432  ! importer_->getSourceMap ()->isSameAs (* source_map) ||
433  ! importer_->getTargetMap ()->isSameAs (* (this->getMap ()))) {
434 
435  // Since we're caching the Import object, and since the Import
436  // needs to keep the source Map, we have to make a copy of the
437  // latter in order to ensure that it will stick around past the
438  // scope of this function call. (Ptr is not reference counted.)
439  srcMap = rcp(new map_type(*source_map));
440  importer_ = rcp (new import_type (srcMap, this->getMap ()));
441  }
442  else {
443  srcMap = importer_->getSourceMap ();
444  }
445 
446  if ( distribution != CONTIGUOUS_AND_ROOTED ) {
447  // Do this if GIDs contiguous - existing functionality
448  // Redistribute the output (multi)vector.
449  const multivec_t source_mv (srcMap, new_data, lda, num_vecs);
450  mv_->doImport (source_mv, *importer_, Tpetra::REPLACE);
451  }
452  else {
453  multivec_t redist_mv (srcMap, num_vecs); // unused for ROOTED case
454  typedef typename multivec_t::dual_view_type dual_view_type;
455  typedef typename dual_view_type::host_mirror_space host_execution_space;
456  redist_mv.template modify< host_execution_space > ();
457 
458  if ( redist_mv.isConstantStride() ) {
459  auto contig_local_view_2d = redist_mv.template getLocalView<host_execution_space>();
460  for ( size_t j = 0; j < num_vecs; ++j) {
461  auto av_j = new_data(lda*j, lda);
462  for ( size_t i = 0; i < lda; ++i ) {
463  contig_local_view_2d(i,j) = av_j[i];
464  }
465  }
466  }
467  else {
468  // ... lda should come from Teuchos::Array* allocation,
469  // not the MultiVector, since the MultiVector does NOT
470  // have constant stride in this case.
471  // TODO lda comes from X->getGlobalLength() in solve_impl - should this be changed???
472  const size_t lclNumRows = redist_mv.getLocalLength();
473  for (size_t j = 0; j < redist_mv.getNumVectors(); ++j) {
474  auto av_j = new_data(lda*j, lclNumRows);
475  auto X_lcl_j_2d = redist_mv.template getLocalView<host_execution_space> ();
476  auto X_lcl_j_1d = Kokkos::subview (X_lcl_j_2d, Kokkos::ALL (), j);
477 
478  using val_type = typename decltype( X_lcl_j_1d )::value_type;
479  Kokkos::View<val_type*, Kokkos::HostSpace> umavj ( const_cast< val_type* > ( reinterpret_cast<const val_type*> ( av_j.getRawPtr () ) ), av_j.size () );
480  Kokkos::deep_copy (umavj, X_lcl_j_1d);
481  }
482  }
483 
484  typedef typename multivec_t::node_type::memory_space memory_space;
485  redist_mv.template sync <memory_space> ();
486 
487  mv_->doImport (redist_mv, *importer_, Tpetra::REPLACE);
488  }
489  }
490 
491  }
492 
493  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node>
494  template <typename KV>
495  void
496  MultiVecAdapter<
497  MultiVector<Scalar,
498  LocalOrdinal,
499  GlobalOrdinal,
500  Node> >::put1dData_kokkos_view(KV& kokkos_new_data,
501  size_t lda,
502  Teuchos::Ptr<
503  const Tpetra::Map<LocalOrdinal,
504  GlobalOrdinal,
505  Node> > source_map,
506  EDistribution distribution )
507  {
508  using Teuchos::RCP;
509  typedef Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node> map_type;
510 
511  TEUCHOS_TEST_FOR_EXCEPTION(
512  source_map.getRawPtr () == NULL, std::invalid_argument,
513  "Amesos2::MultiVecAdapter::put1dData_kokkos_view: source_map argument is null.");
514  TEUCHOS_TEST_FOR_EXCEPTION(
515  mv_.is_null (), std::logic_error,
516  "Amesos2::MultiVecAdapter::put1dData_kokkos_view: the internal MultiVector mv_ is null.");
517  // getMap() calls mv_->getMap(), so test first whether mv_ is null.
518  TEUCHOS_TEST_FOR_EXCEPTION(
519  this->getMap ().is_null (), std::logic_error,
520  "Amesos2::MultiVecAdapter::put1dData_kokkos_view: this->getMap() returns null.");
521 
522  const size_t num_vecs = getGlobalNumVectors ();
523 
524  // Special case when number vectors == 1 and single MPI process
525  if ( num_vecs == 1 && this->getComm()->getRank() == 0 && this->getComm()->getSize() == 1 ) {
526 
527  // num_vecs = 1; stride does not matter
528 
529  // If this is the optimized path then kokkos_new_data will be the dst
530  auto mv_view_to_modify_2d = mv_->getLocalViewDevice();
531  deep_copy_or_assign_view(mv_view_to_modify_2d, kokkos_new_data);
532  }
533  else {
534 
535  // (Re)compute the Import object if necessary. If not, then we
536  // don't need to clone source_map; we can instead just get the
537  // previously cloned source Map from the Import object.
538  RCP<const map_type> srcMap;
539  if (importer_.is_null () ||
540  ! importer_->getSourceMap ()->isSameAs (* source_map) ||
541  ! importer_->getTargetMap ()->isSameAs (* (this->getMap ()))) {
542 
543  // Since we're caching the Import object, and since the Import
544  // needs to keep the source Map, we have to make a copy of the
545  // latter in order to ensure that it will stick around past the
546  // scope of this function call. (Ptr is not reference counted.)
547  srcMap = rcp(new map_type(*source_map));
548  importer_ = rcp (new import_type (srcMap, this->getMap ()));
549  }
550  else {
551  srcMap = importer_->getSourceMap ();
552  }
553 
554  if ( distribution != CONTIGUOUS_AND_ROOTED ) {
555  // Use View scalar type, not MV Scalar because we want Kokkos::complex, not
556  // std::complex to avoid a Kokkos::complex<double> to std::complex<float>
557  // conversion which would require a double copy and fail here. Then we'll be
558  // setup to safely reinterpret_cast complex to std if necessary.
559  typedef typename multivec_t::dual_view_type::t_host::value_type tpetra_mv_view_type;
560  Kokkos::View<tpetra_mv_view_type**,typename KV::array_layout,
561  Kokkos::HostSpace> convert_kokkos_new_data;
562  deep_copy_or_assign_view(convert_kokkos_new_data, kokkos_new_data);
563 #ifdef HAVE_TEUCHOS_COMPLEX
564  // convert_kokkos_new_data may be Kokkos::complex and Scalar could be std::complex
565  auto pData = reinterpret_cast<Scalar*>(convert_kokkos_new_data.data());
566 #else
567  auto pData = convert_kokkos_new_data.data();
568 #endif
569 
570  const multivec_t source_mv (srcMap, Teuchos::ArrayView<const scalar_t>(
571  pData, kokkos_new_data.size()), lda, num_vecs);
572  mv_->doImport (source_mv, *importer_, Tpetra::REPLACE);
573  }
574  else {
575  multivec_t redist_mv (srcMap, num_vecs); // unused for ROOTED case
576  typedef typename multivec_t::dual_view_type dual_view_type;
577  typedef typename dual_view_type::host_mirror_space host_execution_space;
578  redist_mv.template modify< host_execution_space > ();
579 
580  // Cuda solvers won't currently use this path since they are just serial
581  // right now, so this mirror should be harmless (and not strictly necessary).
582  // Adding it for future possibilities though we may then refactor this
583  // for better efficiency if the kokkos_new_data view is on device.
584  auto host_kokkos_new_data = Kokkos::create_mirror_view(kokkos_new_data);
585  Kokkos::deep_copy(host_kokkos_new_data, kokkos_new_data);
586  if ( redist_mv.isConstantStride() ) {
587  auto contig_local_view_2d = redist_mv.template getLocalView<host_execution_space>();
588  for ( size_t j = 0; j < num_vecs; ++j) {
589  auto av_j = Kokkos::subview(host_kokkos_new_data, Kokkos::ALL, j);
590  for ( size_t i = 0; i < lda; ++i ) {
591  contig_local_view_2d(i,j) = av_j(i);
592  }
593  }
594  }
595  else {
596  TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, "Kokkos adapter "
597  "CONTIGUOUS_AND_ROOTED not implemented for put1dData_kokkos_view "
598  "with non constant stride.");
599  }
600 
601  typedef typename multivec_t::node_type::memory_space memory_space;
602  redist_mv.template sync <memory_space> ();
603 
604  mv_->doImport (redist_mv, *importer_, Tpetra::REPLACE);
605  }
606  }
607 
608  }
609 
610  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node >
611  std::string
612  MultiVecAdapter<
613  MultiVector<Scalar,
614  LocalOrdinal,
615  GlobalOrdinal,
616  Node> >::description() const
617  {
618  std::ostringstream oss;
619  oss << "Amesos2 adapter wrapping: ";
620  oss << mv_->description();
621  return oss.str();
622  }
623 
624 
625  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node >
626  void
627  MultiVecAdapter<
628  MultiVector<Scalar,
629  LocalOrdinal,
630  GlobalOrdinal,
631  Node> >::describe (Teuchos::FancyOStream& os,
632  const Teuchos::EVerbosityLevel verbLevel) const
633  {
634  mv_->describe (os, verbLevel);
635  }
636 
637 
638  template <typename Scalar, typename LocalOrdinal, typename GlobalOrdinal, class Node >
639  const char* MultiVecAdapter<
640  MultiVector<Scalar,
641  LocalOrdinal,
642  GlobalOrdinal,
643  Node> >::name = "Amesos2 adapter for Tpetra::MultiVector";
644 
645 } // end namespace Amesos2
646 
647 #endif // AMESOS2_TPETRA_MULTIVEC_ADAPTER_DEF_HPP
Copy or assign views based on memory spaces.
Amesos2::MultiVecAdapter specialization for the Tpetra::MultiVector class.
EDistribution
Definition: Amesos2_TypeDecl.hpp:123