diff --git a/Documentation/release/dev/add-state_metadata_vtk_fields-vtkConduitSource.md b/Documentation/release/dev/add-state_metadata_vtk_fields-vtkConduitSource.md new file mode 100644 index 0000000000000000000000000000000000000000..ba2977485ee569bf492a1602e7b60d223c6eb609 --- /dev/null +++ b/Documentation/release/dev/add-state_metadata_vtk_fields-vtkConduitSource.md @@ -0,0 +1,61 @@ +## vtkConduitSource: Add state/metadata/vtk_fields node + +When defining fields in a Conduit tree, it is often useful to include metadata about the fields that can be +interpreted by VTK, and utilized appropriately. To that end, we have added a new node to the Conduit tree +that can be used to store metadata about the fields in the tree. This node is called `state/metadata/vtk_fields`. + +Each child of the `state/metadata/vtk_fields` node has a name that corresponds to a field in the tree. The number +of children of the `state/metadata/vtk_fields` node should not match the number of `fields` in the tree since not every +field needs to have metadata. + +The current metadata that can be stored for each field is: + +1. `attribute_type`: It is a string and represents the attribute type of a field that, so that VTk can use an attribute + array, such as `GlobalIds`. The values uses are the entries of `vtkDataSetAttributes::AttributeTypes` + `Ghosts`. + The complete list of values is: + - `Scalars` + - `Vectors` + - `Normals` + - `TCoords` + - `Tensors` + - `GlobalIds` + - `PedigreeIds` + - `EdgeFlag` + - `Tangents` + - `RationalWeights` + - `HigherOrderDegrees` + - `ProcessIds` + - `Ghosts` +2. `values_to_replace` and `replacement_values`: These two are vectors of values that be used to replace specific values + in the field. This is useful when the field has some values that are not valid for VTK. For example, + the `vtkGhostType` array uses specific values that other ghost cell generator algorithms may not use. In this case, + the `values_to_replace` would be the values that need to be replaced, and the `replacement_values` would be the + values that should replace them. The two vectors should have the same length. + +Example: + +```cpp +conduit_cpp::Node mesh; +CreateUniformMesh(3, 3, 3, mesh); + +std::vector<int> cellGhosts(8, 0); +cellGhosts[2] = 1; + +conduit_cpp::Node resCellFields = mesh["fields/other_ghosts"]; +resCellFields["association"] = "element"; +resCellFields["topology"] = "mesh"; +resCellFields["volume_dependent"] = "false"; +resCellFields["values"] = cellGhosts; + +std::vector<int> cellGhostValuesToReplace(1, 1); +std::vector<int> cellGhostReplacementValues(1, vtkDataSetAttributes::HIDDENCELL); + +std::vector<int> cellGhostsMetaData(1, 1); +conduit_cpp::Node ghostMetaData = mesh["state/metadata/vtk_fields/other_ghosts"]; +ghostMetaData["attribute_type"] = "Ghosts"; +ghostMetaData["values_to_replace"] = cellGhostValuesToReplace; +ghostMetaData["replacement_values"] = cellGhostReplacementValues; +``` + +Lastly, the usage of `ascent_ghosts` has been deprecated and should be replaced with the new +`state/metadata/vtk_fields` node, as shown above. diff --git a/IO/CatalystConduit/Testing/Cxx/TestConduitSource.cxx b/IO/CatalystConduit/Testing/Cxx/TestConduitSource.cxx index 3468b5fd1dce8b979f8118283dc0913840f79063..a21ed91a2b7d9e50a44d93e4b51d18b1376adde3 100644 --- a/IO/CatalystConduit/Testing/Cxx/TestConduitSource.cxx +++ b/IO/CatalystConduit/Testing/Cxx/TestConduitSource.cxx @@ -412,6 +412,10 @@ void CreateTrisMesh(unsigned int nptsX, unsigned int nptsY, conduit_cpp::Node& r values[i] = i + 0.0; } resFields["values"].set(values); + + conduit_cpp::Node resFieldsMetaData = res["state/metadata/vtk_fields/field"]; + resFieldsMetaData["attribute_type"] = + vtkDataSetAttributes::GetAttributeTypeAsString(vtkDataSetAttributes::SCALARS); } //---------------------------------------------------------------------------- @@ -434,7 +438,9 @@ bool ValidateMeshTypeUnstructured() ug->GetNumberOfPoints()); VERIFY(ug->GetNumberOfCells() == 8, "incorrect number of cells, expected 8, got %lld", ug->GetNumberOfCells()); - VERIFY(ug->GetCellData()->GetArray("field") != nullptr, "missing 'field' cell-data array"); + VERIFY(ug->GetCellData()->GetAttribute(vtkDataSetAttributes::SCALARS) != nullptr, + "missing 'field' cell-data array with attribute '%s'", + vtkDataSetAttributes::GetAttributeTypeAsString(vtkDataSetAttributes::SCALARS)); return true; } @@ -626,14 +632,22 @@ bool ValidateAscentGhostCellData() resCellFields["volume_dependent"] = "false"; resCellFields["values"] = cellGhosts; + std::vector<int> cellGhostValuesToReplace(1, 1); + std::vector<int> cellGhostReplacementValues(1, vtkDataSetAttributes::HIDDENCELL); + + std::vector<int> cellGhostsMetaData(1, 1); + conduit_cpp::Node ghostMetaData = mesh["state/metadata/vtk_fields/ascent_ghosts"]; + ghostMetaData["attribute_type"] = "Ghosts"; + ghostMetaData["values_to_replace"] = cellGhostValuesToReplace; + ghostMetaData["replacement_values"] = cellGhostReplacementValues; + auto data = Convert(mesh); auto pds = vtkPartitionedDataSet::SafeDownCast(data); VERIFY(pds->GetNumberOfPartitions() == 1, "incorrect number of partitions, expected 1, got %d", pds->GetNumberOfPartitions()); auto img = vtkImageData::SafeDownCast(pds->GetPartition(0)); VERIFY(img != nullptr, "missing partition 0"); - vtkUnsignedCharArray* array = vtkUnsignedCharArray::SafeDownCast( - img->GetCellData()->GetArray(vtkDataSetAttributes::GhostArrayName())); + auto array = vtkUnsignedCharArray::SafeDownCast(img->GetCellData()->GetGhostArray()); VERIFY(array != nullptr && array->GetValue(2) == static_cast<unsigned char>(vtkDataSetAttributes::HIDDENCELL), "Verification failed for converting Ascent ghost cell data"); @@ -655,14 +669,22 @@ bool ValidateAscentGhostPointData() resPointFields["topology"] = "mesh"; resPointFields["values"] = pointGhosts; + std::vector<int> pointGhostValuesToReplace(1, 1); + std::vector<int> pointGhostReplacementValues(1, vtkDataSetAttributes::HIDDENPOINT); + + std::vector<int> cellGhostsMetaData(1, 1); + conduit_cpp::Node ghostMetaData = mesh["state/metadata/vtk_fields/ascent_ghosts"]; + ghostMetaData["attribute_type"] = "Ghosts"; + ghostMetaData["values_to_replace"] = pointGhostValuesToReplace; + ghostMetaData["replacement_values"] = pointGhostReplacementValues; + auto data = Convert(mesh); auto pds = vtkPartitionedDataSet::SafeDownCast(data); VERIFY(pds->GetNumberOfPartitions() == 1, "incorrect number of partitions, expected 1, got %d", pds->GetNumberOfPartitions()); auto img = vtkImageData::SafeDownCast(pds->GetPartition(0)); VERIFY(img != nullptr, "missing partition 0"); - vtkUnsignedCharArray* array = vtkUnsignedCharArray::SafeDownCast( - img->GetPointData()->GetArray(vtkDataSetAttributes::GhostArrayName())); + auto array = vtkUnsignedCharArray::SafeDownCast(img->GetPointData()->GetGhostArray()); VERIFY(array != nullptr && array->GetValue(2) == static_cast<unsigned char>(vtkDataSetAttributes::HIDDENPOINT), "Verification failed for converting Ascent ghost point data"); diff --git a/IO/CatalystConduit/Testing/Cxx/TestDataObjectToConduit.cxx b/IO/CatalystConduit/Testing/Cxx/TestDataObjectToConduit.cxx index 53917a9cde9ebf8b93abb2b9d3599993e1949c6b..e346b93e6b2a0086a327049911e7b75ff416c908 100644 --- a/IO/CatalystConduit/Testing/Cxx/TestDataObjectToConduit.cxx +++ b/IO/CatalystConduit/Testing/Cxx/TestDataObjectToConduit.cxx @@ -56,6 +56,12 @@ bool TestImageData() } } } + vtkNew<vtkUnsignedCharArray> ghostCells; + ghostCells->SetName(vtkDataSetAttributes::GhostArrayName()); + ghostCells->SetNumberOfValues(image->GetNumberOfCells()); + ghostCells->SetValue(0, 0); + ghostCells->SetValue(1, vtkDataSetAttributes::HIDDENCELL); + image->GetCellData()->AddArray(ghostCells); bool is_success = vtkDataObjectToConduit::FillConduitNode(vtkDataObject::SafeDownCast(image), node); @@ -89,6 +95,18 @@ bool TestImageData() field_node["volume_dependent"] = "false"; field_node["values"] = std::vector<int>{ 2, 2, 2, 2, 2, 2 }; + auto field_metadata_node = expected_node["state/metadata/vtk_fields/ImageScalars"]; + field_metadata_node["attribute_type"] = "Scalars"; + + auto ghost_field_node = expected_node["fields/vtkGhostType"]; + ghost_field_node["association"] = "element"; + ghost_field_node["topology"] = "mesh"; + ghost_field_node["volume_dependent"] = "false"; + ghost_field_node["values"] = std::vector<unsigned char>{ 0, vtkDataSetAttributes::HIDDENCELL }; + + auto ghost_field_metadata_node = expected_node["state/metadata/vtk_fields/vtkGhostType"]; + ghost_field_metadata_node["attribute_type"] = "Ghosts"; + conduit_cpp::Node diff_info; bool are_nodes_different = node.diff(expected_node, diff_info, 1e-6); if (are_nodes_different) @@ -252,12 +270,18 @@ bool TestStructuredGrid() point_field_node["volume_dependent"] = "false"; point_field_node["values"] = std::vector<double>{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; + auto point_field_metadata_node = expected_node["state/metadata/vtk_fields/point_field"]; + point_field_metadata_node["attribute_type"] = "Scalars"; + auto cell_field_node = expected_node["fields/cell_field"]; cell_field_node["association"] = "element"; cell_field_node["topology"] = "mesh"; cell_field_node["volume_dependent"] = "false"; cell_field_node["values"] = std::vector<double>{ 0, 2 }; + auto cell_field_metadata_node = expected_node["state/metadata/vtk_fields/cell_field"]; + cell_field_metadata_node["attribute_type"] = "Scalars"; + conduit_cpp::Node diff_info; bool are_nodes_different = node.diff(expected_node, diff_info, 1e-6); if (are_nodes_different) diff --git a/IO/CatalystConduit/vtkConduitArrayUtilities.h b/IO/CatalystConduit/vtkConduitArrayUtilities.h index 4a05b04e3723025e4d10a25ed176a94d3c8acaa8..0e7b77b0aab0350a2b8abefe9cf148612bbca6f7 100644 --- a/IO/CatalystConduit/vtkConduitArrayUtilities.h +++ b/IO/CatalystConduit/vtkConduitArrayUtilities.h @@ -17,6 +17,7 @@ #ifndef vtkConduitArrayUtilities_h #define vtkConduitArrayUtilities_h +#include "vtkDeprecation.h" // for VTK_DEPRECATED_IN_9_5_0 #include "vtkIOCatalystConduitModule.h" // for exports #include "vtkObject.h" #include "vtkSmartPointer.h" // for vtkSmartPointer @@ -51,7 +52,13 @@ public: /** * Returns a vtkDataArray from a conduit node in the conduit mcarray protocol * that is a conduit ghost array named ascent_ghosts. + * + * @deprecated: Instead of using this function, use the state/metadata/vtk_fields + * to define the attribute_type, values_to_replace and replacement_values instead for + * the ghost array. */ + VTK_DEPRECATED_IN_9_5_0("This function is deprecated, because in the future " + "state/metadata/vtk_fields will only be used.") static vtkSmartPointer<vtkDataArray> MCGhostArrayToVTKGhostArray( const conduit_node* mcarray, bool is_cell_data); ///@} diff --git a/IO/CatalystConduit/vtkConduitSource.cxx b/IO/CatalystConduit/vtkConduitSource.cxx index b5ed87ac31d2ab308310b20875a139aa9e50e132..0359db93a72db2602f8a2876d5309ff1a79f4a4c 100644 --- a/IO/CatalystConduit/vtkConduitSource.cxx +++ b/IO/CatalystConduit/vtkConduitSource.cxx @@ -116,7 +116,7 @@ bool vtkConduitSource::GenerateAMR(vtkDataObject* output) bool vtkConduitSource::GeneratePartitionedDataSet(vtkDataObject* output) { vtkNew<vtkPartitionedDataSet> pd_output; - if (!vtkConduitToDataObject::FillPartionedDataSet(pd_output, this->Internals->Node)) + if (!vtkConduitToDataObject::FillPartitionedDataSet(pd_output, this->Internals->Node)) { vtkLogF(ERROR, "Failed reading mesh from '%s'", this->Internals->Node.name().c_str()); output->Initialize(); @@ -141,7 +141,7 @@ bool vtkConduitSource::GeneratePartitionedDataSetCollection(vtkDataObject* outpu const auto& child = pdc_node.child(cc); auto pd = pdc_output->GetPartitionedDataSet(static_cast<unsigned int>(cc)); assert(pd != nullptr); - if (!vtkConduitToDataObject::FillPartionedDataSet(pd, child)) + if (!vtkConduitToDataObject::FillPartitionedDataSet(pd, child)) { vtkLogF(ERROR, "Failed reading mesh '%s'", child.name().c_str()); output->Initialize(); diff --git a/IO/CatalystConduit/vtkConduitToDataObject.cxx b/IO/CatalystConduit/vtkConduitToDataObject.cxx index 783960686547087556f4c834f85f6cb1b940574e..30c55483cb65e041514730838865ea8ee34eb785 100644 --- a/IO/CatalystConduit/vtkConduitToDataObject.cxx +++ b/IO/CatalystConduit/vtkConduitToDataObject.cxx @@ -1,5 +1,9 @@ // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause + +// Added due to deprecated vtkConduitArrayUtilities::MCGhostArrayToVTKGhostArray +#define VTK_DEPRECATION_LEVEL 0 + #include "vtkConduitToDataObject.h" #include "vtkAMRBox.h" @@ -18,11 +22,14 @@ #include "vtkParallelAMRUtilities.h" #include "vtkPartitionedDataSet.h" #include "vtkRectilinearGrid.h" +#include "vtkSMPTools.h" #include "vtkStringArray.h" #include "vtkStructuredGrid.h" #include "vtkUniformGrid.h" #include "vtkUnstructuredGrid.h" +#include "vtksys/SystemTools.hxx" + #include <catalyst_conduit.hpp> #include <catalyst_conduit_blueprint.hpp> @@ -34,7 +41,64 @@ namespace vtkConduitToDataObject VTK_ABI_NAMESPACE_BEGIN //---------------------------------------------------------------------------- -bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node& node) +struct FieldMetadata +{ + vtkSmartPointer<vtkDataArray> ValuesToReplace = nullptr; + vtkSmartPointer<vtkDataArray> ReplacementValues = nullptr; + std::string AttributeType; + + static vtkDataSetAttributes::AttributeTypes GetDataSetAttributeType( + const std::string& otherAttributeTypeName) + { + for (int i = 0; i < vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES; ++i) + { + const std::string attributeTypeName = vtkDataSetAttributes::GetAttributeTypeAsString(i); + if (vtksys::SystemTools::UpperCase(otherAttributeTypeName) == + vtksys::SystemTools::UpperCase(attributeTypeName)) + { + return static_cast<vtkDataSetAttributes::AttributeTypes>(i); + } + } + return vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES; + } + + static bool IsGhostsAttributeType(const std::string& otherAttributeTypeName) + { + return vtksys::SystemTools::UpperCase(otherAttributeTypeName) == "GHOSTS"; + } +}; + +//---------------------------------------------------------------------------- +struct ReplaceValuesWorker +{ + template <typename Array1T, typename Array2T, typename Array3T> + void operator()(Array1T* valuesToReplace, Array2T* replacementValues, Array3T* array) const + { + const vtkIdType numValuesToReplace = valuesToReplace->GetNumberOfTuples(); + auto valuesToReplaceRange = vtk::DataArrayValueRange(valuesToReplace); + auto replacementValuesRange = vtk::DataArrayValueRange(replacementValues); + auto arrayRange = vtk::DataArrayValueRange(array); + + vtkSMPTools::For(0, array->GetNumberOfTuples(), + [&](vtkIdType begin, vtkIdType end) + { + for (vtkIdType inputIdx = begin; inputIdx < end; ++inputIdx) + { + for (vtkIdType repValueId = 0; repValueId < numValuesToReplace; ++repValueId) + { + if (valuesToReplaceRange[repValueId] == arrayRange[inputIdx]) + { + arrayRange[inputIdx] = replacementValuesRange[repValueId]; + break; + } + } + } + }); + } +}; + +//---------------------------------------------------------------------------- +bool FillPartitionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node& node) { #if !VTK_MODULE_ENABLE_VTK_AcceleratorsVTKmDataModel // conduit verify_shape_node dereferences the pointer to @@ -51,8 +115,7 @@ bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node // process "topologies". auto topologies = node["topologies"]; - conduit_index_t nchildren = topologies.number_of_children(); - for (conduit_index_t i = 0; i < nchildren; ++i) + for (conduit_index_t i = 0, nchildren = topologies.number_of_children(); i < nchildren; ++i) { auto child = topologies.child(i); try @@ -88,9 +151,73 @@ bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node return true; } + // read "state/metadata/vtk_fields" + std::map<std::string, FieldMetadata> fieldMetadata; + if (node.has_path("state/metadata/vtk_fields")) + { + auto fieldsMetadata = node["state/metadata/vtk_fields"]; + for (conduit_index_t i = 0, nchildren = fieldsMetadata.number_of_children(); i < nchildren; ++i) + { + auto fieldMetadataNode = fieldsMetadata.child(i); + const auto& name = fieldMetadataNode.name(); + try + { + // read values_to_replace and replacement_values if they exist + if (fieldMetadataNode.has_path("values_to_replace") && + fieldMetadataNode.has_path("replacement_values")) + { + auto valuesToReplace = fieldMetadataNode["values_to_replace"]; + fieldMetadata[name].ValuesToReplace = + vtkConduitArrayUtilities::MCArrayToVTKArray(conduit_cpp::c_node(&valuesToReplace)); + auto replacementValues = fieldMetadataNode["replacement_values"]; + fieldMetadata[name].ReplacementValues = + vtkConduitArrayUtilities::MCArrayToVTKArray(conduit_cpp::c_node(&replacementValues)); + if (fieldMetadata[name].ValuesToReplace->GetNumberOfTuples() != + fieldMetadata[name].ReplacementValues->GetNumberOfTuples()) + { + vtkLogF(ERROR, + "values_to_replace and replacement_values should have equal size for field '%s'.", + name.c_str()); + return false; + } + if (fieldMetadata[name].ValuesToReplace->GetNumberOfComponents() != 1 || + fieldMetadata[name].ReplacementValues->GetNumberOfComponents() != 1) + { + vtkLogF(ERROR, + "values_to_replace and replacement_values should have 1 component for field '%s'.", + name.c_str()); + return false; + } + } + // read attribute type if it exists + if (fieldMetadataNode.has_path("attribute_type")) + { + const std::string& attributeType = fieldMetadataNode["attribute_type"].as_string(); + // check if the attribute type is valid + if (FieldMetadata::GetDataSetAttributeType(attributeType) != + vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES || + FieldMetadata::IsGhostsAttributeType(attributeType)) + { + fieldMetadata[name].AttributeType = attributeType; + } + else + { + vtkLogF( + ERROR, "invalid attribute type '%s' for '%s'.", attributeType.c_str(), name.c_str()); + return false; + } + } + } + catch (std::exception& e) + { + vtkLogF(ERROR, "failed to process '../state/metadata/vtk_fields/%s'.", name.c_str()); + vtkLogF(ERROR, "ERROR: \n%s\n", e.what()); + return false; + } + } + } auto fields = node["fields"]; - nchildren = fields.number_of_children(); - for (conduit_index_t i = 0; i < nchildren; ++i) + for (conduit_index_t i = 0, nchildren = fields.number_of_children(); i < nchildren; ++i) { auto fieldNode = fields.child(i); const auto& fieldname = fieldNode.name(); @@ -111,25 +238,68 @@ bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node } if (dataset_size > 0) { - vtkSmartPointer<vtkDataArray> array; + // This code path should be removed once MCGhostArrayToVTKGhostArray is removed. if (fieldname == "ascent_ghosts") { // convert ascent ghost information into VTK ghost information // the VTK array is named vtkDataSetAttributes::GhostArrayName() // and has different values. - array = vtkConduitArrayUtilities::MCGhostArrayToVTKGhostArray( + auto array = vtkConduitArrayUtilities::MCGhostArrayToVTKGhostArray( conduit_cpp::c_node(&values), dsa->IsA("vtkCellData")); + dsa->AddArray(array); + continue; } - else + vtkSmartPointer<vtkDataArray> array = + vtkConduitArrayUtilities::MCArrayToVTKArray(conduit_cpp::c_node(&values), fieldname); + if (array->GetNumberOfTuples() != dataset->GetNumberOfElements(vtk_association)) { - array = - vtkConduitArrayUtilities::MCArrayToVTKArray(conduit_cpp::c_node(&values), fieldname); - if (array->GetNumberOfTuples() != dataset->GetNumberOfElements(vtk_association)) + throw std::runtime_error("mismatched tuple count!"); + } + if (fieldMetadata.find(fieldname) != fieldMetadata.end()) + { + const auto& metadata = fieldMetadata[fieldname]; + // replace values if needed + if (metadata.ValuesToReplace && metadata.ReplacementValues) + { + ReplaceValuesWorker replaceValuesWorker; + if (!vtkArrayDispatch::Dispatch3SameValueType::Execute(metadata.ValuesToReplace.Get(), + metadata.ReplacementValues.Get(), array.Get(), replaceValuesWorker)) + { + replaceValuesWorker( + metadata.ValuesToReplace.Get(), metadata.ReplacementValues.Get(), array.Get()); + } + } + // extract the attribute type, and change the array name if needed + auto dsaAttributeType = vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES; + if (!metadata.AttributeType.empty()) + { + dsaAttributeType = FieldMetadata::GetDataSetAttributeType(metadata.AttributeType); + if (FieldMetadata::IsGhostsAttributeType(metadata.AttributeType)) + { + // convert its name to the VTK ghost array name + array->SetName(vtkDataSetAttributes::GhostArrayName()); + // ensure the array is unsigned char + if (!array->IsA("vtkUnsignedCharArray")) + { + auto ghostArray = vtkSmartPointer<vtkUnsignedCharArray>::New(); + ghostArray->DeepCopy(array); + array = ghostArray; + } + } + } + if (dsaAttributeType != vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES) + { + dsa->SetAttribute(array, dsaAttributeType); + } + else { - throw std::runtime_error("mismatched tuple count!"); + dsa->AddArray(array); } } - dsa->AddArray(array); + else + { + dsa->AddArray(array); + } } } catch (std::exception& e) @@ -143,6 +313,12 @@ bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node return true; } +//---------------------------------------------------------------------------- +bool FillPartionedDataSet(vtkPartitionedDataSet* output, const conduit_cpp::Node& meshNode) +{ + return FillPartitionedDataSet(output, meshNode); +} + //---------------------------------------------------------------------------- bool FillAMRMesh(vtkOverlappingAMR* amr, const conduit_cpp::Node& node) { diff --git a/IO/CatalystConduit/vtkConduitToDataObject.h b/IO/CatalystConduit/vtkConduitToDataObject.h index 77e5a3d2dd512a13f2846c0c9859a0ade17daa08..0b4e3cc381cf34760c2c5bf9596579b633510313 100644 --- a/IO/CatalystConduit/vtkConduitToDataObject.h +++ b/IO/CatalystConduit/vtkConduitToDataObject.h @@ -10,8 +10,9 @@ #include "vtkIOCatalystConduitModule.h" // For windows import/export of shared libraries -#include "vtkObject.h" // for ABI namespace -#include "vtkSmartPointer.h" +#include "vtkDeprecation.h" // for VTK_DEPRECATED_IN_9_5_0 +#include "vtkObject.h" // for ABI namespace +#include "vtkSmartPointer.h" // for vtkSmartPointer namespace conduit_cpp { @@ -36,6 +37,7 @@ namespace vtkConduitToDataObject { VTK_ABI_NAMESPACE_BEGIN +///@{ /** * Fill the vtkPartitionedDataSet input. * Create concrete vtkDataSet subclass to set it as partition and add arrays in its @@ -44,8 +46,12 @@ VTK_ABI_NAMESPACE_BEGIN * Return true if data was correctly generated, false if an error occurred. * Do not throw errors. */ +VTKIOCATALYSTCONDUIT_EXPORT bool FillPartitionedDataSet( + vtkPartitionedDataSet* output, const conduit_cpp::Node& meshNode); +VTK_DEPRECATED_IN_9_5_0("Use FillPartitionedDataSet instead.") VTKIOCATALYSTCONDUIT_EXPORT bool FillPartionedDataSet( vtkPartitionedDataSet* output, const conduit_cpp::Node& meshNode); +///@} /** * Fill the vtkOverlappingAMR input. diff --git a/IO/CatalystConduit/vtkDataObjectToConduit.cxx b/IO/CatalystConduit/vtkDataObjectToConduit.cxx index e188cb5cd4b23fd0daea2bbdd371b0ac499d93d1..80d68bae076b1dcd4093ca020c723bb716795009 100644 --- a/IO/CatalystConduit/vtkDataObjectToConduit.cxx +++ b/IO/CatalystConduit/vtkDataObjectToConduit.cxx @@ -529,7 +529,7 @@ bool FillFields( vtkFieldData* field_data, const std::string& association, conduit_cpp::Node& conduit_node) { bool is_success = true; - + auto dataset_attributes = vtkDataSetAttributes::SafeDownCast(field_data); int array_count = field_data->GetNumberOfArrays(); for (int array_index = 0; is_success && array_index < array_count; ++array_index) { @@ -579,6 +579,26 @@ bool FillFields( auto values_node = field_node["values"]; is_success = ConvertDataArrayToMCArray(data_array, values_node); + if (dataset_attributes) + { + bool is_dataset_attribute = false; + for (int i = 0; i < vtkDataSetAttributes::AttributeTypes::NUM_ATTRIBUTES; ++i) + { + if (dataset_attributes->GetAttribute(i) == data_array) + { + auto field_metadata_node = conduit_node["state/metadata/vtk_fields"][name]; + field_metadata_node["attribute_type"] = + vtkDataSetAttributes::GetAttributeTypeAsString(i); + is_dataset_attribute = true; + break; + } + } + if (!is_dataset_attribute && strcmp(name, vtkDataSetAttributes::GhostArrayName()) == 0) + { + auto field_metadata_node = conduit_node["state/metadata/vtk_fields"][name]; + field_metadata_node["attribute_type"] = "Ghosts"; + } + } } else {