Programmable filter - result not shown after reloading pvsm

Hello,
I successfully implemented a programmable filter in PV 5.10.1 that copies a variable value from a certain region to each cell of other regions, which allows me to use it to normalize other scalars with it. It works fine in my paraview state, but once I save the state and reopen it, the resulting variable is missing, which leads to the contours not showing the expected, normalized contour plots. I can regain the correct view, if I go to the filter, uncheck “copy arrays” → apply → check “copy arrays” → apply. Then the variable is re-calculated and everything is fine. However, this is problematic, as I send the image creation for my simulations to a remote computer.
It looks like the calculation is not properly done when loading the state and we must somehow force an update? How can I do that?
Thank you.

I’m unable to reproduce with ParaView 5.11.1

Hello Mathieu thank you for testing, probably with a similar code you have. Would you mind sharing it, maybe I am missing some key part in the algorithm that forces the update?
E.g. I am not using

from vtk.numpy_interface import dataset_adapter as dsa

because the filter worked really well without it too. It was mentioned here 5. Programmable Filter — ParaView Documentation 5.11.0 documentation so it might be needed?

I have tested my implementation in PV5.11 and get the same behavior. The only thing that changes, is a new error message inside the numpy.mean function. I am using it to extract the average on the source region, but the error seems to stem from the input into the filter not being transfered correctly, it complains that the input to the mean function is NoneType. The error vanishes and it computes correctly when I add a newline and hit apply again.

This is my algorithm, although I cannot provide the data, maybe it helps to spot anything missing?

import numpy as np
  
### INPUT ###
variable = 'var1'
weight_var = 'var2'   # or ''
result_name = 'Normalized Value'
source_patch = 'REGION1'
###

input0 = inputs[0].VTKObject  #returns vtkMultiBlockDataSet
# here, Block(0) -> unstructuredGrid (internalMesh)
# Block(1) -> boundary, another vtkMultiBlockDataSet
 
all_patch_blocks = []
for idx in range(input0.GetBlock(1).GetNumberOfBlocks()):
    all_patch_blocks.append(input0.GetBlock(1).GetBlock(idx))
 
for block_idx, block in enumerate(all_patch_blocks):
    meta_data = input0.GetBlock(1).GetMetaData(block_idx)
    name = meta_data.Get(vtk.vtkCompositeDataSet.NAME())
    if name == source_patch:
        source_block = all_patch_blocks[block_idx]
 
inlet_values = source_block.GetPointData()
inlet_conc_array = inlet_values.GetArray(variable)
mean_conc = np.mean(inlet_conc_array)
 
# collect all blocks, there is input0.Block0 (internal mesh) and an arbitrary number of blocks in input0.Block1
all_blocks = [input0.GetBlock(0)] + all_patch_blocks
 
for block in all_blocks:
    # create a new array in this block
    conc_inlet_array = vtk.vtkFloatArray()
    conc_inlet_array.SetName(result_name)
 
    n_points_this_block = block.GetNumberOfPoints()
    conc_array_this_block = block.GetPointData().GetArray(variable)
    if weight_var:
        weight_array_this_block = block.GetPointData().GetArray(weight_var)
  
    for cell_idx in range(n_points_this_block):
        value = conc_array_this_block.GetValue(cell_idx)
        if not weight_var:
            conc_inlet_array.InsertNextValue(value/mean_conc)
        else:
            weight_value = weight_array_this_block.GetValue(cell_idx)
            conc_inlet_array.InsertNextValue(value*weight_value/mean_conc)
  
    # add the new array
    block.GetPointData().AddArray(conc_inlet_array)

Please provide a simpler example or dummy data to be able to reproduce

I attached a working set of files to reproduce it. This is a classic openfoam benchmark, dambreak. There is a pvsm file called Test.pvsm. It has the openfoam-reader node and my programmable filter. It takes nut from patch atmosphere and creates a new variable nut/nut(atmosphere) = nut_norm in all regions. Open the PVSM file and adjust the path to the open.foam file according to your save location.

When Paraview opens it, you will see that instead of showing nut_norm, it shows it with a solid color according to your PV settings. If you add a new line in the filter and hit apply, the nut_norm variable is displayed correctly.

damBreak.7z (141.3 KB)

You are modifying the input. You need to recover the output and shallow copy the input into it.

Thank you, Mathieu. I adjusted the script to write the resulting vtkArray into the output instead of input. That fixes the issue when reloading the pvsm locally, which I thought was the critical point. Now, as described initially, I am sending the picture creation as a job to a remote computer where the images are created using pyFoamPVSnapshot.py. Here I see the same behavior as before, default solid color.

Here is the new code, instead of inputs, I add everything to the pointData of output.

input0 = inputs[0].VTKObject  #returns vtkMultiBlockDataSet
# here, Block(0) -> unstructuredGrid (internalMesh)
# Block(1) -> boundary, another MultiBlockDataSet
 
all_patch_blocks = []
for idx in range(input0.GetBlock(1).GetNumberOfBlocks()):
    all_patch_blocks.append(input0.GetBlock(1).GetBlock(idx))
 
for block_idx, block in enumerate(all_patch_blocks):
    meta_data = input0.GetBlock(1).GetMetaData(block_idx)
    name = meta_data.Get(vtk.vtkCompositeDataSet.NAME())
    if name == source_patch:
        source_block = all_patch_blocks[block_idx]
 
inlet_values = source_block.GetPointData()
inlet_conc_array = inlet_values.GetArray(variable)
mean_conc = np.mean(inlet_conc_array)
 
# collect all output blocks, there is output.Block0 (internal mesh) and an arbitrary number of blocks in output.Block1
all_out_patch_blocks = []
for idx in range(output.GetBlock(1).GetNumberOfBlocks()):
    all_out_patch_blocks.append(output.GetBlock(1).GetBlock(idx))

all_blocks = [output.GetBlock(0)] + all_out_patch_blocks
 
for block in all_blocks:
    # create a new array in this block
    conc_inlet_array = vtk.vtkFloatArray()
    conc_inlet_array.SetName(result_name)
 
    n_points_this_block = block.GetNumberOfPoints()
    conc_array_this_block = block.GetPointData().GetArray(variable)
    if weight_var:
        weight_array_this_block = block.GetPointData().GetArray(weight_var)
  
    for cell_idx in range(n_points_this_block):
        value = conc_array_this_block.GetValue(cell_idx)
        if not weight_var:
            conc_inlet_array.InsertNextValue(value/mean_conc)
        else:
            weight_value = weight_array_this_block.GetValue(cell_idx)
            conc_inlet_array.InsertNextValue(value*weight_value/mean_conc)
  
    # add the new array
    block.GetPointData().AddArray(conc_inlet_array)

Please clarify what you mean by that

We use a script called pyFoamPVSnapshot.py from PyFoam · PyPI to create snapshots of multiple simulations and timesteps in parallel on a remote computer to not block our workstations with the task. But I realize, I must further investigate the individual steps performed there to pin down the actual problem - right now my feeling is, that this is not a Paraview problem anymore, but might be related to PyFoam itself or some other thing going wrong in between. In the meantime, thanks for your support Mathieu, I will post back once I have identified the issue.

1 Like

Thanks !

Although the original problem remains unknown to me, I have worked around it by completely taking PyFoam out of the game. I now use a simpler Python script to create images using the SaveScreenshot function provided by paraview.simple.
So the problem seems to arise somewhere in PyFoam and I am not willing to track it down there.