Skip to content

Commit

Permalink
Extending support for larger atomic numbers (#5821)
Browse files Browse the repository at this point in the history
**Context:** Currently, we support only first- or second-row elements of
the periodic table for molecule and Hamiltonian constructions. This PR
aims to push this limit to all the elements.

**Description of the Change:** Updates the `atomic_numbers` dictionary
in the `qchem/basis_data.py` and adapts the qchem functionality with
this update.

**Benefits:** We can support more elements by letting users use
`load_data=True` keyword argument.

**Possible Drawbacks:** None

**Related GitHub Issues:**
  • Loading branch information
obliviateandsurrender committed Jul 18, 2024
1 parent c10e423 commit e76e301
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 19 deletions.
4 changes: 4 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
* Observable validation for `default.qubit` is now based on execution mode (analytic vs. finite shots) and measurement type (sample measurement vs. state measurement).
[(#5890)](https://github.com/PennyLaneAI/pennylane/pull/5890)

* Molecules and Hamiltonians can now be constructed for all the elements present in the periodic table.
[(#5821)](https://github.com/PennyLaneAI/pennylane/pull/5821)

<h4>Community contributions 🥳</h4>

* `DefaultQutritMixed` readout error has been added using parameters `readout_relaxation_probs` and
Expand Down Expand Up @@ -92,6 +95,7 @@

This release contains contributions from (in alphabetical order):
Guillermo Alonso,
Utkarsh Azad
Astral Cai,
Yushao Chen,
Gabriel Bottrill,
Expand Down
39 changes: 27 additions & 12 deletions pennylane/qchem/basis_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,30 @@

import itertools

# Note: Below markers are added to prevent reformatting of this dictionary by black
# fmt: off
# IUPAC Periodic Table of the Elements: https://iupac.org/what-we-do/periodic-table-of-elements/
atomic_numbers = {
"H": 1,
"He": 2,
"Li": 3,
"Be": 4,
"B": 5,
"C": 6,
"N": 7,
"O": 8,
"F": 9,
"Ne": 10,
'H': 1, 'He': 2, # Period 1
'Li': 3, 'Be': 4, 'B': 5, 'C': 6, 'N': 7, 'O': 8, 'F': 9, 'Ne': 10, # Period 2
'Na': 11, 'Mg': 12, 'Al': 13, 'Si': 14, 'P': 15, 'S': 16, 'Cl': 17, 'Ar': 18, # Period 3
'K': 19, 'Ca': 20, 'Sc': 21, 'Ti': 22, 'V': 23, 'Cr': 24, 'Mn': 25, 'Fe': 26, 'Co': 27, # Period 4
'Ni': 28, 'Cu': 29, 'Zn': 30, 'Ga': 31, 'Ge': 32, 'As': 33, 'Se': 34, 'Br': 35, 'Kr': 36,
'Rb': 37, 'Sr': 38, 'Y': 39, 'Zr': 40, 'Nb': 41, 'Mo': 42, 'Tc': 43, 'Ru': 44, 'Rh': 45, # Period 5
'Pd': 46, 'Ag': 47, 'Cd': 48, 'In': 49, 'Sn': 50, 'Sb': 51, 'Te': 52, 'I': 53, 'Xe': 54,
'Cs': 55, 'Ba': 56, # Period 6
'La': 57, 'Ce': 58, 'Pr': 59, 'Nd': 60, 'Pm': 61, 'Sm': 62, 'Eu': 63, 'Gd': 64, 'Tb': 65, # Lanthanides
'Dy': 66, 'Ho': 67, 'Er': 68, 'Tm': 69, 'Yb': 70, 'Lu': 71,
'Hf': 72, 'Ta': 73, 'W': 74, 'Re': 75, 'Os': 76, 'Ir': 77, 'Pt': 78, 'Au': 79, 'Hg': 80, # Period 6
'Tl': 81, 'Pb': 82, 'Bi': 83, 'Po': 84, 'At': 85, 'Rn': 86,
'Fr': 87, 'Ra': 88, # Period 7
'Ac': 89, 'Th': 90, 'Pa': 91, 'U': 92, 'Np': 93, 'Pu': 94, 'Am': 95, 'Cm': 96, 'Bk': 97, # Actinides
'Cf': 98, 'Es': 99, 'Fm': 100, 'Md': 101, 'No': 102, 'Lr': 103,
'Rf': 104, 'Db': 105, 'Sg': 106, 'Bh': 107, 'Hs': 108, 'Mt': 109, 'Ds': 110, 'Rg': 111, # Period 7
'Cn': 112, 'Nh': 113, 'Fl': 114, 'Mc': 115, 'Lv': 116, 'Ts': 117, 'Og': 118
}
# fmt: on


STO3G = {
"H": {
Expand Down Expand Up @@ -797,11 +809,14 @@ def load_basisset(basis, element):
"[3]": "F",
"[4]": "G",
"[5]": "H",
"[6]": "I",
}

element = str(atomic_numbers[element])
atomic_number = atomic_numbers.get(element, None)
if atomic_number is None:
raise ValueError(f"Requested element {element} doesn't exist in the periodic table.")

data = bse.get_basis(basis)["elements"][element]["electron_shells"]
data = bse.get_basis(basis)["elements"][str(atomic_number)]["electron_shells"]

orbitals = []
exponents = []
Expand Down
9 changes: 8 additions & 1 deletion pennylane/qchem/basis_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,14 @@ def atom_basis_data(name, atom, load_data=False):
if load_data:
basis = load_basisset(name, atom)
else:
basis = basis_sets[name][atom]
basis = basis_sets[name].get(atom, None)
if basis is None:
raise ValueError(
f"The requested basis set data is not available for {atom}. "
"Please consider using `load_data=True` to download the basis set "
"from the external library basis-set-exchange that can be installed with: "
"pip install basis-set-exchange."
)

params = []
sp_count = 0
Expand Down
5 changes: 1 addition & 4 deletions pennylane/qchem/openfermion_pyscf.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,10 +609,7 @@ def dipole_of(

for i in symbols:
if i not in atomic_numbers:
raise ValueError(
f"Currently, only first- or second-row elements of the periodic table are supported;"
f" got element {i}"
)
raise ValueError(f"Requested element {i} doesn't exist")

hf_file = qml.qchem.meanfield(symbols, coordinates, name, charge, mult, basis, package, outpath)

Expand Down
2 changes: 1 addition & 1 deletion tests/qchem/openfermion_pyscf_tests/test_dipole_of.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ def circuit(hf_state, obs):
("symbols", "coords", "mult", "msg_match"),
[
(["H", "H"], x_h2, 2, "this functionality is constrained to Hartree-Fock states"),
(["H", "Ca"], x_h2, 1, "only first- or second-row elements of the periodic table"),
(["H", "Cx"], x_h2, 1, "Requested element Cx doesn't exist"),
],
)
@pytest.mark.usefixtures("skip_if_no_openfermion_support")
Expand Down
9 changes: 9 additions & 0 deletions tests/qchem/test_basis_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,15 @@ def test_mol_basis_data(self, basis_data):

assert np.allclose(params, params_ref)

def test_mol_basis_data_error(self):
"""Test that correct error is raised if the element is not present in the internal basis-sets"""

with pytest.raises(ValueError, match="The requested basis set data is not available for"):
qchem.basis_set.atom_basis_data(name="sto-3g", atom="Os")

with pytest.raises(ValueError, match="Requested element Ox doesn't exist"):
qchem.basis_data.load_basisset(basis="sto-3g", element="Ox")


class TestLoadBasis:
"""Tests for loading data from external libraries."""
Expand Down
2 changes: 1 addition & 1 deletion tests/qchem/test_molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def test_basis_error(self, symbols, geometry):
@pytest.mark.parametrize(
("symbols", "geometry"),
[
(["H", "Og"], np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]])),
(["H", "Ox"], np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]])),
],
)
def test_symbol_error(self, symbols, geometry):
Expand Down

0 comments on commit e76e301

Please sign in to comment.