MPSlib: Variable template size in mps_snesim_tree and mps_snesim_list

mps_snesim_tree and mps_snesim_list support a template size that changes for each multiple grid level. The template size is specified for the coarsest multiple grid and for the final dense simulation grid; linear interpolation is used at intermediate levels.

For example, using a template size of 8x7x4 on the coarsest grid and 4x3x3 on the finest:

Search template size X # 8 4
Search template size Y # 7 3
Search template size Z # 4 3

This can be set in Python using:

O = mps.mpslib(method='mps_snesim_tree')
O.par['template_size'] = np.array([[8, 7, 4], [4, 3, 3]]).T

A simple constant template of size [8, 7, 4] can be set using:

O.par['template_size'] = np.array([8, 7, 4])

The main reason for using a variable template size is that a considerable amount of CPU is spent in the finer simulation grids pruning (removing) conditional data. Reducing the template at the finest grid can yield significant speedups.

See more at https://mpslib.readthedocs.io/en/latest/Examples/ex_varying_template.html

[1]:
import mpslib as mps
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

Setup

[2]:
#TI1, TI_filename1 = mps.trainingimages.strebelle(2, coarse3d=1)
TI1, TI_filename1 = mps.trainingimages.strebelle(1, coarse3d=1)

O1 = mps.mpslib(method='mps_snesim_tree')
O1.ti = TI1
O1.par['n_multiple_grids'] = 4
O1.par['n_cond'] = 81
O1.par['n_real'] = 1
O1.par['rseed'] = 1
O1.par['debug_level'] = -1
O1.par['simulation_grid_size'][0] = 135
O1.par['simulation_grid_size'][1] = 100
O1.par['simulation_grid_size'][2] = 1

Sweep over template sizes at the finest grid

Fix the coarse-grid template size at 11, and vary the fine-grid template size from 11 down to 1.

[3]:
r1 = 11  # Template size on the coarsest grid
r2 = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]  # Template size on the finest grid

t = []
R = []
for ir in range(len(r2)):

    O1.delete_local_files()

    template = np.array([[r1, r2[ir]], [r1, r2[ir]], [1, 1]])
    O1.par['template_size'] = template
    name = '%s_%d_%d' % (O1.method, r1, r2[ir])
    print(name)
    O1.parameter_filename = name + '.par'
    O1.mps_snesim_par_write()
    O1.run()
    R.append(O1.sim[0])
    t.append(O1.time)
mps_snesim_tree_11_11
mps_snesim_tree_11_10
mps_snesim_tree_11_9
mps_snesim_tree_11_8
mps_snesim_tree_11_7
mps_snesim_tree_11_6
mps_snesim_tree_11_5
mps_snesim_tree_11_4
mps_snesim_tree_11_3
mps_snesim_tree_11_2
mps_snesim_tree_11_1

Plot realizations and computation time

[4]:
fig = plt.figure(figsize=(15, 15))
outer = gridspec.GridSpec(4, 3, wspace=0.2, hspace=0.2)

for ir in range(len(r2)):
    ax1 = plt.Subplot(fig, outer[ir])
    fig.add_subplot(ax1)
    plt.imshow(np.transpose(np.squeeze(R[ir])))
    plt.title('template=[%d,%d], t=%g s' % (r1, r2[ir], t[ir]))

ax1 = plt.Subplot(fig, outer[-1])
fig.add_subplot(ax1)
plt.bar(r2, t)
plt.xlabel('Template size at fine grid')
plt.ylabel('Computation time (s)')
plt.savefig('varying_template', dpi=600, facecolor='w', edgecolor='w',
            orientation='portrait', transparent=True)
plt.show()
../_images/Notebooks_ex_snesim_varying_template_7_0.png

Speedup relative to full template

[5]:
fig = plt.figure(figsize=(5, 5))
plt.bar(r2, t[0] / np.array(t))
plt.xlabel('Template size at fine grid')
plt.ylabel('Speedup compared to using full template')
plt.grid()
plt.savefig('varying_template_speedup', dpi=600, facecolor='w', edgecolor='w',
            orientation='portrait', transparent=True)
plt.show()
../_images/Notebooks_ex_snesim_varying_template_9_0.png