r"""This module is used to export catalyst defined data products directly
within the ParaView GUI."""
from paraview.simple import *
haveCinemaC = True
try:
import paraview.tpl.cinema_python.adaptors.paraview.pv_introspect as pvi
except:
haveCinemaC = False
import os
[docs]class CinemaDHelper(object):
""" A helper that we funnel file save commands through so that we can build up a CinemaD table for them. """
def __init__(self, mcd, rd):
self.__EnableCinemaDTable = mcd
self.__RootDirectory = rd
if rd and not rd.endswith("/"):
self.__RootDirectory = rd + "/"
self.Keys = set()
self.Contents = []
self.KeysWritten = None
def __StripRootDir(self, filename):
if self.__RootDirectory:
return filename[filename.startswith(self.__RootDirectory) and len(self.__RootDirectory):]
return filename
def __MakeCinDFileNamesUnderRootDir(self, filename=""):
""" filename wrangling for root directory placement """
indexfilename = 'data.csv'
datafilename = filename
if self.__RootDirectory:
indexfilename = self.__RootDirectory + "data.csv"
# strip leading root directory from filename if present
datafilename = self.__StripRootDir(filename)
return indexfilename, datafilename
[docs] def AppendToCinemaDTable(self, time, producer, filename):
""" keep a record of every standard file written out so that we can list it later """
if not self.__EnableCinemaDTable:
return
indexfilename, datafilename = self.__MakeCinDFileNamesUnderRootDir(filename)
self.Keys.add("timestep")
self.Keys.add("producer")
self.Keys.add("FILE")
self.Contents.append({'timestep': time, 'producer': producer, 'FILE': datafilename})
[docs] def AppendCViewToCinemaDTable(self, time, producer, filelist):
""" keep a record of every new file that cinema image writes along with the keys that produced them so that we can list them all later """
if not self.__EnableCinemaDTable or not haveCinemaC:
return
self.Keys.add("timestep")
self.Keys.add("producer")
self.Keys.add("FILE")
# unroll the contents into key lists and filenames
for viewname in filelist:
for entry in filelist[viewname]:
keylist = entry[0]
# avoid redundancy from name change
if 'time' in keylist:
time = keylist['time']
del keylist['time']
for k in keylist:
self.Keys.add(k)
keylist['timestep'] = time
keylist['producer'] = producer
keylist['FILE'] = self.__StripRootDir(entry[1])
self.Contents.append(keylist)
[docs] def Finalize(self):
""" Finish off the table and write it to a file """
# this is necessary because we don't really know keys (from cinema image) until the end.
if not self.__EnableCinemaDTable:
return
indexfilename, datafilename = self.__MakeCinDFileNamesUnderRootDir()
if self.__RootDirectory and not os.path.exists(self.__RootDirectory):
os.makedirs(self.__RootDirectory)
f = open(indexfilename, "w")
# write the header line
f.write("timestep,")
f.write("producer,")
for k in self.Keys:
if k != 'timestep' and k != 'producer' and k != 'FILE':
f.write("%s," % k)
f.write("FILE\n")
# write all of the contents
for l in self.Contents:
f.write("%s," % l['timestep'])
f.write("%s," % l['producer'])
for k in self.Keys:
if k != 'timestep' and k != 'producer' and k != 'FILE':
v = ''
if k in l:
v = l[k]
f.write("%s," % v)
f.write("%s\n" % self.__StripRootDir(l['FILE']))
f.close()
[docs] def WriteNow(self):
""" For Catalyst, we don't generally have a Final state, so we call this every CoProcess call and fixup the table if we have to. """
if not self.__EnableCinemaDTable:
return
indexfilename, datafilename = self.__MakeCinDFileNamesUnderRootDir()
if self.KeysWritten == self.Keys:
# phew nothing new, we can just append a record
f = open(indexfilename, "a+")
for l in self.Contents:
f.write("%s," % l['timestep'])
f.write("%s," % l['producer'])
for k in self.Keys:
if k != 'timestep' and k != 'producer' and k != 'FILE':
v = ''
if k in l:
v = l[k]
f.write("%s," % v)
f.write("%s\n" % self.__StripRootDir(l['FILE']))
f.close()
self.Contents = []
return
# dang, whatever we wrote recently had a new variable
# we may have to extend and rewrite the old output file
readKeys = None
readContents = []
if os.path.exists(indexfilename):
# yep we have to do it
# parse the old file
f = open(indexfilename, "r")
for line in f:
read = line[0:-1].split(",") # -1 to skip trailing\n
if readKeys is None:
readKeys = read
else:
entry = {}
for idx in range(0, len(read)):
entry.update({readKeys[idx]: read[idx]})
readContents.append(entry)
# combine contents
if readKeys is not None:
self.Keys = self.Keys.union(readKeys)
readContents.extend(self.Contents)
self.Contents = readContents
# finally, write
self.Finalize()
self.KeysWritten = self.Keys.copy()
self.Contents = []
class __CinemaACHelper(object):
""" Another helper that connects up to cinema_python's export function. """
def __init__(self, rd, vsel, tsel, asel):
self.__RootDirectory = rd
self.__ViewSelection = vsel
self.__TrackSelection = tsel
self.__ArraySelection = asel
self.NewFiles = None
if haveCinemaC:
def ExportNow(self, time):
r = pvi.export_scene(baseDirName=self.__RootDirectory,
viewSelection=dict(self.__ViewSelection),
trackSelection=dict(self.__TrackSelection),
arraySelection=dict(self.__ArraySelection),
forcetime=time)
self.NewFiles = r
else:
def ExportNow(self, time):
pass
def _fixup_and_makedir_if_needed(rootdir):
if rootdir and not rootdir.endswith("/"):
rootdir = rootdir + "/"
if rootdir and not os.path.exists(rootdir):
os.makedirs(rootdir)
return rootdir
[docs]def ExportNow(image_root_directory,
data_root_directory,
file_name_padding,
make_cinema_table,
cinema_tracks,
cinema_arrays,
rendering_info):
"""The user facing entry point. Here we get a hold of ParaView's animation controls, step through the animation, and export the things we've been asked to be the caller."""
CIND = CinemaDHelper(make_cinema_table, image_root_directory)
image_root_directory = _fixup_and_makedir_if_needed(image_root_directory)
data_root_directory = _fixup_and_makedir_if_needed(data_root_directory)
# get a hold of the scene
spm = servermanager.vtkSMProxyManager.GetProxyManager().GetActiveSessionProxyManager()
ed = spm.GetExportDepot()
s = GetAnimationScene()
s.GoToFirst()
et = s.EndTime
tnow = s.AnimationTime
numTimesteps = len(paraview.simple.GetAnimationScene().TimeKeeper.TimestepValues)
timesteps = {}
# We must perform the export loop at least once, even in the case where
# the input data contains no timesteps
if (numTimesteps == 0):
timesteps = list(range(1))
else:
timesteps = list(range(numTimesteps))
# export loop
for tstep in timesteps:
padded_tstep = str(tstep).rjust(file_name_padding, '0')
helpers = []
# loop through the configured writers and export at the requested times
ed.InitNextWriterProxy()
wp = ed.GetNextWriterProxy()
writercnt = 0
while wp:
freq = wp.GetProperty("WriteFrequency").GetElement(0)
if ((tstep % freq == 0) and
(not (wp.GetXMLName() == "Cinema image options"))):
# this isn't pretty. I couldn't find a way to write
# directly with the writer proxy. So what I do here
# is find the input and filename and make a new writer
# to use.
proxyname = spm.GetProxyName("export_writers", wp)
inputname = proxyname[0:proxyname.find("|")]
inputproxy = FindSource(inputname)
if wp.GetProperty("ChooseArraysToWrite").GetElement(0) == 1:
point_arrays = []
cell_arrays = []
arrays_property = wp.GetProperty("PointDataArrays")
for i in range(arrays_property.GetNumberOfElements()):
point_arrays.append(arrays_property.GetElement(i))
arrays_property = wp.GetProperty("CellDataArrays")
for i in range(arrays_property.GetNumberOfElements()):
cell_arrays.append(arrays_property.GetElement(i))
if not point_arrays:
point_arrays = [' ']
if not cell_arrays:
cell_arrays = [' ']
# create a temporary array culling filter
pass_arrays = PassArrays(Input=inputproxy, \
PointDataArrays=point_arrays, CellDataArrays=cell_arrays)
inputproxy = pass_arrays
helpers.append(inputproxy)
fname = wp.GetProperty("CatalystFilePattern").GetElement(0)
if wp.GetXMLName() == "ExodusIIWriter":
fnamefilled = data_root_directory + fname + padded_tstep
else:
fnamefilled = data_root_directory + fname.replace("%t", padded_tstep)
kwargs = {}
DataMode = wp.GetProperty("DataMode")
if DataMode is not None:
kwargs["DataMode"] = wp.GetProperty("DataMode").GetElement(0)
HeaderType = wp.GetProperty("HeaderType")
if HeaderType is not None:
kwargs["HeaderType"] = wp.GetProperty("HeaderType").GetElement(0)
EncodeAppendedData = wp.GetProperty("EncodeAppendedData")
if EncodeAppendedData is not None:
kwargs["EncodeAppendedData"] = wp.GetProperty("EncodeAppendedData").GetElement(0)
CompressorType = wp.GetProperty("CompressorType")
if CompressorType is not None:
kwargs["CompressorType"] = wp.GetProperty("CompressorType").GetElement(0)
CompressionLevel = wp.GetProperty("CompressionLevel")
if CompressionLevel is not None:
kwargs["CompressionLevel"] = wp.GetProperty("CompressionLevel").GetElement(0)
# finally after all of the finageling above, save the data
SaveData(fnamefilled, inputproxy, **kwargs)
# don't forget to tell cinema D about it
CIND.AppendToCinemaDTable(tnow, "writer_%s" % writercnt, fnamefilled)
wp = ed.GetNextWriterProxy()
writercnt = writercnt + 1
# loop through the configured screenshots and export at the requested times
ed.InitNextScreenshotProxy()
ssp = ed.GetNextScreenshotProxy()
viewcnt = 0
while ssp:
if not ssp.HasAnnotation("enabled") or not (ssp.GetAnnotation("enabled") == '1'):
ssp = ed.GetNextScreenshotProxy()
continue
freq = ssp.GetProperty("WriteFrequency").GetElement(0)
if tstep % freq == 0:
fname = ssp.GetProperty("CatalystFilePattern").GetElement(0)
if fname.endswith("cdb"):
CINAC = __CinemaACHelper(image_root_directory,
rendering_info,
cinema_tracks,
cinema_arrays)
# special treatment for cinema image data bases
CINAC.ExportNow(tnow)
# don't forget to tell cinema D about it
CIND.AppendCViewToCinemaDTable(tnow, "cview_%s" % viewcnt, CINAC.NewFiles)
else:
fnamefilled = image_root_directory + fname.replace("%t", padded_tstep)
# save the screenshot
ssp.WriteImage(fnamefilled)
# don't forget to tell cinema D about it
CIND.AppendToCinemaDTable(tnow, "view_%s" % viewcnt, fnamefilled)
ssp = ed.GetNextScreenshotProxy()
viewcnt = viewcnt + 1
tstep = tstep + 1
s.GoToNext()
tnow = s.AnimationTime
# destroy array culling filters
for x in helpers:
Delete(x)
# defer actual cinema D output until the end because we only know now what the full set of cinema D columns actually are
CIND.Finalize()