pre-calculating and storing arrays¶

Say we have a grid, and a function that maps the grid position to a given value (or vector). For example,

$$f(x,y) = ax^3e^{-by},$$

where $a,b$ are constants. And let the grid run from $0$ to $L_x,L_y$.

Something we can do, if $x=idx$ and $y=jdy, is

$$f(x,y) = adx^3i^3e^{-bdyj} = Ai^3B^j,$$

where $A=adx^3$ and $B=e^{-b}dy$. The idea is avoid calculating the same thing more than once.

Another function could be

$$g(x,y) = ax^3 + e^{-by} = Ai^3 + B^j.$$

In this notebook, we propose a methodology that pays off when the calculation of the arrays is expensive.

import numpy as np
import os
Nx, Ny = 200, 100
dx, dy = 0.01, 0.01
a = 12; b = 11;
A = a * dx; B = np.exp(-b)

For function $f$, we pre-calculate the 2D array:

# define the function
def f(ix,iy):
    return A*ix**3*B**iy

# store the array on disk (with a and b values on the file name)
filename = f'array_f_{a}_{b}.npz'

if not os.path.exists(filename): # if file does not exist, create it:
    # calculate the array
    print("calculating array...")
    array_f = np.empty((Nx,Ny))
    for i in range(Nx):
        for j in range(Ny):
            array_f[i][j] = f(i,j)
    print("storing array...")
    np.savez_compressed(filename, array_f=array_f)
else: # if it exists, load it
    print("array exists on disk, loading...")
    data = np.load(filename)
    array_f = data['array_f']

# redefine the function
def f(ix,iy):
    return array_f[ix,iy]
array exists on disk, loading...

In the case of g function, notice how the $x$ and $y$ parts are additive. It is better to calculate them separately and store them in 1D arrays.

# define the function
def gx(ix):
    return A*ix**3
def gy(iy):
    return B**iy

# store the arrays on disk (with a and b values on the file name)
filename2x = f'array_gx_{a}_{b}.npz'
filename2y = f'array_gy_{a}_{b}.npz'

if not os.path.exists(filename2x) and not os.path.exists(filename2y): # if files do not exist, create them:
    # calculate the arrays
    print("calculating arrays...")
    array_gx = np.empty(Nx)
    array_gy = np.empty(Ny)
    for i in range(Nx):
        array_gx[i] = gx(i)
    for i in range(Ny):
        array_gy[i] = gy(i)
        
    print("storing arrays...")
    np.savez_compressed(filename2x, array_gx=array_gx)
    np.savez_compressed(filename2y, array_gy=array_gy)
else: # if they exist, load them
    print("arrays exist on disk, loading...")
    data2x = np.load(filename2x)
    data2y = np.load(filename2y)
    array_gx = data2x['array_gx']
    array_gy = data2y['array_gy']

def g(ix,iy):
    return array_gx[ix] + array_gy[iy]
arrays exist on disk, loading...
print(f(20,30))
print(g(20,30))
4.624791998345352e-141
960.0