TWLab's picture
Add publication-ready ML project structure with full source code
e2b220f verified
"""
Unit tests for core functionality.
"""
import numpy as np
import pytest
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from src.features.engineering import (
compute_effective_pulses,
compute_peak_fluence,
compute_pulse_energy,
compute_spatial_overlap,
)
class TestFeatureEngineering:
"""Test physics-informed feature computations."""
def test_pulse_energy(self):
"""E = P / f: 100 mW / 100 kHz = 1 µJ"""
result = compute_pulse_energy(
np.array([100.0]), np.array([100.0])
)
np.testing.assert_allclose(result, [1.0], rtol=1e-5)
def test_pulse_energy_vectorized(self):
"""Test vectorized computation."""
powers = np.array([100, 200, 500])
rates = np.array([100, 100, 1000])
expected = np.array([1.0, 2.0, 0.5])
result = compute_pulse_energy(powers, rates)
np.testing.assert_allclose(result, expected, rtol=1e-5)
def test_peak_fluence_gaussian(self):
"""Test Gaussian beam fluence formula: F = 2E/(π*r²)"""
# 1 µJ pulse, 10 µm diameter (5 µm radius = 5e-4 cm)
result = compute_peak_fluence(np.array([1.0]), np.array([10.0]))
# Expected: 2 * 1e-6 / (π * (5e-4)²) = 2.546 J/cm²
expected = 2 * 1e-6 / (np.pi * (5e-4) ** 2)
np.testing.assert_allclose(result, [expected], rtol=1e-3)
def test_effective_pulses(self):
"""N_eff = f_rep * d_spot / v_scan"""
# 100 kHz, 10 µm spot, 1 mm/s
result = compute_effective_pulses(
np.array([100.0]), # kHz
np.array([10.0]), # µm
np.array([1.0]), # mm/s
)
# Expected: 100*1000 Hz * 10e-3 mm / 1 mm/s = 1000
np.testing.assert_allclose(result, [1000.0], rtol=1e-5)
def test_overlap_high_speed(self):
"""High speed → low overlap."""
result = compute_spatial_overlap(
np.array([10.0]), # mm/s (fast)
np.array([100.0]), # kHz
np.array([10.0]), # µm
)
# pitch = 10 / (100*1000) * 1000 = 0.1 µm → overlap ≈ 99%
assert result[0] > 90
def test_overlap_bounds(self):
"""Overlap should be clipped to [0, 99.9%]."""
result = compute_spatial_overlap(
np.array([1000.0]), # Very fast
np.array([1.0]), # Low rep rate
np.array([1.0]), # Small spot
)
assert result[0] >= 0
assert result[0] <= 100
class TestDataIntegrity:
"""Test data loading and preprocessing."""
def test_no_negative_targets(self):
"""Physical targets should be non-negative."""
# Generate dummy data matching expected format
n = 100
targets = np.random.exponential(5, size=(n, 5))
assert np.all(targets >= 0)
def test_feature_target_dimensions(self):
"""Feature and target arrays should have correct shapes."""
n_samples, n_features, n_targets = 100, 21, 5
X = np.random.randn(n_samples, n_features).astype(np.float32)
y = np.random.randn(n_samples, n_targets).astype(np.float32)
assert X.shape == (n_samples, n_features)
assert y.shape == (n_samples, n_targets)
if __name__ == "__main__":
pytest.main([__file__, "-v"])