|
16 | 16 | plt.close("all")
|
17 | 17 | np.random.seed(42)
|
18 | 18 |
|
| 19 | +# MPI parameters |
| 20 | +size = MPI.COMM_WORLD.Get_size() # number of nodes |
| 21 | +rank = MPI.COMM_WORLD.Get_rank() # rank of current node |
| 22 | + |
| 23 | + |
19 | 24 | # Defining the global shape of the distributed array
|
20 | 25 | global_shape = (10, 5)
|
21 | 26 |
|
22 | 27 | ###############################################################################
|
23 |
| -# Let's start by defining the |
24 |
| -# class with the input parameters ``global_shape``, |
25 |
| -# ``partition``, and ``axis``. Here's an example implementation of the class with ``axis=0``. |
| 28 | +# Let's start by defining the class with the input parameters ``global_shape``, |
| 29 | +# ``partition``, and ``axis``. Here's an example implementation of the class |
| 30 | +# with ``axis=0``. |
26 | 31 | arr = pylops_mpi.DistributedArray(global_shape=global_shape,
|
27 | 32 | partition=pylops_mpi.Partition.SCATTER,
|
28 | 33 | axis=0)
|
|
72 | 77 | pylops_mpi.plot_local_arrays(arr2, "Distributed Array - 2", vmin=0, vmax=1)
|
73 | 78 |
|
74 | 79 | ###############################################################################
|
| 80 | +# Let's move now to consider various operations that one can perform on |
| 81 | +# :py:class:`pylops_mpi.DistributedArray` objects. |
| 82 | +# |
75 | 83 | # **Scaling** - Each process operates on its local portion of
|
76 | 84 | # the array and scales the corresponding elements by a given scalar.
|
77 | 85 | scale_arr = .5 * arr1
|
|
101 | 109 | # of the array and multiplies the corresponding elements together.
|
102 | 110 | mult_arr = arr1 * arr2
|
103 | 111 | pylops_mpi.plot_local_arrays(mult_arr, "Multiplication", vmin=0, vmax=1)
|
| 112 | + |
| 113 | +############################################################################### |
| 114 | +# Finally, let's look at the case where parallelism could be applied over |
| 115 | +# multiple axes - and more specifically one belonging to the model/data and one |
| 116 | +# to the operator. This kind of "2D"-parallelism requires repeating parts of |
| 117 | +# the model/data over groups of ranks. However, when global operations such as |
| 118 | +# ``dot`` or ``norm`` are applied on a ``pylops_mpi.DistributedArray`` of |
| 119 | +# this kind, we need to ensure that the repeated portions to do all contribute |
| 120 | +# to the computation. This can be achieved via the ``mask`` input parameter: |
| 121 | +# a list of size equal to the number of ranks, whose elements contain the index |
| 122 | +# of the subgroup/subcommunicator (with partial arrays in different groups |
| 123 | +# are identical to each other). |
| 124 | + |
| 125 | +# Defining the local and global shape of the distributed array |
| 126 | +local_shape = 5 |
| 127 | +global_shape = local_shape * size |
| 128 | + |
| 129 | +# Create mask |
| 130 | +nsub = 2 |
| 131 | +subsize = max(1, size // nsub) |
| 132 | +mask = np.repeat(np.arange(size // subsize), subsize) |
| 133 | +if rank == 0: |
| 134 | + print("1D masked arrays") |
| 135 | + print(f"Mask: {mask}") |
| 136 | + |
| 137 | +# Create and fill the distributed array |
| 138 | +x = pylops_mpi.DistributedArray(global_shape=global_shape, |
| 139 | + partition=Partition.SCATTER, |
| 140 | + mask=mask) |
| 141 | +x[:] = (MPI.COMM_WORLD.Get_rank() % subsize + 1.) * np.ones(local_shape) |
| 142 | +xloc = x.asarray() |
| 143 | + |
| 144 | +# Dot product |
| 145 | +dot = x.dot(x) |
| 146 | +dotloc = np.dot(xloc[local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)], |
| 147 | + xloc[local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)]) |
| 148 | +print(f"Dot check (Rank {rank}): {np.allclose(dot, dotloc)}") |
| 149 | + |
| 150 | +# Norm |
| 151 | +norm = x.norm(ord=2) |
| 152 | +normloc = np.linalg.norm(xloc[local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)], |
| 153 | + ord=2) |
| 154 | +print(f"Norm check (Rank {rank}): {np.allclose(norm, normloc)}") |
| 155 | + |
| 156 | +############################################################################### |
| 157 | +# And with 2d-arrays distributed over axis=1 |
| 158 | +extra_dim_shape = 2 |
| 159 | +if rank == 0: |
| 160 | + print("2D masked arrays (over axis=1)") |
| 161 | + |
| 162 | +# Create and fill the distributed array |
| 163 | +x = pylops_mpi.DistributedArray(global_shape=(extra_dim_shape, global_shape), |
| 164 | + partition=Partition.SCATTER, |
| 165 | + axis=1, mask=mask) |
| 166 | +x[:] = (MPI.COMM_WORLD.Get_rank() % subsize + 1.) * np.ones((extra_dim_shape, local_shape)) |
| 167 | +xloc = x.asarray() |
| 168 | + |
| 169 | +# Dot product |
| 170 | +dot = x.dot(x) |
| 171 | +dotloc = np.dot(xloc[:, local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)].ravel(), |
| 172 | + xloc[:, local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)].ravel()) |
| 173 | +print(f"Dot check (Rank {rank}): {np.allclose(dot, dotloc)}") |
| 174 | + |
| 175 | +# Norm |
| 176 | +norm = x.norm(ord=2, axis=1) |
| 177 | +normloc = np.linalg.norm(xloc[:, local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)], |
| 178 | + ord=2, axis=1) |
| 179 | +print(f"Norm check (Rank {rank}): {np.allclose(norm, normloc)}") |
| 180 | + |
| 181 | +############################################################################### |
| 182 | +# And finally with 2d-arrays distributed over axis=0 |
| 183 | +if rank == 0: |
| 184 | + print("2D masked arrays (over axis=0)") |
| 185 | + |
| 186 | +# Create and fill the distributed array |
| 187 | +x = pylops_mpi.DistributedArray(global_shape=(global_shape, extra_dim_shape), |
| 188 | + partition=Partition.SCATTER, |
| 189 | + axis=0, mask=mask) |
| 190 | +x[:] = (MPI.COMM_WORLD.Get_rank() % subsize + 1.) * np.ones((local_shape, extra_dim_shape)) |
| 191 | +xloc = x.asarray() |
| 192 | + |
| 193 | +# Dot product |
| 194 | +dot = x.dot(x) |
| 195 | +dotloc = np.dot(xloc[local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)].ravel(), |
| 196 | + xloc[local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)].ravel()) |
| 197 | +print(f"Dot check (Rank {rank}): {np.allclose(dot, dotloc)}") |
| 198 | + |
| 199 | +# Norm |
| 200 | +norm = x.norm(ord=2, axis=0) |
| 201 | +normloc = np.linalg.norm(xloc[local_shape * subsize * (rank // subsize):local_shape * subsize * (rank // subsize + 1)], |
| 202 | + ord=2, axis=0) |
| 203 | +print(f"Norm check (Rank {rank}): {np.allclose(norm, normloc)}") |
0 commit comments