Skip to content

Commit 90d09a4

Browse files
joeykleingersimikejacksonJDuffeyBQ
authored
ENH: Dream3dImportParameter supports additional import options. (#1230)
* Add Include/Exclude import policies to Dream3dImportParameter. * Add 'All' enumeration option, and switch default to 'IncludeList'. * Switch default to 'All' and require use of ImportData constructor * Modify filter to allow singular data paths without including parent paths. This change allows the filter to handle "Geometry/CellData/Fit" by itself instead of having to also input "Geometry" and "Geometry/CellData". This change will mainly benefit anyone running this filter without the GUI. --------- Signed-off-by: Joey Kleingers <joey.kleingers@bluequartz.net> Co-authored-by: Michael Jackson <mike.jackson@bluequartz.net> Co-authored-by: Jared Duffey <jared.duffey@bluequartz.net>
1 parent 3413c2e commit 90d09a4

27 files changed

+447
-207
lines changed

src/Plugins/OrientationAnalysis/test/MergeTwinsTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ TEST_CASE("Reconstruction::MergeTwinsFilter: Valid Execution", "[Reconstruction]
6767
auto filter = filterList->createFilter(k_ReadDREAM3DFilterHandle);
6868
REQUIRE(nullptr != filter);
6969

70-
Dream3dImportParameter::ImportData parameter;
71-
parameter.FilePath = fs::path(fmt::format("{}/neighbor_orientation_correlation.dream3d", unit_test::k_TestFilesDir));
70+
auto filePath = fs::path(fmt::format("{}/neighbor_orientation_correlation.dream3d", unit_test::k_TestFilesDir));
71+
Dream3dImportParameter::ImportData parameter(filePath);
7272

7373
Arguments args;
7474
args.insertOrAssign(k_ImportFileData, std::make_any<Dream3dImportParameter::ImportData>(parameter));

src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ReadDREAM3DFilter.cpp

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "simplnx/Filter/Actions/ImportH5ObjectPathsAction.hpp"
55
#include "simplnx/Parameters/Dream3dImportParameter.hpp"
66
#include "simplnx/Parameters/StringParameter.hpp"
7+
#include "simplnx/Utilities/Parsing/DREAM3D/Dream3dIO.hpp"
78
#include "simplnx/Utilities/Parsing/HDF5/Readers/FileReader.hpp"
89

910
#include "simplnx/Utilities/SIMPLConversion.hpp"
@@ -14,6 +15,56 @@ namespace
1415
{
1516
constexpr nx::core::int32 k_NoImportPathError = -1;
1617
constexpr nx::core::int32 k_FailedOpenFileReaderError = -25;
18+
constexpr nx::core::int32 k_UnsupportedPathImportPolicyError = -51;
19+
20+
std::vector<nx::core::DataPath> ExpandSelectedPathsToAncestors(const std::vector<nx::core::DataPath>& selectedPaths)
21+
{
22+
std::vector<nx::core::DataPath> finalDataPaths;
23+
for(const auto& dataPath : selectedPaths)
24+
{
25+
auto pathVector = dataPath.getPathVector();
26+
for(size_t i = 1; i <= dataPath.getLength(); ++i)
27+
{
28+
auto dataPathPart = nx::core::DataPath(std::vector<std::string>(pathVector.begin(), pathVector.begin() + i));
29+
if(std::find(finalDataPaths.begin(), finalDataPaths.end(), dataPathPart) == finalDataPaths.end())
30+
{
31+
finalDataPaths.push_back(dataPathPart);
32+
}
33+
}
34+
}
35+
36+
return finalDataPaths;
37+
}
38+
39+
std::vector<nx::core::DataPath> ExpandSelectedPathsToDescendants(const std::vector<nx::core::DataPath>& selectedPaths, const std::vector<nx::core::DataPath>& allPaths)
40+
{
41+
std::vector<nx::core::DataPath> expandedDataPaths = selectedPaths;
42+
for(const auto& dataPath : selectedPaths)
43+
{
44+
for(const auto& candidateDataPath : allPaths)
45+
{
46+
if(candidateDataPath.getLength() <= dataPath.getLength())
47+
{
48+
continue;
49+
}
50+
51+
bool isEqual = true;
52+
for(size_t i = 0; i < dataPath.getPathVector().size(); ++i)
53+
{
54+
if(dataPath.getPathVector()[i] != candidateDataPath.getPathVector()[i])
55+
{
56+
isEqual = false;
57+
}
58+
}
59+
if(isEqual)
60+
{
61+
expandedDataPaths.push_back(candidateDataPath);
62+
}
63+
}
64+
}
65+
66+
return expandedDataPaths;
67+
}
1768
} // namespace
1869

1970
namespace nx::core
@@ -53,7 +104,8 @@ Parameters ReadDREAM3DFilter::parameters() const
53104
{
54105
Parameters params;
55106
params.insertSeparator(Parameters::Separator{"Input Parameter(s)"});
56-
params.insert(std::make_unique<Dream3dImportParameter>(k_ImportFileData, "Import File Path", "The HDF5 file path the DataStructure should be imported from.", Dream3dImportParameter::ImportData()));
107+
params.insert(
108+
std::make_unique<Dream3dImportParameter>(k_ImportFileData, "Import File Path", "The HDF5 file path the DataStructure should be imported from.", Dream3dImportParameter::ImportData({})));
57109
return params;
58110
}
59111

@@ -75,18 +127,79 @@ IFilter::PreflightResult ReadDREAM3DFilter::preflightImpl(const DataStructure& d
75127
auto importData = args.value<Dream3dImportParameter::ImportData>(k_ImportFileData);
76128
if(importData.FilePath.empty())
77129
{
78-
return {nonstd::make_unexpected(std::vector<Error>{Error{k_NoImportPathError, "Import file path not provided."}})};
130+
return {MakeErrorResult<OutputActions>(k_NoImportPathError, "Import file path not provided.")};
79131
}
80132
nx::core::HDF5::FileReader fileReader(importData.FilePath);
81133
if(!fileReader.isValid())
82134
{
83-
return {nonstd::make_unexpected(std::vector<Error>{Error{k_FailedOpenFileReaderError, "Failed to open the HDF5 file at the specified path."}})};
135+
return {MakeErrorResult<OutputActions>(k_FailedOpenFileReaderError, "Failed to open the HDF5 file at the specified path.")};
136+
}
137+
138+
Result<OutputActions> result;
139+
OutputActions& actions = result.value();
140+
141+
Result<DataStructure> dataStructureResult = DREAM3D::ImportDataStructureFromFile(fileReader, true);
142+
if(dataStructureResult.invalid())
143+
{
144+
return {ConvertResultTo<OutputActions>(ConvertResult(std::move(dataStructureResult)), {})};
145+
}
146+
auto importedDataStructure = dataStructureResult.value();
147+
148+
if(importData.ImportPolicy == Dream3dImportParameter::PathImportPolicy::IncludeList)
149+
{
150+
auto allDataPaths = importedDataStructure.getAllDataPaths();
151+
std::vector<DataPath> selectedDataPaths = ExpandSelectedPathsToDescendants(importData.DataPaths, allDataPaths);
152+
selectedDataPaths = ExpandSelectedPathsToAncestors(selectedDataPaths);
153+
154+
if(selectedDataPaths.empty())
155+
{
156+
result.warnings().push_back(
157+
Warning{-10, "The import policy is set to 'Include List' and the file paths list is empty. This will result in no data being imported. Is this what you meant to do?"});
158+
}
159+
160+
actions.appendAction(std::make_unique<ImportH5ObjectPathsAction>(importData.FilePath, selectedDataPaths));
161+
}
162+
else if(importData.ImportPolicy == Dream3dImportParameter::PathImportPolicy::ExcludeList || importData.ImportPolicy == Dream3dImportParameter::PathImportPolicy::All)
163+
{
164+
auto allDataPaths = importedDataStructure.getAllDataPaths();
165+
if(importData.ImportPolicy == Dream3dImportParameter::PathImportPolicy::ExcludeList)
166+
{
167+
if(importData.DataPaths.empty())
168+
{
169+
result.warnings().push_back(Warning{-11,
170+
"The import policy is set to 'Exclude List' and the file paths list is empty. This will result in all data being imported. You can accomplish the same "
171+
"result by setting the import policy to 'All'."});
172+
actions.appendAction(std::make_unique<ImportH5ObjectPathsAction>(importData.FilePath, allDataPaths));
173+
}
174+
else
175+
{
176+
auto expandedDataPaths = ExpandSelectedPathsToDescendants(importData.DataPaths, allDataPaths);
177+
178+
// Erase the expandedDataPaths from allPaths to create finalDataPaths
179+
std::vector<nx::core::DataPath> finalDataPaths = allDataPaths;
180+
for(const auto& dataPath : expandedDataPaths)
181+
{
182+
auto iter = std::find(finalDataPaths.begin(), finalDataPaths.end(), dataPath);
183+
if(iter != finalDataPaths.end())
184+
{
185+
finalDataPaths.erase(iter);
186+
}
187+
}
188+
189+
actions.appendAction(std::make_unique<ImportH5ObjectPathsAction>(importData.FilePath, finalDataPaths));
190+
}
191+
}
192+
else
193+
{
194+
actions.appendAction(std::make_unique<ImportH5ObjectPathsAction>(importData.FilePath, allDataPaths));
195+
}
196+
}
197+
else
198+
{
199+
return {MakeErrorResult<OutputActions>(k_UnsupportedPathImportPolicyError, "The chosen PathImportPolicy is not supported by this filter. Please contact the developers.")};
84200
}
85201

86-
OutputActions actions;
87-
auto action = std::make_unique<ImportH5ObjectPathsAction>(importData.FilePath, importData.DataPaths);
88-
actions.appendAction(std::move(action));
89-
return {std::move(actions)};
202+
return {result};
90203
}
91204

92205
Result<> ReadDREAM3DFilter::executeImpl(DataStructure& dataStructure, const Arguments& args, const PipelineFilter* pipelineNode, const MessageHandler& messageHandler,

src/Plugins/SimplnxCore/test/DREAM3DFileTest.cpp

Lines changed: 105 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ Pipeline CreateImportPipeline()
185185
Pipeline pipeline("Import DREAM3D Pipeline");
186186
{
187187
Arguments args;
188-
Dream3dImportParameter::ImportData importData;
189-
importData.FilePath = GetExportDataPath();
190-
importData.DataPaths = std::vector<DataPath>{DataPath({DataNames::k_Group1Name}), DataPath({DataNames::k_ArrayName})};
188+
auto filePath = GetExportDataPath();
189+
std::vector<DataPath> dataPaths = std::vector<DataPath>{DataPath({DataNames::k_Group1Name}), DataPath({DataNames::k_ArrayName})};
190+
Dream3dImportParameter::ImportData importData(filePath, Dream3dImportParameter::PathImportPolicy::IncludeList, dataPaths);
191191
args.insert("import_data_object", importData);
192192
pipeline.push_back(k_ImportD3DHandle, args);
193193
}
@@ -241,17 +241,13 @@ Pipeline CreateMultiImportPipeline()
241241
Pipeline pipeline("Import DREAM3D Pipeline");
242242
{
243243
Arguments args;
244-
Dream3dImportParameter::ImportData importData;
245-
importData.FilePath = GetMultiExportDataPath1();
246-
importData.DataPaths = std::vector<DataPath>{DataPath({DataNames::k_Group1Name})};
244+
Dream3dImportParameter::ImportData importData(GetMultiExportDataPath1(), Dream3dImportParameter::PathImportPolicy::IncludeList, std::vector<DataPath>{DataPath({DataNames::k_Group1Name})});
247245
args.insert("import_data_object", importData);
248246
pipeline.push_back(k_ImportD3DHandle, args);
249247
}
250248
{
251249
Arguments args;
252-
Dream3dImportParameter::ImportData importData;
253-
importData.FilePath = GetMultiExportDataPath2();
254-
importData.DataPaths = std::vector<DataPath>{DataPath({DataNames::k_Group2Name})};
250+
Dream3dImportParameter::ImportData importData(GetMultiExportDataPath2(), Dream3dImportParameter::PathImportPolicy::IncludeList, std::vector<DataPath>{DataPath({DataNames::k_Group2Name})});
255251
args.insert("import_data_object", importData);
256252
pipeline.push_back(k_ImportD3DHandle, args);
257253
}
@@ -282,7 +278,7 @@ TEST_CASE("DREAM3DFileTest:DREAM3D File IO Test")
282278
{
283279
auto fileData = CreateFileData();
284280
Result<HDF5::FileWriter> result = HDF5::FileWriter::CreateFile(GetIODataPath());
285-
REQUIRE(result.valid());
281+
SIMPLNX_RESULT_REQUIRE_VALID(result);
286282

287283
auto writeResult = DREAM3D::WriteFile(result.value(), fileData);
288284
SIMPLNX_RESULT_REQUIRE_VALID(writeResult);
@@ -408,10 +404,107 @@ TEST_CASE("DREAM3DFileTest: Existing Data Objects Test")
408404

409405
ReadDREAM3DFilter filter;
410406
Arguments args;
411-
Dream3dImportParameter::ImportData importData;
412-
importData.FilePath = fs::path(fmt::format("{}/Small_IN100.dream3d", unit_test::k_TestFilesDir));
407+
Dream3dImportParameter::ImportData importData(fs::path(fmt::format("{}/Small_IN100.dream3d", unit_test::k_TestFilesDir)));
413408
args.insert(ReadDREAM3DFilter::k_ImportFileData, importData);
414409
auto executeResult = filter.execute(ds, args);
415410
SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result);
416411
}
417412
}
413+
414+
TEST_CASE("DREAM3DFileTest: Path Import Policy Tests")
415+
{
416+
const nx::core::UnitTest::TestFileSentinel testDataSentinel(nx::core::unit_test::k_CMakeExecutable, nx::core::unit_test::k_TestFilesDir, "Small_IN100_dream3d_v2.tar.gz", "Small_IN100.dream3d");
417+
auto filePath = fs::path(fmt::format("{}/Small_IN100.dream3d", unit_test::k_TestFilesDir));
418+
DataStructure dataStructure;
419+
ReadDREAM3DFilter filter;
420+
Arguments args;
421+
422+
SECTION("All")
423+
{
424+
Dream3dImportParameter::ImportData importData(filePath);
425+
args.insert(ReadDREAM3DFilter::k_ImportFileData, importData);
426+
auto executeResult = filter.execute(dataStructure, args);
427+
SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result);
428+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer"})));
429+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData"})));
430+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData"})));
431+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "Confidence Index"})));
432+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "EulerAngles"})));
433+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "Fit"})));
434+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "Image Quality"})));
435+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "Phases"})));
436+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "SEM Signal"})));
437+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData", "CrystalStructures"})));
438+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData", "LatticeConstants"})));
439+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData", "MaterialName"})));
440+
REQUIRE(dataStructure.containsData(DataPath({"MirroredXDataContainer"})));
441+
REQUIRE(dataStructure.containsData(DataPath({"MirroredXDataContainer", "Cell Data"})));
442+
REQUIRE(dataStructure.containsData(DataPath({"MirroredXDataContainer", "Cell Data", "Confidence Index"})));
443+
REQUIRE(dataStructure.containsData(DataPath({"MirroredXDataContainer", "Cell Data", "EulerAngles"})));
444+
REQUIRE(dataStructure.containsData(DataPath({"MirroredXDataContainer", "Cell Data", "Fit"})));
445+
REQUIRE(dataStructure.containsData(DataPath({"MirroredXDataContainer", "Cell Data", "Image Quality"})));
446+
REQUIRE(dataStructure.containsData(DataPath({"MirroredXDataContainer", "Cell Data", "Phases"})));
447+
REQUIRE(dataStructure.containsData(DataPath({"MirroredXDataContainer", "Cell Data", "SEM Signal"})));
448+
REQUIRE(dataStructure.containsData(DataPath({"MirroredYDataContainer"})));
449+
REQUIRE(dataStructure.containsData(DataPath({"MirroredYDataContainer", "Cell Data"})));
450+
REQUIRE(dataStructure.containsData(DataPath({"MirroredYDataContainer", "Cell Data", "Confidence Index"})));
451+
REQUIRE(dataStructure.containsData(DataPath({"MirroredYDataContainer", "Cell Data", "EulerAngles"})));
452+
REQUIRE(dataStructure.containsData(DataPath({"MirroredYDataContainer", "Cell Data", "Fit"})));
453+
REQUIRE(dataStructure.containsData(DataPath({"MirroredYDataContainer", "Cell Data", "Image Quality"})));
454+
REQUIRE(dataStructure.containsData(DataPath({"MirroredYDataContainer", "Cell Data", "Phases"})));
455+
REQUIRE(dataStructure.containsData(DataPath({"MirroredYDataContainer", "Cell Data", "SEM Signal"})));
456+
REQUIRE(dataStructure.containsData(DataPath({"MirroredZDataContainer"})));
457+
REQUIRE(dataStructure.containsData(DataPath({"MirroredZDataContainer", "Cell Data"})));
458+
REQUIRE(dataStructure.containsData(DataPath({"MirroredZDataContainer", "Cell Data", "Confidence Index"})));
459+
REQUIRE(dataStructure.containsData(DataPath({"MirroredZDataContainer", "Cell Data", "EulerAngles"})));
460+
REQUIRE(dataStructure.containsData(DataPath({"MirroredZDataContainer", "Cell Data", "Fit"})));
461+
REQUIRE(dataStructure.containsData(DataPath({"MirroredZDataContainer", "Cell Data", "Image Quality"})));
462+
REQUIRE(dataStructure.containsData(DataPath({"MirroredZDataContainer", "Cell Data", "Phases"})));
463+
REQUIRE(dataStructure.containsData(DataPath({"MirroredZDataContainer", "Cell Data", "SEM Signal"})));
464+
}
465+
SECTION("Include List - Leaf Node")
466+
{
467+
Dream3dImportParameter::ImportData importData(filePath, Dream3dImportParameter::PathImportPolicy::IncludeList, {DataPath({"DataContainer", "CellData", "Confidence Index"})});
468+
args.insert(ReadDREAM3DFilter::k_ImportFileData, importData);
469+
auto executeResult = filter.execute(dataStructure, args);
470+
SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result);
471+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer"})));
472+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData"})));
473+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "Confidence Index"})));
474+
REQUIRE(!dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData"})));
475+
}
476+
SECTION("Include List - Parent Node")
477+
{
478+
Dream3dImportParameter::ImportData importData(filePath, Dream3dImportParameter::PathImportPolicy::IncludeList, {DataPath({"DataContainer", "CellData"})});
479+
args.insert(ReadDREAM3DFilter::k_ImportFileData, importData);
480+
auto executeResult = filter.execute(dataStructure, args);
481+
SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result);
482+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer"})));
483+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData"})));
484+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "Confidence Index"})));
485+
REQUIRE(!dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData"})));
486+
}
487+
SECTION("Exclude List - Parent Node")
488+
{
489+
Dream3dImportParameter::ImportData importData(filePath, Dream3dImportParameter::PathImportPolicy::ExcludeList, {DataPath({"DataContainer", "CellData"})});
490+
args.insert(ReadDREAM3DFilter::k_ImportFileData, importData);
491+
auto executeResult = filter.execute(dataStructure, args);
492+
SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result);
493+
REQUIRE(!dataStructure.containsData(DataPath({"DataContainer", "CellData"})));
494+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData"})));
495+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData", "CrystalStructures"})));
496+
}
497+
498+
SECTION("Exclude List - Leaf Node")
499+
{
500+
Dream3dImportParameter::ImportData importData(filePath, Dream3dImportParameter::PathImportPolicy::ExcludeList, {DataPath({"DataContainer", "CellData", "Confidence Index"})});
501+
args.insert(ReadDREAM3DFilter::k_ImportFileData, importData);
502+
auto executeResult = filter.execute(dataStructure, args);
503+
SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result);
504+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData"})));
505+
REQUIRE(!dataStructure.containsData(DataPath({"DataContainer", "CellData", "Confidence Index"})));
506+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellData", "Fit"})));
507+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData"})));
508+
REQUIRE(dataStructure.containsData(DataPath({"DataContainer", "CellEnsembleData", "CrystalStructures"})));
509+
}
510+
}

0 commit comments

Comments
 (0)