Skip to content

Commit

Permalink
FILTER: Concatenate Data Arrays (#1072)
Browse files Browse the repository at this point in the history
* Add Concatenate Data Arrays filter with unit test and documentation.

Signed-off-by: Joey Kleingers <[email protected]>
  • Loading branch information
joeykleingers authored Sep 27, 2024
1 parent af4f5c1 commit e6148a2
Show file tree
Hide file tree
Showing 9 changed files with 978 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Plugins/SimplnxCore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ set(FilterList
ComputeVectorColorsFilter
ComputeVertexToTriangleDistancesFilter
ComputeVolumeFractionsFilter
ConcatenateDataArraysFilter
ConditionalSetValueFilter
ConvertColorToGrayScaleFilter
ConvertDataFilter
Expand Down Expand Up @@ -168,6 +169,7 @@ set(AlgorithmList
ComputeTriangleGeomCentroids
ComputeVectorColors
ComputeVertexToTriangleDistances
ConcatenateDataArrays
ConvertColorToGrayScale
ConvertData
CreatePythonSkeleton
Expand Down
2 changes: 2 additions & 0 deletions src/Plugins/SimplnxCore/docs/CombineAttributeArraysFilter.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ _Combined (vector first)_: tuple 1 - { v1 v2 v3 s1 } ; tuple 2 - { v1 v2 v3 s1 }

The user may also select to normalize the resulting combined array. The normalization procedure will enforce a range of [0, 1] for all values in the combined array. This may be useful for combining two arrays that have different order of magnitude data. Note that this option will fundamentally change the underlying data in the combined array from the original incoming arrays.

**NOTE:** If you are wanting to instead concatenate/append data arrays together into a longer array, please see the [Concatenate Data Arrays](ConcatenateDataArraysFilter.md) filter.

% Auto generated parameter table will be inserted here

## Example Pipelines
Expand Down
27 changes: 27 additions & 0 deletions src/Plugins/SimplnxCore/docs/ConcatenateDataArraysFilter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Concatenate Data Arrays

## Group (Subgroup)

Core (Generation)

## Description

This **Filter** concatenates multiple input arrays by taking a list of input arrays and appending their data sequentially into a single output array. The concatenation process involves combining the arrays such that the order of the input arrays directly affects the structure of the output. For example, if the first input array contains 5 tuples and the second contains 7 tuples, the resulting output array will have 12 tuples, with the tuples from the second array appended directly after those from the first array.

This filter will always output an array with tuple dimensions that are 1-dimensional.

This filter is designed to handle arrays of matching array types and component dimensions. If the arrays have different array types or component dimensions, the filter will raise an error.

**NOTE:** If you are wanting to instead combine data arrays into a multi-component array, please see the [Combine Attribute Arrays](CombineAttributeArraysFilter.md) filter.

% Auto generated parameter table will be inserted here

## Example Pipelines

## License & Copyright

Please see the description file distributed with this **Plugin**

## DREAM3D-NX Help

If you need help, need to file a bug report or want to request a new feature, please head over to the [DREAM3DNX-Issues](https://github.com/BlueQuartzSoftware/DREAM3DNX-Issues/discussions) GitHub site where the community of DREAM3D-NX users can help answer your questions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "ConcatenateDataArrays.hpp"

#include "simplnx/DataStructure/IArray.hpp"

using namespace nx::core;

// -----------------------------------------------------------------------------
ConcatenateDataArrays::ConcatenateDataArrays(DataStructure& dataStructure, const IFilter::MessageHandler& msgHandler, const std::atomic_bool& shouldCancel,
ConcatenateDataArraysInputValues* inputValues)
: m_DataStructure(dataStructure)
, m_InputValues(inputValues)
, m_ShouldCancel(shouldCancel)
, m_MessageHandler(msgHandler)
{
}

// -----------------------------------------------------------------------------
ConcatenateDataArrays::~ConcatenateDataArrays() noexcept = default;

// -----------------------------------------------------------------------------
const std::atomic_bool& ConcatenateDataArrays::getCancel()
{
return m_ShouldCancel;
}

// -----------------------------------------------------------------------------
Result<> ConcatenateDataArrays::operator()()
{
const auto& outputDataArray = m_DataStructure.getDataRefAs<IArray>(m_InputValues->OutputArrayPath);
std::string arrayTypeName = outputDataArray.getTypeName();
switch(outputDataArray.getArrayType())
{
case IArray::ArrayType::DataArray: {
return ConcatenateArrays(m_DataStructure, m_InputValues->InputArrayPaths, m_InputValues->OutputArrayPath, m_MessageHandler, m_ShouldCancel);
}
case IArray::ArrayType::StringArray: {
return ConcatenateArraysImpl<StringArray>(m_DataStructure, m_InputValues->InputArrayPaths, m_InputValues->OutputArrayPath, m_MessageHandler, m_ShouldCancel);
}
case IArray::ArrayType::NeighborListArray: {
return ConcatenateNeighborLists(m_DataStructure, m_InputValues->InputArrayPaths, m_InputValues->OutputArrayPath, m_MessageHandler, m_ShouldCancel);
}
case IArray::ArrayType::Any: {
return MakeErrorResult(to_underlying(ConcatenateDataArrays::ErrorCodes::InputArraysEqualAny),
"Every array in the input arrays list has array type 'Any'. This SHOULD NOT be possible, so please contact the developers.");
}
default: {
return MakeErrorResult(to_underlying(ConcatenateDataArrays::ErrorCodes::InputArraysUnsupported),
"Every array in the input arrays list has array type '{}'. This is an array type that is currently not supported by this filter, so please contact the developers.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
#pragma once

#include "SimplnxCore/SimplnxCore_export.hpp"

#include "simplnx/DataStructure/DataArray.hpp"
#include "simplnx/DataStructure/DataStructure.hpp"
#include "simplnx/DataStructure/NeighborList.hpp"
#include "simplnx/DataStructure/StringArray.hpp"
#include "simplnx/Filter/IFilter.hpp"
#include "simplnx/Utilities/DataArrayUtilities.hpp"
#include "simplnx/Utilities/FilterUtilities.hpp"

namespace nx::core
{
template <typename T>
struct is_allowed_array_type : std::false_type
{
};

template <typename T>
struct is_allowed_array_type<DataArray<T>> : std::true_type
{
};

template <>
struct is_allowed_array_type<StringArray> : std::true_type
{
};

template <typename ArrayType>
typename std::enable_if<is_allowed_array_type<ArrayType>::value, Result<>>::type ConcatenateArraysImpl(DataStructure& dataStructure, const std::vector<DataPath>& inputArrayPaths,
const DataPath& outputArrayPath, const IFilter::MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel)
{
auto& outputDataArray = dataStructure.getDataRefAs<ArrayType>(outputArrayPath);
usize destTupleOffset = 0;
for(const auto& inputArrayPath : inputArrayPaths)
{
if(shouldCancel)
{
return {};
}

messageHandler({IFilter::Message::Type::Info, fmt::format("Concatenating array '{}'...", inputArrayPath.toString())});
const auto& inputDataArray = dataStructure.getDataRefAs<ArrayType>(inputArrayPath);
auto result = CopyFromArray::CopyData(inputDataArray, outputDataArray, destTupleOffset, 0, inputDataArray.getNumberOfTuples());
if(result.invalid())
{
return result;
}
destTupleOffset += inputDataArray.getNumberOfTuples();
}

return {};
}

template <typename T>
Result<> ConcatenateNeighborListsImpl(DataStructure& dataStructure, const std::vector<DataPath>& inputArrayPaths, const DataPath& outputArrayPath, const IFilter::MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel)
{
auto& outputNeighborList = dataStructure.getDataRefAs<NeighborList<T>>(outputArrayPath);
int32 currentOutputTuple = 0;
for(const auto& inputNeighborListPath : inputArrayPaths)
{
if(shouldCancel)
{
return {};
}

messageHandler({IFilter::Message::Type::Info, fmt::format("Concatenating neighbor list '{}'...", inputNeighborListPath.toString())});
const auto& inputNeighborList = dataStructure.getDataRefAs<NeighborList<T>>(inputNeighborListPath);
for(int32 listIdx = 0; listIdx < inputNeighborList.getNumberOfLists(); ++listIdx)
{
outputNeighborList.setList(currentOutputTuple, inputNeighborList.getList(listIdx));
currentOutputTuple++;
}
}

return {};
}

struct SIMPLNXCORE_EXPORT ConcatenateDataArraysInputValues
{
std::vector<DataPath> InputArrayPaths;
DataPath OutputArrayPath;
};

/**
* @class
*/
class SIMPLNXCORE_EXPORT ConcatenateDataArrays
{
public:
ConcatenateDataArrays(DataStructure& dataStructure, const IFilter::MessageHandler& msgHandler, const std::atomic_bool& shouldCancel, ConcatenateDataArraysInputValues* inputValues);
~ConcatenateDataArrays() noexcept;

ConcatenateDataArrays(const ConcatenateDataArrays&) = delete;
ConcatenateDataArrays(ConcatenateDataArrays&&) noexcept = delete;
ConcatenateDataArrays& operator=(const ConcatenateDataArrays&) = delete;
ConcatenateDataArrays& operator=(ConcatenateDataArrays&&) noexcept = delete;

// Error Codes
enum class ErrorCodes : int32
{
EmptyInputArrays = -2300,
OneInputArray = -2301,
NonPositiveTupleDimValue = -2302,
TypeNameMismatch = -2303,
ComponentShapeMismatch = -2304,
InputArraysEqualAny = -2305,
InputArraysUnsupported = -2306
};

// Warning Codes
enum class WarningCodes : int32
{
MultipleTupleDimsNotSupported = -100
};

Result<> operator()();

const std::atomic_bool& getCancel();

private:
DataStructure& m_DataStructure;
const ConcatenateDataArraysInputValues* m_InputValues = nullptr;
const std::atomic_bool& m_ShouldCancel;
const IFilter::MessageHandler& m_MessageHandler;

struct ConcatenateDataArraysTemplateImpl
{
template <typename T>
void operator()(DataStructure& dataStructure, const std::vector<DataPath>& inputArrayPaths, const DataPath& outputArrayPath, const IFilter::MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel, Result<>& result)
{
result = ConcatenateArraysImpl<DataArray<T>>(dataStructure, inputArrayPaths, outputArrayPath, messageHandler, shouldCancel);
}
};

struct ConcatenateNeighborListsTemplateImpl
{
template <typename T>
void operator()(DataStructure& dataStructure, const std::vector<DataPath>& inputArrayPaths, const DataPath& outputArrayPath, const IFilter::MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel, Result<>& result)
{
result = ConcatenateNeighborListsImpl<T>(dataStructure, inputArrayPaths, outputArrayPath, messageHandler, shouldCancel);
}
};

static Result<> ConcatenateArrays(DataStructure& dataStructure, const std::vector<DataPath>& inputArrayPaths, const DataPath& outputArrayPath, const IFilter::MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel)
{
const auto& outputDataArray = dataStructure.getDataRefAs<IDataArray>(outputArrayPath);
Result<> result;
ExecuteDataFunction(ConcatenateDataArraysTemplateImpl{}, outputDataArray.getDataType(), dataStructure, inputArrayPaths, outputArrayPath, messageHandler, shouldCancel, result);
return result;
}

static Result<> ConcatenateNeighborLists(DataStructure& dataStructure, const std::vector<DataPath>& inputArrayPaths, const DataPath& outputArrayPath, const IFilter::MessageHandler& messageHandler,
const std::atomic_bool& shouldCancel)
{
const auto& outputNeighborList = dataStructure.getDataRefAs<INeighborList>(outputArrayPath);
Result<> result;
ExecuteNeighborFunction(ConcatenateNeighborListsTemplateImpl{}, outputNeighborList.getDataType(), dataStructure, inputArrayPaths, outputArrayPath, messageHandler, shouldCancel, result);
return result;
}
};

} // namespace nx::core
Loading

0 comments on commit e6148a2

Please sign in to comment.