diff --git a/src/Plugins/OrientationAnalysis/CMakeLists.txt b/src/Plugins/OrientationAnalysis/CMakeLists.txt index 381e7aced8..adf68735bf 100644 --- a/src/Plugins/OrientationAnalysis/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/CMakeLists.txt @@ -62,6 +62,7 @@ set(FilterList MergeTwinsFilter NeighborOrientationCorrelationFilter ReadAngDataFilter + ReadChannel5DataFilter ReadCtfDataFilter ReadEnsembleInfoFilter ReadGrainMapper3DFilter @@ -194,6 +195,7 @@ set(filter_algorithms MergeTwins NeighborOrientationCorrelation ReadAngData + ReadChannel5Data ReadCtfData ReadEnsembleInfo ReadGrainMapper3D diff --git a/src/Plugins/OrientationAnalysis/docs/ReadChannel5DataFilter.md b/src/Plugins/OrientationAnalysis/docs/ReadChannel5DataFilter.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadChannel5Data.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadChannel5Data.cpp new file mode 100644 index 0000000000..081bf676d4 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadChannel5Data.cpp @@ -0,0 +1,185 @@ +#include "ReadChannel5Data.hpp" + +#include "simplnx/Common/RgbColor.hpp" +#include "simplnx/DataStructure/DataArray.hpp" +#include "simplnx/DataStructure/Geometry/ImageGeom.hpp" +#include "simplnx/DataStructure/StringArray.hpp" +#include "simplnx/Utilities/Math/MatrixMath.hpp" +#include "simplnx/Utilities/StringUtilities.hpp" + +#include "EbsdLib/Core/Orientation.hpp" + +using namespace nx::core; + +using FloatVec3Type = std::vector; + +namespace +{ +template +void copyRawData(const ReadChannel5DataInputValues* m_InputValues, size_t numElements, DataStructure& m_DataStructure, CprReader& m_Reader, const std::string& name, DataPath& dataArrayPath) +{ + using ArrayType = DataArray; + auto& dataRef = m_DataStructure.getDataRefAs(dataArrayPath); + auto* dataStorePtr = dataRef.getDataStore(); + + const nonstd::span rawDataPtr(reinterpret_cast(m_Reader.getPointerByName(name)), numElements); + // std::copy(rawDataPtr.begin(), rawDataPtr.end(), dataStorePtr->begin() + offset); + for(size_t idx = 0; idx < numElements; idx++) + { + dataStorePtr->setValue(idx, rawDataPtr[idx]); + } +} + +} // namespace + +// ----------------------------------------------------------------------------- +ReadChannel5Data::ReadChannel5Data(DataStructure& dataStructure, const IFilter::MessageHandler& msgHandler, const std::atomic_bool& shouldCancel, ReadChannel5DataInputValues* inputValues) +: m_DataStructure(dataStructure) +, m_MessageHandler(msgHandler) +, m_ShouldCancel(shouldCancel) +, m_InputValues(inputValues) +{ +} + +// ----------------------------------------------------------------------------- +ReadChannel5Data::~ReadChannel5Data() noexcept = default; + +// ----------------------------------------------------------------------------- +Result<> ReadChannel5Data::operator()() +{ + CprReader reader; + reader.setFileName(m_InputValues->InputFile.string()); + const int32_t err = reader.readFile(); + if(err < 0) + { + return MakeErrorResult(reader.getErrorCode(), reader.getErrorMessage()); + } + + const auto result = loadMaterialInfo(&reader); + if(result.first < 0) + { + return MakeErrorResult(result.first, result.second); + } + + copyRawEbsdData(&reader); + + return {}; +} + +// ----------------------------------------------------------------------------- +std::pair ReadChannel5Data::loadMaterialInfo(CprReader* reader) const +{ + const std::vector phases = reader->getPhaseVector(); + if(phases.empty()) + { + return {reader->getErrorCode(), reader->getErrorMessage()}; + } + + const DataPath CellEnsembleAttributeMatrixPath = m_InputValues->DataContainerName.createChildPath(m_InputValues->CellEnsembleAttributeMatrixName); + + auto& crystalStructures = m_DataStructure.getDataRefAs(CellEnsembleAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::CrystalStructures)); + + auto& materialNames = m_DataStructure.getDataRefAs(CellEnsembleAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::MaterialName)); + + auto& latticeConstants = m_DataStructure.getDataRefAs(CellEnsembleAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::LatticeConstants)); + + const std::string k_InvalidPhase = "Invalid Phase"; + + // Initialize the zero'th element to unknowns. The other elements will + // be filled in based on values from the data file + crystalStructures[0] = EbsdLib::CrystalStructure::UnknownCrystalStructure; + materialNames[0] = k_InvalidPhase; + + for(size_t i = 0; i < 6; i++) + { + latticeConstants.getDataStoreRef().setComponent(0, i, 0.0F); + } + + for(const CtfPhase::Pointer& phase : phases) + { + const int32_t phaseID = phase->getPhaseIndex(); + crystalStructures[phaseID] = phase->determineOrientationOpsIndex(); + std::string materialName = phase->getMaterialName(); + materialName = nx::core::StringUtilities::replace(materialName, "MaterialName", ""); + materialName = nx::core::StringUtilities::trimmed(materialName); + materialNames[phaseID] = materialName; + + std::vector lattConst = phase->getLatticeConstants(); + + for(size_t i = 0; i < 6; i++) + { + latticeConstants.getDataStoreRef().setComponent(phaseID, i, lattConst[i]); + } + } + return {0, ""}; +} + +// ----------------------------------------------------------------------------- +void ReadChannel5Data::copyRawEbsdData(CprReader* reader) const +{ + const DataPath cellAttributeMatrixPath = m_InputValues->DataContainerName.createChildPath(m_InputValues->CellAttributeMatrixName); + + std::vector cDims = {1}; + + const auto& imageGeom = m_DataStructure.getDataRefAs(m_InputValues->DataContainerName); + const size_t totalCells = imageGeom.getNumberOfCells(); + + // Prepare the Cell Attribute Matrix with the correct number of tuples based on the total Cells being read from the file. + std::vector tDims = {imageGeom.getNumXCells(), imageGeom.getNumYCells(), imageGeom.getNumZCells()}; + + std::vector fieldParsers = reader->createFieldParsers(m_InputValues->InputFile.string()); + for(const auto& parser : fieldParsers) + { + std::string fieldName = parser.FieldDefinition.FieldName; + DataPath dataArrayPath = cellAttributeMatrixPath.createChildPath(fieldName); + // if(m_DataStructure.getData(dataArrayPath) != nullptr) + // { + // std::cout << fieldName << " Exists in Data Structure\n"; + // } + + if(parser.FieldDefinition.numericType == EbsdLib::NumericTypes::Type::Int32) + { + copyRawData(m_InputValues, totalCells, m_DataStructure, *reader, fieldName, dataArrayPath); + } + else if(parser.FieldDefinition.numericType == EbsdLib::NumericTypes::Type::Float) + { + copyRawData(m_InputValues, totalCells, m_DataStructure, *reader, fieldName, dataArrayPath); + } + else if(parser.FieldDefinition.numericType == EbsdLib::NumericTypes::Type::UInt8) + { + copyRawData(m_InputValues, totalCells, m_DataStructure, *reader, fieldName, dataArrayPath); + } + } + + // Copy the data from the 'Phase' array into the 'Phases' array + if(m_InputValues->CreateCompatibleArrays) + { + auto& targetArray = m_DataStructure.getDataRefAs(cellAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::Phases)); + auto* phasePtr = reinterpret_cast(reader->getPointerByName(EbsdLib::Ctf::Phase)); + for(size_t i = 0; i < totalCells; i++) + { + // if(phasePtr[i] < 1) + // { + // phasePtr[i] = 1; + // } + targetArray[i] = phasePtr[i]; + } + } + + // Condense the Euler Angles from 3 separate arrays into a single 1x3 array + if(m_InputValues->CreateCompatibleArrays) + { + const auto* fComp0 = reinterpret_cast(reader->getPointerByName(EbsdLib::Ctf::phi1)); + const auto* fComp1 = reinterpret_cast(reader->getPointerByName(EbsdLib::Ctf::Phi)); + const auto* fComp2 = reinterpret_cast(reader->getPointerByName(EbsdLib::Ctf::phi2)); + cDims[0] = 3; + + auto& cellEulerAngles = m_DataStructure.getDataRefAs(cellAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::EulerAngles)); + for(size_t i = 0; i < totalCells; i++) + { + cellEulerAngles[3 * i] = fComp0[i]; + cellEulerAngles[3 * i + 1] = fComp1[i]; + cellEulerAngles[3 * i + 2] = fComp2[i]; + } + } +} diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadChannel5Data.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadChannel5Data.hpp new file mode 100644 index 0000000000..c9ba7451b1 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/Algorithms/ReadChannel5Data.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include "OrientationAnalysis/OrientationAnalysis_export.hpp" + +#include "simplnx/DataStructure/DataArray.hpp" +#include "simplnx/DataStructure/DataPath.hpp" +#include "simplnx/DataStructure/DataStructure.hpp" +#include "simplnx/DataStructure/IDataArray.hpp" +#include "simplnx/Filter/IFilter.hpp" +#include "simplnx/Parameters/FileSystemPathParameter.hpp" + +#include "EbsdLib/IO/HKL/CprReader.h" + +#include +namespace fs = std::filesystem; + +namespace nx::core +{ + +struct ORIENTATIONANALYSIS_EXPORT ReadChannel5DataInputValues +{ + FileSystemPathParameter::ValueType InputFile; + DataPath DataContainerName; + std::string CellAttributeMatrixName; + std::string CellEnsembleAttributeMatrixName; + bool EdaxHexagonalAlignment; + bool CreateCompatibleArrays; +}; + +struct ORIENTATIONANALYSIS_EXPORT Ang_Private_Data +{ + std::array dims = {0, 0, 0}; + std::array resolution = {0.0F, 0.0F, 0.0F}; + std::array origin = {0.0F, 0.0F, 0.0F}; + std::vector phases; + int32_t units = 0; +}; + +/** + * @brief The ReadChannel5DataPrivate class is a private implementation of the ReadChannel5Data class + */ +class ORIENTATIONANALYSIS_EXPORT ReadChannel5DataPrivate +{ +public: + ReadChannel5DataPrivate() = default; + ~ReadChannel5DataPrivate() = default; + + ReadChannel5DataPrivate(const ReadChannel5DataPrivate&) = delete; // Copy Constructor Not Implemented + ReadChannel5DataPrivate(ReadChannel5DataPrivate&&) = delete; // Move Constructor Not Implemented + ReadChannel5DataPrivate& operator=(const ReadChannel5DataPrivate&) = delete; // Copy Assignment Not Implemented + ReadChannel5DataPrivate& operator=(ReadChannel5DataPrivate&&) = delete; // Move Assignment Not Implemented + + Ang_Private_Data m_Data; + + std::string m_InputFile_Cache; + fs::file_time_type m_TimeStamp_Cache; +}; + +/** + * @class ReadChannel5Data + * @brief This filter will read a single .ang file into a new Image Geometry, allowing the immediate use of Filters on the data instead of having to generate the intermediate + * .h5ebsd file. + */ +class ORIENTATIONANALYSIS_EXPORT ReadChannel5Data +{ +public: + ReadChannel5Data(DataStructure& dataStructure, const IFilter::MessageHandler& msgHandler, const std::atomic_bool& shouldCancel, ReadChannel5DataInputValues* inputValues); + ~ReadChannel5Data() noexcept; + + ReadChannel5Data(const ReadChannel5Data&) = delete; // Copy Constructor Not Implemented + ReadChannel5Data(ReadChannel5Data&&) = delete; // Move Constructor Not Implemented + ReadChannel5Data& operator=(const ReadChannel5Data&) = delete; // Copy Assignment Not Implemented + ReadChannel5Data& operator=(ReadChannel5Data&&) = delete; // Move Assignment Not Implemented + + Result<> operator()(); + +private: + DataStructure& m_DataStructure; + const IFilter::MessageHandler& m_MessageHandler; + const std::atomic_bool& m_ShouldCancel; + const ReadChannel5DataInputValues* m_InputValues = nullptr; + + /** + * @brief + * @param reader + * @return Error code. + */ + std::pair loadMaterialInfo(CprReader* reader) const; + + /** + * @brief + * @param reader + */ + void copyRawEbsdData(CprReader* reader) const; +}; + +} // namespace nx::core diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ReadChannel5DataFilter.cpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ReadChannel5DataFilter.cpp new file mode 100644 index 0000000000..6269261f1d --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ReadChannel5DataFilter.cpp @@ -0,0 +1,288 @@ +#include "ReadChannel5DataFilter.hpp" + +#include "OrientationAnalysis/Filters/Algorithms/ReadChannel5Data.hpp" + +#include "simplnx/DataStructure/DataPath.hpp" +#include "simplnx/DataStructure/Geometry/ImageGeom.hpp" +#include "simplnx/Filter/Actions/CreateArrayAction.hpp" +#include "simplnx/Filter/Actions/CreateAttributeMatrixAction.hpp" +#include "simplnx/Filter/Actions/CreateImageGeometryAction.hpp" +#include "simplnx/Filter/Actions/CreateStringArrayAction.hpp" +#include "simplnx/Filter/Actions/DeleteDataAction.hpp" +#include "simplnx/Parameters/BoolParameter.hpp" +#include "simplnx/Parameters/DataGroupCreationParameter.hpp" +#include "simplnx/Parameters/DataObjectNameParameter.hpp" +#include "simplnx/Parameters/FileSystemPathParameter.hpp" +#include "simplnx/Utilities/SIMPLConversion.hpp" + +#include "EbsdLib/IO/HKL/CprReader.h" +#include "EbsdLib/IO/HKL/CtfFields.h" +#include "EbsdLib/IO/HKL/CtfPhase.h" + +#include + +namespace fs = std::filesystem; + +using namespace nx::core; + +namespace nx::core +{ +//------------------------------------------------------------------------------ +std::string ReadChannel5DataFilter::name() const +{ + return FilterTraits::name.str(); +} + +//------------------------------------------------------------------------------ +std::string ReadChannel5DataFilter::className() const +{ + return FilterTraits::className; +} + +//------------------------------------------------------------------------------ +Uuid ReadChannel5DataFilter::uuid() const +{ + return FilterTraits::uuid; +} + +//------------------------------------------------------------------------------ +std::string ReadChannel5DataFilter::humanName() const +{ + return "Read Oxford Instr. Channel 5 (.cpr/.crc)"; +} + +//------------------------------------------------------------------------------ +std::vector ReadChannel5DataFilter::defaultTags() const +{ + return {className(), "IO", "Input", "Read", "Import", "Oxford", "cpr", "crc", "Channel 5", "EBSD"}; +} + +//------------------------------------------------------------------------------ +Parameters ReadChannel5DataFilter::parameters() const +{ + Parameters params; + // Create the parameter descriptors that are needed for this filter + params.insertSeparator(Parameters::Separator{"Input Parameter(s)"}); + params.insert(std::make_unique(k_InputFile_Key, "Input File (.cpr)", "The input .cpr file path. The .crc file must also exist.", fs::path("input.cpr"), + FileSystemPathParameter::ExtensionsType{".cpr"}, FileSystemPathParameter::PathType::InputFile)); + params.insert(std::make_unique(k_EdaxHexagonalAlignment_Key, "Convert Hexagonal X-Axis to EDAX Standard", + "Whether or not to convert a Hexagonal phase to the EDAX standard for x-axis alignment", false)); + params.insert(std::make_unique(k_CreateCompatibleArrays_Key, "Convert Data Arrays to be more compatible with DREAM3D", + "Some arrays will be converted from the type they are in the file to more compatible types.", true)); + + params.insertSeparator(Parameters::Separator{"Output Image Geometry"}); + params.insert(std::make_unique(k_CreatedImageGeometryPath_Key, "Image Geometry", "The path to the created Image Geometry", DataPath({ImageGeom::k_TypeName}))); + params.insertSeparator(Parameters::Separator{"Output Cell Attribute Matrix"}); + params.insert(std::make_unique(k_CellAttributeMatrixName_Key, "Cell Attribute Matrix", "The name of the cell data attribute matrix for the created Image Geometry", + ImageGeom::k_CellDataName)); + params.insertSeparator(Parameters::Separator{"Output Ensemble Attribute Matrix"}); + params.insert(std::make_unique(k_CellEnsembleAttributeMatrixName_Key, "Ensemble Attribute Matrix", "The Attribute Matrix where the phase information is stored.", + "Cell Ensemble Data")); + + return params; +} + +//------------------------------------------------------------------------------ +IFilter::VersionType ReadChannel5DataFilter::parametersVersion() const +{ + return 1; +} + +//------------------------------------------------------------------------------ +IFilter::UniquePointer ReadChannel5DataFilter::clone() const +{ + return std::make_unique(); +} + +//------------------------------------------------------------------------------ +IFilter::PreflightResult ReadChannel5DataFilter::preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + auto pInputFileValue = filterArgs.value(k_InputFile_Key); + auto pImageGeometryPath = filterArgs.value(k_CreatedImageGeometryPath_Key); + auto pCellAttributeMatrixNameValue = filterArgs.value(k_CellAttributeMatrixName_Key); + auto pCellEnsembleAttributeMatrixNameValue = filterArgs.value(k_CellEnsembleAttributeMatrixName_Key); + auto pCreateCompatibleTypes = filterArgs.value(k_CreateCompatibleArrays_Key); + + PreflightResult preflightResult; + + // First validate that the matching .crc file exists + fs::path crcPath = pInputFileValue; + crcPath.replace_extension(".crc"); + try + { + if(!std::filesystem::exists(crcPath)) + { + return {MakeErrorResult(-66500, fmt::format("Matching .crc file does not exist. '{}' ", crcPath.string())), {}}; + } + } catch(std::exception& e) + { + return {MakeErrorResult(-66501, fmt::format("Attempting to figure out if '{}' exists threw a std::exception. Please report this to the developers.", crcPath.string())), {}}; + } + + // Read the CPR file to gather the Geometry information and what arrays are present in the file. + CprReader reader; + reader.setFileName(pInputFileValue.string()); + int32_t err = reader.readHeaderOnly(); + if(err < 0) + { + return {MakeErrorResult(reader.getErrorCode(), reader.getErrorMessage())}; + } + + CreateImageGeometryAction::DimensionType imageGeomDims = {static_cast(reader.getXDimension()), static_cast(reader.getYDimension()), static_cast(1)}; + std::vector tupleDims = {imageGeomDims[2], imageGeomDims[1], imageGeomDims[0]}; + + CreateImageGeometryAction::SpacingType spacing = {reader.getXStep(), reader.getYStep(), 1.0F}; + CreateImageGeometryAction::OriginType origin = {0.0F, 0.0F, 0.0F}; + + // These variables should be updated with the latest data generated for each variable during preflight. + // These will be returned through the preflightResult variable to the + // user interface. + std::stringstream ss; + std::array halfRes = {spacing[0] * 0.5F, spacing[1] * 0.5F, spacing[2] * 0.5F}; + + ss << "X Step: " << reader.getXStep() << " Y Step: " << reader.getYStep() << "\n" + << "Num Cols: " << reader.getXCells() << " " + << "Num Rows: " << reader.getYCells() << "\n" + << "Sample Physical Dimensions: " << (reader.getXStep() * reader.getXCells()) << " (W) x " << (reader.getYStep() * reader.getYCells()) << " (H) microns" + << "\n"; + std::string fileInfo = ss.str(); + std::vector preflightUpdatedValues = {{"Cpr File Information", fileInfo}}; + + // Define an Action that makes changes to the DataStructure + auto createImageGeometryAction = std::make_unique(pImageGeometryPath, CreateImageGeometryAction::DimensionType({imageGeomDims[0], imageGeomDims[1], imageGeomDims[2]}), + origin, spacing, pCellAttributeMatrixNameValue, IGeometry::LengthUnit::Micrometer); + + // Assign the createImageGeometryAction to the Result::actions vector via an appendAction + nx::core::Result resultOutputActions; + resultOutputActions.value().appendAction(std::move(createImageGeometryAction)); + + DataPath cellAttributeMatrixPath = pImageGeometryPath.createChildPath(pCellAttributeMatrixNameValue); + std::vector cDims = {1ULL}; + + auto fieldParsers = reader.createFieldParsers(pInputFileValue.string()); + for(const auto& parser : fieldParsers) + { + if(parser.FieldDefinition.FieldName.empty()) + { + std::cout << "Field Name was empty?\n"; + continue; + } + DataPath dataArrayPath = cellAttributeMatrixPath.createChildPath(parser.FieldDefinition.FieldName); + + if(parser.FieldDefinition.numericType == EbsdLib::NumericTypes::Type::Int32) + { + auto action = std::make_unique(nx::core::DataType::int32, tupleDims, cDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + } + else if(parser.FieldDefinition.numericType == EbsdLib::NumericTypes::Type::Float) + { + auto action = std::make_unique(nx::core::DataType::float32, tupleDims, cDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + } + else if(parser.FieldDefinition.numericType == EbsdLib::NumericTypes::Type::UInt8) + { + auto action = std::make_unique(nx::core::DataType::uint8, tupleDims, cDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + } + } + + // // Create the Cell Phases Array + if(pCreateCompatibleTypes) + { + cDims[0] = 1; + DataPath dataArrayPath = cellAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::Phases); + auto action = std::make_unique(nx::core::DataType::int32, tupleDims, cDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + + dataArrayPath = cellAttributeMatrixPath.createChildPath(EbsdLib::Ctf::Phase); + ; + auto removeTempArrayAction = std::make_unique(dataArrayPath); + resultOutputActions.value().appendDeferredAction(std::move(removeTempArrayAction)); + } + // + // // Create the Cell Euler Angles Array + if(pCreateCompatibleTypes) + { + cDims[0] = 3; + DataPath dataArrayPath = cellAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::EulerAngles); + auto action = std::make_unique(nx::core::DataType::float32, tupleDims, cDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + + dataArrayPath = cellAttributeMatrixPath.createChildPath(EbsdLib::Ctf::phi1); + ; + auto removeTempArrayAction = std::make_unique(dataArrayPath); + resultOutputActions.value().appendDeferredAction(std::move(removeTempArrayAction)); + + dataArrayPath = cellAttributeMatrixPath.createChildPath(EbsdLib::Ctf::Phi); + ; + removeTempArrayAction = std::make_unique(dataArrayPath); + resultOutputActions.value().appendDeferredAction(std::move(removeTempArrayAction)); + + dataArrayPath = cellAttributeMatrixPath.createChildPath(EbsdLib::Ctf::phi2); + ; + removeTempArrayAction = std::make_unique(dataArrayPath); + resultOutputActions.value().appendDeferredAction(std::move(removeTempArrayAction)); + } + + // Create the Ensemble AttributeMatrix + std::vector> angPhases = reader.getPhaseVector(); + tupleDims = {angPhases.size() + 1}; // Always create 1 extra slot for the phases. + DataPath ensembleAttributeMatrixPath = pImageGeometryPath.createChildPath(pCellEnsembleAttributeMatrixNameValue); + { + auto createAttributeMatrixAction = std::make_unique(ensembleAttributeMatrixPath, tupleDims); + resultOutputActions.value().appendAction(std::move(createAttributeMatrixAction)); + } + + // Create the Crystal Structures Array + { + cDims[0] = 1; + DataPath dataArrayPath = ensembleAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::CrystalStructures); + auto action = std::make_unique(nx::core::DataType::uint32, tupleDims, cDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + } + // Create the Lattice Constants Array + { + cDims[0] = 6; + DataPath dataArrayPath = ensembleAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::LatticeConstants); + auto action = std::make_unique(nx::core::DataType::float32, tupleDims, cDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + } + // Create the Material Names Array + { + DataPath dataArrayPath = ensembleAttributeMatrixPath.createChildPath(EbsdLib::CtfFile::MaterialName); + auto action = std::make_unique(tupleDims, dataArrayPath); + resultOutputActions.value().appendAction(std::move(action)); + } + + // Return both the resultOutputActions and the preflightUpdatedValues via std::move() + return {std::move(resultOutputActions), std::move(preflightUpdatedValues)}; +} + +//------------------------------------------------------------------------------ +Result<> ReadChannel5DataFilter::executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const +{ + ReadChannel5DataInputValues inputValues; + + inputValues.InputFile = filterArgs.value(k_InputFile_Key); + inputValues.EdaxHexagonalAlignment = filterArgs.value(k_EdaxHexagonalAlignment_Key); + inputValues.DataContainerName = filterArgs.value(k_CreatedImageGeometryPath_Key); + inputValues.CellAttributeMatrixName = filterArgs.value(k_CellAttributeMatrixName_Key); + inputValues.CellEnsembleAttributeMatrixName = filterArgs.value(k_CellEnsembleAttributeMatrixName_Key); + inputValues.CreateCompatibleArrays = filterArgs.value(k_CreateCompatibleArrays_Key); + return ReadChannel5Data(dataStructure, messageHandler, shouldCancel, &inputValues)(); +} + +namespace +{ +namespace SIMPL +{ +} // namespace SIMPL +} // namespace + +Result ReadChannel5DataFilter::FromSIMPLJson(const nlohmann::json& json) +{ + return {}; +} +} // namespace nx::core diff --git a/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ReadChannel5DataFilter.hpp b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ReadChannel5DataFilter.hpp new file mode 100644 index 0000000000..ac892e9bbe --- /dev/null +++ b/src/Plugins/OrientationAnalysis/src/OrientationAnalysis/Filters/ReadChannel5DataFilter.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include "OrientationAnalysis/OrientationAnalysis_export.hpp" + +#include "simplnx/Filter/FilterTraits.hpp" +#include "simplnx/Filter/IFilter.hpp" + +namespace nx::core +{ +/** + * @class ReadChannel5DataFilter + * @brief This filter will read a single .ctf file into a new Image Geometry, allowing the immediate use of Filters on the data instead of having to generate the + * intermediate .h5ebsd file. + */ +class ORIENTATIONANALYSIS_EXPORT ReadChannel5DataFilter : public IFilter +{ +public: + ReadChannel5DataFilter() = default; + ~ReadChannel5DataFilter() noexcept override = default; + + ReadChannel5DataFilter(const ReadChannel5DataFilter&) = delete; + ReadChannel5DataFilter(ReadChannel5DataFilter&&) noexcept = delete; + + ReadChannel5DataFilter& operator=(const ReadChannel5DataFilter&) = delete; + ReadChannel5DataFilter& operator=(ReadChannel5DataFilter&&) noexcept = delete; + + // Parameter Keys + static inline constexpr StringLiteral k_InputFile_Key = "input_file"; + static inline constexpr StringLiteral k_EdaxHexagonalAlignment_Key = "edax_hexagonal_alignment"; + static inline constexpr StringLiteral k_CreateCompatibleArrays_Key = "create_compatible_arrays"; + static inline constexpr StringLiteral k_CreatedImageGeometryPath_Key = "output_image_geometry_path"; + static inline constexpr StringLiteral k_CellAttributeMatrixName_Key = "cell_attribute_matrix_name"; + static inline constexpr StringLiteral k_CellEnsembleAttributeMatrixName_Key = "cell_ensemble_attribute_matrix_name"; + + /** + * @brief Reads SIMPL json and converts it simplnx Arguments. + * @param json + * @return Result + */ + static Result FromSIMPLJson(const nlohmann::json& json); + + /** + * @brief Returns the name of the filter. + * @return + */ + std::string name() const override; + + /** + * @brief Returns the C++ classname of this filter. + * @return + */ + std::string className() const override; + + /** + * @brief Returns the uuid of the filter. + * @return + */ + Uuid uuid() const override; + + /** + * @brief Returns the human readable name of the filter. + * @return + */ + std::string humanName() const override; + + /** + * @brief Returns the default tags for this filter. + * @return + */ + std::vector defaultTags() const override; + + /** + * @brief Returns the parameters of the filter (i.e. its inputs) + * @return + */ + Parameters parameters() const override; + + /** + * @brief Returns parameters version integer. + * Initial version should always be 1. + * Should be incremented everytime the parameters change. + * @return VersionType + */ + VersionType parametersVersion() const override; + + /** + * @brief Returns a copy of the filter. + * @return + */ + UniquePointer clone() const override; + +protected: + /** + * @brief Takes in a DataStructure and checks that the filter can be run on it with the given arguments. + * Returns any warnings/errors. Also returns the changes that would be applied to the DataStructure. + * Some parts of the actions may not be completely filled out if all the required information is not available at preflight time. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + PreflightResult preflightImpl(const DataStructure& dataStructure, const Arguments& filterArgs, const MessageHandler& messageHandler, const std::atomic_bool& shouldCancel) const override; + + /** + * @brief Applies the filter's algorithm to the DataStructure with the given arguments. Returns any warnings/errors. + * On failure, there is no guarantee that the DataStructure is in a correct state. + * @param dataStructure The input DataStructure instance + * @param filterArgs These are the input values for each parameter that is required for the filter + * @param messageHandler The MessageHandler object + * @return Returns a Result object with error or warning values if any of those occurred during execution of this function + */ + Result<> executeImpl(DataStructure& dataStructure, const Arguments& filterArgs, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler, + const std::atomic_bool& shouldCancel) const override; +}; +} // namespace nx::core + +SIMPLNX_DEF_FILTER_TRAITS(nx::core, ReadChannel5DataFilter, "6651923c-afb9-4032-8372-5578325c69a4"); diff --git a/src/Plugins/OrientationAnalysis/test/CMakeLists.txt b/src/Plugins/OrientationAnalysis/test/CMakeLists.txt index cd903dceef..d05eb3df99 100644 --- a/src/Plugins/OrientationAnalysis/test/CMakeLists.txt +++ b/src/Plugins/OrientationAnalysis/test/CMakeLists.txt @@ -41,6 +41,7 @@ set(${PLUGIN_NAME}UnitTest_SRCS MergeTwinsTest.cpp NeighborOrientationCorrelationTest.cpp ReadAngDataTest.cpp + ReadChannel5DataTest.cpp ReadCtfDataTest.cpp ReadEnsembleInfoTest.cpp ReadGrainMapper3DTest.cpp diff --git a/src/Plugins/OrientationAnalysis/test/ReadChannel5DataTest.cpp b/src/Plugins/OrientationAnalysis/test/ReadChannel5DataTest.cpp new file mode 100644 index 0000000000..34c46264b2 --- /dev/null +++ b/src/Plugins/OrientationAnalysis/test/ReadChannel5DataTest.cpp @@ -0,0 +1,19 @@ +#include "OrientationAnalysis/Filters/ReadChannel5DataFilter.hpp" +#include "OrientationAnalysis/OrientationAnalysis_test_dirs.hpp" + +#include "simplnx/Parameters/FileSystemPathParameter.hpp" +#include "simplnx/UnitTest/UnitTestCommon.hpp" + +#include + +#include + +namespace fs = std::filesystem; + +using namespace nx::core; +using namespace nx::core::Constants; +using namespace nx::core::UnitTest; + +TEST_CASE("OrientationAnalysis::ReadChannel5Data: Valid Execution", "[OrientationAnalysis][ReadChannel5Data]") +{ +}