def test_transform_orbitals(): """Test orbtools.partition.OrbitalPartitionTools.transform_orbitals.""" with path("chemtools.data", "naclo4_coeff_ab_mo.npy") as fname: coeff_ab_mo = np.load(str(fname)) with path("chemtools.data", "naclo4_olp_ab_ab.npy") as fname: olp_ab_ab = np.load(str(fname)) with path("chemtools.data", "naclo4_occupations.npy") as fname: occupations = np.load(str(fname)) with path("chemtools.data", "naclo4_ab_atom_indices.npy") as fname: ab_atom_indices = np.load(str(fname)) coeff_ab_rand = np.linalg.svd(np.random.rand(124, 124))[0].T rand_atom_indices = (np.random.rand(124) * 6 // 1).astype(int) # normalize olp_rand_rand = coeff_ab_rand.T.dot(olp_ab_ab).dot(coeff_ab_rand) coeff_ab_rand *= np.diag(olp_rand_rand)**(-0.5) olp_rand_rand = coeff_ab_rand.T.dot(olp_ab_ab).dot(coeff_ab_rand) coeff_rand_mo = project(olp_rand_rand, coeff_ab_rand.T.dot(olp_ab_ab).dot(coeff_ab_mo)) orbpart = OrbitalPartitionTools(coeff_ab_mo, occupations, olp_ab_ab, 6, ab_atom_indices) neworbpart = orbpart.transform_orbitals(coeff_ab_rand, rand_atom_indices) assert np.allclose(coeff_ab_rand.dot(coeff_rand_mo), orbpart.coeff_ab_mo) assert np.allclose(coeff_rand_mo, neworbpart.coeff_ab_mo) assert np.allclose(olp_rand_rand, neworbpart.olp_ab_ab)
def test_bond_order(): """Test orbstools.partition.OrbitalPartitionTools.bond_order.""" with path("chemtools.data", "naclo4_coeff_ab_mo.npy") as fname: coeff_ab_mo = np.load(str(fname)) with path("chemtools.data", "naclo4_olp_ab_ab.npy") as fname: olp_ab_ab = np.load(str(fname)) with path("chemtools.data", "naclo4_occupations.npy") as fname: occupations = np.load(str(fname)) with path("chemtools.data", "naclo4_ab_atom_indices.npy") as fname: ab_atom_indices = np.load(str(fname)) bond_order = np.zeros((6, 6)) density = (coeff_ab_mo * occupations[None, :]).dot(coeff_ab_mo.T) raw_pops = olp_ab_ab.dot(density) for atom_one in range(6): for atom_two in range(6): if atom_one == atom_two: continue for i, index_one in enumerate(ab_atom_indices): for j, index_two in enumerate(ab_atom_indices): if index_one == atom_one and index_two == atom_two: # bond_order[atom_one, atom_two] += raw_pops[i, j] bond_order[atom_one, atom_two] += raw_pops[i, j] * raw_pops[j, i] orbpart = OrbitalPartitionTools(coeff_ab_mo, occupations, olp_ab_ab, 6, ab_atom_indices) assert np.allclose(bond_order, orbpart.bond_order())
def test_quambo(): """Test orbstools.quasi.quambo against literature value for Mulliken populations. References ---------- .. [1] Janowski, T. Near equivalence of intrinsic atomic orbitals and quasiatomic orbitals. JCTC, 2014, 10, 3085-3091. """ with path("chemtools.data", "naclo4_coeff_ab_mo.npy") as fname: coeff_ab_mo = np.load(str(fname)) with path("chemtools.data", "naclo4_olp_ab_ab.npy") as fname: olp_ab_ab = np.load(str(fname)) with path("chemtools.data", "naclo4_olp_aao_ab.npy") as fname: olp_aao_ab = np.load(str(fname)) with path("chemtools.data", "naclo4_occupations.npy") as fname: occupations = np.load(str(fname)) indices_span = occupations > 0 with path("chemtools.data", "naclo4_qab_atom_indices.npy") as fname: ab_atom_indices = np.load(str(fname)) olp_ab_omo = olp_ab_ab.dot(coeff_ab_mo[:, indices_span]) coeff_ab_quambo = quambo(olp_ab_ab, olp_aao_ab, coeff_ab_mo, indices_span) olp_quambo_quambo = coeff_ab_quambo.T.dot(olp_ab_ab).dot(coeff_ab_quambo) olp_quambo_omo = coeff_ab_quambo.T.dot(olp_ab_omo) coeff_quambo_omo = project(olp_quambo_quambo, olp_quambo_omo) pop = OrbitalPartitionTools( coeff_quambo_omo, occupations[indices_span], olp_quambo_quambo, 6, ab_atom_indices ).mulliken_populations() partial_pop = np.array([11, 17, 8, 8, 8, 8]) - pop assert np.allclose( partial_pop, np.array([0.968, 2.454, -0.807, -0.904, -0.904, -0.807]), atol=1e-3 )
def test_bond_order_wiberg_mayer_unrestricted(): """Test OrbitalPartitionTools.bond_order_wiberg_mayer against Gaussian results. Results are compared with those generated from Gaussian. The system is H2O UB3LYP/aug-cc-pVDZ, singlet, and at zero net charge. The following the its coordinates (au): O 0.0159484498, 0.0170042791, 0.0238579956 H -0.772778442, 0.561446550, 1.57501231 H 1.29850109, 1.26951236, -0.309113326 """ # pylint: disable=C0103 with path("chemtools.data", "h2o_coeff_ab_mo_alpha.npy") as fname: coeff_ab_mo_alpha = np.load(str(fname)) with path("chemtools.data", "h2o_coeff_ab_mo_beta.npy") as fname: coeff_ab_mo_beta = np.load(str(fname)) with path("chemtools.data", "h2o_occupations_alpha.npy") as fname: occupations_alpha = np.load(str(fname)) with path("chemtools.data", "h2o_occupations_beta.npy") as fname: occupations_beta = np.load(str(fname)) with path("chemtools.data", "h2o_olp_ab_ab_alpha.npy") as fname: olp_ab_ab_alpha = np.load(str(fname)) with path("chemtools.data", "h2o_olp_ab_ab_beta.npy") as fname: olp_ab_ab_beta = np.load(str(fname)) with path("chemtools.data", "h2o_ab_basis_map_alpha.npy") as fname: ab_atom_indices_alpha = np.load(str(fname)) with path("chemtools.data", "h2o_ab_basis_map_beta.npy") as fname: ab_atom_indices_beta = np.load(str(fname)) orbpart_alpha = OrbitalPartitionTools(coeff_ab_mo_alpha, occupations_alpha, olp_ab_ab_alpha, 3, ab_atom_indices_alpha) orbpart_beta = OrbitalPartitionTools(coeff_ab_mo_beta, occupations_beta, olp_ab_ab_beta, 3, ab_atom_indices_beta) bond_order = np.array([[0.0, 1.059127, 1.059127], [1.059127, 0.0, -0.008082], [1.059127, -0.008082, 0.0]]) assert np.allclose( bond_order, orbpart_alpha.bond_order_wiberg_mayer_unrestricted + orbpart_beta.bond_order_wiberg_mayer_unrestricted, atol=1e-6, )
def test_lowdin_populations(): """Test orbstools.partition.OrbitalPartitionTools.lowdin_populations.""" with path("chemtools.data", "naclo4_coeff_ab_mo.npy") as fname: coeff_ab_mo = np.load(str(fname)) with path("chemtools.data", "naclo4_olp_ab_ab.npy") as fname: olp_ab_ab = np.load(str(fname)) with path("chemtools.data", "naclo4_occupations.npy") as fname: occupations = np.load(str(fname)) with path("chemtools.data", "naclo4_ab_atom_indices.npy") as fname: ab_atom_indices = np.load(str(fname)) coeff_ab_oab = power_symmetric(olp_ab_ab, -0.5) orbpart = OrbitalPartitionTools(coeff_ab_mo, occupations, olp_ab_ab, 6, ab_atom_indices) assert np.allclose( coeff_ab_oab.T.dot(olp_ab_ab).dot(coeff_ab_oab), np.identity(124)) assert np.allclose( orbpart.transform_orbitals(coeff_ab_oab, ab_atom_indices).mulliken_populations(), orbpart.lowdin_populations(), )
def compute_bond_orders(self, scheme="wiberg-mayer"): """Return the bond order for each pair of atoms. Parameters ---------- scheme : "wiberg-mayer" Type of the bond order. Default is the Wiberg-Mayer bond order. Returns ------- bond_orders : np.ndarray(N, N) Bond order for each atom pair. Raises ------ ValueError If scheme is not "wiberg-mayer". """ coeff_ab_mo_alpha, coeff_ab_mo_beta = self._mo.coefficient occupations_alpha, occupations_beta = self._mo.occupation olp_ab_ab = self._ao.compute_overlap() num_atoms = len(self._numbers) ab_atom_indices = self._ao.center_index orbpart_alpha = OrbitalPartitionTools( coeff_ab_mo_alpha, occupations_alpha, olp_ab_ab, num_atoms, ab_atom_indices ) orbpart_beta = OrbitalPartitionTools( coeff_ab_mo_beta, occupations_beta, olp_ab_ab, num_atoms, ab_atom_indices ) if scheme == "wiberg-mayer": bond_order = orbpart_alpha.bond_order_wiberg_mayer_unrestricted bond_order += orbpart_beta.bond_order_wiberg_mayer_unrestricted else: raise ValueError("Bond order scheme must 'wiberg-mayer'.") return bond_order
def test_mulliken_populations_newbasis(): """Test orbstools.partition.OrbitalPartitionTools.mulliken_populations with a new basis.""" # pylint: disable=C0103 with path("chemtools.data", "naclo4_coeff_ab_mo.npy") as fname: coeff_ab_mo = np.load(str(fname)) with path("chemtools.data", "naclo4_olp_ab_ab.npy") as fname: olp_ab_ab = np.load(str(fname)) with path("chemtools.data", "naclo4_occupations.npy") as fname: occupations = np.load(str(fname)) with path("chemtools.data", "naclo4_ab_atom_indices.npy") as fname: ab_atom_indices = np.load(str(fname)) orbpart = OrbitalPartitionTools(coeff_ab_mo, occupations, olp_ab_ab, 6, ab_atom_indices) assert np.allclose( orbpart.transform_orbitals(np.identity(124), ab_atom_indices).mulliken_populations(), orbpart.mulliken_populations(), ) coeff_ab_rand = np.linalg.svd(np.random.rand(124, 124))[0].T rand_atom_indices = (np.random.rand(124) * 6 // 1).astype(int) # normalize olp_rand_rand = coeff_ab_rand.T.dot(olp_ab_ab).dot(coeff_ab_rand) coeff_ab_rand *= np.diag(olp_rand_rand)**(-0.5) olp_rand_rand = coeff_ab_rand.T.dot(olp_ab_ab).dot(coeff_ab_rand) coeff_rand_mo = project(olp_rand_rand, coeff_ab_rand.T.dot(olp_ab_ab).dot(coeff_ab_mo)) orbpart = OrbitalPartitionTools(coeff_ab_mo, occupations, olp_ab_ab, 6, rand_atom_indices) assert np.allclose(coeff_ab_rand.dot(coeff_rand_mo), coeff_ab_mo) assert np.allclose( orbpart.transform_orbitals(coeff_ab_rand, rand_atom_indices).mulliken_populations(), OrbitalPartitionTools(coeff_rand_mo, occupations, olp_rand_rand, 6, rand_atom_indices).mulliken_populations(), )
def test_mulliken_populations(): """Test orbstools.partition.OrbitalPartitionTools.mulliken_populations.""" # get random unitary matrix unitary = np.linalg.svd(np.random.rand(20, 20))[0] # get random olp_ab_ab olp_ab_ab = (unitary * np.random.rand(20)).dot(unitary.T) norm = np.diag(olp_ab_ab)**(-0.5) olp_ab_ab *= norm[:, None] olp_ab_ab *= norm[None, :] # get random mo's coeff_ab_mo = np.random.rand(20, 15) - 0.5 coeff_ab_mo *= np.diag( coeff_ab_mo.T.dot(olp_ab_ab).dot(coeff_ab_mo))**(-0.5) occupations = np.random.rand(15) num_atoms = 4 ab_atom_indices = np.array( [0, 1, 2, 1, 1, 0, 2, 1, 0, 2, 1, 2, 0, 1, 2, 0, 3, 3, 1, 0]) atom_weights = np.random.rand(4, 20, 20) atom_weights += np.swapaxes(atom_weights, 1, 2) atom_weights /= np.sum(atom_weights, axis=0)[None, :, :] orbpart = OrbitalPartitionTools(coeff_ab_mo, occupations, olp_ab_ab, num_atoms, ab_atom_indices) assert_raises(TypeError, orbpart.mulliken_populations, atom_weights=atom_weights.tolist()) assert_raises(ValueError, orbpart.mulliken_populations, atom_weights=np.random.rand(3, 20, 20)) assert_raises(ValueError, orbpart.mulliken_populations, atom_weights=np.random.rand(4, 20, 19)) assert_raises(ValueError, orbpart.mulliken_populations, atom_weights=np.random.rand(4, 20, 20)) rand_weights = np.random.rand(4, 20, 20) rand_weights += np.swapaxes(rand_weights, 1, 2) assert_raises(ValueError, orbpart.mulliken_populations, atom_weights=rand_weights) orbpart.mulliken_populations(atom_weights=atom_weights) # Model system coeff_ab_mo = np.identity(10) occupations = np.array([2] * 4 + [0] * 6) olp_ab_ab = np.identity(10) num_atoms = 2 ab_atom_indices = np.array([0, 0, 1, 1, 0, 0, 1, 1, 0, 1]) assert np.allclose( np.array([4, 4]), OrbitalPartitionTools(coeff_ab_mo, occupations, olp_ab_ab, num_atoms, ab_atom_indices).mulliken_populations(), ) # H2O RHF/STO-3G coeff_ab_mo = np.array([ [ 9.94099882e-01, -2.32889095e-01, 1.65502866e-08, 1.00235366e-01, 6.55422174e-16, -1.35631600e-01, 5.67656304e-08, ], [ 2.67799213e-02, 8.31788042e-01, -9.03020278e-08, -5.23423149e-01, -3.01062443e-15, 9.08581133e-01, -4.29452063e-07, ], [ 3.46630004e-03, 1.03349385e-01, -3.46565859e-01, 6.48259144e-01, 3.74502802e-15, 5.83295647e-01, 5.82525068e-01, ], [ 2.72896277e-16, -2.21764760e-16, 4.92555323e-16, -6.18875097e-15, 1.00000000e00, 1.62509738e-16, -6.76860125e-17, ], [ 2.45105601e-03, 7.30794097e-02, 4.90116062e-01, 4.58390414e-01, 2.54192740e-15, 4.12453695e-01, -8.23811720e-01, ], [ -6.08393842e-03, 1.60223990e-01, 4.41542336e-01, 2.69085788e-01, 1.34551715e-15, -8.07337352e-01, 8.42614916e-01, ], [ -6.08393693e-03, 1.60223948e-01, -4.41542341e-01, 2.69085849e-01, 1.99471214e-15, -8.07337875e-01, -8.42614243e-01, ], ]) occupations = np.array([2, 2, 2, 2, 2, 0, 0]) olp_ab_ab = np.array([ [1.0, 0.23670392, 0.0, 0.0, 0.0, 0.05490733, 0.05490732], [0.23670392, 1.0, 0.0, 0.0, 0.0, 0.47954331, 0.47954323], [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.37329955], [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 1.0, 0.39594342, -0.13197959], [0.05490733, 0.47954331, 0.0, 0.0, 0.39594342, 1.0, 0.23846113], [ 0.05490732, 0.47954323, 0.37329955, 0.0, -0.13197959, 0.23846113, 1.0 ], ]) num_atoms = 3 ab_atom_indices = np.array([0, 0, 0, 0, 0, 1, 2]) assert np.allclose( np.array([-0.38189777, 0.1909489, 0.19094886]), np.array([8, 1, 1]) - OrbitalPartitionTools(coeff_ab_mo, occupations, olp_ab_ab, num_atoms, ab_atom_indices).mulliken_populations(), )
def test_init(): """Test MullikenPopulations.__init__.""" # get random unitary matrix unitary = np.linalg.svd(np.random.rand(20, 20))[0] # get random olp_ab_ab olp_ab_ab = (unitary * np.random.rand(20)).dot(unitary.T) norm = np.diag(olp_ab_ab)**(-0.5) olp_ab_ab *= norm[:, None] olp_ab_ab *= norm[None, :] # get random mo's coeff_ab_mo = np.random.rand(20, 15) - 0.5 coeff_ab_mo *= np.diag( coeff_ab_mo.T.dot(olp_ab_ab).dot(coeff_ab_mo))**(-0.5) occupations = np.random.rand(15) num_atoms = 4 ab_atom_indices = np.array( [0, 1, 2, 1, 1, 0, 2, 1, 0, 2, 1, 2, 0, 1, 2, 0, 3, 3, 1, 0]) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo.tolist(), occupations, olp_ab_ab, num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo.ravel(), occupations, olp_ab_ab, num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo.astype(int), occupations, olp_ab_ab, num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations.tolist(), olp_ab_ab, num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations[:, None], olp_ab_ab, num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations.astype(bool), olp_ab_ab, num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab.tolist(), num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab.ravel(), num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab.astype(int), num_atoms, ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab, float(num_atoms), ab_atom_indices, ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab, num_atoms, ab_atom_indices.tolist(), ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab, num_atoms, ab_atom_indices[:, None], ) assert_raises( TypeError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab, num_atoms, ab_atom_indices.astype(float), ) assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab.reshape(10, 40), num_atoms, ab_atom_indices, ) assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo.reshape(15, 20), occupations, olp_ab_ab, num_atoms, ab_atom_indices, ) assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, np.random.rand(20), olp_ab_ab, num_atoms, ab_atom_indices, ) assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, occupations, np.random.rand(20, 20), num_atoms, ab_atom_indices, ) rand_olp_ab_ab = np.random.rand(20, 20) rand_olp_ab_ab += rand_olp_ab_ab.T assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, occupations, rand_olp_ab_ab, num_atoms, ab_atom_indices, ) rand_olp_ab_ab = np.random.rand(20, 20) rand_olp_ab_ab += rand_olp_ab_ab.T rand_norm = np.diag(rand_olp_ab_ab)**(-0.5) rand_olp_ab_ab *= rand_norm[:, None] rand_olp_ab_ab *= rand_norm[None, :] assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, occupations, rand_olp_ab_ab, num_atoms, ab_atom_indices, ) rand_occupations = np.random.rand(15) rand_occupations[6] = -1 assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, rand_occupations, olp_ab_ab, num_atoms, ab_atom_indices, ) # not sure how to check that the warning is raised but the following code prints the warning rand_occupations = np.random.rand(15) rand_occupations[6] = 2.1 OrbitalPartitionTools(coeff_ab_mo, rand_occupations, olp_ab_ab, num_atoms, ab_atom_indices) assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab, num_atoms, np.hstack([ab_atom_indices, 1]), ) bad_ab_atom_indices = ab_atom_indices.copy() bad_ab_atom_indices[0] = -1 assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab, num_atoms, bad_ab_atom_indices, ) bad_ab_atom_indices = ab_atom_indices.copy() bad_ab_atom_indices[0] = num_atoms assert_raises( ValueError, OrbitalPartitionTools, coeff_ab_mo, occupations, olp_ab_ab, num_atoms, bad_ab_atom_indices, )