Hi
We're written a new Filter for mayavi (1.x) which allows one to plot
arbitrary fields (scalars and vectors) on iso-surfaces. It also gives
the volume fluxes and scalar fluxes through the iso-surface. The
result...some interesting diagnostics and cool pictures :-) Note: flux
fields are calculated using point wise quantities (using the normal at a
vertex) while integrals are performed over triangular elements in the
iso-surface.
For those interested in the hacking aspect, it's interesting because you
have the change the active scalar in a vtk dataset, so there cannot be
one dataset, ie. the active scalar required for the iso-surface is
different from the scalar you want to plot on the iso-surface. The only
way around this appears to be to make a deep copy of the output of the
contour filter, modify the active scalar of this copy and make this
object the output of the filter.
Prabhu, after people have had a change to give feedback, are you happy
with this being committed? We have started playing with mayavi2 (very
nice) so at a later stage we'll port it across.
Enjoy!
Gerard Gorman
Colin Cotter
"""
This module uses an iso-surface as a probe allowing arbitary scalars,
vectors and tensors to be plotted on that iso-surface. Fluxes are also
calculated. This will work for any dataset.
This code is distributed under the conditions of the BSD license. See
LICENSE.txt for details.
Copyright (c) 2001-2002, Prabhu Ramachandran.
"""
__author__ = "Gerard Gorman, Colin Cottor annd Prabhu Ramachandran"
__version__ = "$Revision: 1.0 $"
__date__ = "$Date: 2007/03/08 18:30:13 $"
import Base.Objects, Common
import Tkinter, tkColorChooser, math
import vtk
import vtkPipeline.vtkMethodParser
debug = Common.debug
class IsoSurfaceProbe (Base.Objects.Filter):
""" This module finds an iso-surface of scalar data, and
calculates the normal flux across it due to a vector field. This
will work for any dataset."""
def initialize (self):
debug ("In IsoSurfaceProbe::initialize ()")
Common.state.busy ()
self.cont_fil = vtk.vtkContourFilter ()
self.fil = self.cont_fil
if not self.mod_m.get_scalar_data_name ():
msg = "Warning: No scalar data present to contour!"
Common.print_err (msg)
self.iso = vtk.vtkPolyData ()
self.data_range = self.prev_fil.GetOutput ().GetScalarRange ()
self.SetInput (self.prev_fil)
self.cont_fil.SetValue (0, self.midrange)
attributes = self._get_attribute_list (self.prev_fil.GetOutput ().GetPointData ())
self.scalar_lst = attributes['scalars']
self.visible_scalar = ""
if self.scalar_lst:
self.visible_scalar = self.scalar_lst[0]
else:
self.visible_scalar = "Volume flux"
self._gui_init ()
self.scalar_var = Tkinter.StringVar ()
self.scalar_var.set (self.visible_scalar)
# used for the pipeline browser
self.pipe_objs = self.cont_fil
self.Update ()
Common.state.idle ()
def _gui_init (self):
debug ("In IsoSurfaceProbe::_gui_init ()")
self.slider = None
self.slider_pos = self.midrange
self.contour_var = Tkinter.DoubleVar ()
self.contour_var.set (self.slider_pos)
self.c_entry_var = Tkinter.DoubleVar ()
self.c_entry_var.set (self.slider_pos)
dr = self.mod_m.get_scalar_data_range ()
self.min_cnt = Tkinter.DoubleVar ()
self.min_cnt.set (dr[0])
self.max_cnt = Tkinter.DoubleVar ()
self.max_cnt.set (dr[1])
self.volume_flux_value = Tkinter.DoubleVar ()
self.volume_flux_value.set (0.0)
self.flux_values = {}
for sc in self.scalar_lst:
self.flux_values[sc+"Flux"] = Tkinter.DoubleVar ()
self.flux_values[sc+"Flux"].set (0.0)
self._auto_sweep_init ()
self.sweep_step.set (15)
def SetInput (self, source):
debug ("In IsoSurfaceProbe::SetInput ()")
Common.state.busy ()
self.cont_fil.SetInput (source.GetOutput ())
self.midrange = (self.data_range[0] + self.data_range[1])*0.5
dr = source.GetOutput ().GetScalarRange ()
if (dr[0] != self.data_range[0]) or (dr[1] != self.data_range[1]):
self.data_range = dr
self.min_cnt.set (dr[0])
self.max_cnt.set (dr[1])
self.c_entry_var.set ((dr[0] + dr[1])*0.5)
self.change_contour_limits ()
self.change_contour_entry ()
Common.state.idle ()
def save_config (self, file):
debug ("In IsoSurfaceProbe::save_config ()")
file.write ("%f, %f, %f, '%s'\n"%(self.c_entry_var.get (),
self.min_cnt.get (),
self.max_cnt.get (),
self.scalar_var.get()))
p = vtkPipeline.vtkMethodParser.VtkPickler ()
p.dump (self.cont_fil, file)
def load_config (self, file):
debug ("In IsoSurfaceProbe::load_config ()")
c_val, min_cnt, max_cnt, self.visible_scalar = eval (file.readline ())
self.slider_pos = c_val
self.contour_var.set (c_val)
self.c_entry_var.set (c_val)
self.min_cnt.set (min_cnt)
self.max_cnt.set (max_cnt)
self.scalar_var.set (self.visible_scalar)
p = vtkPipeline.vtkMethodParser.VtkPickler ()
p.load (self.cont_fil, file)
self.change_contour_slider ()
def config_changed (self):
debug ("In IsoSurfaceProbe::config_changed ()")
pass
def make_main_gui (self):
debug ("In IsoSurfaceProbe::make_main_gui ()")
frame = Tkinter.Frame (self.root, relief='ridge', bd=2)
frame.pack (side='top', fill='both', expand=1)
name = "Scalar Variable: " + self.mod_m.get_scalar_data_name ()
dr = (self.min_cnt.get (), self.max_cnt.get ())
resolution = (dr[1] - dr[0])/1000
self.slider = Tkinter.Scale (frame, label=name,
resolution=resolution,
variable=self.contour_var,
from_=dr[0], to=dr[1], length="8c",
orient='horizontal')
self.slider.grid (row=0, column=0, columnspan=2, sticky='ew')
self.slider.bind ("<ButtonRelease>", self.change_contour_slider )
lab = Tkinter.Label (frame, text="Iso-surface value :")
lab.grid (row=1, column=0, sticky='w')
entry = Tkinter.Entry (frame, width=10, relief='sunken',
textvariable=self.c_entry_var)
entry.grid (row=1, column=1, sticky='ew')
entry.bind ("<Return>", self.change_contour_entry)
lab = Tkinter.Label (frame, text="Minimum contour:")
lab.grid (row=2, column=0, sticky='w')
entry = Tkinter.Entry (frame, width=10, relief='sunken',
textvariable=self.min_cnt)
entry.grid (row=2, column=1, sticky='we')
entry.bind ("<Return>", self.change_contour_limits)
lab = Tkinter.Label (frame, text="Maximum contour:")
lab.grid (row=3, column=0, sticky='w')
entry = Tkinter.Entry (frame, width=10, relief='sunken',
textvariable=self.max_cnt)
entry.grid (row=3, column=1, sticky='we')
entry.bind ("<Return>", self.change_contour_limits)
self.scalar_gui (self.root)
def scalar_gui (self, master):
debug ("In IsoSurfaceProbe::scalar_gui ()")
if not self.scalar_lst:
return
rw = 0
frame = Tkinter.Frame (master, relief='ridge', bd=2)
frame.pack (side='top')
Tkinter.Label (frame, text="Select Scalar").grid (row=rw,
column=0,
sticky='ew')
rw = rw + 1
for sc in self.scalar_lst:
rb0 = Tkinter.Radiobutton (frame, text=sc,
variable=self.scalar_var, value=sc,
command=self.set_scalar_gui)
rb0.grid (row=rw, column=0, sticky='w')
rw = rw + 1
rb1 = Tkinter.Radiobutton (frame, text=sc+" advective flux",
variable=self.scalar_var, value=sc+"Flux",
command=self.set_scalar_gui)
rb1.grid (row=rw, column=0, sticky='w')
entry = Tkinter.Entry (frame, width=10, relief='sunken',
textvariable=self.flux_values[sc+"Flux"])
entry.grid (row=rw, column=1, sticky='we')
entry.bind ("<Return>", self.calc_flux)
rw = rw + 1
rbv = Tkinter.Radiobutton (frame, text="Volume flux",
variable=self.scalar_var, value="VolumeFlux",
command=self.set_scalar_gui)
rbv.grid (row=rw, column=0, sticky='w')
entryv = Tkinter.Entry (frame, width=10, relief='sunken',
textvariable=self.volume_flux_value)
entryv.grid (row=rw, column=1, sticky='we')
entryv.bind ("<Return>", self.calc_flux)
rw = rw + 1
def set_scalar_gui (self):
debug ("In IsoSurfaceProbe::set_scalar_gui ()")
Common.state.busy ()
self.visible_scalar = self.scalar_var.get()
self.Update ()
self.renwin.Render ()
Common.state.idle ()
def GetOutput (self):
debug ("In Projection::GetOutput ()")
return self.iso
def get_array_type(self,arr):
"""Returns if the array is a scalar ('scalars'), vector
('vectors') or tensor ('tensors'). It looks at the number of
components to decide. If it has a wierd number of components it
returns the empty string."""
n = arr.GetNumberOfComponents()
if n == 1:
return 'scalars'
elif n == 3:
return 'vectors'
elif n == 9:
return 'tensors'
else:
return ''
def _get_attribute_list(self, data):
""" Gets scalar, vector and tensor information from the given data
(either cell or point data). """
debug ("In _get_attribute_list ()")
attr = {'scalars':[], 'vectors':[], 'tensors':[]}
if data:
n = data.GetNumberOfArrays()
for i in range(n):
name = data.GetArrayName(i)
type = self.get_array_type(data.GetArray(i))
if type:
attr[type].extend([name])
return attr
def change_contour_limits (self, event=None):
debug ("In IsoSurfaceProbe::change_contour_limits ()")
min_cnt = self.min_cnt.get ()
max_cnt = self.max_cnt.get ()
val = self.contour_var.get ()
dr = self.data_range
if max_cnt < val:
msg = "Error: max. contour value less than current "\
"contour value."
debug (msg)
max_cnt = dr[1]
self.max_cnt.set (max_cnt)
if min_cnt > val:
msg = "Error: min. contour value larger than current "\
"contour value."
debug (msg)
min_cnt = dr[0]
self.min_cnt.set (min_cnt)
resolution = (max_cnt - min_cnt)/1000
if self.slider:
self.slider.config (from_=min_cnt, to=max_cnt,
resolution=resolution)
def change_contour_slider (self, event=None):
debug ("In IsoSurfaceProbe::change_contour_slider ()")
Common.state.busy ()
self.slider_pos = self.contour_var.get ()
self.c_entry_var.set (self.slider_pos)
self.cont_fil.SetValue (0, self.slider_pos)
self.Update ()
Common.state.idle ()
def change_contour_entry (self, event=None):
debug ("In IsoSurfaceProbe::change_contour_entry ()")
Common.state.busy ()
self.slider_pos = self.c_entry_var.get ()
self.contour_var.set (self.slider_pos)
self.cont_fil.SetValue (0, self.slider_pos)
self.Update ()
Common.state.idle ()
def do_sweep (self, event=None):
debug ("In IsoSurfaceProbe::do_sweep ()")
if self.sweep_var.get ():
val = int (1000*self.sweep_delay.get ())
self.root.after (val, self.update_sweep)
def Update (self):
debug ("In IsoSurfaceProbe::Update ()")
Common.state.busy ()
self.cont_fil.Update ()
self.mod_m.Update ()
self.iso.DeepCopy (self.cont_fil.GetOutput ())
self.calc_flux ()
self.iso.GetPointData ().SetActiveScalars (self.visible_scalar)
self.renwin.Render ()
Common.state.idle ()
def update_sweep (self):
debug ("In IsoSurfaceProbe::update_sweep ()")
if self.sweep_var.get ():
min_cnt = self.min_cnt.get ()
max_cnt = self.max_cnt.get ()
d_pos = (max_cnt - min_cnt)/self.sweep_step.get ()
pos = self.slider_pos + d_pos
if (d_pos > 0) and (pos >= max_cnt):
pos = min_cnt
elif (d_pos < 0) and (pos <= min_cnt):
pos = max_cnt
self.contour_var.set (pos)
self.change_contour_slider ()
val = int (1000*self.sweep_delay.get ())
self.root.after (val, self.update_sweep)
def close_gui (self, event=None):
debug ("In IsoSurfaceProbe::close_gui ()")
Base.Objects.Filter.close_gui (self, event)
self.slider = None
def calc_flux (self, event=None):
debug ("In IsoSurfaceProbe::calc_flux ()")
self.cont_fil.Update ()
n_points = self.GetOutput ().GetNumberOfPoints ()
point_normal_calculator = vtk.vtkPolyDataNormals ()
point_normal_calculator.SetInput (self.GetOutput ())
point_normal_calculator.Update ()
normals = point_normal_calculator.GetOutput ().GetPointData ().GetNormals ()
volume_flux_array = vtk.vtkDoubleArray()
volume_flux_array.SetNumberOfTuples(n_points)
volume_flux_array.SetName('VolumeFlux')
vecs = self.GetOutput().GetPointData().GetVectors()
for i in range(n_points):
(u,v,w) = vecs.GetTuple3(i)
(n1,n2,n3) = normals.GetTuple3 (i)
volume_flux = u*n1 + v*n2 + w*n3
volume_flux_array.SetTuple1 (i, volume_flux)
self.GetOutput ().GetPointData ().AddArray(volume_flux_array)
self.GetOutput ().GetPointData ().SetActiveAttribute(volume_flux_array.GetName(),0)
self.GetOutput ().Update ()
flux_array = vtk.vtkDoubleArray()
flux_array.SetNumberOfTuples(n_points)
for sc in self.scalar_lst:
flux_name = sc+"Flux"
flux_array.SetName (flux_name)
scal = self.cont_fil.GetOutput ().GetPointData ().GetScalars (sc)
fluxscal = self.GetOutput ().GetPointData ().GetScalars ("VolumeFlux")
if self.visible_scalar==flux_name:
for i in range(n_points):
s = scal.GetTuple1 (i)
f = fluxscal.GetTuple1 (i)
flux = s*f
flux_array.SetTuple1 (i, flux)
self.GetOutput ().GetPointData ().AddArray(flux_array)
self.GetOutput ().GetPointData ().SetActiveAttribute(flux_array.GetName(),0)
self.GetOutput ().Update ()
# Integration loop
n_cells = self.GetOutput ().GetNumberOfCells ()
Integral_volume_flux = 0.0
scalar_advected_flux = 0.0
flux_name = None
flux_field = None
for sc in self.scalar_lst:
if self.visible_scalar==sc+"Flux":
flux_name = sc+"Flux"
flux_field = sc
break
vecs = self.GetOutput ().GetPointData ().GetVectors ()
if flux_name != None:
fluxf = self.GetOutput().GetPointData().GetScalars(sc)
for cell_no in range(n_cells):
Cell = self.GetOutput().GetCell(cell_no)
if(Cell.GetNumberOfPoints() != 3):
msg = "We have non-triangular elements in surface! You are too interesting. Go away."
Common.print_err (msg)
Cell_points = Cell.GetPoints ()
Area = Cell.TriangleArea (Cell_points.GetPoint(0), \
Cell_points.GetPoint(1), \
Cell_points.GetPoint(2))
n = [0.0,0.0,0.0]
Cell.ComputeNormal (Cell_points.GetPoint(0), \
Cell_points.GetPoint(1), \
Cell_points.GetPoint(2), n)
(u0,v0,w0) = vecs.GetTuple3 (Cell.GetPointId (0))
(u1,v1,w1) = vecs.GetTuple3 (Cell.GetPointId (1))
(u2,v2,w2) = vecs.GetTuple3 (Cell.GetPointId (2))
u = (u0+u1+u2)/3.0
v = (v0+v1+v2)/3.0
w = (w0+w1+w2)/3.0
f = Area*(u*n[0] + v*n[1] + w*n[2])
Integral_volume_flux = Integral_volume_flux + f
if flux_name != None:
s0 = fluxf.GetTuple1 (Cell.GetPointId (0))
s1 = fluxf.GetTuple1 (Cell.GetPointId (1))
s2 = fluxf.GetTuple1 (Cell.GetPointId (2))
s = (s0+s1+s2)/3.0
scalar_advected_flux = scalar_advected_flux + s*f
self.volume_flux_value.set (Integral_volume_flux)
if flux_name != None:
self.flux_values[flux_name].set (scalar_advected_flux)
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems? Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
MayaVi-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mayavi-users