From ac3ecae5d759c081e06fb5a4fd06932d0e695df7 Mon Sep 17 00:00:00 2001 From: arettig Date: Mon, 22 Jun 2026 16:59:19 +0000 Subject: [PATCH 1/3] Add naming for spin states greater than 2S+1=12 Previously the spin state name was obtained using a dictionary mapping integer spin state to the name string. Only up to 11 unpaired electrons were supported this way. With this change, larger spins are named via n-multiplet (e.g. 12 unpaired electrons gives a 13-multiplet state). --- src/openfermion/chem/molecular_data.py | 8 +++++--- src/openfermion/chem/molecular_data_test.py | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/openfermion/chem/molecular_data.py b/src/openfermion/chem/molecular_data.py index 64dc376b6..00f047b4f 100644 --- a/src/openfermion/chem/molecular_data.py +++ b/src/openfermion/chem/molecular_data.py @@ -273,10 +273,12 @@ def name_molecule(geometry, basis, multiplicity, charge, description): 11: 'undectet', 12: 'duodectet', } - if multiplicity not in multiplicity_dict: - raise MoleculeNameError('Invalid spin multiplicity provided.') - else: + if multiplicity in multiplicity_dict: name += '_{}'.format(multiplicity_dict[multiplicity]) + elif isinstance(multiplicity, (int, numpy.integer)) and multiplicity > 0: + name += '_{}-multiplet'.format(multiplicity) + else: + raise MoleculeNameError('Invalid spin multiplicity provided.') # Add charge. if charge > 0: diff --git a/src/openfermion/chem/molecular_data_test.py b/src/openfermion/chem/molecular_data_test.py index d51e6937c..2391bd974 100644 --- a/src/openfermion/chem/molecular_data_test.py +++ b/src/openfermion/chem/molecular_data_test.py @@ -104,6 +104,21 @@ def test_invalid_multiplicity(self): with self.assertRaises(MoleculeNameError): MolecularData(geometry, basis, multiplicity) + # Test non-integer multiplicity + with self.assertRaises(MoleculeNameError): + MolecularData(geometry, basis, multiplicity=1.5) + + # Test zero multiplicity + with self.assertRaises(MoleculeNameError): + MolecularData(geometry, basis, multiplicity=0) + + def test_high_multiplicity(self): + # 12 hydrogens can support multiplicity 13 + geometry = [('H', (0.0, 0.0, i * 1.3)) for i in range(12)] + basis = 'sto-3g' + molecule = MolecularData(geometry, basis, multiplicity=13) + self.assertEqual(molecule.name, 'H12_sto-3g_13-multiplet') + def test_geometry_from_file(self): water_geometry = [ ('O', (0.0, 0.0, 0.0)), From 1c0bceb2869142e70c3eea69aeffd038bf8b0e83 Mon Sep 17 00:00:00 2001 From: arettig Date: Mon, 22 Jun 2026 20:08:39 +0000 Subject: [PATCH 2/3] Improve handling of incorrect multiplicities The multiplicity parameter of molecular_data is now checked in the constructor and a ValueError is thrown if a noninteger or negative value is used. Tests are added to check errors are correctly thrown. --- src/openfermion/chem/molecular_data.py | 13 +++++++++---- src/openfermion/chem/molecular_data_test.py | 20 ++++++++++++++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/openfermion/chem/molecular_data.py b/src/openfermion/chem/molecular_data.py index 00f047b4f..5e892d466 100644 --- a/src/openfermion/chem/molecular_data.py +++ b/src/openfermion/chem/molecular_data.py @@ -275,10 +275,10 @@ def name_molecule(geometry, basis, multiplicity, charge, description): } if multiplicity in multiplicity_dict: name += '_{}'.format(multiplicity_dict[multiplicity]) - elif isinstance(multiplicity, (int, numpy.integer)) and multiplicity > 0: + elif multiplicity > 0: name += '_{}-multiplet'.format(multiplicity) else: - raise MoleculeNameError('Invalid spin multiplicity provided.') + raise ValueError('Invalid spin multiplicity provided.') # Add charge. if charge > 0: @@ -493,7 +493,12 @@ def __init__( # Metadata fields which must be provided. self.geometry = geometry self.basis = basis - self.multiplicity = multiplicity + if isinstance( + multiplicity, (int, float, numpy.integer, numpy.floating) + ) and multiplicity == int(multiplicity): + self.multiplicity = int(multiplicity) + else: + raise ValueError('Invalid spin multiplicity provided.') # Metadata fields with default values. self.charge = charge @@ -502,7 +507,7 @@ def __init__( self.description = description # Name molecule and get associated filename - self.name = name_molecule(geometry, basis, multiplicity, charge, description) + self.name = name_molecule(geometry, basis, self.multiplicity, charge, description) if filename: if filename[-5:] == '.hdf5': filename = filename[: (len(filename) - 5)] diff --git a/src/openfermion/chem/molecular_data_test.py b/src/openfermion/chem/molecular_data_test.py index 2391bd974..035a52288 100644 --- a/src/openfermion/chem/molecular_data_test.py +++ b/src/openfermion/chem/molecular_data_test.py @@ -30,7 +30,6 @@ bohr_to_angstroms, load_molecular_hamiltonian, MolecularData, - MoleculeNameError, geometry_from_file, MissingCalculationError, periodic_table, @@ -101,15 +100,15 @@ def test_invalid_multiplicity(self): geometry = [('H', (0.0, 0.0, 0.0)), ('H', (0.0, 0.0, 0.7414))] basis = 'sto-3g' multiplicity = -1 - with self.assertRaises(MoleculeNameError): + with self.assertRaises(ValueError): MolecularData(geometry, basis, multiplicity) # Test non-integer multiplicity - with self.assertRaises(MoleculeNameError): + with self.assertRaises(ValueError): MolecularData(geometry, basis, multiplicity=1.5) # Test zero multiplicity - with self.assertRaises(MoleculeNameError): + with self.assertRaises(ValueError): MolecularData(geometry, basis, multiplicity=0) def test_high_multiplicity(self): @@ -119,6 +118,19 @@ def test_high_multiplicity(self): molecule = MolecularData(geometry, basis, multiplicity=13) self.assertEqual(molecule.name, 'H12_sto-3g_13-multiplet') + def test_float_multiplicity(self): + geometry = [('H', (0.0, 0.0, 0.0)), ('H', (0.0, 0.0, 0.7414))] + basis = 'sto-3g' + + # Float multiplicity <= 12 should work and use name + molecule = MolecularData(geometry, basis, multiplicity=2.0) + self.assertEqual(molecule.name, 'H2_sto-3g_doublet') + + # Float multiplicity > 12 should work and use number + geometry_high = [('H', (0.0, 0.0, i * 1.3)) for i in range(12)] + molecule_high = MolecularData(geometry_high, basis, multiplicity=13.0) + self.assertEqual(molecule_high.name, 'H12_sto-3g_13-multiplet') + def test_geometry_from_file(self): water_geometry = [ ('O', (0.0, 0.0, 0.0)), From e17860942917c3479e06d1020d30d7bd436d86f9 Mon Sep 17 00:00:00 2001 From: arettig Date: Tue, 23 Jun 2026 15:14:20 +0000 Subject: [PATCH 3/3] Change error type back to MoleculeNameError The error in molecular_data when providing an incorrect multiplicity needs to remain a MoleculeNameError to ensure backwards compatibility. This error type now inherits from ValueError (which makes more sense physically). --- src/openfermion/chem/molecular_data.py | 8 +++++--- src/openfermion/chem/molecular_data_test.py | 7 ++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/openfermion/chem/molecular_data.py b/src/openfermion/chem/molecular_data.py index 5e892d466..bc79e3e28 100644 --- a/src/openfermion/chem/molecular_data.py +++ b/src/openfermion/chem/molecular_data.py @@ -33,7 +33,9 @@ # Define error objects which inherit from Exception. -class MoleculeNameError(Exception): +class MoleculeNameError(ValueError): + """Exception raised when a molecule name is invalid or cannot be generated.""" + pass @@ -278,7 +280,7 @@ def name_molecule(geometry, basis, multiplicity, charge, description): elif multiplicity > 0: name += '_{}-multiplet'.format(multiplicity) else: - raise ValueError('Invalid spin multiplicity provided.') + raise MoleculeNameError('Invalid spin multiplicity provided.') # Add charge. if charge > 0: @@ -498,7 +500,7 @@ def __init__( ) and multiplicity == int(multiplicity): self.multiplicity = int(multiplicity) else: - raise ValueError('Invalid spin multiplicity provided.') + raise MoleculeNameError('Invalid spin multiplicity provided.') # Metadata fields with default values. self.charge = charge diff --git a/src/openfermion/chem/molecular_data_test.py b/src/openfermion/chem/molecular_data_test.py index 035a52288..c640f3303 100644 --- a/src/openfermion/chem/molecular_data_test.py +++ b/src/openfermion/chem/molecular_data_test.py @@ -30,6 +30,7 @@ bohr_to_angstroms, load_molecular_hamiltonian, MolecularData, + MoleculeNameError, geometry_from_file, MissingCalculationError, periodic_table, @@ -100,15 +101,15 @@ def test_invalid_multiplicity(self): geometry = [('H', (0.0, 0.0, 0.0)), ('H', (0.0, 0.0, 0.7414))] basis = 'sto-3g' multiplicity = -1 - with self.assertRaises(ValueError): + with self.assertRaises(MoleculeNameError): MolecularData(geometry, basis, multiplicity) # Test non-integer multiplicity - with self.assertRaises(ValueError): + with self.assertRaises(MoleculeNameError): MolecularData(geometry, basis, multiplicity=1.5) # Test zero multiplicity - with self.assertRaises(ValueError): + with self.assertRaises(MoleculeNameError): MolecularData(geometry, basis, multiplicity=0) def test_high_multiplicity(self):