Claude Media
Claude CodeでIFCの属性の抜けを点検する — ifcopenshellでプロパティセットを一覧に

Claude CodeでIFCの属性の抜けを点検する — ifcopenshellでプロパティセットを一覧に

IFCモデルの要素ごとのプロパティセットをifcopenshellで取り出し、要求する属性の未入力を表にするスクリプトをClaude Codeに書かせます。セットなし、未入力、空文字を分けて数える手順です。

IFCモデルの属性の抜けは、ビューアで一つずつ要素を開いても見つかりません。数百の部材から未入力を探すには、要素ごとのプロパティセットを一覧にして、要求する項目と突き合わせるのが近道です。Pythonライブラリのifcopenshellなら、この一覧が数行で取れます。ここでは、点検用のスクリプトをClaude Codeに書かせ、未入力を表にする手順を示します。

例に使うIFCは、手順確認のために作った仮のデータです。実在の構造物のものではありません。

点検の対象を決める — 属性情報とは何か

最初に、何を「属性」と呼んで点検するかを決めます。国土交通省の「BIM/CIMモデル等電子納品要領(案)及び同解説」(令和4年3月)は、属性情報を次のように定義しています。3次元モデルに付与する部材の情報で、部材等の名称、形状、寸法、物性及び物性値(強度等)、数量、そのほか付与が可能な情報を指します。

同じ要領は、構造物モデルのデータ交換形式としてIFCを採用しています。納品の対象はIFC 2x3と、ソフトのオリジナルファイルです。つまり点検の相手は、IFCファイルに入った部材ごとのプロパティセットになります。

範囲

点検で扱う範囲

  • IFCに直接入った属性

    プロパティセットに入った名前と値です。ifcopenshellで読めるのはここです。

  • 外部参照ファイルの属性

    要領は、属性情報をCSVやXLSXなどの外部ファイルとして参照する場合を、当面の間は属性情報に含めるとしています。この記事のスクリプトは、そのファイルの中身までは読みません。

どの項目を必須とするかは、発注ごとの規定で決まります。要領は、詳細設計では「3次元モデル成果物作成要領(案)」の附属資料、それ以外の業務や工事では「BIM/CIM活用ガイドライン(案)」を参考にするとしています。以降の必須項目は、それらを写したものではなく、手順を示すための仮の定義です。

ifcopenshellでプロパティセットを取り出す

手元ではバージョン0.9.0.post1が入りました。

python3 -m venv .venv
.venv/bin/pip install ifcopenshell

プロパティセットを読む関数はifcopenshell.util.element.get_psetsです。要素を渡すと、セット名をキー、プロパティ名と値の辞書を値にした辞書が返ります。psets_only=Trueでプロパティセットだけ、qtos_only=Trueで数量セットだけになります。should_inheritは既定でTrueで、型(IfcWallTypeなど)に付いたセットも継承して返します。

セット名と項目名が決まっているなら、get_pset(element, "セット名", "項目名")で一点だけ読めます。ただし点検は「あるはずの項目が無い」を探す作業です。一点指定でNoneが返ると、セットが無いのか、項目が無いのか、値が空なのかが区別できません。だから点検ではget_psetsで全体を取り、自分で場合分けします。

手元のIFCで確かめた戻り値の癖

デモ用に、壁3枚、床版1枚、柱1本のIFC4ファイルを作りました。IFC2X3で作ろうとすると、root.create_entityが所有者の作成を求めて止まったため、デモはIFC4にしています。要領が扱うのはIFC 2x3なので、実際のファイルでは同じ呼び出しで読めるかを先に確かめてください。

壁のうち1枚には、設計基準強度にNoneを入れました。もう1枚は材質を空文字にしています。床版にはプロパティセットを付けていません。get_psets(e, psets_only=True)の結果は次のとおりでした。

IfcColumn C1柱 {'JP_部材': {'材質': 'S', 'id': 24}}
IfcSlab   S1床版 {}
IfcWall   P1壁 {'JP_部材': {'材質': 'RC', '設計基準強度': 24.0, 'id': 10}}
IfcWall   P2壁 {'JP_部材': {'材質': 'RC', 'id': 15}}
IfcWall   P3壁 {'JP_部材': {'材質': '', 'id': 19}}

ここから読み取れる癖が三つあります。

  • 値をNoneで入れた項目(P2壁の設計基準強度)は、辞書にキーごと現れない
  • 空文字の項目(P3壁の材質)は、キーが残り値が空文字で返る
  • 辞書にはidというキーが混ざる。プロパティ名の一覧として数えてはいけない

プロパティセットが無い要素(S1床版)は、Noneではなく空の辞書です。三つの状態は、セットが無い、キーが無い、値が空、と別々に判定できます。点検の表では、この三つを別の理由として出します。

型から継承された値で穴が埋まる

should_inheritが既定でTrueなので、型に入った値は要素の側から読んでも見えます。P2壁に壁タイプを割り当て、型のほうに設計基準強度30.0を入れて試しました。

継承あり: {'JP_部材': {'設計基準強度': 30.0, 'id': 15, '材質': 'RC'}}
継承なし: {'JP_部材': {'材質': 'RC', 'id': 15}}

継承ありでは、要素に未入力だった設計基準強度が型の値で埋まって見えます。ビューアが型の値を表示するソフトなら、人の目にも同じ結果です。どちらを「入力済み」とみなすかは、点検の目的で決めます。要素ごとに値を持たせたい運用ならshould_inherit=Falseで読みます。型の値で足りる運用なら、既定のままにします。決めた方針は、後で述べるCLAUDE.mdに書いておきます。

要求する属性を表にして渡す

必須項目は、コードに埋め込まずJSONに分けます。キーはIFCのクラス名、値はプロパティセット名と必須項目の一覧です。

{
  "IfcWall":   {"JP_部材": ["材質", "設計基準強度"]},
  "IfcColumn": {"JP_部材": ["材質", "設計基準強度"]},
  "IfcSlab":   {"JP_部材": ["材質", "設計基準強度"]}
}

セット名のJP_部材は、デモのために作った名前です。実際の案件では、発注側が指定したセット名と項目名に差し替えます。標準のセット名を調べたいときは、ifcopenshell.util.psetのPsetQto.get_applicable_namesが、クラス名を渡すと適用できるセット名の一覧を返します。

点検スクリプトと出力

Claude Codeに書かせたスクリプトの一例を示します。JSONの条件に沿って全要素を走査し、足りない項目をCSVで出します。

import csv
import json
import sys
 
import ifcopenshell
import ifcopenshell.util.element as el
 
model = ifcopenshell.open(sys.argv[1])
required = json.load(open(sys.argv[2], encoding="utf-8"))
 
rows = []
for cls, psets_req in required.items():
    for e in model.by_type(cls):
        psets = el.get_psets(e, psets_only=True)
        for pset, props in psets_req.items():
            have = psets.get(pset)
            for prop in props:
                if have is None:
                    why = "セットなし"
                elif prop not in have:
                    why = "未入力"        # None は取り出し時に落ちる
                elif have[prop] in ("", None):
                    why = "空文字"
                else:
                    continue
                rows.append((e.is_a(), e.GlobalId, e.Name, pset, prop, why))
 
w = csv.writer(sys.stdout, lineterminator="\n")
w.writerow(["class", "guid", "name", "pset", "property", "status"])
w.writerows(rows)
sys.exit(1 if rows else 0)

デモのIFCで実行すると、次の表が出ました。GUIDは<GUID>に置き換えています。

.venv/bin/python attrcheck.py demo.ifc required.json
class,guid,name,pset,property,status
IfcWall,<GUID>,P2壁,JP_部材,設計基準強度,未入力
IfcWall,<GUID>,P3壁,JP_部材,材質,空文字
IfcWall,<GUID>,P3壁,JP_部材,設計基準強度,未入力
IfcColumn,<GUID>,C1柱,JP_部材,設計基準強度,未入力
IfcSlab,<GUID>,S1床版,JP_部材,材質,セットなし
IfcSlab,<GUID>,S1床版,JP_部材,設計基準強度,セットなし

終了コードは、抜けがあれば1、無ければ0です。CIや、Claude Codeの検証コマンドとして使うときに効きます。

表の読み方にも順序があります。「セットなし」は要素ごと属性付与の工程が漏れた可能性が高く、元のモデルに戻って確認する単位です。「未入力」と「空文字」は、セットはあるのに項目が欠けている状態で、入力ミスや書き出し設定の漏れを疑います。理由列があれば、修正の依頼先を振り分けられます。

Claude Codeに点検をやり切らせる

スクリプト自体は短いので、価値が出るのは依頼文と前提の置き方です。依頼文では、結果の形を先に決めておきます。

  • 出力はCSVで、列はクラス、GUID、名前、セット名、項目名、理由
  • 理由は「セットなし」「未入力」「空文字」の三つに分ける
  • get_psetsの辞書のidキーは項目として数えない
  • 抜けがあれば終了コード1にする

この依頼のあと、Claude Codeに自分でデモ用のIFCを作らせ、実行して出力を読ませます。出力の理由列が想定と違えば、スクリプトを直して再実行させる流れです。実際のモデルで初めて走らせる前に、抜けを仕込んだ小さなIFCで期待どおりの表が出るかを確かめられます。

CLAUDE.mdには、毎回の依頼に書きたくない前提を残します。

- 属性の点検は ifcopenshell.util.element.get_psets(psets_only=True) で取る
- get_psets の辞書の id キーは項目として数えない
- 値が None の項目は辞書に現れない。「未入力」として報告する
- 型から継承された値は入力済みとして扱う(should_inherit は既定のまま)
- 必須項目の定義は required.json にあり、スクリプトに直書きしない

最後の行が特に効きます。必須項目の変更が、スクリプトの修正ではなくJSONの編集で済むからです。発注ごとに条件が変わる運用でも、点検のコードは使い回せます。

クラスと理由で件数を集計する

行が数百を超えると、CSVを上から読むだけでは傾向がつかめません。クラスと理由の組で件数を数えると、抜けがどこに偏っているかが見えます。出力のCSVを読み込んでcollections.Counterで数える、数行の追加で足ります。

import collections
import csv
 
rows = list(csv.DictReader(open("out.csv", encoding="utf-8")))
count = collections.Counter((r["class"], r["status"]) for r in rows)
for key, n in sorted(count.items()):
    print(key, n)

デモのCSVでは、次の件数になりました。

('IfcColumn', '未入力') 1
('IfcSlab', 'セットなし') 2
('IfcWall', '未入力') 2
('IfcWall', '空文字') 1

床版の2件は、どちらも「セットなし」です。項目ごとの入力漏れではなく、床版にセットそのものを付けていない可能性が高いと分かります。壁の3件は項目単位の漏れなので、直す作業の種類が違います。集計を挟むと、修正を「セットを付ける」と「項目を埋める」に分けて依頼できます。件数の多い組から順に手を付ければ、少ない修正回数で抜けの総数を減らせます。

CSVにGUIDを入れてあるのは、修正の依頼先に要素を特定して渡すためです。名前は重複することがあるので、依頼にはGUIDを添えます。修正後のモデルが戻ってきたら同じコマンドを再実行し、表の行数が減ったか、新しい行が増えていないかを比べます。

この点検で分からないこと

この点検が見るのは、項目の存在と値が空でないことだけです。値の正しさは見ません。設計基準強度に24と入っていても、その値が設計と合っているかは別の確認です。要領のモデル確認の項目にも、付与した属性情報の内容が正しいかを確認することが挙がっています。点検の結果が空でも、その確認の代わりにはなりません。

要素のクラスにも注意が要ります。要領は、橋梁、トンネル等の土木構造物としてのクラス定義を含むデータ交換は当面行えないとしています。書き出し元のソフトによっては、部材がIfcWallやIfcSlabではなく汎用のIfcBuildingElementProxyで出ることがありえます。必須項目をクラス名で引く設計だと、そうした要素が走査から漏れます。実際のファイルでは、model.by_type("IfcBuildingElement")で全体を数え、JSONに書いたクラスの合計と合うかを先に比べておくと、漏れに気づけます。

面積の検算は別の話です。IfcSpaceの数量セットと単位の扱いは、Claude Codeでifcopenshellから部屋面積を検算する手順にまとめています。必須項目の欠落を表にして洗い出す考え方は、書誌情報を点検するONIXの必須項目の点検とも共通しています。

まとめ

IFCの属性の点検は、取り出しより場合分けで価値が出ます。値をNoneで持つ項目はキーごと消え、空文字はキーが残り、セットが無い要素は空の辞書になります。この三つを別の理由として表に出せば、修正の依頼先が決まります。継承の扱いと必須項目の置き場所をCLAUDE.mdに書いておけば、次の案件でも同じ点検をそのまま回せます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. docs.ifcopenshell.org/autoapi/ifcopenshell/util/element/index.html
  2. docs.ifcopenshell.org/autoapi/ifcopenshell/util/pset/index.html
  3. mlit.go.jp/tec/content/001472866.pdf
この記事を共有:XはてブLinkedIn