Skip to content

Morse molecule

Pipeline description

This example first loads a VTI file on the disk. The VTI file contains three scalar fields namely Rho, log(Rho), and log(s). We are interested in topological analysis of the log(Rho) scalar field which corresponds to the electron density distribution around a simple molecule.

The MorseSmaleComplex is computed for this scalar field. The reason for computing Morse-Smale complex is that many chemically relevant concepts, for example, covalent bonds can be directly translated to topological structures computed using the Morse-Smale complex. The critical points of this scalar field also have chemical relevance. The maxima correspond to the atom locations and 2-saddles occur along chemical bonds.

Then the critical points are then converted into spheres using IcospheresFromPoints. The maxima are selected and highlighted as bigger spheres.

Then using appropriate filtering, the 1-separatrices corresponding to the covalent bonds are selected. The criteria used is to select the 1-sepatrices which have no critical points on the boundary and for which SeparatrixType = 2, that is they connect a 2-saddle to a maximum. Also, GeometrySmoother is used to make the jagged lines generated by the Morse-Smale complex a little smoother. Then, another type of 1-separatrix is extracted which connects a 2-saddle on a covalent bond to its neighbouring 1-saddles on the boundary.

Lastly, 2-separatrices incident on the covalent bonds (of SeparatrixType = 1) are extracted which correspond to separating walls between adjacent atoms. Another type (SeparatrixType = 2) of separating wall is also extracted.

ParaView

To reproduce the above screenshot, go to your ttk-data directory and enter the following command:

paraview states/morseMolecule.pvsm

Python code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from paraview.simple import *

# create a new 'XML Image Data Reader'
builtInExamplevti = XMLImageDataReader(FileName=["BuiltInExample2.vti"])

# create a new 'TTK MorseSmaleComplex'
tTKMorseSmaleComplex1 = TTKMorseSmaleComplex(Input=builtInExamplevti)
tTKMorseSmaleComplex1.ScalarField = ["POINTS", "log(Rho)"]
tTKMorseSmaleComplex1.Ascending2Separatrices = 1
tTKMorseSmaleComplex1.Descending2Separatrices = 1

# Generate spheres for the critical points using 'TTK IcospheresFromPoints'
tTKIcospheresFromPoints1 = TTKIcospheresFromPoints(Input=tTKMorseSmaleComplex1)
tTKIcospheresFromPoints1.Radius = 1.5

# Generate bigger spheres for the critical points using 'TTK IcospheresFromPoints'
tTKIcospheresFromPoints2 = TTKIcospheresFromPoints(Input=tTKMorseSmaleComplex1)
tTKIcospheresFromPoints2.Radius = 3.0

# Then select critical points of CellDimension 3 using 'Threshold' to select maxima
threshold3 = Threshold(Input=tTKIcospheresFromPoints2)
threshold3.Scalars = ["POINTS", "CellDimension"]
threshold3.ThresholdMethod = "Between"
threshold3.LowerThreshold = 3.0
threshold3.UpperThreshold = 3.0

# create a new 'Threshold'
threshold1 = Threshold(Input=OutputPort(tTKMorseSmaleComplex1, 1))
threshold1.Scalars = ["CELLS", "NumberOfCriticalPointsOnBoundary"]
threshold1.ThresholdMethod = "Between"
threshold1.LowerThreshold = 0.0
threshold1.UpperThreshold = 0.0

# create a new 'Threshold'
threshold2 = Threshold(Input=threshold1)
threshold2.Scalars = ["CELLS", "SeparatrixType"]
threshold2.ThresholdMethod = "Between"
threshold2.LowerThreshold = 2.0
threshold2.UpperThreshold = 2.0

# create a new 'TTK GeometrySmoother'
tTKGeometrySmoother1 = TTKGeometrySmoother(Input=threshold2)
tTKGeometrySmoother1.IterationNumber = 50

# create a new 'Clean to Grid'
cleantoGrid1 = CleantoGrid(Input=tTKGeometrySmoother1)

# create a new 'Extract Surface'
extractSurface1 = ExtractSurface(Input=cleantoGrid1)

# create a new 'Tube'
tube1 = Tube(Input=extractSurface1)
tube1.Scalars = ["POINTS", "CellDimension"]
tube1.Radius = 1.25

# create a new 'Threshold'
threshold8 = Threshold(Input=OutputPort(tTKMorseSmaleComplex1, 1))
threshold8.Scalars = ["CELLS", "SeparatrixType"]
threshold8.ThresholdMethod = "Between"
threshold8.LowerThreshold = 1.0
threshold8.UpperThreshold = 1.0

# create a new 'Threshold'
threshold9 = Threshold(Input=threshold8)
threshold9.Scalars = ["CELLS", "NumberOfCriticalPointsOnBoundary"]
threshold9.ThresholdMethod = "Between"
threshold9.LowerThreshold = 1.0
threshold9.UpperThreshold = 1.0

# create a new 'Threshold'
threshold11 = Threshold(Input=threshold9)
threshold11.Scalars = ["CELLS", "SeparatrixId"]
threshold11.ThresholdMethod = "Between"
threshold11.LowerThreshold = 75.0
threshold11.UpperThreshold = 76.0

# create a new 'Threshold'
threshold10 = Threshold(Input=threshold9)
threshold10.Scalars = ["CELLS", "SeparatrixId"]
threshold10.ThresholdMethod = "Between"
threshold10.LowerThreshold = 73.0
threshold10.UpperThreshold = 74.0

# create a new 'Append Datasets'
appendDatasets1 = AppendDatasets(Input=[threshold10, threshold11])

# create a new 'Clean to Grid'
cleantoGrid4 = CleantoGrid(Input=appendDatasets1)

# create a new 'TTK GeometrySmoother'
tTKGeometrySmoother4 = TTKGeometrySmoother(Input=cleantoGrid4)
tTKGeometrySmoother4.IterationNumber = 10

# create a new 'Extract Surface'
extractSurface3 = ExtractSurface(Input=tTKGeometrySmoother4)

# create a new 'Tube'
tube2 = Tube(Input=extractSurface3)
tube2.Scalars = ["POINTS", "CellDimension"]
tube2.Radius = 0.75

# create a new 'Threshold'
threshold4 = Threshold(Input=OutputPort(tTKMorseSmaleComplex1, 2))
threshold4.Scalars = ["CELLS", "SeparatrixType"]
threshold4.ThresholdMethod = "Between"
threshold4.LowerThreshold = 1.0
threshold4.UpperThreshold = 1.0

# create a new 'Clean to Grid'
cleantoGrid2 = CleantoGrid(Input=threshold4)

# create a new 'Tetrahedralize'
tetrahedralize1 = Tetrahedralize(Input=cleantoGrid2)

# create a new 'Extract Surface'
extractSurface2 = ExtractSurface(Input=tetrahedralize1)

# create a new 'TTK GeometrySmoother'
tTKGeometrySmoother2 = TTKGeometrySmoother(Input=extractSurface2)
tTKGeometrySmoother2.IterationNumber = 20

# select 2-separatrices using 'Threshold'
threshold5 = Threshold(Input=OutputPort(tTKMorseSmaleComplex1, 2))
threshold5.Scalars = ["CELLS", "SeparatrixType"]
threshold5.ThresholdMethod = "Between"
threshold5.LowerThreshold = 2.0
threshold5.UpperThreshold = 2.0

# create a new 'Threshold'
threshold6 = Threshold(Input=threshold5)
threshold6.Scalars = ["CELLS", "NumberOfCriticalPointsOnBoundary"]
threshold6.ThresholdMethod = "Between"
threshold6.LowerThreshold = 4.0
threshold6.UpperThreshold = 4.0

# select a particular 2-separatrix using 'Threshold'
threshold7 = Threshold(Input=threshold6)
threshold7.Scalars = ["CELLS", "SeparatrixId"]
threshold7.ThresholdMethod = "Between"
threshold7.LowerThreshold = 2.0
threshold7.UpperThreshold = 2.0

# create a new 'Clean to Grid'
cleantoGrid3 = CleantoGrid(Input=threshold7)

# create a new 'Tetrahedralize'
tetrahedralize2 = Tetrahedralize(Input=cleantoGrid3)

# create a new 'TTK GeometrySmoother'
tTKGeometrySmoother3 = TTKGeometrySmoother(Input=tetrahedralize2)
tTKGeometrySmoother3.IterationNumber = 20

# save the output
SaveData("CriticalPoints.vtp", tTKIcospheresFromPoints1)
SaveData("Maxima.vtu", threshold3)
SaveData("CovalentBonds.vtp", tube1)
SaveData("Selected2saddle1saddleConnectors.vtp", tube2)
SaveData("CovalentBondSeparatrixWalls.vtp", tTKGeometrySmoother2)
SaveData("SelectedType2SeparatrixWall.vtu", tTKGeometrySmoother3)

To run the above Python script, go to your ttk-data directory and enter the following command:

pvpython python/morseMolecule.py

Inputs

  • BuiltInExample2.vti: 3D scalar field corresponding to electron density distribution around a simple molecule.

Outputs

  • CriticalPoints.vtp: All the output critical points in VTK file format (small spheres in the above screenshot).
  • Maxima.vtu: The computed maxima which also correspond to atom locations in VTK file format (bigger green spheres).
  • CovalentBonds.vtp: Selected 1-separatrices corresponding to the covalent bonds in the molecule (the thick white tubes)
  • Selected2saddle1saddleConnectors.vtp: Geometry of selected separatrices connecting a 2-saddle on a covalent bond to its neighbouring 1-saddles (the dark grey tubes in the screenshot above).
  • CovalentBondSeparatrixWalls.vtp: Surface corresponding to 2-separatrices (walls) incident on the covalent bonds (the translucent blue surfaces in the above screenshot)
  • SelectedType2SeparatrixWall.vtu: Surface corresponding to another type of wall (the green surface).

Note that you are free to change the VTK file extensions to that of any other supported file format (e.g. csv) in the above python script.

C++/Python API

GeometrySmoother

IcospheresFromPoints

MorseSmaleComplex