diff --git a/packages/zoltan2/core/src/input/Zoltan2_Adapter.hpp b/packages/zoltan2/core/src/input/Zoltan2_Adapter.hpp index 5e10e2ae0569..596252b56c76 100644 --- a/packages/zoltan2/core/src/input/Zoltan2_Adapter.hpp +++ b/packages/zoltan2/core/src/input/Zoltan2_Adapter.hpp @@ -130,8 +130,8 @@ template using ConstScalarsDeviceView = Kokkos::View; using ConstScalarsHostView = typename ConstScalarsDeviceView::HostMirror; - using scalarsDeviceView = Kokkos::View; - using scalarsHostView = typename scalarsDeviceView::HostMirror; + using ScalarsDeviceView = Kokkos::View; + using ScalarsHostView = typename ScalarsDeviceView::HostMirror; using ConstWeightsDeviceView1D = Kokkos::View; using ConstWeightsHostView1D = typename ConstWeightsDeviceView1D::HostMirror; diff --git a/packages/zoltan2/core/src/input/Zoltan2_BasicIdentifierAdapter.hpp b/packages/zoltan2/core/src/input/Zoltan2_BasicIdentifierAdapter.hpp index 21adc1b9f2fd..b0be959a4e91 100644 --- a/packages/zoltan2/core/src/input/Zoltan2_BasicIdentifierAdapter.hpp +++ b/packages/zoltan2/core/src/input/Zoltan2_BasicIdentifierAdapter.hpp @@ -201,7 +201,7 @@ template lno_t localNumIDs_; const gno_t *idList_; ArrayRCP > weights_; - size_t numWeightsPerID_; + size_t numWeightsPerID_ = 0; Kokkos::View idsView_; Kokkos::View weightsView_; diff --git a/packages/zoltan2/core/src/input/Zoltan2_MatrixAdapter.hpp b/packages/zoltan2/core/src/input/Zoltan2_MatrixAdapter.hpp index 5d8e40049d0f..5c4ba2d1306a 100644 --- a/packages/zoltan2/core/src/input/Zoltan2_MatrixAdapter.hpp +++ b/packages/zoltan2/core/src/input/Zoltan2_MatrixAdapter.hpp @@ -121,6 +121,8 @@ template using user_t = User; using userCoord_t = UserCoord; using base_adapter_t = MatrixAdapter; + using Base = AdapterWithCoordsWrapper; + using device_t = typename node_t::device_type; #endif enum BaseAdapterType adapterType() const override {return MatrixAdapterType;} @@ -160,12 +162,12 @@ template Z2_THROW_NOT_IMPLEMENTED } - virtual void getRowIDsHostView(typename BaseAdapter::ConstIdsHostView& rowIds) const + virtual void getRowIDsHostView(typename Base::ConstIdsHostView& rowIds) const { Z2_THROW_NOT_IMPLEMENTED } - virtual void getRowIDsDeviceView(typename BaseAdapter::ConstIdsDeviceView& rowIds) const + virtual void getRowIDsDeviceView(typename Base::ConstIdsDeviceView& rowIds) const { Z2_THROW_NOT_IMPLEMENTED } @@ -189,14 +191,14 @@ template Z2_THROW_NOT_IMPLEMENTED } - virtual void getCRSHostView(typename BaseAdapter::ConstOffsetsHostView& offsets, - typename BaseAdapter::ConstIdsHostView& colIds) const + virtual void getCRSHostView(typename Base::ConstOffsetsHostView& offsets, + typename Base::ConstIdsHostView& colIds) const { Z2_THROW_NOT_IMPLEMENTED } - virtual void getCRSDeviceView(typename BaseAdapter::ConstOffsetsDeviceView& offsets, - typename BaseAdapter::ConstIdsDeviceView& colIds) const + virtual void getCRSDeviceView(typename Base::ConstOffsetsDeviceView& offsets, + typename Base::ConstIdsDeviceView& colIds) const { Z2_THROW_NOT_IMPLEMENTED } @@ -227,16 +229,16 @@ template Z2_THROW_NOT_IMPLEMENTED } - virtual void getCRSHostView(typename BaseAdapter::ConstOffsetsHostView& offsets, - typename BaseAdapter::ConstIdsHostView& colIds, - typename BaseAdapter::ConstScalarsHostView& values) const + virtual void getCRSHostView(typename Base::ConstOffsetsHostView& offsets, + typename Base::ConstIdsHostView& colIds, + typename Base::ConstScalarsHostView& values) const { Z2_THROW_NOT_IMPLEMENTED } - virtual void getCRSDeviceView(typename BaseAdapter::ConstOffsetsDeviceView& offsets, - typename BaseAdapter::ConstIdsDeviceView& colIds, - typename BaseAdapter::ConstScalarsDeviceView& values) const + virtual void getCRSDeviceView(typename Base::ConstOffsetsDeviceView& offsets, + typename Base::ConstIdsDeviceView& colIds, + typename Base::ConstScalarsDeviceView& values) const { Z2_THROW_NOT_IMPLEMENTED } @@ -262,16 +264,28 @@ template Z2_THROW_NOT_IMPLEMENTED } - virtual void getRowWeightsHostView(typename BaseAdapter::WeightsHostView& weights) const + virtual void getRowWeightsHostView(typename Base::WeightsHostView1D& weights, + int /* idx */ = 0) const { Z2_THROW_NOT_IMPLEMENTED } - virtual void getRowWeightsDeviceView(typename BaseAdapter::WeightsDeviceView& weights) const + virtual void + getRowWeightsHostView(typename Base::WeightsHostView &weights) const { + Z2_THROW_NOT_IMPLEMENTED + } + + virtual void getRowWeightsDeviceView(typename Base::WeightsDeviceView1D& weights, + int /* idx */ = 0) const { Z2_THROW_NOT_IMPLEMENTED } + virtual void + getRowWeightsDeviceView(typename Base::WeightsDeviceView &weights) const { + Z2_THROW_NOT_IMPLEMENTED + } + /*! \brief Indicate whether row weight with index idx should be the * global number of nonzeros in the row. */ @@ -296,12 +310,12 @@ template Z2_THROW_NOT_IMPLEMENTED } - virtual void getColumnIDsHostView(typename BaseAdapter::ConstIdsHostView& colIds) const + virtual void getColumnIDsHostView(typename Base::ConstIdsHostView& colIds) const { Z2_THROW_NOT_IMPLEMENTED } - virtual void getColumnIDsDeviceView(typename BaseAdapter::ConstIdsDeviceView& colIds) const + virtual void getColumnIDsDeviceView(typename Base::ConstIdsDeviceView& colIds) const { Z2_THROW_NOT_IMPLEMENTED } @@ -371,12 +385,12 @@ template Z2_THROW_NOT_IMPLEMENTED } - virtual void getColumnWeightsHostView(typename BaseAdapter::WeightsHostView& weights) const + virtual void getColumnWeightsHostView(typename Base::WeightsHostView1D& weights) const { Z2_THROW_NOT_IMPLEMENTED } - virtual void getColumnWeightsDeviceView(typename BaseAdapter::WeightsDeviceView& weights) const + virtual void getColumnWeightsDeviceView(typename Base::WeightsDeviceView1D& weights) const { Z2_THROW_NOT_IMPLEMENTED } @@ -495,7 +509,7 @@ template } } - void getIDsHostView(typename BaseAdapter::ConstIdsHostView& ids) const override { + void getIDsHostView(typename Base::ConstIdsHostView& ids) const override { switch (getPrimaryEntityType()) { case MATRIX_ROW: getRowIDsHostView(ids); @@ -517,7 +531,7 @@ template } } - void getIDsDeviceView(typename BaseAdapter::ConstIdsDeviceView& ids) const override { + void getIDsDeviceView(typename Base::ConstIdsDeviceView& ids) const override { switch (getPrimaryEntityType()) { case MATRIX_ROW: getRowIDsDeviceView(ids); @@ -553,7 +567,8 @@ template } } - void getWeightsView(const scalar_t *&wgt, int &stride, int idx = 0) const override + void getWeightsView(const scalar_t *&wgt, int &stride, + int idx = 0) const override { switch (getPrimaryEntityType()) { case MATRIX_ROW: @@ -577,7 +592,8 @@ template } } - virtual void getWeightsHostView(typename BaseAdapter::WeightsHostView& hostWgts) const { + void getWeightsHostView(typename Base::WeightsHostView1D &hostWgts, + int idx = 0) const override { switch (getPrimaryEntityType()) { case MATRIX_ROW: getRowWeightsHostView(hostWgts); @@ -599,7 +615,8 @@ template break; } } - virtual void getWeightsDeviceView(typename BaseAdapter::WeightsDeviceView& deviceWgts) const { + void getWeightsDeviceView(typename Base::WeightsDeviceView1D& deviceWgts, + int idx = 0) const override { switch (getPrimaryEntityType()) { case MATRIX_ROW: getRowWeightsDeviceView(deviceWgts); diff --git a/packages/zoltan2/core/src/input/Zoltan2_TpetraCrsMatrixAdapter.hpp b/packages/zoltan2/core/src/input/Zoltan2_TpetraCrsMatrixAdapter.hpp new file mode 100644 index 000000000000..ee2092e676a2 --- /dev/null +++ b/packages/zoltan2/core/src/input/Zoltan2_TpetraCrsMatrixAdapter.hpp @@ -0,0 +1,218 @@ +// @HEADER +// +// *********************************************************************** +// +// Zoltan2: A package of combinatorial algorithms for scientific computing +// Copyright 2012 Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Karen Devine (kddevin@sandia.gov) +// Erik Boman (egboman@sandia.gov) +// Siva Rajamanickam (srajama@sandia.gov) +// +// *********************************************************************** +// +// @HEADER + +/*! \file Zoltan2_XpetraCrsMatrixAdapter.hpp + \brief Defines the XpetraCrsMatrixAdapter class. +*/ + +#ifndef _ZOLTAN2_TPETRACRSMATRIXADAPTER_HPP_ +#define _ZOLTAN2_TPETRACRSMATRIXADAPTER_HPP_ + +#include +#include +#include +#include +#include + +#include + +#include + +namespace Zoltan2 { + +////////////////////////////////////////////////////////////////////////////// +/*! \brief Provides access for Zoltan2 to Tpetra::CrsMatrix data. + + \todo we assume FillComplete has been called. We should support + objects that are not FillCompleted. + \todo add RowMatrix + + The template parameter is the user's input object: + \li Tpetra::CrsMatrix + + The \c scalar_t type, representing use data such as matrix values, is + used by Zoltan2 for weights, coordinates, part sizes and + quality metrics. + Some User types (like Tpetra::CrsMatrix) have an inherent scalar type, + and some (like Tpetra::CrsGraph) do not. For such objects, the scalar + type is set by Zoltan2 to \c float. If you wish to change it to double, + set the second template parameter to \c double. + +*/ + +template + class TpetraCrsMatrixAdapter : public TpetraRowMatrixAdapter { + +public: +#ifndef DOXYGEN_SHOULD_SKIP_THIS + using scalar_t = typename InputTraits::scalar_t; + using lno_t = typename InputTraits::lno_t; + using gno_t = typename InputTraits::gno_t; + using part_t = typename InputTraits::part_t; + using node_t = typename InputTraits::node_t; + using offset_t = typename InputTraits::offset_t; + using tmatrix_t = Tpetra::CrsMatrix; + using device_t = typename node_t::device_type; + using host_t = typename Kokkos::HostSpace::memory_space; + using user_t = User; + using userCoord_t = UserCoord; + + using Base = MatrixAdapter; + using RowMatrix = TpetraRowMatrixAdapter; + #endif + + /*! \brief Constructor + * \param inmatrix The user's Tpetra::CrsMatrix object + * \param nWeightsPerRow If row weights will be provided in setRowWeights(), + * then set \c nWeightsPerRow to the number of weights per row. + */ + TpetraCrsMatrixAdapter(const RCP &inmatrix, + int nWeightsPerRow=0); + + /*! \brief Access to user's matrix + */ + RCP getUserMatrix() const { return this->matrix_; } + + template + void applyPartitioningSolution(const User &in, User *&out, + const PartitioningSolution &solution) const; + + template + void applyPartitioningSolution(const User &in, RCP &out, + const PartitioningSolution &solution) const; +}; + +///////////////////////////////////////////////////////////////// +// Definitions +///////////////////////////////////////////////////////////////// + + template + TpetraCrsMatrixAdapter::TpetraCrsMatrixAdapter( + const RCP &inmatrix, int nWeightsPerRow): + RowMatrix(nWeightsPerRow, inmatrix) { + + auto colIdsHost = inmatrix->getLocalIndicesHost(); + + auto colIdsGlobalHost = + typename Base::IdsHostView("colIdsGlobalHost", colIdsHost.extent(0)); + auto colMap = inmatrix->getColMap(); + + // Convert to global IDs using Tpetra::Map + Kokkos::parallel_for("colIdsGlobalHost", + Kokkos::RangePolicy( + 0, colIdsGlobalHost.extent(0)), + [=](const int i) { + colIdsGlobalHost(i) = + colMap->getGlobalElement(colIdsHost(i)); + }); + + auto colIdsDevice = Kokkos::create_mirror_view_and_copy( + typename Base::device_t(), colIdsGlobalHost); + + this->colIdsDevice_ = colIdsDevice; + this->offsDevice_ = inmatrix->getLocalRowPtrsDevice(); + + if (this->nWeightsPerRow_ > 0) { + + this->rowWeightsDevice_ = typename Base::WeightsDeviceView( + "rowWeightsDevice_", inmatrix->getLocalNumRows(), + this->nWeightsPerRow_); + + this->numNzWeight_ = Kokkos::View( + "numNzWeight_", this->nWeightsPerRow_); + + for (int i = 0; i < this->nWeightsPerRow_; ++i) { + this->numNzWeight_(i) = false; + } + } +} + +//////////////////////////////////////////////////////////////////////////// +template + template + void TpetraCrsMatrixAdapter::applyPartitioningSolution( + const User &in, User *&out, + const PartitioningSolution &solution) const +{ + // Get an import list (rows to be received) + size_t numNewRows; + ArrayRCP importList; + try{ + numNewRows = Zoltan2::getImportList > + (solution, this, importList); + } + Z2_FORWARD_EXCEPTIONS; + + // Move the rows, creating a new matrix. + RCP outPtr = this->doMigration(in, numNewRows,importList.getRawPtr()); + out = const_cast(outPtr.get()); + outPtr.release(); +} + +//////////////////////////////////////////////////////////////////////////// +template + template + void TpetraCrsMatrixAdapter::applyPartitioningSolution( + const User &in, RCP &out, + const PartitioningSolution &solution) const +{ + // Get an import list (rows to be received) + size_t numNewRows; + ArrayRCP importList; + try{ + numNewRows = Zoltan2::getImportList > + (solution, this, importList); + } + Z2_FORWARD_EXCEPTIONS; + + // Move the rows, creating a new matrix. + out = this->doMigration(in, numNewRows, importList.getRawPtr()); +} + +} //namespace Zoltan2 + +#endif diff --git a/packages/zoltan2/core/src/input/Zoltan2_TpetraRowMatrixAdapter.hpp b/packages/zoltan2/core/src/input/Zoltan2_TpetraRowMatrixAdapter.hpp index 604c9540b75b..f6eb73c22d66 100644 --- a/packages/zoltan2/core/src/input/Zoltan2_TpetraRowMatrixAdapter.hpp +++ b/packages/zoltan2/core/src/input/Zoltan2_TpetraRowMatrixAdapter.hpp @@ -56,6 +56,8 @@ #include +#include + namespace Zoltan2 { ////////////////////////////////////////////////////////////////////////////// @@ -75,6 +77,8 @@ namespace Zoltan2 { template class TpetraRowMatrixAdapter : public MatrixAdapter { public: + + #ifndef DOXYGEN_SHOULD_SKIP_THIS using scalar_t = typename InputTraits::scalar_t; using offset_t = typename InputTraits::offset_t; @@ -86,13 +90,14 @@ class TpetraRowMatrixAdapter : public MatrixAdapter { using host_t = typename Kokkos::HostSpace::memory_space; using user_t = User; using userCoord_t = UserCoord; + + using Base = MatrixAdapter; #endif /*! \brief Constructor * \param inmatrix The user's Tpetra RowMatrix object - * \param nWeightsPerRow If row weights will be provided in - * setRowWeights(), the set \c nWeightsPerRow to the number of weights per - * row. + * \param nWeightsPerRow If row weights will be provided in setRowWeights(), + * then set \c nWeightsPerRow to the number of weights per row. */ TpetraRowMatrixAdapter(const RCP &inmatrix, int nWeightsPerRow = 0); @@ -110,7 +115,28 @@ class TpetraRowMatrixAdapter : public MatrixAdapter { */ void setWeights(const scalar_t *weightVal, int stride, int idx = 0); - void setWeights(Kokkos::View &weights); + + /*! \brief Provide a device view of weights for the primary entity type. + * \param val A view to the weights for index \c idx. + * \param idx A number from 0 to one less than + * weight idx specified in the constructor. + * + * The order of the weights should match the order that + * entities appear in the input data structure. + */ + + void setWeightsDevice(typename Base::ConstWeightsDeviceView1D val, int idx); + + /*! \brief Provide a host view of weights for the primary entity type. + * \param val A view to the weights for index \c idx. + * \param idx A number from 0 to one less than + * weight idx specified in the constructor. + * + * The order of the weights should match the order that + * entities appear in the input data structure. + */ + + void setWeightsHost(typename Base::ConstWeightsHostView1D val, int idx); /*! \brief Specify a weight for each row. * \param weightVal A pointer to the weights for this index. @@ -123,12 +149,42 @@ class TpetraRowMatrixAdapter : public MatrixAdapter { * The order of weights should correspond to the order of rows * returned by * \code - * theMatrix->getRowMap()->getLocalElementList(); + * TheMatrix->getRowMap()->getLocalElementList(); * \endcode */ void setRowWeights(const scalar_t *weightVal, int stride, int idx = 0); - void setRowWeights(Kokkos::View &weights); + + /*! \brief Provide a device view to row weights. + * \param val A pointer to the weights for index \c idx. + * \param idx A number from 0 to one less than + * number of row weights specified in the constructor. + * + * The order of the row weights should match the order that + * rows appear in the input data structure. + * \code + * TheMatrix->getRowMap()->getLocalElementList() + * \endcode + */ + + void setRowWeightsDevice(typename Base::ConstWeightsDeviceView1D val, + int idx); + + /*! \brief Provide a host view to row weights. + * \param val A pointer to the weights for index \c idx. + * \param idx A number from 0 to one less than + * number of row weights specified in the constructor. + * + * The order of the row weights should match the order that + * rows appear in the input data structure. + * \code + * TheMatrix->getRowMap()->getLocalElementList() + * \endcode + */ + + void setRowWeightsHost(typename Base::ConstWeightsHostView1D val, + int idx); + /*! \brief Specify an index for which the weight should be the degree of the entity @@ -144,127 +200,69 @@ class TpetraRowMatrixAdapter : public MatrixAdapter { */ void setRowWeightIsNumberOfNonZeros(int idx); - //////////////////////////////////////////////////// - // The MatrixAdapter interface. - //////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////// +// The MatrixAdapter Interface +///////////////////////////////////////////////////////////////// - size_t getLocalNumRows() const { return matrix_->getLocalNumRows(); } + size_t getLocalNumRows() const; - size_t getLocalNumColumns() const { return matrix_->getLocalNumCols(); } + size_t getLocalNumColumns() const; - size_t getLocalNumEntries() const { return matrix_->getLocalNumEntries(); } + size_t getLocalNumEntries() const; - bool CRSViewAvailable() const { return true; } + bool CRSViewAvailable() const; - void getRowIDsView(const gno_t *&rowIds) const override { - ArrayView rowView = rowMap_->getLocalElementList(); - rowIds = rowView.getRawPtr(); - } + void getRowIDsView(const gno_t *&rowIds) const override; void getRowIDsHostView( - typename BaseAdapter::ConstIdsHostView &rowIds) const override { - auto kRowIds = rowMap_->getMyGlobalIndices(); - auto hostRowIds = Kokkos::create_mirror_view(kRowIds); - Kokkos::deep_copy(hostRowIds, kRowIds); - rowIds = hostRowIds; - } + typename Base::ConstIdsHostView &rowIds) const override; void getRowIDsDeviceView( - typename BaseAdapter::ConstIdsDeviceView &rowIds) const override { - using device_type = typename node_t::device_type; - auto rowIdsDevice = Kokkos::create_mirror_view_and_copy( - device_type(), rowMap_->getMyGlobalIndices()); - rowIds = rowIdsDevice; - } + typename Base::ConstIdsDeviceView &rowIds) const override; void getCRSView(ArrayRCP &offsets, - ArrayRCP &colIds) const { - offsets = offset_; - colIds = columnIds_; - } + ArrayRCP &colIds) const; void getCRSHostView( - typename BaseAdapter::ConstOffsetsHostView &offsets, - typename BaseAdapter::ConstIdsHostView &colIds) const override { - auto hostOffsets = Kokkos::create_mirror_view(kOffset_); - Kokkos::deep_copy(hostOffsets, kOffset_); - offsets = hostOffsets; - - auto hostColIds = Kokkos::create_mirror_view(kColumnIds_); - Kokkos::deep_copy(hostColIds, kColumnIds_); - colIds = hostColIds; - } + typename Base::ConstOffsetsHostView &offsets, + typename Base::ConstIdsHostView &colIds) const override; void getCRSDeviceView( - typename BaseAdapter::ConstOffsetsDeviceView &offsets, - typename BaseAdapter::ConstIdsDeviceView &colIds) const override { - offsets = kOffset_; - colIds = kColumnIds_; - } + typename Base::ConstOffsetsDeviceView &offsets, + typename Base::ConstIdsDeviceView &colIds) const override; void getCRSView(ArrayRCP &offsets, ArrayRCP &colIds, - ArrayRCP &values) const { - offsets = offset_; - colIds = columnIds_; - values = values_; - } + ArrayRCP &values) const; void getCRSHostView( - typename BaseAdapter::ConstOffsetsHostView &offsets, - typename BaseAdapter::ConstIdsHostView &colIds, - typename BaseAdapter::ConstScalarsHostView &values) const override { - auto hostOffsets = Kokkos::create_mirror_view(kOffset_); - Kokkos::deep_copy(hostOffsets, kOffset_); - offsets = hostOffsets; - - auto hostColIds = Kokkos::create_mirror_view(kColumnIds_); - Kokkos::deep_copy(hostColIds, kColumnIds_); - colIds = hostColIds; - - auto hostValues = Kokkos::create_mirror_view(kValues_); - Kokkos::deep_copy(hostValues, kValues_); - values = hostValues; - } + typename Base::ConstOffsetsHostView &offsets, + typename Base::ConstIdsHostView &colIds, + typename Base::ConstScalarsHostView &values) const override; - void - getCRSDeviceView(typename BaseAdapter::ConstOffsetsDeviceView &offsets, - typename BaseAdapter::ConstIdsDeviceView &colIds, - typename BaseAdapter::ConstScalarsDeviceView &values) - const override { - offsets = kOffset_; - colIds = kColumnIds_; - values = kValues_; - } + void getCRSDeviceView( + typename Base::ConstOffsetsDeviceView &offsets, + typename Base::ConstIdsDeviceView &colIds, + typename Base::ConstScalarsDeviceView &values) const override; - int getNumWeightsPerRow() const { return nWeightsPerRow_; } + int getNumWeightsPerRow() const; void getRowWeightsView(const scalar_t *&weights, int &stride, - int idx = 0) const { - if (idx < 0 || idx >= nWeightsPerRow_) { - std::ostringstream emsg; - emsg << __FILE__ << ":" << __LINE__ << " Invalid row weight index " - << idx << std::endl; - throw std::runtime_error(emsg.str()); - } + int idx = 0) const; - size_t length; - rowWeights_[idx].getStridedList(length, weights, stride); - } - - void getRowWeightsHostView( - typename BaseAdapter::WeightsHostView &weights) const { - auto hostWeight = Kokkos::create_mirror_view(kRowWeights_); - Kokkos::deep_copy(hostWeight, kRowWeights_); - weights = hostWeight; - } + void getRowWeightsDeviceView(typename Base::WeightsDeviceView1D &weights, + int idx = 0) const; void getRowWeightsDeviceView( - typename BaseAdapter::WeightsDeviceView &weights) const { - weights = kRowWeights_; - } + typename Base::WeightsDeviceView &weights) const override; - bool useNumNonzerosAsRowWeight(int idx) const { return numNzWeight_[idx]; } + void getRowWeightsHostView(typename Base::WeightsHostView1D &weights, + int idx = 0) const; + + void getRowWeightsHostView( + typename Base::WeightsHostView &weights) const override; + + bool useNumNonzerosAsRowWeight(int idx) const; template void applyPartitioningSolution( @@ -276,26 +274,34 @@ class TpetraRowMatrixAdapter : public MatrixAdapter { const User &in, RCP &out, const PartitioningSolution &solution) const; -private: - // Old Non Kokkos type +protected: + // Used by TpetraCrsMatrixAdapter + TpetraRowMatrixAdapter(int nWeightsPerRow, + const RCP &inmatrix) + : matrix_(inmatrix), nWeightsPerRow_(nWeightsPerRow) {} + RCP matrix_; - RCP> rowMap_; - RCP> colMap_; + ArrayRCP offset_; - ArrayRCP columnIds_; // TODO: KDD Is it necessary to copy and store - ArrayRCP values_; // TODO: the matrix here? Would prefer views. - ArrayRCP> rowWeights_; + ArrayRCP columnIds_; + ArrayRCP values_; - // New Kokkos Type - Kokkos::View kOffset_; - Kokkos::View kColumnIds_; - Kokkos::View kValues_; - Kokkos::View kRowWeights_; - Kokkos::View numNzWeight_; + typename Base::ConstOffsetsHostView offsHost_; + typename Base::ConstIdsHostView colIdsHost_; + typename Base::ScalarsHostView valuesHost_; + + typename Base::ConstOffsetsDeviceView offsDevice_; + typename Base::ConstIdsDeviceView colIdsDevice_; + typename Base::ScalarsDeviceView valuesDevice_; int nWeightsPerRow_; + ArrayRCP> rowWeights_; + typename Base::WeightsDeviceView rowWeightsDevice_; + Kokkos::View numNzWeight_; + bool mayHaveDiagonalEntries; - RCP doMigration(const User &from, size_t numLocalRows, + + virtual RCP doMigration(const User &from, size_t numLocalRows, const gno_t *myNewRows) const; }; @@ -305,72 +311,58 @@ class TpetraRowMatrixAdapter : public MatrixAdapter { template TpetraRowMatrixAdapter::TpetraRowMatrixAdapter( - const RCP &inmatrix, int nWeightsPerRow) - : matrix_(inmatrix), rowMap_(), colMap_(), offset_(), columnIds_(), + const RCP &inmatrix, int nWeightsPerRow): + matrix_(inmatrix), offset_(), columnIds_(), nWeightsPerRow_(nWeightsPerRow), rowWeights_(), mayHaveDiagonalEntries(true) { - typedef StridedData input_t; + using strided_t = StridedData; + using localInds_t = typename User::nonconst_local_inds_host_view_type; + using localVals_t = typename User::nonconst_values_host_view_type; + + const auto nrows = matrix_->getLocalNumRows(); + const auto nnz = matrix_->getLocalNumEntries(); + auto maxNumEntries = matrix_->getLocalMaxNumRowEntries(); + + // Unfortunately we have to copy the offsets, column Ids, and vals + // because column Ids are not usually stored in row id order. + + colIdsHost_ = typename Base::ConstIdsHostView("colIdsHost_", nnz); + offsHost_ = typename Base::ConstOffsetsHostView("offsHost_", nrows + 1); + valuesHost_ = typename Base::ScalarsHostView("valuesHost_", nnz); + + localInds_t localColInds("localColInds", maxNumEntries); + localVals_t localVals("localVals", maxNumEntries); - rowMap_ = matrix_->getRowMap(); - colMap_ = matrix_->getColMap(); - - size_t nrows = matrix_->getLocalNumRows(); - size_t nnz = matrix_->getLocalNumEntries(); - size_t maxnumentries = - matrix_->getLocalMaxNumRowEntries(); // Diff from CrsMatrix - - offset_.resize(nrows + 1, 0); - columnIds_.resize(nnz); - values_.resize(nnz); - typename User::nonconst_local_inds_host_view_type indices("indices", - maxnumentries); - typename User::nonconst_values_host_view_type nzs("nzs", maxnumentries); - - kOffset_ = Kokkos::View( - Kokkos::ViewAllocateWithoutInitializing("offset_"), nrows + 1); - auto kOffsetHost = Kokkos::create_mirror_view(kOffset_); - - kColumnIds_ = Kokkos::View( - Kokkos::ViewAllocateWithoutInitializing("columIds_"), nnz); - auto kColumnIdsHost = Kokkos::create_mirror_view(kColumnIds_); - - kValues_ = Kokkos::View( - Kokkos::ViewAllocateWithoutInitializing("values_"), nnz); - auto kValuesHost = Kokkos::create_mirror_view(kValues_); - - kRowWeights_ = Kokkos::View( - Kokkos::ViewAllocateWithoutInitializing("rowWeights_"), nWeightsPerRow_, - nWeightsPerRow_ * nrows); - - lno_t next = 0; - kOffsetHost(0) = 0; - for (size_t i = 0; i < nrows; i++) { - lno_t row = i; - matrix_->getLocalRowCopy(row, indices, nzs, nnz); // Diff from CrsMatrix + for (size_t r = 0; r < nrows; r++) { + size_t numEntries = 0; + matrix_->getLocalRowCopy(r, localColInds, localVals, numEntries); // Diff from CrsGraph + + offsHost_(r + 1) = offsHost_(r) + numEntries; + for (offset_t e = offsHost_(r), i = 0; e < offsHost_(r + 1); e++) { + colIdsHost_(e) = matrix_->getColMap()->getGlobalElement(localColInds(i++)); + } for (size_t j = 0; j < nnz; j++) { - auto cNzs = nzs[j]; - values_[next] = cNzs; - kValuesHost(next) = cNzs; - // TODO - this will be slow - // Is it possible that global columns ids might be stored in order? - auto colMapGId = colMap_->getGlobalElement(indices[j]); - kColumnIdsHost(next) = colMapGId; - columnIds_[next++] = colMapGId; + valuesHost_(r) = localVals[j]; } - auto nextOffset = offset_[i] + nnz; - offset_[i + 1] = nextOffset; - kOffsetHost(i + 1) = nextOffset; } - - Kokkos::deep_copy(kValues_, kValuesHost); - Kokkos::deep_copy(kOffset_, kOffsetHost); - Kokkos::deep_copy(kColumnIds_, kColumnIdsHost); + offsDevice_ = Kokkos::create_mirror_view_and_copy( + typename Base::device_t(), offsHost_); + colIdsDevice_ = Kokkos::create_mirror_view_and_copy( + typename Base::device_t(), colIdsHost_); + valuesDevice_ = Kokkos::create_mirror_view_and_copy( + typename Base::device_t(), valuesHost_); if (nWeightsPerRow_ > 0) { - rowWeights_ = arcp(new input_t[nWeightsPerRow_], 0, nWeightsPerRow_, true); - numNzWeight_ = - Kokkos::View("numNzWeight_", nWeightsPerRow_); - for (size_t i = 0; i < numNzWeight_.extent(0); ++i) { + rowWeights_ = + arcp(new strided_t[nWeightsPerRow_], 0, nWeightsPerRow_, true); + + rowWeightsDevice_ = typename Base::WeightsDeviceView( + "rowWeightsDevice_", nrows, nWeightsPerRow_); + + numNzWeight_ = Kokkos::View( + "numNzWeight_", nWeightsPerRow_); + + for (int i = 0; i < nWeightsPerRow_; ++i) { numNzWeight_(i) = false; } } @@ -394,10 +386,10 @@ void TpetraRowMatrixAdapter::setWeights( //////////////////////////////////////////////////////////////////////////// template -void TpetraRowMatrixAdapter::setWeights( - Kokkos::View &weights) { +void TpetraRowMatrixAdapter::setWeightsDevice( + typename Base::ConstWeightsDeviceView1D val, int idx) { if (this->getPrimaryEntityType() == MATRIX_ROW) - setRowWeights(weights); + setRowWeightsDevice(val, idx); else { // TODO: Need to allow weights for columns and/or nonzeros std::ostringstream emsg; @@ -410,35 +402,65 @@ void TpetraRowMatrixAdapter::setWeights( //////////////////////////////////////////////////////////////////////////// template -void TpetraRowMatrixAdapter::setRowWeights( - const scalar_t *weightVal, int stride, int idx) { - typedef StridedData input_t; - if (idx < 0 || idx >= nWeightsPerRow_) { +void TpetraRowMatrixAdapter::setWeightsHost( + typename Base::ConstWeightsHostView1D val, int idx) { + if (this->getPrimaryEntityType() == MATRIX_ROW) + setRowWeightsHost(val, idx); + else { + // TODO: Need to allow weights for columns and/or nonzeros std::ostringstream emsg; - emsg << __FILE__ << ":" << __LINE__ << " Invalid row weight index " << idx - << std::endl; + emsg << __FILE__ << "," << __LINE__ + << " error: setWeights not yet supported for" + << " columns or nonzeros." << std::endl; throw std::runtime_error(emsg.str()); } +} - size_t nvtx = getLocalNumRows(); - ArrayRCP weightV(weightVal, 0, nvtx * stride, false); - rowWeights_[idx] = input_t(weightV, stride); +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::setRowWeights( + const scalar_t *weightVal, int stride, int idx) { + typedef StridedData input_t; + AssertCondition((idx >= 0) and (idx < nWeightsPerRow_), + "Invalid row weight index: " + std::to_string(idx)); - // JD-TODO: Check if correct - auto kRowWeightsHost = Kokkos::create_mirror_view(kRowWeights_); - Kokkos::deep_copy(kRowWeightsHost, kRowWeights_); - for (size_t i = 0; i < nvtx; ++i) { - kRowWeightsHost(idx, i) = weightV[i]; - } + size_t nrows = getLocalNumRows(); + ArrayRCP weightV(weightVal, 0, nrows * stride, false); + rowWeights_[idx] = input_t(weightV, stride); +} - Kokkos::deep_copy(kRowWeights_, kRowWeightsHost); +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::setRowWeightsDevice( + typename Base::ConstWeightsDeviceView1D weights, int idx) { + + AssertCondition((idx >= 0) and (idx < nWeightsPerRow_), + "Invalid row weight index: " + std::to_string(idx)); + + const auto nrows = getLocalNumRows(); + auto weightsSub = Kokkos::subview(rowWeightsDevice_, Kokkos::ALL, idx); + Kokkos::parallel_for( + nrows, KOKKOS_LAMBDA(const int rowID) { + weightsSub(rowID) = weights(rowID); + }); } //////////////////////////////////////////////////////////////////////////// template -void TpetraRowMatrixAdapter::setRowWeights( - Kokkos::View &weights) { - kRowWeights_ = weights; +void TpetraRowMatrixAdapter::setRowWeightsHost( + typename Base::ConstWeightsHostView1D weightsHost, int idx) { + AssertCondition((idx >= 0) and (idx < nWeightsPerRow_), + "Invalid row weight index: " + std::to_string(idx)); + + auto weightsDevice = Kokkos::create_mirror_view_and_copy( + typename Base::device_t(), weightsHost); + + const auto nrows = getLocalNumRows(); + Kokkos::parallel_for( + Kokkos::RangePolicy(0, nrows), + KOKKOS_LAMBDA(const int rowID) { + rowWeightsDevice_(rowID, idx) = weightsDevice(rowID); + }); } //////////////////////////////////////////////////////////////////////////// @@ -470,6 +492,193 @@ void TpetraRowMatrixAdapter::setRowWeightIsNumberOfNonZeros( numNzWeight_(idx) = true; } +//////////////////////////////////////////////////////////////////////////// +template +size_t TpetraRowMatrixAdapter::getLocalNumRows() const { + return matrix_->getLocalNumRows(); +} + +//////////////////////////////////////////////////////////////////////////// +template +size_t TpetraRowMatrixAdapter::getLocalNumColumns() const { + return matrix_->getLocalNumCols(); +} + +//////////////////////////////////////////////////////////////////////////// +template +size_t TpetraRowMatrixAdapter::getLocalNumEntries() const { + return matrix_->getLocalNumEntries(); +} + +//////////////////////////////////////////////////////////////////////////// +template +bool TpetraRowMatrixAdapter::CRSViewAvailable() const { return true; } + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getRowIDsView(const gno_t *&rowIds) const { + ArrayView rowView = matrix_->getRowMap()->getLocalElementList(); + rowIds = rowView.getRawPtr(); +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getRowIDsHostView( + typename Base::ConstIdsHostView &rowIds) const { + auto idsDevice = matrix_->getRowMap()->getMyGlobalIndices(); + auto tmpIds = typename Base::IdsHostView("", idsDevice.extent(0)); + + Kokkos::deep_copy(tmpIds, idsDevice); + + rowIds = tmpIds; +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getRowIDsDeviceView( + typename Base::ConstIdsDeviceView &rowIds) const { + + auto idsDevice = matrix_->getRowMap()->getMyGlobalIndices(); + auto tmpIds = typename Base::IdsDeviceView("", idsDevice.extent(0)); + + Kokkos::deep_copy(tmpIds, idsDevice); + + rowIds = tmpIds; +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getCRSView(ArrayRCP &offsets, + ArrayRCP &colIds) const { + offsets = offset_; + colIds = columnIds_; +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getCRSHostView( + typename Base::ConstOffsetsHostView &offsets, + typename Base::ConstIdsHostView &colIds) const { + auto hostOffsets = Kokkos::create_mirror_view(offsDevice_); + Kokkos::deep_copy(hostOffsets, offsDevice_); + offsets = hostOffsets; + + auto hostColIds = Kokkos::create_mirror_view(colIdsDevice_); + Kokkos::deep_copy(hostColIds, colIdsDevice_); + colIds = hostColIds; +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getCRSDeviceView( + typename Base::ConstOffsetsDeviceView &offsets, + typename Base::ConstIdsDeviceView &colIds) const { + offsets = offsDevice_; + colIds = colIdsDevice_; +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getCRSView(ArrayRCP &offsets, + ArrayRCP &colIds, + ArrayRCP &values) const { + offsets = offset_; + colIds = columnIds_; + values = values_; +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getCRSHostView( + typename Base::ConstOffsetsHostView &offsets, + typename Base::ConstIdsHostView &colIds, + typename Base::ConstScalarsHostView &values) const { + auto hostOffsets = Kokkos::create_mirror_view(offsDevice_); + Kokkos::deep_copy(hostOffsets, offsDevice_); + offsets = hostOffsets; + + auto hostColIds = Kokkos::create_mirror_view(colIdsDevice_); + Kokkos::deep_copy(hostColIds, colIdsDevice_); + colIds = hostColIds; + + auto hostValues = Kokkos::create_mirror_view(valuesDevice_); + Kokkos::deep_copy(hostValues, valuesDevice_); + values = hostValues; +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getCRSDeviceView( + typename Base::ConstOffsetsDeviceView &offsets, + typename Base::ConstIdsDeviceView &colIds, + typename Base::ConstScalarsDeviceView &values) const { + offsets = offsDevice_; + colIds = colIdsDevice_; + values = valuesDevice_; +} + +//////////////////////////////////////////////////////////////////////////// +template +int TpetraRowMatrixAdapter::getNumWeightsPerRow() const { return nWeightsPerRow_; } + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getRowWeightsView(const scalar_t *&weights, int &stride, + int idx) const { + if (idx < 0 || idx >= nWeightsPerRow_) { + std::ostringstream emsg; + emsg << __FILE__ << ":" << __LINE__ << " Invalid row weight index " + << idx << std::endl; + throw std::runtime_error(emsg.str()); + } + + size_t length; + rowWeights_[idx].getStridedList(length, weights, stride); +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getRowWeightsDeviceView( + typename Base::WeightsDeviceView1D &weights, int idx) const { + AssertCondition((idx >= 0) and (idx < nWeightsPerRow_), + "Invalid row weight index."); + + weights = Kokkos::subview(rowWeightsDevice_, Kokkos::ALL, idx); +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getRowWeightsDeviceView( + typename Base::WeightsDeviceView &weights) const { + + weights = rowWeightsDevice_; +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getRowWeightsHostView( + typename Base::WeightsHostView1D &weights, int idx) const { + AssertCondition((idx >= 0) and (idx < nWeightsPerRow_), + "Invalid row weight index."); + + auto weightsDevice = Kokkos::subview(rowWeightsDevice_, Kokkos::ALL, idx); + weights = Kokkos::create_mirror_view(weightsDevice); + Kokkos::deep_copy(weights, weightsDevice); +} + +//////////////////////////////////////////////////////////////////////////// +template +void TpetraRowMatrixAdapter::getRowWeightsHostView( + typename Base::WeightsHostView &weights) const { + + weights = Kokkos::create_mirror_view(rowWeightsDevice_); + Kokkos::deep_copy(weights, rowWeightsDevice_); +} + +//////////////////////////////////////////////////////////////////////////// +template +bool TpetraRowMatrixAdapter::useNumNonzerosAsRowWeight(int idx) const { return numNzWeight_[idx]; } + //////////////////////////////////////////////////////////////////////////// template template @@ -481,8 +690,7 @@ void TpetraRowMatrixAdapter::applyPartitioningSolution( ArrayRCP importList; try { numNewRows = - Zoltan2::getImportList>( + Zoltan2::getImportList>( solution, this, importList); } Z2_FORWARD_EXCEPTIONS; @@ -504,8 +712,7 @@ void TpetraRowMatrixAdapter::applyPartitioningSolution( ArrayRCP importList; try { numNewRows = - Zoltan2::getImportList>( + Zoltan2::getImportList>( solution, this, importList); } Z2_FORWARD_EXCEPTIONS; @@ -553,24 +760,6 @@ RCP TpetraRowMatrixAdapter::doMigration( // importer Tpetra::Import importer(smap, tmap); - // target matrix - // Chris Siefert proposed using the following to make migration - // more efficient. - // By default, the Domain and Range maps are the same as in "from". - // As in the original code, we instead set them both to tmap. - // The assumption is a square matrix. - // TODO: what about rectangular matrices? - // TODO: Should choice of domain/range maps be an option to this function? - - // KDD 3/7/16: disabling Chris' new code to avoid dashboard failures; - // KDD 3/7/16: can re-enable when issue #114 is fixed. - // KDD 3/7/16: when re-enable CSIEFERT code, can comment out - // KDD 3/7/16: "Original way" code. - // CSIEFERT RCP M; - // CSIEFERT from.importAndFillComplete(M, importer, tmap, tmap); - - // Original way we did it: - // int oldNumElts = smap->getLocalNumElements(); int newNumElts = numLocalRows; @@ -598,7 +787,6 @@ RCP TpetraRowMatrixAdapter::doMigration( M->doImport(from, importer, Tpetra::INSERT); M->fillComplete(); - // End of original way we did it. return Teuchos::rcp_dynamic_cast(M); } diff --git a/packages/zoltan2/core/src/input/Zoltan2_XpetraCrsMatrixAdapter.hpp b/packages/zoltan2/core/src/input/Zoltan2_XpetraCrsMatrixAdapter.hpp index b6cafb501dab..8627b72ca98b 100644 --- a/packages/zoltan2/core/src/input/Zoltan2_XpetraCrsMatrixAdapter.hpp +++ b/packages/zoltan2/core/src/input/Zoltan2_XpetraCrsMatrixAdapter.hpp @@ -57,6 +57,9 @@ #include +#include +#include + namespace Zoltan2 { ////////////////////////////////////////////////////////////////////////////// @@ -83,25 +86,26 @@ namespace Zoltan2 { */ template - class XpetraCrsMatrixAdapter : public MatrixAdapter { + class XpetraCrsMatrixAdapter : public MatrixAdapter { public: #ifndef DOXYGEN_SHOULD_SKIP_THIS - typedef typename InputTraits::scalar_t scalar_t; - typedef typename InputTraits::lno_t lno_t; - typedef typename InputTraits::gno_t gno_t; - typedef typename InputTraits::part_t part_t; - typedef typename InputTraits::node_t node_t; - typedef typename InputTraits::offset_t offset_t; - typedef Xpetra::CrsMatrix xmatrix_t; - typedef User user_t; - typedef UserCoord userCoord_t; + using scalar_t = typename InputTraits::scalar_t; + using lno_t = typename InputTraits::lno_t; + using gno_t = typename InputTraits::gno_t; + using part_t = typename InputTraits::part_t; + using node_t = typename InputTraits::node_t; + using offset_t = typename InputTraits::offset_t; + using xmatrix_t = Xpetra::CrsMatrix; + + using userCoord_t = UserCoord; + using user_t = User; #endif /*! \brief Constructor - * \param inmatrix The users Epetra, Tpetra, or Xpetra CrsMatrix object + * \param inmatrix The user's Epetra, Tpetra, or Xpetra CrsMatrix object * \param nWeightsPerRow If row weights will be provided in setRowWeights(), - * the set \c nWeightsPerRow to the number of weights per row. + * then set \c nWeightsPerRow to the number of weights per row. */ XpetraCrsMatrixAdapter(const RCP &inmatrix, int nWeightsPerRow=0); @@ -175,9 +179,9 @@ template rowIds = rowView.getRawPtr(); } - void getCRSView(ArrayRCP &offsets, ArrayRCP &colIds) const + void getCRSView(ArrayRCP &offsets, + ArrayRCP &colIds) const { - ArrayRCP< const lno_t > localColumnIds; ArrayRCP values; matrix_->getAllValues(offsets,localColumnIds,values); @@ -186,8 +190,7 @@ template void getCRSView(ArrayRCP &offsets, ArrayRCP &colIds, - ArrayRCP &values) const - { + ArrayRCP &values) const { ArrayRCP< const lno_t > localColumnIds; matrix_->getAllValues(offsets,localColumnIds,values); colIds = columnIds_; @@ -269,7 +272,7 @@ template matrix_->getAllValues(offset,localColumnIds,values); columnIds_.resize(nnz, 0); - for(offset_t i = 0; i < offset[nrows]; i++) { + for(offset_t i = 0; i < offset[nrows]; i++){ columnIds_[i] = colMap_->getGlobalElement(localColumnIds[i]); } diff --git a/packages/zoltan2/example/graph/graph.cpp b/packages/zoltan2/example/graph/graph.cpp index 691c0eded790..810331a5abb8 100644 --- a/packages/zoltan2/example/graph/graph.cpp +++ b/packages/zoltan2/example/graph/graph.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +81,7 @@ int main(int narg, char** arg) typedef Tpetra::Vector Vector_t; // Useful typedefs: Zoltan2 types - typedef Zoltan2::XpetraCrsMatrixAdapter MatrixAdapter_t; + typedef Zoltan2::TpetraCrsMatrixAdapter MatrixAdapter_t; typedef Zoltan2::XpetraMultiVectorAdapter MultiVectorAdapter_t; // Input parameters with default values diff --git a/packages/zoltan2/test/core/unit/CMakeLists.txt b/packages/zoltan2/test/core/unit/CMakeLists.txt index dcd532367800..0c8824c58dee 100644 --- a/packages/zoltan2/test/core/unit/CMakeLists.txt +++ b/packages/zoltan2/test/core/unit/CMakeLists.txt @@ -158,6 +158,15 @@ TRIBITS_COPY_FILES_TO_BINARY_DIR(copy_files_for_scorec_unit_tests ENDIF() +TRIBITS_ADD_EXECUTABLE_AND_TEST( + TpetraCrsMatrixInput + SOURCES input/TpetraCrsMatrixInput.cpp + NUM_MPI_PROCS 4 + COMM serial mpi + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + TRIBITS_ADD_EXECUTABLE_AND_TEST( TpetraRowMatrixInput SOURCES input/TpetraRowMatrixInput.cpp diff --git a/packages/zoltan2/test/core/unit/input/MatrixAdapter.cpp b/packages/zoltan2/test/core/unit/input/MatrixAdapter.cpp index 1e8561195b80..4f0fe9e600d2 100644 --- a/packages/zoltan2/test/core/unit/input/MatrixAdapter.cpp +++ b/packages/zoltan2/test/core/unit/input/MatrixAdapter.cpp @@ -92,7 +92,7 @@ int main(int narg, char *arg[]) { int rank = comm->getRank(); - int nVtxWeights = 5; + int nVtxWeights = 2; int nnzWgtIdx = -1; std::string fname("simple"); @@ -108,43 +108,52 @@ int main(int narg, char *arg[]) { RCP trM = rcp_dynamic_cast(M); RCP ctrM = rcp_const_cast(trM); zlno_t nLocalRows = M->getLocalNumRows(); + std::cout << "nLocalRows: " << nLocalRows << std::endl; // Weights: - zscalar_t **rowWeights = NULL; - Zoltan2::BaseAdapter::WeightsDeviceView kRowWeights( - Kokkos::ViewAllocateWithoutInitializing("kRowWeights"), nVtxWeights, - nLocalRows); - - auto kRowWeightsHost = Kokkos::create_mirror_view(kRowWeights); + zscalar_t **rowWeights = nullptr; + // create as many 1-D weights views as nVtxWeights + Zoltan2::BaseAdapter::WeightsDeviceView1D wgts0("wgts0", + nLocalRows); + Zoltan2::BaseAdapter::WeightsDeviceView1D wgts1("wgts1", + nLocalRows); + + auto wgts0Host = Kokkos::create_mirror_view(wgts0); + auto wgts1Host = Kokkos::create_mirror_view(wgts1); + + for (zlno_t i = 0; i < nLocalRows; i++) { + wgts0Host(i) = i; + wgts1Host(i) = 200000 + i; + } if (nVtxWeights > 0) { rowWeights = new zscalar_t *[nVtxWeights]; for (int i = 0; i < nVtxWeights; i++) { if (nnzWgtIdx == i) { - rowWeights[i] = NULL; - kRowWeightsHost(i, 0) = 0; + rowWeights[i] = nullptr; } else { rowWeights[i] = new zscalar_t[nLocalRows]; for (zlno_t j = 0; j < nLocalRows; j++) { rowWeights[i][j] = 200000 * i + j; - kRowWeightsHost(i, j) = 200000 * i + j; } } } } - Kokkos::deep_copy(kRowWeights, kRowWeightsHost); + Kokkos::deep_copy(wgts0, wgts0Host); + Kokkos::deep_copy(wgts1, wgts1Host); tRowMAdapter_t tmi(ctrM, nVtxWeights); for (int i = 0; i < nVtxWeights; i++) { tmi.setWeights(rowWeights[i], 1, i); } - tmi.setRowWeights(kRowWeights); + tmi.setRowWeightsDevice(wgts0, 0); + tmi.setRowWeightsDevice(wgts1, 1); - simpleVAdapter_t *via = NULL; + simpleVAdapter_t *via = nullptr; // Set up some fake input - zscalar_t **coords = NULL; + zscalar_t **coords = nullptr; int coordDim = 3; if (coordDim > 0) { @@ -157,14 +166,14 @@ int main(int narg, char *arg[]) { } } - zgno_t *gids = NULL; + zgno_t *gids = nullptr; if (coordDim > 0) { gids = new zgno_t[nLocalRows]; for (zlno_t i = 0; i < nLocalRows; i++) gids[i] = M->getRowMap()->getGlobalElement(i); via = new simpleVAdapter_t(nLocalRows, gids, coords[0], - (coordDim > 1 ? coords[1] : NULL), - (coordDim > 2 ? coords[2] : NULL), 1, 1, 1); + (coordDim > 1 ? coords[1] : nullptr), + (coordDim > 2 ? coords[2] : nullptr), 1, 1, 1); tmi.setCoordinateInput(via); } @@ -263,27 +272,48 @@ int main(int narg, char *arg[]) { TEST_FAIL_AND_EXIT(*comm, success, "values != kHostValues != kDeviceValues", 1) - // TEST of getRowWeightsView, getRowWeightsHostView and + // TEST of getRowWeightsView, getRowWeightsHost0View and // getRowWeightsDeviceView + + Zoltan2::BaseAdapter::WeightsHostView1D weightsHost0; + Zoltan2::BaseAdapter::WeightsDeviceView1D weightsDevice0; + Zoltan2::BaseAdapter::WeightsHostView1D weightsHost1; + Zoltan2::BaseAdapter::WeightsDeviceView1D weightsDevice1; + + tmi.getRowWeightsHostView(weightsHost0, 0); + tmi.getRowWeightsDeviceView(weightsDevice0, 0); + + tmi.getRowWeightsHostView(weightsHost1, 1); + tmi.getRowWeightsDeviceView(weightsDevice1, 1); + + auto hostWeightsDevice0 = Kokkos::create_mirror_view(weightsDevice0); + Kokkos::deep_copy(hostWeightsDevice0, weightsDevice0); + + auto hostWeightsDevice1 = Kokkos::create_mirror_view(weightsDevice1); + Kokkos::deep_copy(hostWeightsDevice1, weightsDevice1); + for (int w = 0; success && w < nVtxWeights; w++) { const zscalar_t *wgts; - Zoltan2::BaseAdapter::WeightsHostView kHostWgts; - Zoltan2::BaseAdapter::WeightsDeviceView kDeviceWgts; - Kokkos::View wkgts; + Kokkos::View wkgts; int stride; tmi.getRowWeightsView(wgts, stride, w); - tmi.getRowWeightsHostView(kHostWgts); - tmi.getRowWeightsDeviceView(kDeviceWgts); - auto kDeviceWgtsHost = Kokkos::create_mirror_view(kDeviceWgts); - Kokkos::deep_copy(kDeviceWgtsHost, kDeviceWgts); + if (w == 0) { - for (zlno_t i = 0; success && i < nLocalRows; ++i) { - TEUCHOS_TEST_EQUALITY(wgts[stride * i], kHostWgts(w, i), std::cout, - success); - TEUCHOS_TEST_EQUALITY(wgts[stride * i], kDeviceWgtsHost(w, i), std::cout, - success); + for (zlno_t i = 0; success && i < nLocalRows; ++i) { + TEUCHOS_TEST_EQUALITY(wgts[stride * i], weightsHost0(i), std::cout, + success); + TEUCHOS_TEST_EQUALITY(wgts[stride * i], hostWeightsDevice0(i), std::cout, + success); + } + } else { + for (zlno_t i = 0; success && i < nLocalRows; ++i) { + TEUCHOS_TEST_EQUALITY(wgts[stride * i], weightsHost1(i), std::cout, + success); + TEUCHOS_TEST_EQUALITY(wgts[stride * i], hostWeightsDevice1(i), std::cout, + success); + } } } TEST_FAIL_AND_EXIT(*comm, success, "wgts != vwgts != wkgts", 1) diff --git a/packages/zoltan2/test/core/unit/input/TpetraCrsMatrixInput.cpp b/packages/zoltan2/test/core/unit/input/TpetraCrsMatrixInput.cpp new file mode 100644 index 000000000000..5e71024dd462 --- /dev/null +++ b/packages/zoltan2/test/core/unit/input/TpetraCrsMatrixInput.cpp @@ -0,0 +1,303 @@ +// @HEADER +// +// *********************************************************************** +// +// Zoltan2: A package of combinatorial algorithms for scientific computing +// Copyright 2012 Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Karen Devine (kddevin@sandia.gov) +// Erik Boman (egboman@sandia.gov) +// Siva Rajamanickam (srajama@sandia.gov) +// +// *********************************************************************** +// +// @HEADER +// +// Basic testing of Zoltan2::TpetraCrsMatrixAdapter + +/*! \file TpetraCrsMatrixInput.cpp + * \brief Test of Zoltan2::TpetraCrsMatrixAdapter class. + * \todo test with geometric row coordinates. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using Teuchos::Comm; +using Teuchos::Comm; +using Teuchos::RCP; +using Teuchos::rcp; +using Teuchos::rcp_const_cast; +using Teuchos::rcp_dynamic_cast; + +using ztcrsmatrix_t = Tpetra::CrsMatrix; +using node_t = typename Zoltan2::InputTraits::node_t; +using device_t = typename node_t::device_type; +using crsAdapter_t = Zoltan2::TpetraCrsMatrixAdapter; +using execspace_t = + typename crsAdapter_t::ConstWeightsHostView1D::execution_space; + +////////////////////////////////////////////////////////////////////////// + +template +void printMatrix(RCP > &comm, zlno_t nrows, + const zgno_t *rowIds, const offset_t *offsets, const zgno_t *colIds) { + int rank = comm->getRank(); + int nprocs = comm->getSize(); + comm->barrier(); + for (int p=0; p < nprocs; p++){ + if (p == rank){ + std::cout << rank << ":" << std::endl; + for (zlno_t i=0; i < nrows; i++){ + std::cout << " row " << rowIds[i] << ": "; + for (offset_t j=offsets[i]; j < offsets[i+1]; j++){ + std::cout << colIds[j] << " "; + } + std::cout << std::endl; + } + std::cout.flush(); + } + comm->barrier(); + } + comm->barrier(); +} + +////////////////////////////////////////////////////////////////////////// + +template +void TestMatrixIds(adapter_t &ia, matrix_t &matrix) { + + using idsHost_t = typename adapter_t::ConstIdsHostView; + using offsetsHost_t = typename adapter_t::ConstOffsetsHostView; + using localInds_t = + typename adapter_t::user_t::nonconst_local_inds_host_view_type; + using localVals_t = + typename adapter_t::user_t::nonconst_values_host_view_type; + + + const auto nrows = matrix.getLocalNumRows(); + const auto ncols = matrix.getLocalNumEntries(); + const auto maxNumEntries = matrix.getLocalMaxNumRowEntries(); + + typename adapter_t::Base::ConstIdsHostView colIdsHost_("colIdsHost_", ncols); + typename adapter_t::Base::ConstOffsetsHostView offsHost_("offsHost_", + nrows + 1); + + localInds_t localColInds("localColInds", maxNumEntries); + localVals_t localVals("localVals", maxNumEntries); + + for (size_t r = 0; r < nrows; r++) { + size_t numEntries = 0; + matrix.getLocalRowCopy(r, localColInds, localVals, numEntries);; + + offsHost_(r + 1) = offsHost_(r) + numEntries; + for (size_t e = offsHost_(r), i = 0; e < offsHost_(r + 1); e++) { + colIdsHost_(e) = matrix.getColMap()->getGlobalElement(localColInds(i++)); + } + } + + idsHost_t rowIdsHost; + ia.getRowIDsHostView(rowIdsHost); + + const auto matrixIDS = matrix.getRowMap()->getLocalElementList(); + + Z2_TEST_COMPARE_ARRAYS(matrixIDS, rowIdsHost); + + idsHost_t colIdsHost; + offsetsHost_t offsetsHost; + ia.getCRSHostView(offsetsHost, colIdsHost); + + Z2_TEST_COMPARE_ARRAYS(colIdsHost_, colIdsHost); + Z2_TEST_COMPARE_ARRAYS(offsHost_, offsetsHost); +} + +template +void verifyInputAdapter(adapter_t &ia, matrix_t &matrix) { + using idsDevice_t = typename adapter_t::ConstIdsDeviceView; + using idsHost_t = typename adapter_t::ConstIdsHostView; + using offsetsDevice_t = typename adapter_t::ConstOffsetsDeviceView; + using offsetsHost_t = typename adapter_t::ConstOffsetsHostView; + using weightsDevice_t = typename adapter_t::WeightsDeviceView1D; + using weightsHost_t = typename adapter_t::WeightsHostView1D; + using constWeightsDevice_t = typename adapter_t::ConstWeightsDeviceView1D; + using constWeightsHost_t = typename adapter_t::ConstWeightsHostView1D; + + const auto nrows = ia.getLocalNumIDs(); + + Z2_TEST_EQUALITY(ia.getLocalNumRows(), matrix.getLocalNumRows()); + Z2_TEST_EQUALITY(ia.getLocalNumColumns(), matrix.getLocalNumCols()); + Z2_TEST_EQUALITY(ia.getLocalNumEntries(), matrix.getLocalNumEntries()); + + ///////////////////////////////// + //// getRowIdsView + ///////////////////////////////// + + idsDevice_t rowIdsDevice; + ia.getRowIDsDeviceView(rowIdsDevice); + idsHost_t rowIdsHost; + ia.getRowIDsHostView(rowIdsHost); + + TestDeviceHostView(rowIdsDevice, rowIdsHost); + + ///////////////////////////////// + //// setRowWeightsDevice + ///////////////////////////////// + Z2_TEST_THROW(ia.setRowWeightsDevice( + typename adapter_t::WeightsDeviceView1D{}, 50), + std::runtime_error); + + weightsDevice_t wgts0("wgts0", nrows); + Kokkos::parallel_for( + nrows, KOKKOS_LAMBDA(const int idx) { wgts0(idx) = idx * 2; }); + + Z2_TEST_NOTHROW(ia.setRowWeightsDevice(wgts0, 0)); + + // Don't reuse the same View, since we don't copy the values, + // we just assign the View (increase use count) + weightsDevice_t wgts1("wgts1", nrows); + Kokkos::parallel_for( + nrows, KOKKOS_LAMBDA(const int idx) { wgts1(idx) = idx * 3; }); + + Z2_TEST_NOTHROW(ia.setRowWeightsDevice(wgts1, 1)); + + ///////////////////////////////// + //// getRowWeightsDevice + ///////////////////////////////// + { + weightsDevice_t weightsDevice; + Z2_TEST_NOTHROW(ia.getRowWeightsDeviceView(weightsDevice, 0)); + + weightsHost_t weightsHost; + Z2_TEST_NOTHROW(ia.getRowWeightsHostView(weightsHost, 0)); + + TestDeviceHostView(weightsDevice, weightsHost); + + TestDeviceHostView(wgts0, weightsHost); + } + { + weightsDevice_t weightsDevice; + Z2_TEST_NOTHROW(ia.getRowWeightsDeviceView(weightsDevice, 1)); + + weightsHost_t weightsHost; + Z2_TEST_NOTHROW(ia.getRowWeightsHostView(weightsHost, 1)); + + TestDeviceHostView(weightsDevice, weightsHost); + + TestDeviceHostView(wgts1, weightsHost); + } + { + weightsDevice_t wgtsDevice; + Z2_TEST_THROW(ia.getRowWeightsDeviceView(wgtsDevice, 2), + std::runtime_error); + + weightsHost_t wgtsHost; + Z2_TEST_THROW(ia.getRowWeightsHostView(wgtsHost, 2), std::runtime_error); + } + + TestMatrixIds(ia, matrix); +} + +////////////////////////////////////////////////////////////////////////// + +int main(int narg, char *arg[]) { + using crsSoln_t = Zoltan2::PartitioningSolution; + using crsPart_t = crsAdapter_t::part_t; + + Tpetra::ScopeGuard tscope(&narg, &arg); + const auto comm = Tpetra::getDefaultComm(); + + auto rank = comm->getRank(); + + try { + Teuchos::ParameterList params; + params.set("input file", "simple"); + params.set("file type", "Chaco"); + + auto uinput = rcp(new UserInputForTests(params, comm)); + + // Input crs matrix + const auto crsMatrix = uinput->getUITpetraCrsMatrix(); + + const auto nrows = crsMatrix->getLocalNumRows(); + + // To test migration in the input adapter we need a Solution object. + const auto env = rcp(new Zoltan2::Environment(comm)); + + const int nWeights = 2; + + ///////////////////////////////////////////////////////////// + // User object is Tpetra::CrsMatrix + ///////////////////////////////////////////////////////////// + + PrintFromRoot("Input adapter for Tpetra::CrsMatrix"); + + // Graph Adapters use crsGraph, original TpetraInput uses trM (=CrsMatrix) + auto tpetraCrsMatrixInput = rcp(new crsAdapter_t(crsMatrix, nWeights)); + + verifyInputAdapter(*tpetraCrsMatrixInput, *crsMatrix); + + crsPart_t *p = new crsPart_t[nrows]; + memset(p, 0, sizeof(crsPart_t) * nrows); + ArrayRCP solnParts(p, 0, nrows, true); + + crsSoln_t solution(env, comm, nWeights); + solution.setParts(solnParts); + + ztcrsmatrix_t *mMigrate = NULL; + tpetraCrsMatrixInput->applyPartitioningSolution(*crsMatrix, mMigrate, + solution); + const auto newM = rcp(mMigrate); + auto cnewM = rcp_const_cast(newM); + auto newInput = rcp(new crsAdapter_t(cnewM, nWeights)); + + PrintFromRoot("Input adapter for Tpetra::CrsMatrix migrated to proc 0"); + + verifyInputAdapter(*newInput, *newM); + + } catch (std::exception &e) { + std::cout << e.what() << std::endl; + return EXIT_FAILURE; + } + + PrintFromRoot("PASS"); + +} diff --git a/packages/zoltan2/test/core/unit/input/TpetraRowMatrixInput.cpp b/packages/zoltan2/test/core/unit/input/TpetraRowMatrixInput.cpp index fcb420120867..6c9fd64ce9e1 100644 --- a/packages/zoltan2/test/core/unit/input/TpetraRowMatrixInput.cpp +++ b/packages/zoltan2/test/core/unit/input/TpetraRowMatrixInput.cpp @@ -50,32 +50,39 @@ * \todo test with geometric row coordinates. */ -#include - -#include #include #include +#include +#include -#include -#include #include #include +#include +#include +#include +#include +using Teuchos::Comm; +using Teuchos::Comm; using Teuchos::RCP; using Teuchos::rcp; using Teuchos::rcp_const_cast; using Teuchos::rcp_dynamic_cast; -using Teuchos::Comm; -typedef Tpetra::CrsMatrix ztcrsmatrix_t; -typedef Tpetra::RowMatrix ztrowmatrix_t; +using ztcrsmatrix_t = Tpetra::CrsMatrix; +using ztrowmatrix_t = Tpetra::RowMatrix; +using node_t = typename Zoltan2::InputTraits::node_t; +using device_t = typename node_t::device_type; +using rowAdapter_t = Zoltan2::TpetraRowMatrixAdapter; +using crsAdapter_t = Zoltan2::TpetraCrsMatrixAdapter; +using execspace_t = + typename rowAdapter_t::ConstWeightsHostView1D::execution_space; ////////////////////////////////////////////////////////////////////////// template void printMatrix(RCP > &comm, zlno_t nrows, - const zgno_t *rowIds, const offset_t *offsets, const zgno_t *colIds) -{ + const zgno_t *rowIds, const offset_t *offsets, const zgno_t *colIds) { int rank = comm->getRank(); int nprocs = comm->getSize(); comm->barrier(); @@ -98,169 +105,205 @@ void printMatrix(RCP > &comm, zlno_t nrows, ////////////////////////////////////////////////////////////////////////// -template -int verifyInputAdapter( - Zoltan2::TpetraRowMatrixAdapter &ia, ztrowmatrix_t &M) -{ - typedef typename Zoltan2::InputTraits::offset_t offset_t; +template +void TestMatrixIds(adapter_t &ia, matrix_t &matrix) { - RCP > comm = M.getComm(); - int fail = 0, gfail=0; + using idsHost_t = typename adapter_t::ConstIdsHostView; + using offsetsHost_t = typename adapter_t::ConstOffsetsHostView; + using localInds_t = + typename adapter_t::user_t::nonconst_local_inds_host_view_type; + using localVals_t = + typename adapter_t::user_t::nonconst_values_host_view_type; - if (!fail && ia.getLocalNumRows() != M.getLocalNumRows()) - fail = 4; - if (M.getLocalNumRows()){ - if (!fail && ia.getLocalNumColumns() != M.getLocalNumCols()) - fail = 6; - } + const auto nrows = matrix.getLocalNumRows(); + const auto ncols = matrix.getLocalNumEntries(); + const auto maxNumEntries = matrix.getLocalMaxNumRowEntries(); - gfail = globalFail(*comm, fail); + typename adapter_t::Base::ConstIdsHostView colIdsHost_("colIdsHost_", ncols); + typename adapter_t::Base::ConstOffsetsHostView offsHost_("offsHost_", + nrows + 1); - const zgno_t *rowIds=NULL; - ArrayRCP colIds; - ArrayRCP offsets; - size_t nrows=0; + localInds_t localColInds("localColInds", maxNumEntries); + localVals_t localVals("localVals", maxNumEntries); - if (!gfail){ + for (size_t r = 0; r < nrows; r++) { + size_t numEntries = 0; + matrix.getLocalRowCopy(r, localColInds, localVals, numEntries);; - nrows = ia.getLocalNumRows(); - ia.getRowIDsView(rowIds); - ia.getCRSView(offsets, colIds); + offsHost_(r + 1) = offsHost_(r) + numEntries; + for (size_t e = offsHost_(r), i = 0; e < offsHost_(r + 1); e++) { + colIdsHost_(e) = matrix.getColMap()->getGlobalElement(localColInds(i++)); + } + } - if (nrows != M.getLocalNumRows()) - fail = 8; + idsHost_t rowIdsHost; + ia.getRowIDsHostView(rowIdsHost); - gfail = globalFail(*comm, fail); + const auto matrixIDS = matrix.getRowMap()->getLocalElementList(); - if (gfail == 0){ - printMatrix(comm, nrows, rowIds, offsets.getRawPtr(), colIds.getRawPtr()); - } - else{ - if (!fail) fail = 10; - } - } - return fail; + Z2_TEST_COMPARE_ARRAYS(matrixIDS, rowIdsHost); + + idsHost_t colIdsHost; + offsetsHost_t offsetsHost; + ia.getCRSHostView(offsetsHost, colIdsHost); + + Z2_TEST_COMPARE_ARRAYS(colIdsHost_, colIdsHost); + Z2_TEST_COMPARE_ARRAYS(offsHost_, offsetsHost); } +template +void verifyInputAdapter(adapter_t &ia, matrix_t &matrix) { + using idsDevice_t = typename adapter_t::ConstIdsDeviceView; + using idsHost_t = typename adapter_t::ConstIdsHostView; + using offsetsDevice_t = typename adapter_t::ConstOffsetsDeviceView; + using offsetsHost_t = typename adapter_t::ConstOffsetsHostView; + using weightsDevice_t = typename adapter_t::WeightsDeviceView1D; + using weightsHost_t = typename adapter_t::WeightsHostView1D; + using constWeightsDevice_t = typename adapter_t::ConstWeightsDeviceView1D; + using constWeightsHost_t = typename adapter_t::ConstWeightsHostView1D; -int main(int narg, char *arg[]) -{ - Tpetra::ScopeGuard tscope(&narg, &arg); - Teuchos::RCP > comm = Tpetra::getDefaultComm(); + const auto nrows = ia.getLocalNumIDs(); - int rank = comm->getRank(); - int fail = 0, gfail=0; - bool aok = true; + Z2_TEST_EQUALITY(ia.getLocalNumRows(), matrix.getLocalNumRows()); + Z2_TEST_EQUALITY(ia.getLocalNumColumns(), matrix.getLocalNumCols()); + Z2_TEST_EQUALITY(ia.getLocalNumEntries(), matrix.getLocalNumEntries()); + + ///////////////////////////////// + //// getRowIdsView + ///////////////////////////////// + + idsDevice_t rowIdsDevice; + ia.getRowIDsDeviceView(rowIdsDevice); + idsHost_t rowIdsHost; + ia.getRowIDsHostView(rowIdsHost); + + TestDeviceHostView(rowIdsDevice, rowIdsHost); + + ///////////////////////////////// + //// setRowWeightsDevice + ///////////////////////////////// + Z2_TEST_THROW(ia.setRowWeightsDevice( + typename adapter_t::WeightsDeviceView1D{}, 50), + std::runtime_error); + + weightsDevice_t wgts0("wgts0", nrows); + Kokkos::parallel_for( + nrows, KOKKOS_LAMBDA(const int idx) { wgts0(idx) = idx * 2; }); + + Z2_TEST_NOTHROW(ia.setRowWeightsDevice(wgts0, 0)); + + // Don't reuse the same View, since we don't copy the values, + // we just assign the View (increase use count) + weightsDevice_t wgts1("wgts1", nrows); + Kokkos::parallel_for( + nrows, KOKKOS_LAMBDA(const int idx) { wgts1(idx) = idx * 3; }); - // Create object that can give us Tpetra matrices for testing. + Z2_TEST_NOTHROW(ia.setRowWeightsDevice(wgts1, 1)); - RCP uinput; - Teuchos::ParameterList params; - params.set("input file", "simple"); - params.set("file type", "Chaco"); + ///////////////////////////////// + //// getRowWeightsDevice + ///////////////////////////////// + { + weightsDevice_t weightsDevice; + Z2_TEST_NOTHROW(ia.getRowWeightsDeviceView(weightsDevice, 0)); - try{ - uinput = rcp(new UserInputForTests(params, comm)); + weightsHost_t weightsHost; + Z2_TEST_NOTHROW(ia.getRowWeightsHostView(weightsHost, 0)); + + TestDeviceHostView(weightsDevice, weightsHost); + + TestDeviceHostView(wgts0, weightsHost); } - catch(std::exception &e){ - aok = false; - std::cout << e.what() << std::endl; + { + weightsDevice_t weightsDevice; + Z2_TEST_NOTHROW(ia.getRowWeightsDeviceView(weightsDevice, 1)); + + weightsHost_t weightsHost; + Z2_TEST_NOTHROW(ia.getRowWeightsHostView(weightsHost, 1)); + + TestDeviceHostView(weightsDevice, weightsHost); + + TestDeviceHostView(wgts1, weightsHost); } - TEST_FAIL_AND_EXIT(*comm, aok, "input ", 1); + { + weightsDevice_t wgtsDevice; + Z2_TEST_THROW(ia.getRowWeightsDeviceView(wgtsDevice, 2), + std::runtime_error); - // Input matrix and row matrix cast from it. - RCP tM = uinput->getUITpetraCrsMatrix(); - RCP trM = rcp_dynamic_cast(tM); + weightsHost_t wgtsHost; + Z2_TEST_THROW(ia.getRowWeightsHostView(wgtsHost, 2), std::runtime_error); + } - RCP newM; // migrated matrix + TestMatrixIds(ia, matrix); +} - size_t nrows = trM->getLocalNumRows(); +////////////////////////////////////////////////////////////////////////// - // To test migration in the input adapter we need a Solution object. +int main(int narg, char *arg[]) { + using rowSoln_t = Zoltan2::PartitioningSolution; + using rowPart_t = rowAdapter_t::part_t; - RCP env = rcp(new Zoltan2::Environment(comm)); + using crsSoln_t = Zoltan2::PartitioningSolution; + using crsPart_t = crsAdapter_t::part_t; - int nWeights = 1; + Tpetra::ScopeGuard tscope(&narg, &arg); + const auto comm = Tpetra::getDefaultComm(); - typedef Zoltan2::TpetraRowMatrixAdapter adapter_t; - typedef Zoltan2::PartitioningSolution soln_t; - typedef adapter_t::part_t part_t; + auto rank = comm->getRank(); - part_t *p = new part_t [nrows]; - memset(p, 0, sizeof(part_t) * nrows); - ArrayRCP solnParts(p, 0, nrows, true); + try { + Teuchos::ParameterList params; + params.set("input file", "simple"); + params.set("file type", "Chaco"); - soln_t solution(env, comm, nWeights); - solution.setParts(solnParts); + auto uinput = rcp(new UserInputForTests(params, comm)); - ///////////////////////////////////////////////////////////// - // User object is Tpetra::RowMatrix - if (!gfail){ - if (rank==0) - std::cout << "Input adapter for Tpetra::RowMatrix" << std::endl; + // Input crs matrix and row matrix cast from it. + const auto crsMatrix = uinput->getUITpetraCrsMatrix(); + const auto rowMatrix = rcp_dynamic_cast(crsMatrix); - RCP ctrM = rcp_const_cast( - rcp_dynamic_cast(tM)); - RCP trMInput; + const auto nrows = rowMatrix->getLocalNumRows(); - try { - trMInput = rcp(new adapter_t(ctrM)); - } - catch (std::exception &e){ - aok = false; - std::cout << e.what() << std::endl; - } - TEST_FAIL_AND_EXIT(*comm, aok, "TpetraRowMatrixAdapter ", 1); + // To test migration in the input adapter we need a Solution object. + const auto env = rcp(new Zoltan2::Environment(comm)); - fail = verifyInputAdapter(*trMInput, *trM); + const int nWeights = 2; - gfail = globalFail(*comm, fail); + ///////////////////////////////////////////////////////////// + // User object is Tpetra::RowMatrix + ///////////////////////////////////////////////////////////// - if (!gfail){ - ztrowmatrix_t *mMigrate = NULL; - try{ - trMInput->applyPartitioningSolution(*trM, mMigrate, solution); - newM = rcp(mMigrate); - } - catch (std::exception &e){ - fail = 11; - std::cout << "Error caught: " << e.what() << std::endl; - } + PrintFromRoot("Input adapter for Tpetra::RowMatrix"); - gfail = globalFail(*comm, fail); + // Graph Adapters use crsGraph, original TpetraInput uses trM (=rowMatrix) + auto tpetraRowMatrixInput = rcp(new rowAdapter_t(rowMatrix, nWeights)); - if (!gfail){ - RCP cnewM = - rcp_const_cast(newM); - RCP newInput; - try{ - newInput = rcp(new adapter_t(cnewM)); - } - catch (std::exception &e){ - aok = false; - std::cout << e.what() << std::endl; - } - TEST_FAIL_AND_EXIT(*comm, aok, "TpetraRowMatrixAdapter 2 ", 1); + verifyInputAdapter(*tpetraRowMatrixInput, *rowMatrix); - if (rank==0){ - std::cout << - "Input adapter for Tpetra::RowMatrix migrated to proc 0" << - std::endl; - } - fail = verifyInputAdapter(*newInput, *newM); - if (fail) fail += 100; - gfail = globalFail(*comm, fail); - } - } - if (gfail){ - printFailureCode(*comm, fail); - } + rowPart_t *p = new rowPart_t[nrows]; + memset(p, 0, sizeof(rowPart_t) * nrows); + ArrayRCP solnParts(p, 0, nrows, true); + + rowSoln_t solution(env, comm, nWeights); + solution.setParts(solnParts); + + ztrowmatrix_t *mMigrate = NULL; + tpetraRowMatrixInput->applyPartitioningSolution(*rowMatrix, mMigrate, + solution); + const auto newM = rcp(mMigrate); + auto cnewM = rcp_const_cast(newM); + auto newInput = rcp(new rowAdapter_t(cnewM, nWeights)); + + PrintFromRoot("Input adapter for Tpetra::RowMatrix migrated to proc 0"); + + verifyInputAdapter(*newInput, *newM); + + } catch (std::exception &e) { + std::cout << e.what() << std::endl; + return EXIT_FAILURE; } - ///////////////////////////////////////////////////////////// - // DONE + PrintFromRoot("PASS"); - if (rank==0) - std::cout << "PASS" << std::endl; }