# Programmable filter - eigenvalues/lambda2

**URL:** https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188
**Category:** ParaView Support
**Created:** [May 30, 2023, 3:14pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188 "2023-05-30T15:14:36Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![flotus1](https://discourse.paraview.org/letter_avatar_proxy/v4/letter/f/7ea924/32.png) [@flotus1](https://discourse.paraview.org/u/flotus1)
#### Post date: [May 30, 2023, 3:14pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/1 "2023-05-30T15:14:37Z")

</div>

I followed this guide in an attempt to get Eigenvalues / Lambda2 calculated by ParaView:

> [@Eigenvalue computation](https://discourse.paraview.org/t/eigenvalue-computation/9307):
>
> Hello all, I am implementing Lambda-2 criterion in Paraview 5.6.0 mounted on Linux. What it does is to provide a view of the presence of a vortex in a 3D flow by knowing when at least two of the eigenvalues of (||S||^2 + ||Omega||^2) are negative. Here, S and Omega are the symmetric and antisymmetric parts of the Velocity gradient tensor. By following the instructions of some other posts where they dealt with this implementation, I have made the following: Gradient of unstructured data set. …

My script looks like this:

```auto
import numpy as np
from vtk.numpy_interface import algorithms as algs

input=inputs[0]
Velocity_Vector = input.PointData['velocity']
STRAIN = strain(Velocity_Vector)
V_gradient = gradient(Velocity_Vector)
AAA=STRAIN**2+(V_gradient - STRAIN)**2
print(shape(AAA))
Lambda_2 = np.linalg.eigvals(AAA[:])
Lambda_2 = np.real(Lambda_2)
output.PointData.append(Lambda_2, 'Lambda_2')

```

Which seems to work up to the line “Lambda\_2 = np.linalg.eigvals(AAA[:])”  
Here I get the error “ **numpy.linalg.LinAlgError: 0-dimensional array given. Array must be at least two-dimensional** ”  
The shape of AAA is printed as (12058557,3,3)  
The input for this filter is point data with a velocity field in vector form.  
PV version 5.11.0

I am new to programmable filters and Python in general. A nudge into the right direction would be greatly appreciated.

---

<div class="post-metadata">

### Author: ![flotus1](https://discourse.paraview.org/letter_avatar_proxy/v4/letter/f/7ea924/32.png) [@flotus1](https://discourse.paraview.org/u/flotus1)
#### Post date: [May 31, 2023, 7:35am UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/2 "2023-05-31T07:35:36Z")

</div>

Btw, in case this is an issue of me not working with “numpy arrays”:  
I tried various methods with code snippets I found on the internet, to retain the “Velocity\_Vector = algs.make\_vector(Vx,Vy,Vz)” line from the original. Maybe that makes a difference compared to just importing the velocity vector as-is. So far without success.

For example, I added some calculators earlier in the chain of filters to have the velocity components available as scalars vx, vy, vz.  
Changing my script to  
input=inputs[0]

```auto
Vx = input.PointData["vx"]
Vy = input.PointData["vy"]
Vz = input.PointData["vz"]
print(shape(Vx))
Velocity_Vector = algs.make_vector(Vx,Vy,Vz)

```

I get the shape of Vx printed as (12058557,)  
But the last line throws the error “AttributeError: ‘VTKCompositeDataArray’ object has no attribute ‘shape’”  
???

---

<div class="post-metadata">

### Author: ![Francois\_Mazen](https://discourse.paraview.org/user_avatar/discourse.paraview.org/francois_mazen/32/6483_2.png) [@Francois\_Mazen](https://discourse.paraview.org/u/Francois_Mazen)
#### Post date: [May 31, 2023, 7:23pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/3 "2023-05-31T19:23:19Z")

</div>

Hi @flotus1

have you tried without the copy operation `[:]`, e.g.

```auto
Lambda_2 = np.linalg.eigvals(AAA)

```

Not sure to understand why the copy is needed here.

By the way you may want to read the numpy/VTK doc here: [6. Using NumPy for processing data — ParaView Documentation 5.11.0 documentation](https://docs.paraview.org/en/latest/ReferenceManual/vtkNumPyIntegration.html)

Best,

---

<div class="post-metadata">

### Author: ![flotus1](https://discourse.paraview.org/letter_avatar_proxy/v4/letter/f/7ea924/32.png) [@flotus1](https://discourse.paraview.org/u/flotus1)
#### Post date: [May 31, 2023, 8:16pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/4 "2023-05-31T20:16:57Z")

</div>

Thanks for the reply.  
Yes, I tried without “[:]”, among a few other things. To no avail, the error remains the same.  
I will try to understand the documentation you linked when I have a few hours of downtime.

I was hoping for some kind of a shortcut here, that doesn’t involve me learning python/numpy.  
After all, this should not be horribly difficult to pull off. Yet there are plenty of instances of people asking to do the same thing online. Most of these discussions seem to go nowhere. Some of the guides you find flat out don’t work. And I found a plugin that is no longer maintained for current versions of PV: [VCG - Vortex Criteria - ParaView Plugin - Visual Computing Group - Heidelberg University](https://vcg.iwr.uni-heidelberg.de/plugins/vcg_-_vortex_criteria)

Worst of all: ParaView has computation of lambda2 built-in, in the “Vortex Cores” filter. But that is not particularly useful, since the output of that filter is lines.

I also tried

```auto
...
print(isinstance(AAA, np.ndarray))
np.asarray(AAA)
print(isinstance(AAA, np.ndarray))

```

Which yields “False” both times

---

<div class="post-metadata">

### Author: ![flotus1](https://discourse.paraview.org/letter_avatar_proxy/v4/letter/f/7ea924/32.png) [@flotus1](https://discourse.paraview.org/u/flotus1)
#### Post date: [June 2, 2023, 12:22pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/5 "2023-06-02T12:22:42Z")

</div>

I can’t seem to make this work. None of the commands I find in the documentation, or in similar threads on the internet, seem to help.

What I did now is this: I downloaded the “official” ParaView testing data files. And opened the “timestep\_0\_15.vts” file in PV. After applying the “Clean to grid” filter, it is shown as an “Unstructured Grid” data type. Lo and behold, using the programmable filter from my initial post, adjusted to the “Momentum” vector present in this data, works without a hitch.

After importing the data I actually want to work with, PV shows the data type as “Multi-Block Dataset”.  
It is originally cell-centered data in an Ensight Gold file format. So far, I used the “Cell data to point data” filter in order to work with point data. Applying the “Clean to grid” filter here does not change the data type. It is still “Multi-Block Dataset”.

So I guess this is my new question:

1. what do I need to change in my programmable filter, in order to work with Multi-Block Datasets
2. -or- which filters do I need to apply to a Multi-Block Dataset, for PV to change the data type to unstructured grid. Or any other data type where the usual way of writing programmable filters works. **EDIT: the “Merge Blocks” filter seems to do the trick**

---

<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: [June 2, 2023, 12:29pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/6 "2023-06-02T12:29:15Z")

</div>

> [@flotus1](#):
>
> which filters do I need to apply to a Multi-Block Dataset, for PV to change the data type to unstructured grid. Or any other data type where the usual way of writing programmable filters works.

MergeBlocks.

---

<div class="post-metadata">

### Author: ![flotus1](https://discourse.paraview.org/letter_avatar_proxy/v4/letter/f/7ea924/32.png) [@flotus1](https://discourse.paraview.org/u/flotus1)
#### Post date: [June 2, 2023, 12:30pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/7 "2023-06-02T12:30:04Z")

</div>

Yeah, just after I finished typing, I found that myself.

---

<div class="post-metadata">

### Author: ![flotus1](https://discourse.paraview.org/letter_avatar_proxy/v4/letter/f/7ea924/32.png) [@flotus1](https://discourse.paraview.org/u/flotus1)
#### Post date: [June 2, 2023, 2:00pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/8 "2023-06-02T14:00:40Z")

</div>

With that out of the way, I tried comparing the results of my filter to the ones obtained with this plugin: [VCG - Vortex Criteria - ParaView Plugin - Visual Computing Group - Heidelberg University](https://vcg.iwr.uni-heidelberg.de/plugins/vcg_-_vortex_criteria)  
Had to go back to PV version 5.6 to use it though.

The results don’t look too promising. With Lambda2 as a criterion to identify vortices in turbulent flows, the results on the left (from the plugin) are much more plausible.  
Bottom row of images is an iso-surface with a value of -5e9.

 ![comparison_01](https://discourse.paraview.org/uploads/default/original/2X/d/d935160eb69965cce69587a39292cf2907e1f86b.jpeg)

---

<div class="post-metadata">

### Author: ![bastian](https://discourse.paraview.org/user_avatar/discourse.paraview.org/bastian/32/7513_2.png) [@bastian](https://discourse.paraview.org/u/bastian)
#### Post date: [August 18, 2023, 4:54pm UTC](https://discourse.paraview.org/t/programmable-filter-eigenvalues-lambda2/12188/9 "2023-08-18T16:54:50Z")

</div>

> [@flotus1](#):
>
> My script looks like this:
> 
> ```auto
> import numpy as np
> from vtk.numpy_interface import algorithms as algs
> 
> input=inputs[0]
> Velocity_Vector = input.PointData['velocity']
> STRAIN = strain(Velocity_Vector)
> V_gradient = gradient(Velocity_Vector)
> AAA=STRAIN**2+(V_gradient - STRAIN)**2
> print(shape(AAA))
> Lambda_2 = np.linalg.eigvals(AAA[:])
> Lambda_2 = np.real(Lambda_2)
> output.PointData.append(Lambda_2, 'Lambda_2')
> 
> ```

I think that you have a few errors in your code:

1. `STRAIN**2` is probably an elementwise square. What you actually want is the matrix product that matches the signature _(n,k),(k,m)→(n,m)_, which matmul should provide
2. `np.linalg.eigvals` does not order the eigenvalues, but you want lambda\_2 to correspond to the second largest eigenvalue.

I wrote a filter that should give you the proper result, but I haven’t validated it:

```python
import numpy as np
from vtk.numpy_interface import algorithms as algs

# Compute the lambda_2 Vortex criterion, see pp.76-77 in
# J. Jeong and F. Hussain, “On the identification of a vortex,” 
# Journal of Fluid Mechanics, vol. 285, pp. 69–94, 1995, doi: 10.1017/S0022112095000462.

vvector = inputs[0].PointData['velocity']

vstrain = strain(vvector)
vskew = gradient(vvector) - vstrain

aaa = matmul(vstrain, vstrain) + matmul(vskew, vskew)

# since aaa is symmetric, it only has real eigenvalues
lambdas = eigenvalue(aaa)
lambdas = real(lambdas)
lambda2 = sort(lambdas)[:,1]

output.PointData.append(lambda2, 'lambda2')

```
