//============================================================================ // 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. // // Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 Los Alamos National Security. // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National // Laboratory (LANL), the U.S. Government retains certain rights in // this software. //============================================================================ #ifndef vtk_m_worklet_AverageByKey_h #define vtk_m_worklet_AverageByKey_h #include #include #include #include #include #include #include #include #include #include #include namespace vtkm { namespace worklet { struct AverageByKey { struct AverageWorklet : public vtkm::worklet::WorkletReduceByKey { typedef void ControlSignature(KeysIn keys, ValuesIn<> valuesIn, ReducedValuesOut<> averages); typedef _3 ExecutionSignature(_2); using InputDomain = _1; template VTKM_EXEC typename ValuesVecType::ComponentType operator()(const ValuesVecType& valuesIn) const { using ComponentType = typename ValuesVecType::ComponentType; ComponentType sum = valuesIn[0]; for (vtkm::IdComponent index = 1; index < valuesIn.GetNumberOfComponents(); ++index) { ComponentType component = valuesIn[index]; sum = sum + component; } return sum / static_cast(valuesIn.GetNumberOfComponents()); } }; /// \brief Compute average values based on a set of Keys. /// /// This method uses an existing \c Keys object to collected values by those keys and find /// the average of those groups. /// template VTKM_CONT static void Run(const vtkm::worklet::Keys& keys, const vtkm::cont::ArrayHandle& inValues, vtkm::cont::ArrayHandle& outAverages, Device) { VTKM_IS_DEVICE_ADAPTER_TAG(Device); vtkm::worklet::DispatcherReduceByKey dispatcher; dispatcher.Invoke(keys, inValues, outAverages); } /// \brief Compute average values based on a set of Keys. /// /// This method uses an existing \c Keys object to collected values by those keys and find /// the average of those groups. /// template VTKM_CONT static vtkm::cont::ArrayHandle Run( const vtkm::worklet::Keys& keys, const vtkm::cont::ArrayHandle& inValues, Device) { VTKM_IS_DEVICE_ADAPTER_TAG(Device); vtkm::cont::ArrayHandle outAverages; Run(keys, inValues, outAverages, Device()); return outAverages; } struct DivideWorklet : public vtkm::worklet::WorkletMapField { typedef void ControlSignature(FieldIn<>, FieldIn<>, FieldOut<>); typedef void ExecutionSignature(_1, _2, _3); template VTKM_EXEC void operator()(const ValueType& v, const vtkm::Id& count, ValueType& vout) const { using ComponentType = typename VecTraits::ComponentType; vout = v * ComponentType(1. / static_cast(count)); } template VTKM_EXEC void operator()(const T1&, const vtkm::Id&, T2&) const { } }; /// \brief Compute average values based on an array of keys. /// /// This method uses an array of keys and an equally sized array of values. The keys in that /// array are collected into groups of equal keys, and the values corresponding to those groups /// are averaged. /// /// This method is less sensitive to constructing large groups with the keys than doing the /// similar reduction with a \c Keys object. For example, if you have only one key, the reduction /// will still be parallel. However, if you need to run the average of different values with the /// same keys, you will have many duplicated operations. /// template VTKM_CONT static void Run(const vtkm::cont::ArrayHandle& keyArray, const vtkm::cont::ArrayHandle& valueArray, vtkm::cont::ArrayHandle& outputKeyArray, vtkm::cont::ArrayHandle& outputValueArray, DeviceAdapter) { using Algorithm = vtkm::cont::DeviceAdapterAlgorithm; using ValueInArray = vtkm::cont::ArrayHandle; using IdArray = vtkm::cont::ArrayHandle; using ValueArray = vtkm::cont::ArrayHandle; // sort the indexed array vtkm::cont::ArrayHandleIndex indexArray(keyArray.GetNumberOfValues()); IdArray indexArraySorted; vtkm::cont::ArrayHandle keyArraySorted; Algorithm::Copy(keyArray, keyArraySorted); // keep the input key array unchanged Algorithm::Copy(indexArray, indexArraySorted); Algorithm::SortByKey(keyArraySorted, indexArraySorted, vtkm::SortLess()); // generate permultation array based on the indexes using PermutatedValueArray = vtkm::cont::ArrayHandlePermutation; PermutatedValueArray valueArraySorted = vtkm::cont::make_ArrayHandlePermutation(indexArraySorted, valueArray); // reduce both sumArray and countArray by key using ConstIdArray = vtkm::cont::ArrayHandleConstant; ConstIdArray constOneArray(1, valueArray.GetNumberOfValues()); IdArray countArray; ValueArray sumArray; vtkm::cont::ArrayHandleZip inputZipHandle(valueArraySorted, constOneArray); vtkm::cont::ArrayHandleZip outputZipHandle(sumArray, countArray); Algorithm::ReduceByKey( keyArraySorted, inputZipHandle, outputKeyArray, outputZipHandle, vtkm::Add()); // get average DispatcherMapField().Invoke( sumArray, countArray, outputValueArray); } }; } } // vtkm::worklet #endif //vtk_m_worklet_AverageByKey_h