Look up parameters based on a numpy array of input values Aim: Write a function that looks up empirical parameters A, B and C for a  solar radiation model. Each parameter has a value for a certain interval of time, represented as the day of the year. For now, I basically translate the four-column (day_of_year-interval, A, B, C) table that I have on paper into the following look up. The function works, but I have a feeling that this is not the most Pythonic way to do it.

Current implementation:

import numpy as np

def lookup_DNI_parameters(day_of_year):
    """Sets parameters A, B, and C for the calculation of direct normal irradiance
    based on day of year-intervals.

    A is in W/m^2
    B and C are dimensionless
    """
    A = np.empty_like(day_of_year)
    B = np.empty_like(day_of_year)
    C = np.empty_like(day_of_year)

    # generate boolean indices for each day_of_year-interval
    interval_1 = np.logical_and(day_of_year &gt;=1, day_of_year &lt; 32)
    interval_2 = np.logical_and(day_of_year &gt;= 32, day_of_year &lt; 60)
    interval_3 = np.logical_and(day_of_year &gt;= 60, day_of_year &lt; 91)
    interval_4 = np.logical_and(day_of_year &gt;= 91, day_of_year &lt; 121)
    interval_5 = np.logical_and(day_of_year &gt;= 121, day_of_year &lt; 152)
    interval_6 = np.logical_and(day_of_year &gt;= 152, day_of_year &lt; 182)
    interval_7 = np.logical_and(day_of_year &gt;= 182, day_of_year &lt; 213)
    interval_8 = np.logical_and(day_of_year &gt;= 213, day_of_year &lt; 244)
    interval_9 = np.logical_and(day_of_year &gt;= 244, day_of_year &lt; 274)
    interval_10 = np.logical_and(day_of_year &gt;= 274, day_of_year &lt; 305)
    interval_11 = np.logical_and(day_of_year &gt;= 305, day_of_year &lt; 335)
    interval_12 = day_of_year &gt;= 335

    # set parameter values based on the interval
    A[interval_1] = 1230.0
    A[interval_2] = 1215.0
    A[interval_3] = 1186.0
    A[interval_4] = 1136.0
    A[interval_5] = 1104.0
    A[interval_6] = 1088.0
    A[interval_7] = 1085.0
    A[interval_8] = 1107.0
    A[interval_9] = 1152.0
    A[interval_10] = 1193.0
    A[interval_11] = 1221.0
    A[interval_12] = 1234.0

    B[interval_1] = 0.142
    B[interval_2] = 0.144
    B[interval_3] = 0.156
    B[interval_4] = 0.180
    B[interval_5] = 0.196
    B[interval_6] = 0.205
    B[interval_7] = 0.207
    B[interval_8] = 0.201
    B[interval_9] = 0.177
    B[interval_10] = 0.160
    B[interval_11] = 0.149
    B[interval_12] = 0.142

    C[interval_1] = 0.058
    C[interval_2] = 0.060
    C[interval_3] = 0.071
    C[interval_4] = 0.097
    C[interval_5] = 0.121
    C[interval_6] = 0.134
    C[interval_7] = 0.136
    C[interval_8] = 0.122
    C[interval_9] = 0.092
    C[interval_10] = 0.073
    C[interval_11] = 0.063
    C[interval_12] = 0.057

    return A, B, C

# test an array of a few sample days for correctness of results
days = np.array([21., 80., 141., 202., 264., 325.])
A, B, C = lookup_DNI_parameters(days)
print A # [1230, 1186, 1104, 1085, 1152, 1221]
print B # [0.142, 0.156, 0.196, 0.207, 0.177, 0.149]
print C # [0.058, 0.060, 0.071, 0.121, 0.136, 0.092, 0.063]
So you are doing a lookup over many intervals.  A repeated pattern like that can be turned into a loop or vectorized

The repeated boilerplate suggests an iterative solution - looping over an array (or list) of dates and values.  It doesn't save on run time, and may, or may not, be more maintainable.

def lookup_DNI_parameters1(day_of_year):
    """solution based on iterating over ranges of dates
    """
    A = np.empty_like(day_of_year)
    dates = [1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]
    Avalues = [1230.0, 1215.0, 1186.0, 1136.0, 1104.0, 1088.0, 1085.0, 1107.0, 1152.0, 1193.0, 1221.0, 1234.0]
    for i in range(len(dates)-1):
        interval = np.logical_and(day_of_year &gt;= dates[i], day_of_year &lt; dates[i+1])
        A[interval] = Avalues[i]
    # similarly for B and C
    return A


The operation can also be vectorized (in MATLAB as well as numpy), by constructing a matrix that compares the whole day_of_year array against the dates intervals array(s).  The [:,None] broadcasting may be novel to a MATLAB user.

def lookup_DNI_parameters2(day_of_year):
    """solution based on vectorized matching of days
    """
    dates = [1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]
    dates1 = np.array(dates[:-1]) # interval start
    dates2 = np.array(dates[1:]) # interval stop
    Avalues = [1230.0, 1215.0, 1186.0, 1136.0, 1104.0, 1088.0, 1085.0, 1107.0, 1152.0, 1193.0, 1221.0, 1234.0]
    Avalues = np.array(Avalues)
    I = (dates1[:,None] &lt;= day_of_year) &amp; (day_of_year &lt; dates2[:,None]) # boolean index array
    I = np.where(I)[0]  # convert to numeric index
    return Avalues[I]


Or this could be generalized to use a dates parameter, and a values array that has information for A, B and C:

def lookup_DNI_parameters3(day_of_year, dates, values):
    """solution based on vectorized matching of days
    """
    dates1 = np.array(dates[:-1]) # interval start
    dates2 = np.array(dates[1:]) # interval stop
    I = (dates1[:,None] &lt;= day_of_year) &amp; (day_of_year &lt; dates2[:,None]) # boolean index array
    I = np.where(I)[0]  # convert to numeric index
    return values[...,I]

dates = [1, 32, 60, 91,...]
values = np.array([[1230.0, 1215.0,...], [142., 144., ...], [...]])
lookup_DNI_parameters3(day_of_years, dates, values)