0

Given two known 2D arrays (dimensions are time and position), dhdt_arr and dTsdt_arr, how can I generate some other 2D arrays from these faster than using nested for loops?

The arrays I would like to generate are named below, and have been setup like the known arrays:

dmdt_arr = np.zeros_like(dhdt_arr) #change in mass holdup
T_arr = np.zeros_like(dhdt_arr) # fluid temperature
m_hold_arr = np.zeros_like(dhdt_arr) # mass hold up
U_arr = np.zeros_like(dhdt_arr) # heat transfer coefficient array

The nested for loop I am using to generate the above arrays (assume the algebra is correct, the constants are known, and the functions I used are also known). I am just looking for a way to replace this structure with something faster, like a numpy vectorized approach):

for i in range(time.shape[0]): #iteratung through 2D array time x #positions
    for j in range(n): #yep

        T = temperature(h_arr[j,i],P)

        dmdt_arr[j, i] = dhdt_arr[j, i] * dpdh(h_arr[j, i], P) * V
        T_arr[j,i] = T
        m_hold_arr[j, i] = mass(h_arr[j, i], P)
        U_arr[j,i] = mAlumina*CP_ALUMINA*dTsdt_arr[j,i]/(sa*(T_arr[j,i] - Ts_arr[j,i]))

How can these same arrays be generated in a way that is faster than a nested for loop?

  • Have a look at that, it might answer your question: https://stackoverflow.com/questions/35215161/most-efficient-way-to-map-function-over-numpy-array – VicN Feb 27 '22 at 21:03
  • Hmm no I don't think this is directly related. I am looking for a nested for loop replacement, unless I am missing the link – casualguitar Feb 27 '22 at 21:16
  • some of these operations might be trivial to vectorise, but it is unclear what some of your functions, like temperature() do, if P is a scalar and you are multiplying you can write h_arr * P to multiply every element by P - clarify the operations in the functions – braulio Feb 27 '22 at 21:23
  • It's easy to create `I` and `J` that are arrays, e.g. `np.arange(n)[:,None]` and `np.arange(m)` that broadcast against each other. Then you just need to figure out how use those arrays in the body, rather than the scalar indices. The indexed uses like `dmdt_arr` are easy. We don't know what the functions accept - like `temperature` and `dpdh`. If those only work with scalar arguments, there isn't a "speed optimized manner". This applies to any loop, nested or not. – hpaulj Feb 27 '22 at 21:23
  • @braulio yes apologies I have not explained the functions. Each function accepts scalars and returns a single scalar. P is also scalar – casualguitar Feb 27 '22 at 21:28
  • @hpaulj I see what you are saying - "why would there be a faster approach when we still have to iterate through the 2D array". Is this correct that there is no faster way than a nested for loop? – casualguitar Feb 27 '22 at 21:29
  • As long as you have to call the body of that code once for each `i,j` pair, it doesn't matter much whether it's with a single `range(100)` loop, or a nested (10,10) loop. It's still run 100 times at Python speeds. As long as the body isn't trivial, its speed dominates the total time, not the iteration mechanism. – hpaulj Feb 27 '22 at 21:36
  • Understood and this makes sense in my head. However I have seen that nested for loops are slow compared to 'vectorized' numpy alternatives. What would this mean, or when is this true? – casualguitar Feb 27 '22 at 21:38
  • Well we can do this step by step: You can start with `temperature` and `mass` returning a 2D-array instead of an scalar and puting them *before* the for loop. You can take advantage of [scalar operations with numpy arrays](https://www.pythonprogramming.in/scalar-arithmetic-operations-on-numpy-array.html), and then redefine the functions so that they receive a numpy 2D-array and return another numpy 2D-array, like `T_arr = temperature(h_arr,P)` and `m_hold_arr = mass(h_arr, P)` – Gabriel Avendaño Feb 27 '22 at 23:37

0 Answers0