Reinforcement Learning
stable-baselines3
Joblib
PyTorch
tabular-regression
xgboost
femtosecond-laser
hydrogel
GelMA
HAMA
laser-machining
SAC
materials-science
manufacturing
ml-intern
Instructions to use TWLab/femtosecond-laser-hydrogel-etching-model with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- stable-baselines3
How to use TWLab/femtosecond-laser-hydrogel-etching-model with stable-baselines3:
from huggingface_sb3 import load_from_hub checkpoint = load_from_hub( repo_id="TWLab/femtosecond-laser-hydrogel-etching-model", filename="{MODEL FILENAME}.zip", ) - Notebooks
- Google Colab
- Kaggle
File size: 6,854 Bytes
e2b220f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | """
Physics-informed feature engineering for femtosecond laser processing.
Derives key physical quantities from raw laser parameters following
established laser-material interaction physics:
- Pulse energy from average power and repetition rate
- Peak fluence from pulse energy and beam geometry (Gaussian beam)
- Effective pulse number from scanning parameters
- Spatial overlap from scan speed and spot size
References
----------
- Perry et al., J. Biomed. Opt. (2009) - fs-laser ablation of hydrogels
- Gamaly et al., Physics Reports (2002) - fs-laser ablation theory
- Petit et al., JLMN (2025) - physics-informed ML features for laser machining
"""
from __future__ import annotations
import logging
from typing import Optional
import numpy as np
import pandas as pd
logger = logging.getLogger(__name__)
def compute_pulse_energy(power_mW: np.ndarray, rep_rate_kHz: np.ndarray) -> np.ndarray:
"""
Compute pulse energy from average power and repetition rate.
E_pulse = P_avg / f_rep
Parameters
----------
power_mW : array-like
Average laser power in milliwatts
rep_rate_kHz : array-like
Pulse repetition rate in kilohertz
Returns
-------
np.ndarray
Pulse energy in microjoules (µJ)
"""
return np.asarray(power_mW) / np.maximum(np.asarray(rep_rate_kHz), 1e-6)
def compute_peak_fluence(
pulse_energy_uJ: np.ndarray,
spot_diameter_um: np.ndarray,
) -> np.ndarray:
"""
Compute peak fluence for a Gaussian beam profile.
F_peak = 2 * E_pulse / (π * w₀²)
where w₀ = spot_diameter / 2 is the beam waist radius.
Parameters
----------
pulse_energy_uJ : array-like
Pulse energy in microjoules
spot_diameter_um : array-like
Beam spot diameter (1/e²) in micrometers
Returns
-------
np.ndarray
Peak fluence in J/cm²
"""
E_J = np.asarray(pulse_energy_uJ) * 1e-6 # µJ → J
r_cm = np.asarray(spot_diameter_um) / 2 * 1e-4 # µm → cm (radius)
return 2 * E_J / (np.pi * np.maximum(r_cm, 1e-8) ** 2)
def compute_effective_pulses(
rep_rate_kHz: np.ndarray,
spot_diameter_um: np.ndarray,
scan_speed_mm_s: np.ndarray,
) -> np.ndarray:
"""
Compute effective number of pulses per spot.
N_eff = f_rep × d_spot / v_scan
This represents the average number of laser pulses that irradiate
each point along the scan path.
Parameters
----------
rep_rate_kHz : array-like
Repetition rate in kHz
spot_diameter_um : array-like
Spot diameter in µm
scan_speed_mm_s : array-like
Scanning speed in mm/s
Returns
-------
np.ndarray
Effective pulse count (dimensionless)
"""
rep_Hz = np.asarray(rep_rate_kHz) * 1000
spot_mm = np.asarray(spot_diameter_um) * 1e-3
speed = np.maximum(np.asarray(scan_speed_mm_s), 1e-6)
return rep_Hz * spot_mm / speed
def compute_spatial_overlap(
scan_speed_mm_s: np.ndarray,
rep_rate_kHz: np.ndarray,
spot_diameter_um: np.ndarray,
) -> np.ndarray:
"""
Compute spatial pulse overlap percentage.
Overlap = (1 - pitch / d_spot) × 100%
where pitch = v_scan / f_rep is the distance between consecutive pulses.
Parameters
----------
scan_speed_mm_s : array-like
rep_rate_kHz : array-like
spot_diameter_um : array-like
Returns
-------
np.ndarray
Overlap percentage [0, 100)
"""
pitch_um = np.asarray(scan_speed_mm_s) * 1000 / (np.asarray(rep_rate_kHz) * 1000)
# pitch in µm: (mm/s * 1000 µm/mm) / (kHz * 1000 Hz/kHz) = µm
# Actually: pitch = v/f = (mm/s) / (kHz*1000) = mm, convert to µm
pitch_um = np.asarray(scan_speed_mm_s) / (np.asarray(rep_rate_kHz) * 1000) * 1000 # mm→µm
spot = np.maximum(np.asarray(spot_diameter_um), 1e-6)
overlap = np.clip(1 - pitch_um / spot, 0, 0.999)
return overlap * 100
def compute_energy_dose(
peak_fluence: np.ndarray,
effective_pulses: np.ndarray,
) -> np.ndarray:
"""
Compute total energy dose (accumulated fluence).
Dose = F_peak × N_eff
Parameters
----------
peak_fluence : array-like
Peak fluence in J/cm²
effective_pulses : array-like
Effective pulse number
Returns
-------
np.ndarray
Energy dose in J/cm²
"""
return np.asarray(peak_fluence) * np.asarray(effective_pulses)
def compute_all_derived_features(df: pd.DataFrame) -> pd.DataFrame:
"""
Compute all physics-informed derived features and add to DataFrame.
Parameters
----------
df : pd.DataFrame
DataFrame with raw laser parameters
Returns
-------
pd.DataFrame
DataFrame with added derived feature columns
"""
df = df.copy()
# Pulse energy
if "pulse_energy_uJ" not in df.columns:
df["pulse_energy_uJ"] = compute_pulse_energy(
df["power_mW"].values, df["repetition_rate_kHz"].values
)
logger.info("Computed: pulse_energy_uJ")
# Peak fluence
if "peak_fluence_J_cm2" not in df.columns:
df["peak_fluence_J_cm2"] = compute_peak_fluence(
df["pulse_energy_uJ"].values, df["spot_diameter_um"].values
)
logger.info("Computed: peak_fluence_J_cm2")
# Effective pulses
if "effective_pulses" not in df.columns:
df["effective_pulses"] = compute_effective_pulses(
df["repetition_rate_kHz"].values,
df["spot_diameter_um"].values,
df["scan_speed_mm_s"].values,
)
logger.info("Computed: effective_pulses")
# Overlap
if "overlap_percent" not in df.columns:
df["overlap_percent"] = compute_spatial_overlap(
df["scan_speed_mm_s"].values,
df["repetition_rate_kHz"].values,
df["spot_diameter_um"].values,
)
logger.info("Computed: overlap_percent")
# Energy dose
if "energy_dose_J_cm2" not in df.columns:
df["energy_dose_J_cm2"] = compute_energy_dose(
df["peak_fluence_J_cm2"].values, df["effective_pulses"].values
)
logger.info("Computed: energy_dose_J_cm2")
return df
def get_feature_groups(config: dict) -> dict:
"""
Get feature groups from configuration for ablation studies.
Parameters
----------
config : dict
Experiment configuration dictionary
Returns
-------
dict
Mapping from group name to list of feature column names
"""
data_cfg = config["data"]
return {
"laser": data_cfg["laser_features"],
"material": data_cfg["material_features"],
"derived": data_cfg["derived_features"],
"all": (
data_cfg["laser_features"]
+ data_cfg["material_features"]
+ data_cfg["derived_features"]
),
}
|