Zoltan2
Loading...
Searching...
No Matches
Zoltan2_XpetraMultiVectorAdapter.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Zoltan2: A package of combinatorial algorithms for scientific computing
4//
5// Copyright 2012 NTESS and the Zoltan2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
14#ifndef _ZOLTAN2_XPETRAMULTIVECTORADAPTER_HPP_
15#define _ZOLTAN2_XPETRAMULTIVECTORADAPTER_HPP_
16
21
22#if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
23#include <Xpetra_EpetraMultiVector.hpp>
24#endif
25#include <Xpetra_TpetraMultiVector.hpp>
26
27namespace Zoltan2 {
28
46template <typename User>
48public:
49
50#ifndef DOXYGEN_SHOULD_SKIP_THIS
52 typedef typename InputTraits<User>::impl_scalar_t impl_scalar_t;
53 typedef typename InputTraits<User>::lno_t lno_t;
54 typedef typename InputTraits<User>::gno_t gno_t;
55 typedef typename InputTraits<User>::part_t part_t;
56 typedef typename InputTraits<User>::node_t node_t;
57 typedef User user_t;
58 typedef User userCoord_t;
59
60 typedef Xpetra::MultiVector<scalar_t, lno_t, gno_t, node_t> x_mvector_t;
61 typedef Xpetra::TpetraMultiVector<
62 scalar_t, lno_t, gno_t, node_t> xt_mvector_t;
63#endif
64
80 XpetraMultiVectorAdapter(const RCP<const User> &invector,
81 std::vector<const scalar_t *> &weights, std::vector<int> &weightStrides);
82
88 XpetraMultiVectorAdapter(const RCP<const User> &invector);
89
90
92 // The Adapter interface.
94
95 size_t getLocalNumIDs() const { return vector_->getLocalLength();}
96
97 void getIDsView(const gno_t *&ids) const
98 {
99 ids = map_->getLocalElementList().getRawPtr();
100 }
101
103 Kokkos::View<const gno_t *, typename node_t::device_type> &ids) const {
104 if (map_->lib() == Xpetra::UseTpetra) {
105 using device_type = typename node_t::device_type;
106 const xt_mvector_t *tvector =
107 dynamic_cast<const xt_mvector_t *>(vector_.get());
108 // MJ can be running Host, CudaSpace, or CudaUVMSpace while Map now
109 // internally never stores CudaUVMSpace so we may need a conversion.
110 // However Map stores both Host and CudaSpace so this could be improved
111 // if device_type was CudaSpace. Then we could add a new accessor to
112 // Map such as getMyGlobalIndicesDevice() which could be direct assigned
113 // here. Since Tpetra is still UVM dependent that is not going to happen
114 // yet so just leaving this as Host to device_type conversion for now.
115 ids = Kokkos::create_mirror_view_and_copy(device_type(),
116 tvector->getTpetra_MultiVector()->getMap()->getMyGlobalIndices());
117 }
118 else if (map_->lib() == Xpetra::UseEpetra) {
119#if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
120 // this will call getIDsView to get raw ptr and create a view from it
122#else
123 throw std::logic_error("Epetra requested, but Trilinos is not "
124 "built with Epetra");
125#endif
126 }
127 else {
128 throw std::logic_error("getIDsKokkosView called but not on Tpetra or Epetra!");
129 }
130 }
131
132 int getNumWeightsPerID() const { return numWeights_;}
133
134 void getWeightsView(const scalar_t *&weights, int &stride, int idx) const
135 {
136 if(idx<0 || idx >= numWeights_)
137 {
138 std::ostringstream emsg;
139 emsg << __FILE__ << ":" << __LINE__
140 << " Invalid weight index " << idx << std::endl;
141 throw std::runtime_error(emsg.str());
142 }
143
144 size_t length;
145 weights_[idx].getStridedList(length, weights, stride);
146 }
147
148 void getWeightsKokkos2dView(Kokkos::View<scalar_t **,
149 typename node_t::device_type> &wgt) const {
150 typedef Kokkos::View<scalar_t**, typename node_t::device_type> view_t;
151 wgt = view_t("wgts", vector_->getLocalLength(), numWeights_);
152 typename view_t::host_mirror_type host_wgt = Kokkos::create_mirror_view(wgt);
153 for(int idx = 0; idx < numWeights_; ++idx) {
154 const scalar_t * weights;
155 size_t length;
156 int stride;
157 weights_[idx].getStridedList(length, weights, stride);
158 size_t fill_index = 0;
159 for(size_t n = 0; n < length; n += stride) {
160 host_wgt(fill_index++,idx) = weights[n];
161 }
162 }
163 Kokkos::deep_copy(wgt, host_wgt);
164 }
165
167 // The VectorAdapter interface.
169
170 int getNumEntriesPerID() const {return vector_->getNumVectors();}
171
172 void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const;
173
175 // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
176 Kokkos::View<impl_scalar_t **, Kokkos::LayoutLeft,
177 typename node_t::device_type> & elements) const;
178
179 template <typename Adapter>
180 void applyPartitioningSolution(const User &in, User *&out,
181 const PartitioningSolution<Adapter> &solution) const;
182
183 template <typename Adapter>
184 void applyPartitioningSolution(const User &in, RCP<User> &out,
185 const PartitioningSolution<Adapter> &solution) const;
186
187private:
188
189 RCP<const User> invector_;
190 RCP<const x_mvector_t> vector_;
191 RCP<const Xpetra::Map<lno_t, gno_t, node_t> > map_;
192
193 int numWeights_;
194 ArrayRCP<StridedData<lno_t, scalar_t> > weights_;
195};
196
198// Definitions
200
201template <typename User>
203 const RCP<const User> &invector,
204 std::vector<const scalar_t *> &weights, std::vector<int> &weightStrides):
205 invector_(invector), vector_(), map_(),
206 numWeights_(weights.size()), weights_(weights.size())
207{
208 typedef StridedData<lno_t, scalar_t> input_t;
209
210 try {
211 RCP<x_mvector_t> tmp =
212 XpetraTraits<User>::convertToXpetra(rcp_const_cast<User>(invector));
213 vector_ = rcp_const_cast<const x_mvector_t>(tmp);
214 }
216
217 map_ = vector_->getMap();
218
219 size_t length = vector_->getLocalLength();
220
221 if (length > 0 && numWeights_ > 0){
222 int stride = 1;
223 for (int w=0; w < numWeights_; w++){
224 if (weightStrides.size())
225 stride = weightStrides[w];
226 ArrayRCP<const scalar_t> wgtV(weights[w], 0, stride*length, false);
227 weights_[w] = input_t(wgtV, stride);
228 }
229 }
230}
231
232
234template <typename User>
236 const RCP<const User> &invector):
237 invector_(invector), vector_(), map_(),
238 numWeights_(0), weights_()
239{
240 try {
241 RCP<x_mvector_t> tmp =
242 XpetraTraits<User>::convertToXpetra(rcp_const_cast<User>(invector));
243 vector_ = rcp_const_cast<const x_mvector_t>(tmp);
244 }
246
247 map_ = vector_->getMap();
248}
249
251template <typename User>
253 const scalar_t *&elements, int &stride, int idx) const
254{
255 size_t vecsize;
256 stride = 1;
257 elements = NULL;
258 if (map_->lib() == Xpetra::UseTpetra){
259 const xt_mvector_t *tvector =
260 dynamic_cast<const xt_mvector_t *>(vector_.get());
261
262 vecsize = tvector->getLocalLength();
263 if (vecsize > 0){
264 ArrayRCP<const scalar_t> data = tvector->getData(idx);
265 elements = data.get();
266 }
267 }
268 else if (map_->lib() == Xpetra::UseEpetra){
269#if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
270 typedef Xpetra::EpetraMultiVectorT<gno_t,node_t> xe_mvector_t;
271 const xe_mvector_t *evector =
272 dynamic_cast<const xe_mvector_t *>(vector_.get());
273
274 vecsize = evector->getLocalLength();
275 if (vecsize > 0){
276 ArrayRCP<const double> data = evector->getData(idx);
277
278 // Cast so this will compile when scalar_t is not double,
279 // a case when this code should never execute.
280 elements = reinterpret_cast<const scalar_t *>(data.get());
281 }
282#else
283 throw std::logic_error("Epetra requested, but Trilinos is not "
284 "built with Epetra");
285#endif
286 }
287 else{
288 throw std::logic_error("invalid underlying lib");
289 }
290}
291
293template <typename User>
295 // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
296 Kokkos::View<impl_scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type> & elements) const
297{
298 if (map_->lib() == Xpetra::UseTpetra){
299 const xt_mvector_t *tvector =
300 dynamic_cast<const xt_mvector_t *>(vector_.get());
301 // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
302 auto view2d =
303 tvector->getTpetra_MultiVector()->template getLocalView<typename node_t::device_type>(Tpetra::Access::ReadWrite);
304 elements = view2d;
305 // CMS/KDD: Look at this stuff right here. Compare against a non-cuda build OR, look at core/driver/driverinputs/kuberry/kuberry.coords
306 // Ca try changing the kuberry.xml to use "input adapter" "BasicVector" rather than "XpetraMultiVector"
307
308 }
309 else if (map_->lib() == Xpetra::UseEpetra){
310#if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
311 typedef Xpetra::EpetraMultiVectorT<gno_t,node_t> xe_mvector_t;
312 const xe_mvector_t *evector =
313 dynamic_cast<const xe_mvector_t *>(vector_.get());
314 elements =
315 Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type>
316 ("elements", evector->getLocalLength(), evector->getNumVectors());
317 if(evector->getLocalLength() > 0) {
318 for(size_t idx = 0; idx < evector->getNumVectors(); ++idx) {
319 const scalar_t * ptr;
320 int stride;
321 getEntriesView(ptr, stride, idx);
322 for(size_t n = 0; n < evector->getLocalLength(); ++n) {
323 elements(n, idx) = ptr[n];
324 }
325 }
326 }
327#else
328 throw std::logic_error("Epetra requested, but Trilinos is not "
329 "built with Epetra");
330#endif
331 }
332 else {
333 throw std::logic_error("getEntriesKokkosView called but not using Tpetra or Epetra!");
334 }
335}
336
338template <typename User>
339 template <typename Adapter>
341 const User &in, User *&out,
342 const PartitioningSolution<Adapter> &solution) const
343{
344 // Get an import list (rows to be received)
345 size_t numNewRows;
346 ArrayRCP<gno_t> importList;
347 try{
348 numNewRows = Zoltan2::getImportList<Adapter,
350 (solution, this, importList);
351 }
353
354 // Move the rows, creating a new vector.
355 RCP<User> outPtr = XpetraTraits<User>::doMigration(in, numNewRows,
356 importList.getRawPtr());
357 out = outPtr.get();
358 outPtr.release();
359}
360
362template <typename User>
363 template <typename Adapter>
365 const User &in, RCP<User> &out,
366 const PartitioningSolution<Adapter> &solution) const
367{
368 // Get an import list (rows to be received)
369 size_t numNewRows;
370 ArrayRCP<gno_t> importList;
371 try{
372 numNewRows = Zoltan2::getImportList<Adapter,
374 (solution, this, importList);
375 }
377
378 // Move the rows, creating a new vector.
379 out = XpetraTraits<User>::doMigration(in, numNewRows,
380 importList.getRawPtr());
381}
382
383} //namespace Zoltan2
384
385#endif
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition Metric.cpp:39
typename Zoltan2::InputTraits< ztcrsmatrix_t >::node_t node_t
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
Helper functions for Partitioning Problems.
This file defines the StridedData class.
Defines the VectorAdapter interface.
Traits of Xpetra classes, including migration method.
typename BaseAdapter< User >::scalar_t scalar_t
typename InputTraits< User >::node_t node_t
typename InputTraits< User >::lno_t lno_t
virtual void getIDsKokkosView(ConstIdsDeviceView &ids) const
Provide a Kokkos view to this process' identifiers.
typename InputTraits< User >::gno_t gno_t
typename InputTraits< User >::part_t part_t
A PartitioningSolution is a solution to a partitioning problem.
The StridedData class manages lists of weights or coordinates.
VectorAdapter defines the interface for vector input.
void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const
Provide a pointer to the elements of the specified vector.
void applyPartitioningSolution(const User &in, User *&out, const PartitioningSolution< Adapter > &solution) const
void getWeightsKokkos2dView(Kokkos::View< scalar_t **, typename node_t::device_type > &wgt) const
XpetraMultiVectorAdapter(const RCP< const User > &invector, std::vector< const scalar_t * > &weights, std::vector< int > &weightStrides)
Constructor.
void getIDsKokkosView(Kokkos::View< const gno_t *, typename node_t::device_type > &ids) const
int getNumEntriesPerID() const
Return the number of vectors.
int getNumWeightsPerID() const
Returns the number of weights per object. Number of weights per object should be zero or greater....
void getWeightsView(const scalar_t *&weights, int &stride, int idx) const
void getEntriesKokkosView(Kokkos::View< impl_scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type > &elements) const
size_t getLocalNumIDs() const
Returns the number of objects on this process.
map_t::global_ordinal_type gno_t
Created by mbenlioglu on Aug 31, 2020.
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...
static ArrayRCP< ArrayRCP< zscalar_t > > weights
The traits required of User input classes or structures.
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.
default_lno_t lno_t
The ordinal type (e.g., int, long, int64_t) that represents local counts and local indices.
default_part_t part_t
The data type to represent part numbers.
default_scalar_t scalar_t
The data type for weights and coordinates.
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...
static RCP< User > convertToXpetra(const RCP< User > &a)
Convert the object to its Xpetra wrapped version.