coxeter#

JOSS ReadTheDocs PyPI conda-forge

Welcome to the documentation for coxeter! The coxeter Python library provides tools for working with common geometric objects in two and three dimensions. Named for the 20th century geometer best known for his work on polytopes, coxeter is especially focused on polygons and polyhedra, but it also support various standard curved shapes such as spheres and ellipsoids.

The package emphasizes working with shapes as mutable objects whose geometric attributes may be accessed using property-based APIs. Since coxeter originally arose to support representations of anisotropic nanoparticles, many shapes support calculations of physical properties (such as form factors and inertia tensors) in addition to purely geometric ones. However, the package is designed with more general audiences in mind as well, and it aims to support precise calculations of a wide range of geometric quantities that are useful in a number of fields.

Some core features of coxeter include:

  • Libraries of common shapes to support easy construction.

  • Mutable shape objects that can be rescaled in a variety of ways to suit a number of needs.

  • Immediate access to geometric properties of shapes via Python properties of shape objects.

  • Plotting functionality to make it easy to visualize shapes in both two and three dimensions.

More detailed information on coxeter’s features and examples of how to use them may be found in the documentation.

Setup#

The recommended methods for installing coxeter are using pip or conda.

Installation via pip#

To install the package from PyPI, execute:

pip install coxeter --user

Installation via conda#

To install the package from conda, first add the conda-forge channel:

conda config --add channels conda-forge

After the conda-forge channel has been added, you can install coxeter by executing

conda install coxeter

Installation from source#

Start by executing the following:

git clone https://github.com/glotzerlab/coxeter.git
cd coxeter

To install coxeter and other optional dependencies, choose one of the following:

pip install . # Install with no additional dependencies
pip install .[tests] # RECOMMENDED: Install with dependencies required to run pytests
pip install .[tests,doc] # Install all dependencies required to develop for coxeter

Requirements#

  • Python >= 3.8

  • NumPy >= 1.19.0

  • SciPy >= 1.0.0

  • rowan >= 1.2.0

Testing#

The package is currently tested for Python >= 3.8 on Unix-like systems. Continuous integrated testing is performed using Github actions on these Python versions.

First, install the packages required to test coxeter (if not already done):

pip install -r tests/requirements.txt

To run the packaged unit tests, execute the following line from the root of the repository:

pytest

To run the packaged unit tests with the coverage module:

pytest --cov=coxeter

Building Documentation#

Documentation for coxeter is written in reStructuredText and compiled using Sphinx. To build the documentation, first install Sphinx and the other required packages:

pip install -r doc/requirements.txt
conda install -c conda-forge fresnel

Warning

The fresnel package on conda-forge must be used. The PyPI package fresnel is different and will not function properly.

You can then use Sphinx to create the actual documentation in either PDF or HTML form by running the following commands:

cd doc
make html # For html output
make latexpdf # For a LaTeX compiled PDF file
open build/html/index.html

Support and Contribution#

This package is hosted on GitHub. Please report any bugs or problems that you find on the issue tracker. All contributions to coxeter are welcomed via pull requests!

Introduction#

JOSS ReadTheDocs PyPI conda-forge

Welcome to the documentation for coxeter! The coxeter Python library provides tools for working with common geometric objects in two and three dimensions. Named for the 20th century geometer best known for his work on polytopes, coxeter is especially focused on polygons and polyhedra, but it also support various standard curved shapes such as spheres and ellipsoids.

The package emphasizes working with shapes as mutable objects whose geometric attributes may be accessed using property-based APIs. Since coxeter originally arose to support representations of anisotropic nanoparticles, many shapes support calculations of physical properties (such as form factors and inertia tensors) in addition to purely geometric ones. However, the package is designed with more general audiences in mind as well, and it aims to support precise calculations of a wide range of geometric quantities that are useful in a number of fields.

Some core features of coxeter include:

  • Libraries of common shapes to support easy construction.

  • Mutable shape objects that can be rescaled in a variety of ways to suit a number of needs.

  • Immediate access to geometric properties of shapes via Python properties of shape objects.

  • Plotting functionality to make it easy to visualize shapes in both two and three dimensions.

Installation#

Setup#

The recommended methods for installing coxeter are using pip or conda.

Installation via pip#

To install the package from PyPI, execute:

pip install coxeter --user

Installation via conda#

To install the package from conda, first add the conda-forge channel:

conda config --add channels conda-forge

After the conda-forge channel has been added, you can install coxeter by executing

conda install coxeter

Installation from source#

Start by executing the following:

git clone https://github.com/glotzerlab/coxeter.git
cd coxeter

To install coxeter and other optional dependencies, choose one of the following:

pip install . # Install with no additional dependencies
pip install .[tests] # RECOMMENDED: Install with dependencies required to run pytests
pip install .[tests,doc] # Install all dependencies required to develop for coxeter

Requirements#

  • Python >= 3.8

  • NumPy >= 1.19.0

  • SciPy >= 1.0.0

  • rowan >= 1.2.0

Testing#

The package is currently tested for Python >= 3.8 on Unix-like systems. Continuous integrated testing is performed using Github actions on these Python versions.

First, install the packages required to test coxeter (if not already done):

pip install -r tests/requirements.txt

To run the packaged unit tests, execute the following line from the root of the repository:

pytest

To run the packaged unit tests with the coverage module:

pytest --cov=coxeter

Building Documentation#

Documentation for coxeter is written in reStructuredText and compiled using Sphinx. To build the documentation, first install Sphinx and the other required packages:

pip install -r doc/requirements.txt
conda install -c conda-forge fresnel

Warning

The fresnel package on conda-forge must be used. The PyPI package fresnel is different and will not function properly.

You can then use Sphinx to create the actual documentation in either PDF or HTML form by running the following commands:

cd doc
make html # For html output
make latexpdf # For a LaTeX compiled PDF file
open build/html/index.html

Quickstart Tutorial#

Once you have installed coxeter, most workflows involve creating an instance of a shape, such as a Polygon:

>>> import coxeter
>>> square = coxeter.shapes.Polygon([[0, 0], [1, 0], [1, 1], [0, 1]])

All shapes may be found in the coxeter.shapes subpackage and are created in a similar manner. For instance, making a sphere requires a radius: sphere = coxeter.shapes.Sphere(3). Once you have a shape, you can immediately query it for properties.

>>> square.vertices
array([[0., 0., 0.],
       [1., 0., 0.],
       [1., 1., 0.],
       [0., 1., 0.]])
>>> square.area
1.0
>>> square.perimeter
4.0

The coxeter library comes with a range of shape families, collections of shapes with standard definitions so that you don’t have to parameterize them yourself. The regular \(n\)-gon family is such an example, provided as coxeter.families.RegularNGonFamily.

>>> hexagon = coxeter.families.RegularNGonFamily.get_shape(6)
>>> hexagon.vertices.round(2)
array([[ 0.62,  0.  ,  0.  ],
       [ 0.31,  0.54,  0.  ],
       [-0.31,  0.54,  0.  ],
       [-0.62,  0.  ,  0.  ],
       [-0.31, -0.54,  0.  ],
       [ 0.31, -0.54,  0.  ]])

Part of what makes coxeter so powerful is that all shapes are mutable. This means that once you have a prototype of a shape, it can be modified to fit a specific need. For example, the snippet below finds the area of the smallest regular pentagon that contains an equilateral triangle of unit area:

>>> triangle = coxeter.families.RegularNGonFamily.get_shape(3)
>>> pentagon = coxeter.families.RegularNGonFamily.get_shape(5)
>>> pentagon.incircle_radius = triangle.circumcircle.radius
>>> triangle.area
0.9999999999999999
>>> triangle.circumcircle.area
2.418399152312292
>>> pentagon.area
2.796463494144044

This tutorial just scratches the surface of the features coxeter offers. For more complete demonstrations of the package’s features, see the Examples.

Examples#

While coxeter’s API is very easy to work with, it can be helpful to see some real demonstrations of how it can be used. Here we include some practical examples of using coxeter.

Checking if points lie in a shape#

For the purpose of tasks like Monte Carlo integration it is often useful to check if points are inside a shape. coxeter makes it easy to check this for various shapes, as we’ll demonstrate here.

[1]:
import numpy as np
from matplotlib import patches
from matplotlib import pyplot as plt

import coxeter
[2]:
def plot_polygon(vertices):
    """Convenience function to plot a nonconvex polygon from a set of vertices."""
    fig, ax = plt.subplots(figsize=(6, 6))
    polygon_plot = ax.add_patch(
        patches.Polygon(vertices[:, :2], fill=False, linewidth=7, edgecolor="k")
    )

    ax.tick_params(bottom=False, left=False, labelbottom=False, labelleft=False)
    for spine in ax.spines.values():
        spine.set_visible(False)
    fig.tight_layout()
    ax.set_xlim([-1.1, 1.1])
    ax.set_ylim([-1.1, 1.1])

    return fig, ax

We start by generating a nontrivial polygon and visualizing it.

[3]:
vertices = (
    np.array(
        [
            [5, 0],
            [4, 4],
            [2, 2],
            [0, 5],
            [-1, 3],
            [-3, 4],
            [-5, 0],
            [-3, -4],
            [-1, -2],
            [2, -5],
        ]
    )
    / 5
)
[4]:
plot_polygon(vertices)
[4]:
(<Figure size 600x600 with 1 Axes>, <Axes: >)
_images/examples_PointInShape_5_1.png

Now we generate a set of points somewhere in the \((-1, 1)\) range in \(x\) and \(y\). Some of these points will lie inside the shape, while others will lie outside. We’ll create a coxeter Polygon from the vertices above, then use it to check which points lie inside the shape.

[5]:
polygon = coxeter.shapes.Polygon(vertices)

# This seed gives a reasonable set of points.
np.random.seed(38023)
test_points = np.random.rand(40, 3) * 2 - 1
test_points[:, 2] = 0
is_inside = polygon.is_inside(test_points)

Finally, we replot the polygon, and this time we also plot all the test points. We will color code them, using red to indicate points outside the shape and blue for points inside.

[6]:
fig, ax = plot_polygon(vertices)
ax.scatter(test_points[is_inside][:, 0], test_points[is_inside][:, 1], c="blue", s=300)
ax.scatter(test_points[~is_inside][:, 0], test_points[~is_inside][:, 1], c="red", s=300)
[6]:
<matplotlib.collections.PathCollection at 0x7f48442eef30>
_images/examples_PointInShape_9_1.png

Measuring the distance to shape surfaces#

The distance from the center of a shape to its surface is a useful quantity in various situations. For instance, when the shape represents a vacancy in a crystal, we may wish to know how far the vacancy extends in certain directions. Another useful example is perturbative theories that treat various geometries relative to their inscribed spheres. Here we’ll see how coxeter can be used to compute this quantity for a shape.

[16]:
import numpy as np
from matplotlib import patches
from matplotlib import pyplot as plt

import coxeter
[45]:
def plot_distances(shape, vectors, colors):
    """Plot vectors from the center of a shape with suitable labeling."""
    fig, ax = plt.subplots(figsize=(4, 4))

    for v, c in zip(vectors, colors):
        ax.add_patch(
            patches.FancyArrow(
                x=shape.center[0],
                y=shape.center[1],
                dx=v[0],
                dy=v[1],
                width=0.02,
                color=c,
                length_includes_head=True,
                label=f"{np.linalg.norm(v):0.2f}",
            )
        )

    ax.legend(fontsize=18, bbox_to_anchor=(1.05, 0.75))

    # Pad the extent so the shapes edges aren't cut off.
    extent = shape.minimal_bounding_circle.radius + 0.02
    ax.set_xlim([-extent, extent])
    ax.set_ylim([-extent, extent])
    for spine in ax.spines.values():
        spine.set_visible(False)
    ax.tick_params(labelbottom=False, labelleft=False, bottom=False, left=False)
    return fig, ax

Using the handy plotting function defined above, we visualize distance vectors computed using coxeter. We’ll show how this works for both pentagons and ellipses.

[38]:
# These are the directions in which we'll find distances to the shape surfaces.
random_angles = np.array([0.75 * np.pi, 1.5 * np.pi, 0])
unit_vectors = np.vstack((np.cos(random_angles), np.sin(random_angles))).T
colors = ("r", "b", "g")

# Create a pentagon.
pentagon = coxeter.families.RegularNGonFamily.get_shape(5)

# Create a unit area ellipse.
ellipse = coxeter.shapes.Ellipse(3, 4)
ellipse.area = 1
[46]:
vectors = unit_vectors * pentagon.distance_to_surface(random_angles)[:, np.newaxis]
fig, ax = plot_distances(pentagon, vectors, colors)
ax.add_patch(
    patches.Polygon(pentagon.vertices[:, :2], fill=False, linewidth=2, edgecolor="k")
)
_images/examples_DistanceToSurface_6_0.png
[47]:
vectors = unit_vectors * ellipse.distance_to_surface(random_angles)[:, np.newaxis]
fig, ax = plot_distances(ellipse, vectors, colors)
ax.add_patch(
    patches.Ellipse(
        (0, 0), 2 * ellipse.a, 2 * ellipse.b, fill=False, linewidth=2, edgecolor="k"
    )
)
_images/examples_DistanceToSurface_7_0.png

Calculating inertia tensors of shapes#

Computing the inertia tensor of an arbitrary volume in 3D involves a complicated integral. For polytopes, the integral becomes especially complicated because the shape must be broken up into simplices in order to perform the calculation, and making the calculation numerically robust requires careful consideration of how best to perform the calculation. coxeter uses the best available algorithms for different shapes to minimize these errors, making it equally easy to compute moments of inertia for simple shapes like circles and complex ones like polyhedra.

[1]:
import numpy as np
import rowan
from matplotlib import pyplot as plt
from mpl_toolkits import mplot3d

import coxeter
[2]:
def plot_polyhedron(poly, include_tensor=False, length_scale=3):
    """Plot a polyhedron a provided set of matplotlib axes.

    The include_tensor parameter controls whether or not the axes
    of the inertia tensor are plotted. If they are, then the
    length_scale controls how much the axis vectors are extended,
    which is purely for visualization purposes.
    """
    fig, ax = plt.subplots(figsize=(6, 6), subplot_kw={"projection": "3d"})

    # Generate a triangulation for plot_trisurf.
    vertex_to_index = {tuple(v): i for i, v in enumerate(poly.vertices)}
    triangles = [
        [vertex_to_index[tuple(v)] for v in triangle]
        for triangle in poly._surface_triangulation()
    ]

    # Plot the triangulation to get faces, but without any outlines because outlining
    # the triangulation will include lines along faces where coplanar simplices intersect.
    verts = poly.vertices
    ax.plot_trisurf(
        verts[:, 0],
        verts[:, 1],
        verts[:, 2],
        triangles=triangles,
        # Make the triangles partly transparent.
        color=tuple([*plt.get_cmap("tab10").colors[4], 0.3]),
    )

    # Add lines manually.
    for face in poly.faces:
        verts = poly.vertices[face]
        verts = np.concatenate((verts, verts[[0]]))
        ax.plot(verts[:, 0], verts[:, 1], verts[:, 2], c="k", lw=0.4)

    # If requested, plot the axes of the inertia tensor.
    if include_tensor:
        centers = np.repeat(poly.center[np.newaxis, :], axis=0, repeats=3)
        arrows = poly.inertia_tensor * length_scale
        ax.quiver3D(
            centers[:, 0],
            centers[:, 1],
            centers[:, 2],
            arrows[:, 0],
            arrows[:, 1],
            arrows[:, 2],
            color="k",
            lw=3,
        )

    ax.view_init(elev=30, azim=-90)
    limits = np.array([ax.get_xlim3d(), ax.get_ylim3d(), ax.get_zlim3d()])
    center = np.mean(limits, axis=1)
    radius = 0.5 * np.max(limits[:, 1] - limits[:, 0])
    ax.set_xlim([center[0] - radius, center[0] + radius])
    ax.set_ylim([center[1] - radius, center[1] + radius])
    ax.set_zlim([center[2] - radius, center[2] + radius])
    ax.tick_params(which="both", axis="both", labelsize=0)
    fig.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
    fig.tight_layout()

In this notebook, we will demonstrate the inertia tensor calculation using a square pyramid, a shape whose 3D orientation is easy to visualize. First, let’s see what this shape looks like.

[3]:
vertices = np.array(
    [
        [0.0, 0.0, 1.073],
        [0.0, -0.707, -0.634],
        [0.0, -0.707, 0.366],
        [0.0, 0.707, -0.634],
        [0.0, 0.707, 0.366],
        [-0.707, 0.0, -0.634],
        [-0.707, 0.0, 0.366],
        [0.707, 0.0, -0.634],
        [0.707, 0.0, 0.366],
    ]
)
pyramid = coxeter.shapes.ConvexPolyhedron(vertices)
[4]:
plot_polyhedron(pyramid)
print(pyramid.inertia_tensor.round(3))
[[ 0.27  0.   -0.  ]
 [ 0.    0.27  0.  ]
 [-0.    0.    0.19]]
_images/examples_InertiaTensors_5_1.png

Now let’s see what the axes of the inertia tensor are as calculated using coxeter. To make them more prominent, we’ll scale them since we’re not doing any physical calculations where the magnitude is important here. Additionally, we’ll rotate the shape so that it’s principal frame is not aligned to the coordinate axes to make it easier to see the axes of the inertia tensor.

[5]:
rotated_pyramid = coxeter.shapes.ConvexPolyhedron(
    rowan.rotate([-0.6052796, 0.49886219, -0.21305172, 0.58256509], vertices)
)

plot_polyhedron(rotated_pyramid, include_tensor=True, length_scale=3)
print(rotated_pyramid.inertia_tensor.round(3))
[[ 0.214 -0.024 -0.028]
 [-0.024  0.26  -0.012]
 [-0.028 -0.012  0.257]]
_images/examples_InertiaTensors_7_1.png

From this perspective, we can at least two of the axes quite well (the third vector pointing into the screen is largely obscured by the vector pointing up). It is often convenient to work with shapes in their principal frame, i.e. the frame in which the inertia tensor is diagonalized. coxeter makes it easy to diagonalize a shape with a single command.

[6]:
rotated_pyramid.diagonalize_inertia()
plot_polyhedron(rotated_pyramid, include_tensor=True)
print(rotated_pyramid.inertia_tensor.round(3))
[[ 0.19 -0.   -0.  ]
 [-0.    0.27  0.  ]
 [-0.    0.    0.27]]
_images/examples_InertiaTensors_9_1.png

Computing and inspheres and circumspheres#

Under different conditions, various types of spheres containing or contained within a shape can be useful. For example, for spheres contained in a shape we may be interested in the largest sphere contained by a shape, or the largest concentric sphere contained within the shape. For a polyhedron, we may instead want to find the sphere that touches all the faces, if it exists.

[1]:
import fresnel
import numpy as np
from matplotlib import pyplot as plt

import coxeter
[2]:
def plot_polyhedron_with_sphere(shape, insphere=True):
    """Image a polyhedron along with a sphere contained within it."""
    device = fresnel.Device()
    scene = fresnel.Scene(device)

    transparent_material = fresnel.material.Material(
        color=fresnel.color.linear([1, 1, 1]),
        spec_trans=0.95,
        roughness=0.2,
        primitive_color_mix=0.0,
    )
    colored_material = fresnel.material.Material(
        color=fresnel.color.linear([0.9, 0.714, 0.169]),
        roughness=0.8,
    )

    # First make the shape and set up its properties.
    primitive = fresnel.geometry.ConvexPolyhedron(
        scene,
        fresnel.util.convex_polyhedron_from_vertices(shape.vertices),
        N=1,
        outline_width=0.01,
        material=transparent_material if insphere else colored_material,
    )
    primitive.color_by_face = 0.0

    # Now draw the insphere within the shape.
    sphere = fresnel.geometry.Sphere(
        scene,
        N=1,
        material=colored_material if insphere else transparent_material,
    )

    # Make the sphere a little bit smaller than it really is,
    # otherwise you get artifacts near the intersection of the
    # polyhedron and the insphere.
    sphere.radius[:] = [
        shape.insphere.radius * 0.99 if insphere else shape.circumsphere.radius * 1.01
    ]

    scene.camera = fresnel.camera.Orthographic.fit(scene, view="front")
    tracer = fresnel.tracer.Path(device=device, w=300, h=300)
    return tracer.sample(scene, samples=24, light_samples=40)

The Platonic solids are a canonical set of shapes we can use for our analysis. Conveniently, they can easily be generated using coxeter. A good example is the dodecahedron.

[3]:
dodecahedron = coxeter.families.PlatonicFamily.get_shape("Dodecahedron")

We can query different types of spheres from this shape now:

[4]:
# The sphere tangent to all the faces of the polyhedron.
print(dodecahedron.insphere)

# The largest concentric sphere contained in the shape.
print(dodecahedron.maximal_centered_bounded_sphere)
coxeter.shapes.Sphere(radius=0.5648000780281438, center=[-5.551115123125784e-17, -2.220446049250313e-16, -3.23771046624367e-16])
coxeter.shapes.Sphere(radius=0.564800078028144, center=[-1.7347234759768062e-17, -1.1564823173178707e-17, 1.619075244245019e-17])

Let’s visualize what these shapes look like:

[5]:
plot_polyhedron_with_sphere(dodecahedron)
[5]:
_images/examples_Spheres_8_0.png

If we instead want to look at spheres containing a shape, we can get those as well.

[6]:
# The sphere tangent to all the faces of the polyhedron.
print(dodecahedron.circumsphere)

# The largest concentric sphere contained in the shape.
print(dodecahedron.minimal_centered_bounding_sphere)
coxeter.shapes.Sphere(radius=0.7107492598629351, center=[0.0, -2.7755575615628914e-17, -1.1102230246251565e-16])
coxeter.shapes.Sphere(radius=0.7107492598629351, center=[-1.7347234759768062e-17, -1.1564823173178707e-17, 1.619075244245019e-17])
[7]:
plot_polyhedron_with_sphere(dodecahedron, False)
[7]:
_images/examples_Spheres_11_0.png

Anisotropic Form Factors#

Scientists frequently use diffraction patterns to study structure at the nanoscale. In many cases, it is sufficient to model radiation as scattering off of isotropic bodies arranged in an anisotropic manner, as atoms in a crystal. However, in some cases the scatterers may themselves be anisotropic, in which case it is also necessary to account for the different scattering in different directions caused by the shape of the scatterers. In scattering theory, this distinction is captured by splitting the total scattering density into two parts, the structure factor (which describes scattering caused by the arrangement of particles) and the form factor (which describes scattering due to the shapes of the particles). Computing form factors for all but a few shapes can be a difficult matter, so coxeter simplifies that for you.

[1]:
import numpy as np
from matplotlib import pyplot as plt

import coxeter

As a demonstration, let’s use a tetrahedron.

[2]:
R = 1
sphere = coxeter.shapes.Sphere(R)
tetrahedron = coxeter.families.PlatonicFamily.get_shape("Tetrahedron")
tetrahedron.insphere_radius = sphere.radius

The form factor is computed at user-specified vectors in reciprocal space. For example, here’s the form factor of a tetrahedron at a few points in reciprocal space.

[27]:
tetrahedron.compute_form_factor_amplitude(np.array([[1, 0, 0], [2, 0, 0]]))
[27]:
array([10.24019611+0.52644567j,  3.91828341+2.15816328j])

As previously mentioned, a critical property of the form factor is that it is anistropic. This means that the form factor depends on the direction of the incident radiation. To capture this fact, let’s look at how the form factor varies along the three coordinate axes for this tetrahedron. For comparison, we’ll do a comparable calculation for a sphere.

[11]:
q = np.linspace(0.0001, 20, 100)
rho = 0.0005
qR = q * R

q_vectors_x = np.zeros((q.shape[0], 3))
q_vectors_y = np.zeros((q.shape[0], 3))
q_vectors_z = np.zeros((q.shape[0], 3))
q_vectors_x[:, 0] = q
q_vectors_y[:, 1] = q
q_vectors_z[:, 2] = q
F_tet_x = tetrahedron.compute_form_factor_amplitude(q_vectors_x, density=rho)
F_tet_y = tetrahedron.compute_form_factor_amplitude(q_vectors_y, density=rho)
F_tet_z = tetrahedron.compute_form_factor_amplitude(q_vectors_z, density=rho)

The form factor of a sphere is a good baseline for comparison. Since a sphere is isotropic, so is its form factor, and it provides a quantitative basis for comparison to the tetrahedron.

[29]:
F_sphere = sphere.compute_form_factor_amplitude(q_vectors_x, density=rho)

Finally, let’s use a plot to visualize the results.

[32]:
fig, ax = plt.subplots(figsize=(10, 10))
ax.semilogy(qR, (F_sphere.real) ** 2, label="Sphere", lw=5)

scale_factor = F_sphere[0].real / F_tet_x[0].real
ax.semilogy(
    qR, (scale_factor * F_tet_x.real) ** 2 * 4 * np.pi, label="Tetrahedron $x$", lw=5
)
ax.semilogy(
    qR, (scale_factor * F_tet_y.real) ** 2 * 4 * np.pi, label="Tetrahedron $y$", lw=5
)
ax.semilogy(
    qR, (scale_factor * F_tet_z.real) ** 2 * 4 * np.pi, label="Tetrahedron $z$", lw=5
)

ax.legend(loc="best", fontsize=18)
ax.set_xlabel(r"$qR$", fontsize=24)
ax.set_ylabel(r"$F^2(qR)$", fontsize=24)
ax.tick_params(which="both", axis="both", labelsize=0)
_images/examples_FormFactors_11_0.png

Evidently, the form factor varies substantially along different coordinate axes for the tetrahedron. While the x and z axis results are relatively similar, the form factor along the y axis is far less oscillatory. Moreover, all three results contain many more interesting results than the sphere’s form factor, which is essentially just a simple periodic wave. Note that all these results are subject to global transformation laws, i.e. they depend on the orientation of the tetrahedron used in this calculation. If the tetrahedron were to rotate, then the results would shift accordingly.

Shapes Module#

Overview

Define shape classes.

This subpackage is the core of coxeter and defines various shapes in two and three dimensions. Shapes support standard calculations like volume and area, and they take care of various conveniences such as orienting polyhedron faces and automatically identifying convex hulls of points.

Classes:

Circle(radius[, center])

A circle with the given radius.

ConvexPolygon(vertices[, normal, ...])

A convex polygon.

ConvexPolyhedron(vertices)

A convex polyhedron.

ConvexSpheropolygon(vertices, radius[, normal])

A convex spheropolygon.

ConvexSpheropolyhedron(vertices, radius)

A convex spheropolyhedron.

Ellipse(a, b[, center])

An ellipse with principal axes a and b.

Ellipsoid(a, b, c[, center])

An ellipsoid with principal axes a, b, and c.

Polygon(vertices[, normal, ...])

A simple (non-self-overlapping) polygon.

Polyhedron(vertices, faces[, faces_are_convex])

A three-dimensional polytope.

Shape()

An abstract representation of a shape in N dimensions.

Shape2D()

An abstract representation of a shape in 2 dimensions.

Shape3D()

An abstract representation of a shape in 3 dimensions.

Sphere(radius[, center])

A sphere with the given radius.

class coxeter.shapes.Circle(radius, center=(0, 0, 0))#

Bases: Shape2D

A circle with the given radius.

Parameters:
  • radius (float) – Radius of the circle.

  • center (Sequence[float]) – The coordinates of the centroid of the circle (Default value: (0, 0, 0)).

Example

>>> circle = coxeter.shapes.circle.Circle(radius=1.0, center=(1, 1, 1))
>>> import numpy as np
>>> assert np.isclose(circle.area, np.pi)
>>> circle.centroid
array([1, 1, 1])
>>> assert np.isclose(circle.circumference, 2 * np.pi)
>>> circle.eccentricity
0
>>> circle.gsd_shape_spec
{'type': 'Sphere', 'diameter': 2.0}
>>> circle.iq
1
>>> assert np.isclose(circle.perimeter, 2 * np.pi)
>>> assert np.allclose(
...   circle.planar_moments_inertia,
...   (5. / 4. * np.pi, 5. / 4. * np.pi, np.pi))
>>> assert np.isclose(circle.polar_moment_inertia, 5. / 2. * np.pi)
>>> circle.radius
1.0

Attributes:

area

Get the area of the circle.

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

circumference

Get the circumference, alias for Circle.perimeter.

eccentricity

Get the eccentricity of the circle.

gsd_shape_spec

Get a complete GSD specification.

inertia_tensor

Get the inertia tensor.

iq

The isoperimetric quotient.

maximal_bounded_circle

Get the largest bounded circle.

maximal_bounded_circle_radius

Get or set the radius of the maximal bounded circle.

maximal_bounding_circle

Get the largest bounded circle.

maximal_centered_bounded_circle

Get the largest bounded concentric circle.

maximal_centered_bounded_circle_radius

Get or set the radius of the maximal centered bounded circle.

minimal_bounding_circle

Get the smallest bounding circle.

minimal_bounding_circle_radius

Get or set the radius of the minimal bounding circle.

minimal_centered_bounding_circle

Get the smallest bounding concentric circle.

minimal_centered_bounding_circle_radius

Get or set the radius of the minimal centered bounding circle.

perimeter

Get the perimeter of the circle.

planar_moments_inertia

Get the planar and product moments of inertia.

polar_moment_inertia

Get the polar moment of inertia.

radius

Get the radius of the circle.

Methods:

compute_form_factor_amplitude(q)

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

is_inside(points)

Determine whether a set of points are contained in this circle.

plot()

Plot the shape.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property area#

Get the area of the circle.

Type:

float

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

property circumference#

Get the circumference, alias for Circle.perimeter.

Type:

float

compute_form_factor_amplitude(q)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property eccentricity#

Get the eccentricity of the circle.

This is 0 by definition for circles.

Type:

float

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property inertia_tensor#

Get the inertia tensor.

For non-orientable 2D shapes, the inertia tensor can be trivially constructed from the polar moment of inertia. This calculation assumes that the shape lies in the \(xy\)-plane. Shapes that can be rotated relative to this plane must define their own methods.

Type:

\((3, 3)\) numpy.ndarray

property iq#

The isoperimetric quotient.

This is 1 by definition for circles.

Type:

float

is_inside(points)#

Determine whether a set of points are contained in this circle.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the circle.

Return type:

\((N, )\) numpy.ndarray

Example

>>> circle = coxeter.shapes.Circle(1.0)
>>> circle.is_inside([[0, 0, 0], [20, 20, 20]])
array([ True, False])
property maximal_bounded_circle#

Get the largest bounded circle.

The largest circle contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the incircle of a polygon), this property is named as an explicit analog to minimal_bounding_circle.

Type:

Circle

property maximal_bounded_circle_radius#

Get or set the radius of the maximal bounded circle.

See maximal_bounded_circle() for more information.

Type:

float

property maximal_bounding_circle#

Get the largest bounded circle.

Type:

Circle

property maximal_centered_bounded_circle#

Get the largest bounded concentric circle.

Type:

Circle

property maximal_centered_bounded_circle_radius#

Get or set the radius of the maximal centered bounded circle.

See maximal_centered_bounded_circle() for more information.

Type:

float

property minimal_bounding_circle#

Get the smallest bounding circle.

Type:

Circle

property minimal_bounding_circle_radius#

Get or set the radius of the minimal bounding circle.

See minimal_bounding_circle() for more information.

Type:

float

property minimal_centered_bounding_circle#

Get the smallest bounding concentric circle.

Type:

Circle

property minimal_centered_bounding_circle_radius#

Get or set the radius of the minimal centered bounding circle.

See minimal_centered_bounding_circle() for more information.

Type:

float

property perimeter#

Get the perimeter of the circle.

Type:

float

property planar_moments_inertia#

Get the planar and product moments of inertia.

Moments are computed with respect to the \(x\) and \(y\) axes. In addition to the two planar moments, this property also provides the product of inertia.

The planar moments and the product of inertia are defined by the formulas:

\[\begin{split}\begin{align} I_x &= {\int \int}_A y^2 dA = \frac{\pi}{4} r^4 = \frac{Ar^2}{4} \\ I_y &= {\int \int}_A x^2 dA = \frac{\pi}{4} r^4 = \frac{Ar^2}{4} \\ I_{xy} &= {\int \int}_A xy dA = 0 \\ \end{align}\end{split}\]

These formulas are given here. Note that the product moment is zero by symmetry.

Type:

list[float, float, float]

plot()#

Plot the shape.

property polar_moment_inertia#

Get the polar moment of inertia.

The polar moment of inertia is always calculated about an axis perpendicular to the shape (i.e. the normal vector).

The polar moment is computed as the sum of the two planar moments of inertia.

Type:

float

property radius#

Get the radius of the circle.

Type:

float

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

class coxeter.shapes.ConvexPolygon(vertices, normal=None, planar_tolerance=1e-05)#

Bases: Polygon

A convex polygon.

The polygon is embedded in 3-dimensions, so the normal vector determines which way is “up”.

Parameters:
  • vertices (\((N, 3)\) or \((N, 2)\) numpy.ndarray) – The vertices of the polygon. They need not be sorted since the order will be determined by the hull.

  • normal (sequence of length 3 or None) – The normal vector to the polygon. If None, the normal is computed by taking the cross product of the vectors formed by the first three vertices np.cross(vertices[2, :] - vertices[1, :], vertices[0, :] - vertices[1, :]). This choice is made so that if the provided vertices are in the \(xy\) plane and are specified in counterclockwise order, the resulting normal is the \(z\) axis. Since this arbitrary choice may not preserve the orientation of the provided vertices, users may provide a normal instead (Default value: None).

  • planar_tolerance (float) – The tolerance to use to verify that the vertices are planar. Providing this argument may be necessary if you have a large number of vertices and are rotated significantly out of the plane.

Example

>>> square = coxeter.shapes.ConvexPolygon(
...   [[1, 1], [-1, -1], [1, -1], [-1, 1]])
>>> import numpy as np
>>> assert np.isclose(square.area, 4.0)
>>> assert np.isclose(
...   square.minimal_bounding_circle.radius,
...   np.sqrt(2.))
>>> square.center
array([0., 0., 0.])
>>> assert np.isclose(
...   square.circumcircle.radius,
...   np.sqrt(2.))
>>> square.gsd_shape_spec
{'type': 'Polygon', 'vertices': [[1.0, 1.0, 0.0], [-1.0, 1.0, 0.0],
[-1.0, -1.0, 0.0], [1.0, -1.0, 0.0]]}
>>> assert np.isclose(square.maximal_centered_bounded_circle.radius, 1.0)
>>> assert np.allclose(
...   square.inertia_tensor,
...   [[0., 0., 0.],
...    [0., 0., 0.],
...    [0., 0., 8. / 3.]])
>>> square.normal
array([0., 0., 1.])
>>> assert np.allclose(
...   square.planar_moments_inertia,
...   (4. / 3., 4. / 3., 0.))
>>> assert np.isclose(square.polar_moment_inertia, 8. / 3.)
>>> assert np.isclose(square.signed_area, 4.0)
>>> square.vertices
array([[ 1.,  1.,  0.],
       [-1.,  1.,  0.],
       [-1., -1.,  0.],
       [ 1., -1.,  0.]])

Attributes:

area

Get or set the polygon's area.

bounding_circle

Get the minimal bounding circle.

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

circumcircle

Get the polygon's circumcircle.

circumcircle_radius

Get the radius of the polygon's circumcircle.

gsd_shape_spec

Get a complete GSD specification.

incircle

Get the polygon's incircle.

incircle_from_center

Get the largest concentric inscribed circle.

incircle_radius

Get the radius of the polygon's incircle.

inertia_tensor

Get the inertia tensor.

iq

The isoperimetric quotient.

maximal_bounded_circle

Get the largest bounded circle.

maximal_bounded_circle_radius

Get or set the radius of the maximal bounded circle.

maximal_centered_bounded_circle

Get the largest bounded concentric circle.

maximal_centered_bounded_circle_radius

Get or set the radius of the maximal centered bounded circle.

minimal_bounding_circle

Get the minimal bounding circle.

minimal_bounding_circle_radius

Get or set the radius of the minimal bounding circle.

minimal_centered_bounding_circle

Get the smallest bounding concentric circle.

minimal_centered_bounding_circle_radius

Get or set the radius of the minimal centered bounding circle.

normal

Get the normal vector.

num_vertices

Get the number of vertices.

perimeter

Get the perimeter of the polygon.

planar_moments_inertia

Get the planar and product moments of inertia.

polar_moment_inertia

Get the polar moment of inertia.

signed_area

Get the polygon's area.

vertices

Get the vertices of the polygon.

Methods:

compute_form_factor_amplitude(q[, density])

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

is_inside(points)

Implement a simple point-in-polygon algorithm based on winding number.

plot([ax, center, plot_verts, label_verts])

Plot the polygon.

to_hoomd()

Get a JSON-serializable subset of Polygon properties.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property area#

Get or set the polygon’s area.

To get the area, we simply compute the signed area and take the absolute value.

Type:

float

property bounding_circle#

Get the minimal bounding circle.

Type:

Circle

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

The centroid of a polygon is calculated according to this formula.

Type:

\((3, )\) numpy.ndarray of float

property circumcircle#

Get the polygon’s circumcircle.

A circumcircle must touch all the points of the polygon. A circumcircle exists if and only if there is a point equidistant from all the vertices. The circumcircle is found by finding the least squares solution of the overdetermined system of linear equations defined by this constraint, and the circumcircle only exists if the resulting solution has no residual.

Raises:

RuntimeError – If no circumcircle exists for this polygon.:

Type:

Circle

property circumcircle_radius#

Get the radius of the polygon’s circumcircle.

Type:

float

compute_form_factor_amplitude(q, density=1.0)#

Calculate the form factor intensity.

The form factor amplitude of a polygon is computed according to the derivation provided in this dissertation: https://deepblue.lib.umich.edu/handle/2027.42/120906. The Kelvin-Stokes theorem allows reducing the surface integral to a line integral around the boundary.

For more generic information about form factors, see Shape.compute_form_factor_amplitude.

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property incircle#

Get the polygon’s incircle.

Note

The incircle of a polygon is defined as the circle contained within the polygon that is tangent to all its faces. This condition uniquely defines the circle, if it exists. The set of equations defined by this equation is solved using a least squares approach, with the magnitude of the residual used to determine whether or not the incircle exists.

Type:

Sphere

property incircle_from_center#

Get the largest concentric inscribed circle.

Type:

Circle

property incircle_radius#

Get the radius of the polygon’s incircle.

Type:

float

property inertia_tensor#

Get the inertia tensor.

The inertia tensor is computed for the polygon embedded in \(\mathbb{R}^3\). This computation proceeds by first computing the polar moment of inertia for the polygon in the \(xy\)-plane relative to its centroid. The tensor is then rotated back to the orientation of the polygon and shifted to the original centroid.

Type:

\((3, 3)\) numpy.ndarray

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the area of a shape to the area of a circle with the same perimeter. Given a shape of area \(A\) and perimeter \(p\), the circle with the same perimeter has radius \(r_p = \frac{p}{2\pi}\) and therefore has an area \(A_{circle} = \pi r_p^2 = \frac{p^2}{4\pi}\). Therefore, we have that:

\[\begin{split}\begin{align} IQ &= \frac{A}{A_{circle}} \\ &= \frac{4\pi A}{p^2} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Implement a simple point-in-polygon algorithm based on winding number.

The code in this function is based on implementation in [Dic19] which is licensed under the BSD-3 license.

Given a closed, possibly non-simple polygon described as a list of vertices in \(\mathbb{R}^2\) and a point that doesn’t lie directly on the path of the polygon, we’d like to compute the winding number of the polygon around the point. To achieve this, we place the point at the origin. Divide the remainder of the plane (i.e., \(\mathbb{R}^2\) minus the origin) into two halves, \(L\) and \(R\), defined as follows:

\[ \begin{align}\begin{aligned}L = {(x, y) | x < 0 \lor x = 0 \land y < 0}\\R = {(x, y) | x > 0 \lor x = 0 \land y > 0}\end{aligned}\end{align} \]

That is, \(R\) contains all points with argument in the half-closed interval \(\left[-\frac{\pi}{2},\frac{\pi}{2}\right)\), and \(L\) contains all others. Note that with these definitions, \(L\) and \(R\) are both convex: a line segment between two points in \(R\) lies entirely in \(R\), and similarly for \(L\). In particular, a line segment between two points can only pass through the origin if one of those points is in \(L\) and the other in \(R\). Now, we follow the edges of the polygon, keeping track of how many times we move between \(L\) and \(R\). For each move from \(L\) to \(R\) (or vice versa), we also need to compute whether the edge passes above or below the origin, to compute its contribution to the total winding number. From the comment above, we can safely ignore all edges that lie entirely within either \(L\) or \(R\).

Note

Points on the boundary of the shape will return False.

Parameters:

points (\((N, 3)\) or \((N, 2)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the polyhedron.

Return type:

\((N, )\) numpy.ndarray

property maximal_bounded_circle#

Get the largest bounded circle.

The largest circle contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the incircle of a polygon), this property is named as an explicit analog to minimal_bounding_circle.

Type:

Circle

property maximal_bounded_circle_radius#

Get or set the radius of the maximal bounded circle.

See maximal_bounded_circle() for more information.

Type:

float

property maximal_centered_bounded_circle#

Get the largest bounded concentric circle.

Type:

Circle

property maximal_centered_bounded_circle_radius#

Get or set the radius of the maximal centered bounded circle.

See maximal_centered_bounded_circle() for more information.

Type:

float

property minimal_bounding_circle#

Get the minimal bounding circle.

Type:

Circle

property minimal_bounding_circle_radius#

Get or set the radius of the minimal bounding circle.

See minimal_bounding_circle() for more information.

Type:

float

property minimal_centered_bounding_circle#

Get the smallest bounding concentric circle.

Type:

Circle

property minimal_centered_bounding_circle_radius#

Get or set the radius of the minimal centered bounding circle.

See minimal_centered_bounding_circle() for more information.

Type:

float

property normal#

Get the normal vector.

Type:

\((3, )\) numpy.ndarray of float

property num_vertices#

Get the number of vertices.

Type:

int

property perimeter#

Get the perimeter of the polygon.

Type:

float

property planar_moments_inertia#

Get the planar and product moments of inertia.

Moments are computed with respect to the \(x\) and \(y\) axes. In addition to the two planar moments, this property also provides the product of inertia.

The planar moments and the product of inertia are defined by the formulas:

\[\begin{split}\begin{align} I_x &= {\int \int}_A y^2 dA \\ I_y &= {\int \int}_A x^2 dA \\ I_{xy} &= {\int \int}_A xy dA \\ \end{align}\end{split}\]

To compute this for a polygon, we discretize the sum:

\[\begin{split}\begin{align} I_x &= \frac{1}{12} \sum_{i=1}^N (x_i y_{i+1} - x_{i+1} y_i) (y_i^2 + y_i*y_{i+1} + y_{i+1}^2) \\ I_y &= \frac{1}{12} \sum_{i=1}^N (x_i y_{i+1} - x_{i+1} y_i) (x_i^2 + x_i*x_{i+1} + x_{i+1}^2) \\ I_{xy} &= \frac{1}{12} \sum_{i=1}^N (x_i y_{i+1} - x_{i+1} y_i) (x_i y_{i+1} + 2 x_i y_i + 2 x_{i+1} y_{i+1} + x_{i+1} y_i) \\ \end{align}\end{split}\]

These formulas can be derived as described here.

Note that the moments are always calculated about an axis perpendicular to the polygon, i.e. the normal vector is aligned with the \(z\) axis before the moments are calculated. This alignment should be considered when computing the moments for polygons embedded in three-dimensional space that are rotated out of the \(xy\) plane, since the planar moments are invariant to this orientation. The exact rotation used for this computation (i.e. changes in the \(x\) and \(y\) position) should not be relied upon.

Type:

list[float, float, float]

plot(ax=None, center=False, plot_verts=False, label_verts=False)#

Plot the polygon.

Note that the polygon is always rotated into the \(xy\) plane and plotted in two dimensions.

Parameters:
  • ax (matplotlib.axes.Axes) – The axes on which to draw the polygon. Axes will be created if this is None (Default value: None).

  • center (bool) – If True, the polygon vertices are plotted relative to its center (Default value: False).

  • plot_verts (bool) – If True, scatter points will be added at the vertices (Default value: False).

  • label_verts (bool) – If True, vertex indices will be added next to the vertices (Default value: False).

property polar_moment_inertia#

Get the polar moment of inertia.

The polar moment of inertia is always calculated about an axis perpendicular to the shape (i.e. the normal vector).

The polar moment is computed as the sum of the two planar moments of inertia.

Type:

float

property signed_area#

Get the polygon’s area.

To support polygons embedded in 3 dimensional space, we employ a projection- and rescaling-based algorithm described here. Specifically, the polygon is projected onto the plane it is “most parallel” to, the area of the projected polygon is computed, then the area is rescaled by the component of the normal in the projected dimension.

Type:

float

to_hoomd()#

Get a JSON-serializable subset of Polygon properties.

The JSON-serializable output of the to_hoomd method can be directly imported into data management tools like signac. This data can then be queried for use in HOOMD simulations. Key naming matches HOOMD integrators: for example, the moment_inertia key links to data from coxeter’s inertia_tensor. Stored values are based on the shape with its centroid at the origin.

For a Polygon or ConvexPolygon, the following properties are stored:

  • vertices (list(list)):

    The vertices of the shape.

  • centroid (list(float))

    The centroid of the shape. This is set to [0,0,0] per HOOMD’s spec.

  • sweep_radius (float):

    The rounding radius of the shape (0.0).

  • area (float)

    The area of the shape.

  • moment_inertia (list(list))

    The shape’s inertia tensor.

Returns:

Dict containing a subset of shape properties required for HOOMD function.

Return type:

dict

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

property vertices#

Get the vertices of the polygon.

Type:

\((N_{verts}, 3)\) numpy.ndarray of float

class coxeter.shapes.ConvexPolyhedron(vertices)#

Bases: Polyhedron

A convex polyhedron.

A convex polyhedron is defined as the convex hull of its vertices. The class is an extension of Polyhedron that builds the faces from the simplices of the convex hull. Simplices are stored and class methods are optimized to make use of the triangulation, as well as special properties of convex solids in three dimensions. This class also includes various additional properties that can be used to characterize geometric features of the polyhedron.

Parameters:

vertices (\((N, 3)\) numpy.ndarray) – The vertices of the polyhedron.

Example

>>> cube = coxeter.shapes.ConvexPolyhedron(
...   [[-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1, 1, 1],
...    [1, -1, -1], [1, -1, 1], [1, 1, -1], [1, 1, 1]])
>>> import numpy as np
>>> assert np.isclose(cube.asphericity, 1.5)
>>> bounding_sphere = cube.minimal_bounding_sphere
>>> assert np.isclose(bounding_sphere.radius, np.sqrt(3))
>>> cube.centroid
array([0., 0., 0.])
>>> circumsphere = cube.circumsphere
>>> assert np.isclose(circumsphere.radius, np.sqrt(3))
>>> cube.faces
[array([0, 2, 6, 4], dtype=int32), array([0, 4, 5, 1], dtype=int32),
array([4, 6, 7, 5], dtype=int32), array([0, 1, 3, 2], dtype=int32),
array([2, 3, 7, 6], dtype=int32), array([1, 5, 7, 3], dtype=int32)]
>>> cube.gsd_shape_spec
{'type': 'ConvexPolyhedron', 'vertices': [[-1.0, -1.0, -1.0], [-1.0, -1.0, 1.0],
[-1.0, 1.0, -1.0], [-1.0, 1.0, 1.0], [1.0, -1.0, -1.0], [1.0, -1.0, 1.0],
[1.0, 1.0, -1.0], [1.0, 1.0, 1.0]]}
>>> assert np.allclose(
...   cube.inertia_tensor,
...   np.diag([16. / 3., 16. / 3., 16. / 3.]))
>>> sphere = cube.maximal_centered_bounded_sphere
>>> sphere.radius
1.0
>>> assert np.isclose(cube.iq, np.pi / 6.)
>>> assert np.isclose(cube.mean_curvature, 1.5)
>>> cube.neighbors
[array([1, 2, 3, 4]), array([0, 2, 3, 5]), array([0, 1, 4, 5]),
array([0, 1, 4, 5]), array([0, 2, 3, 5]), array([1, 2, 3, 4])]
>>> cube.normals
array([[-0., -0., -1.],
       [ 0., -1.,  0.],
       [ 1., -0., -0.],
       [-1., -0., -0.],
       [ 0.,  1., -0.],
       [-0., -0.,  1.]])
>>> cube.num_faces
6
>>> cube.num_vertices
8
>>> cube.surface_area
24.0
>>> assert np.isclose(cube.tau, 3. / 8. * np.pi)
>>> cube.vertices
array([[-1., -1., -1.],
       [-1., -1.,  1.],
       [-1.,  1., -1.],
       [-1.,  1.,  1.],
       [ 1., -1., -1.],
       [ 1., -1.,  1.],
       [ 1.,  1., -1.],
       [ 1.,  1.,  1.]])
>>> assert np.isclose(cube.volume, 8.)

Attributes:

asphericity

Get the asphericity as defined in [IES+17].

bounding_sphere

Get the polyhedron's bounding sphere.

center

Alias for centroid.

centroid

Get or set the center of mass.

circumsphere

Get the polyhedron's circumsphere.

circumsphere_from_center

Get the smallest circumscribed sphere centered at the centroid.

circumsphere_radius

Get the radius of the polygon's circumsphere.

edge_lengths

Get the length of each edge of the polyhedron.

edge_vectors

Get the polyhedron's edges as vectors.

edges

Get the polyhedron's edges.

equations

Get plane equations for each face.

face_centroids

Calculate the centroid (center of mass) of each polygonal face.

faces

Get the polyhedron's faces.

gsd_shape_spec

Get a complete GSD specification.

inertia_tensor

Get the inertia tensor.

insphere

Get the polyhedron's insphere.

insphere_from_center

Get the largest concentric inscribed sphere.

insphere_radius

Get the radius of the polygon's insphere.

iq

The isoperimetric quotient.

maximal_bounded_sphere

Get the largest bounded sphere.

maximal_bounded_sphere_radius

Get or set the radius of the maximal bounded sphere.

maximal_centered_bounded_sphere

Get the largest bounded concentric sphere.

maximal_centered_bounded_sphere_radius

Get or set the radius of the maximal centered bounded sphere.

mean_curvature

The integrated, normalized mean curvature.

minimal_bounding_sphere

Get the polyhedron's bounding sphere.

minimal_bounding_sphere_radius

Get or set the radius of the minimal bounding sphere.

minimal_centered_bounding_sphere

Get the smallest bounding concentric sphere.

minimal_centered_bounding_sphere_radius

Get or set the radius of the minimal concentric bounding sphere.

neighbors

Get neighboring pairs of faces.

normals

Get normal vectors for each face.

num_edges

Get the number of edges.

num_faces

Get the number of faces.

num_vertices

Get the number of vertices.

simplices

Output the vertex indices of simplices composing the polyhedron's surface.

surface_area

Get or set the surface area.

tau

Get the parameter \(\tau = \frac{4\pi R^2}{S}\).

vertices

Get the vertices of the polyhedron.

volume

Get or set the polyhedron's volume.

Methods:

compute_form_factor_amplitude(q[, density])

Calculate the form factor intensity.

diagonalize_inertia()

Orient the shape along its principal axes.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

get_dihedral(a, b)

Get the dihedral angle between a pair of faces.

get_face_area([face])

Get the total surface area of a set of faces.

is_inside(points)

Determine whether points are contained in this polyhedron.

merge_faces([atol, rtol])

Merge coplanar faces to a given tolerance.

plot([ax, plot_verts, label_verts])

Plot the polyhedron.

sort_faces()

Reorder faces counterclockwise relatative to the plane they lie on.

to_hoomd()

Get a JSON-serializable subset of Polyhedron properties.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property asphericity#

Get the asphericity as defined in [IES+17].

Type:

float

property bounding_sphere#

Get the polyhedron’s bounding sphere.

Type:

Sphere

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the center of mass.

The centroid is calculated using the curl theorem over the surface simplices.

Type:

\((3, )\) numpy.ndarray of float

property circumsphere#

Get the polyhedron’s circumsphere.

A circumsphere must touch all the points of the polyhedron. A circumsphere exists if and only if there is a point equidistant from all the vertices. The circumsphere is found by finding the least squares solution of the overdetermined system of linear equations defined by this constraint, and the circumsphere only exists if the resulting solution has no residual.

Raises:

RuntimeError – If no circumsphere exists for this polyhedron.:

Type:

Sphere

property circumsphere_from_center#

Get the smallest circumscribed sphere centered at the centroid.

The requirement that the sphere be centered at the centroid of the shape distinguishes this sphere from most typical circumsphere calculations.

Type:

Sphere

property circumsphere_radius#

Get the radius of the polygon’s circumsphere.

Type:

float

compute_form_factor_amplitude(q, density=1.0)#

Calculate the form factor intensity.

The form factor amplitude of a polyhedron is computed according to the derivation provided in this dissertation: https://deepblue.lib.umich.edu/handle/2027.42/120906. In brief, two applications of Stokes theorem (or to use the names more familiar from elementary vector calculus, the application of the divergence theorem followed by the classic Kelvin-Stokes theorem) are used to reduce the volume integral over a polyhedron into a series of line integrals around the boundaries of each polygonal face.

For more generic information about form factors, see Shape.compute_form_factor_amplitude.

diagonalize_inertia()#

Orient the shape along its principal axes.

The principal axes of a shape are defined by the eigenvectors of the inertia tensor. This method computes the inertia tensor of the shape, diagonalizes it, and then rotates the shape by the corresponding orthogonal transformation.

Example

>>> cube = coxeter.shapes.ConvexPolyhedron(
...   [[1, 1, 1], [1, -1, 1], [1, 1, -1], [1, -1, -1],
...    [-1, 1, 1], [-1, -1, 1], [-1, 1, -1], [-1, -1, -1]])
>>> cube.diagonalize_inertia()
>>> cube.vertices
array([[ 1.,  1.,  1.],
       [ 1., -1.,  1.],
       [ 1.,  1., -1.],
       [ 1., -1., -1.],
       [-1.,  1.,  1.],
       [-1., -1.,  1.],
       [-1.,  1., -1.],
       [-1., -1., -1.]])
distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property edge_lengths#

Get the length of each edge of the polyhedron.

edge_lengths are returned in the same order as in edges.

Type:

numpy.ndarray

property edge_vectors#

Get the polyhedron’s edges as vectors.

edge_vectors are returned in the same order as in edges.

Type:

numpy.ndarray

property edges#

Get the polyhedron’s edges.

Results returned as vertex index pairs, with each edge of the polyhedron included exactly once. Edge (i,j) pairs are ordered by vertex index with i<j.

Type:

numpy.ndarray

property equations#

Get plane equations for each face.

Sign convention matches Scipy Convex Hull (ax + by + cz + d = 0).

Type:

\((N, 4)\) numpy.ndarray

property face_centroids#

Calculate the centroid (center of mass) of each polygonal face.

Returns:

Array of centroids for each face.

Return type:

\((N,3)\) numpy.ndarray

property faces#

Get the polyhedron’s faces.

Type:

list(numpy.ndarray)

get_dihedral(a, b)#

Get the dihedral angle between a pair of faces.

The dihedral is computed from the dot product of the face normals.

Parameters:
  • a (int) – The index of the first face.

  • b (int) – The index of the second face.

Returns:

float

Return type:

The dihedral angle in radians.

Example

>>> cube = coxeter.shapes.ConvexPolyhedron(
...   [[1, 1, 1], [1, -1, 1], [1, 1, -1], [1, -1, -1],
...    [-1, 1, 1], [-1, -1, 1], [-1, 1, -1], [-1, -1, -1]])
>>> cube = coxeter.shapes.Polyhedron(
...   vertices=cube.vertices, faces=cube.faces)
>>> import numpy as np
>>> assert np.isclose(cube.get_dihedral(1, 2), np.pi / 2.)
get_face_area(face=None)#

Get the total surface area of a set of faces.

Parameters:

faces (int, sequence, or None) – The index of a face or a set of face indices for which to find the area. If None, finds the area of all faces. (Default value: None).

Returns:

:class:`numpy.ndarray`

Return type:

The area of each face.

Example

>>> cube = coxeter.shapes.ConvexPolyhedron(
...   [[1, 1, 1], [1, -1, 1], [1, 1, -1], [1, -1, -1],
...    [-1, 1, 1], [-1, -1, 1], [-1, 1, -1], [-1, -1, -1]])
>>> cube = coxeter.shapes.Polyhedron(
...   vertices=cube.vertices,faces=cube.faces)
>>> import numpy as np
>>> assert np.allclose(
...   cube.get_face_area([1, 2, 3]),
...   [4., 4., 4.])
property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property inertia_tensor#

Get the inertia tensor.

The inertia tensor for convex shapes is computed using the algorithm described in [MT80].

Note

For improved stability, the inertia tensor is computed about the center of mass and then shifted rather than directly computed in the global frame.

Type:

\((3, 3)\) numpy.ndarray

property insphere#

Get the polyhedron’s insphere.

Note

The insphere of a polyhedron is defined as the sphere contained within the polyhedron that is tangent to all its faces. This condition uniquely defines the sphere, if it exists. The set of equations defined by this equation is solved using a least squares approach, with the magnitude of the residual used to determine whether or not the insphere exists.

Type:

Sphere

property insphere_from_center#

Get the largest concentric inscribed sphere.

Type:

Sphere

property insphere_radius#

Get the radius of the polygon’s insphere.

Type:

float

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the volume of a shape to the volume of a sphere with the same perimeter. Given a shape of volume \(A\) and surface \(S\), the sphere with the same surface has radius \(r_S = \sqrt{\frac{S}{4\pi}}\) and therefore has volume \(V_{sphere} = \frac{4}{3} \pi r_S^3 = \frac{S^{3/2}}{\sqrt{4\pi}}\). Taking the ratio of volumes gives:

\[\begin{equation} \frac{V}{V_{sphere}} = \frac{6\sqrt{\pi} V}{S^{3/2}} \end{equation}\]

To avoid inconvenient fractional exponents, the isoperimetric quotient is conventionally defined as the square of this quantity:

\[\begin{split}\begin{align} IQ &= \left(\frac{V}{V_{sphere}}\right)^2 \\ &= \frac{36\pi V^2}{S^3} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Determine whether points are contained in this polyhedron.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the polyhedron.

Return type:

\((N, )\) numpy.ndarray

property maximal_bounded_sphere#

Get the largest bounded sphere.

The largest sphere contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the insphere of a polyhedron), this property is named as an explicit analog to minimal_bounding_sphere.

Type:

Sphere

property maximal_bounded_sphere_radius#

Get or set the radius of the maximal bounded sphere.

See maximal_bounded_sphere() for more information.

Type:

float

property maximal_centered_bounded_sphere#

Get the largest bounded concentric sphere.

Type:

Sphere

property maximal_centered_bounded_sphere_radius#

Get or set the radius of the maximal centered bounded sphere.

See maximal_centered_bounded_sphere() for more information.

Type:

float

property mean_curvature#

The integrated, normalized mean curvature.

This quantity is calculated by the formula \(R = \sum_i (1/2) L_i (\pi - \phi_i) / (4 \pi)\) with edge lengths \(L_i\) and dihedral angles \(\phi_i\) (see [IES+17] for more information).

Type:

float

merge_faces(atol=1e-08, rtol=1e-05)#

Merge coplanar faces to a given tolerance.

Whether or not faces should be merged is determined using numpy.allclose() to compare the plane equations of neighboring faces. Connected components of mergeable faces are then merged into a single face. This method can be safely called many times with different tolerances, however, the operation is destructive in the sense that merged faces cannot be recovered. Users wishing to undo a merge to attempt a less expansive merge must build a new polyhedron.

Parameters:
property minimal_bounding_sphere#

Get the polyhedron’s bounding sphere.

Type:

Sphere

property minimal_bounding_sphere_radius#

Get or set the radius of the minimal bounding sphere.

See minimal_bounding_sphere() for more information.

Type:

float

property minimal_centered_bounding_sphere#

Get the smallest bounding concentric sphere.

Type:

Sphere

property minimal_centered_bounding_sphere_radius#

Get or set the radius of the minimal concentric bounding sphere.

See minimal_centered_bounding_sphere() for more information.

Type:

float

property neighbors#

Get neighboring pairs of faces.

The neighbors are provided as a list where the \(i^{\text{th}}\) element is an array of indices of faces that are neighbors of face \(i\).

Type:

list(numpy.ndarray)

property normals#

Get normal vectors for each face.

Type:

\((N, 3)\) numpy.ndarray

property num_edges#

Get the number of edges.

Type:

int

property num_faces#

Get the number of faces.

Type:

int

property num_vertices#

Get the number of vertices.

Type:

int

plot(ax=None, plot_verts=False, label_verts=False)#

Plot the polyhedron.

Note that the ax argument should be a 3D axes object; passing in a 2D axes object will result in wrong behavior.

Parameters:
  • ax (mpl_toolkits.mplot3d.axes3d.Axes3D) – The axes on which to draw the polyhedron. Axes will be created if this is None (Default value: None).

  • plot_verts (bool) – If True, scatter points will be added at the vertices (Default value: False).

  • label_verts (bool) – If True, vertex indices will be added next to the vertices (Default value: False).

property simplices#

Output the vertex indices of simplices composing the polyhedron’s surface.

Returns:

Array of vertex indices of simplices making up the polyhedron’s surface.

Return type:

\((N,3)\) numpy.ndarray

sort_faces()#

Reorder faces counterclockwise relatative to the plane they lie on.

This does NOT change the order of faces in the list.

property surface_area#

Get or set the surface area.

Type:

float

property tau#

Get the parameter \(\tau = \frac{4\pi R^2}{S}\).

This parameter is defined in [NL84] and is closely related to the Pitzer acentric factor. This quantity appears relevant to the third and fourth virial coefficient for hard polyhedron fluids.

Type:

float

to_hoomd()#

Get a JSON-serializable subset of Polyhedron properties.

The JSON-serializable output of the to_hoomd method can be directly imported into data management tools like signac. This data can then be queried for use in HOOMD simulations. Key naming matches HOOMD integrators: for example, the moment_inertia key links to data from coxeter’s inertia_tensor. Stored values are based on the shape with its centroid at the origin.

For a Polyhedron or ConvexPolyhedron, the following properties are stored:

  • vertices (list(list)):

    The vertices of the shape.

  • faces (list(list)):

    The faces of the shape.

  • centroid (list(float))

    The centroid of the shape. This is set to [0,0,0] per HOOMD’s spec.

  • sweep_radius (float):

    The rounding radius of the shape (0.0).

  • volume (float)

    The volume of the shape.

  • moment_inertia (list(list))

    The shape’s inertia tensor.

Returns:

Dict containing a subset of shape properties required for HOOMD function.

Return type:

dict

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

property vertices#

Get the vertices of the polyhedron.

Type:

\((N, 3)\) numpy.ndarray

property volume#

Get or set the polyhedron’s volume.

Type:

float

class coxeter.shapes.ConvexSpheropolygon(vertices, radius, normal=None)#

Bases: Shape2D

A convex spheropolygon.

Parameters:
  • vertices (\((N, 3)\) or \((N, 2)\) numpy.ndarray) – The vertices of the polygon.

  • radius (float) – The rounding radius of the spheropolygon.

  • normal (sequence of length 3 or None) – The normal vector to the polygon. If None, the normal is computed by taking the cross product of the vectors formed by the first three vertices np.cross(vertices[2, :] - vertices[1, :], vertices[0, :] - vertices[1, :]). Since this arbitrary choice may not preserve the orientation of the provided vertices, users may provide a normal instead (Default value: None).

Example

>>> rounded_tri = coxeter.shapes.ConvexSpheropolygon(
...   [[-1, 0], [0, 1], [1, 0]], radius=.1)
>>> rounded_tri.area
1.5142...
>>> rounded_tri.gsd_shape_spec
{'type': 'Polygon', 'vertices': [[-1.0, 0.0, 0.0],
[0.0, 1.0, 0.0], [1.0, 0.0, 0.0]], 'rounding_radius': 0.1}
>>> rounded_tri.radius
0.1
>>> rounded_tri.signed_area
1.5142...
>>> rounded_tri.vertices
array([[-1.,  0.,  0.],
       [ 0.,  1.,  0.],
       [ 1.,  0.,  0.]])

Attributes:

area

Get or set the polygon's area.

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

gsd_shape_spec

Get a complete GSD specification.

inertia_tensor

Get the inertia tensor.

iq

The isoperimetric quotient.

maximal_bounded_circle

Get the largest bounded circle.

maximal_bounded_circle_radius

Get or set the radius of the maximal bounded circle.

maximal_centered_bounded_circle

Get the largest concentric bounded circle.

maximal_centered_bounded_circle_radius

Get or set the radius of the maximal centered bounded circle.

minimal_bounding_circle

Get the smallest bounding circle.

minimal_bounding_circle_radius

Get or set the radius of the minimal bounding circle.

minimal_centered_bounding_circle

Get the smallest bounding concentric circle.

minimal_centered_bounding_circle_radius

Get or set the radius of the minimal centered bounding circle.

normal

Get the normal vector.

num_vertices

Get the number of vertices.

perimeter

Get the perimeter of the spheropolygon.

planar_moments_inertia

Get the planar and product moments of inertia.

polar_moment_inertia

Get the polar moment of inertia.

polygon

The underlying polygon.

radius

Get or set the rounding radius.

signed_area

Get the signed area of the spheropolygon.

vertices

Get the vertices of the spheropolygon.

Methods:

compute_form_factor_amplitude(q)

Calculate the form factor intensity.

distance_to_surface(angles)

Distance to the surface of this shape.

is_inside(points)

Determine whether points are contained in this shape.

plot()

Plot the shape.

to_hoomd()

Get a JSON-serializable subset of ConvexSpheropolygon properties.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property area#

Get or set the polygon’s area.

To get the area, we simply compute the signed area and take the absolute value.

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

compute_form_factor_amplitude(q)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

distance_to_surface(angles)#

Distance to the surface of this shape.

Since the centroid of a spheropolygon is difficult to compute in general, the distance is calculated relative to the centroid of the core polygon. For more general information about this calculation, see Shape.distance_to_surface.

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property inertia_tensor#

Get the inertia tensor.

For non-orientable 2D shapes, the inertia tensor can be trivially constructed from the polar moment of inertia. This calculation assumes that the shape lies in the \(xy\)-plane. Shapes that can be rotated relative to this plane must define their own methods.

Type:

\((3, 3)\) numpy.ndarray

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the area of a shape to the area of a circle with the same perimeter. Given a shape of area \(A\) and perimeter \(p\), the circle with the same perimeter has radius \(r_p = \frac{p}{2\pi}\) and therefore has an area \(A_{circle} = \pi r_p^2 = \frac{p^2}{4\pi}\). Therefore, we have that:

\[\begin{split}\begin{align} IQ &= \frac{A}{A_{circle}} \\ &= \frac{4\pi A}{p^2} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Determine whether points are contained in this shape.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the shape.

Return type:

\((N, )\) numpy.ndarray

property maximal_bounded_circle#

Get the largest bounded circle.

The largest circle contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the incircle of a polygon), this property is named as an explicit analog to minimal_bounding_circle.

Type:

Circle

property maximal_bounded_circle_radius#

Get or set the radius of the maximal bounded circle.

See maximal_bounded_circle() for more information.

Type:

float

property maximal_centered_bounded_circle#

Get the largest concentric bounded circle.

This property gives the largest circle that fits in the shape whose center also coincides with the center of the shape.

Type:

Circle

property maximal_centered_bounded_circle_radius#

Get or set the radius of the maximal centered bounded circle.

See maximal_centered_bounded_circle() for more information.

Type:

float

property minimal_bounding_circle#

Get the smallest bounding circle.

A bounding circle in two dimensions is a circle containing all of the points. There are an infinite set of possible bounding circles for a shape (since any circle that entirely contains a bounding circle is also a bounding circle), so additional constraints must be imposed to define a unique circle. This property provides the smallest bounding circle of a shape.

Type:

Circle

property minimal_bounding_circle_radius#

Get or set the radius of the minimal bounding circle.

See minimal_bounding_circle() for more information.

Type:

float

property minimal_centered_bounding_circle#

Get the smallest bounding concentric circle.

This property gives the smallest bounding circle whose center coincides with the center of the shape.

Type:

Circle

property minimal_centered_bounding_circle_radius#

Get or set the radius of the minimal centered bounding circle.

See minimal_centered_bounding_circle() for more information.

Type:

float

property normal#

Get the normal vector.

Type:

\((3, )\) numpy.ndarray of float

property num_vertices#

Get the number of vertices.

Type:

int

property perimeter#

Get the perimeter of the spheropolygon.

Type:

float

property planar_moments_inertia#

Get the planar and product moments of inertia.

Moments are computed with respect to the \(x\) and \(y\) axes. In addition to the two planar moments, this property also provides the product of inertia.

The planar moments of inertia and the product of inertia define the in-plane area distribution.

Type:

list[float, float, float]

plot()#

Plot the shape.

property polar_moment_inertia#

Get the polar moment of inertia.

The polar moment of inertia is always calculated about an axis perpendicular to the shape (i.e. the normal vector).

The polar moment is computed as the sum of the two planar moments of inertia.

Type:

float

property polygon#

The underlying polygon.

Type:

ConvexPolygon

property radius#

Get or set the rounding radius.

Type:

float

property signed_area#

Get the signed area of the spheropolygon.

The area is computed as the sum of the underlying polygon area and the area added by the rounding radius.

to_hoomd()#

Get a JSON-serializable subset of ConvexSpheropolygon properties.

The JSON-serializable output of the to_hoomd method can be directly imported into data management tools like signac. This data can then be queried for use in HOOMD simulations. Key naming matches HOOMD integrators: for example, the moment_inertia key links to data from coxeter’s inertia_tensor. Stored values are based on the shape with its centroid at the origin.

For a ConvexSpheropolygon, the following properties are stored:

  • vertices (list(list)):

    The vertices of the shape.

  • centroid (list(float))

    The centroid of the shape. This is set to [0,0,0] per HOOMD’s spec.

  • sweep_radius (float):

    The rounding radius of the shape.

  • area (float)

    The area of the shape.

Returns:

Dict containing a subset of shape properties required for HOOMD function.

Return type:

dict

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

property vertices#

Get the vertices of the spheropolygon.

Type:

\((N_{verts}, 3)\) numpy.ndarray of float

class coxeter.shapes.ConvexSpheropolyhedron(vertices, radius)#

Bases: Shape3D

A convex spheropolyhedron.

A convex spheropolyhedron is defined as a convex polyhedron plus a rounding radius. All properties of the underlying polyhedron (the vertices, the faces and their neighbors, etc.) can be accessed directly through polyhedron.

Parameters:
  • vertices (\((N, 3)\) numpy.ndarray) – The vertices of the underlying polyhedron.

  • radius (float) – The rounding radius of the spheropolyhedron.

Example

>>> spherocube = coxeter.shapes.ConvexSpheropolyhedron(
...   [[1, 1, 1], [1, -1, 1], [1, 1, -1], [1, -1, -1],
...    [-1, 1, 1], [-1, -1, 1], [-1, 1, -1], [-1, -1, -1]],
...   radius=0.5)
>>> spherocube.gsd_shape_spec
{'type': 'ConvexPolyhedron', 'vertices': [[1.0, 1.0, 1.0], [1.0, -1.0, 1.0],
[1.0, 1.0, -1.0], [1.0, -1.0, -1.0], [-1.0, 1.0, 1.0], [-1.0, -1.0, 1.0],
[-1.0, 1.0, -1.0], [-1.0, -1.0, -1.0]], 'rounding_radius': 0.5}
>>> cube = spherocube.polyhedron
>>> cube.vertices
array([[ 1.,  1.,  1.],
       [ 1., -1.,  1.],
       [ 1.,  1., -1.],
       [ 1., -1., -1.],
       [-1.,  1.,  1.],
       [-1., -1.,  1.],
       [-1.,  1., -1.],
       [-1., -1., -1.]])
>>> spherocube.radius
0.5
>>> spherocube.surface_area
45.991...
>>> spherocube.vertices
array([[ 1.,  1.,  1.],
       [ 1., -1.,  1.],
       [ 1.,  1., -1.],
       [ 1., -1., -1.],
       [-1.,  1.,  1.],
       [-1., -1.,  1.],
       [-1.,  1., -1.],
       [-1., -1., -1.]])
>>> spherocube.volume
25.235...

Attributes:

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

gsd_shape_spec

Get a complete GSD specification.

iq

The isoperimetric quotient.

maximal_bounded_sphere

Get the largest bounded sphere.

maximal_bounded_sphere_radius

Get or set the radius of the maximal bounded sphere.

maximal_centered_bounded_sphere

Get the largest concentric bounded sphere.

maximal_centered_bounded_sphere_radius

Get or set the radius of the maximal centered bounded sphere.

mean_curvature

Get the mean curvature.

minimal_bounding_sphere

Get a bounding sphere sharing the center of this shape.

minimal_bounding_sphere_radius

Get or set the radius of the minimal bounding sphere.

minimal_centered_bounding_sphere

Get a bounding sphere sharing the center of this shape.

minimal_centered_bounding_sphere_radius

Get or set the radius of the minimal concentric bounding sphere.

polyhedron

The underlying polyhedron.

radius

The rounding radius.

surface_area

Get the surface area.

vertices

Get the vertices of the spheropolyhedron.

volume

The volume.

Methods:

compute_form_factor_amplitude(q)

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

inertia_tensor()

\((3, 3)\) numpy.ndarray: Get the inertia tensor.

is_inside(points)

Determine whether points are contained in this spheropolyhedron.

plot()

Plot the shape.

to_hoomd()

Get a JSON-serializable subset of ConvexSpheropolyhedron properties.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

compute_form_factor_amplitude(q)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

inertia_tensor()#

\((3, 3)\) numpy.ndarray: Get the inertia tensor.

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the volume of a shape to the volume of a sphere with the same perimeter. Given a shape of volume \(A\) and surface \(S\), the sphere with the same surface has radius \(r_S = \sqrt{\frac{S}{4\pi}}\) and therefore has volume \(V_{sphere} = \frac{4}{3} \pi r_S^3 = \frac{S^{3/2}}{\sqrt{4\pi}}\). Taking the ratio of volumes gives:

\[\begin{equation} \frac{V}{V_{sphere}} = \frac{6\sqrt{\pi} V}{S^{3/2}} \end{equation}\]

To avoid inconvenient fractional exponents, the isoperimetric quotient is conventionally defined as the square of this quantity:

\[\begin{split}\begin{align} IQ &= \left(\frac{V}{V_{sphere}}\right)^2 \\ &= \frac{36\pi V^2}{S^3} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Determine whether points are contained in this spheropolyhedron.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the spheropolyhedron.

Return type:

\((N, )\) numpy.ndarray

Example

>>> sphero = coxeter.shapes.ConvexSpheropolyhedron(
...   [[1, 1, 1], [1, -1, 1], [1, 1, -1], [1, -1, -1],
...    [-1, 1, 1], [-1, -1, 1], [-1, 1, -1], [-1, -1, -1]],
...   radius=0.5)
>>> sphero.is_inside([[0, 0, 0], [10, 10, 10]])
array([ True, False])
property maximal_bounded_sphere#

Get the largest bounded sphere.

The largest sphere contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the insphere of a polyhedron), this property is named as an explicit analog to minimal_bounding_sphere.

Type:

Sphere

property maximal_bounded_sphere_radius#

Get or set the radius of the maximal bounded sphere.

See maximal_bounded_sphere() for more information.

Type:

float

property maximal_centered_bounded_sphere#

Get the largest concentric bounded sphere.

This property gives the largest sphere that fits in the shape whose center also coincides with the center of the shape.

Type:

Sphere

property maximal_centered_bounded_sphere_radius#

Get or set the radius of the maximal centered bounded sphere.

See maximal_centered_bounded_sphere() for more information.

Type:

float

property mean_curvature#

Get the mean curvature.

Type:

float

property minimal_bounding_sphere#

Get a bounding sphere sharing the center of this shape.

A bounding sphere of a collection of points in dimensions is a sphere containing all of the points. There are an infinite set of possible bounding spheres for a shape (since any sphere that entirely contains a bounding sphere is also a bounding sphere), so additional constraints must be imposed to define a unique sphere. This property provides the smallest bounding sphere of a shape.

Type:

Sphere

property minimal_bounding_sphere_radius#

Get or set the radius of the minimal bounding sphere.

See minimal_bounding_sphere() for more information.

Type:

float

property minimal_centered_bounding_sphere#

Get a bounding sphere sharing the center of this shape.

A bounding sphere of a collection of points in is a sphere containing all of the points. There are an infinite set of possible bounding spheres for a shape (since any sphere that entirely contains a bounding sphere is also a bounding sphere), so additional constraints must be imposed to define a unique sphere. This property provides the smallest bounding sphere of a shape whose center coincides with the center of the shape.

Type:

Sphere

property minimal_centered_bounding_sphere_radius#

Get or set the radius of the minimal concentric bounding sphere.

See minimal_centered_bounding_sphere() for more information.

Type:

float

plot()#

Plot the shape.

property polyhedron#

The underlying polyhedron.

Type:

ConvexPolyhedron

property radius#

The rounding radius.

Type:

float

property surface_area#

Get the surface area.

Type:

float

to_hoomd()#

Get a JSON-serializable subset of ConvexSpheropolyhedron properties.

The JSON-serializable output of the to_hoomd method can be directly imported into data management tools like signac. This data can then be queried for use in HOOMD simulations. Key naming matches HOOMD integrators: for example, the moment_inertia key links to data from coxeter’s inertia_tensor. Stored values are based on the shape with its centroid at the origin.

For a ConvexSpheropolyhedron, the following properties are stored:

  • vertices (list(list)):

    The vertices of the shape.

  • centroid (list(float))

    The centroid of the shape. This is set to [0,0,0] per HOOMD’s spec.

  • sweep_radius (float):

    The rounding radius of the shape.

  • volume (float)

    The volume of the shape.

Returns:

Dict containing a subset of shape properties required for HOOMD function.

Return type:

dict

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

property vertices#

Get the vertices of the spheropolyhedron.

property volume#

The volume.

Type:

float

class coxeter.shapes.Ellipse(a, b, center=(0, 0, 0))#

Bases: Shape2D

An ellipse with principal axes a and b.

Parameters:
  • a (float) – Principal axis a of the ellipse (radius in the \(x\) direction).

  • b (float) – Principal axis b of the ellipse (radius in the \(y\) direction).

  • center (Sequence[float]) – The coordinates of the centroid of the ellipse (Default value: (0, 0, 0)).

Example

>>> ellipse = coxeter.shapes.Ellipse(1.0, 2.0)
>>> ellipse.a
1.0
>>> ellipse.b
2.0
>>> ellipse.area
6.28318...
>>> ellipse.centroid
array([0, 0, 0])
>>> ellipse.circumference
9.68844...
>>> ellipse.eccentricity
0.86602...
>>> ellipse.gsd_shape_spec
{'type': 'Ellipsoid', 'a': 1.0, 'b': 2.0}
>>> ellipse.iq
0.84116...
>>> ellipse.perimeter
9.68844...
>>> ellipse.polar_moment_inertia
7.85398...

Attributes:

a

Length of principal axis a (radius in the \(x\) direction).

area

Get or set the area.

b

Length of principal axis b (radius in the \(y\) direction).

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

circumference

Alias for Ellipse.perimeter.

eccentricity

The eccentricity.

gsd_shape_spec

Get a complete GSD specification.

inertia_tensor

Get the inertia tensor.

iq

The isoperimetric quotient.

maximal_bounded_circle

Get the largest bounded circle.

maximal_bounded_circle_radius

Get or set the radius of the maximal bounded circle.

maximal_centered_bounded_circle

Get the largest bounded concentric circle.

maximal_centered_bounded_circle_radius

Get or set the radius of the maximal centered bounded circle.

minimal_bounding_circle

Get the smallest bounding circle.

minimal_bounding_circle_radius

Get or set the radius of the minimal bounding circle.

minimal_centered_bounding_circle

Get the smallest bounding concentric circle.

minimal_centered_bounding_circle_radius

Get or set the radius of the minimal centered bounding circle.

perimeter

The perimeter.

planar_moments_inertia

Get the planar and product moments of inertia.

polar_moment_inertia

Get the polar moment of inertia.

Methods:

compute_form_factor_amplitude(q)

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

is_inside(points)

Determine whether a set of points are contained in this ellipse.

plot()

Plot the shape.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property a#

Length of principal axis a (radius in the \(x\) direction).

Type:

float

property area#

Get or set the area.

Type:

float

property b#

Length of principal axis b (radius in the \(y\) direction).

Type:

float

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

property circumference#

Alias for Ellipse.perimeter.

Type:

float

compute_form_factor_amplitude(q)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property eccentricity#

The eccentricity.

An ellipse’s eccentricity is defined as \(e = \sqrt{1 - \frac{b^2}{a^2}}\) where \(b\) is the length of the smaller semi-axis and \(a\) is the length of the larger semi-axis.

Type:

float

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property inertia_tensor#

Get the inertia tensor.

For non-orientable 2D shapes, the inertia tensor can be trivially constructed from the polar moment of inertia. This calculation assumes that the shape lies in the \(xy\)-plane. Shapes that can be rotated relative to this plane must define their own methods.

Type:

\((3, 3)\) numpy.ndarray

property iq#

The isoperimetric quotient.

Type:

float

is_inside(points)#

Determine whether a set of points are contained in this ellipse.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the ellipsoid.

Return type:

\((N, )\) numpy.ndarray

Example

>>> ellipse = coxeter.shapes.Ellipse(1.0, 2.0)
>>> ellipse.is_inside([[0, 0, 0], [100, 1, 1]])
array([ True, False])
property maximal_bounded_circle#

Get the largest bounded circle.

Type:

Circle

property maximal_bounded_circle_radius#

Get or set the radius of the maximal bounded circle.

See maximal_bounded_circle() for more information.

Type:

float

property maximal_centered_bounded_circle#

Get the largest bounded concentric circle.

Type:

Circle

property maximal_centered_bounded_circle_radius#

Get or set the radius of the maximal centered bounded circle.

See maximal_centered_bounded_circle() for more information.

Type:

float

property minimal_bounding_circle#

Get the smallest bounding circle.

Type:

Circle

property minimal_bounding_circle_radius#

Get or set the radius of the minimal bounding circle.

See minimal_bounding_circle() for more information.

Type:

float

property minimal_centered_bounding_circle#

Get the smallest bounding concentric circle.

Type:

Circle

property minimal_centered_bounding_circle_radius#

Get or set the radius of the minimal centered bounding circle.

See minimal_centered_bounding_circle() for more information.

Type:

float

property perimeter#

The perimeter.

Type:

float

property planar_moments_inertia#

Get the planar and product moments of inertia.

Moments are computed with respect to the \(x\) and \(y\) axes. In addition to the two planar moments, this property also provides the product of inertia.

The planar moments and the product of inertia are defined by the formulas:

\[\begin{split}\begin{align} I_x &= {\int \int}_A y^2 dA = \frac{\pi}{4} a b^3 = \frac{Ab^2}{4} \\ I_y &= {\int \int}_A x^2 dA = \frac{\pi}{4} a^3 b = \frac{Aa^2}{4} \\ I_{xy} &= {\int \int}_A xy dA = 0 \\ \end{align}\end{split}\]

These formulas are given here. Note that the product moment is zero by symmetry.

Type:

list[float, float, float]

plot()#

Plot the shape.

property polar_moment_inertia#

Get the polar moment of inertia.

The polar moment of inertia is always calculated about an axis perpendicular to the shape (i.e. the normal vector).

The polar moment is computed as the sum of the two planar moments of inertia.

Type:

float

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

class coxeter.shapes.Ellipsoid(a, b, c, center=(0, 0, 0))#

Bases: Shape3D

An ellipsoid with principal axes a, b, and c.

Parameters:
  • a (float) – Length of the principal semi-axis of the ellipsoid in the \(x\) direction.

  • b (float) – Length of the principal semi-axis of the ellipsoid in the \(y\) direction.

  • c (float) – Length of the principal semi-axis of the ellipsoid in the \(z\) direction.

  • center (Sequence[float]) – The coordinates of the centroid of the ellipsoid (Default value: (0, 0, 0)).

Example

>>> ellipsoid = coxeter.shapes.Ellipsoid(1.0, 3.0, 2.0)
>>> ellipsoid.a
1.0
>>> ellipsoid.b
3.0
>>> ellipsoid.c
2.0
>>> ellipsoid.centroid
array([0, 0, 0])
>>> ellipsoid.gsd_shape_spec
{'type': 'Ellipsoid', 'a': 1.0, 'b': 3.0, 'c': 2.0}
>>> ellipsoid.inertia_tensor
array([[65.34512...,  0.        ,  0.        ],
       [ 0.        , 25.13274...,  0.        ],
       [ 0.        ,  0.        , 50.26548...]])
>>> ellipsoid.iq
0.61161...
>>> ellipsoid.surface_area
48.88214...
>>> ellipsoid.volume
25.13274...

Attributes:

a

Get or set the length of principal axis a (the \(x\) radius).

b

Get or set the length of principal axis b (the \(y\) radius).

c

Get or set the length of principal axis c (the \(z\) radius).

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

gsd_shape_spec

Get a complete GSD specification.

inertia_tensor

Get the inertia tensor.

iq

The isoperimetric quotient.

maximal_bounded_sphere

Get the largest bounded sphere.

maximal_bounded_sphere_radius

Get or set the radius of the maximal bounded sphere.

maximal_centered_bounded_sphere

Get the largest bounded concentric sphere.

maximal_centered_bounded_sphere_radius

Get or set the radius of the maximal centered bounded sphere.

minimal_bounding_sphere

Get the smallest bounding sphere.

minimal_bounding_sphere_radius

Get or set the radius of the minimal bounding sphere.

minimal_centered_bounding_sphere

Get the smallest bounding concentric sphere.

minimal_centered_bounding_sphere_radius

Get or set the radius of the minimal concentric bounding sphere.

surface_area

Get the surface area.

volume

Get or set the volume.

Methods:

compute_form_factor_amplitude(q)

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

is_inside(points)

Determine whether a set of points are contained in this ellipsoid.

plot()

Plot the shape.

to_hoomd()

Get a JSON-serializable subset of Ellipsoid properties.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property a#

Get or set the length of principal axis a (the \(x\) radius).

Type:

float

property b#

Get or set the length of principal axis b (the \(y\) radius).

Type:

float

property c#

Get or set the length of principal axis c (the \(z\) radius).

Type:

float

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

compute_form_factor_amplitude(q)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property inertia_tensor#

Get the inertia tensor.

Assumes a constant density of 1.

Type:

\((3, 3)\) numpy.ndarray

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the volume of a shape to the volume of a sphere with the same perimeter. Given a shape of volume \(A\) and surface \(S\), the sphere with the same surface has radius \(r_S = \sqrt{\frac{S}{4\pi}}\) and therefore has volume \(V_{sphere} = \frac{4}{3} \pi r_S^3 = \frac{S^{3/2}}{\sqrt{4\pi}}\). Taking the ratio of volumes gives:

\[\begin{equation} \frac{V}{V_{sphere}} = \frac{6\sqrt{\pi} V}{S^{3/2}} \end{equation}\]

To avoid inconvenient fractional exponents, the isoperimetric quotient is conventionally defined as the square of this quantity:

\[\begin{split}\begin{align} IQ &= \left(\frac{V}{V_{sphere}}\right)^2 \\ &= \frac{36\pi V^2}{S^3} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Determine whether a set of points are contained in this ellipsoid.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the ellipsoid.

Return type:

\((N, )\) numpy.ndarray

Example

>>> ellipsoid = coxeter.shapes.Ellipsoid(1.0, 2.0, 3.0)
>>> ellipsoid.is_inside([[0, 0, 0], [100, 1, 1]])
array([ True, False])
property maximal_bounded_sphere#

Get the largest bounded sphere.

Type:

Sphere

property maximal_bounded_sphere_radius#

Get or set the radius of the maximal bounded sphere.

See maximal_bounded_sphere() for more information.

Type:

float

property maximal_centered_bounded_sphere#

Get the largest bounded concentric sphere.

Type:

Sphere

property maximal_centered_bounded_sphere_radius#

Get or set the radius of the maximal centered bounded sphere.

See maximal_centered_bounded_sphere() for more information.

Type:

float

property minimal_bounding_sphere#

Get the smallest bounding sphere.

Type:

Sphere

property minimal_bounding_sphere_radius#

Get or set the radius of the minimal bounding sphere.

See minimal_bounding_sphere() for more information.

Type:

float

property minimal_centered_bounding_sphere#

Get the smallest bounding concentric sphere.

Type:

Sphere

property minimal_centered_bounding_sphere_radius#

Get or set the radius of the minimal concentric bounding sphere.

See minimal_centered_bounding_sphere() for more information.

Type:

float

plot()#

Plot the shape.

property surface_area#

Get the surface area.

Type:

float

to_hoomd()#

Get a JSON-serializable subset of Ellipsoid properties.

The JSON-serializable output of the to_hoomd method can be directly imported into data management tools like signac. This data can then be queried for use in HOOMD simulations. Key naming matches HOOMD integrators: for example, the moment_inertia key links to data from coxeter’s inertia_tensor. Stored values are based on the shape with its centroid at the origin.

For an Ellipsoid, the following properties are stored:

  • a (float):

    half axis of ellipsoid in the x direction

  • b (float):

    half axis of ellipsoid in the y direction

  • c (float):

    half axis of ellipsoid in the z direction

  • centroid (list(float))

    The centroid of the shape. This is set to [0,0,0] per HOOMD’s spec.

  • volume (float)

    The volume of the shape.

  • moment_inertia (list(list))

    The shape’s inertia tensor.

Returns:

Dict containing a subset of shape properties required for HOOMD function.

Return type:

dict

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

property volume#

Get or set the volume.

Type:

float

class coxeter.shapes.Polygon(vertices, normal=None, planar_tolerance=1e-05, test_simple=True)#

Bases: Shape2D

A simple (non-self-overlapping) polygon.

The polygon is embedded in 3-dimensions, so the normal vector determines which way is “up”.

Note

This class is designed for polygons without self-intersections, so the internal sorting will automatically result in such intersections being removed.

Parameters:
  • vertices (\((N, 3)\) or \((N, 2)\) numpy.ndarray) – The vertices of the polygon.

  • normal (sequence of length 3 or None) – The normal vector to the polygon. If None, the normal is computed by taking the cross product of the vectors formed by the first three vertices np.cross(vertices[2, :] - vertices[1, :], vertices[0, :] - vertices[1, :]). This choice is made so that if the provided vertices are in the \(xy\) plane and are specified in counterclockwise order, the resulting normal is the \(z\) axis. Since this arbitrary choice may not preserve the orientation of the provided vertices, users may provide a normal instead (Default value: None).

  • planar_tolerance (float) – The tolerance to use to verify that the vertices are planar. Providing this argument may be necessary if you have a large number of vertices and are rotated significantly out of the plane.

  • test_simple (bool) – If True, perform a sanity check on construction that the provided vertices constitute a simple polygon. If this check is omitted, the class may produce invalid results if the user inputs incorrect coordinates, so this flag should be set to False with care.

Example

>>> triangle = coxeter.shapes.Polygon([[-1, 0], [0, 1], [1, 0]])
>>> import numpy as np
>>> assert np.isclose(triangle.area, 1.0)
>>> bounding_circle = triangle.minimal_bounding_circle
>>> assert np.isclose(bounding_circle.radius, 1.0)
>>> assert np.allclose(triangle.center, [0., 1. / 3., 0.])
>>> circumcircle = triangle.circumcircle
>>> assert np.isclose(circumcircle.radius, 1.0)
>>> triangle.gsd_shape_spec
{'type': 'Polygon', 'vertices': [[-1.0, 0.0, 0.0], [0.0, 1.0, 0.0],
[1.0, 0.0, 0.0]]}
>>> assert np.allclose(
...   triangle.inertia_tensor,
...   np.diag([1. / 9., 0., 1. / 3.]))
>>> triangle.normal
array([ 0., -0., -1.])
>>> assert np.allclose(
...   triangle.planar_moments_inertia,
...   (1. / 6., 1. / 6., 0.))
>>> assert np.isclose(triangle.polar_moment_inertia, 1. / 3.)
>>> assert np.isclose(triangle.signed_area, 1.0)

Attributes:

area

Get or set the polygon's area.

bounding_circle

Get the minimal bounding circle.

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

circumcircle

Get the polygon's circumcircle.

circumcircle_radius

Get the radius of the polygon's circumcircle.

gsd_shape_spec

Get a complete GSD specification.

incircle

Get the polygon's incircle.

incircle_radius

Get the radius of the polygon's incircle.

inertia_tensor

Get the inertia tensor.

iq

The isoperimetric quotient.

maximal_bounded_circle

Get the largest bounded circle.

maximal_bounded_circle_radius

Get or set the radius of the maximal bounded circle.

maximal_centered_bounded_circle

Get the largest concentric bounded circle.

maximal_centered_bounded_circle_radius

Get or set the radius of the maximal centered bounded circle.

minimal_bounding_circle

Get the minimal bounding circle.

minimal_bounding_circle_radius

Get or set the radius of the minimal bounding circle.

minimal_centered_bounding_circle

Get the smallest bounding concentric circle.

minimal_centered_bounding_circle_radius

Get or set the radius of the minimal centered bounding circle.

normal

Get the normal vector.

num_vertices

Get the number of vertices.

perimeter

Get the perimeter of the polygon.

planar_moments_inertia

Get the planar and product moments of inertia.

polar_moment_inertia

Get the polar moment of inertia.

signed_area

Get the polygon's area.

vertices

Get the vertices of the polygon.

Methods:

compute_form_factor_amplitude(q[, density])

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

is_inside(points)

Implement a simple point-in-polygon algorithm based on winding number.

plot([ax, center, plot_verts, label_verts])

Plot the polygon.

to_hoomd()

Get a JSON-serializable subset of Polygon properties.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property area#

Get or set the polygon’s area.

To get the area, we simply compute the signed area and take the absolute value.

Type:

float

property bounding_circle#

Get the minimal bounding circle.

Type:

Circle

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

The centroid of a polygon is calculated according to this formula.

Type:

\((3, )\) numpy.ndarray of float

property circumcircle#

Get the polygon’s circumcircle.

A circumcircle must touch all the points of the polygon. A circumcircle exists if and only if there is a point equidistant from all the vertices. The circumcircle is found by finding the least squares solution of the overdetermined system of linear equations defined by this constraint, and the circumcircle only exists if the resulting solution has no residual.

Raises:

RuntimeError – If no circumcircle exists for this polygon.:

Type:

Circle

property circumcircle_radius#

Get the radius of the polygon’s circumcircle.

Type:

float

compute_form_factor_amplitude(q, density=1.0)#

Calculate the form factor intensity.

The form factor amplitude of a polygon is computed according to the derivation provided in this dissertation: https://deepblue.lib.umich.edu/handle/2027.42/120906. The Kelvin-Stokes theorem allows reducing the surface integral to a line integral around the boundary.

For more generic information about form factors, see Shape.compute_form_factor_amplitude.

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property incircle#

Get the polygon’s incircle.

Note

The incircle of a polygon is defined as the circle contained within the polygon that is tangent to all its faces. This condition uniquely defines the circle, if it exists. The set of equations defined by this equation is solved using a least squares approach, with the magnitude of the residual used to determine whether or not the incircle exists.

Type:

Sphere

property incircle_radius#

Get the radius of the polygon’s incircle.

Type:

float

property inertia_tensor#

Get the inertia tensor.

The inertia tensor is computed for the polygon embedded in \(\mathbb{R}^3\). This computation proceeds by first computing the polar moment of inertia for the polygon in the \(xy\)-plane relative to its centroid. The tensor is then rotated back to the orientation of the polygon and shifted to the original centroid.

Type:

\((3, 3)\) numpy.ndarray

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the area of a shape to the area of a circle with the same perimeter. Given a shape of area \(A\) and perimeter \(p\), the circle with the same perimeter has radius \(r_p = \frac{p}{2\pi}\) and therefore has an area \(A_{circle} = \pi r_p^2 = \frac{p^2}{4\pi}\). Therefore, we have that:

\[\begin{split}\begin{align} IQ &= \frac{A}{A_{circle}} \\ &= \frac{4\pi A}{p^2} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Implement a simple point-in-polygon algorithm based on winding number.

The code in this function is based on implementation in [Dic19] which is licensed under the BSD-3 license.

Given a closed, possibly non-simple polygon described as a list of vertices in \(\mathbb{R}^2\) and a point that doesn’t lie directly on the path of the polygon, we’d like to compute the winding number of the polygon around the point. To achieve this, we place the point at the origin. Divide the remainder of the plane (i.e., \(\mathbb{R}^2\) minus the origin) into two halves, \(L\) and \(R\), defined as follows:

\[ \begin{align}\begin{aligned}L = {(x, y) | x < 0 \lor x = 0 \land y < 0}\\R = {(x, y) | x > 0 \lor x = 0 \land y > 0}\end{aligned}\end{align} \]

That is, \(R\) contains all points with argument in the half-closed interval \(\left[-\frac{\pi}{2},\frac{\pi}{2}\right)\), and \(L\) contains all others. Note that with these definitions, \(L\) and \(R\) are both convex: a line segment between two points in \(R\) lies entirely in \(R\), and similarly for \(L\). In particular, a line segment between two points can only pass through the origin if one of those points is in \(L\) and the other in \(R\). Now, we follow the edges of the polygon, keeping track of how many times we move between \(L\) and \(R\). For each move from \(L\) to \(R\) (or vice versa), we also need to compute whether the edge passes above or below the origin, to compute its contribution to the total winding number. From the comment above, we can safely ignore all edges that lie entirely within either \(L\) or \(R\).

Note

Points on the boundary of the shape will return False.

Parameters:

points (\((N, 3)\) or \((N, 2)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the polyhedron.

Return type:

\((N, )\) numpy.ndarray

property maximal_bounded_circle#

Get the largest bounded circle.

The largest circle contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the incircle of a polygon), this property is named as an explicit analog to minimal_bounding_circle.

Type:

Circle

property maximal_bounded_circle_radius#

Get or set the radius of the maximal bounded circle.

See maximal_bounded_circle() for more information.

Type:

float

property maximal_centered_bounded_circle#

Get the largest concentric bounded circle.

This property gives the largest circle that fits in the shape whose center also coincides with the center of the shape.

Type:

Circle

property maximal_centered_bounded_circle_radius#

Get or set the radius of the maximal centered bounded circle.

See maximal_centered_bounded_circle() for more information.

Type:

float

property minimal_bounding_circle#

Get the minimal bounding circle.

Type:

Circle

property minimal_bounding_circle_radius#

Get or set the radius of the minimal bounding circle.

See minimal_bounding_circle() for more information.

Type:

float

property minimal_centered_bounding_circle#

Get the smallest bounding concentric circle.

This property gives the smallest bounding circle whose center coincides with the center of the shape.

Type:

Circle

property minimal_centered_bounding_circle_radius#

Get or set the radius of the minimal centered bounding circle.

See minimal_centered_bounding_circle() for more information.

Type:

float

property normal#

Get the normal vector.

Type:

\((3, )\) numpy.ndarray of float

property num_vertices#

Get the number of vertices.

Type:

int

property perimeter#

Get the perimeter of the polygon.

Type:

float

property planar_moments_inertia#

Get the planar and product moments of inertia.

Moments are computed with respect to the \(x\) and \(y\) axes. In addition to the two planar moments, this property also provides the product of inertia.

The planar moments and the product of inertia are defined by the formulas:

\[\begin{split}\begin{align} I_x &= {\int \int}_A y^2 dA \\ I_y &= {\int \int}_A x^2 dA \\ I_{xy} &= {\int \int}_A xy dA \\ \end{align}\end{split}\]

To compute this for a polygon, we discretize the sum:

\[\begin{split}\begin{align} I_x &= \frac{1}{12} \sum_{i=1}^N (x_i y_{i+1} - x_{i+1} y_i) (y_i^2 + y_i*y_{i+1} + y_{i+1}^2) \\ I_y &= \frac{1}{12} \sum_{i=1}^N (x_i y_{i+1} - x_{i+1} y_i) (x_i^2 + x_i*x_{i+1} + x_{i+1}^2) \\ I_{xy} &= \frac{1}{12} \sum_{i=1}^N (x_i y_{i+1} - x_{i+1} y_i) (x_i y_{i+1} + 2 x_i y_i + 2 x_{i+1} y_{i+1} + x_{i+1} y_i) \\ \end{align}\end{split}\]

These formulas can be derived as described here.

Note that the moments are always calculated about an axis perpendicular to the polygon, i.e. the normal vector is aligned with the \(z\) axis before the moments are calculated. This alignment should be considered when computing the moments for polygons embedded in three-dimensional space that are rotated out of the \(xy\) plane, since the planar moments are invariant to this orientation. The exact rotation used for this computation (i.e. changes in the \(x\) and \(y\) position) should not be relied upon.

Type:

list[float, float, float]

plot(ax=None, center=False, plot_verts=False, label_verts=False)#

Plot the polygon.

Note that the polygon is always rotated into the \(xy\) plane and plotted in two dimensions.

Parameters:
  • ax (matplotlib.axes.Axes) – The axes on which to draw the polygon. Axes will be created if this is None (Default value: None).

  • center (bool) – If True, the polygon vertices are plotted relative to its center (Default value: False).

  • plot_verts (bool) – If True, scatter points will be added at the vertices (Default value: False).

  • label_verts (bool) – If True, vertex indices will be added next to the vertices (Default value: False).

property polar_moment_inertia#

Get the polar moment of inertia.

The polar moment of inertia is always calculated about an axis perpendicular to the shape (i.e. the normal vector).

The polar moment is computed as the sum of the two planar moments of inertia.

Type:

float

property signed_area#

Get the polygon’s area.

To support polygons embedded in 3 dimensional space, we employ a projection- and rescaling-based algorithm described here. Specifically, the polygon is projected onto the plane it is “most parallel” to, the area of the projected polygon is computed, then the area is rescaled by the component of the normal in the projected dimension.

Type:

float

to_hoomd()#

Get a JSON-serializable subset of Polygon properties.

The JSON-serializable output of the to_hoomd method can be directly imported into data management tools like signac. This data can then be queried for use in HOOMD simulations. Key naming matches HOOMD integrators: for example, the moment_inertia key links to data from coxeter’s inertia_tensor. Stored values are based on the shape with its centroid at the origin.

For a Polygon or ConvexPolygon, the following properties are stored:

  • vertices (list(list)):

    The vertices of the shape.

  • centroid (list(float))

    The centroid of the shape. This is set to [0,0,0] per HOOMD’s spec.

  • sweep_radius (float):

    The rounding radius of the shape (0.0).

  • area (float)

    The area of the shape.

  • moment_inertia (list(list))

    The shape’s inertia tensor.

Returns:

Dict containing a subset of shape properties required for HOOMD function.

Return type:

dict

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

property vertices#

Get the vertices of the polygon.

Type:

\((N_{verts}, 3)\) numpy.ndarray of float

class coxeter.shapes.Polyhedron(vertices, faces, faces_are_convex=None)#

Bases: Shape3D

A three-dimensional polytope.

A polyhedron is defined by a set of vertices and a set of faces composed of the vertices. On construction, the faces are reordered counterclockwise with respect to an outward normal. The polyhedron provides various standard geometric calculations, such as volume and surface area. Most features of the polyhedron can be accessed via properties, including the plane equations defining the faces and the neighbors of each face.

Note

For the purposes of calculations like moments of inertia, the polyhedron is assumed to be of constant, unit density.

Parameters:
  • vertices (\((N, 3)\) numpy.ndarray) – The vertices of the polyhedron.

  • faces (list(list)) – The faces of the polyhedron.

  • faces_are_convex (bool, optional) – Whether or not the faces of the polyhedron are all convex. This is used to determine whether certain operations like coplanar face merging are allowed (Default value: False).

Example

>>> cube = coxeter.shapes.ConvexPolyhedron(
...   [[-1, -1, -1], [-1, -1, 1], [-1, 1, -1], [-1, 1, 1],
...    [1, -1, -1], [1, -1, 1], [1, 1, -1], [1, 1, 1]])
>>> cube = coxeter.shapes.Polyhedron(
...   vertices=cube.vertices, faces=cube.faces)
>>> bounding_sphere = cube.minimal_bounding_sphere
>>> import numpy as np
>>> assert np.isclose(bounding_sphere.radius, np.sqrt(3))
>>> cube.center
array([0., 0., 0.])
>>> cube.faces
[array([0, 2, 6, 4], dtype=int32), array([0, 4, 5, 1], dtype=int32),
array([4, 6, 7, 5], dtype=int32), array([0, 1, 3, 2], dtype=int32),
array([2, 3, 7, 6], dtype=int32), array([1, 5, 7, 3], dtype=int32)]
>>> cube.gsd_shape_spec
{'type': 'Mesh', 'vertices': [[-1.0, -1.0, -1.0], [-1.0, -1.0, 1.0],
[-1.0, 1.0, -1.0], [-1.0, 1.0, 1.0], [1.0, -1.0, -1.0], [1.0, -1.0, 1.0],
[1.0, 1.0, -1.0], [1.0, 1.0, 1.0]], 'indices':
[array([0, 2, 6, 4], dtype=int32), array([0, 4, 5, 1], dtype=int32),
array([4, 6, 7, 5], dtype=int32), array([0, 1, 3, 2], dtype=int32),
array([2, 3, 7, 6], dtype=int32), array([1, 5, 7, 3], dtype=int32)]}
>>> assert np.allclose(
...   cube.inertia_tensor,
...   np.diag([16. / 3., 16. / 3., 16. / 3.]))
>>> assert np.isclose(cube.iq, np.pi / 6.)
>>> cube.neighbors
[array([1, 2, 3, 4]), array([0, 2, 3, 5]), array([0, 1, 4, 5]),
array([0, 1, 4, 5]), array([0, 2, 3, 5]), array([1, 2, 3, 4])]
>>> cube.normals
array([[ 0.,  0., -1.],
       [ 0., -1.,  0.],
       [ 1.,  0., -0.],
       [-1.,  0.,  0.],
       [-0.,  1.,  0.],
       [ 0., -0.,  1.]])
>>> cube.num_faces
6
>>> cube.num_vertices
8
>>> assert np.isclose(cube.surface_area, 24.0)
>>> cube.vertices
array([[-1., -1., -1.],
       [-1., -1.,  1.],
       [-1.,  1., -1.],
       [-1.,  1.,  1.],
       [ 1., -1., -1.],
       [ 1., -1.,  1.],
       [ 1.,  1., -1.],
       [ 1.,  1.,  1.]])
>>> assert np.isclose(cube.volume, 8.0)

Attributes:

bounding_sphere

Get the polyhedron's bounding sphere.

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

circumsphere

Get the polyhedron's circumsphere.

circumsphere_radius

Get the radius of the polygon's circumsphere.

edge_lengths

Get the length of each edge of the polyhedron.

edge_vectors

Get the polyhedron's edges as vectors.

edges

Get the polyhedron's edges.

faces

Get the polyhedron's faces.

gsd_shape_spec

Get a complete GSD specification.

inertia_tensor

Get the inertia tensor.

insphere

Get the polyhedron's insphere.

insphere_radius

Get the radius of the polygon's insphere.

iq

The isoperimetric quotient.

maximal_bounded_sphere

Get the largest bounded sphere.

maximal_bounded_sphere_radius

Get or set the radius of the maximal bounded sphere.

maximal_centered_bounded_sphere

Get the largest concentric bounded sphere.

maximal_centered_bounded_sphere_radius

Get or set the radius of the maximal centered bounded sphere.

minimal_bounding_sphere

Get the polyhedron's bounding sphere.

minimal_bounding_sphere_radius

Get or set the radius of the minimal bounding sphere.

minimal_centered_bounding_sphere

Get a bounding sphere sharing the center of this shape.

minimal_centered_bounding_sphere_radius

Get or set the radius of the minimal concentric bounding sphere.

neighbors

Get neighboring pairs of faces.

normals

Get the face normals.

num_edges

Get the number of edges.

num_faces

Get the number of faces.

num_vertices

Get the number of vertices.

surface_area

Get the surface area.

vertices

Get the vertices of the polyhedron.

volume

Get or set the polyhedron's volume.

Methods:

compute_form_factor_amplitude(q[, density])

Calculate the form factor intensity.

diagonalize_inertia()

Orient the shape along its principal axes.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

get_dihedral(a, b)

Get the dihedral angle between a pair of faces.

get_face_area([faces])

Get the total surface area of a set of faces.

is_inside(points)

Determine whether points are contained in this polyhedron.

merge_faces([atol, rtol])

Merge coplanar faces to a given tolerance.

plot([ax, plot_verts, label_verts])

Plot the polyhedron.

sort_faces()

Sort faces of the polyhedron.

to_hoomd()

Get a JSON-serializable subset of Polyhedron properties.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property bounding_sphere#

Get the polyhedron’s bounding sphere.

Type:

Sphere

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

The centroid is computed using the algorithm described in [Ebe02].

Type:

\((3, )\) numpy.ndarray of float

property circumsphere#

Get the polyhedron’s circumsphere.

A circumsphere must touch all the points of the polyhedron. A circumsphere exists if and only if there is a point equidistant from all the vertices. The circumsphere is found by finding the least squares solution of the overdetermined system of linear equations defined by this constraint, and the circumsphere only exists if the resulting solution has no residual.

Raises:

RuntimeError – If no circumsphere exists for this polyhedron.:

Type:

Sphere

property circumsphere_radius#

Get the radius of the polygon’s circumsphere.

Type:

float

compute_form_factor_amplitude(q, density=1.0)#

Calculate the form factor intensity.

The form factor amplitude of a polyhedron is computed according to the derivation provided in this dissertation: https://deepblue.lib.umich.edu/handle/2027.42/120906. In brief, two applications of Stokes theorem (or to use the names more familiar from elementary vector calculus, the application of the divergence theorem followed by the classic Kelvin-Stokes theorem) are used to reduce the volume integral over a polyhedron into a series of line integrals around the boundaries of each polygonal face.

For more generic information about form factors, see Shape.compute_form_factor_amplitude.

diagonalize_inertia()#

Orient the shape along its principal axes.

The principal axes of a shape are defined by the eigenvectors of the inertia tensor. This method computes the inertia tensor of the shape, diagonalizes it, and then rotates the shape by the corresponding orthogonal transformation.

Example

>>> cube = coxeter.shapes.ConvexPolyhedron(
...   [[1, 1, 1], [1, -1, 1], [1, 1, -1], [1, -1, -1],
...    [-1, 1, 1], [-1, -1, 1], [-1, 1, -1], [-1, -1, -1]])
>>> cube = coxeter.shapes.Polyhedron(
...   vertices=cube.vertices, faces=cube.faces)
>>> cube.diagonalize_inertia()
>>> cube.vertices
array([[ 1.,  1.,  1.],
       [ 1., -1.,  1.],
       [ 1.,  1., -1.],
       [ 1., -1., -1.],
       [-1.,  1.,  1.],
       [-1., -1.,  1.],
       [-1.,  1., -1.],
       [-1., -1., -1.]])
distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property edge_lengths#

Get the length of each edge of the polyhedron.

edge_lengths are returned in the same order as in edges.

Type:

numpy.ndarray

property edge_vectors#

Get the polyhedron’s edges as vectors.

edge_vectors are returned in the same order as in edges.

Type:

numpy.ndarray

property edges#

Get the polyhedron’s edges.

Results returned as vertex index pairs, with each edge of the polyhedron included exactly once. Edge (i,j) pairs are ordered by vertex index with i<j.

Type:

numpy.ndarray

property faces#

Get the polyhedron’s faces.

Results returned as vertex index lists.

Type:

list(numpy.ndarray)

get_dihedral(a, b)#

Get the dihedral angle between a pair of faces.

The dihedral is computed from the dot product of the face normals.

Parameters:
  • a (int) – The index of the first face.

  • b (int) – The index of the second face.

Returns:

float

Return type:

The dihedral angle in radians.

Example

>>> cube = coxeter.shapes.ConvexPolyhedron(
...   [[1, 1, 1], [1, -1, 1], [1, 1, -1], [1, -1, -1],
...    [-1, 1, 1], [-1, -1, 1], [-1, 1, -1], [-1, -1, -1]])
>>> cube = coxeter.shapes.Polyhedron(
...   vertices=cube.vertices, faces=cube.faces)
>>> import numpy as np
>>> assert np.isclose(cube.get_dihedral(1, 2), np.pi / 2.)
get_face_area(faces=None)#

Get the total surface area of a set of faces.

Parameters:

faces (int, sequence, or None) – The index of a face or a set of face indices for which to find the area. If None, finds the area of all faces (Default value: None).

Returns:

:class:`numpy.ndarray`

Return type:

The area of each face.

Example

>>> cube = coxeter.shapes.ConvexPolyhedron(
...   [[1, 1, 1], [1, -1, 1], [1, 1, -1], [1, -1, -1],
...    [-1, 1, 1], [-1, -1, 1], [-1, 1, -1], [-1, -1, -1]])
>>> cube = coxeter.shapes.Polyhedron(
...   vertices=cube.vertices,faces=cube.faces)
>>> import numpy as np
>>> assert np.allclose(
...   cube.get_face_area([1, 2, 3]),
...   [4., 4., 4.])
property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property inertia_tensor#

Get the inertia tensor.

The inertia tensor is computed using the algorithm described in [Kal06].

Note

For improved stability, the inertia tensor is computed about the center of mass and then shifted rather than directly computed in the global frame.

Type:

\((3, 3)\) numpy.ndarray

property insphere#

Get the polyhedron’s insphere.

Note

The insphere of a polyhedron is defined as the sphere contained within the polyhedron that is tangent to all its faces. This condition uniquely defines the sphere, if it exists. The set of equations defined by this equation is solved using a least squares approach, with the magnitude of the residual used to determine whether or not the insphere exists.

Type:

Sphere

property insphere_radius#

Get the radius of the polygon’s insphere.

Type:

float

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the volume of a shape to the volume of a sphere with the same perimeter. Given a shape of volume \(A\) and surface \(S\), the sphere with the same surface has radius \(r_S = \sqrt{\frac{S}{4\pi}}\) and therefore has volume \(V_{sphere} = \frac{4}{3} \pi r_S^3 = \frac{S^{3/2}}{\sqrt{4\pi}}\). Taking the ratio of volumes gives:

\[\begin{equation} \frac{V}{V_{sphere}} = \frac{6\sqrt{\pi} V}{S^{3/2}} \end{equation}\]

To avoid inconvenient fractional exponents, the isoperimetric quotient is conventionally defined as the square of this quantity:

\[\begin{split}\begin{align} IQ &= \left(\frac{V}{V_{sphere}}\right)^2 \\ &= \frac{36\pi V^2}{S^3} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Determine whether points are contained in this polyhedron.

The code in this function is based on implementation in [Dic19] which is licensed under the BSD-3 license. The computation is based on calculation of winding number.

Note

Points on the boundary of the shape will return False.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the polyhedron.

Return type:

\((N, )\) numpy.ndarray

property maximal_bounded_sphere#

Get the largest bounded sphere.

The largest sphere contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the insphere of a polyhedron), this property is named as an explicit analog to minimal_bounding_sphere.

Type:

Sphere

property maximal_bounded_sphere_radius#

Get or set the radius of the maximal bounded sphere.

See maximal_bounded_sphere() for more information.

Type:

float

property maximal_centered_bounded_sphere#

Get the largest concentric bounded sphere.

This property gives the largest sphere that fits in the shape whose center also coincides with the center of the shape.

Type:

Sphere

property maximal_centered_bounded_sphere_radius#

Get or set the radius of the maximal centered bounded sphere.

See maximal_centered_bounded_sphere() for more information.

Type:

float

merge_faces(atol=1e-08, rtol=1e-05)#

Merge coplanar faces to a given tolerance.

Whether or not faces should be merged is determined using numpy.allclose() to compare the plane equations of neighboring faces. Connected components of mergeable faces are then merged into a single face. This method can be safely called many times with different tolerances, however, the operation is destructive in the sense that merged faces cannot be recovered. Users wishing to undo a merge to attempt a less expansive merge must build a new polyhedron.

Parameters:
property minimal_bounding_sphere#

Get the polyhedron’s bounding sphere.

Type:

Sphere

property minimal_bounding_sphere_radius#

Get or set the radius of the minimal bounding sphere.

See minimal_bounding_sphere() for more information.

Type:

float

property minimal_centered_bounding_sphere#

Get a bounding sphere sharing the center of this shape.

A bounding sphere of a collection of points in is a sphere containing all of the points. There are an infinite set of possible bounding spheres for a shape (since any sphere that entirely contains a bounding sphere is also a bounding sphere), so additional constraints must be imposed to define a unique sphere. This property provides the smallest bounding sphere of a shape whose center coincides with the center of the shape.

Type:

Sphere

property minimal_centered_bounding_sphere_radius#

Get or set the radius of the minimal concentric bounding sphere.

See minimal_centered_bounding_sphere() for more information.

Type:

float

property neighbors#

Get neighboring pairs of faces.

The neighbors are provided as a list where the \(i^{\text{th}}\) element is an array of indices of faces that are neighbors of face \(i\).

Type:

list(numpy.ndarray)

property normals#

Get the face normals.

Type:

\((N, 3)\) numpy.ndarray

property num_edges#

Get the number of edges.

Type:

int

property num_faces#

Get the number of faces.

Type:

int

property num_vertices#

Get the number of vertices.

Type:

int

plot(ax=None, plot_verts=False, label_verts=False)#

Plot the polyhedron.

Note that the ax argument should be a 3D axes object; passing in a 2D axes object will result in wrong behavior.

Parameters:
  • ax (mpl_toolkits.mplot3d.axes3d.Axes3D) – The axes on which to draw the polyhedron. Axes will be created if this is None (Default value: None).

  • plot_verts (bool) – If True, scatter points will be added at the vertices (Default value: False).

  • label_verts (bool) – If True, vertex indices will be added next to the vertices (Default value: False).

sort_faces()#

Sort faces of the polyhedron.

This method ensures that all faces are ordered such that the normals are counterclockwise and point outwards. This algorithm proceeds in four steps. First, it ensures that each face is ordered in either clockwise or counterclockwise order such that edges can be found from the sequence of the vertices in each face. Next, it calls the neighbor finding routine to establish with faces are neighbors. Then, it performs a breadth-first search, reorienting faces to match the orientation of the first face. Finally, it computes the signed volume to determine whether or not all the normals need to be flipped.

Note

This method can only be called for polyhedra whose faces are all convex (i.e. constructed with faces_are_convex=True).

property surface_area#

Get the surface area.

Type:

float

to_hoomd()#

Get a JSON-serializable subset of Polyhedron properties.

The JSON-serializable output of the to_hoomd method can be directly imported into data management tools like signac. This data can then be queried for use in HOOMD simulations. Key naming matches HOOMD integrators: for example, the moment_inertia key links to data from coxeter’s inertia_tensor. Stored values are based on the shape with its centroid at the origin.

For a Polyhedron or ConvexPolyhedron, the following properties are stored:

  • vertices (list(list)):

    The vertices of the shape.

  • faces (list(list)):

    The faces of the shape.

  • centroid (list(float))

    The centroid of the shape. This is set to [0,0,0] per HOOMD’s spec.

  • sweep_radius (float):

    The rounding radius of the shape (0.0).

  • volume (float)

    The volume of the shape.

  • moment_inertia (list(list))

    The shape’s inertia tensor.

Returns:

Dict containing a subset of shape properties required for HOOMD function.

Return type:

dict

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

property vertices#

Get the vertices of the polyhedron.

Type:

\((N, 3)\) numpy.ndarray

property volume#

Get or set the polyhedron’s volume.

Type:

float

class coxeter.shapes.Shape#

Bases: ABC

An abstract representation of a shape in N dimensions.

Attributes:

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

gsd_shape_spec

Get a complete GSD specification.

Methods:

compute_form_factor_amplitude(q)

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

inertia_tensor()

\((3, 3)\) numpy.ndarray: Get the inertia tensor.

is_inside(points)

Determine whether points are contained in this shape.

plot()

Plot the shape.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

compute_form_factor_amplitude(q)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

inertia_tensor()#

\((3, 3)\) numpy.ndarray: Get the inertia tensor.

is_inside(points)#

Determine whether points are contained in this shape.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the shape.

Return type:

\((N, )\) numpy.ndarray

plot()#

Plot the shape.

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

class coxeter.shapes.Shape2D#

Bases: Shape

An abstract representation of a shape in 2 dimensions.

Attributes:

area

Get or set the area of the shape.

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

gsd_shape_spec

Get a complete GSD specification.

inertia_tensor

Get the inertia tensor.

iq

The isoperimetric quotient.

maximal_bounded_circle

Get the largest bounded circle.

maximal_bounded_circle_radius

Get or set the radius of the maximal bounded circle.

maximal_centered_bounded_circle

Get the largest concentric bounded circle.

maximal_centered_bounded_circle_radius

Get or set the radius of the maximal centered bounded circle.

minimal_bounding_circle

Get the smallest bounding circle.

minimal_bounding_circle_radius

Get or set the radius of the minimal bounding circle.

minimal_centered_bounding_circle

Get the smallest bounding concentric circle.

minimal_centered_bounding_circle_radius

Get or set the radius of the minimal centered bounding circle.

perimeter

Get the perimeter of the shape.

planar_moments_inertia

Get the planar and product moments of inertia.

polar_moment_inertia

Get the polar moment of inertia.

Methods:

compute_form_factor_amplitude(q)

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

is_inside(points)

Determine whether points are contained in this shape.

plot()

Plot the shape.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

abstract property area#

Get or set the area of the shape.

Type:

float

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

compute_form_factor_amplitude(q)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property inertia_tensor#

Get the inertia tensor.

For non-orientable 2D shapes, the inertia tensor can be trivially constructed from the polar moment of inertia. This calculation assumes that the shape lies in the \(xy\)-plane. Shapes that can be rotated relative to this plane must define their own methods.

Type:

\((3, 3)\) numpy.ndarray

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the area of a shape to the area of a circle with the same perimeter. Given a shape of area \(A\) and perimeter \(p\), the circle with the same perimeter has radius \(r_p = \frac{p}{2\pi}\) and therefore has an area \(A_{circle} = \pi r_p^2 = \frac{p^2}{4\pi}\). Therefore, we have that:

\[\begin{split}\begin{align} IQ &= \frac{A}{A_{circle}} \\ &= \frac{4\pi A}{p^2} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Determine whether points are contained in this shape.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the shape.

Return type:

\((N, )\) numpy.ndarray

property maximal_bounded_circle#

Get the largest bounded circle.

The largest circle contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the incircle of a polygon), this property is named as an explicit analog to minimal_bounding_circle.

Type:

Circle

property maximal_bounded_circle_radius#

Get or set the radius of the maximal bounded circle.

See maximal_bounded_circle() for more information.

Type:

float

property maximal_centered_bounded_circle#

Get the largest concentric bounded circle.

This property gives the largest circle that fits in the shape whose center also coincides with the center of the shape.

Type:

Circle

property maximal_centered_bounded_circle_radius#

Get or set the radius of the maximal centered bounded circle.

See maximal_centered_bounded_circle() for more information.

Type:

float

property minimal_bounding_circle#

Get the smallest bounding circle.

A bounding circle in two dimensions is a circle containing all of the points. There are an infinite set of possible bounding circles for a shape (since any circle that entirely contains a bounding circle is also a bounding circle), so additional constraints must be imposed to define a unique circle. This property provides the smallest bounding circle of a shape.

Type:

Circle

property minimal_bounding_circle_radius#

Get or set the radius of the minimal bounding circle.

See minimal_bounding_circle() for more information.

Type:

float

property minimal_centered_bounding_circle#

Get the smallest bounding concentric circle.

This property gives the smallest bounding circle whose center coincides with the center of the shape.

Type:

Circle

property minimal_centered_bounding_circle_radius#

Get or set the radius of the minimal centered bounding circle.

See minimal_centered_bounding_circle() for more information.

Type:

float

abstract property perimeter#

Get the perimeter of the shape.

Type:

float

property planar_moments_inertia#

Get the planar and product moments of inertia.

Moments are computed with respect to the \(x\) and \(y\) axes. In addition to the two planar moments, this property also provides the product of inertia.

The planar moments of inertia and the product of inertia define the in-plane area distribution.

Type:

list[float, float, float]

plot()#

Plot the shape.

property polar_moment_inertia#

Get the polar moment of inertia.

The polar moment of inertia is always calculated about an axis perpendicular to the shape (i.e. the normal vector).

The polar moment is computed as the sum of the two planar moments of inertia.

Type:

float

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

class coxeter.shapes.Shape3D#

Bases: Shape

An abstract representation of a shape in 3 dimensions.

Attributes:

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

gsd_shape_spec

Get a complete GSD specification.

iq

The isoperimetric quotient.

maximal_bounded_sphere

Get the largest bounded sphere.

maximal_bounded_sphere_radius

Get or set the radius of the maximal bounded sphere.

maximal_centered_bounded_sphere

Get the largest concentric bounded sphere.

maximal_centered_bounded_sphere_radius

Get or set the radius of the maximal centered bounded sphere.

minimal_bounding_sphere

Get a bounding sphere sharing the center of this shape.

minimal_bounding_sphere_radius

Get or set the radius of the minimal bounding sphere.

minimal_centered_bounding_sphere

Get a bounding sphere sharing the center of this shape.

minimal_centered_bounding_sphere_radius

Get or set the radius of the minimal concentric bounding sphere.

surface_area

Get or set the surface area of the shape.

volume

Get or set the volume of the shape.

Methods:

compute_form_factor_amplitude(q)

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

inertia_tensor()

\((3, 3)\) numpy.ndarray: Get the inertia tensor.

is_inside(points)

Determine whether points are contained in this shape.

plot()

Plot the shape.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

compute_form_factor_amplitude(q)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

inertia_tensor()#

\((3, 3)\) numpy.ndarray: Get the inertia tensor.

property iq#

The isoperimetric quotient.

The isoperimetric quotient is the ratio of the volume of a shape to the volume of a sphere with the same perimeter. Given a shape of volume \(A\) and surface \(S\), the sphere with the same surface has radius \(r_S = \sqrt{\frac{S}{4\pi}}\) and therefore has volume \(V_{sphere} = \frac{4}{3} \pi r_S^3 = \frac{S^{3/2}}{\sqrt{4\pi}}\). Taking the ratio of volumes gives:

\[\begin{equation} \frac{V}{V_{sphere}} = \frac{6\sqrt{\pi} V}{S^{3/2}} \end{equation}\]

To avoid inconvenient fractional exponents, the isoperimetric quotient is conventionally defined as the square of this quantity:

\[\begin{split}\begin{align} IQ &= \left(\frac{V}{V_{sphere}}\right)^2 \\ &= \frac{36\pi V^2}{S^3} \end{align}\end{split}\]
Type:

float

is_inside(points)#

Determine whether points are contained in this shape.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the shape.

Return type:

\((N, )\) numpy.ndarray

property maximal_bounded_sphere#

Get the largest bounded sphere.

The largest sphere contained in a shape is referred to by a range of ambiguous names. To avoid conflicts with the most common naming choices of other properties in the literature (particularly the insphere of a polyhedron), this property is named as an explicit analog to minimal_bounding_sphere.

Type:

Sphere

property maximal_bounded_sphere_radius#

Get or set the radius of the maximal bounded sphere.

See maximal_bounded_sphere() for more information.

Type:

float

property maximal_centered_bounded_sphere#

Get the largest concentric bounded sphere.

This property gives the largest sphere that fits in the shape whose center also coincides with the center of the shape.

Type:

Sphere

property maximal_centered_bounded_sphere_radius#

Get or set the radius of the maximal centered bounded sphere.

See maximal_centered_bounded_sphere() for more information.

Type:

float

property minimal_bounding_sphere#

Get a bounding sphere sharing the center of this shape.

A bounding sphere of a collection of points in dimensions is a sphere containing all of the points. There are an infinite set of possible bounding spheres for a shape (since any sphere that entirely contains a bounding sphere is also a bounding sphere), so additional constraints must be imposed to define a unique sphere. This property provides the smallest bounding sphere of a shape.

Type:

Sphere

property minimal_bounding_sphere_radius#

Get or set the radius of the minimal bounding sphere.

See minimal_bounding_sphere() for more information.

Type:

float

property minimal_centered_bounding_sphere#

Get a bounding sphere sharing the center of this shape.

A bounding sphere of a collection of points in is a sphere containing all of the points. There are an infinite set of possible bounding spheres for a shape (since any sphere that entirely contains a bounding sphere is also a bounding sphere), so additional constraints must be imposed to define a unique sphere. This property provides the smallest bounding sphere of a shape whose center coincides with the center of the shape.

Type:

Sphere

property minimal_centered_bounding_sphere_radius#

Get or set the radius of the minimal concentric bounding sphere.

See minimal_centered_bounding_sphere() for more information.

Type:

float

plot()#

Plot the shape.

abstract property surface_area#

Get or set the surface area of the shape.

Type:

float

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

abstract property volume#

Get or set the volume of the shape.

Type:

float

class coxeter.shapes.Sphere(radius, center=(0, 0, 0))#

Bases: Shape3D

A sphere with the given radius.

Parameters:
  • radius (float) – Radius of the sphere.

  • center (Sequence[float]) – The coordinates of the centroid of the sphere (Default value: (0, 0, 0)).

Example

>>> sphere = coxeter.shapes.Sphere(1.0)
>>> assert np.isclose(sphere.radius, 1.0)
>>> assert np.allclose(sphere.centroid, [0., 0., 0.])
>>> sphere.gsd_shape_spec
{'type': 'Sphere', 'diameter': 2.0}
>>> assert np.allclose(
...   np.diag(sphere.inertia_tensor),
...   8. / 15. * np.pi)
>>> sphere.iq
1
>>> sphere.surface_area
12.56637...
>>> sphere.volume
4.18879...

Attributes:

center

Alias for centroid.

centroid

Get or set the centroid of the shape.

diameter

Get or set the radius of the sphere.

gsd_shape_spec

Get a complete GSD specification.

inertia_tensor

Get the inertia tensor.

iq

The isoperimetric quotient.

maximal_bounded_sphere

Get the largest bounded sphere.

maximal_bounded_sphere_radius

Get or set the radius of the maximal bounded sphere.

maximal_centered_bounded_sphere

Get the largest bounded concentric sphere.

maximal_centered_bounded_sphere_radius

Get or set the radius of the maximal centered bounded sphere.

minimal_bounding_sphere

Get the smallest bounding sphere.

minimal_bounding_sphere_radius

Get or set the radius of the minimal bounding sphere.

minimal_centered_bounding_sphere

Get the smallest bounding concentric sphere.

minimal_centered_bounding_sphere_radius

Get or set the radius of the minimal concentric bounding sphere.

radius

Get or set the radius of the sphere.

surface_area

Get the surface area.

volume

Get the volume of the sphere.

Methods:

compute_form_factor_amplitude(q[, density])

Calculate the form factor intensity.

distance_to_surface(angles)

Compute the distance to the surface of the shape at the given angles.

is_inside(points)

Determine whether a set of points are contained in this sphere.

plot()

Plot the shape.

to_hoomd()

Get a dict of JSON-serializable subset of Sphere properties.

to_json(attributes)

Get a JSON-serializable subset of shape properties.

to_plato_scene([backend, scene, scene_kwargs])

Add this shape to a new or existing plato.draw.Scene.

property center#

Alias for centroid.

Type:

\((3, )\) numpy.ndarray of float

property centroid#

Get or set the centroid of the shape.

Type:

\((3, )\) numpy.ndarray of float

compute_form_factor_amplitude(q, density=1.0)#

Calculate the form factor intensity.

In solid state physics, scattering theory is concerned with understanding the ways in which radiation is scattered from a sample. For a single point particle at position P, the the amplitude of a scattered wave observed at position Q is the product of the incoming wave amplitude (which follows the standard equation for a traveling wave) and the scattering density at P. For a crystal composed of many point particles, the intensity of the resulting superposition of waves can be identified as the Fourier transform of the total scattering density. When the particles are not point particles, the scattering density of the particles in their local coordinate systems are no longer identical. Conveniently, this component is separable in the Fourier transform of the total density; as a result, the scattering scattering intensity can be decomposed into two terms, the Fourier transform of the distribution of scatterers and the Fourier transform of each scatterer in its local coordinate system. The first term is known as the static structure factor \(S(\vec{q})\) and describes the spatial distribution of scatterers, while the second term is called the form factor \(f(\vec{q})\) and describes the local scattering profile.

While the form factor (the scattering intensity) can be measured from diffraction experiments, the Fourier transform of a single particle cannot. However, it can be computed theoretically for a known scattering volume and can be inserted directly into the expression for the total scattering intensity. This local profile directly describes the wave emitted from a single scatterer (in reciprocal space) and is known as the form factor amplitude. This function computes the form factor amplitude for a given wavevector \(q\).

property diameter#

Get or set the radius of the sphere.

Type:

float

distance_to_surface(angles)#

Compute the distance to the surface of the shape at the given angles.

Gets the distance to the surface at each of the angles provided, where the definition of the angles depends on the dimensionality of the shape (a single angle in 2D, or the phi/theta angles in 3D). All angles are relative to the x axis. In general, the distance is computed from the centroid of the shape unless stated otherwise.

Parameters:

angles (\((N, d-1)\) numpy.ndarray) – Angles between \(0\) and \(2 \pi\) over which to calculate the distances. \(d\) is the number of dimensions.

Returns:

An array of distances from the center of the shape to its surface at each of the given angles.

Return type:

\((N,)\) numpy.ndarray

property gsd_shape_spec#

Get a complete GSD specification.

Type:

dict

property inertia_tensor#

Get the inertia tensor.

Assumes a constant density of 1.

Type:

\((3, 3)\) numpy.ndarray

property iq#

The isoperimetric quotient.

This is 1 by definition for spheres.

Type:

float

is_inside(points)#

Determine whether a set of points are contained in this sphere.

Note

Points on the boundary of the shape will return True.

Parameters:

points (\((N, 3)\) numpy.ndarray) – The points to test.

Returns:

Boolean array indicating which points are contained in the sphere.

Return type:

\((N, )\) numpy.ndarray

Example

>>> sphere = coxeter.shapes.Sphere(1.0)
>>> sphere.is_inside([[0, 0, 0], [20, 20, 20]])
array([ True, False])
property maximal_bounded_sphere#

Get the largest bounded sphere.

Type:

Sphere

property maximal_bounded_sphere_radius#

Get or set the radius of the maximal bounded sphere.

See maximal_bounded_sphere() for more information.

Type:

float

property maximal_centered_bounded_sphere#

Get the largest bounded concentric sphere.

Type:

Sphere

property maximal_centered_bounded_sphere_radius#

Get or set the radius of the maximal centered bounded sphere.

See maximal_centered_bounded_sphere() for more information.

Type:

float

property minimal_bounding_sphere#

Get the smallest bounding sphere.

Type:

Sphere

property minimal_bounding_sphere_radius#

Get or set the radius of the minimal bounding sphere.

See minimal_bounding_sphere() for more information.

Type:

float

property minimal_centered_bounding_sphere#

Get the smallest bounding concentric sphere.

Type:

Sphere

property minimal_centered_bounding_sphere_radius#

Get or set the radius of the minimal concentric bounding sphere.

See minimal_centered_bounding_sphere() for more information.

Type:

float

plot()#

Plot the shape.

property radius#

Get or set the radius of the sphere.

Type:

float

property surface_area#

Get the surface area.

Type:

float

to_hoomd()#

Get a dict of JSON-serializable subset of Sphere properties.

The JSON-serializable output of the to_hoomd method can be directly imported into data management tools like signac. This data can then be queried for use in HOOMD simulations. Key naming matches HOOMD integrators: for example, the moment_inertia key links to data from coxeter’s inertia_tensor. Stored values are based on the shape with its centroid at the origin.

For a Sphere, the following properties are stored:

  • diameter (float):

    The diameter of the sphere, equal to twice the radius.

  • centroid (list(float))

    The centroid of the shape. This is set to [0,0,0] per HOOMD’s spec.

  • volume (float)

    The volume of the shape.

  • moment_inertia (list(list))

    The shape’s inertia tensor.

Returns:

Dict containing a subset of shape properties required for HOOMD function.

Return type:

dict

to_json(attributes: list)#

Get a JSON-serializable subset of shape properties.

Parameters:

attributes (list) – List of attributes to export. Each element must be a valid attribute of the class.

Returns:

A dict containing the requested attributes.

Return type:

dict

Raises:

AttributeError: – If any keys in the input list are invalid.

to_plato_scene(backend='matplotlib', scene=None, scene_kwargs=None)#

Add this shape to a new or existing plato.draw.Scene.

The plato visualization package provides support for several backends, including matplotlib, fresnel, povray, pythreejs, and vispy. The backend package must be separately installed by the user. Each backend supports different primitives (geometry objects) and may not support the primitive corresponding to a specific shape class in coxeter. Please refer to the plato documentation for more information about supported primitives for each backend.

Parameters:
  • backend (str) – Name of backend to use from plato. The backend must support the primitive corresponding to this shape (Default value: "matplotlib"). Supported values include "matplotlib", "fresnel", "povray", "pythreejs", "vispy", and "zdog". See plato documentation for more information about each backend.

  • scene (plato.draw.Scene) – Scene object to render into. If not provided or None, a new scene is created (Default value: None).

  • scene_kwargs (dict) – Keyword arguments forwarded to the plato.draw.Scene (Default value: None). Only used if scene is not provided or None.

Returns:

A scene containing this shape.

Return type:

plato.draw.Scene

Raises:
  • NotImplementedError: – If no plato primitive corresponds to this coxeter shape class.

  • AttributeError: – If the selected plato backend does not support the primitive for this coxeter shape class.

property volume#

Get the volume of the sphere.

Type:

float

Families Module#

Overview

Provide tools for generating shapes.

Shape families are coxeter’s way of providing well-defined methods for generating classes of shapes according to some set of rules. The basic interface is defined by the ShapeFamily, which is a functor that is called to generate a shape. The TabulatedShapeFamily group of subclasses enable the generation of shape families according to some tabulated set of data, while other families are defined by some set of (discrete or continuous) parameters that are used to construct a shape analytically.

The DOI_SHAPE_REPOSITORIES variable provides convenient access to the shape families associated with different scientific publications. This dataset is useful for reproducing the exact set of shapes from publications.

Classes:

ArchimedeanFamily()

The family of Archimedean solids (13 total).

CatalanFamily()

The family of Catalan solids, also known as Archimedean duals (13 total).

Family323Plus()

The 323+ shape family defined in [CKE+14].

Family423()

The 423 shape family defined in [CKE+14].

Family523()

The 523 shape family defined in [CKE+14].

JohnsonFamily()

The family of Johnson solids, as enumerated in [Joh66] (92 total).

PlatonicFamily()

The family of Platonic solids (5 total).

PrismAntiprismFamily()

The family of uniform n-prisms and n-antiprisms with n∈[3,10] (16 total).

PyramidDipyramidFamily()

The family of regular equilateral pyramids and dipyramids (6 total).

RegularNGonFamily()

The family of convex regular polygons.

ShapeFamily()

A factory for instances of Shape.

TabulatedGSDShapeFamily()

A tabulated shape family defined by a GSD shape schema.

TabulatedShapeFamily()

A shape family corresponding to a tabulated set of shapes.

TruncatedTetrahedronFamily()

The truncated tetrahedron family used in [DEG12].

Data:

DOI_SHAPE_REPOSITORIES

A mapping of DOIs to a list of shape families.

class coxeter.families.ArchimedeanFamily#

Bases: TabulatedGSDShapeFamily

The family of Archimedean solids (13 total).

Parameters:

name (str) – The name of the Archimedean solid.

Options are “Cuboctahedron”, “Icosidodecahedron”, “Truncated Tetrahedron”, “Truncated Octahedron”, “Truncated Cube”, “Truncated Icosahedron”, “Truncated Dodecahedron”, “Rhombicuboctahedron”, “Rhombicosidodecahedron”, “Truncated Cuboctahedron”, “Truncated Icosidodecahedron”, “Snub Cuboctahedron”, and “Snub Icosidodecahedron”.

Methods:

from_json_file(filename, *args, **kwargs)

Generate a subclass for a dataset from a JSON file.

from_mapping(mapping[, classname, docstring])

Generate a subclass for a dataset from a mapping.

get_shape(name)

Use the class's data to produce a shape for the given name.

classmethod from_json_file(filename, *args, **kwargs)#

Generate a subclass for a dataset from a JSON file.

This method simply loads the JSON file into a dictionary and calls from_mapping(), see that docstring for more information.

Parameters:
Return type:

A subclass of this one associated with the the provided data.

classmethod from_mapping(mapping, classname=None, docstring=None)#

Generate a subclass for a dataset from a mapping.

Notably, this method is a _class_ factory: rather than generating a new instance, this method actually generates a new subclass. This design is consistent with the usage ShapeFamily subclasses by direct interaction with the class (without instantiation).

Parameters:
  • mapping (Mapping) – A dict-like object containing valid shape definitions.

  • classname (str, optional) – The name of the new class to use if provided (Default value: None).

  • docstring (str, optional) – The docstring to apply to the class.

Return type:

A subclass of this one associated with the the provided data.

classmethod get_shape(name)#

Use the class’s data to produce a shape for the given name.

Parameters:

name (str) – The key of the desired shape in the data dict.

Returns:

:class:`~coxeter.shapes.Shape`

Return type:

The requested shape.

class coxeter.families.CatalanFamily#

Bases: TabulatedGSDShapeFamily

The family of Catalan solids, also known as Archimedean duals (13 total).

Parameters:

name (str) – The name of the Catalan solid.

Options are “Deltoidal Hexecontahedron”, “Deltoidal Icositetrahedron”, “Disdyakis Dodecahedron”, “Disdyakis Triacontahedron”, “Pentagonal Hexecontahedron”, “Pentagonal Icositetrahedron”, “Pentakis Dodecahedron”, “Rhombic Dodecahedron”, “Rhombic Triacontahedron”, “Triakis Octahedron”, “Tetrakis Hexahedron”, “Triakis Icosahedron”, and “Triakis Tetrahedron”.

Methods:

from_json_file(filename, *args, **kwargs)

Generate a subclass for a dataset from a JSON file.

from_mapping(mapping[, classname, docstring])

Generate a subclass for a dataset from a mapping.

get_shape(name)

Use the class's data to produce a shape for the given name.

classmethod from_json_file(filename, *args, **kwargs)#

Generate a subclass for a dataset from a JSON file.

This method simply loads the JSON file into a dictionary and calls from_mapping(), see that docstring for more information.

Parameters:
Return type:

A subclass of this one associated with the the provided data.

classmethod from_mapping(mapping, classname=None, docstring=None)#

Generate a subclass for a dataset from a mapping.

Notably, this method is a _class_ factory: rather than generating a new instance, this method actually generates a new subclass. This design is consistent with the usage ShapeFamily subclasses by direct interaction with the class (without instantiation).

Parameters:
  • mapping (Mapping) – A dict-like object containing valid shape definitions.

  • classname (str, optional) – The name of the new class to use if provided (Default value: None).

  • docstring (str, optional) – The docstring to apply to the class.

Return type:

A subclass of this one associated with the the provided data.

classmethod get_shape(name)#

Use the class’s data to produce a shape for the given name.

Parameters:

name (str) – The key of the desired shape in the data dict.

Returns:

:class:`~coxeter.shapes.Shape`

Return type:

The requested shape.

coxeter.families.DOI_SHAPE_REPOSITORIES = {}#

A mapping of DOIs to a list of shape families.

Each known DOI is associated with a list of shape families that can be used to generate the shapes from those papers. Currently supported DOIs are:

  • 10.1126/science.1220869: [DEG12]

  • 10.1103/PhysRevX.4.011024: [CKE+14]

  • 10.1021/nn204012y: [DEG12]

class coxeter.families.Family323Plus#

Bases: TruncationPlaneShapeFamily

The 323+ shape family defined in [CKE+14].

This class requires the parameters

\(a \in [1, 3]\)

\(c \in [1, 3]\)

The \(b\) parameter is always equal to 1 for this family.

The extremal shapes in this shape family are an octahedron at (1, 1), a tetrahedron at (3, 1) and (1, 3), and a cube at (3, 3).

Methods:

get_plane_types()

Get the types of the planes.

get_planes()

Get the set of planes used to truncate the shape.

get_shape(a, c)

Generate a shape for the provided parameters.

make_vertices(a, b, c)

Generate vertices from the a, b, and c parameters.

classmethod get_plane_types()#

Get the types of the planes.

The types are encoded via the following integer mapping:

  • type 0 corresponds to the parameter a.

  • type 1 corresponds to the parameter b.

  • type 2 corresponds to the parameter c.

Returns:

The plane types.

Return type:

(\(N_{planes}\), ) numpy.ndarray of int

classmethod get_planes()#

Get the set of planes used to truncate the shape.

Returns:

The planes defining this family

Return type:

(\(N_{planes}\), 3) numpy.ndarray of float

classmethod get_shape(a, c)#

Generate a shape for the provided parameters.

Parameters:
  • a (float) – The parameter \(a \in [1, 3]\).

  • c (float) – The parameter \(c \in [1, 3]\).

Returns:

The desired shape.

Return type:

ConvexPolyhedron

classmethod make_vertices(a, b, c)#

Generate vertices from the a, b, and c parameters.

Parameters:
  • a (float) – The a parameter.

  • b (float) – The b parameter.

  • c (float) – The c parameter.

Returns:

The vertices of the shape generated by the provided parameters.

Return type:

(\(N_{vertices}\), 3) numpy.ndarray of float

class coxeter.families.Family423#

Bases: TruncationPlaneShapeFamily

The 423 shape family defined in [CKE+14].

This class requires the parameters

\(a \in [1, 2]\)

\(c \in [2, 3]\)

The \(b\) parameter is always equal to 2 for this family.

The extremal shapes in this shape family are a cuboctahedron at (1, 2), an octahedron at (2, 2), a cube at (1, 3), and a rhombic dodecahedron at (2, 3).

Methods:

get_plane_types()

Get the types of the planes.

get_planes()

Get the set of planes used to truncate the shape.

get_shape(a, c)

Generate a shape for the provided parameters.

make_vertices(a, b, c)

Generate vertices from the a, b, and c parameters.

classmethod get_plane_types()#

Get the types of the planes.

The types are encoded via the following integer mapping:

  • type 0 corresponds to the parameter a.

  • type 1 corresponds to the parameter b.

  • type 2 corresponds to the parameter c.

Returns:

The plane types.

Return type:

(\(N_{planes}\), ) numpy.ndarray of int

classmethod get_planes()#

Get the set of planes used to truncate the shape.

Returns:

The planes defining this family

Return type:

(\(N_{planes}\), 3) numpy.ndarray of float

classmethod get_shape(a, c)#

Generate a shape for the provided parameters.

Parameters:
  • a (float) – The parameter \(a \in [1, 2]\).

  • c (float) – The parameter \(c \in [2, 3]\).

Returns:

The desired shape.

Return type:

ConvexPolyhedron

classmethod make_vertices(a, b, c)#

Generate vertices from the a, b, and c parameters.

Parameters:
  • a (float) – The a parameter.

  • b (float) – The b parameter.

  • c (float) – The c parameter.

Returns:

The vertices of the shape generated by the provided parameters.

Return type:

(\(N_{vertices}\), 3) numpy.ndarray of float

class coxeter.families.Family523#

Bases: TruncationPlaneShapeFamily

The 523 shape family defined in [CKE+14].

This class requires the parameters

\(a \in [1, s\sqrt{5}]\)

\(c \in [S^2, 3]\)

where \(S = \frac{1}{2}\left(\sqrt{5} + 1\right)\) is the golden ratio and \(s = \frac{1}{2}\left(\sqrt{5} - 1\right)\) is its inverse. The \(b\) parameter is always equal to 2 for this family.

The extremal shapes in this shape family are an icosidodecahedron at (\(1\), \(S^2\)), an icosahedron at (\(s\sqrt{5}\), \(S^2\)), a dodecahedron at (\(1\), \(3\)), and a rhombic triacontahedron at (\(s\sqrt{5}\), \(3\)).

Attributes:

S

The constant S (the golden ratio).

s

The constant s (the inverse of the golden ratio).

Methods:

get_plane_types()

Get the types of the planes.

get_planes()

Get the set of planes used to truncate the shape.

get_shape(a, c)

Generate a shape for the provided parameters.

make_vertices(a, b, c)

Generate vertices from the a, b, and c parameters.

S = 1.618033988749895#

The constant S (the golden ratio).

classmethod get_plane_types()#

Get the types of the planes.

The types are encoded via the following integer mapping:

  • type 0 corresponds to the parameter a.

  • type 1 corresponds to the parameter b.

  • type 2 corresponds to the parameter c.

Returns:

The plane types.

Return type:

(\(N_{planes}\), ) numpy.ndarray of int

classmethod get_planes()#

Get the set of planes used to truncate the shape.

Returns:

The planes defining this family

Return type:

(\(N_{planes}\), 3) numpy.ndarray of float

classmethod get_shape(a, c)#

Generate a shape for the provided parameters.

Parameters:
  • a (float) – The parameter \(a \in [1, s\sqrt{5}]\).

  • c (float) – The parameter \(c \in [S^2, 3]\).

Returns:

The desired shape.

Return type:

ConvexPolyhedron

classmethod make_vertices(a, b, c)#

Generate vertices from the a, b, and c parameters.

Parameters:
  • a (float) – The a parameter.

  • b (float) – The b parameter.

  • c (float) – The c parameter.

Returns:

The vertices of the shape generated by the provided parameters.

Return type:

(\(N_{vertices}\), 3) numpy.ndarray of float

s = 0.6180339887498948#

The constant s (the inverse of the golden ratio).

class coxeter.families.JohnsonFamily#

Bases: TabulatedGSDShapeFamily

The family of Johnson solids, as enumerated in [Joh66] (92 total).

Parameters:

name (str) – The name of the Johnson solid.

A full list of Johnson solids is available in [Joh66]. In general, shape names should have the first character of each word capitalized, with spaces between words (e.g. “Elongated Triangular Cupola”). Pyramids and dipyramids are named from their base polygon (e.g. “Square Pyramid” or “Elongated Pentagonal Dipyramid”).

Methods:

from_json_file(filename, *args, **kwargs)

Generate a subclass for a dataset from a JSON file.

from_mapping(mapping[, classname, docstring])

Generate a subclass for a dataset from a mapping.

get_shape(name)

Use the class's data to produce a shape for the given name.

classmethod from_json_file(filename, *args, **kwargs)#

Generate a subclass for a dataset from a JSON file.

This method simply loads the JSON file into a dictionary and calls from_mapping(), see that docstring for more information.

Parameters:
Return type:

A subclass of this one associated with the the provided data.

classmethod from_mapping(mapping, classname=None, docstring=None)#

Generate a subclass for a dataset from a mapping.

Notably, this method is a _class_ factory: rather than generating a new instance, this method actually generates a new subclass. This design is consistent with the usage ShapeFamily subclasses by direct interaction with the class (without instantiation).

Parameters:
  • mapping (Mapping) – A dict-like object containing valid shape definitions.

  • classname (str, optional) – The name of the new class to use if provided (Default value: None).

  • docstring (str, optional) – The docstring to apply to the class.

Return type:

A subclass of this one associated with the the provided data.

classmethod get_shape(name)#

Use the class’s data to produce a shape for the given name.

Parameters:

name (str) – The key of the desired shape in the data dict.

Returns:

:class:`~coxeter.shapes.Shape`

Return type:

The requested shape.

class coxeter.families.PlatonicFamily#

Bases: TabulatedGSDShapeFamily

The family of Platonic solids (5 total).

Parameters:

name (str) – The name of the Platonic solid.

Options are “Cube”, “Dodecahedron”, “Icosahedron”, “Octahedron”, and “Tetrahedron”.

Methods:

from_json_file(filename, *args, **kwargs)

Generate a subclass for a dataset from a JSON file.

from_mapping(mapping[, classname, docstring])

Generate a subclass for a dataset from a mapping.

get_shape(name)

Use the class's data to produce a shape for the given name.

classmethod from_json_file(filename, *args, **kwargs)#

Generate a subclass for a dataset from a JSON file.

This method simply loads the JSON file into a dictionary and calls from_mapping(), see that docstring for more information.

Parameters:
Return type:

A subclass of this one associated with the the provided data.

classmethod from_mapping(mapping, classname=None, docstring=None)#

Generate a subclass for a dataset from a mapping.

Notably, this method is a _class_ factory: rather than generating a new instance, this method actually generates a new subclass. This design is consistent with the usage ShapeFamily subclasses by direct interaction with the class (without instantiation).

Parameters:
  • mapping (Mapping) – A dict-like object containing valid shape definitions.

  • classname (str, optional) – The name of the new class to use if provided (Default value: None).

  • docstring (str, optional) – The docstring to apply to the class.

Return type:

A subclass of this one associated with the the provided data.

classmethod get_shape(name)#

Use the class’s data to produce a shape for the given name.

Parameters:

name (str) – The key of the desired shape in the data dict.

Returns:

:class:`~coxeter.shapes.Shape`

Return type:

The requested shape.

class coxeter.families.PrismAntiprismFamily#

Bases: TabulatedGSDShapeFamily

The family of uniform n-prisms and n-antiprisms with n∈[3,10] (16 total).

Parameters:

name (str) – The name of the prism or antiprism.

Options for prisms are “Triangular Prism”, “Square Prism”, “Pentagonal Prism”, “Hexagonal Prism”, “Heptagonal Prism”, “Octagonal Prism”, “Nonagonal Prism”, and “Decagonal Prism”. Options for antiprisms are “Triangular Antiprism”, “Square Antiprism”, “Pentagonal Antiprism”, “Hexagonal Antiprism”, “Heptagonal Antiprism”, “Octagonal Antiprism”,”Nonagonal Antiprism”, and “Decagonal Antiprism”.

Methods:

from_json_file(filename, *args, **kwargs)

Generate a subclass for a dataset from a JSON file.

from_mapping(mapping[, classname, docstring])

Generate a subclass for a dataset from a mapping.

get_shape(name)

Use the class's data to produce a shape for the given name.

classmethod from_json_file(filename, *args, **kwargs)#

Generate a subclass for a dataset from a JSON file.

This method simply loads the JSON file into a dictionary and calls from_mapping(), see that docstring for more information.

Parameters:
Return type:

A subclass of this one associated with the the provided data.

classmethod from_mapping(mapping, classname=None, docstring=None)#

Generate a subclass for a dataset from a mapping.

Notably, this method is a _class_ factory: rather than generating a new instance, this method actually generates a new subclass. This design is consistent with the usage ShapeFamily subclasses by direct interaction with the class (without instantiation).

Parameters:
  • mapping (Mapping) – A dict-like object containing valid shape definitions.

  • classname (str, optional) – The name of the new class to use if provided (Default value: None).

  • docstring (str, optional) – The docstring to apply to the class.

Return type:

A subclass of this one associated with the the provided data.

classmethod get_shape(name)#

Use the class’s data to produce a shape for the given name.

Parameters:

name (str) – The key of the desired shape in the data dict.

Returns:

:class:`~coxeter.shapes.Shape`

Return type:

The requested shape.

class coxeter.families.PyramidDipyramidFamily#

Bases: TabulatedGSDShapeFamily

The family of regular equilateral pyramids and dipyramids (6 total).

Parameters:

name (str) – The name of the pyramid or dipyramid.

Options for pyramids are “Triangular Pyramid”, “Square Pyramid”, and “Pentagonal Pyramid”. Options for dipyramids are “Triangular Dipyramid”, “Square Dipyramid”, and “Pentagonal Dipyramid”.

Methods:

from_json_file(filename, *args, **kwargs)

Generate a subclass for a dataset from a JSON file.

from_mapping(mapping[, classname, docstring])

Generate a subclass for a dataset from a mapping.

get_shape(name)

Use the class's data to produce a shape for the given name.

classmethod from_json_file(filename, *args, **kwargs)#

Generate a subclass for a dataset from a JSON file.

This method simply loads the JSON file into a dictionary and calls from_mapping(), see that docstring for more information.

Parameters:
Return type:

A subclass of this one associated with the the provided data.

classmethod from_mapping(mapping, classname=None, docstring=None)#

Generate a subclass for a dataset from a mapping.

Notably, this method is a _class_ factory: rather than generating a new instance, this method actually generates a new subclass. This design is consistent with the usage ShapeFamily subclasses by direct interaction with the class (without instantiation).

Parameters:
  • mapping (Mapping) – A dict-like object containing valid shape definitions.

  • classname (str, optional) – The name of the new class to use if provided (Default value: None).

  • docstring (str, optional) – The docstring to apply to the class.

Return type:

A subclass of this one associated with the the provided data.

classmethod get_shape(name)#

Use the class’s data to produce a shape for the given name.

Parameters:

name (str) – The key of the desired shape in the data dict.

Returns:

:class:`~coxeter.shapes.Shape`

Return type:

The requested shape.

class coxeter.families.RegularNGonFamily#

Bases: ShapeFamily

The family of convex regular polygons.

This class generates the set of convex regular polygons with \(n\) sides. The polygons are normalized to be unit area by default, and the initial vertex always lies on the \(x\) axis (so, for example, a 4-sided shape generated by this will look like a diamond, i.e. a square rotated by 45 degrees).

The following parameters are required by this class:

  • \(n\): The number of vertices of the polygon

Methods:

get_shape(n)

Generate a unit area n-gon.

make_vertices(n)

Generate vertices of a unit area n-gon.

classmethod get_shape(n)#

Generate a unit area n-gon.

Parameters:

n (int) – The number of vertices (greater than or equal to 3).

Returns:

:class:`~.ConvexPolygon`

Return type:

The corresponding regular polygon.

classmethod make_vertices(n)#

Generate vertices of a unit area n-gon.

Parameters:

n (int) – An integer greater than or equal to 3.

Returns:

:math:`(n, 3)` :class:`numpy.ndarray` of float

Return type:

The vertices of the polygon.

class coxeter.families.ShapeFamily#

Bases: ABC

A factory for instances of Shape.

This abstract class represents a simple promise of a get_shape method that accepts some set of arguments and returns some shape class. The precise behavior is left up to specific subclasses, which document the parameters in the class docstring.

This class is designed to never be instantiated. All relevant operations of its subclasses should be classmethods, and any data intrinsic to a family should be stored within the class. This design avoids creating an antipattern of instantiating a stateless class, while also providing a suitable means for using inheritance to create meaningful relationships between shape families. It also simplifies user APIs, avoiding confusing idioms like shape = family()(SHAPE_NAME). For instance, given a family for generating regular polygons, getting a hexagon should look roughly like family.get_shape(n=6).

Methods:

get_shape()

Generate a shape.

abstract classmethod get_shape()#

Generate a shape.

Subclasses must define this function to accept whatever parameters are necessary to define a shape. The method should return an instance of some concrete subclass of Shape.

class coxeter.families.TabulatedGSDShapeFamily#

Bases: TabulatedShapeFamily

A tabulated shape family defined by a GSD shape schema.

The values of the dictionary used to construct this class must adhere to the GSD shape spec. Each mapping may contain additional data, which is ignored when the class is called to actually produce Shape objects.

Parameters:

filename_or_dict (str or Mapping) – A dictionary containing valid shape definitions or a JSON file that can be read into such a dictionary.

Methods:

from_json_file(filename, *args, **kwargs)

Generate a subclass for a dataset from a JSON file.

from_mapping(mapping[, classname, docstring])

Generate a subclass for a dataset from a mapping.

get_shape(name)

Use the class's data to produce a shape for the given name.

classmethod from_json_file(filename, *args, **kwargs)#

Generate a subclass for a dataset from a JSON file.

This method simply loads the JSON file into a dictionary and calls from_mapping(), see that docstring for more information.

Parameters:
Return type:

A subclass of this one associated with the the provided data.

classmethod from_mapping(mapping, classname=None, docstring=None)#

Generate a subclass for a dataset from a mapping.

Notably, this method is a _class_ factory: rather than generating a new instance, this method actually generates a new subclass. This design is consistent with the usage ShapeFamily subclasses by direct interaction with the class (without instantiation).

Parameters:
  • mapping (Mapping) – A dict-like object containing valid shape definitions.

  • classname (str, optional) – The name of the new class to use if provided (Default value: None).

  • docstring (str, optional) – The docstring to apply to the class.

Return type:

A subclass of this one associated with the the provided data.

classmethod get_shape(name)#

Use the class’s data to produce a shape for the given name.

Parameters:

name (str) – The key of the desired shape in the data dict.

Returns:

:class:`~coxeter.shapes.Shape`

Return type:

The requested shape.

class coxeter.families.TabulatedShapeFamily#

Bases: ShapeFamily

A shape family corresponding to a tabulated set of shapes.

Data can either be read from a file or provided in the form of a dictionary. If a filename is provided, it must be a JSON file that can be parsed into an appropriately formatted dictionary, namely a set of key-value pairs such that the call operator of this class can generate a Shape from the dictionary. The raw parsed JSON is accessible via the data attribute. Subclasses of this class implement the call operator to define exactly how the dictionary values are converted to a shape definition.

Methods:

from_json_file(filename, *args, **kwargs)

Generate a subclass for a dataset from a JSON file.

from_mapping(mapping[, classname, docstring])

Generate a subclass for a dataset from a mapping.

get_shape()

Generate a shape.

classmethod from_json_file(filename, *args, **kwargs)#

Generate a subclass for a dataset from a JSON file.

This method simply loads the JSON file into a dictionary and calls from_mapping(), see that docstring for more information.

Parameters:
Return type:

A subclass of this one associated with the the provided data.

classmethod from_mapping(mapping, classname=None, docstring=None)#

Generate a subclass for a dataset from a mapping.

Notably, this method is a _class_ factory: rather than generating a new instance, this method actually generates a new subclass. This design is consistent with the usage ShapeFamily subclasses by direct interaction with the class (without instantiation).

Parameters:
  • mapping (Mapping) – A dict-like object containing valid shape definitions.

  • classname (str, optional) – The name of the new class to use if provided (Default value: None).

  • docstring (str, optional) – The docstring to apply to the class.

Return type:

A subclass of this one associated with the the provided data.

abstract classmethod get_shape()#

Generate a shape.

Subclasses must define this function to accept whatever parameters are necessary to define a shape. The method should return an instance of some concrete subclass of Shape.

class coxeter.families.TruncatedTetrahedronFamily#

Bases: Family323Plus

The truncated tetrahedron family used in [DEG12].

The following parameters are required by this class:

  • truncation \(\in [0, 1]\)

This family is constructed as a limiting case of Family323Plus with a = 1. The c value is then directly related to a linear interpolation over truncations. In particular, \(c = 3 - 2(\text{truncation})\).

Methods:

get_plane_types()

Get the types of the planes.

get_planes()

Get the set of planes used to truncate the shape.

get_shape(truncation)

Generate a shape for a given truncation value.

make_vertices(a, b, c)

Generate vertices from the a, b, and c parameters.

classmethod get_plane_types()#

Get the types of the planes.

The types are encoded via the following integer mapping:

  • type 0 corresponds to the parameter a.

  • type 1 corresponds to the parameter b.

  • type 2 corresponds to the parameter c.

Returns:

The plane types.

Return type:

(\(N_{planes}\), ) numpy.ndarray of int

classmethod get_planes()#

Get the set of planes used to truncate the shape.

Returns:

The planes defining this family

Return type:

(\(N_{planes}\), 3) numpy.ndarray of float

classmethod get_shape(truncation)#

Generate a shape for a given truncation value.

Parameters:

truncation (float) – The parameter \(truncation \in [0, 1]\).

Returns:

The desired truncated tetrahedron.

Return type:

ConvexPolyhedron

classmethod make_vertices(a, b, c)#

Generate vertices from the a, b, and c parameters.

Parameters:
  • a (float) – The a parameter.

  • b (float) – The b parameter.

  • c (float) – The c parameter.

Returns:

The vertices of the shape generated by the provided parameters.

Return type:

(\(N_{vertices}\), 3) numpy.ndarray of float

Shape Getters#

Module for defining various convenience functions for shape generation.

The methods here provide routes for generating instances of Shape based on certain pre-specified mappings.

Functions:

from_gsd_type_shapes(params[, dimensions])

Create a Shape from a dict conforming to the GSD schema.

coxeter.shape_getters.from_gsd_type_shapes(params, dimensions=3)#

Create a Shape from a dict conforming to the GSD schema.

See here for the specification of the schema. Note that the schema does not differentiate between 2D and 3D shapes for spheres (vs. circles) and ellipsoids (vs. ellipses) because in context the dimensionality of those shapes can be inferred from simulation boxes. To address this ambiguity, this function accepts a dimensions parameter that can be used to disambiguate explicitly between these two cases.

Parameters:
  • params (dict) – The parameters of the shape to construct.

  • dimensions (int) – The dimensionality of the shape (either 2 or 3). Ignored except when the shape is a sphere or an ellipsoid, in which case a value of 2 is used to indicate generating a Circle or Ellipse instead of a Sphere or Ellipsoid (Default value: 3).

Returns:

The desired shape.

Return type:

Shape

Development Guide#

All contributions to coxeter are welcome! Developers are invited to contribute to the framework by pull request to the package repository on GitHub, and all users are welcome to provide contributions in the form of user feedback and bug reports. We recommend discussing new features in form of a proposal on the issue tracker for the appropriate project prior to development.

General Guidelines#

All code contributed to coxeter must adhere to the following guidelines:

  • Use the OneFlow model of development: - Both new features and bug fixes should be developed in branches based on master. - Hotfixes (critical bugs that need to be released fast) should be developed in a branch based on the latest tagged release.

  • Avoid external dependencies wherever possible, and avoid introducing any hard dependencies outside the standard Python scientific stack (NumPy, SciPy, etc). Soft dependencies are allowed for specific functionality, but such dependencies cannot impede the installation of coxeter or the use of any other features.

  • All code should adhere to the source code conventions and satisfy the documentation and testing requirements discussed below.

  • Preserve backwards-compatibility whenever possible. Make clear if something must change, and notify package maintainers that merging such changes will require a major release.

To provide a reasonable balance between a high level of backwards compatibility and a reasonable maintenance burden, coxeter has adopted NEP 29 to limit the Python and NumPy versions that will be supported.

Tip

During continuous integration, the code is checked automatically with pre-commit. To run these checks locally, you can install and run pre-commit like so:

python -m pip install pre-commit
pre-commit run --all-files

To avoid having commits fail in case you forget to run this, you can set up a git pre-commit hook using pre-commit:

pre-commit install

Style Guidelines#

The coxeter package adheres to a relatively strict set of style guidelines. All code in coxeter should be formatted using black. Imports should be formatted using `isort`_. For guidance on the style, see PEP 8 and the Google Python Style Guide, but any ambiguities should be resolved automatically by running black. All code should of course also follow the principles in PEP 20.

Tip

Developers should format their code using black and isort locally. Running the pre-commit hooks will take care of this:

pre-commit run

Alternatively, the tools can be run manually using the commands:

# From the root of the repository
ruff check . --fix

black coxeter/ tests/

Documentation#

API documentation should be written as part of the docstrings of the package in the Google style. There is one notable exception to the guide: class properties should be documented in the getters functions, not as class attributes, to allow for more useful help messages and inheritance of docstrings. Docstrings may be validated using pydocstyle (or using the flake8-docstrings plugin as documented above). The official documentation is generated from the docstrings using Sphinx.

In addition to API documentation, inline comments are highly encouraged. Code should be written as transparently as possible, so the primary goal of documentation should be explaining the algorithms or mathematical concepts underlying the code. Avoid comments that simply restate the nature of lines of code. For example, the comment “solve the system of equations” is uninformative, since the code itself should make this obvious, e.g, np.linalg.solve. On the other hand, the comment “the solution to this system of equations is the intersection of truncation planes” is instructive.

Unit Tests#

All code should include a set of tests which test for correct behavior. All tests should be placed in the tests folder at the root of the project. In general, most parts of coxeter primarily require unit tests, but where appropriate integration tests are also welcome. Tests in coxter use the pytest testing framework. To run the tests, simply execute pytest at the root of the repository.

Release Guide#

To make a new release of coxeter, follow the following steps:

  1. Make a new branch off of master based on the expected new version, e.g. release-2.3.1.

  2. Make any final changes as desired on this branch. Push the changes and ensure all tests are passing as expected on the new branch.

  3. Once the branch is completely finalized, run bumpversion with the appropriate type (patch, minor, major) so that the version now matches the version number in the branch name.

  4. Merge the branch back into master, then push master and push tags. The tagged commit will automatically trigger generation of binaries and upload to PyPI and conda-forge.

  5. Delete the release branch both locally and on the remote.

Changelog#

The format is based on Keep a Changelog. This project adheres to Semantic Versioning.

v0.x.x - 20xx-xx-xx

v0.8.0 - 2024-02-21

Added#

  • New edge_lengths method.

  • combine_simplices, find_simplex_equations, _find_face_centroids, find_coplanar_simplices, _find_face_centroids, and calculate_signed_volume methods for the ConvexPolyhedron class.

  • simplices, equations, and face_centroids properties for the ConvexPolyhedron class.

  • Additional pytests for surface area, volume, centroid, moment of inertia, and equations properties.

  • New to_hoomd and to_json export methods for use with simulation tools

Changed#

  • Pre-commit now uses ruff instead of flake8, pydocstyle, pyupgrade and isort.

  • CI now uses GitHub Actions.

  • Docs ported to furo theme.

  • Reimplemented find_equations, _volume, surface_area, centroid, _compute_inertia_tensor, rescale, and get_face_area methods for convex polyhedra using NumPy vectorized operations and polyhedron simplices.

  • [breaking] ConvexPolyhedron._surface_triangulation now returns sorted simplices, rather than running polytri. This can change the order of vertices and/or triangles.

  • [breaking] faces may return faces in a different order than previously. Faces are still sorted with sort_faces, and will still be ordered such that curl and divergence theorems work properly.

  • volume, surface_area, and centroid properties now return stored values, rather than computing the quantity at each call.

  • rescale now computes the centroid to ensure the correct value is available when centroid is called.

  • Optimized pytest configurations for more efficient use of local and remote resources.

v0.7.0 - 2023-09-18#

Fixed#

  • Numerical precision issues in tests.

  • GSD spec correctly outputs for Polyhedron objects.

  • Error in __repr__ for polyhedra with multiple face degrees.

  • ReadTheDocs build errors resulting from conda memory usage.

Changed#

  • The minimum required Python version is now 3.8.

  • The minimum required NumPy version is now 1.19.

  • [breaking] Sped up point in polygon and point in polyhedron using NumPy.

  • Migrated to pyproject.toml.

Added#

  • New edges and edge_vectors properties for polyhedra.

  • New shape families for Archimedean, Catalan, and Johnson shapes.

  • New shape families for regular pyramids and dipyramids, and a selection of regular prisms and antiprisms.

v0.6.1 - 2021-07-15#

Fixed#

  • Typos in JOSS paper.

v0.6.0 - 2021-07-14#

Added#

  • Plotting and other graphical rendering of shapes using plato.

  • Notebooks with example use-cases for the package.

  • A quickstart tutorial.

v0.5.0 - 2021-02-23#

Added#

  • Ellipse area setter and Ellipsoid volume setter.

  • Point in circle checks.

  • Point in ellipse checks.

  • Inertia tensors for 2D shapes that implement moments of inertia.

  • Add minimal bounding sphere for all shapes.

  • Add minimal centered bounding sphere calculations for all shapes except general polygons, general polyhedra, spheropolygons, and spheropolyhedra.

  • Enable getting and setting the circumsphere or bounding sphere radius of a polyhedron (for both types of bounding sphere).

  • Add maximal bounded sphere for all shapes.

  • Add maximal centered bounded sphere calculations for all shapes except general polygons, general polyhedra, spheropolygons, and spheropolyhedra.

  • Enable getting and setting the insphere or bounded sphere radius of a polyhedron (for both types of bounding sphere).

  • Point in polygon checks for general (nonconvex) polygons.

  • Point in polyhedron checks for general (nonconvex) polyhedrons.

  • Minimal bounding sphere for all shapes except spheropolygons and spheropolyhedra.

  • Add minimal centered bounding sphere calculations for all shapes except general polygons, general polyhedra, spheropolygons, and spheropolyhedra.

  • Getters and setters for the circumsphere or bounding sphere radius of a polyhedron (for both types of bounding sphere).

  • A repr for all shapes.

Changed#

  • Ensure that hypothesis-based tests don’t implicitly reuse pytest fixtures.

Deprecated#

  • The circumsphere from center calculations (replaced by minimal centered bounding sphere).

  • The bounding_sphere property is deprecated in favor of minimal_bounding_sphere.

  • The insphere from center calculations (replaced by maximal centered bounded sphere).

Fixed#

  • Centroid calculations for polygon and polyhedron use the full integrals rather than simple averages of vertices.

v0.4.0 - 2020-10-14#

Added#

  • Circumsphere and insphere from center calculations for ConvexSpheropolyhedron.

  • Form factors amplitudes for sphere, polygons, and polyhedra.

  • Shape families associated with a DOI can be directly accessed via a dictionary.

  • Expected abstract interface for shapes (both 2D and 3D) has expanded.

  • Plotting polygons or polyhedra can automatically create matplotlib axes.

  • Perimeter calculation for polygons.

  • Area and perimeter setters for spheropolygons.

Changed#

  • Shape family API is now entirely based on class methods rather than a call operator.

  • The parent ShapeFamily class is now part of the public API.

  • Doctests are now run as part of pytest.

  • Subpackages have been renamed: shape_classes is now shapes, and shape_families is now families.

  • The common_families submodule of shape_families is now just common.

Fixed#

  • Volume calculation for ConvexSpheropolyhedron includes area of extruded faces in addition to vertices and edges.

  • Documentation has been revised and edited.

Removed#

  • The symmetry.py module.

  • The ft.py module.

  • The symmetry.py module.

  • The get_params method of TabulatedShapeFamily.

  • The family_from_doi method (the underlying data dictionary is now directly exposed).

v0.3.0 - 2020-06-18#

Added#

  • Calculation of circumsphere from center for convex polyhedra.

  • Simple name-based shape getter for damasceno SHAPES dictionary.

  • Polygons moment of inertia calculation.

  • Interoperability with the GSD shape specification.

  • Shape families and stored data for well-known families.

  • All shapes can be centered anywhere in 3D Euclidean space.

  • Extensive style checking using black, isort, and various other flake8 plugins.

  • Make Circle area settable.

  • 3D shapes can be oriented by their principal axes.

  • Make Sphere volume settable.

Changed#

  • Inertia tensors for polyhedra and moments of inertia for polygons are calculated in global coordinates rather than the body frame.

  • Modified testing of convex hulls to generate points on ellipsoids to avoid degenerate simplices.

  • All insphere, circumsphere, and bounding sphere calculations now return the appropriate classes instead of tuples.

Removed#

  • The common_shapes subpackage.

v0.2.0 - 2020-04-09#

Added#

  • Continuous integrated testing on CircleCI.

  • New Polygon class with property-based API.

  • New ConvexSpheropolygon class with property-based API.

  • New Polyhedron class with property-based API and robust facet sorting and merging.

  • New ConvexPolyhedron class with property-based API.

  • New ConvexSpheropolyhedron class with property-based API.

  • Ability to plot Polyhedra and Polygons.

  • Can now check whether points lie inside a ConvexPolyhedron or ConvexSpheropolyhedron.

  • Added documentation.

  • New Ellipsoid class with property-based API.

  • New Sphere class with property-based API.

  • New Ellipse class with property-based API.

  • New Circle class with property-based API.

  • Added insphere from center calculation for convex polyhedra.

  • New ConvexPolygon class.

  • Documentation is hosted on ReadTheDocs.

Changed#

  • Moved core shape classes from euclid.FreudShape into top-level package namespace.

  • Moved common shape definitions into common_shapes subpackage.

  • Shapes from Damasceno science 2012 paper are now stored in a JSON file that is loaded in the damasceno module.

Fixed#

  • Formatting now properly follows PEP8.

Removed#

  • Various unused or redundant functions in the utils module.

  • The quaternion_tools module (uses rowan for quaternion math instead).

  • The shapelib module.

  • Old polygon.py and polyhedron.py modules, which contained old implementations of various poly* and spheropoly* classes.

v0.1.0#

  • Initial version of code base.

Credits#

coxeter Developers#

The following people contributed to the development of coxeter.

Vyas Ramasubramani - Creator and lead developer

  • Created documentation pages.

  • Formalized contribution guidelines and contributor agreement.

  • Cleaned up damasceno module and separated out shape information into a JSON file that is read on demand.

  • Fixed code formatting to conform to PEP8 requirements.

  • Implemented Polygon class.

  • Implemented ConvexSpheropolygon class.

  • Implemented Polyhedron class.

  • Implemented ConvexPolyhedron class.

  • Implemented ConvexSpheropolyhedron class.

  • Add ability to check if points are contained in convex polyhedra.

  • Fix calculation of circumsphere to work for non-regular polyhedra.

  • Fix calculation of circumcircle to work for non-regular polygons.

  • Add ability to calculate minimum bounding sphere/circle for polyhedra/polygons.

  • Implemented ConvexPolygon class.

  • Added ReadTheDocs support.

  • Added circumsphere from center calculation for convex polyhedra.

  • Added shape getter for damasceno shapes.

  • Define proper inertia tensor calculations and transformations for polygons and polyhedra.

  • Added interoperability with the GSD shape specification.

  • Developed shape families and all associated shape repository APIs.

  • Add ability to diagonalize the inertia tensors of shapes.

  • Defined base classes for all shapes.

  • Standardize usage of Sphere/Circle classes for circum, in, and bounding sphere/circle calculations.

  • Moved form factor amplitude calculations from legacy ft module to shape classes, cleaned and added more tests.

  • Added point-in-shape checks for circles and ellipses.

  • Added generic inertia tensors for 2D shapes.

  • Added minimal bounding sphere for all shapes.

  • Added minimal centered bounding sphere calculations for all shapes except general polygons and polyhedra.

  • Enabled getting and setting the circumsphere or bounding sphere/circle radius of a polyhedron/polygon (for both types of bounding sphere/circle).

  • Added maximal bounding sphere for all shapes.

  • Added maximal centered bounded sphere calculations for all shapes except general polygons and polyhedra.

  • Enabled getting and setting the insphere or bounded sphere/circle radius of a polyhedron/polygon (for both types of bounding sphere/circle).

  • Added point in polygon checks.

  • Added point in polyhedron checks.

  • Added repr for all shapes.

  • Fixed centroid calculations for polygon and polyhedron to use integrals rather than simple averages of vertices.

  • Wrote example notebooks.

Bryan VanSaders - Original maintainer of legacy euclid package

  • Created package layout.

  • Original port of classes and methods into package.

  • Added some methods to the utils module.

  • Added symmetry groups.

James Proctor

  • Ported some damasceno code into coxeter from standalone module.

Bradley Dice

  • Migrated ft code into coxeter from freud and added tests.

  • Added CircleCI support.

  • Add ability to check if points are contained in convex spheropolyhedra.

  • Revised and edited all documentation.

  • Updated doctests to be part of pytest suite.

  • Added automatic axis creation for plotting.

  • Added spheropolygon area and perimeter setters.

  • Added ellipse area setter and ellipsoid volume setter.

  • Added plato support.

Brandon Butler

  • Removed old quat_tools module and modified modules to use rowan.

  • Moved logic in FreudShape module to top-level package namespace.

  • Moved all common shape definitions into a common_shapes module.

Eric Harper

  • Migrated shape classes into coxeter from freud.

Jens Glaser

  • Bug fix for convex hull finding.

  1. Eric Irrgang

  • Bugfixes to imports.

  • Implemented core shape classes.

  • Implemented the ft module.

Carl Simon Adorf

  • Implemented the damasceno module.

Matthew Spellings

  • Added some methods to the utils module.

  • Triangulation of core shape classes.

William Zygmunt

  • Helped clean up utils module.

Tobias Dwyer

  • Added getter and setter tests to some of the shape classes.

  • Added examples for the shape classes.

Jen Bradley

  • Bug fixes for gsd_shape_spec to correctly comply with GSD specifications.

  • Fixed error where __repr__ would fail for polyhedra with multiple face types.

  • Increased accuracy of stored data for PlatonicFamily solids

  • Added shape families for Archimedean, Catalan, and Johnson solids.

  • Expanded on tests for shape families

  • Added shape family for prisms and antiprisms.

  • Added shape family for equilateral pyramids and dipyramids.

  • Added edges, edge_vectors, edge_lengths, and num_edges methods.

  • Reimplemented find_equations, _volume, surface_area, centroid, _compute_inertia_tensor, rescale, and get_face_area methods for convex polyhedra using NumPy vectorized operations and polyhedron simplices.

  • Added the combine_simplices, find_simplex_equations, _find_face_centroids, find_coplanar_simplices, _find_face_centroids, and calculate_signed_volume methods to the ConvexPolyhedron class.

  • Added simplices, equations, and face_centroids properties to the ConvexPolyhedron class.

  • Optimized pytest configurations for more efficient use of local and remote resources.

  • Added to_json and to_hoomd export methods.

Domagoj Fijan

  • Rewrote point in polygon check to use NumPy vectorized operations.

  • Rewrote point in polyhedron check to use NumPy vectorized operations.

  • Pre-commit now uses ruff instead of flake8, pydocstyle, pyupgrade and isort.

  • Ported CI to github actions.

  • Ported docs to Furo.

Source code#

coxeter includes the source code of the following Python packages and modules.

The source of polytri (https://github.com/bjorkegeek/polytri) is included directly into the coxeter package. The module implementing that code is reproduced in its entirety along with an additional __init__ file to enable its import as a subpackage. It is used for the triangulation of polygons and the surface triangulation of polyhedra. This software is made available under the MIT license:

The MIT License (MIT)

Copyright (c) 2016 David Björkevik

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE

The source of isect_segments-bentley_ottmann (https://github.com/ideasman42/isect_segments-bentley_ottmann) is included directly into the coxeter package. The module implementing that code is reproduced in its entirety along with an additional __init__ file to enable its import as a subpackage. It is used to check whether a set of vertices defines a simple or a complex polygon. This software is made available under the MIT license:

Copyright (c) 2010 by Bart Kiers
Copyright (c) 2015 by Campbell Barton

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

The code for point in polygon and point in polyhedron check is based on the polyhedron repository (https://github.com/mdickinson/polyhedron) which implements winding number calculator to check if points are in shapes, but has been rewritten to utilize vectorized NumPy operations. This software is made available under the BSD-3 license:

BSD 3-Clause License

Copyright (c) 2019, Mark Dickinson
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

License#

BSD 3-Clause License for coxeter

Copyright (c) 2015-2021 The Regents of the University of Michigan All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
   may be used to endorse or promote products derived from this software without
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

References#

[CKE+14]

Elizabeth R. Chen, Daphne Klotsa, Michael Engel, Pablo F. Damasceno, and Sharon C. Glotzer. Complexity in surfaces of densest packings for families of polyhedra. Phys. Rev. X, 4:011024, Feb 2014. doi:10.1103/PhysRevX.4.011024.

[DEG12]

Pablo F. Damasceno, Michael Engel, and Sharon C. Glotzer. Crystalline assemblies and densest packings of a family of truncated tetrahedra and the role of directional entropic forces. ACS Nano, 6(1):609–614, 2012. doi:10.1021/nn204012y.

[Dic19]

Mark Dickinson. Mdickinson/polyhedron: robust point-in-polyhedron testing. GitHub, 2019. URL: https://github.com/mdickinson/polyhedron.

[Ebe02]

David Eberly. Polyhedral mass properties (revisited). Technical Report, Geometric Tools, 2002. URL: https://www.geometrictools.com/Documentation/PolyhedralMassProperties.pdf.

[IES+17]

M. Eric Irrgang, Michael Engel, Andrew J. Schultz, David A. Kofke, and Sharon C. Glotzer. Virial coefficients and equations of state for hard polyhedron fluids. Langmuir, 33(42):11788–11796, 2017. PMID: 28915732. arXiv:https://doi.org/10.1021/acs.langmuir.7b02384, doi:10.1021/acs.langmuir.7b02384.

[Joh66]

Norman W. Johnson. Convex polyhedra with regular faces. Canadian Journal of Mathematics, 18:169–200, 1966. doi:10.4153/cjm-1966-021-8.

[Kal06]

Michael Kallay. Computing the moment of inertia of a solid defined by a triangle mesh. Journal of Graphics Tools, 11(2):51–57, 2006. doi:10.1080/2151237X.2006.10129220.

[MT80]

A. M. Messner and G. Q. Taylor. Algorithm 550: solid polyhedron measures [z]. ACM Transactions on Mathematical Software, 6(1):121–130, 1980. doi:10.1145/355873.355885.

[NL84]

K.-H. Naumann and T.W. Leland. Conformal solution methods based on the hard convex body expansion theory. Fluid Phase Equilibria, 18(1):1 – 45, 1984. doi:https://doi.org/10.1016/0378-3812(84)80019-9.

Indices and tables#