Skip to content

Latest commit

 

History

History
217 lines (163 loc) · 4.62 KB

File metadata and controls

217 lines (163 loc) · 4.62 KB

ライブラリ化 - モジュールとパッケージ

自分で作った関数やクラスをライブラリとしてまとめると、複数のスクリプトから再利用できます。

モジュールとは

.py ファイルがモジュールです。他のファイルから import できます。

モジュールの作成

simlec/utils.py:

"""ユーティリティ関数"""
import numpy as np

def calc_norm(v):
    """ベクトルのノルムを計算"""
    return np.sqrt(np.sum(v**2))

def deg2rad(deg):
    """度をラジアンに変換"""
    return deg * np.pi / 180.0

モジュールの使用

# import文でモジュールを読み込む
from simlec.utils import calc_norm, deg2rad

v = np.array([3, 4])
print(calc_norm(v))  # 5.0

print(deg2rad(90))  # 1.5707...

パッケージとは

複数のモジュールをまとめたディレクトリがパッケージです。__init__.py を置くことでパッケージになります。

パッケージ構成

simlec/
├── __init__.py      # パッケージの初期化
├── rocket.py        # ロケットクラス
├── integrators.py   # 数値積分法
└── utils.py         # ユーティリティ

__init__.py の役割

よく使う機能をパッケージ直下から使えるようにします。

simlec/__init__.py:

"""小型ロケット飛翔シミュレータ"""
from .rocket import Rocket
from .integrators import euler_step, rk4_step

__version__ = "1.0.0"

これにより、以下のように使えます:

from simlec import Rocket

ライブラリの実装例

simlec/rocket.py

"""ロケットクラス"""
import numpy as np

class Rocket:
    """ロケットを表すクラス"""

    def __init__(self, mass, thrust, Cd=0.5, A=0.01):
        self.mass = mass
        self.thrust = thrust
        self.Cd = Cd
        self.A = A

        # 状態
        self.position = np.array([0.0, 0.0, 0.0])
        self.velocity = np.array([0.0, 0.0, 0.0])

    def calc_drag(self, rho=1.225):
        """空気抵抗を計算"""
        v_mag = np.linalg.norm(self.velocity)
        if v_mag < 1e-10:
            return np.zeros(3)
        v_unit = self.velocity / v_mag
        drag_mag = 0.5 * rho * v_mag**2 * self.Cd * self.A
        return -drag_mag * v_unit

    def calc_forces(self, thrust_direction):
        """全ての力を計算"""
        # 推力
        F_thrust = self.thrust * thrust_direction
        # 重力
        F_gravity = np.array([0, 0, -self.mass * 9.8])
        # 空気抵抗
        F_drag = self.calc_drag()

        return F_thrust + F_gravity + F_drag

simlec/integrators.py

"""数値積分法"""
import numpy as np

def euler_step(f, y, t, dt):
    """
    オイラー法の1ステップ

    Parameters
    ----------
    f : callable
        微分方程式 dy/dt = f(t, y)
    y : array
        現在の状態
    t : float
        現在時刻
    dt : float
        時間刻み

    Returns
    -------
    array
        次の状態
    """
    return y + dt * f(t, y)


def rk4_step(f, y, t, dt):
    """
    ルンゲクッタ4次法の1ステップ

    Parameters
    ----------
    f : callable
        微分方程式 dy/dt = f(t, y)
    y : array
        現在の状態
    t : float
        現在時刻
    dt : float
        時間刻み

    Returns
    -------
    array
        次の状態
    """
    k1 = f(t, y)
    k2 = f(t + dt/2, y + dt/2 * k1)
    k3 = f(t + dt/2, y + dt/2 * k2)
    k4 = f(t + dt, y + dt * k3)

    return y + dt/6 * (k1 + 2*k2 + 2*k3 + k4)

simlec/utils.py

"""ユーティリティ関数"""
import numpy as np

def calc_norm(v):
    """ベクトルのノルムを計算"""
    return np.linalg.norm(v)

def normalize(v):
    """単位ベクトルを返す"""
    n = calc_norm(v)
    if n < 1e-10:
        return np.zeros_like(v)
    return v / n

def deg2rad(deg):
    """度をラジアンに変換"""
    return np.radians(deg)

def rad2deg(rad):
    """ラジアンを度に変換"""
    return np.degrees(rad)

パッケージの使用例

from simlec import Rocket
from simlec.integrators import euler_step, rk4_step
from simlec.utils import deg2rad

# ロケットの作成
rocket = Rocket(mass=1.0, thrust=50.0)

# シミュレーション...

実行してみよう

scripts/01_python/06_packaging_example.py を実行してください:

python scripts/01_python/06_packaging_example.py

これで Part 1: Pythonの使い方 は終了です。

次へ: Part 2: ロケットの物理と数学