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>::lno_t lno_t;
53 typedef typename InputTraits<User>::gno_t gno_t;
54 typedef typename InputTraits<User>::part_t part_t;
55 typedef typename InputTraits<User>::node_t node_t;
56 typedef User user_t;
57 typedef User userCoord_t;
58
59 typedef Xpetra::MultiVector<scalar_t, lno_t, gno_t, node_t> x_mvector_t;
60 typedef Xpetra::TpetraMultiVector<
61 scalar_t, lno_t, gno_t, node_t> xt_mvector_t;
62#endif
63
79 XpetraMultiVectorAdapter(const RCP<const User> &invector,
80 std::vector<const scalar_t *> &weights, std::vector<int> &weightStrides);
81
87 XpetraMultiVectorAdapter(const RCP<const User> &invector);
88
89
91 // The Adapter interface.
93
94 size_t getLocalNumIDs() const { return vector_->getLocalLength();}
95
96 void getIDsView(const gno_t *&ids) const
97 {
98 ids = map_->getLocalElementList().getRawPtr();
99 }
100
102 Kokkos::View<const gno_t *, typename node_t::device_type> &ids) const {
103 if (map_->lib() == Xpetra::UseTpetra) {
104 using device_type = typename node_t::device_type;
105 const xt_mvector_t *tvector =
106 dynamic_cast<const xt_mvector_t *>(vector_.get());
107 // MJ can be running Host, CudaSpace, or CudaUVMSpace while Map now
108 // internally never stores CudaUVMSpace so we may need a conversion.
109 // However Map stores both Host and CudaSpace so this could be improved
110 // if device_type was CudaSpace. Then we could add a new accessor to
111 // Map such as getMyGlobalIndicesDevice() which could be direct assigned
112 // here. Since Tpetra is still UVM dependent that is not going to happen
113 // yet so just leaving this as Host to device_type conversion for now.
114 ids = Kokkos::create_mirror_view_and_copy(device_type(),
115 tvector->getTpetra_MultiVector()->getMap()->getMyGlobalIndices());
116 }
117 else if (map_->lib() == Xpetra::UseEpetra) {
118#if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
119 // this will call getIDsView to get raw ptr and create a view from it
121#else
122 throw std::logic_error("Epetra requested, but Trilinos is not "
123 "built with Epetra");
124#endif
125 }
126 else {
127 throw std::logic_error("getIDsKokkosView called but not on Tpetra or Epetra!");
128 }
129 }
130
131 int getNumWeightsPerID() const { return numWeights_;}
132
133 void getWeightsView(const scalar_t *&weights, int &stride, int idx) const
134 {
135 if(idx<0 || idx >= numWeights_)
136 {
137 std::ostringstream emsg;
138 emsg << __FILE__ << ":" << __LINE__
139 << " Invalid weight index " << idx << std::endl;
140 throw std::runtime_error(emsg.str());
141 }
142
143 size_t length;
144 weights_[idx].getStridedList(length, weights, stride);
145 }
146
147 void getWeightsKokkos2dView(Kokkos::View<scalar_t **,
148 typename node_t::device_type> &wgt) const {
149 typedef Kokkos::View<scalar_t**, typename node_t::device_type> view_t;
150 wgt = view_t("wgts", vector_->getLocalLength(), numWeights_);
151 typename view_t::host_mirror_type host_wgt = Kokkos::create_mirror_view(wgt);
152 for(int idx = 0; idx < numWeights_; ++idx) {
153 const scalar_t * weights;
154 size_t length;
155 int stride;
156 weights_[idx].getStridedList(length, weights, stride);
157 size_t fill_index = 0;
158 for(size_t n = 0; n < length; n += stride) {
159 host_wgt(fill_index++,idx) = weights[n];
160 }
161 }
162 Kokkos::deep_copy(wgt, host_wgt);
163 }
164
166 // The VectorAdapter interface.
168
169 int getNumEntriesPerID() const {return vector_->getNumVectors();}
170
171 void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const;
172
174 // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
175 Kokkos::View<scalar_t **, Kokkos::LayoutLeft,
176 typename node_t::device_type> & elements) const;
177
178 template <typename Adapter>
179 void applyPartitioningSolution(const User &in, User *&out,
180 const PartitioningSolution<Adapter> &solution) const;
181
182 template <typename Adapter>
183 void applyPartitioningSolution(const User &in, RCP<User> &out,
184 const PartitioningSolution<Adapter> &solution) const;
185
186private:
187
188 RCP<const User> invector_;
189 RCP<const x_mvector_t> vector_;
190 RCP<const Xpetra::Map<lno_t, gno_t, node_t> > map_;
191
192 int numWeights_;
193 ArrayRCP<StridedData<lno_t, scalar_t> > weights_;
194};
195
197// Definitions
199
200template <typename User>
202 const RCP<const User> &invector,
203 std::vector<const scalar_t *> &weights, std::vector<int> &weightStrides):
204 invector_(invector), vector_(), map_(),
205 numWeights_(weights.size()), weights_(weights.size())
206{
207 typedef StridedData<lno_t, scalar_t> input_t;
208
209 try {
210 RCP<x_mvector_t> tmp =
211 XpetraTraits<User>::convertToXpetra(rcp_const_cast<User>(invector));
212 vector_ = rcp_const_cast<const x_mvector_t>(tmp);
213 }
215
216 map_ = vector_->getMap();
217
218 size_t length = vector_->getLocalLength();
219
220 if (length > 0 && numWeights_ > 0){
221 int stride = 1;
222 for (int w=0; w < numWeights_; w++){
223 if (weightStrides.size())
224 stride = weightStrides[w];
225 ArrayRCP<const scalar_t> wgtV(weights[w], 0, stride*length, false);
226 weights_[w] = input_t(wgtV, stride);
227 }
228 }
229}
230
231
233template <typename User>
235 const RCP<const User> &invector):
236 invector_(invector), vector_(), map_(),
237 numWeights_(0), weights_()
238{
239 try {
240 RCP<x_mvector_t> tmp =
241 XpetraTraits<User>::convertToXpetra(rcp_const_cast<User>(invector));
242 vector_ = rcp_const_cast<const x_mvector_t>(tmp);
243 }
245
246 map_ = vector_->getMap();
247}
248
250template <typename User>
252 const scalar_t *&elements, int &stride, int idx) const
253{
254 size_t vecsize;
255 stride = 1;
256 elements = NULL;
257 if (map_->lib() == Xpetra::UseTpetra){
258 const xt_mvector_t *tvector =
259 dynamic_cast<const xt_mvector_t *>(vector_.get());
260
261 vecsize = tvector->getLocalLength();
262 if (vecsize > 0){
263 ArrayRCP<const scalar_t> data = tvector->getData(idx);
264 elements = data.get();
265 }
266 }
267 else if (map_->lib() == Xpetra::UseEpetra){
268#if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
269 typedef Xpetra::EpetraMultiVectorT<gno_t,node_t> xe_mvector_t;
270 const xe_mvector_t *evector =
271 dynamic_cast<const xe_mvector_t *>(vector_.get());
272
273 vecsize = evector->getLocalLength();
274 if (vecsize > 0){
275 ArrayRCP<const double> data = evector->getData(idx);
276
277 // Cast so this will compile when scalar_t is not double,
278 // a case when this code should never execute.
279 elements = reinterpret_cast<const scalar_t *>(data.get());
280 }
281#else
282 throw std::logic_error("Epetra requested, but Trilinos is not "
283 "built with Epetra");
284#endif
285 }
286 else{
287 throw std::logic_error("invalid underlying lib");
288 }
289}
290
292template <typename User>
294 // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
295 Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type> & elements) const
296{
297 if (map_->lib() == Xpetra::UseTpetra){
298 const xt_mvector_t *tvector =
299 dynamic_cast<const xt_mvector_t *>(vector_.get());
300 // coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
301 Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type> view2d =
302 tvector->getTpetra_MultiVector()->template getLocalView<typename node_t::device_type>(Tpetra::Access::ReadWrite);
303 elements = view2d;
304 // CMS/KDD: Look at this stuff right here. Compare against a non-cuda build OR, look at core/driver/driverinputs/kuberry/kuberry.coords
305 // Ca try changing the kuberry.xml to use "input adapter" "BasicVector" rather than "XpetraMultiVector"
306
307 }
308 else if (map_->lib() == Xpetra::UseEpetra){
309#if defined(HAVE_ZOLTAN2_EPETRA) && defined(HAVE_XPETRA_EPETRA)
310 typedef Xpetra::EpetraMultiVectorT<gno_t,node_t> xe_mvector_t;
311 const xe_mvector_t *evector =
312 dynamic_cast<const xe_mvector_t *>(vector_.get());
313 elements =
314 Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type>
315 ("elements", evector->getLocalLength(), evector->getNumVectors());
316 if(evector->getLocalLength() > 0) {
317 for(size_t idx = 0; idx < evector->getNumVectors(); ++idx) {
318 const scalar_t * ptr;
319 int stride;
320 getEntriesView(ptr, stride, idx);
321 for(size_t n = 0; n < evector->getLocalLength(); ++n) {
322 elements(n, idx) = ptr[n];
323 }
324 }
325 }
326#else
327 throw std::logic_error("Epetra requested, but Trilinos is not "
328 "built with Epetra");
329#endif
330 }
331 else {
332 throw std::logic_error("getEntriesKokkosView called but not using Tpetra or Epetra!");
333 }
334}
335
337template <typename User>
338 template <typename Adapter>
340 const User &in, User *&out,
341 const PartitioningSolution<Adapter> &solution) const
342{
343 // Get an import list (rows to be received)
344 size_t numNewRows;
345 ArrayRCP<gno_t> importList;
346 try{
347 numNewRows = Zoltan2::getImportList<Adapter,
349 (solution, this, importList);
350 }
352
353 // Move the rows, creating a new vector.
354 RCP<User> outPtr = XpetraTraits<User>::doMigration(in, numNewRows,
355 importList.getRawPtr());
356 out = outPtr.get();
357 outPtr.release();
358}
359
361template <typename User>
362 template <typename Adapter>
364 const User &in, RCP<User> &out,
365 const PartitioningSolution<Adapter> &solution) const
366{
367 // Get an import list (rows to be received)
368 size_t numNewRows;
369 ArrayRCP<gno_t> importList;
370 try{
371 numNewRows = Zoltan2::getImportList<Adapter,
373 (solution, this, importList);
374 }
376
377 // Move the rows, creating a new vector.
378 out = XpetraTraits<User>::doMigration(in, numNewRows,
379 importList.getRawPtr());
380}
381
382} //namespace Zoltan2
383
384#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
void getEntriesKokkosView(Kokkos::View< scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type > &elements) const
Provide a Kokkos view to the elements of the specified vector.
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
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
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.