倭算数理研究所

科学・数学・学習関連の記事を、「倭マン日記」とは別に書いていくのだ!

物理系 PhysicalSystem

今回から何回かにわたって、反復シミュレーションを構成するコンポーネント前回参照)を見ていきます。 今回は物理系

反復シミュレーションで求められる物理系の特性は、物理系の状態を保持するフィールドとそれらのフィールド(つまりは物理系の状態)を更新するメソッドです。 物理系の状態を保持するフィールドは、それらの値が分かれば、その物理系の全ての物理量が計算できるものであるべきです。 以降ではこれらのフィールドを(その物理系の)支配変数 (Dominant Variables) 状態変数 (State Variables) と呼ぶことにしましょう。 必ずしもシミュレーションで計算して出力するデータを状態変数にする必要はありません。 もう1つの物理系の特性、状態更新メソッドは反復ごとに呼び出されます。 反復シミュレーションとは「状態の更新」と「物理量の計算&出力」を反復するシミュレーションと言っていいでしょうから、このメソッドは非常に重要です。 これはまた、多くの(古き良き)物理理論で、微分方程式が規定するものでもあるので、理論の観点からもその大切さが分かると思います。 このメソッドでは、上記の支配変数のみを変更する点に注意しましょう。

物理系の実装に際して上記の2点が最も注意すべき点だと思いますが、他にもシミュレーション実行中に値が変化しないシミュレーション・パラメータ(以降、パラメータ (Parameter))や、状態初期化メソッドなども考慮する必要があります。

Groops では、物理系を表すインターフェースとして PhysicalSystem を提供します。 ただし、Groops はこの物理系の構築にはほとんど寄与しません。 PhysicalSystem インターフェースを実装したオブジェクトを受け取るだけです(プロパティの注入などはできるようにする予定)。 物理系を部品から構築できるようなフレームワークは(もし作るなら)別途作成します。

PhysicalSystem インターフェース


では、もう少し具体的に PhysicalSystem インターフェースを見ていきましょう。 まずはメソッド。 インターフェースにはメソッドしか定義できないので

  • 状態初期化メソッド initialize()
  • 状態更新メソッド evolve()

を定義しています:

package org.waman.groops.simulation;

import java.util.Map;

public interface PhysicalSystem{

    /** 状態初期化メソッド */
    void initialize(Map<String, Object> params) throws BuildTimeException;

    /** 状態更新メソッド */
    void evolve(Map<String, Object> params) throws StateEvolutionException;
}

それぞれのメソッドに渡される Map オブジェクトは外部から渡されるパラメータです。 例外に関してはとりあえず気にしないで下さい。 ほかにも状態変数やパラメータを取得・設定する Accessor メソッドも定義していますが、ここでは省略(こちらを参照)。 次はフィールド。 インターフェースには直接フィールドを定義させることを強制できませんが、PhysicalSystem のサブクラスには

  • 状態変数
  • シミュレーション・パラメータ

の2種類のフィールドを定義することになります。 これらのフィールドには、それぞれ @Dominant @State, @Parameter アノテーションを付加することにしましょう*1。 PhysicalSystem インターフェースについてはこんな感じです。

実装例


では具体的に PhysicalSystem のサブクラスを作成してみましょう。 物理系のサンプルとして『計算物理学入門』に載っているニュートンの冷却の法則にしたがう系を取り上げます。

理論の準備

ニュートンの冷却の法則は、温度が T の物体(例えばコーヒー)が時間 t と共に冷えていくとき、以下の微分方程式に従うというものです:

  

ここで Troom は室温(一定)、r は定数(冷却定数)です。 コーヒーの初期温度 T0 は室温 Troom より高いとします*2

モデリング

では PhysicalSystem のサブクラスを作成するためのモデリングをしましょう。 ニュートンの冷却の法則に従う物理系を CoolSystem としましょう。 まずはフィールドから。

  • 状態変数:
    • 経過時間 time
    • 温度 T
  • シミュレーション・パラメータ:
    • 時間間隔 dt
    • 室温 T_room
    • 冷却定数 r

微分方程式で使っている文字と少々違うのもありますがご了承を。 次は状態更新メソッドを実装するために微分方程式を差分化しましょう。

  

モデリングはこんな感じで、次実装。

Groovy コード

では上記のモデリングの結果を実装に落とし込みましょう。 で、PhysicalSystem インターフェースを直接実装したクラスを定義してもいいんですが、ここでは AnnotationPhysicalSystem クラスを継承してサブクラスを作成することにします。 このクラスは initialize() メソッドのデフォルト実装を提供します。 このデフォルト実装では @State アノテーションが付加されたフィールドに初期値を注入します(詳しくはそのうちやる SimulationBuilder にて)。 実装の胆は微分方程式(を差分化した式)による状態の更新ロジックです:

import org.waman.groops.simulation.system.*;

class CoolSystem extends AnnotationPhysicalSystem{

    @State BigDecimal time
    @State double T

    @Parameter BigDecimal dt
    @Parameter double T_room
    @Parameter double r

    @Override
    void evolve(Map<String, Object> params){
        time += dt
        T += -r*(T - T_room)*dt.doubleValue()
    }
}

時間に関する状態変数、パラメータ (time, dt) に関しては double ではなく BigDecimal 型にしてます。 まぁ何か長々と説明しましたが、Groovy の記述力を使えばコード見ただけで物理系が把握できますね・・・(たぶん)*3

追記


Groops 0.1-beta から、少々互換性のない変更を加えたので、記事も修正しています(可能な箇所は修正線  を入れています)

計算物理学入門

計算物理学入門

  • 作者: ハーベイゴールド,ジャントボチニク,Harvey Gould,Jan Tobochnik,鈴木増雄,石川正勝,溜渕継博,宮島佐介
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2000/12
  • メディア: 単行本
  • クリック: 5回
  • この商品を含むブログ (45件) を見る

*1:結構面倒なので、そのうち付けなくてもいいようにするかも知れませんが。

*2:低くても同じ微分方程式に従うようです。

*3:一応そのためにちょっと長くなるけど @State, @Parameter アノテーションを付けるようにさせてます。

*4:パッケージも変更して org.waman.groops.simulation.system としてます。

*5:こちらもパッケージはorg.waman.groops.simulation.system です。