Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_XpetraMultiVectorAdapter.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Zoltan2: A package of combinatorial algorithms for scientific computing
6 // Copyright 2012 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 Karen Devine (kddevin@sandia.gov)
39 // Erik Boman (egboman@sandia.gov)
40 // Siva Rajamanickam (srajama@sandia.gov)
41 //
42 // ***********************************************************************
43 //
44 // @HEADER
45 
50 #ifndef _ZOLTAN2_XPETRAMULTIVECTORADAPTER_HPP_
51 #define _ZOLTAN2_XPETRAMULTIVECTORADAPTER_HPP_
52 
53 #include <Zoltan2_XpetraTraits.hpp>
55 #include <Zoltan2_StridedData.hpp>
57 
58 #if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
59 #include <Xpetra_EpetraMultiVector.hpp>
60 #endif
61 #include <Xpetra_TpetraMultiVector.hpp>
62 
63 namespace Zoltan2 {
64 
82 template <typename User>
83  class XpetraMultiVectorAdapter : public VectorAdapter<User> {
84 public:
85 
86 #ifndef DOXYGEN_SHOULD_SKIP_THIS
87  typedef typename InputTraits<User>::scalar_t scalar_t;
88  typedef typename InputTraits<User>::lno_t lno_t;
89  typedef typename InputTraits<User>::gno_t gno_t;
90  typedef typename InputTraits<User>::part_t part_t;
91  typedef typename InputTraits<User>::node_t node_t;
92  typedef User user_t;
93  typedef User userCoord_t;
94 
95  typedef Xpetra::MultiVector<scalar_t, lno_t, gno_t, node_t> x_mvector_t;
96  typedef Xpetra::TpetraMultiVector<
97  scalar_t, lno_t, gno_t, node_t> xt_mvector_t;
98 #endif
99 
115  XpetraMultiVectorAdapter(const RCP<const User> &invector,
116  std::vector<const scalar_t *> &weights, std::vector<int> &weightStrides);
117 
123  XpetraMultiVectorAdapter(const RCP<const User> &invector);
124 
125 
127  // The Adapter interface.
129 
130  size_t getLocalNumIDs() const { return vector_->getLocalLength();}
131 
132  void getIDsView(const gno_t *&ids) const
133  {
134  ids = map_->getLocalElementList().getRawPtr();
135  }
136 
138  Kokkos::View<const gno_t *, typename node_t::device_type> &ids) const {
139  if (map_->lib() == Xpetra::UseTpetra) {
140  using device_type = typename node_t::device_type;
141  const xt_mvector_t *tvector =
142  dynamic_cast<const xt_mvector_t *>(vector_.get());
143  // MJ can be running Host, CudaSpace, or CudaUVMSpace while Map now
144  // internally never stores CudaUVMSpace so we may need a conversion.
145  // However Map stores both Host and CudaSpace so this could be improved
146  // if device_type was CudaSpace. Then we could add a new accessor to
147  // Map such as getMyGlobalIndicesDevice() which could be direct assigned
148  // here. Since Tpetra is still UVM dependent that is not going to happen
149  // yet so just leaving this as Host to device_type conversion for now.
150  ids = Kokkos::create_mirror_view_and_copy(device_type(),
151  tvector->getTpetra_MultiVector()->getMap()->getMyGlobalIndices());
152  }
153  else if (map_->lib() == Xpetra::UseEpetra) {
154 #if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
155  // this will call getIDsView to get raw ptr and create a view from it
157 #else
158  throw std::logic_error("Epetra requested, but Trilinos is not "
159  "built with Epetra");
160 #endif
161  }
162  else {
163  throw std::logic_error("getIDsKokkosView called but not on Tpetra or Epetra!");
164  }
165  }
166 
167  int getNumWeightsPerID() const { return numWeights_;}
168 
169  void getWeightsView(const scalar_t *&weights, int &stride, int idx) const
170  {
171  if(idx<0 || idx >= numWeights_)
172  {
173  std::ostringstream emsg;
174  emsg << __FILE__ << ":" << __LINE__
175  << " Invalid weight index " << idx << std::endl;
176  throw std::runtime_error(emsg.str());
177  }
178 
179  size_t length;
180  weights_[idx].getStridedList(length, weights, stride);
181  }
182 
183  void getWeightsKokkos2dView(Kokkos::View<scalar_t **,
184  typename node_t::device_type> &wgt) const {
185  typedef Kokkos::View<scalar_t**, typename node_t::device_type> view_t;
186  wgt = view_t("wgts", vector_->getLocalLength(), numWeights_);
187  typename view_t::HostMirror host_wgt = Kokkos::create_mirror_view(wgt);
188  for(int idx = 0; idx < numWeights_; ++idx) {
189  const scalar_t * weights;
190  size_t length;
191  int stride;
192  weights_[idx].getStridedList(length, weights, stride);
193  size_t fill_index = 0;
194  for(size_t n = 0; n < length; n += stride) {
195  host_wgt(fill_index++,idx) = weights[n];
196  }
197  }
198  Kokkos::deep_copy(wgt, host_wgt);
199  }
200 
202  // The VectorAdapter interface.
204 
205  int getNumEntriesPerID() const {return vector_->getNumVectors();}
206 
207  void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const;
208 
210  // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
211  Kokkos::View<scalar_t **, Kokkos::LayoutLeft,
212  typename node_t::device_type> & elements) const;
213 
214  template <typename Adapter>
215  void applyPartitioningSolution(const User &in, User *&out,
216  const PartitioningSolution<Adapter> &solution) const;
217 
218  template <typename Adapter>
219  void applyPartitioningSolution(const User &in, RCP<User> &out,
220  const PartitioningSolution<Adapter> &solution) const;
221 
222 private:
223 
224  RCP<const User> invector_;
225  RCP<const x_mvector_t> vector_;
226  RCP<const Xpetra::Map<lno_t, gno_t, node_t> > map_;
227 
228  int numWeights_;
229  ArrayRCP<StridedData<lno_t, scalar_t> > weights_;
230 };
231 
233 // Definitions
235 
236 template <typename User>
238  const RCP<const User> &invector,
239  std::vector<const scalar_t *> &weights, std::vector<int> &weightStrides):
240  invector_(invector), vector_(), map_(),
241  numWeights_(weights.size()), weights_(weights.size())
242 {
243  typedef StridedData<lno_t, scalar_t> input_t;
244 
245  try {
246  RCP<x_mvector_t> tmp =
247  XpetraTraits<User>::convertToXpetra(rcp_const_cast<User>(invector));
248  vector_ = rcp_const_cast<const x_mvector_t>(tmp);
249  }
251 
252  map_ = vector_->getMap();
253 
254  size_t length = vector_->getLocalLength();
255 
256  if (length > 0 && numWeights_ > 0){
257  int stride = 1;
258  for (int w=0; w < numWeights_; w++){
259  if (weightStrides.size())
260  stride = weightStrides[w];
261  ArrayRCP<const scalar_t> wgtV(weights[w], 0, stride*length, false);
262  weights_[w] = input_t(wgtV, stride);
263  }
264  }
265 }
266 
267 
269 template <typename User>
271  const RCP<const User> &invector):
272  invector_(invector), vector_(), map_(),
273  numWeights_(0), weights_()
274 {
275  try {
276  RCP<x_mvector_t> tmp =
277  XpetraTraits<User>::convertToXpetra(rcp_const_cast<User>(invector));
278  vector_ = rcp_const_cast<const x_mvector_t>(tmp);
279  }
281 
282  map_ = vector_->getMap();
283 }
284 
286 template <typename User>
288  const scalar_t *&elements, int &stride, int idx) const
289 {
290  size_t vecsize;
291  stride = 1;
292  elements = NULL;
293  if (map_->lib() == Xpetra::UseTpetra){
294  const xt_mvector_t *tvector =
295  dynamic_cast<const xt_mvector_t *>(vector_.get());
296 
297  vecsize = tvector->getLocalLength();
298  if (vecsize > 0){
299  ArrayRCP<const scalar_t> data = tvector->getData(idx);
300  elements = data.get();
301  }
302  }
303  else if (map_->lib() == Xpetra::UseEpetra){
304 #if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
305  typedef Xpetra::EpetraMultiVectorT<gno_t,node_t> xe_mvector_t;
306  const xe_mvector_t *evector =
307  dynamic_cast<const xe_mvector_t *>(vector_.get());
308 
309  vecsize = evector->getLocalLength();
310  if (vecsize > 0){
311  ArrayRCP<const double> data = evector->getData(idx);
312 
313  // Cast so this will compile when scalar_t is not double,
314  // a case when this code should never execute.
315  elements = reinterpret_cast<const scalar_t *>(data.get());
316  }
317 #else
318  throw std::logic_error("Epetra requested, but Trilinos is not "
319  "built with Epetra");
320 #endif
321  }
322  else{
323  throw std::logic_error("invalid underlying lib");
324  }
325 }
326 
328 template <typename User>
330  // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
331  Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type> & elements) const
332 {
333  if (map_->lib() == Xpetra::UseTpetra){
334  const xt_mvector_t *tvector =
335  dynamic_cast<const xt_mvector_t *>(vector_.get());
336  // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
337  Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type> view2d =
338  tvector->getTpetra_MultiVector()->template getLocalView<typename node_t::device_type>(Tpetra::Access::ReadWrite);
339  elements = view2d;
340  // CMS/KDD: Look at this stuff right here. Compare against a non-cuda build OR, look at core/driver/driverinputs/kuberry/kuberry.coords
341  // Ca try changing the kuberry.xml to use "input adapter" "BasicVector" rather than "XpetraMultiVector"
342 
343  }
344  else if (map_->lib() == Xpetra::UseEpetra){
345 #if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
346  typedef Xpetra::EpetraMultiVectorT<gno_t,node_t> xe_mvector_t;
347  const xe_mvector_t *evector =
348  dynamic_cast<const xe_mvector_t *>(vector_.get());
349  elements =
350  Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type>
351  ("elements", evector->getLocalLength(), evector->getNumVectors());
352  if(evector->getLocalLength() > 0) {
353  for(size_t idx = 0; idx < evector->getNumVectors(); ++idx) {
354  const scalar_t * ptr;
355  int stride;
356  getEntriesView(ptr, stride, idx);
357  for(size_t n = 0; n < evector->getLocalLength(); ++n) {
358  elements(n, idx) = ptr[n];
359  }
360  }
361  }
362 #else
363  throw std::logic_error("Epetra requested, but Trilinos is not "
364  "built with Epetra");
365 #endif
366  }
367  else {
368  throw std::logic_error("getEntriesKokkosView called but not using Tpetra or Epetra!");
369  }
370 }
371 
373 template <typename User>
374  template <typename Adapter>
376  const User &in, User *&out,
377  const PartitioningSolution<Adapter> &solution) const
378 {
379  // Get an import list (rows to be received)
380  size_t numNewRows;
381  ArrayRCP<gno_t> importList;
382  try{
383  numNewRows = Zoltan2::getImportList<Adapter,
385  (solution, this, importList);
386  }
388 
389  // Move the rows, creating a new vector.
390  RCP<User> outPtr = XpetraTraits<User>::doMigration(in, numNewRows,
391  importList.getRawPtr());
392  out = outPtr.get();
393  outPtr.release();
394 }
395 
397 template <typename User>
398  template <typename Adapter>
400  const User &in, RCP<User> &out,
401  const PartitioningSolution<Adapter> &solution) const
402 {
403  // Get an import list (rows to be received)
404  size_t numNewRows;
405  ArrayRCP<gno_t> importList;
406  try{
407  numNewRows = Zoltan2::getImportList<Adapter,
409  (solution, this, importList);
410  }
412 
413  // Move the rows, creating a new vector.
414  out = XpetraTraits<User>::doMigration(in, numNewRows,
415  importList.getRawPtr());
416 }
417 
418 } //namespace Zoltan2
419 
420 #endif
Helper functions for Partitioning Problems.
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
static ArrayRCP< ArrayRCP< zscalar_t > > weights
default_part_t part_t
The data type to represent part numbers.
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:18
XpetraMultiVectorAdapter(const RCP< const User > &invector, std::vector< const scalar_t * > &weights, std::vector< int > &weightStrides)
Constructor.
Defines the VectorAdapter interface.
static RCP< User > doMigration(const User &from, size_t numLocalRows, const gno_t *myNewRows)
Migrate the object Given a user object and a new row distribution, create and return a new user objec...
typename Zoltan2::InputTraits< ztcrsmatrix_t >::node_t node_t
Traits of Xpetra classes, including migration method.
typename InputTraits< User >::part_t part_t
void getIDsKokkosView(Kokkos::View< const gno_t *, typename node_t::device_type > &ids) const
static RCP< User > convertToXpetra(const RCP< User > &a)
Convert the object to its Xpetra wrapped version.
size_t getImportList(const PartitioningSolution< SolutionAdapter > &solution, const DataAdapter *const data, ArrayRCP< typename DataAdapter::gno_t > &imports)
From a PartitioningSolution, get a list of IDs to be imported. Assumes part numbers in PartitioningSo...
virtual void getIDsKokkosView(ConstIdsDeviceView &ids) const
Provide a Kokkos view to this process&#39; identifiers.
int getNumEntriesPerID() const
Return the number of vectors.
typename InputTraits< User >::node_t node_t
A PartitioningSolution is a solution to a partitioning problem.
typename InputTraits< User >::gno_t gno_t
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
default_lno_t lno_t
The ordinal type (e.g., int, long, int64_t) that represents local counts and local indices...
VectorAdapter defines the interface for vector input.
The StridedData class manages lists of weights or coordinates.
void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const
Provide a pointer to the elements of the specified vector.
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater...
An adapter for Xpetra::MultiVector.
default_gno_t gno_t
The ordinal type (e.g., int, long, int64_t) that can represent global counts and identifiers.
default_node_t node_t
The Kokkos node type. This is only meaningful for users of Tpetra objects.
void getWeightsKokkos2dView(Kokkos::View< scalar_t **, typename node_t::device_type > &wgt) const
size_t getLocalNumIDs() const
Returns the number of objects on this process.
typename BaseAdapter< User >::scalar_t scalar_t
typename InputTraits< User >::lno_t lno_t
default_scalar_t scalar_t
The data type for weights and coordinates.
void getWeightsView(const scalar_t *&weights, int &stride, int idx) const
Provide pointer to a weight array with stride.
void getEntriesKokkosView(Kokkos::View< scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type > &elements) const
This file defines the StridedData class.
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition: Metric.cpp:74