11.3. ファイル読み込みプラグイン

11.3.1. Extending ATHENA to read new file types

bend ATHENA はデータの読み込みに,IFEFFITread_data() 関数,あるいは LARCHread_ascii() 関数を利用しています.これは,ATHENA が受け入れられるデータ形式は, IFEFFIT (あるいは,LARCH) と全く同じであるということです.すなわち,もちろんのことですが,IFEFFIT (あるいは,LARCH)が読み込める形式であれば,ATHENA も読み込めるということです.

実際に,これはとてもうまくいっています.IFEFFIT は世界の多くの XAS ビームラインで生成されるデータファイルを読み込むことができます.よって,また,ATHENA でも読み込むことができるということです.残念なことに,IFEFFITATHENA で読み込むことができない形式を使っているビームラインもたくさんあります.そういったビームラインのデータを扱うためには,2つの方法が考えられます.

  1. それらのデータを直接を扱うのを諦め,IFEFFIT が扱うことができる形式に変換する.

  2. 新しいデータ形式に気づく度に ATHENA にそのファイルが読めるようなコードを足していく

いずれもユーザーフレンドリーとは言えません.ATHENA はその代わりに,内部のコードを変更することなしに,新しいデータ形式を直接扱えるように拡張するためのプラグイン機構を持っています.

このページでは ATHENA のユーザが自分のファイル形式のためのプラグインを書くことができるようにプラグイン機構について説明します.

11.3.2. プラグイン動作の概観

簡単に言うと,perl モジュールとは特別な場所に置かれた特別な perl のコードを含む短いファイルのことです.ATHENA はそのファイルに含まれたコードを使って,データファイル形式を認識して,IFEFFIT で適切に読み込むことができるように前処理を行います.

もう少し技術的にいうと,プラグインとはあなたのコンピュータのパスの通っている場所に置かれた単なる perl モジュールです.このファイルは ATHENA が起動した際に読み込まれ,データ読み込みの際に利用できるようなります.

プラグインが有効化されていると,Open file 機能で ATHENA にファイルが読み込まれる度にプラグインの機能が呼び出されます.その際,プラグインの持つメソッドのうちの1つを使って,読み込もうとしているファイルがそのプラグインによって変換されるべきものなのか確認します.もし,そのファイルが変換対象であれば,プラグインにある他のメソッドが元のデータファイルを IFEFFIT が読むことができる形式に変換します.この変換は元のデータファイルに変更を加えることなく行われます.

変換がうまくいくと,ATHENA の列選択ダイアログが表示され,いつもと同じようにデータを読み込むことができます.うまく書かれたプラグインは,理想的にはデータを ATHENA に読み込むときにユーザからは全く見えないプロセスとなります.

11.3.3. プラグインの例

ここには,DEMETER に含まれ,うまく動作するプラグインの完全な例について説明します.ATHENA はこのプラグインを使って NSLS のビームライン X10C のファイルを読み込むことができます.ご覧のように,プラグインは非常に短いものです.このページの続きではこの例について詳しく説明します.

package Demeter::Plugins::X10C;

use Moose;
extends 'Demeter::Plugins::FileType';

has '+is_binary'    => (default => 0);
has '+description'  => (default => "NSLS beamline X10C");
has '+version'      => (default => 0.1);
has '+metadata_ini' => (default =>
                        File::Spec->catfile(File::Basename::dirname($INC{'Demeter.pm'}),
                                            'Demeter', 'share', 'xdi', 'x10c.ini'));

sub is {
  my ($self) = @_;
  open D, $self->file or $self->Croak("could not open " . $self->file . " as data (X10C)\n");
  my $first = <D>;
  close D, return 0 unless (uc($first) =~ /^EXAFS/);
  my $lines = 0;
  while (<D>) {
    close D, return 1 if (uc($first) =~ /^\s+DATA START/);
    ++$lines;
  };
  close D;
};


sub fix {
  my ($self) = @_;
  my $new = File::Spec->catfile($self->stash_folder, $self->filename);
  ($new = File::Spec->catfile($self->stash_folder, "toss")) if (length($new) > 127);
  open D, $self->file or die "could not open " , $self->file . " as data (fix in X10C)\n";
  open N, ">".$new or die "could not write to $new (fix in X10C)\n";
  my $header = 1;
  my $null = chr(0).'+';
  while (<D>) {
    $_ =~ s/$null//g;             # clean up nulls
    print N "# " . $_ if $header; # comment headers
    ($header = 0), next if (uc($_) =~ /^\s+DATA START/);
    next if ($header);
    $_ =~ s/([eE][-+]\d{1,2})-/$1 -/g; # clean up 5th column
    print N $_;
  };
  close N;
  close D;
  $self->fixed($new);
  return $new;
}

sub suggest {
  my ($self, $which) = @_;
  $which ||= 'transmission';
  if ($which eq 'transmission') {
    return (energy      => '$1',
            numerator   => '$4',
            denominator => '$6',
            ln          =>  1,);
  } else {
    return ();
  };
};


__PACKAGE__->meta->make_immutable;
1;

11.3.4. 名前空間

モジュールは特定の名前空間に含まれている必要があります.名前空間は例の1行目にパッケージ関数で定義されています.パッケージは Demeter::Plugins 名前空間の下にある必要があり,そのプラグインがどのような形式のために書かれたか記述されている名前であるべきです.例の場合,プラグインは NSLS のビームライン X10C のファイルを変換するように意図されているので,モジュールの全名前空間は Demeter::Plugins::X10C です.3, 4, 62, 63 行目は,DEMETERATHENA でこのモジュールがうまく動作するようにするための必須の決まり文句です.

11.3.5. 必須のメソッドと変数

プラグインでは3つのメソッドとプラグインオブジェクトのいくつかの要素を設定しなければなりません.

11.3.5.1. 必須要素

12 - 14 行目ではこのモジュールのスコープの外から扱えるようにするための2つの必須の変数を定義しています.

is_binary

(6行目) この真偽値は ATHENA に対して,入力ファイルがテキスト形式なのかバイナリ形式なのかを伝えます.ATHENA において,バイナリファイルを列選択ダイアログで少し異なった扱われ方をします.

description

(7行目) このプラグインの目的を簡潔に記述した短いテキスト.この文字列はプラグインレジストリに表示されます.この記述内容はおよそ 30 文字以下であるべきです.

version

(8行目) このプラグインの(数値で示された)バージョン

metadata_ini

share/xdi/ フォルダにあるファイルでビームラインや施設に共通のメタデータを含むもの

headers

プラグインによってなされることに関係する追加的なメタデータを含むハッシュへのリファレンス

11.3.5.2. is メソッド

12 - 23 行目は,is メソッドです.このメソッドは,ATHENA が入力データファイルがある特定のフォーマットであるか確認するために使われます.この例の場合,X10C ファイルはファイルの最初の 2, 3 行の含まれるテキストによって認識されます.ファイルが認識されると,このメソッドは true を返します.もし,テストが失敗すれば,0 を返します.true が返ってくると,ATHENA はデータファイルを IFEFFIT あるいは LARCH で扱える形式に変換するための fix メソッドを実行します.

is メソッドが速いことは重要です.データファイルはたくさんのプラグインによってテストされるかもしれません.もしこのメソッドが遅ければ,ファイル読み込みが遅くなってしまいます.

11.3.5.3. fix メソッド

26 - 46 行目は fix メソッドです.このメソッドは is メソッドが true を返したときに実行されます.ある方法で,元のデータファイルのコピーを作り,そのコピーを IFEFFIT あるいは LARCH が読むことのできる形式に変換します.このメソッドはいくつかの厳密なルールにしたがう必要がありますが,これらのルールを守れば,変換をどのように行うか,またデータに対してどのような変換を行うかという範囲について柔軟に扱うことが出来ます.

まず,最も重要なのは,元のデータを一切変更しないことです!メモリの中の元のファイルの中身やデータのコピーを行う場合には,stash フォルダで行うのがよいです(このフォルダは DEMETER にとっては scratch のファイルを書き出すための場所です.).29行目では変換されたデータを保持するためにファイルが stash フォルダで開かれることがわかります.データが処理されると,出力はそのファイルに対して行われます.(36行目と40行目を見てください)

元データファイルで注意を払うべき部分の変換に必要なことを行ってください.その後で,入力ファイルと出力ファイルを閉じてください.これらのファイルを閉じておくのは,特に Windows のように他のプロセスからの利用を防ぐためにファイルをロックしてしまうような場合に重要です.

最終的に,オブジェクトの fix された要素のパスと変換されたファイルの名前を設定し,同じ文字列を返します.

このページに示されている例では,fix メソッドが最初に行うことは,変換されたファイルのために stash ディレクトリ内のファイル名を作ることです.28行目では,ATHENA は元のファイル名と同じ stash ファイルを stash ディレクトリ内に作っています.(このメソッドが呼ばれる前に,ATHENA は,filename 要素を適切に設定しています.)(catfile メソッドはプラットフォームに依存しないファイル名を作成します.)29行目では,IFEFFIT に内部的な制限に引っかからないようにファイル名の長さを確認しています.

X10C ファイルを変換するためには3つの処理が行われます.ヘッダーはヌル文字で取り除かれます.ヘッダーは行頭に # をつけてコメントアウトされ,列の間に空白がないためにファイルの変換がうまくいかないという問題が解決されます.元のファイルは1行ずつ読み込まれて処理され,stash ディレクトリにある変換後のファイルに書き込まれていきます.34行目から始まる while ループでファイルは一行ずつ読み込まれて処理が行われます.

42 行目と 43 行目は元のファイルおよび新しいファイルのハンドラを閉じています.フィルターは常にファイルハンドラを閉じる必要があります.これは unix では大した問題ではありませんが,Windows 上ではファイルハンドラが開かれているとロックがかかってしまいます.もしファイル閉じるのに失敗すると,ATHENA が実行されている間,他のプロセスではそのファイルに対して何もできなくなってしまいます

45 行目では変換されたファイルの完全なファイル名を返しています.元のファイルはどのような意味でも変更されません.ATHENA が終了すると,stash ディレクトリを片付けるので,不要なデータファイルが積み上がってしまうことはありません.

DEMETER は様々な種類のプラグインと共に提供されています.これらのうちのいくつかは(上の例のように)単純な変換を行います.他のものはバイナリデータを解釈します.いくつかのものはデータファイルではなくプロジェクトファイルを出力します.あるいはエネルギー分散型検出器からのデータに対してその場でデッドタイム補正を行うものもあります.これらを見て,あなた自身がプラグインを作る参考にしてください.

11.3.5.4. suggest メソッド

48 - 59 行目は suggest メソッドです.これは,列選択ダイアログにおけるデータの分子と分母を含む列の初期推定を行います.この場合,透過法であれば適当な列を推定しますが,蛍光法のデータに対しては推定を行いません.

11.3.6. ATHENA's plugin registry

たくさんのファイル読み込み用プラグインがあるかもしれないので,どのプラグインを有効化するかについてチェックボックスで変更することができます.メインメニューには Plugin Registry があります.これは,システムおよびユーザのディレクトリで見つかるすべてのプラグインのリストです.チェックボックスを使って,プラグインを有効化あるいは無効化することができます.リストには description 変数の値が表示されます.(よって,この変数には適切かつ適当に短い値を入れてください)

../_images/import_plugin.png

図 11.4 プラグイン登録

プラグインが表示される順番はファイルがプラグインによってチェックされる順番と同じだということに注意してください.ユーザープラグインはシステムプラグインの前にチェックされます.その後はプラグインはアルファベット順に並べられます.もし,まずシステムプラグインをデータに対して適用したければ,アルファベット順で初めの方にくるような名前をつけてください.

登録画面の項目を右クリックすると,上の図に示したようなコンテキストメニューが表示されます.このようなコンテキストメニューでは少なくともプラグインのソースコードに含まれるドキュメントを読むための項目が1つ含まれます.他のプラグインでは,例えば上に示したようにプラグインの挙動を変更する方法を提供している場合もあります.

11.3.7. システムプラグインとユーザープラグイン

ATHENA はこれらのプラグインを2つの場所で探します.1つめは ATHENA がインストールされたところで,DEMETER ディストリビューションと共にインストールされたプラグインを見つけることができます.もう1つはユーザの場所で(Windows では C:\\Program File\\Ifeffit\\horae\\Ifeffit\\Plugins\\Filetype\\Athena\\ にあり,unix では $HOME/.horae/Ifeffit/Plugins/Filetype/Athena/)です.両方の場所で,.pm で終わるファイルをプラグインとして読み込もうとします.

11.3.8. プラグインに関する雑多なアドバイス

  1. カットアンドペーストは新しいプラグインを作るよい方法です.あなたのファイルに似たファイルのためのプラグインのコピーを作り,新しいプラグインの元としてみて下さい.

  2. X15B.pm はバイナリ形式のデータのためのプラグインの例です.

  3. 必要とするどんなモジュールを使っても構いません.すなわち,自分用のプラグインを設計するときには CPAN にあるすべてのモジュールが使えます.もし,かなり重たい仕事をしないといけないような場合は,Math::Pari モジュールや Perl Data Language についてチェックしてみてください.

  4. よくテストされ,ロバストなプラグインが目標だとは思いますが,プラグイン機構のよいところは “good-enough” プラグインは簡単に書け,ファイル読み込みという困難を素早く乗り越えることができるという点にあります.




DEMETER is copyright © 2009-2016 Bruce Ravel – This document is copyright © 2016 Bruce Ravel

This document is licensed under The Creative Commons Attribution-ShareAlike License.

If DEMETER and this document are useful to you, please consider supporting The Creative Commons.