Oregon Curriculum Network

Computing Volumes in XYZ and IVM units

by Kirby Urner, July 2016

Fig. 1

A cube is composed of 24 identical not-regular tetrahedrons, each with a corner at the cube's center, an edge from cube's center to a face center, and two more to adjacent cube corners on that face, defining six edges in all (Fig. 1).

If we define the cube's edges to be √2 then the whole cube would have volume √2 √2 √2 in XYZ units.

However, in IVM units, the very same cube has a volume of 3, owing to the differently-shaped volume unit, a tetrahedron of edges 2, inscribed in this same cube. Fig. 986.210 from Synergetics:

Fig. 2

Those lengths would be in R-units, where R is the radius of a unit sphere. In D-units, twice as long (D = 2R), the tetrahedron has edges 1 and the cube has edges √2/2.

By XYZ we mean the XYZ coordinate system of René Descartes (1596 – 1650).

By IVM we mean the "octet-truss", a space-frame consisting of tetrahedrons and octahedrons in a space-filling matrix, with twice as many tetrahedrons as octahedrons.

octet truss

The tetrahedron and octahedron have relative volumes of 1:4. The question then becomes, how to superimpose the two.

The canonical solution is to start with unit-radius balls (spheres) of radius R. R = 1 in other words, whereas D, the diameter, is 2. Alternatively, we may set D = 1 and R = 0.5, keeping the same 2:1 ratio for D:R.

The XYZ cube has edges R, whereas the IVM tetrahedron has edges D. That relative sizing convention brings their respective volumes fairly close together, with the cube's volume exceeding the tetrahedron's by about six percent.

In [1]:
import math
xyz_volume = math.sqrt(2)**3
ivm_volume = 3
print("XYZ units:", xyz_volume)
print("IVM units:", ivm_volume)
print("Conversion constant:", ivm_volume/xyz_volume)
XYZ units: 2.8284271247461907
IVM units: 3
Conversion constant: 1.060660171779821

The Python code below encodes a Tetrahedron type based solely on its six edge lengths. The code makes no attempt to determine the consequent angles.

A complicated volume formula, mined from the history books and streamlined by mathematician Gerald de Jong, outputs the volume of said tetrahedron in both IVM and XYZ units.

The unittests that follow assure it's producing the expected results.

In [2]:
from math import sqrt, hypot

class Tetrahedron:
    Takes six edges of tetrahedron with faces
    (a,b,d)(b,c,e)(c,a,f)(d,e,f) -- returns volume
    in ivm and xyz units

    def __init__(self, a,b,c,d,e,f):
        self.a, self.a2 = a, a**2
        self.b, self.b2 = b, b**2
        self.c, self.c2 = c, c**2
        self.d, self.d2 = d, d**2
        self.e, self.e2 = e, e**2
        self.f, self.f2 = f, f**2

    def ivm_volume(self):
        ivmvol = ((self._addopen() - self._addclosed() - self._addopposite())/2) ** 0.5
        return ivmvol

    def xyz_volume(self):
        xyzvol = sqrt(8/9) * self.ivm_volume()
        return xyzvol

    def _addopen(self):
        a2,b2,c2,d2,e2,f2 = self.a2, self.b2, self.c2, self.d2, self.e2, self.f2
        sumval = f2*a2*b2
        sumval +=  d2 * a2 * c2
        sumval +=  a2 * b2 * e2
        sumval +=  c2 * b2 * d2
        sumval +=  e2 * c2 * a2
        sumval +=  f2 * c2 * b2
        sumval +=  e2 * d2 * a2
        sumval +=  b2 * d2 * f2
        sumval +=  b2 * e2 * f2
        sumval +=  d2 * e2 * c2
        sumval +=  a2 * f2 * e2
        sumval +=  d2 * f2 * c2
        return sumval

    def _addclosed(self):
        a2,b2,c2,d2,e2,f2 = self.a2, self.b2, self.c2, self.d2, self.e2, self.f2
        sumval =   a2 * b2 * d2
        sumval +=  d2 * e2 * f2
        sumval +=  b2 * c2 * e2
        sumval +=  a2 * c2 * f2
        return sumval

    def _addopposite(self):
        a2,b2,c2,d2,e2,f2 = self.a2, self.b2, self.c2, self.d2, self.e2, self.f2
        sumval =  a2 * e2 * (a2 + e2)
        sumval += b2 * f2 * (b2 + f2)
        sumval += c2 * d2 * (c2 + d2)
        return sumval

PHI = sqrt(5)/2 + 0.5

R =0.5
D =1.0

tet = Tetrahedron(D, D, D, D, D, D)
In [3]:
import unittest
class Test_Tetrahedron(unittest.TestCase):

    def test_unit_volume(self):
        tet = Tetrahedron(D, D, D, D, D, D)
        self.assertAlmostEqual(tet.ivm_volume(), 1.0, places=5)

    def test_unit_volume(self):
        tet = Tetrahedron(R, R, R, R, R, R)
        self.assertAlmostEqual(tet.xyz_volume(), 0.11785, places=5)

    def test_phi_edge_tetra(self):
        tet = Tetrahedron(D, D, D, D, D, PHI)
        self.assertAlmostEqual(tet.ivm_volume(), 0.70711, places=5)

    def test_right_tetra(self):
        e = hypot(sqrt(3)/2, sqrt(3)/2)  # right tetrahedron
        tet = Tetrahedron(D, D, D, D, D, e)
        self.assertAlmostEqual(tet.xyz_volume(), 1.0, places=5)

a = Test_Tetrahedron()

R =0.5
D =1.0

suite = unittest.TestLoader().loadTestsFromModule(a)
Ran 3 tests in 0.005s

<unittest.runner.TextTestResult run=3 errors=0 failures=0>
In [4]:
a = 2
b = 4
c = 5
d = 3.4641016151377544
e = 4.58257569495584
f = 4.358898943540673
tetra = Tetrahedron(a,b,c,d,e,f)
print("IVM volume of tetra:", tetra.ivm_volume())
IVM volume of tetra: 39.99999999999998

Lets define a MITE, one of these 24 identical space-filling tetrahedrons, with reference to D=1, R=0.5, as this is how our Tetrahedron class is calibrated. The cubes 12 edges will all be √2/2.

Edges 'a' 'b' 'c' fan out from the cube center, with 'b' going up to a face center, with 'a' and 'c' to adjacent ends of the face's edge.

From the cube's center to mid-face is √2/4 (half an edge), our 'b'. 'a' and 'c' are both half the cube's body diagonal of √(3/2)/2 or √(3/8).

Edges 'd', 'e' and 'f' define the facet opposite the cube's center.

'd' and 'e' are both half face diagonals or 0.5, whereas 'f' is a cube edge, √2/2. This gives us our tetrahedron:

In [5]:
b = sqrt(2)/4
a = c = sqrt(3/8)
d = e = 0.5
f = sqrt(2)/2
mite = Tetrahedron(a, b, c, d, e, f)
print("IVM volume of Mite:", mite.ivm_volume())
print("XYZ volume of Mite:", mite.xyz_volume())
IVM volume of Mite: 0.12499999999999994
XYZ volume of Mite: 0.11785113019775786

Allowing for floating point error, this space-filling right tetrahedron has a volume of 0.125 or 1/8. Since 24 of them form a cube, said cube has a volume of 3. The XYZ volume, on the other hand, is what we'd expect from a regular tetrahedron of edges 0.5 in the current calibration system.

In [6]:
regular = Tetrahedron(0.5, 0.5, 0.5, 0.5, 0.5, 0.5)
print("MITE volume in XYZ units:", regular.xyz_volume())
print("XYZ volume of 24-Mite Cube:", 24 * regular.xyz_volume())
MITE volume in XYZ units: 0.11785113019775792
XYZ volume of 24-Mite Cube: 2.82842712474619

The MITE (minimum tetrahedron) further dissects into component modules, a left and right A module, then either a left or right B module. Outwardly, the positive and negative MITEs look the same. Here are some drawings from R. Buckminster Fuller's research, the chief popularizer of the A and B modules.

A and B mods

In a different Jupyter Notebook, we could run these tetrahedra through our volume computer to discover both As and Bs have a volume of 1/24 in IVM units.

Instead, lets take a look at the E-module and compute its volume.

The black hub is at the center of the RT, as shown here...

E module with origin RT center is the black hub (Koski with vZome)
In [7]:
from math import sqrt as rt2
from tetravolume import make_tet, Vector

ø = (rt2(5)+1)/2
e0 = Black_Yellow = rt2(3)*ø**-1
e1 = Black_Blue = 1
e3 = Yellow_Blue = (3 - rt2(5))/2
e6 = Black_Red = rt2((5 - rt2(5))/2)
e7 = Blue_Red = 1/ø

# E-mod is a right tetrahedron, so xyz is easy
v0 = Vector((Black_Blue, 0, 0))
v1 = Vector((Black_Blue, Yellow_Blue, 0))
v2 = Vector((Black_Blue, 0, Blue_Red))

# assumes R=0.5 so computed result is 8x needed
# volume, ergo divide by 8.
ivm, xyz = make_tet(v0,v1,v2)

print("IVM volume:", ivm/8)
print("XYZ volume:", xyz/8)
IVM volume: 0.04173131692777364453602187865
XYZ volume: 0.03934466291663160686315718999

This information is being shared around Portland in various contexts. Below, an image from a hands-on workshop in 2010 organized by the Portland Free School.

Free School, Portland