Skip to content

API Reference

Top-level API

compute_melt_pool(data: pd.DataFrame, *, domain: SimulationDomain | None = None, chunk_size: int = 50, workers: int | None = None, output_dir: Path | str | None = None, return_field: bool = True) -> pd.DataFrame

Compute melt pool dimensions for every row in a DataFrame.

Parameters are processed in chunks; each chunk can be dispatched to a separate process for parallelism. Results are appended as new columns to a copy of data and returned.

Parameters:

Name Type Description Default

data

DataFrame

Input DataFrame. Must contain the columns listed in _REQUIRED_COLUMNS.

required

domain

SimulationDomain | None

Custom simulation domain. If None, the default 1200 x 1200 x 1000 um domain is used for every row.

None

chunk_size

int

Number of rows per chunk. Larger values reduce multiprocessing overhead at the cost of coarser progress. Defaults to 50.

50

workers

int | None

Worker processes to use. 1 or None runs serially; -1 uses all available cores.

None

output_dir

Path | str | None

If provided, each processed chunk is saved as a CSV file under this directory before results are concatenated.

None

return_field

bool

When True, a temperature_field column is added to the output DataFrame containing the TemperatureField for each row (None for rows that failed).

True

Returns:

Type Description
DataFrame

A new DataFrame identical to data plus the output columns:

DataFrame

melt_length, melt_width, melt_depth (m),

DataFrame

melt_length_um, melt_width_um, melt_depth_um (um),

DataFrame

peak_temperature, min_temperature (K), and optionally

DataFrame

temperature_field when return_field=True.

Raises:

Type Description
TypeError

If data is not a pandas DataFrame.

ValueError

If any required column is absent from data.

ValueError

If workers is not a positive integer, -1, or None.

Examples:

import pandas as pd
from eagar_tsai import compute_melt_pool

df = pd.DataFrame({
    "velocity_m_s": [0.5],
    "power_w": [200.0],
    "beam_diameter_m": [100e-6],
    "absorptivity": [0.35],
    "liquidus_temperature_k": [1700.0],
    "thermal_conductivity_w_mk": [30.0],
    "density_kg_m3": [7800.0],
    "specific_heat_j_kgk": [700.0],
})
result = compute_melt_pool(df, workers=1)

compute_single_point(beam: BeamParameters, material: MaterialProperties, domain: SimulationDomain | None = None, *, full_field: bool = True) -> MeltPoolResult

Compute melt pool dimensions for a single set of process parameters.

The temperature field is evaluated on the x-y (z=0) and x-z (y=0) planes. Melt pool extents are extracted from the liquidus isotherm. If the melt pool touches a domain boundary the domain is expanded iteratively (up to _MAX_EXPANSION_ITERS times) and the computation is repeated on the enlarged grid.

Parameters:

Name Type Description Default

beam

BeamParameters

Laser beam and process parameters.

required

material

MaterialProperties

Material thermal properties.

required

domain

SimulationDomain | None

Spatial domain; defaults to 1200 x 1200 x 1000 um, 1 um.

None

full_field

bool

When True (default), T_xy and T_xz are computed for every grid point and stored in the returned TemperatureField. When False, T_xz is computed only at the x-indices that fall inside the melt pool, which is significantly faster when the melt pool spans a small fraction of the domain. The TemperatureField is still returned but T_xz is filled with the ambient temperature outside the melt x-range, so it should not be used for plotting.

True

Returns:

Type Description
MeltPoolResult

A MeltPoolResult containing melt pool dimensions, temperature

MeltPoolResult

extremes, and the full TemperatureField. All lengths are zero

MeltPoolResult

if the peak temperature does not exceed the liquidus temperature.

Raises:

Type Description
RuntimeError

If domain expansion does not converge within _MAX_EXPANSION_ITERS iterations.

compute_printability_map(params: PrintabilityParameters, material: MaterialProperties, *, power_range: tuple[float, float] = (40.0, 400.0), velocity_range: tuple[float, float] = (0.05, 3.0), n_power: int = 50, n_velocity: int = 50, keyhole_wdr_threshold: float = 2.5, domain: SimulationDomain | None = None, workers: int | None = None) -> pd.DataFrame

Compute a printability map over a laser power * scan speed grid.

Runs the Eagar-Tsai model at every (power, velocity) grid point and classifies each point using five defect criteria from Sheikh et al. (2023): LOF1, LOF2, Ball1, Ball2, and KH1. Points are labeled as one of "defect_free", "keyhole", "lack_of_fusion", or "balling" in priority order: keyhole > lack of fusion > balling > defect-free.

Parameters:

Name Type Description Default

params

PrintabilityParameters

Fixed process parameters (beam diameter, absorptivity, layer thickness, hatch spacing).

required

material

MaterialProperties

Material thermal properties.

required

power_range

tuple[float, float]

(min_power_W, max_power_W) for the grid. Defaults to (40.0, 400.0).

(40.0, 400.0)

velocity_range

tuple[float, float]

(min_velocity_m_s, max_velocity_m_s) for the grid. Defaults to (0.05, 3.0).

(0.05, 3.0)

n_power

int

Number of power grid points. Defaults to 50.

50

n_velocity

int

Number of velocity grid points. Defaults to 50.

50

keyhole_wdr_threshold

float

Width-to-depth ratio threshold for KH1 keyhole criterion. Defaults to 2.5.

2.5

domain

SimulationDomain | None

Simulation domain. Defaults to SimulationDomain(1200, 1200, 1000, 5) (5 µm resolution), which is ~25x faster than the 1 µm default used by compute_melt_pool with negligible classification accuracy loss. Pass an explicit domain to override.

None

workers

int | None

Worker processes for parallel computation. None or 1 runs serially; -1 uses all available cores. Each grid point is dispatched as an independent task, so workers stay fully utilized even when isolated points require iterative domain expansion.

None

Returns:

Type Description
DataFrame

A DataFrame with one row per grid point containing:

DataFrame

power_w, velocity_m_s, melt_length_um, melt_width_um,

DataFrame

melt_depth_um, defect (str), lof1, lof2, ball1,

DataFrame

ball2, kh1 (bool).

Examples:

from eagar_tsai import MaterialProperties, PrintabilityParameters, compute_printability_map

mat = MaterialProperties(
    liquidus_temperature=1700.0,
    thermal_conductivity=30.0,
    density=7800.0,
    specific_heat=700.0,
)
process = PrintabilityParameters(
    beam_diameter_m=80e-6,
    absorptivity=0.35,
    layer_thickness_m=40e-6,
    hatch_spacing_m=90e-6,
)
df = compute_printability_map(process, mat, n_power=30, n_velocity=30, workers=-1)
print(df["defect"].value_counts())

Data Classes

BeamParameters(beam_diameter: float, power: float, velocity: float, absorptivity: float) dataclass

Laser beam and process parameters.

Attributes:

Name Type Description
beam_diameter float

Beam diameter in metres, equal to 2*sigma where σ is the Gaussian standard deviation of the source distribution.

power float

Laser power in Watts.

velocity float

Scan velocity in m/s.

absorptivity float

Absorptivity (dimensionless, must be in (0, 1]).

sigma float

Beam width parameter used in the dimensionless formulation: sqrt(2) * (beam_diameter / 2) = sqrt(2) * sigma. Differs from the Gaussian standard deviation sigma = beam_diameter / 2 by sqrt(2).

__post_init__() -> None

Validate physical constraints and compute derived sigma.

MaterialProperties(liquidus_temperature: float, thermal_conductivity: float, density: float, specific_heat: float) dataclass

Material thermal properties evaluated at the liquidus temperature.

Attributes:

Name Type Description
liquidus_temperature float

Liquidus temperature in Kelvin.

thermal_conductivity float

Thermal conductivity in W/(m K).

density float

Density in kg/m^3.

specific_heat float

Specific heat capacity in J/(kg K).

thermal_diffusivity: float property

Thermal diffusivity alpha = k / (rho * cp) in m^2/s.

__post_init__() -> None

Validate physical constraints.

PrintabilityParameters(beam_diameter_m: float, absorptivity: float, layer_thickness_m: float, hatch_spacing_m: float) dataclass

Fixed process parameters for printability map computation.

Holds the parameters that remain constant while laser power and scan speed vary across the printability map grid.

Attributes:

Name Type Description
beam_diameter_m float

Laser beam diameter in metres (= 2σ).

absorptivity float

Laser absorptivity (dimensionless, must be in (0, 1]).

layer_thickness_m float

Powder layer thickness in metres.

hatch_spacing_m float

Hatch spacing between adjacent scan tracks in metres.

hatch_spacing_um: float property

Hatch spacing in micrometres.

layer_thickness_um: float property

Powder layer thickness in micrometres.

__post_init__() -> None

Validate physical constraints.

SimulationDomain(x_length_um: float = 1200.0, y_length_um: float = 1200.0, z_depth_um: float = 1000.0, spatial_resolution_um: float = 1.0) dataclass

Spatial domain for numerical temperature field evaluation.

All _um attributes are in micrometres; corresponding properties (without the suffix) return the equivalent value in metres.

Attributes:

Name Type Description
x_length_um float

Domain length along x (scan direction) in um.

y_length_um float

Domain half-width along y in um.

z_depth_um float

Domain depth along z in um.

spatial_resolution_um float

Grid spacing in um.

spatial_resolution: float property

Grid spacing in metres.

x_length: float property

Domain length along x in metres.

y_length: float property

Domain half-width along y in metres.

z_depth: float property

Domain depth along z in metres.

__post_init__() -> None

Validate that all domain dimensions and resolution are positive.

expanded(*, dx_um: float = 0.0, dy_um: float = 0.0, dz_um: float = 0.0) -> SimulationDomain

Return a new domain with expanded dimensions.

Parameters:

Name Type Description Default

dx_um

float

Additional length along x in um.

0.0

dy_um

float

Additional half-width along y in um.

0.0

dz_um

float

Additional depth along z in um.

0.0

Returns:

Type Description
SimulationDomain

A new SimulationDomain with the specified expansions added.

MeltPoolResult(length: float, width: float, depth: float, peak_temperature: float, min_temperature: float, temperature_field: TemperatureField) dataclass

Melt pool geometry, temperature extremes, and associated temperature field.

Attributes:

Name Type Description
length float

Melt pool length along x in metres.

width float

Melt pool full width along y in metres.

depth float

Melt pool depth along z in metres.

peak_temperature float

Maximum temperature in the domain in Kelvin.

min_temperature float

Minimum temperature in the domain in Kelvin.

temperature_field TemperatureField

Full 2-D temperature field for the x-y and x-z planes.

depth_um: float property

Melt pool depth in micrometres.

length_um: float property

Melt pool length in micrometres.

width_um: float property

Melt pool full width in micrometres.

plot(*, output: str | None = None, annotate: bool = True) -> matplotlib.figure.Figure

Render a two-panel temperature field figure (x-y surface and x-z depth cross-section).

Delegates to self.temperature_field.plot().

Parameters:

Name Type Description Default

output

str | None

File path to save the figure. When None the figure is returned without saving.

None

annotate

bool

When True, overlay width and depth annotations.

True

Returns:

Type Description
Figure

A matplotlib.figure.Figure.

TemperatureField(T_xy: np.ndarray, T_xz: np.ndarray, x_range_m: np.ndarray, y_range_m: np.ndarray, z_range_m: np.ndarray, liquidus_temperature_k: float, melt_width_m: float = 0.0, melt_depth_m: float = 0.0) dataclass

Full 2-D temperature field associated with a MeltPoolResult.

Attributes:

Name Type Description
T_xy ndarray

Temperature on the x-y plane (z=0, surface). Shape (ny, nx), Kelvin.

T_xz ndarray

Temperature on the x-z plane (y=0, centerline). Shape (nz, nx), Kelvin.

x_range_m ndarray

1-D x-coordinate array in metres (scan direction).

y_range_m ndarray

1-D y-coordinate array in metres (cross-scan, half-domain).

z_range_m ndarray

1-D z-coordinate array in metres (negative values = depth below surface).

liquidus_temperature_k float

Liquidus temperature in Kelvin, used for contour plots.

melt_width_m float

Melt pool full width in metres, used for width annotation in plots.

melt_depth_m float

Melt pool depth in metres, used for depth annotation in plots.

x_range_um: np.ndarray property

x-coordinate array in micrometres.

y_range_um: np.ndarray property

y-coordinate array in micrometres.

z_range_um: np.ndarray property

z-coordinate array in micrometres (negative values = depth below surface).

plot(*, output: str | None = None, annotate: bool = True) -> matplotlib.figure.Figure

Render a two-panel temperature field figure (x-y surface and x-z depth cross-section).

Parameters:

Name Type Description Default

output

str | None

File path to save the figure. When None the figure is returned without saving.

None

annotate

bool

When True, overlay width and depth annotations derived from melt_width_m and melt_depth_m.

True

Returns:

Type Description
Figure

A matplotlib.figure.Figure.

Plotting

plot_temperature_field(beam: BeamParameters, material: MaterialProperties, domain: SimulationDomain | None = None, *, output: str | Path | None = None, annotate: bool = True) -> matplotlib.figure.Figure

Compute and render the x-y surface and x-z depth temperature planes.

Internally calls compute_single_point and passes the temperature field to _render_temperature_panels. Use this function when you only need the figure. If you also want access to the raw temperature arrays or melt pool summary, call compute_single_point directly and then call result.plot() or result.temperature_field.plot().

Parameters:

Name Type Description Default

beam

BeamParameters

Laser beam and process parameters.

required

material

MaterialProperties

Material thermal properties.

required

domain

SimulationDomain | None

Spatial domain. Defaults to SimulationDomain(1200, 1200, 1000, 1) um.

None

output

str | Path | None

File path to save the figure (e.g. "field.png"). Supports any format recognized by matplotlib.figure.Figure.savefig. When None the figure is returned without saving.

None

annotate

bool

When True (default), overlay width and depth annotations on the respective panels.

True

Returns:

Type Description
Figure

A matplotlib.figure.Figure containing two panels: the x-y surface

Figure

heatmap (top) and the x-z depth cross-section (bottom).

plot_temperature_field_3d(beam: BeamParameters, material: MaterialProperties, domain: SimulationDomain | None = None, *, workers: int | None = None, chunk_size: int = 10, output: str | Path | None = None, output_vti: str | Path | None = None, mirror_y: bool = True, liquidus_contour: bool = True, show_scalar_bar: bool = True, return_plotter: bool = False) -> matplotlib.figure.Figure | pv.Plotter

Compute and render the 3-D Eagar-Tsai temperature volume.

Internally calls compute_temperature_volume to auto-size the domain and evaluate the full (nx, ny, nz) temperature array, then renders the result with PyVista.

Parameters:

Name Type Description Default

beam

BeamParameters

Laser beam and process parameters.

required

material

MaterialProperties

Material thermal properties.

required

domain

SimulationDomain | None

Starting simulation domain for auto-sizing. When None, the default SimulationDomain() is used.

None

workers

int | None

Worker processes for parallel x-slice computation. None or 1 runs serially. -1 uses all available cores.

None

chunk_size

int

Number of x-index slices per worker task.

10

output

str | Path | None

File path to save the PyVista-rendered image directly (e.g. "volume.png"). Only used when return_plotter=True. PDF, SVG, and EPS paths use PyVista's save_graphic; all other extensions are saved as a raster screenshot.

None

output_vti

str | Path | None

When provided, also export the volume to a .vti file at this path before rendering.

None

mirror_y

bool

When True (default), mirror the y-axis to show the full symmetric melt pool.

True

liquidus_contour

bool

When True (default), overlay the liquidus isotherm as a contour surface.

True

show_scalar_bar

bool

When True (default), show the temperature color bar.

True

return_plotter

bool

When True, return the interactive pyvista.Plotter directly. When False (default), render off-screen and return a matplotlib.figure.Figure containing the captured image.

False

Returns:

Type Description
Figure | Plotter

A matplotlib.figure.Figure when return_plotter=False, or the

Figure | Plotter

pyvista.Plotter instance when return_plotter=True.

Examples:

from eagar_tsai import BeamParameters, MaterialProperties
from eagar_tsai.plot import plot_temperature_field_3d

beam = BeamParameters(beam_diameter=80e-6, power=250.0, velocity=0.5, absorptivity=0.59)
mat = MaterialProperties(liquidus_temperature=3455.0, thermal_conductivity=23.75,
                         density=18038.9, specific_heat=251.6)

# Default: returns a matplotlib Figure (off-screen render)
fig = plot_temperature_field_3d(beam, mat, workers=-1)

# Interactive PyVista window
plotter = plot_temperature_field_3d(beam, mat, workers=-1, return_plotter=True)

plot_printability_map(params: PrintabilityParameters, material: MaterialProperties, *, power_range: tuple[float, float] = (40.0, 400.0), velocity_range: tuple[float, float] = (0.05, 3.0), n_power: int = 50, n_velocity: int = 50, keyhole_wdr_threshold: float = 2.5, domain: SimulationDomain | None = None, workers: int | None = None, output: str | Path | None = None, show_data_points: bool = False) -> matplotlib.figure.Figure

Compute and render a printability map over a laser power * scan speed grid.

Calls compute_printability_map internally and renders the resulting defect classification as a color-coded map with laser power on the Y-axis and scan speed on the X-axis.

Parameters:

Name Type Description Default

params

PrintabilityParameters

Fixed process parameters (beam diameter, absorptivity, layer thickness, hatch spacing).

required

material

MaterialProperties

Material thermal properties.

required

power_range

tuple[float, float]

(min_power_W, max_power_W) for the grid. Defaults to (40.0, 400.0).

(40.0, 400.0)

velocity_range

tuple[float, float]

(min_velocity_m_s, max_velocity_m_s) for the grid. Defaults to (0.05, 3.0).

(0.05, 3.0)

n_power

int

Number of laser power grid points. Defaults to 50.

50

n_velocity

int

Number of scan speed grid points. Defaults to 50.

50

keyhole_wdr_threshold

float

Width-to-depth ratio threshold for the KH1 keyhole criterion. Defaults to 2.5.

2.5

domain

SimulationDomain | None

Simulation domain. For large grids a coarser domain (e.g. SimulationDomain(1200, 1200, 1000, 5)) reduces compute time.

None

workers

int | None

Worker processes for parallel computation. None or 1 runs serially; -1 uses all available cores.

None

output

str | Path | None

File path to save the figure. When None the figure is returned without saving.

None

show_data_points

bool

When True, overlay a scatter marker at every computed grid point. Defaults to False.

False

Returns:

Type Description
Figure

A matplotlib.figure.Figure with a single axes showing the printability

Figure

map colored by defect regime.

Integrand

eagar_tsai_integrand(t: float, x: float, y: float, z: float, p: float) -> float

Evaluate the Eagar-Tsai integrand at a single point.

This function has the signature expected by scipy.integrate.quad when passed via the args keyword: quad(f, 0, inf, args=(x, y, z, p)).

Parameters:

Name Type Description Default

t

float

Integration variable (dimensionless time), must be > 0.

required

x

float

Non-dimensional x-coordinate, positive in the trailing wake direction (opposite to the scan direction).

required

y

float

Non-dimensional y-coordinate (cross-scan direction).

required

z

float

Non-dimensional z-coordinate (depth, scaled by sqrt(alpha * sigma / v)).

required

p

float

Non-dimensional parameter alpha / (v * sigma).

required

Returns:

Type Description
float

Integrand value at the given point.