landlab.graph.quasi_spherical.refinable_icosahedron

RefinableIcosahedron: class that creates the vertices and triangular faces of an icosahedron (20-sided polygonal solid) that can be iteratively refined by replacing each triangle with four smaller triangles. Designed to provide the starting point for a Landlab icosphere grid.

Greg Tucker, University of Colorado Boulder, 2023 Adapted from a blog post and code snippet by Andreas Kahler, and translated into Python (plus function to output in vtk format)

class RefinableIcosahedron[source]

Bases: object

An icosahedron with faces that can be iteratively subdivided.

Class includes Cartesian coordinates of vertices (12 if not subdivided) and IDs of vertices composing each face (20 faces if not subdivided). Adapted from a blog post by Andreas Kahler.

Parameters:

radius (float) – Radius for the RefinableIcosahedron, length units (default 1)

Examples

Basic icosahedron

>>> ico = RefinableIcosahedron()
>>> len(ico.faces)
20
>>> len(ico.vertices)
12

Icosphere with two iterations of refinement

>>> ico.refine_triangles(recursion_level=2)
>>> len(ico.faces)
320
>>> len(ico.vertices)
162

Icosahedron with radius != 1

>>> ico = RefinableIcosahedron(radius=2.0)
>>> round(ico.vertices[1][0], 2)
1.05
>>> round(ico.vertices[0][1], 2)
1.7

Initialize RefinableIcosahedron

__init__(radius=1.0)[source]

Initialize RefinableIcosahedron

__new__(**kwargs)
add_vertex(vtx)[source]

Add a vertex, scaling its coordinates to fit the given radius, and return its index in the vertices list.

Parameters:

vtx (3-element tuple of float) – x, y, and z coordinates of vertex

Returns:

int

Return type:

index number of the new vertex

create_faces()[source]

Create the 20 triangular faces of the icosahedron.

Faces are stored in a list of 3-element tuples with the vertex IDs.

Note that “face” here means a triangle on the surface of the object, and is different from the Landlab definition of face as the edge shared by two neighboring cells.

create_vertices()[source]

Create the 12 vertices of an icosahedron.

Note that the vertex coordinates will be scaled to match the given radius.

get_middle_point(p1, p2)[source]

Identify and add a new point between two existing points.

Parameters:
  • p1 (int) – IDs of two points (vertices)

  • p2 (int) – IDs of two points (vertices)

Returns:

int

Return type:

index of the point (vertex) added

Notes

This function is used to refine the icosphere, and is called to place new vertices in the middle of the edges of triangles. Because each edge is shared by two triangles, we have to avoid adding the same point twice. To do this, we use a dictionary (middle_point_index_cache) to keep track of points already added. Each point has a key made of the two vertex IDs (one is bit-shifted, then they are added together). We only add a point if it isn’t already in the dict.

refine_triangles(recursion_level=1)[source]

Subdivide each triangle into four, and add corresponding vertices.

Parameters:

recursion_level (int, optional) – Number of subdivisions to apply (default 1)

write_to_vtk(path, clobber=False)[source]

Save the geometry in a vtk-format text file.

Note: this function is intended to test the RefinableIcosahedron. To write vtk for a Landlab IcosphereGlobalGrid, use landlab.io.legacy_vtk.dump to capture the full set of geometric primitives.

Parameters:
  • path (str, path-like , or file-like) – Target for output.

  • clobber (bool, optional) – Whether to allow overwriting of existing file.

Returns:

path – The given output path

Return type:

same as input above

Examples

>>> import io
>>> import os
>>> ico = RefinableIcosahedron()
>>> output = ico.write_to_vtk(io.StringIO())
>>> lines = output.getvalue().splitlines()
>>> print(lines[0])
# vtk DataFile Version 2.0
>>> print(os.linesep.join(lines[5:18]))
POINTS 12 float
-0.5257311121191336 0.85065080835204 0.0
0.5257311121191336 0.85065080835204 0.0
-0.5257311121191336 -0.85065080835204 0.0
0.5257311121191336 -0.85065080835204 0.0
0.0 -0.5257311121191336 0.85065080835204
0.0 0.5257311121191336 0.85065080835204
0.0 -0.5257311121191336 -0.85065080835204
0.0 0.5257311121191336 -0.85065080835204
0.85065080835204 0.0 -0.5257311121191336
0.85065080835204 0.0 0.5257311121191336
-0.85065080835204 0.0 -0.5257311121191336
-0.85065080835204 0.0 0.5257311121191336
>>> print(os.linesep.join(lines[18:40]))
CELLS 20 80
3 0 11 5
3 0 5 1
3 0 1 7
3 0 7 10
3 0 10 11
3 1 5 9
3 5 11 4
3 11 10 2
3 10 7 6
3 7 1 8
3 3 9 4
3 3 4 2
3 3 2 6
3 3 6 8
3 3 8 9
3 4 9 5
3 2 4 11
3 6 2 10
3 8 6 7
3 9 8 1
>>> print(os.linesep.join(lines[41:45]))
CELL_TYPES 20
5
5
5