Spaces:
Sleeping
Sleeping
| """Tests for FTIR preprocessing functionality.""" | |
| import pytest | |
| import numpy as np | |
| from utils.preprocessing import ( | |
| preprocess_spectrum, | |
| validate_spectrum_range, | |
| get_modality_info, | |
| MODALITY_RANGES, | |
| MODALITY_PARAMS, | |
| ) | |
| def test_modality_ranges(): | |
| """Test that modality ranges are correctly defined.""" | |
| assert "raman" in MODALITY_RANGES | |
| assert "ftir" in MODALITY_RANGES | |
| raman_range = MODALITY_RANGES["raman"] | |
| ftir_range = MODALITY_RANGES["ftir"] | |
| assert raman_range[0] < raman_range[1] # Valid range | |
| assert ftir_range[0] < ftir_range[1] # Valid range | |
| assert ftir_range[0] >= 400 # FTIR starts at 400 cm⁻¹ | |
| assert ftir_range[1] <= 4000 # FTIR ends at 4000 cm⁻¹ | |
| def test_validate_spectrum_range(): | |
| """Test spectrum range validation for different modalities.""" | |
| # Test Raman range validation | |
| raman_x = np.linspace(300, 3500, 100) # Typical Raman range | |
| assert validate_spectrum_range(raman_x, "raman") == True | |
| # Test FTIR range validation | |
| ftir_x = np.linspace(500, 3800, 100) # Typical FTIR range | |
| assert validate_spectrum_range(ftir_x, "ftir") == True | |
| # Test out-of-range data | |
| out_of_range_x = np.linspace(50, 150, 100) # Too low for either | |
| assert validate_spectrum_range(out_of_range_x, "raman") == False | |
| assert validate_spectrum_range(out_of_range_x, "ftir") == False | |
| def test_ftir_preprocessing(): | |
| """Test FTIR-specific preprocessing parameters.""" | |
| # Generate synthetic FTIR spectrum | |
| x = np.linspace(400, 4000, 200) # FTIR range | |
| y = np.sin(x / 500) + 0.1 * np.random.randn(len(x)) + 2.0 # Synthetic absorbance | |
| # Test FTIR preprocessing | |
| x_proc, y_proc = preprocess_spectrum(x, y, modality="ftir", target_len=500) | |
| assert x_proc.shape == (500,) | |
| assert y_proc.shape == (500,) | |
| assert np.all(np.diff(x_proc) > 0) # Monotonic increasing | |
| assert np.min(y_proc) >= 0.0 # Normalized to [0, 1] | |
| assert np.max(y_proc) <= 1.0 | |
| def test_raman_preprocessing(): | |
| """Test Raman-specific preprocessing parameters.""" | |
| # Generate synthetic Raman spectrum | |
| x = np.linspace(200, 3500, 200) # Raman range | |
| y = np.exp(-(((x - 1500) / 200) ** 2)) + 0.05 * np.random.randn( | |
| len(x) | |
| ) # Gaussian peak | |
| # Test Raman preprocessing | |
| x_proc, y_proc = preprocess_spectrum(x, y, modality="raman", target_len=500) | |
| assert x_proc.shape == (500,) | |
| assert y_proc.shape == (500,) | |
| assert np.all(np.diff(x_proc) > 0) # Monotonic increasing | |
| assert np.min(y_proc) >= 0.0 # Normalized to [0, 1] | |
| assert np.max(y_proc) <= 1.0 | |
| def test_modality_specific_parameters(): | |
| """Test that different modalities use different default parameters.""" | |
| x = np.linspace(400, 4000, 200) | |
| y = np.sin(x / 500) + 1.0 | |
| # Test that FTIR uses different window length than Raman | |
| ftir_params = MODALITY_PARAMS["ftir"] | |
| raman_params = MODALITY_PARAMS["raman"] | |
| assert ftir_params["smooth_window"] != raman_params["smooth_window"] | |
| # Preprocess with both modalities (should use different parameters) | |
| x_raman, y_raman = preprocess_spectrum(x, y, modality="raman") | |
| x_ftir, y_ftir = preprocess_spectrum(x, y, modality="ftir") | |
| # Results should be slightly different due to different parameters | |
| assert not np.allclose(y_raman, y_ftir, rtol=1e-10) | |
| def test_get_modality_info(): | |
| """Test modality information retrieval.""" | |
| raman_info = get_modality_info("raman") | |
| ftir_info = get_modality_info("ftir") | |
| assert "range" in raman_info | |
| assert "params" in raman_info | |
| assert "range" in ftir_info | |
| assert "params" in ftir_info | |
| # Check that ranges match expected values | |
| assert raman_info["range"] == MODALITY_RANGES["raman"] | |
| assert ftir_info["range"] == MODALITY_RANGES["ftir"] | |
| # Check that parameters are present | |
| assert "baseline_degree" in raman_info["params"] | |
| assert "smooth_window" in ftir_info["params"] | |
| def test_invalid_modality(): | |
| """Test handling of invalid modality.""" | |
| x = np.linspace(1000, 2000, 100) | |
| y = np.sin(x / 100) | |
| with pytest.raises(ValueError, match="Unsupported modality"): | |
| preprocess_spectrum(x, y, modality="invalid") | |
| with pytest.raises(ValueError, match="Unknown modality"): | |
| validate_spectrum_range(x, "invalid") | |
| with pytest.raises(ValueError, match="Unknown modality"): | |
| get_modality_info("invalid") | |
| def test_modality_parameter_override(): | |
| """Test that modality defaults can be overridden.""" | |
| x = np.linspace(400, 4000, 100) | |
| y = np.sin(x / 500) + 1.0 | |
| # Override FTIR default window length | |
| custom_window = 21 # Different from FTIR default (13) | |
| x_proc, y_proc = preprocess_spectrum( | |
| x, y, modality="ftir", window_length=custom_window | |
| ) | |
| assert x_proc.shape[0] > 0 | |
| assert y_proc.shape[0] > 0 | |
| def test_range_validation_warning(): | |
| """Test that range validation warnings work correctly.""" | |
| # Create spectrum outside typical FTIR range | |
| x_bad = np.linspace(100, 300, 50) # Too low for FTIR | |
| y_bad = np.ones_like(x_bad) | |
| # Should still process but with validation disabled | |
| x_proc, y_proc = preprocess_spectrum( | |
| x_bad, y_bad, modality="ftir", validate_range=False # Disable validation | |
| ) | |
| assert len(x_proc) > 0 | |
| assert len(y_proc) > 0 | |
| def test_backwards_compatibility(): | |
| """Test that old preprocessing calls still work (defaults to Raman).""" | |
| x = np.linspace(1000, 2000, 100) | |
| y = np.sin(x / 100) | |
| # Old style call (should default to Raman) | |
| x_old, y_old = preprocess_spectrum(x, y) | |
| # New style call with explicit Raman | |
| x_new, y_new = preprocess_spectrum(x, y, modality="raman") | |
| # Should be identical | |
| np.testing.assert_array_equal(x_old, x_new) | |
| np.testing.assert_array_equal(y_old, y_new) | |
| if __name__ == "__main__": | |
| pytest.main([__file__]) | |