This page was generated from docs/src/notebooks/choosing-site-basis-sets.ipynb.

Choosing the site basis set for a cluster subspace#

[1]:
import random
import numpy as np
from monty.serialization import loadfn
from smol.cofe import ClusterSubspace, available_site_basis_sets
[2]:
# load the prim structure
prim = loadfn('data/lmo_drx_prim.json')

0) Listing available basis sets#

A variety of different site basis sets are available in smol. To list the options simply use the function available_site_basis_sets

[3]:
print(f"The available site basis set options are:\n {available_site_basis_sets()}")
The available site basis set options are:
 ('indicator', 'sinusoid', 'polynomial', 'chebyshev', 'legendre')

1) Setting the site basis type in a cluster subspace#

The default site basis set is indicator, also known as the “occupancy” basis or the “lattice-gas” basis. However, the basis type can be set using the basis keyword argument when creating a cluster subspace.

[4]:
subspace_indicator = ClusterSubspace.from_cutoffs(
    prim,
    cutoffs={2: 4, 3: 3}, # will include orbits of 2 and 3 sites.
    supercell_size='O2-'
)

subspace_sine = ClusterSubspace.from_cutoffs(
    prim,
    cutoffs={2: 4, 3: 3}, # will include orbits of 2 and 3 sites.
    basis="sinusoid",
    supercell_size='O2-'
)
[5]:
print(subspace_indicator)
print(subspace_sine)
Basis/Orthogonal/Orthonormal : indicator/False/False
       Unit Cell Composition : Li+0.7 Mn2+0.7 Mn3+0.2 Mn4+0.2 O2-1
            Number of Orbits : 17
No. of Correlation Functions : 123
             Cluster Cutoffs : 2: 3.64, 3: 2.97
              External Terms : []
Orbit Summary
 ------------------------------------------------------------------------
 |  ID     Degree    Cluster Diameter    Multiplicity    No. Functions  |
 |   0       0             NA                 0                1        |
 |   1       1            0.0000              2                2        |
 |   2       1            0.0000              1                4        |
 |   3       2            1.8187              8                8        |
 |   4       2            2.1000              6                3        |
 |   5       2            2.9699              12               3        |
 |   6       2            2.9699              6               10        |
 |   7       2            3.4825              24               8        |
 |   8       2            3.6373              4                3        |
 |   9       2            3.6373              4                3        |
 |  10       3            2.1000              12              12        |
 |  11       3            2.9699              24               6        |
 |  12       3            2.9699              12              12        |
 |  13       3            2.9699              12              20        |
 |  14       3            2.9699              8                4        |
 |  15       3            2.9699              8                4        |
 |  16       3            2.9699              8               20        |
 ------------------------------------------------------------------------
Basis/Orthogonal/Orthonormal : sinusoid/True/False
       Unit Cell Composition : Li+0.7 Mn2+0.7 Mn3+0.2 Mn4+0.2 O2-1
            Number of Orbits : 17
No. of Correlation Functions : 123
             Cluster Cutoffs : 2: 3.64, 3: 2.97
              External Terms : []
Orbit Summary
 ------------------------------------------------------------------------
 |  ID     Degree    Cluster Diameter    Multiplicity    No. Functions  |
 |   0       0             NA                 0                1        |
 |   1       1            0.0000              2                2        |
 |   2       1            0.0000              1                4        |
 |   3       2            1.8187              8                8        |
 |   4       2            2.1000              6                3        |
 |   5       2            2.9699              12               3        |
 |   6       2            2.9699              6               10        |
 |   7       2            3.4825              24               8        |
 |   8       2            3.6373              4                3        |
 |   9       2            3.6373              4                3        |
 |  10       3            2.1000              12              12        |
 |  11       3            2.9699              24               6        |
 |  12       3            2.9699              12              12        |
 |  13       3            2.9699              12              20        |
 |  14       3            2.9699              8                4        |
 |  15       3            2.9699              8                4        |
 |  16       3            2.9699              8               20        |
 ------------------------------------------------------------------------

Checking orthogonality and orthonormality#

We see from printing the subspace above that the indicator basis is not orthogonal, and that the sinusoid basis is not orthonormal (it orthonormal for binary systems only)

We can also check if a the basis is orthogonal or orthonormal programmatically.

[6]:
print(f"The {subspace_indicator.basis_type} basis is orthogonal {subspace_indicator.basis_orthogonal}")
print(f"The {subspace_indicator.basis_type} basis is orthogonal {subspace_indicator.basis_orthonormal}\n")

print(f"The {subspace_sine.basis_type} basis is orthogonal {subspace_sine.basis_orthogonal}")
print(f"The {subspace_sine.basis_type} basis is orthogonal {subspace_sine.basis_orthonormal}")
The indicator basis is orthogonal False
The indicator basis is orthogonal False

The sinusoid basis is orthogonal True
The sinusoid basis is orthogonal False

Inspecting basis functions#

We can see the actual basis functions by printing the basis_array of singlet orbits. Each row of the basis array corresponds to a basis function.

[7]:
i = 0
print(subspace_indicator.orbits[i], "\n")

print(f"{subspace_indicator.basis_type} basis function:\n {subspace_indicator.orbits[i].basis_arrays[0]}\n")
print(f"{subspace_sine.basis_type} basis function:\n {subspace_sine.orbits[i].basis_arrays[0]}\n")
Orbit  1
    Multiplicity : 2
   No. functions : 2
No. symmetry ops : 24
Function ids : [1, 2]
Base Cluster :
  | Diameter : 0.0000
  |   Charge : 1.0
  | Centroid :     2.571966     1.818654     4.454775  ->     0.750000     0.750000     0.750000
  | Sites (1)
  | ------------------------------------------------------------------------------------------------------------------------
  | 0 vacA0+:0.333, Li+:0.333, Mn2+:0.333     2.571966     1.818654     4.454775   ->     0.750000     0.750000     0.750000

indicator basis function:
 [[1. 0. 0.]
 [0. 1. 0.]]

sinusoid basis function:
 [[-1.         0.5        0.5      ]
 [-0.        -0.8660254  0.8660254]]

[8]:
i = 1
print(subspace_indicator.orbits[i], "\n")

print(f"{subspace_indicator.basis_type} basis function:\n {subspace_indicator.orbits[i].basis_arrays[0]}\n")
print(f"{subspace_sine.basis_type} basis function:\n {subspace_sine.orbits[i].basis_arrays[0]}\n")
Orbit  2
    Multiplicity : 1
   No. functions : 4
No. symmetry ops : 48
Function ids : [3, 4, 5, 6]
Base Cluster :
  | Diameter : 0.0000
  |   Charge : 2.0
  | Centroid :     0.000000     0.000000     0.000000  ->     0.000000     0.000000     0.000000
  | Sites (1)
  | ------------------------------------------------------------------------------------------------------------------------------------------------
  | 0 vacA0+:0.200, Li+:0.200, Mn2+:0.200, Mn3+:0.200, Mn4+:0.200     0.000000     0.000000     0.000000   ->     0.000000     0.000000     0.000000

indicator basis function:
 [[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]]

sinusoid basis function:
 [[-1.         -0.30901699  0.80901699  0.80901699 -0.30901699]
 [-0.         -0.95105652 -0.58778525  0.58778525  0.95105652]
 [-1.          0.80901699 -0.30901699 -0.30901699  0.80901699]
 [-0.         -0.58778525  0.95105652 -0.95105652  0.58778525]]

2) Changing the basis set of a cluster subspace#

We can change the basis set of a cluster subspace without having to create a new one (which is faster since it does not generate the orbits from scratch)

Note that changing the basis set of a cluster subspace used in a cluster expansion that has already been fitted does not transform the ECI, so it will need to be re-fitted.

[9]:
subspace_cheby = subspace_sine.copy()
subspace_cheby.change_site_bases("chebyshev")

print(f"The {subspace_cheby.basis_type} basis is orthogonal {subspace_cheby.basis_orthogonal}")
print(f"The {subspace_cheby.basis_type} basis is orthogonal {subspace_cheby.basis_orthonormal}")
The chebyshev basis is orthogonal False
The chebyshev basis is orthogonal False

Hey! Isn’t the Chebyshev basis from the original Sanchez paper orthonormal?#

That is correct! But the default implementation in smol uses Chebyshev polynomials without orthonormalizing. In order to get the original Sanchez et al, basis you must use the orthonormal=True option.

[10]:
# this option is also available in the from_cutoffs method
subspace_cheby.change_site_bases("chebyshev", orthonormal=True)

print(f"The {subspace_cheby.basis_type} basis is orthogonal {subspace_cheby.basis_orthogonal}")
print(f"The {subspace_cheby.basis_type} basis is orthogonal {subspace_cheby.basis_orthonormal}")
The chebyshev basis is orthogonal True
The chebyshev basis is orthogonal True

Technically you can orthonormalize any basis!#

And they will be essentially equivalent!

[11]:
subspace_indicator_on = ClusterSubspace.from_cutoffs(
    prim,
    cutoffs={2: 4, 3: 3}, # will include orbits of 2 and 3 sites.
    supercell_size='O2-',
    basis="indicator",
    orthonormal=True
)
[12]:
print(f"The {subspace_indicator_on.basis_type} basis is orthogonal {subspace_indicator_on.basis_orthogonal}")
print(f"The {subspace_indicator_on.basis_type} basis is orthogonal {subspace_indicator_on.basis_orthonormal}")
The indicator basis is orthogonal True
The indicator basis is orthogonal True

This is actually no longer an indicator basis!#

Lets have a look at the basis functions

[13]:
i = 0
print(subspace_cheby.orbits[i], "\n")

print(f"{subspace_cheby.basis_type} basis function:\n {subspace_cheby.orbits[i].basis_arrays[0]}\n")
print(f"{subspace_indicator_on.basis_type} basis function:\n {subspace_indicator_on.orbits[i].basis_arrays[0]}\n")
Orbit  1
    Multiplicity : 2
   No. functions : 2
No. symmetry ops : 24
Function ids : [1, 2]
Base Cluster :
  | Diameter : 0.0000
  |   Charge : 1.0
  | Centroid :     2.571966     1.818654     4.454775  ->     0.750000     0.750000     0.750000
  | Sites (1)
  | ------------------------------------------------------------------------------------------------------------------------
  | 0 vacA0+:0.333, Li+:0.333, Mn2+:0.333     2.571966     1.818654     4.454775   ->     0.750000     0.750000     0.750000

chebyshev basis function:
 [[-1.22474487 -0.          1.22474487]
 [-0.70710678  1.41421356 -0.70710678]]

indicator basis function:
 [[-1.41421356  0.70710678  0.70710678]
 [-0.          1.22474487 -1.22474487]]

The orthonormalized chebyshev and orthonormalized indicator basis sets look remarkably similar! In fact they are related simply by a rotation!