Merge lp:~fluidity-core/fluidity/speedup-vtudiff into lp:fluidity

Proposed by Stephan Kramer
Status: Merged
Merged at revision: 4320
Proposed branch: lp:~fluidity-core/fluidity/speedup-vtudiff
Merge into: lp:fluidity
Diff against target: 386 lines (+101/-212)
2 files modified
manual/visualisation_and_diagnostics.tex (+1/-13)
python/vtktools.py (+100/-199)
To merge this branch: bzr merge lp:~fluidity-core/fluidity/speedup-vtudiff
Reviewer Review Type Date Requested Status
Jon Hill Approve
Review via email: mp+201957@code.launchpad.net

Description of the change

This speeds up the vtudiff script run on vtus with multiple fields, by only setting up the VTK probe once instead of once per field. It does not change anything in the way fields are probed.

There is also a little bit of cleaning up:
* removing the option to call vtktools as a main: this really doesn't make sense and should be in a separate script
* removing the "field manipulation" methods. These were basically vectorial operations on fields but implemented in a rather inefficient way. I see no reason to not simply use numpy vector operations for that, so instead of:

vtu.SubFieldFromField("fieldName", array, "newFieldName")

just do:

field = vtu.GetField("fieldName")
vtu.AddField("newFieldName", field-array)

To post a comment you must log in.
4308. By Stephan Kramer

For vtudiff: Also compute diff of cell-based fields (only works if both meshes are the same)

Revision history for this message
Jon Hill (jon-hill) :
review: Approve
Revision history for this message
Stephan Kramer (s-kramer) wrote :

Thanks Jon, will merge once I have a green buildbot.

4309. By Stephan Kramer

Maintain the same sign convention in vtudiff as before:

With "vtudiff A.vtu B.vtu C.vtu" we get fieldC = fieldA-fieldB
Also don't try to subtract vtkGhostLevels field.

4310. By Stephan Kramer

Merge in trunk.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'manual/visualisation_and_diagnostics.tex'
--- manual/visualisation_and_diagnostics.tex 2013-04-12 10:31:41 +0000
+++ manual/visualisation_and_diagnostics.tex 2014-02-19 10:25:38 +0000
@@ -350,8 +350,6 @@
350 method & arguments & use \\ \hline 350 method & arguments & use \\ \hline
351\lstinline[language=Python]+AddField+ & \lstinline[language=Python]+name, array+ & Adds the values in \lstinline[language=Python]+array+ (the entries of which may have an arbitrary number of components) as a field called \lstinline[language=Python]+name+ \\ \hline351\lstinline[language=Python]+AddField+ & \lstinline[language=Python]+name, array+ & Adds the values in \lstinline[language=Python]+array+ (the entries of which may have an arbitrary number of components) as a field called \lstinline[language=Python]+name+ \\ \hline
352%352%
353\lstinline[language=Python]+AddFieldtoField+ & \lstinline[language=Python]+fieldname,+ \lstinline[language=Python]+array,+ \lstinline[language=Python]+newFieldName=None+ & Adds the values in \lstinline[language=Python]+array+ to the field \lstinline[language=Python]+fieldname+. If \lstinline[language=Python]+newFieldName+ is specified then a new field with that name is created with the new values, otherwise the original field is replaced. \\ \hline
354%
355\lstinline[language=Python]+AddScalarField+ & \lstinline[language=Python]+name, array+ & Adds a scalar field called \lstinline[language=Python]+name+ using the values in \lstinline[language=Python]+array+ \\ \hline353\lstinline[language=Python]+AddScalarField+ & \lstinline[language=Python]+name, array+ & Adds a scalar field called \lstinline[language=Python]+name+ using the values in \lstinline[language=Python]+array+ \\ \hline
356%354%
357\lstinline[language=Python]+AddVectorField+ & \lstinline[language=Python]+name, array+ & Adds a vector field called \lstinline[language=Python]+name+ using the values in \lstinline[language=Python]+array+ \\ \hline355\lstinline[language=Python]+AddVectorField+ & \lstinline[language=Python]+name, array+ & Adds a vector field called \lstinline[language=Python]+name+ using the values in \lstinline[language=Python]+array+ \\ \hline
@@ -365,10 +363,6 @@
365\lstinline[language=Python]+CellDataToPointData+ & & transforms all cell--wise fields to point--wise fields. All existing fields will remain, \\ \hline363\lstinline[language=Python]+CellDataToPointData+ & & transforms all cell--wise fields to point--wise fields. All existing fields will remain, \\ \hline
366\lstinline[language=Python]+Crop+ & \lstinline[language=Python]+min_x, max_x,+ \lstinline[language=Python]+min_y, max_y+, \lstinline[language=Python]+min_z, max_z+ & Crops the edges defined by the bounding box given by the arguments \\ \hline364\lstinline[language=Python]+Crop+ & \lstinline[language=Python]+min_x, max_x,+ \lstinline[language=Python]+min_y, max_y+, \lstinline[language=Python]+min_z, max_z+ & Crops the edges defined by the bounding box given by the arguments \\ \hline
367%365%
368\lstinline[language=Python]+CrossFieldWithField+ & \lstinline[language=Python]+fieldName,+ \lstinline[language=Python]+array,+ \lstinline[language=Python]+newFieldName=None,+ \lstinline[language=Python]+postMultiply=True+ & Calculates the cross product, ${\bf a} \times {\bf b}$, where ${\bf a}$ is the field \lstinline[language=Python]+fieldName+ and ${\bf b}$ is \lstinline[language=Python]+array+. If \lstinline[language=Python]+postMultiply$\neq$True+ then ${\bf b} \times {\bf a}$ will be calculated. If \lstinline[language=Python]+newFieldName+ is specified then a new field with that name is created that takes the values of the cross product, otherwise the original field is replaced. \\ \hline
369%
370\lstinline[language=Python]+DotFieldWithField+ & \lstinline[language=Python]+fieldName,+ \lstinline[language=Python]+array,+ \lstinline[language=Python]+newFieldName+ & Calculates the dot product of the field called \lstinline[language=Python]+fieldName+ and \lstinline[language=Python]+array+. If \lstinline[language=Python]+newFieldName+ is specified then a new field with that name is created that takes the values of the dot product, otherwise the original field is replaced. \\ \hline
371%
372\lstinline[language=Python]+GetCellPoints+ & \lstinline[language=Python]+id+ & Returns an array with the node numbers of the cell (mesh element) number \lstinline[language=Python]+id+. \\ \hline366\lstinline[language=Python]+GetCellPoints+ & \lstinline[language=Python]+id+ & Returns an array with the node numbers of the cell (mesh element) number \lstinline[language=Python]+id+. \\ \hline
373%367%
374\lstinline[language=Python]+GetCellVolume+ & \lstinline[language=Python]+id+ & Returns the volume of the cell (mesh element) with number \lstinline[language=Python]+id+ \\ \hline368\lstinline[language=Python]+GetCellVolume+ & \lstinline[language=Python]+id+ & Returns the volume of the cell (mesh element) with number \lstinline[language=Python]+id+ \\ \hline
@@ -404,18 +398,12 @@
404%398%
405\lstinline[language=Python]+IntegrateField+ & \lstinline[language=Python]+field+ & Returns the integral of the field called \lstinline[language=Python]+field+ assuming a linear representation on a tetrahedral mesh. \\ \hline399\lstinline[language=Python]+IntegrateField+ & \lstinline[language=Python]+field+ & Returns the integral of the field called \lstinline[language=Python]+field+ assuming a linear representation on a tetrahedral mesh. \\ \hline
406%400%
407\lstinline[language=Python]+ManipulateField+ & \lstinline[language=Python]+fieldName,+ \lstinline[language=Python]+manipFunc,+ \lstinline[language=Python]+newFieldName=None+ & Generic field manipulation method. Applies the supplied manipulation function, \lstinline[language=Python]+manipFunc+, to the field called \lstinline[language=Python]+fieldName+. \lstinline[language=Python]+manipFunc+ must have form \lstinline[language=Python]+def manipFunc(field, index):+ $\ldots$ \lstinline[language=Python]+return fieldValAtIndex+. If \lstinline[language=Python]+newFieldName+ is specified then a new field with that name is created that takes the calculated values, otherwise the original field is replaced. \\ \hline401\lstinline[language=Python]+ProbeData+ & \lstinline[language=Python]+coordinates,+ \lstinline[language=Python]+name+ & Returns an array of values of the field called \lstinline[language=Python]+name+ at the positions given in \lstinline[language=Python]+coordinates+. The values are calculated by interpolation of the field to the positions given. \lstinline[language=Python]+coordinates+ can be created using \lstinline[language=Python]+vtktools.arr()+ e.g. \lstinline[language=Python]+coordinates=vtktools.arr([[1,1,1],[1,1,2]])+. \\ \hline
408%
409\lstinline[language=Python]+MatMulFieldWithField+ & \lstinline[language=Python]+fieldName,+ \lstinline[language=Python]+array,+ \lstinline[language=Python]+newFieldName=None,+ \lstinline[language=Python]+postMultiply=True+. & Multiplies two matrices $\bar{\bar{A}}\bar{\bar{B}}$ where $\bar{\bar{A}}$ is the field \lstinline[language=Python]+fieldName+, and $\bar{\bar{B}}$ is \lstinline[language=Python]+array+. If \lstinline[language=Python]+postMultiply+$\neq$\lstinline[language=Python]+True+ then $\bar{\bar{A}}\bar{\bar{B}}$ will be calculated. If \lstinline[language=Python]+newFieldName+ is specified then a new field with that name is created that takes the values of the product, otherwise the original field is replaced. \\ \hline
410%
411 \lstinline[language=Python]+ProbeData+ & \lstinline[language=Python]+coordinates,+ \lstinline[language=Python]+name+ & Returns an array of values of the field called \lstinline[language=Python]+name+ at the positions given in \lstinline[language=Python]+coordinates+. The values are calculated by interpolation of the field to the positions given. \lstinline[language=Python]+coordinates+ can be created using \lstinline[language=Python]+vtktools.arr()+ e.g. \lstinline[language=Python]+coordinates=vtktools.arr([[1,1,1],[1,1,2]])+. \\ \hline
412%402%
413\lstinline[language=Python]+RemoveField+ & \lstinline[language=Python]+name+ & Removes the field called \lstinline[language=Python]+name+. \\ \hline 403\lstinline[language=Python]+RemoveField+ & \lstinline[language=Python]+name+ & Removes the field called \lstinline[language=Python]+name+. \\ \hline
414%404%
415\lstinline[language=Python]+StructuredPointProbe+ & \lstinline[language=Python]+nx,+ \lstinline[language=Python]+ny,+ \lstinline[language=Python]+nz,+ \lstinline[language=Python]+bounding_box=None+ & Returns a vtk structured object. \lstinline[language=Python]+nx, ny, nz+ are the number of points in the $x,\, y, \, z$ directions respectively. If \lstinline[language=Python]+bounding_box+ is not specified the bounding box of the domain is calculated automatically. If specified \lstinline[language=Python]+bounding_box = [xmin, xmax, ymin, ymax, zmin, zmax]+. \\ \hline405\lstinline[language=Python]+StructuredPointProbe+ & \lstinline[language=Python]+nx,+ \lstinline[language=Python]+ny,+ \lstinline[language=Python]+nz,+ \lstinline[language=Python]+bounding_box=None+ & Returns a vtk structured object. \lstinline[language=Python]+nx, ny, nz+ are the number of points in the $x,\, y, \, z$ directions respectively. If \lstinline[language=Python]+bounding_box+ is not specified the bounding box of the domain is calculated automatically. If specified \lstinline[language=Python]+bounding_box = [xmin, xmax, ymin, ymax, zmin, zmax]+. \\ \hline
416%406%
417\lstinline[language=Python]+SubFieldFromField+ & \lstinline[language=Python]+fieldName,+ \lstinline[language=Python]+array,+ \lstinline[language=Python]+newFieldName=None+ & Subtracts \lstinline[language=Python]+array+ from the field called \lstinline[language=Python]+fieldName+. If \lstinline[language=Python]+newFieldName+ is specified then a new field with that name is created that takes the values of the product, otherwise the original field is replaced. \\ \hline
418%
419\lstinline[language=Python]+Write+ & \lstinline[language=Python]+filename = []+ & Writes the data to a vtu file. If \lstinline[language=Python]+filename+ is not specified the name of the file originally read in will be used and therefore the input file will be overwritten. \\ \hline407\lstinline[language=Python]+Write+ & \lstinline[language=Python]+filename = []+ & Writes the data to a vtu file. If \lstinline[language=Python]+filename+ is not specified the name of the file originally read in will be used and therefore the input file will be overwritten. \\ \hline
420%408%
421% 409%
422410
=== modified file 'python/vtktools.py'
--- python/vtktools.py 2012-03-19 21:00:50 +0000
+++ python/vtktools.py 2014-02-19 10:25:38 +0000
@@ -262,64 +262,8 @@
262262
263 def ProbeData(self, coordinates, name):263 def ProbeData(self, coordinates, name):
264 """Interpolate field values at these coordinates."""264 """Interpolate field values at these coordinates."""
265265 probe = VTU_Probe(self.ugrid, coordinates)
266 # Initialise locator266 return probe.GetField(name)
267 locator = vtk.vtkPointLocator()
268 locator.SetDataSet(self.ugrid)
269 locator.SetTolerance(10.0)
270 locator.Update()
271
272 # Initialise probe
273 points = vtk.vtkPoints()
274 points.SetDataTypeToDouble()
275 ilen, jlen = coordinates.shape
276 for i in range(ilen):
277 points.InsertNextPoint(coordinates[i][0], coordinates[i][1], coordinates[i][2])
278 polydata = vtk.vtkPolyData()
279 polydata.SetPoints(points)
280 probe = vtk.vtkProbeFilter()
281 probe.SetInput(polydata)
282 probe.SetSource(self.ugrid)
283 probe.Update()
284
285 # Generate a list invalidNodes, containing a map from invalid nodes in the
286 # result to their closest nodes in the input
287 valid_ids = probe.GetValidPoints()
288 valid_loc = 0
289 invalidNodes = []
290 for i in range(ilen):
291 if valid_ids.GetTuple1(valid_loc) == i:
292 valid_loc += 1
293 else:
294 nearest = locator.FindClosestPoint([coordinates[i][0], coordinates[i][1], coordinates[i][2]])
295 invalidNodes.append((i, nearest))
296
297 # Get final updated values
298 pointdata=probe.GetOutput().GetPointData()
299 vtkdata=pointdata.GetArray(name)
300 nc=vtkdata.GetNumberOfComponents()
301 nt=vtkdata.GetNumberOfTuples()
302 array = arr([vtkdata.GetValue(i) for i in range(nt * nc)])
303
304 # Fix the point data at invalid nodes
305 if len(invalidNodes) > 0:
306 try:
307 oldField = self.ugrid.GetPointData().GetArray(name)
308 components = oldField.GetNumberOfComponents()
309 except:
310 try:
311 oldField = self.ugrid.GetCellData().GetArray(name)
312 components = oldField.GetNumberOfComponents()
313 except:
314 raise Exception("ERROR: couldn't find point or cell field data with name "+name+" in file "+self.filename+".")
315 for invalidNode, nearest in invalidNodes:
316 for comp in range(nc):
317 array[invalidNode * nc + comp] = oldField.GetValue(nearest * nc + comp)
318
319 valShape = self.GetField(name)[0].shape
320 array.shape = tuple([nt] + list(valShape))
321
322 return array
323267
324 def RemoveField(self, name):268 def RemoveField(self, name):
325 """Removes said field from the unstructured grid."""269 """Removes said field from the unstructured grid."""
@@ -489,93 +433,6 @@
489 probe.Update ()433 probe.Update ()
490434
491 return probe.GetOutput()435 return probe.GetOutput()
492
493 ### Field manipulation methods ###
494
495 def ManipulateField(self, fieldName, manipFunc, newFieldName = None):
496 """
497 Generic field manipulation method. Applies the supplied manipulation function
498 manipFunc to the field fieldName. manipFunc must be a function of the form:
499
500 def manipFunc(field, index):
501 # ...
502 return fieldValAtIndex
503 """
504
505 field = self.GetField(fieldName)
506 if newFieldName is None or fieldName == newFieldName:
507 self.RemoveField(fieldName)
508 newFieldName = fieldName
509
510 field = arr([manipFunc(field, i) for i in range(len(field))])
511 self.AddField(newFieldName, field)
512
513 return
514
515 def AddFieldToField(self, fieldName, array, newFieldName = None):
516 def ManipFunc(field, index):
517 return field[index] + array[index]
518
519 self.ManipulateField(fieldName, ManipFunc, newFieldName)
520
521 return
522
523 def SubFieldFromField(self, fieldName, array, newFieldName = None):
524 def ManipFunc(field, index):
525 return field[index] - array[index]
526
527 self.ManipulateField(fieldName, ManipFunc, newFieldName)
528
529 return
530
531 def DotFieldWithField(self, fieldName, array, newFieldName = None):
532 """
533 Dot product
534 """
535
536 def ManipFunc(field, index):
537 sum = 0.0
538 for i, val in enumerate(field[index]):
539 sum += val * array[index][i]
540
541 return sum
542
543 self.ManipulateField(fieldName, ManipFunc, newFieldName)
544
545 return
546
547 def CrossFieldWithField(self, fieldName, array, newFieldName = None, postMultiply = True):
548 """
549 Cross product
550 """
551
552 def ManipFunc(field, index):
553 if postMultiply:
554 return numpy.cross(field[index], array[index])
555 else:
556 return numpy.cross(array[index], field[index])
557
558 self.ManipulateField(fieldName, ManipFunc, newFieldName)
559
560 return
561
562 def MatMulFieldWithField(self, fieldName, array, newFieldName = None, postMultiply = True):
563 """
564 Matrix multiplication
565 """
566
567 def ManipFunc(field, index):
568 if postMultiply:
569 return numpy.matrix(field[i]) * numpy.matix(array[i])
570 else:
571 return numpy.matix(array[i]) * numpy.matrix(field[i])
572
573 self.ManipulateField(fieldName, ManipFunc, newFieldName)
574
575 return
576
577 # Default multiplication is dot product
578 MulFieldByField = DotFieldWithField
579 436
580 def GetDerivative(self, name):437 def GetDerivative(self, name):
581 """438 """
@@ -629,6 +486,73 @@
629 cdtpd.PassCellDataOn()486 cdtpd.PassCellDataOn()
630 cdtpd.Update()487 cdtpd.Update()
631 self.ugrid=cdtpd.GetUnstructuredGridOutput()488 self.ugrid=cdtpd.GetUnstructuredGridOutput()
489
490class VTU_Probe(object):
491 """A class that combines a vtkProbeFilter with a list of invalid points (points that it failed to probe
492 where we take the value of the nearest point)"""
493
494 def __init__(self, ugrid, coordinates):
495 # Initialise locator
496 locator = vtk.vtkPointLocator()
497 locator.SetDataSet(ugrid)
498 locator.SetTolerance(10.0)
499 locator.Update()
500
501 # Initialise probe
502 points = vtk.vtkPoints()
503 points.SetDataTypeToDouble()
504 ilen, jlen = coordinates.shape
505 for i in range(ilen):
506 points.InsertNextPoint(coordinates[i][0], coordinates[i][1], coordinates[i][2])
507 polydata = vtk.vtkPolyData()
508 polydata.SetPoints(points)
509 self.probe = vtk.vtkProbeFilter()
510 self.probe.SetInput(polydata)
511 self.probe.SetSource(ugrid)
512 self.probe.Update()
513
514 # Generate a list invalidNodes, containing a map from invalid nodes in the
515 # result to their closest nodes in the input
516 valid_ids = self.probe.GetValidPoints()
517 valid_loc = 0
518 self.invalidNodes = []
519 for i in range(ilen):
520 if valid_ids.GetTuple1(valid_loc) == i:
521 valid_loc += 1
522 else:
523 nearest = locator.FindClosestPoint([coordinates[i][0], coordinates[i][1], coordinates[i][2]])
524 self.invalidNodes.append((i, nearest))
525 self.ugrid = ugrid
526
527 def GetField(self, name):
528 # Get final updated values
529 pointdata = self.probe.GetOutput().GetPointData()
530 vtkdata=pointdata.GetArray(name)
531 nc=vtkdata.GetNumberOfComponents()
532 nt=vtkdata.GetNumberOfTuples()
533 array = arr([vtkdata.GetValue(i) for i in range(nt * nc)])
534
535 # Fix the point data at invalid nodes
536 if len(self.invalidNodes) > 0:
537 oldField = self.ugrid.GetPointData().GetArray(name)
538 if oldField is None:
539 oldField = self.ugrid.GetCellData().GetArray(name)
540 if oldField is None:
541 raise Exception("ERROR: couldn't find point or cell field data with name "+name+".")
542 components = oldField.GetNumberOfComponents()
543 for invalidNode, nearest in self.invalidNodes:
544 for comp in range(nc):
545 array[invalidNode * nc + comp] = oldField.GetValue(nearest * nc + comp)
546
547 # this is a copy and paster from vtu.GetField above:
548 if nc==9:
549 return array.reshape(nt,3,3)
550 elif nc==4:
551 return array.reshape(nt,2,2)
552 else:
553 return array.reshape(nt,nc)
554
555 return array
632 556
633def VtuMatchLocations(vtu1, vtu2, tolerance = 1.0e-6):557def VtuMatchLocations(vtu1, vtu2, tolerance = 1.0e-6):
634 """558 """
@@ -698,6 +622,8 @@
698622
699 # If the input vtu point locations match, do not use probe623 # If the input vtu point locations match, do not use probe
700 useProbe = not VtuMatchLocations(vtu1, vtu2)624 useProbe = not VtuMatchLocations(vtu1, vtu2)
625 if useProbe:
626 probe = VTU_Probe(vtu2.ugrid, vtu1.GetLocations())
701627
702 # Copy the grid from the first input vtu into the output vtu628 # Copy the grid from the first input vtu into the output vtu
703 resultVtu.ugrid.DeepCopy(vtu1.ugrid)629 resultVtu.ugrid.DeepCopy(vtu1.ugrid)
@@ -707,65 +633,40 @@
707 fieldNames1 = vtu1.GetFieldNames()633 fieldNames1 = vtu1.GetFieldNames()
708 fieldNames2 = vtu2.GetFieldNames()634 fieldNames2 = vtu2.GetFieldNames()
709 for fieldName in fieldNames1:635 for fieldName in fieldNames1:
636 field1 = vtu1.GetField(fieldName)
710 if fieldName in fieldNames2:637 if fieldName in fieldNames2:
711 if useProbe:638 if useProbe:
712 field2 = vtu2.ProbeData(vtu1.GetLocations(), fieldName)639 field2 = probe.GetField(fieldName)
713 else:640 else:
714 field2 = vtu2.GetField(fieldName)641 field2 = vtu2.GetField(fieldName)
715 resultVtu.SubFieldFromField(fieldName, field2)642 resultVtu.AddField(fieldName, field1-field2)
716 else:643 else:
717 resultVtu.RemoveField(fieldName)644 resultVtu.RemoveField(fieldName)
718645
646 # Also look for cell-based fields. This only works if we don't have
647 # to interpolate (both meshes are the same)
648 vtkdata=vtu1.ugrid.GetCellData()
649 fieldNames1 = [vtkdata.GetArrayName(i) for i in range(vtkdata.GetNumberOfArrays())]
650 vtkdata=vtu2.ugrid.GetCellData()
651 fieldNames2 = [vtkdata.GetArrayName(i) for i in range(vtkdata.GetNumberOfArrays())]
652 if useProbe:
653 # meshes are different - we can't interpolate cell-based fields so let's just remove them from the output
654 for fieldName in fieldNames1:
655 if fieldName=='vtkGhostLevels':
656 # this field should just be passed on unchanged
657 continue
658 resultVtu.RemoveField(fieldName)
659 else:
660 # meshes are the same - we can simply subtract
661 for fieldName in fieldNames1:
662 if fieldName=='vtkGhostLevels':
663 # this field should just be passed on unchanged
664 continue
665 elif fieldName in fieldNames2:
666 field1 = vtu1.GetField(fieldName)
667 field2 = vtu2.GetField(fieldName)
668 resultVtu.AddField(fieldName, field1-field2)
669 else:
670 resultVtu.RemoveField(fieldName)
671
719 return resultVtu 672 return resultVtu
720
721def usage():
722 print 'Usage:'
723 print 'COMMAND LINE: vtktools.py [-h] [-p] [-e var1,var2, ...] INPUT_FILENAME'
724 print ''
725 print 'INPUT_FILENAME:'
726 print ' The input file name.'
727 print ''
728 print 'OPTIONS:'
729 print ' -h Prints this usage message.'
730 print ' -p Converts the coordinates from xyz to latitude and longitude.'
731 print ' -e Extracts the data point from the variables provided.'
732
733if __name__ == "__main__":
734 import vtktools
735 import math
736 import getopt
737
738 optlist, args = getopt.getopt(sys.argv[1:], 'hpe:')
739
740 v = vtktools.vtu(args[0])
741
742 # Parse arguments
743 LongLat = False
744 for o,a in optlist:
745 if o == '-h':
746 usage()
747 elif o == '-p':
748 LongLat = True
749 elif o == '-e':
750 scalars = a.strip().split(",")
751
752 # Project domain if necessary
753 if(LongLat):
754 v.ApplyEarthProjection()
755
756 # Extract variables
757 if(scalars):
758 npoints = v.ugrid.GetNumberOfPoints ()
759 nvar = len(scalars)
760 for i in range (npoints):
761 (x,y,z) = v.ugrid.GetPoint (i)
762 line = "%lf "%x+"%lf "%y
763 for scalar in scalars:
764 line = line+" %lf"%v.ugrid.GetPointData().GetArray(scalar).GetTuple1(i)
765 print line
766
767
768
769
770
771