File size: 6,065 Bytes
88e8763
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""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__])