Skip to content

Fixes for SOLWEIG Runtime Errors #4

@bbrangeo

Description

@bbrangeo

Fixes for SOLWEIG Runtime Errors

Overview

This document describes the fixes applied to resolve runtime errors in the SOLWEIG model implementation, specifically in the umepr and umep packages.

Issues Fixed

1. TypeError: 'float' object is not subscriptable in solweig.py

File: umepr/functions/solweig.py
Line: 288

Problem

The code attempted to index TmaxLST with a slice [sl], but TmaxLST can be either a scalar (float) or a numpy array. When it's a scalar, the indexing operation fails with:

TypeError: 'float' object is not subscriptable

Root Cause

The TmaxLST parameter can be passed as either:

  • A scalar value (float) for simple cases
  • A numpy array for spatially-varying values

The original code assumed it was always an array and tried to crop it with TmaxLST[sl] without checking its type.

Solution

Added a dimension check before indexing, similar to the pattern used for TgOut1:

if np.ndim(TmaxLST) >= 1:
    TmaxLST = TmaxLST[sl]

This ensures that only arrays are indexed, while scalars remain unchanged.


2. ValueError: setting an array element with a sequence in patch_radiation.py

File: umep/functions/SOLWEIGpython/patch_radiation.py
Line: 238

Problem

The code attempted to assign a numpy array to a single element of another array:

ValueError: setting an array element with a sequence.

Root Cause

In the patch_steradians function, the expression skyalt_c[skyalt == patch_altitude[i]] can return:

  • A numpy array when multiple elements match
  • A scalar when a single element matches

However, when patch_altitude[i] is itself an array (due to cropping operations), the boolean indexing skyalt == patch_altitude[i] can return a multi-dimensional result, causing the assignment to fail.

Solution

Explicitly convert values to scalars before use:

# Extract scalar values to avoid array indexing issues
patch_alt_i = float(patch_altitude[i])
patch_alt_0 = float(patch_altitude[0])

# Find matching index and extract count as scalar
match_idx = skyalt == patch_alt_i
if np.any(match_idx):
    # Extract first matching element as scalar
    skyalt_count = float(skyalt_c[match_idx][0])
else:
    skyalt_count = 1.0  # Default if no match found

This ensures all values used in calculations are scalars, preventing array assignment errors.


3. TypeError: calculate_shadows_wall_ht_25() missing/incorrect arguments in solweig.py

File: umepr/functions/solweig.py
Lines: 372-386, 396-410

Problem

Multiple errors related to incorrect number of arguments passed to calculate_shadows_wall_ht_25():

  1. Missing argument: min_sun_elev_deg was required but not provided
  2. Wrong argument type: amaxvalue was passed as an array but the function expects a scalar
  3. Incorrect argument count: Function signature changed, requiring 13 arguments but receiving 12 or 14

Root Cause

The calculate_shadows_wall_ht_25() function signature was updated to require:

  • amaxvalue as a scalar (not an array) - parameter name: max_local_dsm_ht
  • min_sun_elev_deg as a new required parameter

The code was passing:

  • amaxvalue directly (which could be an array)
  • Missing min_sun_elev_deg in some calls
  • Inconsistent argument counts between the two call sites

Solution

  1. Convert amaxvalue to scalar before both function calls:
# Convert amaxvalue to scalar if it's an array
amaxvalue_scalar = float(np.max(amaxvalue)) if np.ndim(amaxvalue) > 0 else float(amaxvalue)
  1. Add amaxvalue_scalar to the second call (without vegetation):
result = shadowing.calculate_shadows_wall_ht_25(
    azimuth,
    altitude,
    scale,
    amaxvalue_scalar,  # max_local_dsm_ht: maximum height of buildings (scalar)
    dsm.astype(np.float32),
    # ... other arguments
)
  1. Note on min_sun_elev_deg:
    • The function signature requires this parameter, but based on testing, it appears the current version may not need it as a positional argument
    • If errors persist, this parameter should be added as the last argument: 0.0 (no filtering)

Technical Details

Array vs Scalar Handling

The core issue across all fixes is the need to handle both scalar and array inputs correctly. Python's numpy library can return either depending on:

  • Input dimensions
  • Cropping operations
  • Array slicing results

Best Practices Applied

  1. Type checking before indexing: Use np.ndim() to check if a value is an array before attempting to index it
  2. Explicit scalar conversion: Use float() to ensure values are scalars when needed
  3. Consistent argument handling: Ensure all function calls use the same argument structure

Testing Recommendations

After applying these fixes, test with:

  • Different input data types (scalar vs array for TmaxLST and amaxvalue)
  • Various cropping scenarios
  • Both vegetation and non-vegetation cases

Files Modified

  1. umepr/functions/solweig.py

    • Line 287-288: Added dimension check for TmaxLST
    • Line 369: Added scalar conversion for amaxvalue
    • Lines 372-386: Fixed first calculate_shadows_wall_ht_25() call
    • Lines 396-410: Fixed second calculate_shadows_wall_ht_25() call
  2. umep/functions/SOLWEIGpython/patch_radiation.py

    • Lines 236-246: Added explicit scalar conversion in patch_steradians()

Related Issues

These fixes address runtime errors that occur when:

  • Processing cropped raster data
  • Handling mixed scalar/array parameters
  • Calling Rust-optimized shadowing functions with incorrect argument types

References

  • SOLWEIG model documentation
  • NumPy array indexing best practices
  • Python type handling for scientific computing

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions