How do I get the block names from an exodus file in my programmable filter

I hope someone can give me some help with this. I’m relatively new to Python programming and plugins/programmable filters in Paraview.

For background, I’m trying to transition from Paraview 5.4.1 to a newer version - I’m targeting 5.11. As part of that process, I’m updating some plugins/programmable filters that were developed one of my colleagues, @DennisConklin, from Python 2 to Python 3.

For the most part, the conversion has gone fairly smoothly, and the process of generating the .xml files is straightforward. However, one of the plugins returns an error I can’t figure out how to fix.

The plugin does some simple calculations on variables from the multiblock exodus dataset it’s applied to and adds the new variables to the output multiblock data set. If the variable being calculated isn’t relevant to one or more blocks (based on the element type in that block), then it prints a message indicating the name of the block and that it’s being skipped.

The calculations are working correctly, the issue is in the generation of that message.

Here’s a stripped down version of the script:
(the calculations have been removed and only the overall structure and get_block_name function remain)

import numpy,vtk
from vtk.numpy_interface import algorithms as algs
from operator import mul

def check_elem_variable_exists(block,variable_name):
   keys=block.CellData.keys()
   return (variable_name in keys)

def get_block_name(block):
   # Get block ID - This is the line that fails
   block_id=block.FieldData.GetArray('ElementBlockIds')
   output=self.GetOutput()
   ElementBlocks=output.GetBlock(0)
   block_meta=ElementBlocks.GetMetaData(block_id-1)
   block_name=block_meta.Get(vtk.vtkCompositeDataSet.NAME())
   return block_name

def hex_ElmCalc(block):
    for var in range(numVars):
        if not (check_elem_variable_exists(block,arrays[var])):
           print(get_block_name(block),"is missing variable",arrays[var])
           print("This may cause inaccuracy of the calculation for",arrays[var])
           continue
    return()

def quad_ElmCalc(block):
    for var in range(numVars):
        if not (check_elem_variable_exists(block,arrays[var])):
           print("Quad block is missing variable",arrays[var])
           print("This may cause inaccuracy of the calculation for",arrays[var])
           continue
    return()

###################################################################      
# main routine starts here
output.CopyStructure(inputs[0].VTKObject)
output.DeepCopy(inputs[0].VTKObject)  

numVars = arrays.__len__()
print()
for block in output:
   # VTK element types:
   #     12 = VTK_HEXAHEDRON
   #      9 = VTK_QUAD
   if block.GetCellType(0)==12:
      hex_ElmCalc(block)

   if block.GetCellType(0)==9:
      quad_ElmCalc(block)

print()

This works properly as a python2 script in Paraview 5.4.1, but it returns the error “TypeError: arguments do not match any overloaded methods” in the newer version (using the same exodus file input).

I’m running Paraview 5.11.1 in Linux (RHEL 7.9).

Please tell me how I need to change the line “block_id=block.FieldData.GetArray(‘ElementBlockIds’)” to get the block id.
(or if there’s a simpler/better way to get the block name)

Thanks

Exodus reader switched from multiblock dataset to partitioned dataset, does adding a “ConvertToMultiblock” filter first fixes the issue ?

@mwestphal,
Thanks for the response.

I tried applying the “ConvertToMultiBlock” filter before running the programmable filter, but that didn’t address the issue; I still got the same error message.

Is there a way I can easily view/explore the contents of the block’s data structure?
When I try printing it, it tells me it’s a “paraview.vtk.numpy_interface.dataset_adapter.UnstructuredGrid object”.

Thanks again for your help.

Could you share your dataset ?

Unfortunately, I can’t share the dataset that I’ve been using for testing for proprietary reasons.
However, I’ve attached an updated version of the plugin .xml and a simple exodus file that can be used to recreate the error.

beam.e (379.4 KB)
BlockID_Example.xml (4.0 KB)

In this version of the plugin file, I basically removed the “not” in the line:

        if not (check_elem_variable_exists(block,arrays[var])):

Now it should print out the block ID of all the blocks that have variables defined on them. (if the error doesn’t happen)
This should basically make the error happen for any multi-block exodus result file.

@mwestphal, does the data set I uploaded help to clarify the problem?

I reproduce, more investigation is needed.

@mwestphal,
Thanks for the update. Please let me know if there’s any more information I can provide to help find a solution.

I’m afraid I won’t have time to investigate, I hope somebody else take the time to. Do not hesitate to reach out to Kitware for help if needed.

It seems that the order of the blocks stored in the vtkPartitionedDataSetCollection is used as the MetaData number.

Therefore, It looks like the block name can be retrieved by simply using the index of the enumerate function in the for statement.


import numpy,vtk

def check_elem_variable_exists(block,variable_name):
    keys=block.CellData.keys()
    return (variable_name in keys)

def get_block_name(id):
    output=self.GetOutput()
    ElementBlocks=output.GetBlock(0)
    block_meta=output.GetMetaData(id)
    block_name=block_meta.Get(vtk.vtkCompositeDataSet.NAME())
    return block_name

def hex_ElmCalc(id, block):
    for var in range(numVars):
        if (check_elem_variable_exists(block,arrays[var])):
            print(arrays[var],"exists in hex block",get_block_name(id))
            continue
    return()

def quad_ElmCalc(id, block):
    for var in range(numVars):
        if (check_elem_variable_exists(block,arrays[var])):
            print(arrays[var],"exists in quad block",get_block_name(id))
            continue
    return()

###################################################################
# main routine starts here
output.CopyStructure(inputs[0].VTKObject)
output.DeepCopy(inputs[0].VTKObject)

numVars = arrays.__len__()
print()
for id, block in enumerate(output):
    # VTK element types:
    #     12 = VTK_HEXAHEDRON
    #      9 = VTK_QUAD
    if block.GetCellType(0)==12:
        hex_ElmCalc(id, block)

    if block.GetCellType(0)==9:
        quad_ElmCalc(id, block)

print()

@Kenichiro-Yoshimi,
Thanks for your input. Unfortunately, that doesn’t work for my problem. The issue is that I may not load every block in the exodus model, so I can’t simply use the order of the blocks as stored in the vtkPartitionedDataSetCollection.
For example, assume I have an exodus file with 5 blocks, numbered 1, 2, 3 ,4, and 5 and that they are named A, B, C, D, and, E, respectively.
If I only load blocks C and E, I want the code to identify that those are blocks 3 and 5, and return the associated names.
Unfortunately, if I use the enumerated id, it will identify them as blocks A and B.

I spent some time looking at the vtkIOSSReader file to linked in your comment, but I’m still relatively new to this, so I wasn’t able to figure anything out.

I know that Paraview reads and knows the actual block numbers and names, as they’re visible in the spreadsheet view when I look at the cell data.
The code for getting the block name from the block number is definitely working, I just need to figure out how to extract the block number in python.

Please let me know if you have other ideas or I can do anything to clarify my problem.

I’ve had some time to look into this problem a little bit more and I’m hoping that I’m closer to a solution, but I still need help.
I started by loading the can.e file from the paraview testing data files (can.e.4.0*), so I’m working from an input everyone has access to.

When searching these forums, someone had a similar issue, and the recommendation was to run:

GetActiveSource().GetDataInformation().DataInformation.GetNumberOfDataSets()

It gives me:

5

I then looked at other commands that are available for DataInformation, and found GetHierarchy();

print(GetActiveSource().GetDataInformation().DataInformation.GetHierarchy())

gives me

vtkDataAssembly (0x188ecdd0)
  Debug: Off
  Modified Time: 2188274
  Reference Count: 18
  Registered Events: (none)
  XML Representation : 

<?xml version="1.0"?>
<Root type="vtkDataAssembly" version="1.0" id="0" vtk_type="38" vtk_category="hierarchy" label="vtkPartitionedDataSetCollection">
    <dataset id="0" />
    <block_1 id="1" label="block_1" number_of_partitions="3">
        <dataset id="1" />
    </block_1>
    <block_2 id="2" label="block_2" number_of_partitions="2">
        <dataset id="5" />
    </block_2>
    <nodelist_1 id="3" label="nodelist_1" number_of_partitions="0">
        <dataset id="8" />
    </nodelist_1>
    <nodelist_100 id="4" label="nodelist_100" number_of_partitions="0">
        <dataset id="9" />
    </nodelist_100>
    <surface_4 id="5" label="surface_4" number_of_partitions="0">
        <dataset id="10" />
    </surface_4>
</Root>

This shows the information I’m trying to get.
For example, from:

<block_1 id="1" label="block_1" number_of_partitions="3">

I can see that the id=1 and the label is “block_1”.
I want a python command where I can give the id as an input and get the label back.
How do I do this?