//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ #define vtk_m_cont_CellSetExplicit_cxx #include #include #include #include #include #include #include namespace { template void DoBuildReverseConnectivity( const vtkm::cont::ArrayHandle& connections, const vtkm::cont::ArrayHandle& offsets, vtkm::Id numberOfPoints, vtkm::cont::detail::DefaultVisitPointsWithCellsConnectivityExplicit& visitPointsWithCells, vtkm::cont::DeviceAdapterId suggestedDevice) { using CellsWithPointsConnectivity = vtkm::cont::internal:: ConnectivityExplicitInternals; // Make a fake visitCellsWithPoints to pass to ComputeRConnTable. This is a bit of a // patchwork from changing implementation. CellsWithPointsConnectivity visitCellsWithPoints; visitCellsWithPoints.ElementsValid = true; visitCellsWithPoints.Connectivity = connections; visitCellsWithPoints.Offsets = offsets; bool success = vtkm::cont::TryExecuteOnDevice(suggestedDevice, [&](vtkm::cont::DeviceAdapterId realDevice) { vtkm::cont::internal::ComputeRConnTable( visitPointsWithCells, visitCellsWithPoints, numberOfPoints, realDevice); return true; }); if (!success) { throw vtkm::cont::ErrorExecution("Failed to run CellSetExplicit reverse " "connectivity builder."); } } struct BuildReverseConnectivityForCellSetType { template void BuildExplicit( const vtkm::cont::CellSetExplicit*, const vtkm::cont::UnknownArrayHandle* connections, const vtkm::cont::UnknownArrayHandle* offsets, vtkm::Id numberOfPoints, vtkm::cont::detail::DefaultVisitPointsWithCellsConnectivityExplicit* visitPointsWithCells, vtkm::cont::DeviceAdapterId* device) const { if (visitPointsWithCells->ElementsValid) { return; // Already computed reverse } using ConnectArrayType = vtkm::cont::ArrayHandle; using OffsetArrayType = vtkm::cont::ArrayHandle; if (connections->CanConvert() && offsets->CanConvert()) { DoBuildReverseConnectivity(connections->AsArrayHandle(), offsets->AsArrayHandle(), numberOfPoints, *visitPointsWithCells, *device); } } void BuildExplicit(...) const { // Not an explicit cell set, so skip. } // Note that we are doing something a little weird here. We are taking a method templated // on the cell set type, getting pointers of many of the arguments, and then calling // a different overloaded method to do the actual work. Here is why. // // Our ultimate goal is to call one method if operating on `CellSetExplict` or // _any subclass_. We also want to ignore any cell type that is not a `CellSetExplicit` // or one of its sublcasses. So we want one templated method that specializes on a // `CellSetExplicit` with its three template arguments and another that is templated on // any `CellSet`. That works for a class of `CellSetExplicit`, but not of a subclass. // A subclass will match the more generic class. // // We can get around that by use variadic arguments (e.g. `...` for the arguments), which // we can easily do since we just want to ignore the arguments. C++ will match the arguments // with templates before matching the C variadic arguments. However, these variadic // arguments only work for POD types. To convert to POD types, we make a new overloaded // method that accepts pointers instead. (Not sure why pointers work but references do not.) template void operator()( const CellSetType& cellset, const vtkm::cont::UnknownArrayHandle& connections, const vtkm::cont::UnknownArrayHandle& offsets, vtkm::Id numberOfPoints, vtkm::cont::detail::DefaultVisitPointsWithCellsConnectivityExplicit& visitPointsWithCells, vtkm::cont::DeviceAdapterId device) const { this->BuildExplicit( &cellset, &connections, &offsets, numberOfPoints, &visitPointsWithCells, &device); } }; } // anonymous namespace namespace vtkm { namespace cont { template class VTKM_CONT_EXPORT CellSetExplicit<>; // default template class VTKM_CONT_EXPORT CellSetExplicit::StorageTag, VTKM_DEFAULT_CONNECTIVITY_STORAGE_TAG, typename vtkm::cont::ArrayHandleCounting::StorageTag>; namespace detail { void BuildReverseConnectivity( const vtkm::cont::UnknownArrayHandle& connections, const vtkm::cont::UnknownArrayHandle& offsets, vtkm::Id numberOfPoints, vtkm::cont::detail::DefaultVisitPointsWithCellsConnectivityExplicit& visitPointsWithCells, vtkm::cont::DeviceAdapterId device) { if (visitPointsWithCells.ElementsValid) { return; // Already computed } vtkm::ListForEach(BuildReverseConnectivityForCellSetType{}, VTKM_DEFAULT_CELL_SET_LIST{}, connections, offsets, numberOfPoints, visitPointsWithCells, device); if (!visitPointsWithCells.ElementsValid) { VTKM_LOG_S(vtkm::cont::LogLevel::Warn, "BuildReverseConnectivity attempted for all known cell set types; " "falling back to copy connectivity arrays."); vtkm::cont::ArrayHandle connectionsCopy; vtkm::cont::ArrayCopy(connections, connectionsCopy); vtkm::cont::ArrayHandle offsetsCopy; vtkm::cont::ArrayCopy(offsets, offsetsCopy); DoBuildReverseConnectivity( connectionsCopy, offsetsCopy, numberOfPoints, visitPointsWithCells, device); } } } // namespace vtkm::cont::detail } // namespace vtkm::cont } // namespace vtkm