SSブログ

光学薄膜設計ソフトの設計 その6 計算エンジンの設計 [考え中 - 光学薄膜設計]

前回、計算のための数学を整理した。計算にベクタユニットを使おうとすると問題がありそうなことがわかった。今回はもうちょっと上位の設計を進めてみる。
あまり数値計算を高レベルな言語で記述することは少ないけど、あとからやりたいNSOperationのサブクラスとしての相性の良さを考えて計算エンジンのレベルではObjective-Cで書くことにする。いずれにせよ数値計算の難しさは汎用のソフトウェア技術的な側面にはないのが普通なので(精度追跡や離散化の粒度評価や非線形性の扱いなどに本来の難しさがあってそこをカバーするような言語はまだない。せいぜいMathematicaがそれに対する問題意識を持っているぐらい)あまり記述言語に依存しない。特に今回の光学薄膜計算は、計算そのものは前回提示したように非常に簡単。

まず、ひとつの層を表現するOTFLayerのクラスを作る。このクラスは媒質の屈折率と膜厚の値を保持する。また、波長と入射角と偏光を指定すると、特性マトリクスを数値として出力することができる。

薄膜系全体を表現するOTFLayerCompositionというクラスにする。これは
  • OTFLayerのインスタンスのNSArray
  • 入射側の屈折率と、基板側の屈折率
を保持している。これ単体で臨界角なんかを決定することができる。これも波長と入射角と偏光を指定すると、前回の式-14のBとCを持つベクトルを返す。

OTFOpticalCharacteristicsというクラスも作る。これは
  • OTFLayerCompositionのインスタンス
  • 波長
  • 入射角
  • 偏光
を保持する。例えばこのクラスのインスタンスにreflectanceメソッドを投げると反射率を返すようにする。 計算はこれだけ。これを絵にすると
0303config.png
となる。

次に、あとから実装する最適化計算のための細工をしておく。
波長や入射角、偏光などの計算前提や、最適化の対象である層厚、屈折率媒質などは、上のインスタンスがそれぞれ値として保持せず、値を保持する特別のクラスのインスタンスへのポインタだけを保持するようにする。その、値を保持するクラスをOTFValriableとしよう。

OTFVariableは
- (void)setRealValue:(double)value;
- (double)realValue;
などのメソッドを持つ。つまり、外から値を変更して、OTFOpticalCharacteristicsなどのクラスのインスタンスはそれに従って(もちろんReadOnlyで)反射率などの計算をすることにする。

このままだとメソッド呼び出しだらけになってしまってせっかくベクタユニットを使って計算を速くしてもオーバーヘッドの方が大きくて意味が無くなってしまう。そこで、OTFVariableの値はキャッシュするようにしよう。そしてOTFVariableは外から値が変更されたときに、その値を参照している他のインスタンスに対して変更通知をしよう。

全部のパラメータを一斉に変更して計算する場合には逆にオーバーヘッドが大きくなるけど、なるべく影響が局所的に収まるようなパラメータ設定をして行けばキャッシュが有効に使える。

例えば、波長を変えてしまうと全部がチャラになるが、例えばある層の厚さだけを変えたときはその層に対応するマトリクスだけ更新すればいい。このようにちょっとずつ変えるようにすればパフォーマンスの低下は押さえられるはず。

ところで、通知にはその名の通りのNSNotificationというクラスがあるが、これはかなり高機能でオーバーヘッドも大きい。その昔PowerPlantでマック用のソフトを書いたことのある人なら知ってると思うけど、PowerPlantにはLBroadCasterとLListenerというクラスがあった。あの手を使おう。

LBroadCasterとLListenerというのも、NSNotificationに似た機能を持っている。LListenerのサブクラスのインスタンスはLBroadCasterのサブクラスのインスタンスに自分を登録することで、LBroadCasterから通知をもらうことができる。NSNotificationと違って通知を集配するオブジェクトがある訳ではなく、LBroadCaster自身がLListenerと協調して集配やLListenerの管理に責任を持つ。

ちなみにPowerPlantというのはMacOS9以前の時代に一番ポピュラーだったMetrowerksのCodeWarriorという開発環境のおまけについていたC++ベースのFrameworkで、ソースからコンパイルするのでソースが全部ごっそりついていた。このPowerPlantというのは巨大でコンパイルが大変だったけど、頭が冴えたすばらしい人が設計したと見えて中身は実にシンプルで、抽象的だけどわかりやすい概念をひょい、と導入することで魔法のように何でも簡単にしてしまうようにできていた。

ソースを見ると、たいていの関数はものの数行しかない。ソースを見ていて何回もスクロールしないと閉じカッコが出てこないという経験をしたことが無い。名前の付け方も上手くてメンバ関数の名前を見て、その中身を見るだけで何をやってるのかすぐにわかる。多重継承の使い方がスマートで(テレビとビデオを継承したテレビデオを作るような多重継承ではなく)、実体と機能を別々に記述してそれらを両方から継承する、というような使い方をしていた。当時PowerPlantのソースはすごく勉強になった。影響も受けたがあれほど簡単には書けていない。頭の冴え加減では圧倒的に負けてる。

LBroadCasterとLListenerをどうやって実現していたかと言うと、実に簡単でLBroadCasterはLListenerへのポインタの配列を持っていてLListenerの登録のときに、そのオブジェクトへのポインタをその配列に付け足す。ブロードキャストが必要になったら、配列の中のオブジェクト全部にLListenerが持ってる「ブロードキャストが来たよ」というメッセージ関数を呼ぶだけ。あとは配列のダイナミックな管理がちょっとあるだけ。

さらに賢いのはLBroadCasterやLListenerを使いたいオブジェクトがそれを継承する必要さえ無いということ。LAttachmentというクラスがあってオブジェクトに機能をぺた、と言う感じで追加することができる。継承の微妙な問題を避けてただその機能を使いたいときに便利にできている。LAttachmentをどうやって実現していたかは忘れたけど、やっぱりずいぶん簡単にできていて感心したことだけは覚えている。

これのまねをしよう。つぎはこの実装のあたりを考えてみることにする。 でもPowerPlantってその後どうなったのだろう?もったいないな。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立03/05献立03/06 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。