コンテンツにスキップ

2025年度

25/06/27 進捗報告

並列化を行うことで高速化を行おうとしたが数十万点であれば確かにその効果を感じた。

しかし、今回の数億点ある状況においては高速化されたというより、遅くなったようにさえ感じた。

pygrackleの公式サイト

そもそも、pygrackleの中はFortranで動いており、この高速化はあまり有用ではないことがある程度分かった。

そこで lookup tableをpygrackleで作成し、そのテーブルを線形補間を行うことにした。

修正は必要であるものの一旦のコードが下記。

from pygrackle import chemistry_data, setup_fluid_container
import numpy as np
from pygrackle.utilities.physical_constants import mass_hydrogen_cgs, sec_per_Myr, cm_per_mpc, boltzmann_constant_cgs

def compute_tcool_Gyr(rho_cgs, T, Z, x_e, chem, redshift=0.0):
    chem.a_value = 1.0 / (1.0 + redshift)
    metal_mass_fraction = np.asarray(Z) * 0.0127
    fc = setup_fluid_container(
        chem,
        density=np.asarray(rho_cgs),
        temperature=np.asarray(T),
        metal_mass_fraction=metal_mass_fraction,
        converge=True
    )
    data = fc.finalize_data()
    Lambda = data["cooling_rate"]  # erg cm^3 / s

    n_H = np.asarray(rho_cgs) / (0.6 * mass_hydrogen_cgs)
    n_e = np.asarray(x_e) * n_H
    tcool_s = (1.5 * boltzmann_constant_cgs * np.asarray(T)) / (n_e * -Lambda)  # [s]
    tcool_Gyr = tcool_s / (60 * 60 * 24 * 365 * 1e9) # [Gyr]
    return tcool_Gyr

rho_grid = np.logspace(-28, -22, 24)
T_grid = np.logspace(4, 8, 32)
Z_grid = np.logspace(-3, 0, 8)
xe_grid = np.linspace(0.01, 1.0, 8)

tcool_table = np.zeros((len(rho_grid), len(T_grid), len(Z_grid), len(xe_grid)), dtype=np.float64)

for i, rho in enumerate(rho_grid):
    for j, T in enumerate(T_grid):
        for k, Z in enumerate(Z_grid):
            for l, x_e in enumerate(xe_grid):
                chem = chemistry_data()
                chem.use_grackle = 1
                chem.with_radiative_cooling = 0
                chem.primordial_chemistry = 3
                chem.metal_cooling = 1
                chem.UVbackground = 1
                chem.grackle_data_file = "/home/nishihama/Osaka-gadget4/data/CloudyDatav3/CloudyData_UVB=HM2012.h5"
                chem.comoving_coordinates = 0
                chem.a_units = 1.0
                chem.a_value = 1.0
                chem.density_units = mass_hydrogen_cgs
                chem.length_units = cm_per_mpc
                chem.time_units = sec_per_Myr
                chem.set_velocity_units()
                chem.initialize()
                tcool = compute_tcool_Gyr(rho, T, Z, x_e, chem)
                tcool_table[i, j, k, l] = tcool

np.savez(
    "tcool_lookup_table_4d.v3.npz",
    rho_grid=rho_grid, T_grid=T_grid, Z_grid=Z_grid, xe_grid=xe_grid,
    tcool_table=tcool_table
)
print("4D Lookup table (rho, T, Z, x_e) saved as tcool_lookup_table_4d.npz")

image-20250728144103824

image-20250728144111674

黒色がGrackleで赤色が補完で作成したものである。

綺麗に計算できている。これを採用することにする。

使い方

import numpy as np
from scipy.interpolate import RegularGridInterpolator

# --- テーブル読み込み ---
data = np.load("tcool_lookup_table_4d.v3.npz")
rho_grid = data["rho_grid"]
T_grid = data["T_grid"]
Z_grid = data["Z_grid"]
xe_grid = data["xe_grid"]
tcool_table = data["tcool_table"]

# --- 4D補間関数を作成 ---
interp = RegularGridInterpolator(
    (rho_grid, T_grid, Z_grid, xe_grid),
    tcool_table,
    bounds_error=False, fill_value=np.nan  # グリッド外はNaN
)

補完したい値を代入する時は以下のようにする。

points = np.stack([rho_cgs, T, Z, x_e], axis=-1)
tcool_interp = interp(points)

tcool_interpが結果である。