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 |
|---|---|---|---|
|
DataFrame
|
Input DataFrame. Must contain the columns listed in _REQUIRED_COLUMNS. |
required |
|
SimulationDomain | None
|
Custom simulation domain. If None, the default 1200 x 1200 x 1000 um domain is used for every row. |
None
|
|
int
|
Number of rows per chunk. Larger values reduce multiprocessing overhead at the cost of coarser progress. Defaults to 50. |
50
|
|
int | None
|
Worker processes to use. |
None
|
|
Path | str | None
|
If provided, each processed chunk is saved as a CSV file under this directory before results are concatenated. |
None
|
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
A new DataFrame identical to |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ValueError
|
If any required column is absent from |
ValueError
|
If |
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 |
|---|---|---|---|
|
BeamParameters
|
Laser beam and process parameters. |
required |
|
MaterialProperties
|
Material thermal properties. |
required |
|
SimulationDomain | None
|
Spatial domain; defaults to 1200 x 1200 x 1000 um, 1 um. |
None
|
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
MeltPoolResult
|
A |
MeltPoolResult
|
extremes, and the full |
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 |
|---|---|---|---|
|
PrintabilityParameters
|
Fixed process parameters (beam diameter, absorptivity, layer thickness, hatch spacing). |
required |
|
MaterialProperties
|
Material thermal properties. |
required |
|
tuple[float, float]
|
|
(40.0, 400.0)
|
|
tuple[float, float]
|
|
(0.05, 3.0)
|
|
int
|
Number of power grid points. Defaults to |
50
|
|
int
|
Number of velocity grid points. Defaults to |
50
|
|
float
|
Width-to-depth ratio threshold for KH1 keyhole
criterion. Defaults to |
2.5
|
|
SimulationDomain | None
|
Simulation domain. Defaults to |
None
|
|
int | None
|
Worker processes for parallel computation. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
A DataFrame with one row per grid point containing: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
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 |
|---|---|---|---|
|
float
|
Additional length along x in um. |
0.0
|
|
float
|
Additional half-width along y in um. |
0.0
|
|
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 |
|---|---|---|---|
|
str | None
|
File path to save the figure. When |
None
|
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
Figure
|
A |
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 |
|---|---|---|---|
|
str | None
|
File path to save the figure. When |
None
|
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
Figure
|
A |
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 |
|---|---|---|---|
|
BeamParameters
|
Laser beam and process parameters. |
required |
|
MaterialProperties
|
Material thermal properties. |
required |
|
SimulationDomain | None
|
Spatial domain. Defaults to |
None
|
|
str | Path | None
|
File path to save the figure (e.g. |
None
|
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
Figure
|
A |
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 |
|---|---|---|---|
|
BeamParameters
|
Laser beam and process parameters. |
required |
|
MaterialProperties
|
Material thermal properties. |
required |
|
SimulationDomain | None
|
Starting simulation domain for auto-sizing. When |
None
|
|
int | None
|
Worker processes for parallel x-slice computation.
|
None
|
|
int
|
Number of x-index slices per worker task. |
10
|
|
str | Path | None
|
File path to save the PyVista-rendered image directly
(e.g. |
None
|
|
str | Path | None
|
When provided, also export the volume to a |
None
|
|
bool
|
When |
True
|
|
bool
|
When |
True
|
|
bool
|
When |
True
|
|
bool
|
When |
False
|
Returns:
| Type | Description |
|---|---|
Figure | Plotter
|
A |
Figure | Plotter
|
|
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 |
|---|---|---|---|
|
PrintabilityParameters
|
Fixed process parameters (beam diameter, absorptivity, layer thickness, hatch spacing). |
required |
|
MaterialProperties
|
Material thermal properties. |
required |
|
tuple[float, float]
|
|
(40.0, 400.0)
|
|
tuple[float, float]
|
|
(0.05, 3.0)
|
|
int
|
Number of laser power grid points. Defaults to |
50
|
|
int
|
Number of scan speed grid points. Defaults to |
50
|
|
float
|
Width-to-depth ratio threshold for the KH1 keyhole
criterion. Defaults to |
2.5
|
|
SimulationDomain | None
|
Simulation domain. For large grids a coarser domain
(e.g. |
None
|
|
int | None
|
Worker processes for parallel computation. |
None
|
|
str | Path | None
|
File path to save the figure. When |
None
|
|
bool
|
When |
False
|
Returns:
| Type | Description |
|---|---|
Figure
|
A |
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 |
|---|---|---|---|
|
float
|
Integration variable (dimensionless time), must be > 0. |
required |
|
float
|
Non-dimensional x-coordinate, positive in the trailing wake direction (opposite to the scan direction). |
required |
|
float
|
Non-dimensional y-coordinate (cross-scan direction). |
required |
|
float
|
Non-dimensional z-coordinate (depth, scaled by sqrt(alpha * sigma / v)). |
required |
|
float
|
Non-dimensional parameter alpha / (v * sigma). |
required |
Returns:
| Type | Description |
|---|---|
float
|
Integrand value at the given point. |