// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause /** * @class vtkRedistributeDataSetFilter * @brief redistributes input dataset into requested number of partitions * * vtkRedistributeDataSetFilter is intended for redistributing data in a load * balanced fashion. * * The filter allows users to pick how cells along the boundary of the cuts * either automatically generated or explicitly specified are to be distributed * using `BoundaryMode`. One can choose to assign those cells uniquely to one of * those regions or duplicate then on all regions or split the cells (using * vtkTableBasedClipDataSet filter). When cells are * duplicated along the boundary, the filter will mark the duplicated cells as * `vtkDataSetAttributes::DUPLICATECELL` correctly on all but one of the * partitions using the ghost cell array (@sa `vtkDataSetAttributes::GhostArrayName`). * * @warning Generated duplicate ghost cells do not span entire layers of ghosts. * They are sparse, only appearing where cells overlap at the new boundaries between * partitions. If one wants to have full layers of ghost cells, one should use * `vtkGhostCellsGenerator`. * * Besides redistributing the data, the filter can optionally generate global * cell ids. This is provided since it relative easy to generate these * on when it is known that the data is spatially partitioned as is the case * after this filter has executed. * * @section vtkRedistributeDataSetFilter-SupportedDataTypes Supported Data Types * * vtkRedistributeDataSetFilter is primarily intended for unstructured datasets * i.e. vtkUnstructuredGrid, vtkPolyData and composite datasets comprising of * the same. It will work when applied to structured datasets as well, however, * it results in conversion of the dataset to an unstructured grid -- which is * often not suitable. * * For composite datasets, the filter supports `vtkPartitionedDataSet` and * `vtkPartitionedDataSetCollection`. When input is a * `vtkPartitionedDataSetCollection`, you can set `LoadBalanceAcrossAllBlocks` * to true to build the load balancing KdTree using all vtkPartitionedDataSets * in the collection. Default is load balance each `vtkPartitionedDataSet` * separately. * * For `vtkMultiBlockDataSet`, the filter internally uses * `vtkDataAssemblyUtilities` to convert the * vtkMultiBlockDataSet to a vtkPartitionedDataSetCollection and back. */ #ifndef vtkRedistributeDataSetFilter_h #define vtkRedistributeDataSetFilter_h #include "vtkDataObjectAlgorithm.h" #include "vtkFiltersParallelDIY2Module.h" // for export macros #include "vtkPartitioningStrategy.h" // for PartitionInformation #include "vtkSmartPointer.h" // for vtkSmartPointer #include // for std::shared_ptr #include // for std::vector // clang-format off #include "vtk_diy2.h" // for DIY2 APIs #include VTK_DIY2(diy/assigner.hpp) // clang-format on VTK_ABI_NAMESPACE_BEGIN class vtkMultiProcessController; class vtkBoundingBox; class vtkPartitionedDataSet; class vtkMultiBlockDataSet; class vtkMultiPieceDataSet; class vtkDataObjectTree; class VTKFILTERSPARALLELDIY2_EXPORT vtkRedistributeDataSetFilter : public vtkDataObjectAlgorithm { public: static vtkRedistributeDataSetFilter* New(); vtkTypeMacro(vtkRedistributeDataSetFilter, vtkDataObjectAlgorithm); void PrintSelf(ostream& os, vtkIndent indent) override; /** * Necessary to override this in order to take into account modifications to strategy */ vtkMTimeType GetMTime() override; ///@{ /** * Get/Set the controller to use. By default * vtkMultiProcessController::GlobalController will be used. */ void SetController(vtkMultiProcessController*); vtkGetObjectMacro(Controller, vtkMultiProcessController); ///@} enum BoundaryModes { ASSIGN_TO_ONE_REGION = 0, ASSIGN_TO_ALL_INTERSECTING_REGIONS = 1, SPLIT_BOUNDARY_CELLS = 2 }; ///@{ /** * Specify how cells on the boundaries are handled. * * \li `ASSIGN_TO_ONE_REGION` results in a cell on the boundary uniquely added * to one of the ranks containing the region intersecting the cell. * \li `ASSIGN_TO_ALL_INTERSECTING_REGIONS` results in a cell on the boundary * added to all ranks containing the region intersecting the cell. * \li `SPLIT_BOUNDARY_CELLS` results in cells along the boundary being * clipped along the region boundaries. * * Default is `ASSIGN_TO_ONE_REGION`. */ virtual void SetBoundaryMode(int mode); virtual int GetBoundaryModeMinValue() { return ASSIGN_TO_ONE_REGION; } virtual int GetBoundaryModeMaxValue() { return SPLIT_BOUNDARY_CELLS; } vtkGetMacro(BoundaryMode, int); void SetBoundaryModeToAssignToOneRegion() { this->SetBoundaryMode(ASSIGN_TO_ONE_REGION); } void SetBoundaryModeToAssignToAllIntersectingRegions() { this->SetBoundaryMode(ASSIGN_TO_ALL_INTERSECTING_REGIONS); } void SetBoundaryModeToSplitBoundaryCells() { this->SetBoundaryMode(SPLIT_BOUNDARY_CELLS); } ///@} ///@{ /** * Specify whether to compute the load balancing automatically or use * explicitly provided cuts. Set to false (default) to automatically compute * the cuts to use for redistributing the dataset. */ void SetUseExplicitCuts(bool); bool GetUseExplicitCuts() const; vtkBooleanMacro(UseExplicitCuts, bool); ///@} ///@{ /** * Specify the cuts to use when `UseExplicitCuts` is true. */ void SetExplicitCuts(const std::vector& boxes); const std::vector& GetExplicitCuts() const; void RemoveAllExplicitCuts(); void AddExplicitCut(const vtkBoundingBox& bbox); void AddExplicitCut(const double bbox[6]); int GetNumberOfExplicitCuts() const; const vtkBoundingBox& GetExplicitCut(int index) const; ///@} ///@{ /** * Specify the DIY assigner used for distributing cuts. If you use this API, you have to be * careful and use an assigner matching your setup. For example, if you use explicit cuts (by * calling SetExplicitCuts()), you want to assign all the cuts you provide. */ void SetAssigner(std::shared_ptr assigner); std::shared_ptr GetAssigner(); std::shared_ptr GetAssigner() const; ///@{ /** * When using explicit cuts, it possible that the bounding box defined by all * the cuts is smaller than the input's bounds. In that case, the filter can * automatically expand the edge boxes to include the input bounds to avoid * clipping of the input dataset on the external faces of the combined * bounding box. * * Default is true, that is explicit cuts will automatically be expanded. * */ void SetExpandExplicitCuts(bool); bool GetExpandExplicitCuts() const; vtkBooleanMacro(ExpandExplicitCuts, bool); ///@} ///@{ /** * Returns the cuts used by the most recent `RequestData` call. This is only * valid after a successful `Update` request. */ const std::vector& GetCuts() const; ///@} ///@{ /** * Specify the number of partitions to split the input dataset into. * Set to -1 to indicate that the partitions should match the number of * ranks (processes) determined using vtkMultiProcessController provided. * Setting to a non-zero positive number will result in the filter generating at * least as many partitions. * * This is simply a hint and not an exact number of partitions the data will be * split into. * * Default is -1. * * @sa PreservePartitionsInOutput */ void SetNumberOfPartitions(vtkIdType); vtkIdType GetNumberOfPartitions() const; ///@} ///@{ /** * When set to true (default is false), this filter will generate a vtkPartitionedDataSet as the * output. The advantage of doing that is each partition that the input dataset was split * into can be individually accessed. Otherwise, when the number of partitions generated is * greater than the number of ranks, a rank with more than one partition will use * `vtkAppendFilter` to merge the multiple partitions into a single unstructured grid. * * The output dataset type is always vtkUnstructuredGrid when * PreservePartitionsInOutput is false and always a vtkPartitionedDataSet when * PreservePartitionsInOutput is true. * * Default is false i.e. the filter will generate a single vtkUnstructuredGrid. */ vtkSetMacro(PreservePartitionsInOutput, bool); vtkGetMacro(PreservePartitionsInOutput, bool); vtkBooleanMacro(PreservePartitionsInOutput, bool); ///@} ///@{ /** * Generate global cell ids if none present in the input. If global cell ids are present * in the input then this flag is ignored. Default is true. */ vtkSetMacro(GenerateGlobalCellIds, bool); vtkGetMacro(GenerateGlobalCellIds, bool); vtkBooleanMacro(GenerateGlobalCellIds, bool); ///@} ///@{ /** * Enable/disable debugging mode. In this mode internal arrays are preserved * and ghost cells are not explicitly marked as such so that they can be inspected * without risk of being dropped or removed by the pipeline. * * Default is false. */ vtkSetMacro(EnableDebugging, bool); vtkGetMacro(EnableDebugging, bool); vtkBooleanMacro(EnableDebugging, bool); ///@} ///@{ /** * When UseExplicitCuts is false, and input is a * `vtkPartitionedDataSetCollection`, set this to true to generate cuts for * load balancing using all the datasets in the * vtkPartitionedDataSetCollection. * * Default is true. */ void SetLoadBalanceAcrossAllBlocks(bool); bool GetLoadBalanceAcrossAllBlocks(); vtkBooleanMacro(LoadBalanceAcrossAllBlocks, bool); ///@} ///@{ /** * Setter/Getter for Strategy */ vtkPartitioningStrategy* GetStrategy(); void SetStrategy(vtkPartitioningStrategy*); ///@} protected: vtkRedistributeDataSetFilter(); ~vtkRedistributeDataSetFilter() override; int FillInputPortInformation(int port, vtkInformation* info) override; int RequestDataObject(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; /* * A method with this signature used to exist. With the refactoring of this filter to accept * different partitioning strategies, this method no longer had any meaning in the generic * sense. * * If you inherited this filter and overrid this method, please implement a new partitioning * strategy instead. */ // virtual vtkSmartPointer SplitDataSet( // vtkDataSet* dataset, const std::vector& cuts); private: vtkRedistributeDataSetFilter(const vtkRedistributeDataSetFilter&) = delete; void operator=(const vtkRedistributeDataSetFilter&) = delete; /** * This method is called to split a vtkDataSet into multiple datasets by the * vector of partition information passed in. The returned vtkPartitionedDataSet * must have exactly as many partitions as the number of information elements * in the `info` vector. * * Note, this method may duplicate cells that lie on the boundaries and add cell * arrays that indicate cell ownership and flag boundary cells. */ virtual vtkSmartPointer SplitDataSet( vtkDataSet* dataset, const vtkPartitioningStrategy::PartitionInformation& info); bool Redistribute(vtkPartitionedDataSetCollection* inputCollection, vtkPartitionedDataSetCollection* outputCollection, const std::vector& info, bool preserve_input_hierarchy); bool RedistributePTD(vtkPartitionedDataSet*, vtkPartitionedDataSet*, const std::vector&, unsigned int*, vtkIdType*); bool RedistributeDataSet(vtkDataSet* inputDS, vtkPartitionedDataSet* outputPDS, const vtkPartitioningStrategy::PartitionInformation& info); vtkSmartPointer ClipDataSet(vtkDataSet* dataset, const vtkBoundingBox& bbox); void MarkGhostCells(vtkPartitionedDataSet* pieces); vtkSmartPointer AssignGlobalCellIds( vtkPartitionedDataSet* input, vtkIdType* mb_offset = nullptr); vtkSmartPointer AssignGlobalCellIds( vtkDataSet* input, vtkIdType* mb_offset = nullptr); void MarkValidDimensions(const vtkBoundingBox& gbounds); std::shared_ptr Assigner; vtkMultiProcessController* Controller; int BoundaryMode; bool PreservePartitionsInOutput; bool GenerateGlobalCellIds; bool EnableDebugging; bool ValidDim[3]; vtkSmartPointer Strategy; }; VTK_ABI_NAMESPACE_END #endif