patternpythonMinor
Look up parameters based on a numpy array of input values
Viewed 0 times
numpyarraylookinputbasedvaluesparameters
Problem
Aim: Write a function that looks up empirical parameters
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 >=1, day_of_year = 32, day_of_year = 60, day_of_year = 91, day_of_year = 121, day_of_year = 152, day_of_year = 182, day_of_year = 213, day_of_year = 244, day_of_year = 274, day_of_year = 305, day_of_year = 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[
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 >=1, day_of_year = 32, day_of_year = 60, day_of_year = 91, day_of_year = 121, day_of_year = 152, day_of_year = 182, day_of_year = 213, day_of_year = 244, day_of_year = 274, day_of_year = 305, day_of_year = 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[
Solution
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.
The operation can also be vectorized (in MATLAB as well as numpy), by constructing a matrix that compares the whole
Or this could be generalized to use a
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 >= dates[i], day_of_year < dates[i+1])
A[interval] = Avalues[i]
# similarly for B and C
return AThe 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] <= day_of_year) & (day_of_year < 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] <= day_of_year) & (day_of_year < 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)Code Snippets
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 >= dates[i], day_of_year < dates[i+1])
A[interval] = Avalues[i]
# similarly for B and C
return Adef 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] <= day_of_year) & (day_of_year < dates2[:,None]) # boolean index array
I = np.where(I)[0] # convert to numeric index
return Avalues[I]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] <= day_of_year) & (day_of_year < 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)Context
StackExchange Code Review Q#72258, answer score: 3
Revisions (0)
No revisions yet.