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!