I've updated the following packages:


- ~~chore: update lxml to 4.8.0~~
- chore: update MarkupSafe to 2.1.0
- chore: update astropy to 5.0.1
- chore: update logbook to 1.5.3
- chore: update regex to 2022.1.18
- chore: update sqlalchemy to 1.4.31
- chore: updated cffi to 1.15.0
- chore: updated imageio to 2.16.1
- chore: updated setuptools to 60.9.3
- chore: updated pytest to 7.0.1
- chore: updated typing-extensions to 4.1.1
- chore: updated pyrsistent to 0.18.1
- chore: updated threadpoolctl to 3.1.0

I wasn't sure how caching was done (if I update numpy, etc. all at once will
that blow up the CI build time?), and I'm hoping to avoid failures, so I left
the big or patched ones alone. Was after lxml (see #2225), but thought I'd get a couple other ones while at it. Removed it, having an issue so will be bumped separately.

* matplotlib 3.3.3 ❌ -> 3.5.1
* nltk 3.6.7 ❌ -> 3.7
* numpy 1.21.4 ❌ -> 1.22.2
* pandas 1.3.5 ❌ -> 1.4.1
* pillow 9.0.0 ❌ -> 9.0.1
* pyrsistent 0.18.0 ❌ -> 0.18.1
* python-sat 0.1.7.dev15 ❌ -> 0.1.7.dev16
* scikit-image 0.19.1 ❌ -> 0.19.2
* scipy 1.7.3 ❌ -> 1.8.0
* statsmodels 0.13.1 ❌ -> 0.13.2
* swiglpk 5.0.3 ❌ -> 5.0.4
* yt 3.6.1 ❌ -> 4.0.2
* zarr 2.10.3 ❌ -> 2.11.0

chore: some package updates. I've updated the following packages:


- ~~chore: update lxml to 4.8.0~~
- chore: update MarkupSafe to 2.1.0
- chore: update astropy to 5.0.1
- chore: update logbook to 1.5.3
- chore: update regex to 2022.1.18
- chore: update sqlalchemy to 1.4.31
- chore: updated cffi to 1.15.0
- chore: updated imageio to 2.16.1
- chore: updated setuptools to 60.9.3
- chore: updated pytest to 7.0.1
- chore: updated typing-extensions to 4.1.1
- chore: updated pyrsistent to 0.18.1
- chore: updated threadpoolctl to 3.1.0

I wasn't sure how caching was done (if I update numpy, etc. all at once will
that blow up the CI build time?), and I'm hoping to avoid failures, so I left
the big or patched ones alone. Was after lxml (see #2225), but thought I'd get a couple other ones while at it. Removed it, having an issue so will be bumped separately.

* matplotlib 3.3.3 ❌ -> 3.5.1
* nltk 3.6.7 ❌ -> 3.7
* numpy 1.21.4 ❌ -> 1.22.2
* pandas 1.3.5 ❌ -> 1.4.1
* pillow 9.0.0 ❌ -> 9.0.1
* pyrsistent 0.18.0 ❌ -> 0.18.1
* python-sat 0.1.7.dev15 ❌ -> 0.1.7.dev16
* scikit-image 0.19.1 ❌ -> 0.19.2
* scipy 1.7.3 ❌ -> 1.8.0
* statsmodels 0.13.1 ❌ -> 0.13.2
* swiglpk 5.0.3 ❌ -> 5.0.4
* yt 3.6.1 ❌ -> 4.0.2
* zarr 2.10.3 ❌ -> 2.11.0

# setup: import numpy as np ; N = 20 ; x = y = z = np.arange(0., N, 0.1) ; L = 4 ; periodic = True  # noqa
# run: periodic_dist(x, x, x, L,periodic, periodic, periodic)

# pythran export periodic_dist(float [], float[], float[], int, bool,
# bool, bool)
import numpy as np


def periodic_dist(x, y, z, L, periodicX, periodicY, periodicZ):
    """Computes distances between all particles and places the result
    in a matrix such that the ij th matrix entry corresponds to the
    distance between particle i and j"""
    N = len(x)
    xtemp = np.tile(x, (N, 1))
    dx = xtemp - xtemp.T
    ytemp = np.tile(y, (N, 1))
    dy = ytemp - ytemp.T
    ztemp = np.tile(z, (N, 1))
    dz = ztemp - ztemp.T

    # Particles 'feel' each other across the periodic boundaries
    if periodicX:
        dx[dx > L / 2] = dx[dx > L / 2] - L
        dx[dx < -L / 2] = dx[dx < -L / 2] + L

    if periodicY:
        dy[dy > L / 2] = dy[dy > L / 2] - L
        dy[dy < -L / 2] = dy[dy < -L / 2] + L

    if periodicZ:
        dz[dz > L / 2] = dz[dz > L / 2] - L
        dz[dz < -L / 2] = dz[dz < -L / 2] + L

    # Total Distances
    d = np.sqrt(dx**2 + dy**2 + dz**2)

    # Mark zero entries with negative 1 to avoid divergences
    d[d == 0] = -1

    return d, dx, dy, dz

# setup: import numpy as np ; N = 20 ; x = y = z = np.arange(0., N, 0.1) ; L = 4 ; periodic = True  # noqa
# run: periodic_dist(x, x, x, L,periodic, periodic, periodic)

# pythran export periodic_dist(float [], float[], float[], int, bool,
# bool, bool)
import numpy as np


def periodic_dist(x, y, z, L, periodicX, periodicY, periodicZ):
    """Computes distances between all particles and places the result
    in a matrix such that the ij th matrix entry corresponds to the
    distance between particle i and j"""
    N = len(x)
    xtemp = np.tile(x, (N, 1))
    dx = xtemp - xtemp.T
    ytemp = np.tile(y, (N, 1))
    dy = ytemp - ytemp.T
    ztemp = np.tile(z, (N, 1))
    dz = ztemp - ztemp.T

    # Particles 'feel' each other across the periodic boundaries
    if periodicX:
        dx[dx > L / 2] = dx[dx > L / 2] - L
        dx[dx < -L / 2] = dx[dx < -L / 2] + L

    if periodicY:
        dy[dy > L / 2] = dy[dy > L / 2] - L
        dy[dy < -L / 2] = dy[dy < -L / 2] + L

    if periodicZ:
        dz[dz > L / 2] = dz[dz > L / 2] - L
        dz[dz < -L / 2] = dz[dz < -L / 2] + L

    # Total Distances
    d = np.sqrt(dx**2 + dy**2 + dz**2)

    # Mark zero entries with negative 1 to avoid divergences
    d[d == 0] = -1

    return d, dx, dy, dz
