Programmable Source with vtkUnstructuredGrid and Python re

I’m currently experimenting with the Programmable Source and vtkUnstructuredGrid output, but I’m having trouble getting it to work. I’m simply trying to generate a single polyhedral cell, and I’m fairly certain I have the right source:

import re

cell_str = \
"""
1 :: polyhedra
n: 8
(
  1 :: [0.0 0.0 0.0]
  2 :: [1.0 0.0 0.0]
  3 :: [1.0 1.0 0.0]
  4 :: [0.0 1.0 0.0]
  5 :: [0.0 0.0 1.0]
  6 :: [1.0 0.0 1.0]
  7 :: [1.0 1.0 1.0]
  8 :: [0.0 1.0 1.0]
)
f: 6
(
  10 :: c0: 1 c1: 0 n: 4 (1, 4, 3, 2)
  15 :: c0: 1 c1: 0 n: 4 (1, 2, 6, 5)
  13 :: c0: 1 c1: 0 n: 4 (1, 5, 8, 4)
  12 :: c0: 1 c1: 0 n: 4 (7, 3, 4, 8)
  14 :: c0: 1 c1: 0 n: 4 (7, 8, 5, 6)
  19 :: c0: 1 c1: 0 n: 4 (7, 6, 2, 3)
)
"""

coords = []
n_index = 0
n_nodes = 0
n_faces = 0
node_line = 0
face_line = 0
node_map = {}
connectivity = []
lines = cell_str.split('\n')
cell = int(re.match('(\d+) :: (\S+)', lines[1]).group(1))
facet_pattern = "  (\d+) :: c0: (\d+) c1: (\d+) n: (\d+)"
float_pattern = "([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)"
coord_pattern = "  (\d+) :: \[{0} {0} {0}\]".format(float_pattern)

for i, line in enumerate(lines):
  node_match = re.match('n: (\d+)', line)
  face_match = re.match('f: (\d+)', line)
  if node_match:
    node_line = i + 2
    n_nodes = int(node_match.group(1))
  if face_match:
    face_line = i + 2
    n_faces = int(face_match.group(1))

for line in lines[node_line:node_line + n_nodes]:
  mat = re.match(coord_pattern, line)
  if mat:
    coord = (float(mat[2]), float(mat[4]), float(mat[6]))
    node_map[int(mat[1])] = n_index
    n_index = n_index + 1
    coords.append(coord)

connectivity.append(n_faces)

for line in lines[face_line:face_line + n_faces]:
  mat = re.match(facet_pattern, line)
  if mat:
    facet = (int(mat[1]), int(mat[2]), int(mat[3]), int(mat[4]))
    nodes = [node_map[int(i)] for i in re.split("[\(\)]", line)[1].split(',')]
    if facet[2] == cell:
      nodes.reverse()
    connectivity.append(len(nodes))
    for id in nodes:
      connectivity.append(id)

# Output to Paraview
from paraview import vtk
ids = vtk.vtkIdList()
pts = vtk.vtkPoints()
output = self.GetOutput()
output.Allocate(1, 1000)
for coord in coords:
  pts.InsertNextPoint(coord[0], coord[1], coord[2])
output.SetPoints(pts)
for index, id in enumerate(connectivity):
  ids.InsertId(index, id)
output.InsertNextCell(42, ids)

However, with Paraview-5.8.1, I currently get the following error:

Traceback (most recent call last):
  File "<string>", line 20, in <module>
  File "<string>", line 38, in RequestData
AttributeError: 'NoneType' object has no attribute 'group'

It’s clearly coming from the line:

cell = int(re.match('(\d+) :: (\S+)', lines[1]).group(1))

but when I type it in interactively via the Python Shell in Paraview, I get the expected result (i.e., 1)
Any ideas on what is going wrong here?

Thanks!

I figured out what was wrong. It looks like Paraview adds two spaces for every line in a multi-line string embedded in source code. As a result, all the regular expression matches were failing because of the leading whitespaces. Since Paraview doesn’t really allow console output to debug Programmable Source objects, I resorted to file output to check that the proper connectivity is being generated. With those changes, it works great!

This sounds like a bug though. Can you give more details on what doesn’t work with an example ?

Sure @mwestphal.
Using my example above, every line of cell_str has two leading spaces added to it.
So this line:

1 :: polyhedra

turns into the following:

  1 :: polyhedra

which was unexpected. Since my regular expression match format was:

cell = int(re.match('(\d+) :: (\S+)', lines[1]).group(1))

the match would fail since it didn’t account for the leading whitespaces. The fix was simple enough:

cell = int(re.match('(\d+) :: (\S+)', lines[1].strip()).group(1))

but I do agree that Paraview shouldn’t have added the whitespaces in the embedded string, and that’s likely a bug.

I was also mistaken in my earlier post about console output. A simple print statement does output to the Output Messages window, which I didn’t notice earlier, and file output for debugging is unnecessary.

Definitely unexpected.

I’ve opened an issue :
https://gitlab.kitware.com/paraview/paraview-superbuild/-/issues/165

A work around is to replace literal new lines by \n everywhere in your triple quoted string.