Skip to content

Commit 66e3ed1

Browse files
meriadegpmperrinel
authored andcommitted
46: Created TpetraMultiVectorAdapter
1 parent 35b8f66 commit 66e3ed1

File tree

3 files changed

+890
-0
lines changed

3 files changed

+890
-0
lines changed
Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
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 ([email protected])
39+
// Erik Boman ([email protected])
40+
// Siva Rajamanickam ([email protected])
41+
//
42+
// ***********************************************************************
43+
//
44+
// @HEADER
45+
46+
/*! \file Zoltan2_TpetraMultiVectorAdapter.hpp
47+
\brief Defines the TpetraMultiVectorAdapter
48+
*/
49+
50+
#ifndef _ZOLTAN2_TPETRAMULTIVECTORADAPTER_HPP_
51+
#define _ZOLTAN2_TPETRAMULTIVECTORADAPTER_HPP_
52+
53+
#include <Zoltan2_VectorAdapter.hpp>
54+
#include <Zoltan2_StridedData.hpp>
55+
#include <Zoltan2_PartitioningHelpers.hpp>
56+
57+
namespace Zoltan2 {
58+
59+
/*! \brief An adapter for Tpetra::MultiVector.
60+
61+
The template parameter is the user's input object:
62+
\li \c Tpetra::MultiVector
63+
64+
The \c scalar_t type, representing use data such as vector values, is
65+
used by Zoltan2 for weights, coordinates, part sizes and
66+
quality metrics.
67+
Some User types (like Tpetra::CrsMatrix) have an inherent scalar type,
68+
and some
69+
(like Tpetra::CrsGraph) do not. For such objects, the scalar type is
70+
set by Zoltan2 to \c float. If you wish to change it to double, set
71+
the second template parameter to \c double.
72+
*/
73+
74+
template <typename User>
75+
class TpetraMultiVectorAdapter : public VectorAdapter<User> {
76+
public:
77+
78+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
79+
typedef typename InputTraits<User>::scalar_t scalar_t;
80+
typedef typename InputTraits<User>::lno_t lno_t;
81+
typedef typename InputTraits<User>::gno_t gno_t;
82+
typedef typename InputTraits<User>::part_t part_t;
83+
typedef typename InputTraits<User>::node_t node_t;
84+
typedef User user_t;
85+
typedef User userCoord_t;
86+
87+
typedef Tpetra::MultiVector<scalar_t, lno_t, gno_t, node_t> t_mvector_t;
88+
#endif
89+
90+
/*! \brief Constructor
91+
*
92+
* \param invector the user's Tpetra MultiVector object
93+
* \param weights a list of pointers to arrays of weights.
94+
* The number of weights per multivector element is assumed to be
95+
* \c weights.size().
96+
* \param weightStrides a list of strides for the \c weights.
97+
* The weight for weight index \c n for multivector element
98+
* \c k should be found at <tt>weights[n][weightStrides[n] * k]</tt>.
99+
* If \c weightStrides.size() is zero, it is assumed all strides are one.
100+
*
101+
* The values pointed to the arguments must remain valid for the
102+
* lifetime of this Adapter.
103+
*/
104+
105+
TpetraMultiVectorAdapter(const RCP<const User> &invector,
106+
std::vector<const scalar_t *> &weights, std::vector<int> &weightStrides);
107+
108+
/*! \brief Constructor for case when weights are not being used.
109+
*
110+
* \param invector the user's Tpetra MultiVector object
111+
*/
112+
113+
TpetraMultiVectorAdapter(const RCP<const User> &invector);
114+
115+
116+
////////////////////////////////////////////////////
117+
// The Adapter interface.
118+
////////////////////////////////////////////////////
119+
120+
size_t getLocalNumIDs() const { return vector_->getLocalLength();}
121+
122+
void getIDsView(const gno_t *&ids) const
123+
{
124+
ids = map_->getLocalElementList().getRawPtr();
125+
}
126+
127+
void getIDsKokkosView(
128+
Kokkos::View<const gno_t *, typename node_t::device_type> &ids) const {
129+
using device_type = typename node_t::device_type;
130+
// MJ can be running Host, CudaSpace, or CudaUVMSpace while Map now
131+
// internally never stores CudaUVMSpace so we may need a conversion.
132+
// However Map stores both Host and CudaSpace so this could be improved
133+
// if device_type was CudaSpace. Then we could add a new accessor to
134+
// Map such as getMyGlobalIndicesDevice() which could be direct assigned
135+
// here. Since Tpetra is still UVM dependent that is not going to happen
136+
// yet so just leaving this as Host to device_type conversion for now.
137+
ids = Kokkos::create_mirror_view_and_copy(device_type(),
138+
map_->getMyGlobalIndices());
139+
}
140+
141+
int getNumWeightsPerID() const { return numWeights_;}
142+
143+
void getWeightsView(const scalar_t *&weights, int &stride, int idx) const
144+
{
145+
if(idx<0 || idx >= numWeights_)
146+
{
147+
std::ostringstream emsg;
148+
emsg << __FILE__ << ":" << __LINE__
149+
<< " Invalid weight index " << idx << std::endl;
150+
throw std::runtime_error(emsg.str());
151+
}
152+
153+
size_t length;
154+
weights_[idx].getStridedList(length, weights, stride);
155+
}
156+
157+
void getWeightsKokkos2dView(Kokkos::View<scalar_t **,
158+
typename node_t::device_type> &wgt) const {
159+
typedef Kokkos::View<scalar_t**, typename node_t::device_type> view_t;
160+
wgt = view_t("wgts", vector_->getLocalLength(), numWeights_);
161+
typename view_t::HostMirror host_wgt = Kokkos::create_mirror_view(wgt);
162+
for(int idx = 0; idx < numWeights_; ++idx) {
163+
const scalar_t * weights;
164+
size_t length;
165+
int stride;
166+
weights_[idx].getStridedList(length, weights, stride);
167+
size_t fill_index = 0;
168+
for(size_t n = 0; n < length; n += stride) {
169+
host_wgt(fill_index++,idx) = weights[n];
170+
}
171+
}
172+
Kokkos::deep_copy(wgt, host_wgt);
173+
}
174+
175+
////////////////////////////////////////////////////
176+
// The VectorAdapter interface.
177+
////////////////////////////////////////////////////
178+
179+
int getNumEntriesPerID() const {return vector_->getNumVectors();}
180+
181+
void getEntriesView(const scalar_t *&elements, int &stride, int idx=0) const;
182+
183+
void getEntriesKokkosView(
184+
// coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
185+
Kokkos::View<scalar_t **, Kokkos::LayoutLeft,
186+
typename node_t::device_type> & elements) const;
187+
188+
template <typename Adapter>
189+
void applyPartitioningSolution(const User &in, User *&out,
190+
const PartitioningSolution<Adapter> &solution) const;
191+
192+
template <typename Adapter>
193+
void applyPartitioningSolution(const User &in, RCP<User> &out,
194+
const PartitioningSolution<Adapter> &solution) const;
195+
196+
private:
197+
198+
// MPL: 07/20/2023: TOCHECK: invector_ seems to be useless
199+
RCP<const User> invector_;
200+
RCP<const t_mvector_t> vector_;
201+
RCP<const Tpetra::Map<lno_t, gno_t, node_t> > map_;
202+
203+
int numWeights_;
204+
ArrayRCP<StridedData<lno_t, scalar_t> > weights_;
205+
206+
RCP<User> doMigration(const User &from, size_t numLocalRows,
207+
const gno_t *myNewRows) const;
208+
};
209+
210+
////////////////////////////////////////////////////////////////////////////
211+
// Definitions
212+
////////////////////////////////////////////////////////////////////////////
213+
214+
template <typename User>
215+
TpetraMultiVectorAdapter<User>::TpetraMultiVectorAdapter(
216+
const RCP<const User> &invector,
217+
std::vector<const scalar_t *> &weights, std::vector<int> &weightStrides):
218+
invector_(invector), vector_(), map_(),
219+
numWeights_(weights.size()), weights_(weights.size())
220+
{
221+
typedef StridedData<lno_t, scalar_t> input_t;
222+
// MPL: 07/13/86: should we copy the data from invector to vector_ ?
223+
vector_ = invector;
224+
225+
map_ = vector_->getMap();
226+
227+
size_t length = vector_->getLocalLength();
228+
229+
if (length > 0 && numWeights_ > 0){
230+
int stride = 1;
231+
for (int w=0; w < numWeights_; w++){
232+
if (weightStrides.size())
233+
stride = weightStrides[w];
234+
ArrayRCP<const scalar_t> wgtV(weights[w], 0, stride*length, false);
235+
weights_[w] = input_t(wgtV, stride);
236+
}
237+
}
238+
}
239+
240+
241+
////////////////////////////////////////////////////////////////////////////
242+
template <typename User>
243+
TpetraMultiVectorAdapter<User>::TpetraMultiVectorAdapter(
244+
const RCP<const User> &invector):
245+
invector_(invector), vector_(), map_(),
246+
numWeights_(0), weights_()
247+
{
248+
// MPL: 07/13/86: should we copy the data from invector to vector_ ?
249+
vector_ = invector;
250+
map_ = vector_->getMap();
251+
}
252+
253+
////////////////////////////////////////////////////////////////////////////
254+
template <typename User>
255+
void TpetraMultiVectorAdapter<User>::getEntriesView(
256+
const scalar_t *&elements, int &stride, int idx) const
257+
{
258+
size_t vecsize;
259+
stride = 1;
260+
elements = NULL;
261+
262+
vecsize = vector_->getLocalLength();
263+
if (vecsize > 0){
264+
ArrayRCP<const scalar_t> data = vector_->getData(idx);
265+
elements = data.get();
266+
}
267+
}
268+
269+
////////////////////////////////////////////////////////////////////////////
270+
template <typename User>
271+
void TpetraMultiVectorAdapter<User>::getEntriesKokkosView(
272+
// coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
273+
Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type> & elements) const
274+
{
275+
// coordinates in MJ are LayoutLeft since Tpetra Multivector gives LayoutLeft
276+
Tpetra::MultiVector<scalar_t, lno_t, gno_t, node_t> vec = *vector_.get();
277+
Kokkos::View<scalar_t **, Kokkos::LayoutLeft, typename node_t::device_type> view2d =
278+
vec.template getLocalView<typename node_t::device_type>(Tpetra::Access::ReadWrite);
279+
elements = view2d;
280+
281+
}
282+
283+
////////////////////////////////////////////////////////////////////////////
284+
template <typename User>
285+
template <typename Adapter>
286+
void TpetraMultiVectorAdapter<User>::applyPartitioningSolution(
287+
const User &in, User *&out,
288+
const PartitioningSolution<Adapter> &solution) const
289+
{
290+
// Get an import list (rows to be received)
291+
size_t numNewRows;
292+
ArrayRCP<gno_t> importList;
293+
try{
294+
numNewRows = Zoltan2::getImportList<Adapter,
295+
TpetraMultiVectorAdapter<User> >
296+
(solution, this, importList);
297+
}
298+
Z2_FORWARD_EXCEPTIONS;
299+
300+
// Move the rows, creating a new vector.
301+
RCP<User> outPtr = doMigration(in, numNewRows, importList.getRawPtr());
302+
out = outPtr.get();
303+
outPtr.release();
304+
}
305+
306+
////////////////////////////////////////////////////////////////////////////
307+
template <typename User>
308+
template <typename Adapter>
309+
void TpetraMultiVectorAdapter<User>::applyPartitioningSolution(
310+
const User &in, RCP<User> &out,
311+
const PartitioningSolution<Adapter> &solution) const
312+
{
313+
// Get an import list (rows to be received)
314+
size_t numNewRows;
315+
ArrayRCP<gno_t> importList;
316+
try{
317+
numNewRows = Zoltan2::getImportList<Adapter,
318+
TpetraMultiVectorAdapter<User> >
319+
(solution, this, importList);
320+
}
321+
Z2_FORWARD_EXCEPTIONS;
322+
323+
// Move the rows, creating a new vector.
324+
out = doMigration(in, numNewRows, importList.getRawPtr());
325+
}
326+
327+
////////////////////////////////////////////////////////////////////////////
328+
template < typename User>
329+
RCP<User> TpetraMultiVectorAdapter<User>::doMigration(
330+
const User &from,
331+
size_t numLocalRows,
332+
const gno_t *myNewRows
333+
) const
334+
{
335+
typedef Tpetra::Map<lno_t, gno_t, node_t> map_t;
336+
337+
// source map
338+
const RCP<const map_t> &smap = from.getMap();
339+
gno_t numGlobalElts = smap->getGlobalNumElements();
340+
gno_t base = smap->getMinAllGlobalIndex();
341+
342+
// target map
343+
ArrayView<const gno_t> eltList(myNewRows, numLocalRows);
344+
const RCP<const Teuchos::Comm<int> > comm = from.getMap()->getComm();
345+
RCP<const map_t> tmap = rcp(new map_t(numGlobalElts, eltList, base, comm));
346+
347+
// importer
348+
Tpetra::Import<lno_t, gno_t, node_t> importer(smap, tmap);
349+
350+
// target vector
351+
RCP<t_mvector_t> MV = rcp(
352+
new t_mvector_t(tmap, from.getNumVectors(), true));
353+
MV->doImport(from, importer, Tpetra::INSERT);
354+
355+
gno_t base2 = smap->getMinAllGlobalIndex();
356+
357+
return MV;
358+
}
359+
360+
} //namespace Zoltan2
361+
362+
#endif

0 commit comments

Comments
 (0)