manyspheres.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import datetime as dt
  2. from paraview import servermanager
  3. from paraview.simple import *
  4. from paraview.benchmark import *
  5. #import logbase, logparser
  6. logbase.maximize_logs()
  7. records = []
  8. n0 = dt.datetime.now()
  9. def get_render_view(size):
  10. '''Similar to GetRenderView except if a new view is created, it's
  11. created with the specified size instead of having t resize afterwards
  12. '''
  13. view = active_objects.view
  14. if not view:
  15. # it's possible that there's no active view, but a render view exists.
  16. # If so, locate that and return it (before trying to create a new one).
  17. view = servermanager.GetRenderView()
  18. if not view:
  19. view = CreateRenderView(ViewSize=size)
  20. return view
  21. def save_render_buffer(fname):
  22. '''Similar to SaveScreenshot except a re-render will not be triggered'''
  23. from vtkmodules.vtkRenderingCore import vtkWindowToImageFilter
  24. w = GetRenderView().SMProxy.GetRenderWindow()
  25. w2i = vtkWindowToImageFilter()
  26. w2i.ReadFrontBufferOff()
  27. w2i.ShouldRerenderOff()
  28. w2i.SetInput(w)
  29. w2i.Modified()
  30. png = PNGWriter()
  31. png.Input = w2i.GetOutput()
  32. png.FileName = fname
  33. png.UpdatePipeline()
  34. def flush_render_buffer():
  35. '''When running as a single process use the WindowToImage filter to
  36. force a framebuffer read. This bypasses driver optimizations that
  37. perform lazy rendering and allows you to get actual frame rates for
  38. a single process with a GPU. Multi-process doesn't need this since
  39. compositing forces the frame buffer read.
  40. '''
  41. # If we're not using off-screen rendering then we can bypass this since
  42. # the frame buffer display will force a GL flush
  43. w = GetRenderView().SMProxy.GetRenderWindow()
  44. if not w.GetOffScreenRendering():
  45. return
  46. from vtkmodules.vtkRenderingCore import vtkWindowToImageFilter
  47. from vtkmodules.vtkParallelCore import vtkMultiProcessController
  48. # If we're using MPI we can also bypass this since compositing will
  49. # for a GL flush
  50. controller = vtkMultiProcessController.GetGlobalController()
  51. if controller.GetNumberOfProcesses() > 1:
  52. return
  53. # Force a GL flush by retrieving the frame buffer image
  54. w2i = vtkWindowToImageFilter()
  55. w2i.ReadFrontBufferOff()
  56. w2i.ShouldRerenderOff()
  57. w2i.SetInput(w)
  58. w2i.Modified()
  59. w2i.Update()
  60. def memtime_stamp():
  61. global records
  62. global n0
  63. m = logbase.get_memuse()
  64. n1 = dt.datetime.now()
  65. et = n1 - n0
  66. print(et, m)
  67. n0 = n1
  68. records.append([et, m])
  69. def run(output_basename='log', num_spheres=8, num_spheres_in_scene=None,
  70. resolution=725, view_size=(1920, 1080), num_frames=10, save_logs=True,
  71. transparency=False, ospray=False):
  72. if num_spheres_in_scene is None:
  73. num_spheres_in_scene = num_spheres
  74. from vtkmodules.vtkParallelCore import vtkMultiProcessController
  75. from vtkmodules.vtkCommonSystem import vtkTimerLog
  76. controller = vtkMultiProcessController.GetGlobalController()
  77. view = get_render_view(view_size)
  78. if ospray:
  79. view.EnableRayTracing = 1
  80. print('Generating bounding box')
  81. import math
  82. edge = math.ceil(math.pow(num_spheres_in_scene, (1.0 / 3.0)))
  83. box = Box()
  84. box.XLength = edge
  85. box.YLength = edge
  86. box.ZLength = edge
  87. box.Center = [edge * 0.5, edge * 0.5, edge * 0.5]
  88. boxDisplay = Show()
  89. boxDisplay.SetRepresentationType('Outline')
  90. print('Generating all spheres')
  91. gen = ProgrammableSource(Script='''
  92. import math
  93. from vtkmodules.vtkParallelCore import vtkMultiProcessController
  94. from vtkmodules.vtkFiltersSources import vtkSphereSource
  95. from vtkmodules.vtkFiltersCore import vtkAppendPolyData
  96. from vtkmodules.vtkCommonDataModel import vtkPolyData
  97. try:
  98. num_spheres
  99. except:
  100. num_spheres = 8
  101. try:
  102. num_spheres_in_scene
  103. except:
  104. num_spheres_in_scene = num_spheres
  105. try:
  106. res
  107. except:
  108. res = 725
  109. edge = math.ceil(math.pow(num_spheres_in_scene, (1.0 / 3.0)))
  110. controller = vtkMultiProcessController.GetGlobalController()
  111. np = controller.GetNumberOfProcesses()
  112. p = controller.GetLocalProcessId()
  113. ns=lambda rank:num_spheres/np + (1 if rank >= np-num_spheres%np else 0)
  114. # Not sure why but the builtin sum() gives weird results here so we'll just
  115. # so it manually
  116. start=0
  117. for r in range(0,p):
  118. start += int(ns(r))
  119. end=start+ns(p)
  120. start = int(start)
  121. end = int(end)
  122. ss = vtkSphereSource()
  123. ss.SetPhiResolution(res)
  124. ss.SetThetaResolution(res)
  125. ap = vtkAppendPolyData()
  126. print(' source %d: generating %d spheres from %d to %d' % (p, end-start, start, end))
  127. for x in range(start,end):
  128. i = x%edge
  129. j = math.floor((x / edge))%edge
  130. k = math.floor((x / (edge * edge)))
  131. ss.SetCenter(i + 0.5,j + 0.5,k + 0.5)
  132. ss.Update()
  133. pd = vtkPolyData()
  134. pd.ShallowCopy(ss.GetOutput())
  135. # pd.GetPointData().RemoveArray('Normals')
  136. ap.AddInputData(pd)
  137. ap.Update()
  138. self.GetOutput().ShallowCopy(ap.GetOutput())
  139. ''')
  140. paramprop = gen.GetProperty('Parameters')
  141. paramprop.SetElement(0, 'num_spheres_in_scene')
  142. paramprop.SetElement(1, str(num_spheres_in_scene))
  143. paramprop.SetElement(2, 'num_spheres')
  144. paramprop.SetElement(3, str(num_spheres))
  145. paramprop.SetElement(4, 'res')
  146. paramprop.SetElement(5, str(resolution))
  147. gen.UpdateProperty('Parameters')
  148. print('Assigning colors')
  149. pidScale = ProcessIdScalars()
  150. pidScaleDisplay = Show()
  151. pidScaleDisplay.SetRepresentationType('Surface')
  152. if transparency:
  153. print('Enabling 50% transparency')
  154. pidScaleDisplay.Opacity = 0.5
  155. print('Repositioning initial camera')
  156. c = GetActiveCamera()
  157. c.Azimuth(22.5)
  158. c.Elevation(22.5)
  159. print('Rendering first frame')
  160. Render()
  161. print('Saving frame 0 screenshot')
  162. fdigits = int(math.ceil(math.log(num_frames, 10)))
  163. frame_fname_fmt = output_basename + '.scene.f%(f)0' + str(fdigits) + 'd.png'
  164. SaveScreenshot(frame_fname_fmt % {'f': 0})
  165. print('Gathering geometry counts')
  166. vtkTimerLog.MarkStartEvent('GetViewItemStats')
  167. num_polys = 0
  168. num_points = 0
  169. for r in view.Representations:
  170. num_polys += r.GetRepresentedDataInformation().GetNumberOfCells()
  171. num_points += r.GetRepresentedDataInformation().GetNumberOfPoints()
  172. vtkTimerLog.MarkEndEvent('GetViewItemStats')
  173. print('Beginning benchmark loop')
  174. deltaAz = 45.0 / num_frames
  175. deltaEl = 45.0 / num_frames
  176. memtime_stamp()
  177. fpsT0 = dt.datetime.now()
  178. for frame in range(1, num_frames):
  179. c.Azimuth(deltaAz)
  180. c.Elevation(deltaEl)
  181. Render()
  182. flush_render_buffer()
  183. memtime_stamp()
  184. fpsT1 = dt.datetime.now()
  185. if controller.GetLocalProcessId() == 0:
  186. if save_logs:
  187. # Save the arguments this was executed with
  188. with open(output_basename + '.args.txt', 'w') as argfile:
  189. argfile.write(str({
  190. 'output_basename': output_basename,
  191. 'num_spheres': num_spheres,
  192. 'num_spheres_in_scene': num_spheres_in_scene,
  193. 'resolution': resolution, 'view_size': view_size,
  194. 'num_frames': num_frames, 'save_logs': save_logs,
  195. 'transparency': transparency, 'ospray': ospray}))
  196. # Save the memory statistics collected
  197. with open(output_basename + '.mem.txt', 'w') as ofile:
  198. ofile.write('\n'.join([str(x) for x in records]))
  199. # Process frame timing statistics
  200. logparser.summarize_results(num_frames, (fpsT1-fpsT0).total_seconds(),
  201. num_polys, 'Polys', save_logs,
  202. output_basename)
  203. print('Points / Frame: %d' % (num_points))
  204. def main(argv):
  205. import argparse
  206. parser = argparse.ArgumentParser(
  207. description='Benchmark ParaView geometry rendering')
  208. parser.add_argument('-o', '--output-basename', default='log', type=str,
  209. help='Basename to use for generated output files')
  210. parser.add_argument('-s', '--spheres', default=100, type=int,
  211. help='The total number of spheres to render')
  212. parser.add_argument('-n', '--spheres-in-scene', type=int,
  213. help='The number of spheres in the entire scene, including those not rendered.')
  214. parser.add_argument('-r', '--resolution', default=4, type=int,
  215. help='Theta and Phi resolution to use for the spheres')
  216. parser.add_argument('-v', '--view-size', default=[400, 400],
  217. type=lambda s: [int(x) for x in s.split(',')],
  218. help='View size used to render')
  219. parser.add_argument('-f', '--frames', default=10, type=int,
  220. help='Number of frames')
  221. parser.add_argument('-t', '--transparency', action='store_true',
  222. help='Enable transparency')
  223. parser.add_argument('-y', '--ospray', action='store_true',
  224. help='Use OSPRAY to render')
  225. args = parser.parse_args(argv)
  226. options = servermanager.vtkRemotingCoreConfiguration.GetInstance()
  227. url = options.GetServerURL()
  228. if url:
  229. import re
  230. m = re.match('([^:/]*://)?([^:]*)(:([0-9]+))?', url)
  231. if m.group(4):
  232. Connect(m.group(2), m.group(4))
  233. else:
  234. Connect(m.group(2))
  235. run(output_basename=args.output_basename, num_spheres=args.spheres,
  236. num_spheres_in_scene=args.spheres_in_scene, resolution=args.resolution,
  237. view_size=args.view_size, num_frames=args.frames,
  238. transparency=args.transparency, ospray=args.ospray)
  239. if __name__ == "__main__":
  240. import sys
  241. main(sys.argv[1:])