Programmable Filter

2015年12月17日

はじめに

Programmable Filter の使い方について。

使用バージョン

ParaView 4.4.0

Programmable Filter とは

Programmable Filter は、Python でフィルターを作ることができるものである。

簡単な例

たとえば、"temperature" というケルビン単位の温度データがあったとして、それを摂氏に変換するフィルターを作るとしたら、次のようになる。

input = inputs[0]
data = input.PointData['temperature'] - 273.15
output.PointData.append(data, 'temperature_degC')

この書き方は、既存のデータに値を足したり掛けたりするときに使うことができるが、その場合は Calculator のほうが簡単に済むだろう。

※そもそもこの方法が使えない場合がある。理由は知らない。

複雑な例

複雑な例、たとえば、あるデータの値に対して場合分けをして新たなデータを生成したりするような、式だけでは表現できないような例では、上記の方法では難しい。

入力のコピー

複雑な例を実現する方法を示す前に、まず、入力を出力にコピーするだけの方法を以下に示す。

input = self.GetInputDataObject(0, 0)
output = self.GetOutputDataObject(0)
output.ShallowCopy(input)

入力と同じデータを見ることができたら OK。

ブロックごとのコピー

Multi-Block データセットの場合、データはブロックに分かれている (データセットの種類は "Information" タブで確認できる)。ブロックを巡回してコピーする場合は、次のように書ける。

input = self.GetInputDataObject(0, 0)
output = self.GetOutputDataObject(0)

numBlocks = input.GetNumberOfBlocks()

for i in range(numBlocks):
    block = input.GetBlock(i)
    newBlock = block.NewInstance()
    newBlock.CopyStructure(block)
    output.SetBlock(i, newBlock)

    newBlock.ShallowCopy(block)

イテレータを用いると、同じ処理を次のようにも書ける。

input = self.GetInputDataObject(0, 0)
output = self.GetOutputDataObject(0)

output.CopyStructure(input)

iter = input.NewIterator()
iter.UnRegister(None)
iter.InitTraversal()

while not iter.IsDoneWithTraversal():
    curInput = iter.GetCurrentDataObject()
    curOutput = curInput.NewInstance()
    curOutput.UnRegister(None)
    output.SetDataSet(iter, curOutput)

    curOutput.ShallowCopy(curInput)

    iter.GoToNextItem()
 

温度変換の例

上記の方法を用いると、温度変換は次のようになる。

input = self.GetInputDataObject(0, 0)
output = self.GetOutputDataObject(0)

output.CopyStructure(input)

numBlocks = input.GetNumberOfBlocks()

for i in range(numBlocks):
    block = input.GetBlock(i)
    newBlock = block.NewInstance()
    newBlock.CopyStructure(block)
    output.SetBlock(i, newBlock)

    newBlock.ShallowCopy(block)

    data = block.GetPointData().GetArray('temperature')
    numTuples = data.GetNumberOfTuples()

    newData = vtk.vtkFloatArray()
    newData.SetNumberOfTuples(numTuples)
    newData.SetName('temperature_degC')

    for j in range(numTuples):
        newData.SetValue(j, data.GetValue(j) - 273.15)

    newBlock.GetPointData().AddArray(newData)

ブロックのコピーの後に、温度変換データを作成してブロックに追加している。

イテレータ版は次の通りである。

input = self.GetInputDataObject(0, 0)
output = self.GetOutputDataObject(0)

output.CopyStructure(input)

iter = input.NewIterator()
iter.UnRegister(None)
iter.InitTraversal()

while not iter.IsDoneWithTraversal():
    curInput = iter.GetCurrentDataObject()
    curOutput = curInput.NewInstance()
    curOutput.UnRegister(None)
    output.SetDataSet(iter, curOutput)

    curOutput.ShallowCopy(curInput)

    data = curInput.GetPointData().GetArray('temperature')
    numTuples = data.GetNumberOfTuples()

    newData = vtk.vtkFloatArray()
    newData.SetNumberOfTuples(numTuples)
    newData.SetName('temperature_degC')

    for i in range(numTuples):
        newData.SetValue(i, data.GetValue(i) - 273.15)

    curOutput.GetPointData().AddArray(newData)

    iter.GoToNextItem()

Multi-Block とそうでないものと両方のデータに対応するには、次のように書けばよいらしい。

def calc(input, output):
    output.ShallowCopy(input)

    data = input.GetPointData().GetArray('temperature')
    numTuples = data.GetNumberOfTuples()

    newData = vtk.vtkFloatArray()
    newData.SetNumberOfTuples(numTuples)
    newData.SetName('temperature_degC')

    for i in range(numTuples):
        newData.SetValue(i, data.GetValue(i) - 273.15)

    output.GetPointData().AddArray(newData)


input = self.GetInputDataObject(0, 0)
output = self.GetOutputDataObject(0)

if input.IsA('vtkMultiBlockDataSet'):
    output.CopyStructure(input)

    iter = input.NewIterator()
    iter.UnRegister(None)
    iter.InitTraversal()

    while not iter.IsDoneWithTraversal():
        curInput = iter.GetCurrentDataObject()
        curOutput = curInput.NewInstance()
        curOutput.UnRegister(None)
        output.SetDataSet(iter, curOutput)

        calc(curInput, curOutput)

        iter.GoToNextItem()
else:
    calc(input, output)

参考