# Working with multi-block/multi-piece data sets

**URL:** https://discourse.paraview.org/t/working-with-multi-block-multi-piece-data-sets/1050
**Category:** ParaView Support
**Created:** [December 16, 2018, 11:59pm UTC](https://discourse.paraview.org/t/working-with-multi-block-multi-piece-data-sets/1050 "2018-12-16T23:59:41Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![olesenm](https://discourse.paraview.org/user_avatar/discourse.paraview.org/olesenm/32/17416_2.png) [@olesenm](https://discourse.paraview.org/u/olesenm)
#### Post date: [December 16, 2018, 11:59pm UTC](https://discourse.paraview.org/t/working-with-multi-block-multi-piece-data-sets/1050/1 "2018-12-16T23:59:42Z")

</div>

I’m fiddling with a plugin and trying to determine a quick test for the existence/non-existence of a particular cell-data array, or point-data array and its overall range. I was hoping for a min/max vtkAlgorithm or equivalent but seem to be overseeing it. The problem is that my data are most likely to be multi-block with sub-block, the final leaves are either unstructured-grid or multi-piece containing unstructured-grid.

At the moment, I’ve coded up a GetRange() traversing method that works but is just **so** ugly that it cannot be the right way to do things. Attached is an example of my ad hoc min/max for a particular CellData or PointData field. Does anyone know of a simpler means of doing this?

```auto
// Works, but really cannot be correct (too ugly)

typedef std::pair<double,double> doublePair;

const doublePair invalidMinMax(GREAT, -GREAT);
template<class DataType>
doublePair getMinMax(DataType* input, const std::string& name)
{
    return invalidMinMax;
}

const doublePair doMinMax(const doublePair& a, const doublePair& b)
{
    return doublePair
    (
        std::min(a.first, b.first),
        std::max(a.second, b.second)
    );
}

doublePair getMinMax(vtkFieldData* input, const std::string& name)
{
    // Info<< "minmax(" << name << ") of vtkFieldData" << nl;
    doublePair result(invalidMinMax);

    if (input && name.size())
    {
        // Get min/max
        vtkDataArray* field = vtkDataArray::SafeDownCast
        (
            input->GetAbstractArray(name.c_str())
        );

        // May wish to handle vectors too?
        if (field && field->GetNumberOfComponents() == 1)
        {
            double range[2]{ GREAT, -GREAT };
            field->GetRange(range);
            result.first = range[0];
            result.second = range[1];
        }
    }

    return result;
}

doublePair getMinMax(vtkCellData* input, const std::string& name)
{
    // Info<< "minmax(" << name << ") of vtkCellArray" << nl;
    return getMinMax(vtkFieldData::SafeDownCast(input), name);
}

doublePair getMinMax(vtkPointData* input, const std::string& name)
{
    // Info<< "minmax(" << name << ") of vtkCellArray" << nl;
    return getMinMax(vtkFieldData::SafeDownCast(input), name);
}

template<class FieldType>
doublePair getMinMax(vtkDataSet* input, const std::string& name)
{
    // Info<< "minmax(" << name << ") FieldType" << nl;
    return invalidMinMax;
}

template<>
doublePair getMinMax<vtkCellData>(vtkDataSet* input, const std::string& name)
{
    // Info<< "minmax(" << name << ") vtkDataSet -> CellData" << nl;
    if (input && name.size())
    {
        return getMinMax(input->GetCellData(), name);
    }

    return invalidMinMax;
}

template<>
doublePair getMinMax<vtkPointData>(vtkDataSet* input, const std::string& name)
{
    // Info<< "minmax(" << name << ") vtkDataSet -> PointData" << nl;
    if (input && name.size())
    {
        return getMinMax(input->GetPointData(), name);
    }

    return invalidMinMax;
}

template<class FieldType>
doublePair getMinMax(vtkMultiPieceDataSet* input, const std::string& name)
{
    doublePair result(invalidMinMax);

    const unsigned n =
        ((input && name.size()) ? input->GetNumberOfPieces() : 0);

    // Info<< "minmax(" << name << ") vtkMultiPieceDataSet ("
    // << n << ") pieces" << nl;

    for (unsigned i = 0; i < n; ++i)
    {
        doublePair local = getMinMax<FieldType>
        (
            vtkDataSet::SafeDownCast(input->GetPiece(i)),
            name
        );

        result = doMinMax(result, local);
    }

    return result;
}

emplate<class FieldType>
doublePair getMinMax(vtkMultiBlockDataSet* input, const std::string& name)
{
    doublePair result(invalidMinMax);

    const unsigned n =
        ((input && name.size()) ? input->GetNumberOfBlocks() : 0);

    // Info<< "minmax(" << name << ") vtkMultiBlockDataSet ("
    // << n << ") blocks" << nl;

    for (unsigned i = 0; i < n; ++i)
    {
        vtkDataObject* obj = input->GetBlock(i);

        vtkMultiBlockDataSet* mb = vtkMultiBlockDataSet::SafeDownCast(obj);
        if (mb)
        {
            doublePair local = getMinMax<FieldType>(mb, name);
            result = doMinMax(result, local);
            continue;
        }

        vtkMultiPieceDataSet* mp = vtkMultiPieceDataSet::SafeDownCast(obj);
        if (mp)
        {
            doublePair local = getMinMax<FieldType>(mp, name);
            result = doMinMax(result, local);
            continue;
        }

        vtkDataSet* dobj = vtkDataSet::SafeDownCast(obj);
        if (dobj)
        {
            doublePair local = getMinMax<FieldType>(dobj, name);
            result = doMinMax(result, local);
            continue;
        }
    }

    return result;
}

```

This whole thing would finally be called like this:

```auto
    doublePair minmax = getMinMax<vtkCellData>(mesh, myFieldName);
    // parallel reduce

```

We can also check if the lower/upper values are in the correct order. If they are not, then the field was not found at all.

There must surely be something simpler and more obvious, but I didn’t see it.

/mark

---

<div class="post-metadata">

### Author: ![mwestphal](https://discourse.paraview.org/user_avatar/discourse.paraview.org/mwestphal/32/17_2.png) [@mwestphal](https://discourse.paraview.org/u/mwestphal)
#### Post date: [December 17, 2018, 9:33am UTC](https://discourse.paraview.org/t/working-with-multi-block-multi-piece-data-sets/1050/2 "2018-12-17T09:33:21Z")

</div>

You should a `vtkCompositeDataSetIterator` with `OnlyLeavesOn` and use `GetRange` on each leaf.

---

<div class="post-metadata">

### Author: ![olesenm](https://discourse.paraview.org/user_avatar/discourse.paraview.org/olesenm/32/17416_2.png) [@olesenm](https://discourse.paraview.org/u/olesenm)
#### Post date: [December 17, 2018, 12:57pm UTC](https://discourse.paraview.org/t/working-with-multi-block-multi-piece-data-sets/1050/3 "2018-12-17T12:57:41Z")

</div>

Oh yes, that looks much better.  
Thank you!

/mark

For others, this is what the revised version looks like:

```auto
doublePair getMinMax
(
    vtkCompositeDataSet* data,
    const std::string& name,
    const vtkDataObject::FieldAssociations attr =
        vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS
)
{
    doublePair result(invalidMinMax);

    auto iter = vtkSmartPointer<vtkDataObjectTreeIterator>::New();

    iter->SetDataSet(data);
    iter->VisitOnlyLeavesOn();
    iter->SkipEmptyNodesOn();

    for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem())
    {
        vtkDataSet* dataset = vtkDataSet::SafeDownCast
        (
            iter->GetCurrentDataObject()
        );

        if (dataset)
        {
            doublePair local = getMinMax
            (
                dataset->GetAttributesAsFieldData(attr),
                name
            );

            result = doMinMax(result, local);
         }
    }

    return result;
}

```
