CrystFEL でパネル座標から検出器座標へ (.geom ファイルとその周辺)

CrystFEL では、検出器を定義するのに .geom ファイルを使っている。LCLS の検出器は小さなパネルをたくさん並べた構造になっており(たとえば https://confluence.slac.stanford.edu/display/PCDS/Pds+csPad を参照)、その配置は自明ではないからだ。

このファイルは、リゾチームのチュートリアルから引用すると、

q0a0/min_fs = 0
q0a0/min_ss = 0
q0a0/max_fs = 193
q0a0/max_ss = 184
q0a0/fs = -0.005723x +0.999984y
q0a0/ss = -0.999984x -0.005723y
q0a0/corner_x = 424.923
q0a0/corner_y = -10.2352

のようなブロックの繰り返しになっている。

パネル1つ1つは別々の検出器として動作するので、生のデータとしては CXIDB で Data Files として配布されている .cxi ファイルのように、HDF ファイルの中で別々のブロックに保存される。これを1つの大きなイメージに並べたのが、CrystFEL format として配布されている h5 ファイルだ。.geom ファイルは、後者の「統合後イメージ」と検出器上のパネル配置の対応を記述している。

fs と ss は、fast scan と slow scan を表す。配列の内側のループが fast scan だ。

min_fs, min_ss, max_fs, max_ss は、パネル結合後のデータファイルのどの部分にそのパネルに由来するデータが置いてあるかを表している。この geometry だと、q0a0 は(0, 0)-(193, 184), q0a1 は(194, 0)-(387, 184), q1a0 は(388, 0)-(581, 184) ... というように、左上から右に向かって配置されており、q3a1 が(1358, 0)-(1551, 184) が右上で、q0a2 (0, 193)-(185, 369) で「改行」して次の段の左端に戻るという具合。これはあくまで、各パネルに由来するピクセルを統合後イメージの中でどこに配置したかという便宜的なものであって、実際の検出器でのパネルの物理的配列とは何の関係もない。

各パネルが実際の検出器上でどこに置いてあるかを表すのが、fs, ss, corner_x, corner_y の4つのパラメータだ。(corner_x, corner_y) は、パネルの原点のピクセルが検出器座標系でどこに位置するかを表している。パネル上のピクセル座標 (x, y) は、検出器座標で (corner_x + fs, corner_y + ss) に対応する。この q0a0 パネルでは、fs はほぼ y, ss はほぼ -x なので、90度回転して縦に取り付けられているようだ。完全に 0 とか 1 にならないのは、パネルがわずかに回転しているからである。以前、CrystFEL tutorial をやってみた(未完) - biochem_fan's note

アセンブルといっても検出器の繋ぎ目(gap)を含めてしまうとデータサイズが無駄になるので、とりあえず全部詰めて並べてあって、それを geometry file の情報で修正するということかな

と書いたが、繋ぎ目のムダもさることながら、アセンブリ後の画像は微妙な回転のせいで pixel-by-pixel になっておらず、うまく保存できないのである(今回は全てのパネルがほぼ直交しているのでアセンブリ後でも誤差はわずかだと思われるが、例えばパネルが45度など傾いている場合はこうするしかない)。

なお、PILATUS 6M などのピクセルアレイ検出器も複数のパネルからできている。内部的にはこのような補正が行われているはずであるが、ユーザが受け取るのは、1枚に再構成した画像だけである。

CrystFEL の hdfsee の実装上は、描画ライブラリ Cairo に fs や ss などを affine 変換行列としてそのまま設定している。Cairo は画像の表示にハードウェア・アクセラレーションを使う(こともある)ので、自前で座標変換するよりも効率的である。