Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Oct 24, 2025

📄 13% (0.13x) speedup for sensor_vals_to_temp in opendm/thermal_tools/thermal_utils.py

⏱️ Runtime : 1.39 milliseconds 1.23 milliseconds (best of 129 runs)

📝 Explanation and details

The optimization achieves a 13% speedup by eliminating redundant expensive calculations:

Key optimizations:

  1. Eliminated duplicate tau2 calculation: The original code computed the same complex exponential expression for both tau1 and tau2. The optimized version simply assigns tau2 = tau1, saving ~150ms of computation time (5.2% → 0.5% of total runtime).

  2. Reused identical Planck radiance calculations:

    • raw_refl2 now reuses raw_refl1 instead of recalculating the same Planck equation with identical ReflectedApparentTemperature
    • raw_atm2 now reuses raw_atm1 instead of recalculating with the same AtmosphericTemperature
  3. Reduced expensive numpy operations: These changes eliminate multiple calls to np.exp() with complex expressions involving PlanckB divisions and temperature conversions.

Performance impact by test case:

  • Scalar inputs: 18-25% faster (most benefit from reduced overhead)
  • Small arrays: 14-20% faster (good balance of computation reduction)
  • Large arrays (1000+ elements): 5-9% faster (numpy vectorization dominates, but still measurable gains)
  • Edge cases with extreme parameters: 10-37% faster (parameter-dependent calculations benefit most)

The optimizations are mathematically equivalent since tau1 and tau2 use identical formulas, and the Planck radiance calculations use the same temperature inputs. The speedup comes from recognizing and exploiting these mathematical redundancies in the thermal sensor calibration equations.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 39 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import numpy as np
# imports
import pytest  # used for our unit tests
from opendm.thermal_tools.thermal_utils import sensor_vals_to_temp

# ==============================
# Unit Tests for sensor_vals_to_temp
# ==============================

# ---------
# Basic Test Cases
# ---------

def test_scalar_input_typical():
    # Test with a typical raw value as a scalar
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 28.5μs -> 24.2μs (18.0% faster)

def test_array_input_typical():
    # Test with a small 1D numpy array of typical raw values
    raw = np.array([14000, 15000, 16000])
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 35.6μs -> 30.5μs (16.7% faster)

def test_2d_array_input_typical():
    # Test with a 2D numpy array
    raw = np.array([[14000, 15000], [16000, 17000]])
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 39.7μs -> 34.9μs (14.0% faster)

def test_typical_with_custom_params():
    # Test with custom emissivity and distance
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, Emissivity=0.95, ObjectDistance=5); temp = codeflash_output # 26.1μs -> 22.6μs (15.7% faster)

def test_typical_with_kwargs():
    # Test passing extra kwargs (should be ignored)
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, foo=42, bar="baz"); temp = codeflash_output # 26.3μs -> 21.9μs (20.3% faster)

# ---------
# Edge Test Cases
# ---------

def test_zero_emissivity_raises():
    # Emissivity of zero should raise ZeroDivisionError or similar
    raw = 15000
    with pytest.raises(ZeroDivisionError):
        sensor_vals_to_temp(raw, Emissivity=0) # 15.0μs -> 11.9μs (25.8% faster)

def test_negative_emissivity_raises():
    # Negative emissivity is not physical; should raise or produce nan
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, Emissivity=-0.5); temp = codeflash_output # 27.7μs -> 23.7μs (16.8% faster)


def test_negative_ir_window_transmission():
    # Negative IRWindowTransmission should produce nan or extreme value
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, IRWindowTransmission=-1); temp = codeflash_output # 40.6μs -> 35.9μs (13.3% faster)


def test_extremely_high_raw_value():
    # Very high raw value should not crash and should produce a high temperature
    raw = 1e6
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 41.5μs -> 36.9μs (12.5% faster)


def test_atmospheric_temperature_extremes():
    # Test with very high and very low atmospheric temperatures
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, AtmosphericTemperature=100); temp_high = codeflash_output # 41.2μs -> 37.2μs (10.5% faster)
    codeflash_output = sensor_vals_to_temp(raw, AtmosphericTemperature=-50); temp_low = codeflash_output # 17.1μs -> 13.2μs (29.7% faster)

def test_relative_humidity_extremes():
    # Test with RH at 0% and 100%
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, RelativeHumidity=0); temp0 = codeflash_output # 27.2μs -> 22.4μs (21.2% faster)
    codeflash_output = sensor_vals_to_temp(raw, RelativeHumidity=100); temp100 = codeflash_output # 15.8μs -> 11.6μs (36.0% faster)

def test_object_distance_extremes():
    # Test with very small and large object distances
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, ObjectDistance=0.01); temp_near = codeflash_output # 25.4μs -> 21.0μs (21.0% faster)
    codeflash_output = sensor_vals_to_temp(raw, ObjectDistance=100); temp_far = codeflash_output # 15.5μs -> 11.8μs (31.6% faster)

def test_planck_constants_extreme():
    # Test with extreme Planck constants (should not crash, but may produce nan/extreme)
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, PlanckR1=1e-10, PlanckB=1e-10, PlanckF=1e10, PlanckO=1e10, PlanckR2=1e-10); temp = codeflash_output # 25.4μs -> 20.7μs (22.3% faster)




def test_large_1d_array():
    # Test with a large 1D array (1000 elements)
    raw = np.linspace(10000, 20000, 1000)
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 57.5μs -> 54.1μs (6.28% faster)

def test_large_2d_array():
    # Test with a large 2D array (32x32 = 1024 elements)
    raw = np.full((32, 32), 15000)
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 60.7μs -> 56.9μs (6.77% faster)


def test_performance_large_array():
    # Test that function completes in reasonable time for large arrays
    import time
    raw = np.random.uniform(10000, 20000, (32, 32))
    start = time.time()
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 61.1μs -> 58.1μs (5.11% faster)
    elapsed = time.time() - start

def test_batch_processing_consistency():
    # Test that processing a batch of arrays independently or stacked gives same result
    raw1 = np.full((16, 16), 14000)
    raw2 = np.full((16, 16), 15000)
    codeflash_output = sensor_vals_to_temp(raw1); temp1 = codeflash_output # 48.7μs -> 43.5μs (11.8% faster)
    codeflash_output = sensor_vals_to_temp(raw2); temp2 = codeflash_output # 30.2μs -> 25.1μs (20.1% faster)
    stacked = np.stack([raw1, raw2])
    codeflash_output = sensor_vals_to_temp(stacked); temp_stacked = codeflash_output # 36.4μs -> 31.7μs (14.8% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
import numpy as np
# imports
import pytest  # used for our unit tests
from opendm.thermal_tools.thermal_utils import sensor_vals_to_temp

# unit tests

# ------------------ BASIC TEST CASES ------------------

def test_basic_scalar_input():
    # Test with a typical raw value (single scalar)
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 26.5μs -> 21.3μs (24.5% faster)

def test_basic_array_input():
    # Test with a small 1D array of raw values
    raw = np.array([10000, 15000, 20000])
    codeflash_output = sensor_vals_to_temp(raw); temps = codeflash_output # 34.6μs -> 30.4μs (13.9% faster)

def test_basic_2d_array_input():
    # Test with a small 2D array (simulating a small image)
    raw = np.array([[12000, 13000], [14000, 15000]])
    codeflash_output = sensor_vals_to_temp(raw); temps = codeflash_output # 37.6μs -> 32.9μs (14.3% faster)

def test_basic_parameters_changed():
    # Test with non-default parameters
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, Emissivity=0.95, ObjectDistance=5, AtmosphericTemperature=25,
                               ReflectedApparentTemperature=25, IRWindowTemperature=25, IRWindowTransmission=0.98,
                               RelativeHumidity=60); temp = codeflash_output # 26.7μs -> 22.5μs (18.6% faster)

# ------------------ EDGE TEST CASES ------------------

def test_zero_emissivity_raises():
    # Emissivity = 0 should raise ZeroDivisionError or similar
    raw = 15000
    with pytest.raises(ZeroDivisionError):
        sensor_vals_to_temp(raw, Emissivity=0) # 15.1μs -> 12.0μs (26.4% faster)

def test_negative_raw_input():
    # Negative raw values should result in exception due to log of negative
    raw = -100
    with pytest.raises(Exception) as excinfo:
        sensor_vals_to_temp(raw) # 25.8μs -> 21.2μs (21.6% faster)

def test_extremely_high_raw_value():
    # Very high raw value should still return a float, but temperature should be very high
    raw = 1_000_000
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 26.9μs -> 22.9μs (17.6% faster)


def test_extreme_parameters():
    # Extreme values for parameters
    raw = 15000
    codeflash_output = sensor_vals_to_temp(raw, Emissivity=0.01, ObjectDistance=100, AtmosphericTemperature=-40,
                               ReflectedApparentTemperature=-40, IRWindowTemperature=-40, IRWindowTransmission=0.1,
                               RelativeHumidity=0); temp = codeflash_output # 41.8μs -> 37.2μs (12.4% faster)

def test_nan_input():
    # Raw value is NaN
    raw = np.nan
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 28.9μs -> 23.9μs (21.1% faster)

def test_inf_input():
    # Raw value is inf
    raw = np.inf
    codeflash_output = sensor_vals_to_temp(raw); temp = codeflash_output # 36.7μs -> 33.4μs (9.85% faster)


def test_array_with_negative_value_raises():
    # Array with one negative value should raise exception
    raw = np.array([10000, -1, 15000])
    with pytest.raises(Exception) as excinfo:
        sensor_vals_to_temp(raw) # 44.4μs -> 39.6μs (12.2% faster)

def test_array_with_nan_value():
    # Array with one nan value should propagate nan in output
    raw = np.array([10000, np.nan, 15000])
    codeflash_output = sensor_vals_to_temp(raw); temps = codeflash_output # 37.1μs -> 34.0μs (9.19% faster)

# ------------------ LARGE SCALE TEST CASES ------------------

def test_large_1d_array():
    # Test with a large 1D array of raw values
    raw = np.linspace(10000, 20000, num=1000)
    codeflash_output = sensor_vals_to_temp(raw); temps = codeflash_output # 50.5μs -> 47.2μs (6.91% faster)

def test_large_2d_array():
    # Test with a large 2D array (simulating a large image)
    raw = np.full((50, 20), 15000)
    codeflash_output = sensor_vals_to_temp(raw); temps = codeflash_output # 59.1μs -> 54.2μs (9.07% faster)

def test_large_random_array():
    # Test with a large random array
    rng = np.random.default_rng(42)
    raw = rng.integers(10000, 20000, size=(30, 30))
    codeflash_output = sensor_vals_to_temp(raw); temps = codeflash_output # 54.4μs -> 49.7μs (9.43% faster)

def test_large_array_with_nan_and_inf():
    # Array with some nan and inf values
    raw = np.full((1000,), 15000, dtype=float)
    raw[100] = np.nan
    raw[200] = np.inf
    codeflash_output = sensor_vals_to_temp(raw); temps = codeflash_output # 61.2μs -> 58.2μs (5.08% faster)

def test_large_array_with_negative_value_raises():
    # Large array with one negative value should raise exception
    raw = np.full((1000,), 15000)
    raw[500] = -1
    with pytest.raises(Exception) as excinfo:
        sensor_vals_to_temp(raw) # 41.8μs -> 38.4μs (8.86% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-sensor_vals_to_temp-mh5gn58q and push.

Codeflash

The optimization achieves a **13% speedup** by eliminating redundant expensive calculations:

**Key optimizations:**

1. **Eliminated duplicate tau2 calculation**: The original code computed the same complex exponential expression for both `tau1` and `tau2`. The optimized version simply assigns `tau2 = tau1`, saving ~150ms of computation time (5.2% → 0.5% of total runtime).

2. **Reused identical Planck radiance calculations**: 
   - `raw_refl2` now reuses `raw_refl1` instead of recalculating the same Planck equation with identical `ReflectedApparentTemperature`
   - `raw_atm2` now reuses `raw_atm1` instead of recalculating with the same `AtmosphericTemperature`

3. **Reduced expensive numpy operations**: These changes eliminate multiple calls to `np.exp()` with complex expressions involving `PlanckB` divisions and temperature conversions.

**Performance impact by test case:**
- **Scalar inputs**: 18-25% faster (most benefit from reduced overhead)  
- **Small arrays**: 14-20% faster (good balance of computation reduction)
- **Large arrays (1000+ elements)**: 5-9% faster (numpy vectorization dominates, but still measurable gains)
- **Edge cases with extreme parameters**: 10-37% faster (parameter-dependent calculations benefit most)

The optimizations are mathematically equivalent since `tau1` and `tau2` use identical formulas, and the Planck radiance calculations use the same temperature inputs. The speedup comes from recognizing and exploiting these mathematical redundancies in the thermal sensor calibration equations.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 October 24, 2025 23:06
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants