Houdini 18.5 PDG/TOPsを使ってタスクを実行する方法

パーティショナー系ノードコールバック

パーティショナー系ノードは複数の上流ワークアイテムを単一パーティションにグループ化します。

On this page

概要

パーティショナー系ノードは、PDGグラフが複数の上流ワークアイテムをグループ化する際に使用する仕組みです。 このノードで生成されたワークアイテムのグループのことを パーティション と呼びます。 このパーティション自体がそのパーティション内のワークアイテムに直接依存する特別なタイプのワークアイテムになっています。 パーティションは、その中のワークアイテムからアトリビュートも出力ファイルリストも継承します。 各パーティショナー系ノードのAdvancedタブには、上流アトリビュートをパーティションにコピーする方法を制御するためのパラメータがあります。

PDGには、アトリビュート値、インデックス、フレーム、ノードトポロジーなどのプロパティでワークアイテムをグループ化するために使用可能なビルトインのパーティショナー系ノードがたくさん含まれています。 Partition by Expressionノードや Python Partitionerノードを使用することで、同梱されているノードでは制御できないような場合のために独自のパーティションロジックを組むことができます。 他にも、スタンドアローンのPythonスクリプトとして独自のパーティショナー系ノードを組むこともできます。

プロセッサ系ノードと同様に、パーティショナーは静的または動的のどちらにも対応しています。 静的パーティショナーは、静的クックプリパス時にグループ化ロジックを実行します。 静的パーティショナーの入力は、すべての入力コネクションからのすべての静的ワークアイテムのリストになります。 静的パーティショナーに動的な入力ノードが含まれていても、そのノードがスキップされ、静的ワークアイテムのノードが見つかるまで上流を走査します。 動的パーティショナーは、すべての入力ノードがワークアイテムを生成した後でグループ化ロジックを評価します。 したがって、動的パーティショナーは、2レベル上のすべてのノードがクックされるまで待機した後で入力ワークアイテムをパーティション化しなければならないことになります。

独自のプロセッサ系ノードの登録で使用するものと同じPythonメソッドを使って、独自のパーティショナーノードを登録することができます。

アトリビュートによる分割

パーティショナーが入力ワークアイテムに対してonPartitionコールバックを実行する前に、PDGには、アトリビュート値に基づいてそれらのワークアイテムを分割するかどうかのオプションがあります。 パーティショナーに対して Split by Attribute パラメータが 有効 な時、PDGは、分割アトリビュートの固有な値毎に1回だけonPartitionメソッドをコールします。 このメソッドは、特定のアトリビュート値を持った入力ワークアイテムのリストを使ってコールされます。 PDGは、分割アトリビュートの値が異なるワークアイテムが同じパーティションに入らないように、これらのコールで生成されたパーティションが別個のインデックスを持つことを保証します。

その分割アトリビュートが見つからないワークアイテムは、どのパーティションにも追加しないようにしたり、または、すべてのパーティションに追加するようにすることができます。 この機能は、デフォルトでどのノードでも利用可能で、ノード作成者による余計な作業は不要です。 Python Partitionerまたはカスタムノードの Missing Attribute パラメータに対して適切なオプションを選択することで、あなた自身のコード内でそのアトリビュートが見つからなかった場合の処理を制御することもできます。 ワークアイテムを分割するための基本となるAPI関数は、Pythonからでも利用可能です。

アトリビュート分割オプションを 有効 にすると、onPartitionコールバックに渡されたpdg.PartitionHolder上でいくつかの追加プロパティを利用することができます。 例えば、ホルダーは分割アトリビュートの名前と現行値を用意することができます。 詳細は、そのクラスのAPIドキュメントを参照してください。

パーティショナーノードは、入力ワークアイテムのリストを1度ループして、アトリビュートで分割する際、または、そのアトリビュートが見つからないワークアイテムを検知する際に使用されるデータ構造を構築します。 これは、複数のTOPノードを使って同じ挙動を実装するよりも非常に効率的です。 しかも、固有な値の数がワークアイテムの総数よりも少ない場合は、このアトリビュート分割の機能がもっと上手く実行されます。 固有な値毎に別々にonPartitionコールバックが呼び出されるので、そのコールバック内で膨大な数のワークを処理するほどパフォーマンスコストが良くなります。 例えば、100,000個のワークアイテムと80,000個の固有なアトリビュート値があったと仮定すると、Partition Partitionerノードを使用して独自のロジックを記述するよりもパフォーマンスが良いです。

パーティション系アトリビュート

現在のところ、パーティショナー系ノードは、カスタムアトリビュートをパーティション上に追加することが できません 。 パーティションは、ノードの Advanced タブにあるパラメータに基づいて、そのパーティション内のワークアイテムからアトリビュートと出力ファイルを継承します。 Merge Input Attributes パラメータを 無効 にした場合、パーティションは何もアトリビュートを 継承しなくなります 。 しかし、そのパーティション内のワークアイテムからすべての出力ファイルはそのパーティション自身の出力リストにコピーされます。 このパラメータを 有効 にした場合、そのパーティション内のワークアイテムからアトリビュートがそのパーティションのアトリビュートにマージされます。 各パーティショナー系ノード(例えば、Python Partitioner)のドキュメントには、各パラメータの用途に関する詳細が載っています。

マージは、まず最初にパーティショナー系ノードのソート関連のパラメータに基づいてワークアイテムをソートすることから始まります。 次に、PDGは、そのソートされたワークアイテムをループさせて、各ワークアイテムからアトリビュート値をそのパーティションにコピーします。 そのパーティション上に既にそのアトリビュートが存在した場合は、そのアトリビュートは無視されます。 例えば、すべてのワークアイテムに同じアトリビュート名セットがあった場合、ソートされたリスト内の1番目のワークアイテムのアトリビュート値のみがそのパーティションにコピーされます。 ソートされたリスト内の2番目のワークアイテムのアトリビュートが1番目のワークアイテムになかった場合、そのアトリビュートもパーティションにコピーされます。 このマージ工程におけるソート順は、そのパーティション上の出力ファイルの順番も決めます。

ノードコールバック

パーティショナー系ノードには、上流ワークアイテムのリストを入力として受け取るコールバック関数の1つしかありません。 このコールバック関数では、パーティションオペレーションのステータスを示したpdg.result値を返す必要があります。

onPartition(self, partition_holder, work_items)pdg.result

このコールバックは、PDGグラフのクック中にパーティショナー毎に1回評価、または、( Split by Attribute有効 な場合)固有のアトリビュート値毎に1回評価されます。 パーティショナーが静的だった場合、このコールバックは静的プリパス時に実行されます。 動的だった場合、すべての入力ワークアイテムが生成された後にクック時に評価されます。 この関数のwork_items引数には、パーティションの対象となる上流ワークアイテムのリストを渡します。 partition_holder引数には、パーティションの作成で使用されるpdg.PartitionHolderクラスのインスタンスを渡します。

各パーティションは、onPartition関数から提供された固有の数値を使って定義されます。 ワークアイテムは、addItemToPartition関数にそのワークアイテム自身とパーティション番号を引数に渡すことでパーティションに追加されます:

# 各ワークアイテムを固有のパーティションに追加します。
partition_holder.addItemToPartition(work_items[0], 0)
partition_holder.addItemToPartition(work_items[1], 1)

# 両方のワークアイテムを3番目の共通パーティションに追加します。
partition_holder.addItemToPartition(work_items[0], 2)
partition_holder.addItemToPartition(work_items[1], 2)

ワークアイテムを複数のパーティションに追加したり、どのパーティションにも追加しないようにすることもできます。 場合によっては、作成されるパーティションの数がわかる前に、ワークアイテムをすべてのパーティションに追加したい事があります。 addItemToAllPartitionsメソッドは、そのワークアイテムがすべてのパーティション(そのコールの後で追加されたパーティションも含む)に属することをマークします。

他にも、ワークアイテムをそのパーティションで requirement(必須) としてマークすることもできます。 必須としてマークされたワークアイテムが削除されると、パーティション内にまだ他のワークアイテムが存在していても、そのパーティションもまるごと削除されます。 例えば、上流ワークアイテムのペアからパーティションを作成するPartition by Combinationがこの挙動に該当します。 ペアのどちらかのワークアイテムが削除されると、もはやペアではなくなるので、そのパーティションが無効になります。 以下のコードは、入力ワークアイテムの固有のペア毎にパーティションを形成するonPartition関数の実装例です:

partition_index=0

# ワークアイテムの外側ループ
for index1, item1 in enumerate(work_items):

    # ワークアイテムの内側ループ
    for index2, item2 in enumerate(work_items):

        # 順番はどうであれ、ワークアイテムのペア毎に1つだけパーティションを作成したいとします。
        # 以下のチェックがなかった場合、(a,b)と(b,a)の両方に対してパーティションが作成されてしまいます。
        if index2 <= index1:
            continue

        # 次で利用可能なパーティションに両方のワークアイテムを追加し、それらのワークアイテムをrequired(必須)としてフラグを立てます。
        partition_holder.addItemToPartition(item1, partition_index, True)
        partition_holder.addItemToPartition(item2, partition_index, True)

        partition_index += 1

PDG/TOPsを使ってタスクを実行する方法

基本

初心者向けチュートリアル

次のステップ

リファレンス