user5019516
user5019516

Reputation:

Splitting Python MeshGrid Into Cells

Problem Statement

Need to split an N-Dimensional MeshGrid into "cubes":

Ex) 2-D Case:

(-1,1) |(0,1) |(1,1)

(-1,0) |(0,0) |(1,0)

(-1,-1)|(0,-1)|(1,-1)

There will be 4 cells, each with 2^D points:

I want to be able to process the mesh, placing the coordinate points of each cell into a container to do further processing.

Cells =   [{(-1,1) (0,1)(-1,0),(0,0)},

          {(0,1),(1,1),(0,0),(1,0)},

          {(-1,0),(0,0)(-1,-1),(0,-1)}

          {(0,0),(1,0)(0,-1),(1,-1)}]

I use the following to generate the mesh for an arbitrary dimension d:

grid = [np.linspace(-1.0 , 1.0, num = K+1) for i in range(d)]
res_to_unpack = np.meshgrid(*grid,indexing = 'ij')

Which has output:

[array([[-1., -1., -1.],
   [ 0.,  0.,  0.],
   [ 1.,  1.,  1.]]), array([[-1.,  0.,  1.],
   [-1.,  0.,  1.],
   [-1.,  0.,  1.]])]

So I want to be able to generate the above cells container for a given D dimensional mesh grid. Split on a given K that is a power of 2.

I need this container so for each cell, I need to reference all 2^D points associated and calculate the distance from an origin.

Edit For Clarification

K should partition the grid into K ** D number of cells, with (K+1) ** D points. Each Cell should have 2 ** D number of points. Each "cell" will have volume (2/K)^D.

So for K = 4, D = 2

Cells = [ {(-1,1),(-0.5,1),(-1,0.5),(-0.5,0.5)},
          {(-0.5,1),(-0.5,0.5)(0.0,1.0),(0,0.5)},
            ...
          {(0.0,-0.5),(0.5,-0.5),(0.0,-1.0),(0.5,-1.0)},
          {(0.5,-1.0),(0.5,-1.0),(1.0,-0.5),(1.0,-1.0)}]

This is output for TopLeft, TopLeft + Right Over, Bottom Left, Bottom Left + Over Left. There will we 16 cells in this set, each with four coordinates each. For increasing K, say K = 8. There will be 64 cells, each with four points.

Upvotes: 2

Views: 1866

Answers (1)

tel
tel

Reputation: 13999

This should give you what you need:

from itertools import product
import numpy as np

def splitcubes(K, d):
    coords = [np.linspace(-1.0 , 1.0, num=K + 1) for i in range(d)]
    grid = np.stack(np.meshgrid(*coords)).T

    ks = list(range(1, K))
    for slices in product(*([[slice(b,e) for b,e in zip([None] + ks, [k+1 for k in ks] + [None])]]*d)):
        yield grid[slices]

def cubesets(K, d):
    if (K & (K - 1)) or K < 2:
        raise ValueError('K must be a positive power of 2. K: %s' % K)

    return [set(tuple(p.tolist()) for p in c.reshape(-1, d)) for c in splitcubes(K, d)]

Demonstration of 2D case

Here's a little demonstration of the 2D case:

import matplotlib.pyplot as plt

def assemblecube(c, spread=.03):
    c = np.array(list(c))
    c = c[np.lexsort(c.T[::-1])]

    d = int(np.log2(c.size))
    for i in range(d):
        c[2**i:2**i + 2] = c[2**i + 1:2**i - 1:-1]

    # get the point farthest from the origin
    sp = c[np.argmax((c**2).sum(axis=1)**.5)]
    # shift all points a small distance towards that farthest point
    c += sp * .1 #np.copysign(np.ones(sp.size)*spread, sp)

    # create several different orderings of the same points so that matplotlib will draw a closed shape
    return [(np.roll(c, i, axis=1) - (np.roll(c, i, axis=1)[0] - c[0])[None,:]).T for i in range(d)]

fig = plt.figure(figsize=(6,6))
ax = fig.gca()

for i,c in enumerate(cubesets(4, 2)):
    for cdata in assemblecube(c):
        p = ax.plot(*cdata, c='C%d' % (i % 9))

ax.set_aspect('equal', 'box')
fig.show()

Output:

enter image description here

The cubes have been shifted slightly apart for visualization purposes (so they don't overlap and cover each other up).

Demonstration of 3D case

Here's the same thing for the 3D case:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(111, projection='3d')

for i,c in enumerate(cubesets(2,3)):
    for cdata in assemblecube(c, spread=.05):
        ax.plot(*cdata, c=('C%d' % (i % 9)))

plt.gcf().gca().set_aspect('equal', 'box')
plt.show()

Output:

enter image description here

Demonstration for K=4

Here's the output for the same 2D and 3D demonstrations as above, but with K=4:

enter image description here

enter image description here

Upvotes: 8

Related Questions