Help with exporting quaternion data in vtu file

Hello,
I am exporting data from a software called EDEM (Altair / DEM Solutions). I want to use ParaView to visualize the particle information from EDEM. I have used the pointsToVTK function to export the x, y, z positions of the particles and some data associated with the particles including particle ID, and length (both scalar values). I would like to also export the orientation information in the form of quaternions (q, x, y, z). It appears to me that the function pointsToVTK / data can only accept scalar, or vector data (1 element or 3 elements per point), however the quaternion has 4 elements per point. I am wondering if anyone has any suggestions on how I can overcome this issue?

Options that I have investigated…
1).Convert the quaternions (4 elements) to euler angles (three elements) before exporting the data. This allows me to export the data with the points, but the conversion to euler when applied to millions of particles is significantly slowing the data export from EDEM to vtu file.

2). Export the 4 elements of the quaternion as scalars into the vtu file. However I do not know if there is a way to combine the 4 elements into one in ParaView. I know it is possible to combine three elements together using the calculator and i, j, and k Hat functions. Is there any way to create the 4 element quaternion using the 4 individual values?

Thanks in advance for any guidance that you can offer!
Eric

VTK and ParaView support that without any issue. From where are you trying to export ?

Thanks for the reply Mathieu.
The data is exported from a EDEM simulation deck using the pointsToVTK function in python.

Do I understand you correctly, if for each point that is exported from EDEM I have a scalar value (q,w,x,y) that I can combine all four into a single attribute that I could reference for the orientation of a glyph as a quaternions? If so, can you please explain me the steps, or point me to a resource that has the information?
Regards,
Eric

Looks like this function does not support 4 components array. Since your problem is within EDEM, not sure how we can help. Does EDEM support exporting to other formats ?

Mathieu,
Is there any way in ParaView to combine the four individual elements of the quaternion into one? I am able to get the data into ParaView as individual elements(shown in attached) using the PointtoKTK function, but i need to combine them together so I can use it as the direction input for the Glyph as a quaternion.

Any help you can provide would be greatly appreciated!
Eric

EDEM does not directly support export to other formats directly. The only work around would be to use Option 1 defined in my original post.

Sadly ParaView does not support that easily yet. The feature request is here :
https://gitlab.kitware.com/paraview/paraview/-/issues/19885

It can be done using a ProgrammableFilter though.
https://www.paraview.org/Wiki/Python_Programmable_Filter

Do not hesitate if you need help to go forward.

Mathieu,
I will give the ProgrammableFilter a shot, thanks for the guidance!
Eric

Mathieu,
I have found a solution to my problem with two different options. I will share here in case it is useful for anyone else in the future. I suspect that my code is not the most efficient approach, but it works…

First I export the data from EDEM to vtu files using pointsToVTK. I export the 4 elements of the quaternion as:

pointsToVTK(vtkFileName, x, y, z, data = {“pID” : ids, “Length” : los, “Quatw” : qw,“Quatx” : qx,“Quaty” : qy,“Quatz” : qz})

next in Paraview I combine the the 4 elements of the quaternion together [Quatw, Quatx, Quaty, Quartz]

Option 1 - Programmable Filter

The programmable filter Script is as follows (it may not be the most efficient implementation but it works…):

#combine all 4 elements of the Quaternion into one structure
import numpy as np  
print("Quaternion creation started")
#store 4 Quat elements in arrays
input0 = inputs[0] 
dataArray = input0.PointData["Quatw"]
dataArray1 = input0.PointData["Quatx"]
dataArray2 = input0.PointData["Quaty"]
dataArray3 = input0.PointData["Quatz"]
#stack the arrays together to create 4 element Quat
All_Data2=np.vstack((dataArray,dataArray1))
All_Data2=np.vstack((All_Data2,dataArray2))
All_Data2=np.vstack((All_Data2,dataArray3))
#transpose the array to create the form (number point X 4)
All_Data2=np.transpose(All_Data2)
print("Quaternion of sphere")
print(All_Data2)
output.PointData.append(All_Data2, "Quaternion")
print("done")

Alternatively, I created a py script that can be imported as a ParaView Plugin (which makes it easier to share with others that will use the tool). The Python script is as follows:

Option 2 - Plugin Filter

from vtkmodules.vtkCommonDataModel import vtkDataSet, vtkUnstructuredGrid
from vtkmodules.util.vtkAlgorithm import VTKPythonAlgorithmBase
from vtkmodules.numpy_interface import dataset_adapter as dsa
import numpy as np  

#module for ParaView-specific decorators.
from paraview.util.vtkAlgorithm import smproxy, smproperty, smdomain
@smproxy.filter(label="Custom_Quaternion")
@smproperty.input(name="Input")

class CustomQuatFilter(VTKPythonAlgorithmBase):
# define output data type - vtkUnstructuredGrid .
def __init__(self):
    VTKPythonAlgorithmBase.__init__(self,
                                    nInputPorts=1,
                                    nOutputPorts=1,
                                    outputType="vtkUnstructuredGrid")

def RequestData(self, request, inInfo, outInfo):
   
    print("Started Custom Quaternion")  
   
    #store 4 Quat elements in arrays
    input0 = dsa.WrapDataObject(vtkUnstructuredGrid.GetData(inInfo[0]))

    #read in data in ParaView
    dataArray = input0.PointData["Quatw"]
    dataArray1 = input0.PointData["Quatx"]
    dataArray2 = input0.PointData["Quaty"]
    dataArray3 = input0.PointData["Quatz"]

    #stack the arrays together to create 4 element Quat
    All_Data2=np.vstack((dataArray,dataArray1))
    All_Data2=np.vstack((All_Data2,dataArray2))
    All_Data2=np.vstack((All_Data2,dataArray3))
   
    #transpose the array to create the form (number point X 4)
    All_Data2=np.transpose(All_Data2)

    # add to output
    output = dsa.WrapDataObject(vtkUnstructuredGrid.GetData(outInfo))
    output.ShallowCopy(vtkUnstructuredGrid.GetData(inInfo[0]))
    output.PointData.append(All_Data2, "Quaternion");
    print("Completed Custom Quaternion")  
   
    return 1

The .py file is added to the ParaView filters by going to the Tools-> Manage Plugins-> Load New
Regards,
Eric