Skip to content

Star Log-extended eMulation: a general overview

Authors: Sudhanva Lalit

Date last edited: 26 October 2025

In this tutorial notebook, we outline the use of our package SLM and show its power using the Sly4 equation of state (EOS). This notebook reproduces Figs. 1 and 2 in our accompanying paper.

# import packages
#[include autoreload here]

import os
import numpy as np
from pathlib import Path
import slmemulator as slme
from importlib import resources, util
from slmemulator import get_paths
from slmemulator import TOV, SLM
from slmemulator import plot_eigs, plot_slm_rad

# install the SLM package from source (potentially)
# 
# List EOS/data files directly from the package data directory to avoid
# importlib.resources on a non-package submodule.
eos_data_dir = get_paths()["package_eos_data_dir"]
data_files = [p.name for p in eos_data_dir.iterdir() if p.is_file()]
print("Data files in EOS data dir:", data_files)
Data files in EOS data dir: ['BFH_eos.table', 'BL_eos.table', 'DS_CMF_eos.table', 'EOS_Quarkyonia.dat', 'FSUGarnetNStarEOSA.txt', 'MFT_ns6p.dat', 'apr_eos.table', 'delta_eos.table', 'eos_tov_20n0.dat', 'eos_tov_40n0.dat', 'sortedDD2YDelta.dat', 'sortedDSeos.dat', 'sorted_Sly4.dat']

As we can see, there are several EOS files given for our purpose. We pick one of these: apr_eos.table. Since we are not doing any parametric EOS calculations (MSEOS/Quarkyonia) we set them to False.

parametric = False
mseos = False
eos_name = "apr_eos.table"
# run the help function to see what SLM does
help(slme.SLM)
Help on function SLM in module slmemulator.SLM:

SLM(X, dt, error_threshold=0.0001, max_r=None)
    Dynamic Mode decomposition for the augmented Data.
    Automatically determines the number of modes (r) based on an error threshold.

    Parameters:
        X (np.ndarray): The data matrix where each row is a variable, and each column is a snapshot
            in time. Expected to be log-transformed where appropriate.

        dt (np.float): The time difference of linear DMDs.

        error_threshold (float): (Optional) The maximum allowed absolute difference between the
            original data and the DMD reconstruction. Defaults to 1e-4.

        max_r (int): (Optional) The maximum number of modes to consider. If None, it will go up to
            the maximum possible rank (min(X.shape)).


# Initialize list to store paths of generated TOV data files for ParametricSLM
tov_data_files = []
EOS_DATA_DIR = get_paths()["package_eos_data_dir"]
filePath = EOS_DATA_DIR / eos_name
tidal = True  # Whether to compute tidal deformability
print("Running General SLM for file:", eos_name)
tov = TOV(filePath, tidal=tidal)
results = tov.tov_routine()
tov_file_name = f"MR_{eos_name}.txt"
mr_results = np.asarray(
    [
        results[0],  # Radius (km)
        results[1],  # Central Pressure (MeV/fm^3)
        results[2],  # Mass (M_sun)
        results[3],  # Tidal Deformability k2
    ],
    dtype=np.float64,
)
X = np.asarray(
    [
        np.log(results[0]),
        np.log(results[1]),
        np.log(results[2]),
        np.log(results[3]),
    ],
    dtype=np.float64,
)
slm = SLM(X, dt=1, error_threshold=1e-6)
Xdmd = slm[4]
Running General SLM for file: apr_eos.table
Woo it worked!
Max mass:  2.192818228236291 Radius:  9.967329639499997 Central pressure:  1032.2286804996406
Optimal 'r' determined: 13 (Max absolute error = 0.002434)

SLM results

Let's check how the emulator performs with respect to the high-fidelity solver.

# Find max mass index
slm_results = np.exp(Xdmd.real)
max_mass_index = np.argmax(slm_results[2])
max_mass_row = slm_results[:, max_mass_index]
max_mass = max_mass_row[2]
corresponding_radius = max_mass_row[0]
corresponding_pressure = max_mass_row[1]
corresponding_tidal = max_mass_row[3]

# Print the results
print(f"SLM Maximum Mass: {max_mass}")
print(f"SLM Corresponding Radius: {corresponding_radius}")
print(f"SLM Corresponding Central Pressure: {corresponding_pressure}")
print(f"SLM Corresponding Tidal Deformability: {corresponding_tidal}")
SLM Maximum Mass: 2.1928375511446463
SLM Corresponding Radius: 9.967184195761295
SLM Corresponding Central Pressure: 1032.3308271760657
SLM Corresponding Tidal Deformability: 0.013961311647316425

Generate Plots

Let us now plot the HF results and corresponding SLM results

First the eigenvalues:

plot_path = (
    f"SLM_{eos_name}.png"
)
plot_eigs(slm[2], output_path=plot_path)
ylabels = [
    r"Central Pressure $({\rm{MeV/fm}}^3)$",
    r"Mass $({\rm{M}}_{\odot})$",
    r"Tidal Deformability $k_2$",
]
print(f"File Name: {eos_name}")
fileNames = [
    f"SLM_{eos_name}".strip(".txt"),
    f"Eigs_{eos_name}".strip(".txt"),
]
plot_slm_rad(
    X,
    Xdmd,
    fileNames_for_labels=fileNames,
    plots_output_base_path=".",
    ylabels=ylabels,
)
File Name: apr_eos.table

No description has been provided for this image
No description has been provided for this image
No description has been provided for this image